diff --git a/usr.bin/dnsquery/Makefile b/usr.bin/dnsquery/Makefile new file mode 100644 index 000000000000..5f4fb9774a20 --- /dev/null +++ b/usr.bin/dnsquery/Makefile @@ -0,0 +1,6 @@ +# $Id$ + +PROG= dnsquery +MAN1= dnsquery.1 + +.include diff --git a/usr.bin/dnsquery/dnsquery.1 b/usr.bin/dnsquery/dnsquery.1 new file mode 100644 index 000000000000..ff147f0e84f9 --- /dev/null +++ b/usr.bin/dnsquery/dnsquery.1 @@ -0,0 +1,164 @@ +.TH DNSQUERY 1 "10 March 1990" +.UC 6 +.SH NAME +dnsquery \- query domain name servers using resolver +.SH SYNOPSIS +.B dnsquery +[-n +.I nameserver] +[-t +.I type] +[-c +.I class] +[-r +.I retry] +[-p +.I retry period] +[-d] [-s] [-v] host +.SH DESCRIPTION +The +.IR dnsquery +program is a general interface to nameservers via +BIND resolver library calls. The program supports +queries to the nameserver with an opcode of QUERY. +This program is intended to be a replacement or +supplement to programs like nstest, nsquery and +nslookup. All arguments except for +.IR host +and +.IR ns +are treated without case-sensitivity. +.SH OPTIONS +.TP 1i +.B \-n +The nameserver to be used in the query. Nameservers can appear as either +Internet addresses of the form w.x.y.z or can appear as domain names. +(default: as specified in /etc/resolv.conf) +.TP 1i +.B \-t +The type of resource record of interest. Types include: +.RS 1.5i +.TP 1i +A +address +.PD 0 +.TP 1i +NS +nameserver +.TP 1i +CNAME +canonical name +.TP 1i +PTR +domain name pointer +.TP 1i +SOA +start of authority +.TP 1i +WKS +well-known service +.TP 1i +HINFO +host information +.TP 1i +MINFO +mailbox information +.TP 1i +MX +mail exchange +.TP 1i +RP +responsible person +.TP 1i +MG +mail group member +.TP 1i +AFSDB +DCE or AFS server +.TP 1i +ANY +wildcard +.RE +.PD +.IP +Note that any case may be used. (default: ANY) +.TP 1i +.B \-c +The class of resource records of interest. +Classes include: +.RS 2i +.TP 1i +IN +Internet +.PD 0 +.TP 1i +HS +Hesiod +.TP 1i +CHAOS +Chaos +.TP 1i +ANY +wildcard +.RE +.PD +.IP +Note that any case may be used. (default: IN) +.TP 1i +.B \-r +The number of times to retry if the nameserver is +not responding. (default: 4) +.TP 1i +.B \-p +Period to wait before timing out. (default: RES_TIMEOUT) +.IR options +field. (default: any answer) +.TP 1i +.B \-d +Turn on debugging. This sets the RES_DEBUG bit of the resolver's +.IR options +field. (default: no debugging) +.TP 1i +.B \-s +Use a +.IR stream +rather than a packet. This uses a TCP stream connection with +the nameserver rather than a UDP datagram. This sets the +RES_USEVC bit of the resolver's +.IR options +field. (default: UDP) +.TP 1i +.B \-v +Synonym for the 's' flag. +.TP 1i +.B host +The name of the host (or domain) of interest. +.SH FILES +/etc/resolv.conf to get the default ns and search lists +.br + list of usable RR types and classes +.br + list of resolver flags +.SH "SEE ALSO" +nslookup(8), nstest(1), nsquery(1), +named(8), resolver(5) +.SH DIAGNOSTICS +If the resolver fails to answer the query and debugging has not been +turned on, +.IR dnsquery +will simply print a message like: +.TP 1i +Query failed (rc = 1) : Unknown host +.LP +The value of the return code is supplied by h_errno. +.SH BUGS +Queries of a class other than IN can have interesting results +since ordinarily a nameserver only has a list of root nameservers +for class IN resource records. +.PP +Query uses a call to inet_addr() to determine if the argument +for the '-n' option is a valid Internet address. Unfortunately, +inet_addr() seems to cause a segmentation fault with some (bad) +addresses (e.g. 1.2.3.4.5). +.SH AUTHOR +Bryan Beecher diff --git a/usr.bin/dnsquery/dnsquery.c b/usr.bin/dnsquery/dnsquery.c new file mode 100644 index 000000000000..d28f9294900b --- /dev/null +++ b/usr.bin/dnsquery/dnsquery.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../conf/portability.h" + +extern int errno; +extern int h_errno; +extern char *h_errlist[]; + +main(argc, argv) +int argc; +char *argv[]; +{ + char name[MAXDNAME]; + u_char answer[8*1024]; + register int c, i = 0; + unsigned long ul; + int nameservers = 0, class, type, len; + struct in_addr q_nsaddr[MAXNS]; + struct hostent *q_nsname; + extern int optind, opterr; + extern char *optarg; + HEADER *hp; + int stream = 0, debug = 0; + + /* set defaults */ + len = MAXDNAME; + gethostname(name, len); + class = C_IN; + type = T_ANY; + + /* if no args, exit */ + if (argc == 1) { + fprintf(stderr, "Usage: %s [-h] host [-n ns] [-t type] [-c class] [-r retry] [-p period] [-s] [-v] [-d] [-a]\n", argv[0]); + exit(-1); + } + + /* handle args */ + while ((c = getopt(argc, argv, "c:dh:n:p:r:st:u:v")) != EOF) { + switch (c) { + + case 'r' : _res.retry = atoi(optarg); + break; + + case 'p' : _res.retrans = atoi(optarg); + break; + + case 'h' : strcpy(name, optarg); + break; + + case 'c' : if (!strcasecmp(optarg, "IN")) + class = C_IN; + else if (!strcasecmp(optarg, "HS")) + class = C_HS; + else if (!strcasecmp(optarg, "CHAOS")) + class = C_CHAOS; + else if (!strcasecmp(optarg, "ANY")) + class = C_ANY; + else { + class = T_ANY; + fprintf(stderr, "optarg=%s\n", optarg); + } + break; + + case 't' : if (!strcasecmp(optarg, "A")) + type = T_A; + else if (!strcasecmp(optarg, "NS")) + type = T_NS; + else if (!strcasecmp(optarg, "CNAME")) + type = T_CNAME; + else if (!strcasecmp(optarg, "SOA")) + type = T_SOA; + else if (!strcasecmp(optarg, "WKS")) + type = T_WKS; + else if (!strcasecmp(optarg, "PTR")) + type = T_PTR; + else if (!strcasecmp(optarg, "HINFO")) + type = T_HINFO; + else if (!strcasecmp(optarg, "MINFO")) + type = T_MINFO; + else if (!strcasecmp(optarg, "MX")) + type = T_MX; + else if (!strcasecmp(optarg, "MG")) + type = T_MG; + else if (!strcasecmp(optarg, "RP")) + type = T_RP; + else if (!strcasecmp(optarg, "TXT")) + type = T_TXT; + else if (!strcasecmp(optarg, "AFSDB")) + type = T_AFSDB; + else if (!strcasecmp(optarg, "ANY")) + type = T_ANY; + else { + fprintf(stderr, "Bad type (%s)\n", optarg); + exit(-1); + } + break; + + case 'd' : debug++; + break; + + case 's' : + case 'v' : stream++; + break; + + case 'n' : + /* + * If we set some nameservers here without + * using gethostbyname() first, then they will + * get overwritten when we do the first query. + * So, we must init the resolver before any + * of this. + */ + if (!(_res.options & RES_INIT)) + if (res_init() == -1) { + fprintf(stderr, + "res_init() failed\n"); + exit(-1); + } + if (nameservers >= MAXNS) break; + (void) inet_aton(optarg, + &q_nsaddr[nameservers]); + if (!inet_aton(optarg, &ul)) { + q_nsname = gethostbyname(optarg); + if (q_nsname == 0) { + fprintf(stderr, + "Bad nameserver (%s)\n", + optarg); + exit(-1); + } + bcopy((char *) q_nsname->h_addr, + (char *) &q_nsaddr[nameservers], + INADDRSZ); + } + else + q_nsaddr[nameservers].s_addr = ul; + nameservers++; + break; + + default : fprintf(stderr, + "\tUsage: %s [-n ns] [-h host] [-t type] [-c class] [-r retry] [-p period] [-s] [-v] [-d] [-a]\n", argv[0]); + exit(-1); + } + } + if (optind < argc) + strcpy(name, argv[optind]); + + len = sizeof(answer); + + /* + * set these here so they aren't set for a possible call to + * gethostbyname above + */ + if (debug) + _res.options |= RES_DEBUG; + if (stream) + _res.options |= RES_USEVC; + + /* if the -n flag was used, add them to the resolver's list */ + if (nameservers != 0) { + _res.nscount = nameservers; + for (i = nameservers - 1; i >= 0; i--) { + _res.nsaddr_list[i].sin_addr.s_addr = q_nsaddr[i].s_addr; + _res.nsaddr_list[i].sin_family = AF_INET; + _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT); + } + } + + /* + * if the -h arg is fully-qualified, use res_query() since + * using res_search() will lead to use of res_querydomain() + * which will strip the trailing dot + */ + if (name[strlen(name) - 1] == '.') { + if (res_query(name, class, type, answer, len) < 0) { + hp = (HEADER *) answer; + if ((hp->rcode == 0) && (hp->ancount > 0)) + __p_query(answer); + else + fprintf(stderr, "Query failed (h_errno = %d) : %s\n", + h_errno, h_errlist[h_errno]); + exit(-1); + } + } + else if (res_search(name, class, type, answer, len) < 0) { + hp = (HEADER *) answer; + if ((hp->rcode == 0) && (hp->ancount > 0)) + __p_query(answer); + else + fprintf(stderr, "Query failed (h_errno = %d) : %s\n", + h_errno, h_errlist[h_errno]); + exit(-1); + } + __p_query(answer); + exit(0); +}