From: Michael Sawyer Date: Fri, 6 Oct 2000 19:08:08 +0000 (+0000) Subject: The big dig changes. Virtually everything is changed. X-Git-Tag: v9.0.0^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ada606b0061f21c8602ed552f6bf2c1cfe588ba;p=thirdparty%2Fbind9.git The big dig changes. Virtually everything is changed. Reviewed by myself and Brian. --- diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in index 9b8b32b55cb..0ac933f3eb5 100644 --- a/bin/dig/Makefile.in +++ b/bin/dig/Makefile.in @@ -1,19 +1,19 @@ # Copyright (C) 2000 Internet Software Consortium. -# +# # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS -# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE -# CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -# SOFTWARE. - -# $Id: Makefile.in,v 1.10.2.2 2000/08/08 00:17:59 gson Exp $ +# +# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM +# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# $Id: Makefile.in,v 1.10.2.3 2000/10/06 19:08:00 mws Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -25,7 +25,7 @@ top_srcdir = @top_srcdir@ CINCLUDES = -I${srcdir}/include ${DNS_INCLUDES} ${ISC_INCLUDES} -CDEFINES = +CDEFINES = -DVERSION=\"${VERSION}\" CWARNINGS = DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_OPENSSL_LIBS@ @@ -44,7 +44,7 @@ TARGETS = dig host nslookup OBJS = dig.@O@ dighost.@O@ host.@O@ nslookup.@O@ -UOBJS = +UOBJS = SRCS = dig.c dighost.c host.c nslookup.c @@ -63,9 +63,7 @@ clean distclean:: rm -f ${TARGETS} installdirs: - if [ ! -d ${DESTDIR}${bindir} ]; then \ - mkdir ${DESTDIR}${bindir}; \ - fi + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} install:: dig host nslookup installdirs ${LIBTOOL} ${INSTALL_PROGRAM} dig ${DESTDIR}${bindir} diff --git a/bin/dig/dig.c b/bin/dig/dig.c index e29ee14b8ad..656bc08cb35 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -1,40 +1,46 @@ /* * Copyright (C) 2000 Internet Software Consortium. - * + * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.c,v 1.51.2.8 2000/09/15 22:56:11 gson Exp $ */ +/* $Id: dig.c,v 1.51.2.9 2000/10/06 19:08:01 mws Exp $ */ #include #include +#include +#include #include +#include #include #include #include +#include +#include #include #include #include #include #include +#include #include extern ISC_LIST(dig_lookup_t) lookup_list; -extern ISC_LIST(dig_server_t) server_list; +extern dig_serverlist_t server_list; extern ISC_LIST(dig_searchlist_t) search_list; #define ADD_STRING(b, s) { \ @@ -45,8 +51,8 @@ extern ISC_LIST(dig_searchlist_t) search_list; } -extern isc_boolean_t have_ipv6, show_details, specified_source, - usesearch, qr, ignore; +extern isc_boolean_t have_ipv6, specified_source, + usesearch, qr; extern in_port_t port; extern unsigned int timeout; extern isc_mem_t *mctx; @@ -61,35 +67,27 @@ extern char fixeddomain[MXNAME]; extern int exitcode; extern isc_sockaddr_t bind_address; extern char keynametext[MXNAME]; +extern char keyfile[MXNAME]; extern char keysecret[MXNAME]; extern dns_tsigkey_t *key; extern isc_boolean_t validated; extern isc_taskmgr_t *taskmgr; extern isc_task_t *global_task; +extern isc_boolean_t free_now; +dig_lookup_t *default_lookup = NULL; +extern isc_uint32_t name_limit; +extern isc_uint32_t rr_limit; -extern isc_boolean_t debugging; -extern isc_boolean_t isc_mem_debugging; +extern isc_boolean_t debugging, show_packets; +char *batchname = NULL; +FILE *batchfp = NULL; +char *argv0; -isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE; +isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE, + nibble = ISC_FALSE; isc_uint16_t bufsize = 0; -isc_boolean_t - identify = ISC_FALSE, - trace = ISC_FALSE, - ns_search_only = ISC_FALSE, - forcecomment = ISC_FALSE, - stats = ISC_TRUE, - comments = ISC_TRUE, - section_question = ISC_TRUE, - section_answer = ISC_TRUE, - section_authority = ISC_TRUE, - section_additional = ISC_TRUE, - recurse = ISC_TRUE, - defname = ISC_TRUE, - aaonly = ISC_FALSE, - tcpmode = ISC_FALSE, - adflag = ISC_FALSE, - cdflag = ISC_FALSE; +isc_boolean_t forcecomment = ISC_FALSE; static const char *opcodetext[] = { "QUERY", @@ -139,11 +137,12 @@ show_usage(void) { " {global-d-opt} host [@local-server] {local-d-opt}\n" " [ host [@local-server] {local-d-opt} [...]]\n" "Where: domain are in the Domain Name System\n" -" q-class is one of (in,chaos,...) [default: in]\n" +" q-class is one of (in,hs,ch,...) [default: in]\n" " q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n" " (Use ixfr=version for type ixfr)\n" " q-opt is one of:\n" " -x dot-notation (shortcut for in-addr lookups)\n" +" -n (nibble form for reverse IPv6 lookups)\n" " -f filename (batch mode)\n" " -p port (specify port number)\n" " -t type (specify query type)\n" @@ -157,15 +156,16 @@ show_usage(void) { " +domain=### (Set default domainname)\n" " +bufsize=### (Set EDNS0 Max UDP packet size)\n" " +[no]search (Set whether to use searchlist)\n" -" +[no]defname (Set whether to use default domaon)\n" +" +[no]defname (Set whether to use default domain)\n" " +[no]recursive (Recursive mode)\n" " +[no]ignore (Don't revert to TCP for TC responses.)" "\n" +" +[no]fail (Don't try next server on SERVFAIL)\n" " +[no]aaonly (Set AA flag in query)\n" " +[no]adflag (Set AD flag in query)\n" " +[no]cdflag (Set CD flag in query)\n" -" +[no]details (Show details of all requests)\n" " +ndots=### (Set NDOTS value)\n" +" +[no]cmd (Control display of command line)\n" " +[no]comments (Control display of comment lines)\n" " +[no]question (Control display of question)\n" " +[no]answer (Control display of answer)\n" @@ -178,17 +178,16 @@ show_usage(void) { " +[no]nssearch (Search all authorative nameservers)\n" " +[no]identify (ID responders in short answers)\n" " +[no]trace (Trace delegation down from root)\n" +" +rrlimit=### (Limit number of rr's in xfr)\n" +" +namelimit=### (Limit number of names in xfr)\n" " global d-opts and servers (before host name) affect all queries.\n" " local d-opts and servers (after host name) affect only that lookup.\n" , stderr); -} - -void -dighost_shutdown(void) { - free_lists(); - isc_app_shutdown(); } +/* + * Callback from dighost.c to print the received message. + */ void received(int bytes, int frmsize, char *frm, dig_query_t *query) { isc_uint64_t diff; @@ -198,14 +197,21 @@ received(int bytes, int frmsize, char *frm, dig_query_t *query) { result = isc_time_now(&now); check_result(result, "isc_time_now"); - + if (query->lookup->stats) { diff = isc_time_microdiff(&now, &query->time_sent); printf(";; Query time: %ld msec\n", (long int)diff/1000); - printf(";; SERVER: %.*s\n", frmsize, frm); + printf(";; SERVER: %.*s(%s)\n", frmsize, frm, + query->servname); time(&tnow); printf(";; WHEN: %s", ctime(&tnow)); - printf(";; MSG SIZE rcvd: %d\n", bytes); + if (query->lookup->doing_xfr) { + printf(";; XFR size: %d names, %d rrs\n", + query->name_count, query->rr_count); + } else { + printf(";; MSG SIZE rcvd: %d\n", bytes); + + } if (key != NULL) { if (!validated) puts(";; WARNING -- Some TSIG could not " @@ -217,11 +223,17 @@ received(int bytes, int frmsize, char *frm, dig_query_t *query) { puts(""); } else if (query->lookup->identify && !short_form) { diff = isc_time_microdiff(&now, &query->time_sent); - printf(";; Received %u bytes from %.*s in %d ms\n", - bytes, frmsize, frm, (int)diff/1000); + printf(";; Received %u bytes from %.*s(%s) in %d ms\n\n", + bytes, frmsize, frm, query->servname, + (int)diff/1000); } } +/* + * Callback from dighost.c to print that it is trying a server. + * Not used in dig. + * XXX print_trying + */ void trying(int frmsize, char *frm, dig_lookup_t *lookup) { UNUSED(frmsize); @@ -229,6 +241,9 @@ trying(int frmsize, char *frm, dig_lookup_t *lookup) { UNUSED(lookup); } +/* + * Internal print routine used to print short form replies. + */ static isc_result_t say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { isc_result_t result; @@ -258,6 +273,9 @@ say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { return (ISC_R_SUCCESS); } +/* + * short_form message print handler. Calls above say_message() + */ static isc_result_t short_answer(dns_message_t *msg, dns_messagetextflag_t flags, isc_buffer_t *buf, dig_query_t *query) @@ -269,7 +287,7 @@ short_answer(dns_message_t *msg, dns_messagetextflag_t flags, dns_name_t empty_name; char t[4096]; dns_rdata_t rdata; - + UNUSED(flags); dns_name_init(&empty_name, NULL); @@ -303,11 +321,13 @@ short_answer(dns_message_t *msg, dns_messagetextflag_t flags, else if (result != ISC_R_SUCCESS) return (result); } - + return (ISC_R_SUCCESS); } - +/* + * Callback from dighost.c to print the reply from a server + */ isc_result_t printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { isc_boolean_t did_flag = ISC_FALSE; @@ -316,18 +336,12 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { isc_buffer_t *buf = NULL; unsigned int len = OUTPUTBUF; - UNUSED(query); - + if (query->lookup->cmdline[0] != 0) { + fputs(query->lookup->cmdline, stdout); + query->lookup->cmdline[0]=0; + } debug("printmessage(%s)", headers ? "headers" : "noheaders"); - /* - * Exitcode 9 means we timed out, but if we're printing a message, - * we must have recovered. Go ahead and reset it to code 0, and - * call this a success. - */ - if (exitcode == 9) - exitcode = 0; - flags = 0; if (!headers) { flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; @@ -343,6 +357,8 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { if (query->lookup->comments && !short_form) { if (!query->lookup->doing_xfr) { + if (query->lookup->cmdline[0] != 0) + printf ("; %s\n",query->lookup->cmdline); if (msg == query->lookup->sendmsg) printf(";; Sending:\n"); else @@ -365,7 +381,7 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { printf("%stc", did_flag ? " " : ""); did_flag = ISC_TRUE; - } + } if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { printf("%srd", did_flag ? " " : ""); did_flag = ISC_TRUE; @@ -382,7 +398,7 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { printf("%scd", did_flag ? " " : ""); did_flag = ISC_TRUE; } - + printf("; QUERY: %u, ANSWER: %u, " "AUTHORITY: %u, ADDITIONAL: %u\n", msg->counts[DNS_SECTION_QUESTION], @@ -393,7 +409,7 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_OPT, flags, buf); - check_result(result, + check_result(result, "dns_message_pseudosectiontotext"); } } @@ -413,7 +429,7 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { } check_result(result, "dns_message_sectiontotext"); } - } + } if (query->lookup->section_answer) { if (!short_form) { answer_again: @@ -432,7 +448,7 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { result = short_answer(msg, flags, buf, query); check_result(result, "short_answer"); } - } + } if (query->lookup->section_authority) { if (!short_form) { authority_again: @@ -448,7 +464,7 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { } check_result(result, "dns_message_sectiontotext"); } - } + } if (query->lookup->section_additional) { if (!short_form) { additional_again: @@ -477,12 +493,12 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { msg, DNS_PSEUDOSECTION_SIG0, flags, buf); - + check_result(result, "dns_message_pseudosectiontotext"); } } - } + } if (headers && query->lookup->comments && !short_form) printf("\n"); @@ -492,20 +508,35 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { return (result); } +/* + * print the greeting message when the program first starts up. + */ static void -printgreeting(int argc, char **argv) { - int i = 1; +printgreeting(int argc, char **argv, dig_lookup_t *lookup) { + int i; + static isc_boolean_t first = ISC_TRUE; + char append[MXNAME]; if (printcmd) { - puts(""); - printf("; <<>> DiG 9.0 <<>>"); + snprintf(lookup->cmdline, sizeof(lookup->cmdline), + "%s; <<>> DiG " VERSION " <<>>", + first?"\n":""); + i = 1; while (i < argc) { - printf(" %s", argv[i++]); + snprintf(append, sizeof(append), " %s", argv[i++]); + strncat(lookup->cmdline, append, + sizeof (lookup->cmdline)); + } + strncat(lookup->cmdline, "\n", sizeof (lookup->cmdline)); + if (first) { + snprintf(append, sizeof (append), + ";; global options: %s %s\n", + short_form ? "short_form" : "", + printcmd ? "printcmd" : ""); + first = ISC_FALSE; + strncat(lookup->cmdline, append, + sizeof (lookup->cmdline)); } - puts(""); - printf(";; global options: %s %s\n", - short_form ? "short_form" : "", - printcmd ? "printcmd" : ""); } } @@ -548,695 +579,696 @@ reorder_args(int argc, char *argv[]) { /* * We're not using isc_commandline_parse() here since the command line * syntax of dig is quite a bit different from that which can be described - * that routine. There is a portability issue here. + * that routine. + * XXX doc options */ -static void -parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { - isc_boolean_t have_host = ISC_FALSE; - dig_server_t *srv = NULL; - dig_lookup_t *lookup = NULL; - char *batchname = NULL; - char batchline[MXNAME]; - char address[MXNAME]; - FILE *fp = NULL; - int bargc; - char *bargv[16]; - char bargv0[sizeof("dig")]; - int i, n; - int adrs[4]; - int rc; - char **rv; - char *ptr; - /* - * The semantics for parsing the args is a bit complex; if - * we don't have a host yet, make the arg apply globally, - * otherwise make it apply to the latest host. This is - * a bit different than the previous versions, but should - * form a consistent user interface. - */ +static void +plus_option(char *option, isc_boolean_t is_batchfile, + dig_lookup_t *lookup) +{ + char option_store[256]; + char *cmd, *value, *ptr; + isc_boolean_t state = ISC_TRUE; - rc = argc; - rv = argv; - for (rc--, rv++; rc > 0; rc--, rv++) { - debug("main parsing %s", rv[0]); - if (strncmp(rv[0], "%", 1) == 0) + strncpy(option_store, option, sizeof(option_store)); + option_store[sizeof(option_store)-1]=0; + ptr = option_store; + cmd=next_token(&ptr,"="); + if (cmd == NULL) { + printf(";; Invalid option %s\n",option_store); + return; + } + value=ptr; + if (strncasecmp(cmd,"no",2)==0) { + cmd += 2; + state = ISC_FALSE; + } + switch (tolower(cmd[0])) { + case 'a': + switch (tolower(cmd[1])) { + case 'a': /* aaflag */ + lookup->aaonly = state; break; - if (strncmp(rv[0], "@", 1) == 0) { - srv = isc_mem_allocate(mctx, - sizeof(struct dig_server)); - if (srv == NULL) - fatal("Memory allocation failure"); - strncpy(srv->servername, &rv[0][1], MXNAME-1); - if (is_batchfile && have_host) { - if (!lookup->use_my_server_list) { - ISC_LIST_INIT(lookup-> - my_server_list); - lookup->use_my_server_list = - ISC_TRUE; - } - ISC_LIST_APPEND(lookup->my_server_list, - srv, link); - } else { - ISC_LIST_APPEND(server_list, srv, link); - } - } else if ((strcmp(rv[0], "+vc") == 0) - && (!is_batchfile)) { - if (have_host) - lookup->tcp_mode = ISC_TRUE; - else - tcpmode = ISC_TRUE; - } else if ((strcmp(rv[0], "+novc") == 0) - && (!is_batchfile)) { - if (have_host) - lookup->tcp_mode = ISC_FALSE; - else - tcpmode = ISC_FALSE; - } else if ((strcmp(rv[0], "+tcp") == 0) - && (!is_batchfile)) { - if (have_host) - lookup->tcp_mode = ISC_TRUE; - else - tcpmode = ISC_TRUE; - } else if ((strcmp(rv[0], "+notcp") == 0) - && (!is_batchfile)) { - if (have_host) - lookup->tcp_mode = ISC_FALSE; - else - tcpmode = ISC_FALSE; - } else if (strncmp(rv[0], "+domain=", 8) == 0) { - /* Global option always */ - strncpy(fixeddomain, &rv[0][8], MXNAME); - } else if (strncmp(rv[0], "+sea", 4) == 0) { - /* Global option always */ - usesearch = ISC_TRUE; - } else if (strncmp(rv[0], "+nosea", 6) == 0) { - usesearch = ISC_FALSE; - } else if (strncmp(rv[0], "+defn", 5) == 0) { - if (have_host) - lookup->defname = ISC_TRUE; - else - defname = ISC_TRUE; - } else if (strncmp(rv[0], "+nodefn", 7) == 0) { - if (have_host) - lookup->defname = ISC_FALSE; - else - defname = ISC_FALSE; - } else if (strncmp(rv[0], "+time=", 6) == 0) { - /* Global option always */ - timeout = atoi(&rv[0][6]); - if (timeout <= 0) - timeout = 1; - debug ("timeout set to %d", timeout); - } else if (strncmp(rv[0], "+timeout=", 9) == 0) { - /* Global option always */ - timeout = atoi(&rv[0][9]); - if (timeout <= 0) - timeout = 1; - debug ("timeout set to %d", timeout); - } else if (strncmp(rv[0], "+tries=", 7) == 0) { - if (have_host) { - lookup->retries = atoi(&rv[0][7]); - if (lookup->retries <= 0) - lookup->retries = 1; - } else { - tries = atoi(&rv[0][7]); - if (tries <= 0) - tries = 1; - } - } else if (strncmp(rv[0], "+buf=", 5) == 0) { - if (have_host) { - lookup->udpsize = atoi(&rv[0][5]); - if (lookup->udpsize <= 0) - lookup->udpsize = 0; - if (lookup->udpsize > COMMSIZE) - lookup->udpsize = COMMSIZE; - } else { - bufsize = atoi(&rv[0][5]); - if (bufsize <= 0) - bufsize = 0; - if (bufsize > COMMSIZE) - bufsize = COMMSIZE; - } - } else if (strncmp(rv[0], "+bufsize=", 9) == 0) { - if (have_host) { - lookup->udpsize = atoi(&rv[0][9]); - if (lookup->udpsize <= 0) - lookup->udpsize = 0; - if (lookup->udpsize > COMMSIZE) - lookup->udpsize = COMMSIZE; - } else { - bufsize = atoi(&rv[0][9]); - if (bufsize <= 0) - bufsize = 0; - if (bufsize > COMMSIZE) - bufsize = COMMSIZE; + case 'd': + switch (tolower(cmd[2])) { + case 'd': /* additional */ + lookup->section_additional = state; + break; + case 'f': /* adflag */ + lookup->adflag = state; + break; + default: + goto invalid_option; } - } else if (strncmp(rv[0], "+ndots=", 7) == 0) { - /* Global option always */ - ndots = atoi(&rv[0][7]); + break; + case 'l': /* all */ + lookup->section_question = state; + lookup->section_authority = state; + lookup->section_answer = state; + lookup->section_additional = state; + lookup->comments = state; + break; + case 'n': /* answer */ + lookup->section_answer = state; + break; + case 'u': /* authority */ + lookup->section_authority = state; + break; + default: + goto invalid_option; + } + break; + case 'b': /* bufsize */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + lookup->udpsize = atoi(value); + if (lookup->udpsize <= 0) + lookup->udpsize = 0; + if (lookup->udpsize > COMMSIZE) + lookup->udpsize = COMMSIZE; + break; + case 'c': + switch (tolower(cmd[1])) { + case 'd':/* cdflag */ + lookup->cdflag = state; + break; + case 'm': /* cmd */ + printcmd = state; + break; + case 'o': /* comments */ + lookup->comments = state; + break; + default: + goto invalid_option; + } + break; + case 'd': + switch (tolower(cmd[1])) { + case 'e': + lookup->defname = state; + break; + case 'o': /* domain */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + strncpy(fixeddomain, value, sizeof(fixeddomain)); + fixeddomain[sizeof(fixeddomain)-1]=0; + break; + default: + goto invalid_option; + } + break; + case 'f': /* fail */ + lookup->servfail_stops = state; + break; + case 'i': + switch (tolower(cmd[1])) { + case 'd': /* identify */ + lookup->identify = state; + break; + case 'g': /* ignore */ + default: /* Inherets default for compatibility */ + lookup->ignore = ISC_TRUE; + } + break; + case 'n': + switch (tolower(cmd[1])) { + case 'a': /* namelimit */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + name_limit = atoi(value); + break; + case 'd': /* ndots */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + ndots = atoi(value); if (ndots < 0) ndots = 0; - } else if (strncmp(rv[0], "+rec", 4) == 0) { - if (have_host) - lookup->recurse = ISC_TRUE; - else - recurse = ISC_TRUE; - } else if (strncmp(rv[0], "+norec", 6) == 0) { - if (have_host) - lookup->recurse = ISC_FALSE; - else - recurse = ISC_FALSE; - } else if (strncmp(rv[0], "+aa", 3) == 0) { - if (have_host) - lookup->aaonly = ISC_TRUE; - else - aaonly = ISC_TRUE; - } else if (strncmp(rv[0], "+noaa", 5) == 0) { - if (have_host) - lookup->aaonly = ISC_FALSE; - else - aaonly = ISC_FALSE; - } else if (strncmp(rv[0], "+adf", 4) == 0) { - if (have_host) - lookup->adflag = ISC_TRUE; - else - adflag = ISC_TRUE; - } else if (strncmp(rv[0], "+noadf", 6) == 0) { - if (have_host) - lookup->adflag = ISC_FALSE; - else - adflag = ISC_FALSE; - } else if (strncmp(rv[0], "+cd", 3) == 0) { - if (have_host) - lookup->cdflag = ISC_TRUE; - else - cdflag = ISC_TRUE; - } else if (strncmp(rv[0], "+nocd", 5) == 0) { - if (have_host) - lookup->cdflag = ISC_FALSE; - else - cdflag = ISC_FALSE; - } else if (strncmp(rv[0], "+ns", 3) == 0) { - if (have_host) { - lookup->ns_search_only = ISC_TRUE; + break; + case 's': /* nssearch */ + lookup->ns_search_only = state; + if (state) { lookup->trace_root = ISC_TRUE; lookup->recurse = ISC_FALSE; lookup->identify = ISC_TRUE; lookup->stats = ISC_FALSE; - if (!forcecomment) - lookup->comments = ISC_FALSE; + lookup->comments = ISC_FALSE; lookup->section_additional = ISC_FALSE; lookup->section_authority = ISC_FALSE; lookup->section_question = ISC_FALSE; - } else { - ns_search_only = ISC_TRUE; - recurse = ISC_FALSE; - identify = ISC_TRUE; - stats = ISC_FALSE; - if (!forcecomment) - comments = ISC_FALSE; - section_additional = ISC_FALSE; - section_authority = ISC_FALSE; - section_question = ISC_FALSE; + lookup->rdtype = dns_rdatatype_soa; + short_form = ISC_TRUE; } - } else if (strncmp(rv[0], "+nons", 6) == 0) { - if (have_host) - lookup->ns_search_only = ISC_FALSE; - else - ns_search_only = ISC_FALSE; - } else if (strncmp(rv[0], "+tr", 3) == 0) { - if (have_host) { - lookup->trace = ISC_TRUE; - lookup->trace_root = ISC_TRUE; - lookup->recurse = ISC_FALSE; - lookup->identify = ISC_TRUE; - if (!forcecomment) { - lookup->comments = ISC_FALSE; - lookup->stats = ISC_FALSE; - } + break; + default: + goto invalid_option; + } + break; + case 'q': + switch (tolower(cmd[1])) { + case 'r': /* qr */ + qr = state; + break; + case 'u': /* question */ + lookup->section_question = state; + break; + default: + goto invalid_option; + } + break; + case 'r': + switch (tolower(cmd[1])) { + case 'e': /* recurse */ + lookup->recurse = state; + break; + case 'r': /* rrlimit */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + rr_limit = atoi(value); + break; + default: + goto invalid_option; + } + break; + case 's': + switch (tolower(cmd[1])) { + case 'e': /* search */ + usesearch = state; + break; + case 'h': /* short */ + short_form = state; + if (state) { + printcmd = ISC_FALSE; lookup->section_additional = ISC_FALSE; lookup->section_authority = ISC_FALSE; lookup->section_question = ISC_FALSE; - show_details = ISC_TRUE; - } else { - trace = ISC_TRUE; - recurse = ISC_FALSE; - identify = ISC_TRUE; - if (!forcecomment) { - comments = ISC_FALSE; - stats = ISC_FALSE; - } - section_additional = ISC_FALSE; - section_authority = ISC_FALSE; - section_question = ISC_FALSE; - show_details = ISC_TRUE; - } - } else if (strncmp(rv[0], "+notr", 6) == 0) { - if (have_host) { - lookup->trace = ISC_FALSE; - lookup->trace_root = ISC_FALSE; + lookup->comments = ISC_FALSE; + lookup->stats = ISC_FALSE; } - else - trace = ISC_FALSE; - } else if (strncmp(rv[0], "+det", 4) == 0) { - show_details = ISC_TRUE; - } else if (strncmp(rv[0], "+nodet", 6) == 0) { - show_details = ISC_FALSE; - } else if (strncmp(rv[0], "+cmd", 4) == 0) { - printcmd = ISC_TRUE; - } else if (strncmp(rv[0], "+nocmd", 6) == 0) { - printcmd = ISC_FALSE; - } else if (strncmp(rv[0], "+sho", 4) == 0) { - short_form = ISC_TRUE; - printcmd = ISC_FALSE; - if (have_host) { - lookup->section_additional = ISC_FALSE; - lookup->section_authority = ISC_FALSE; - lookup->section_question = ISC_FALSE; - if (!forcecomment) { + break; + case 't': /* stats */ + lookup->stats = state; + break; + default: + goto invalid_option; + } + break; + case 't': + switch (tolower(cmd[1])) { + case 'c': /* tcp */ + if (!is_batchfile) + lookup->tcp_mode = state; + break; + case 'i': /* timeout */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + timeout = atoi(value); + if (timeout <= 0) + timeout = 1; + break; + case 'r': + switch (tolower(cmd[2])) { + case 'a': /* trace */ + lookup->trace = state; + lookup->trace_root = state; + if (state) { + lookup->recurse = ISC_FALSE; + lookup->identify = ISC_TRUE; lookup->comments = ISC_FALSE; lookup->stats = ISC_FALSE; + lookup->section_additional = ISC_FALSE; + lookup->section_authority = ISC_TRUE; + lookup->section_question = ISC_FALSE; } - } else { - section_additional = ISC_FALSE; - section_authority = ISC_FALSE; - section_question = ISC_FALSE; - if (!forcecomment) { - comments = ISC_FALSE; - stats = ISC_FALSE; - } - } - } else if (strncmp(rv[0], "+nosho", 6) == 0) { - short_form = ISC_FALSE; - } else if (strncmp(rv[0], "+i", 2) == 0) { - ignore = ISC_TRUE; - } else if (strncmp(rv[0], "+noi", 4) == 0) { - ignore = ISC_FALSE; - } else if (strncmp(rv[0], "+id", 3) == 0) { - if (have_host) - lookup->identify = ISC_TRUE; - else - identify = ISC_TRUE; - } else if (strncmp(rv[0], "+noid", 5) == 0) { - if (have_host) - lookup->identify = ISC_FALSE; - else - identify = ISC_FALSE; - } else if (strncmp(rv[0], "+com", 4) == 0) { - if (have_host) - lookup->comments = ISC_TRUE; - else - comments = ISC_TRUE; - forcecomment = ISC_TRUE; - } else if (strncmp(rv[0], "+nocom", 6) == 0) { - if (have_host) { - lookup->comments = ISC_FALSE; - lookup->stats = ISC_FALSE; - } else { - comments = ISC_FALSE; - stats = ISC_FALSE; + break; + case 'i': /* tries */ + if (value == NULL) + goto need_value; + if (!state) + goto invalid_option; + lookup->retries = atoi(value); + if (lookup->retries <= 0) + lookup->retries = 1; + break; + default: + goto invalid_option; } - forcecomment = ISC_FALSE; - } else if (strncmp(rv[0], "+sta", 4) == 0) { - if (have_host) - lookup->stats = ISC_TRUE; - else - stats = ISC_TRUE; - } else if (strncmp(rv[0], "+nosta", 6) == 0) { - if (have_host) - lookup->stats = ISC_FALSE; - else - stats = ISC_FALSE; - } else if (strncmp(rv[0], "+qr", 3) == 0) { - qr = ISC_TRUE; - } else if (strncmp(rv[0], "+noqr", 5) == 0) { - qr = ISC_FALSE; - } else if (strncmp(rv[0], "+que", 4) == 0) { - if (have_host) - lookup->section_question = ISC_TRUE; - else - section_question = ISC_TRUE; - } else if (strncmp(rv[0], "+noque", 6) == 0) { - if (have_host) - lookup->section_question = ISC_FALSE; - else - section_question = ISC_FALSE; - } else if (strncmp(rv[0], "+ans", 4) == 0) { - if (have_host) - lookup->section_answer = ISC_TRUE; - else - section_answer = ISC_TRUE; - } else if (strncmp(rv[0], "+noans", 6) == 0) { - if (have_host) - lookup->section_answer = ISC_FALSE; - else - section_answer = ISC_FALSE; - } else if (strncmp(rv[0], "+add", 4) == 0) { - if (have_host) - lookup->section_additional = ISC_TRUE; - else - section_additional = ISC_TRUE; - } else if (strncmp(rv[0], "+noadd", 6) == 0) { - if (have_host) - lookup->section_additional = ISC_FALSE; - else - section_additional = ISC_FALSE; - } else if (strncmp(rv[0], "+aut", 4) == 0) { - if (have_host) - lookup->section_authority = ISC_TRUE; - else - section_authority = ISC_TRUE; - } else if (strncmp(rv[0], "+noaut", 6) == 0) { - if (have_host) - lookup->section_authority = ISC_FALSE; - else - section_authority = ISC_FALSE; - } else if (strncmp(rv[0], "+all", 4) == 0) { - if (have_host) { - lookup->section_question = ISC_TRUE; - lookup->section_authority = ISC_TRUE; - lookup->section_answer = ISC_TRUE; - lookup->section_additional = ISC_TRUE; - lookup->comments = ISC_TRUE; - } else { - section_question = ISC_TRUE; - section_authority = ISC_TRUE; - section_answer = ISC_TRUE; - section_additional = ISC_TRUE; - comments = ISC_TRUE; + break; + default: + goto invalid_option; + } + break; + case 'v': /* vc */ + if (!is_batchfile) + lookup->tcp_mode = state; + break; + default: + invalid_option: + need_value: + fprintf(stderr, "Invalid option: +%s\n", + option); + show_usage(); + exit(1); + } + return; +} + +/* + * ISC_TRUE returned if value was used + */ +static isc_boolean_t +dash_option(char *option, char *next, dig_lookup_t **lookup, + isc_boolean_t *open_type_class) +{ + char cmd, *value, *ptr; + isc_result_t result; + isc_boolean_t value_from_next; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + int adrs[4]; + int n, i; + char batchline[MXNAME]; + + cmd = option[0]; + if (strlen(option) > 1) { + value_from_next = ISC_FALSE; + value = &option[1]; + } + else { + value_from_next = ISC_TRUE; + value = next; + } + switch (tolower(cmd)) { + case 'd': + debugging = ISC_TRUE; + return (ISC_FALSE); + case 'h': + show_usage(); + exit(0); + break; + case 'm': + isc_mem_debugging = ISC_TRUE; + return (ISC_FALSE); + case 'n': + nibble = ISC_TRUE; + return (ISC_FALSE); + case 'w': + show_packets = ISC_TRUE; + return (ISC_FALSE); + + } + if (value == NULL) + goto invalid_option; + switch (tolower(cmd)) { + case 'b': + get_address(value, 0, &bind_address); + specified_source = ISC_TRUE; + return (value_from_next); + case 'c': + *open_type_class = ISC_FALSE; + tr.base = value; + tr.length = strlen(value); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) + (*lookup)->rdclass = rdclass; + else + fprintf(stderr, ";; Warning, ignoring " + "invalid class %s\n", + value); + return (value_from_next); + case 'f': + batchname = value; + return (value_from_next); + case 'k': + strncpy(keyfile, value, sizeof(keyfile)); + keyfile[sizeof(keyfile)-1]=0; + return (value_from_next); + case 'p': + port = atoi(value); + return (value_from_next); + case 't': + *open_type_class = ISC_FALSE; + if (strncasecmp(value, "ixfr=", 5) == 0) { + (*lookup)->rdtype = dns_rdatatype_ixfr; + (*lookup)->ixfr_serial = + atoi(&value[5]); + return (value_from_next); + } + tr.base = value; + tr.length = strlen(value); + result = dns_rdatatype_fromtext(&rdtype, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) + (*lookup)->rdtype = rdtype; + else + fprintf(stderr, ";; Warning, ignoring " + "invalid type %s\n", + value); + return (value_from_next); + case 'y': + ptr = next_token(&value,":"); + if (ptr == NULL) { + show_usage(); + exit(1); + } + strncpy(keynametext, ptr, sizeof(keynametext)); + keynametext[sizeof(keynametext)-1]=0; + ptr = next_token(&value, ""); + if (ptr == NULL) { + show_usage(); + exit(1); + } + strncpy(keysecret, ptr, sizeof(keysecret)); + keysecret[sizeof(keysecret)-1]=0; + return (value_from_next); + case 'x': + *lookup = clone_lookup(default_lookup, ISC_TRUE); + if (strchr(value, ':') == NULL) { + n = sscanf(value, "%d.%d.%d.%d", + &adrs[0], &adrs[1], + &adrs[2], &adrs[3]); + if (n == 0) { + show_usage(); + exit (1); } - } else if (strncmp(rv[0], "+noall", 6) == 0) { - if (have_host) { - lookup->section_question = ISC_FALSE; - lookup->section_authority = ISC_FALSE; - lookup->section_answer = ISC_FALSE; - lookup->section_additional = ISC_FALSE; - lookup->comments = ISC_FALSE; - } else { - section_question = ISC_FALSE; - section_authority = ISC_FALSE; - section_answer = ISC_FALSE; - section_additional = ISC_FALSE; - comments = ISC_FALSE; + for (i = n - 1; i >= 0; i--) { + snprintf(batchline, MXNAME/8, "%d.", + adrs[i]); + strncat((*lookup)->textname, batchline, + MXNAME); } + strncat((*lookup)->textname, "in-addr.arpa.", + MXNAME); + } else { + isc_netaddr_t addr; + dns_fixedname_t fname; + dns_name_t *name; + isc_buffer_t b; + + addr.family = AF_INET6; + n = inet_pton(AF_INET6, value, &addr.type.in6); + if (n <= 0) + show_usage(); + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + (*lookup)->nibble = nibble; + result = dns_byaddr_createptrname(&addr, nibble, + name); + if (result != ISC_R_SUCCESS) + show_usage(); + isc_buffer_init(&b, (*lookup)->textname, + sizeof (*lookup)->textname); + result = dns_name_totext(name, ISC_FALSE, &b); + isc_buffer_putuint8(&b, 0); + if (result != ISC_R_SUCCESS) + show_usage(); + } + debug("looking up %s", (*lookup)->textname); + (*lookup)->trace_root = ISC_TF((*lookup)->trace || + (*lookup)->ns_search_only); + (*lookup)->rdtype = dns_rdatatype_ptr; + (*lookup)->rdclass = dns_rdataclass_in; + (*lookup)->new_search = ISC_TRUE; + + ISC_LIST_APPEND(lookup_list, *lookup, link); + return (value_from_next); + invalid_option: + default: + fprintf(stderr, "Invalid option: -%s\n", option); + show_usage(); + exit(1); + } + return (ISC_FALSE); +} - } else if (strncmp(rv[0], "-c", 2) == 0) { - if (have_host) { - if (rv[0][2] != 0) { - strncpy(lookup->rctext, &rv[0][2], - MXRD); - } else { - strncpy(lookup->rctext, rv[1], - MXRD); - rv++; - rc--; +static void +parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, + int argc, char **argv) { + isc_result_t result; + isc_textregion_t tr; + isc_boolean_t firstarg = ISC_TRUE; + dig_server_t *srv = NULL; + dig_lookup_t *lookup = NULL; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + isc_boolean_t open_type_class = ISC_TRUE; + char batchline[MXNAME]; + int bargc; + char *bargv[16]; + int rc; + char **rv; +#ifndef NOPOSIX + char *homedir; + char rcfile[132]; +#endif + char *input; + + /* + * The semantics for parsing the args is a bit complex; if + * we don't have a host yet, make the arg apply globally, + * otherwise make it apply to the latest host. This is + * a bit different than the previous versions, but should + * form a consistent user interface. + * + * First, create a "default lookup" which won't actually be used + * anywhere, except for cloning into new lookups + */ + + debug("parse_args()"); + if (!is_batchfile) { + debug("making new lookup"); + default_lookup = make_empty_lookup(); + +#ifndef NOPOSIX + /* + * Treat .digrc as a special batchfile + */ + homedir = getenv("HOME"); + if (homedir != NULL) + snprintf(rcfile, 132, "%s/.digrc", homedir); + else + strcpy(rcfile, ".digrc"); + batchfp = fopen(rcfile, "r"); + if (batchfp != NULL) { + while (fgets(batchline, sizeof(batchline), + batchfp) != 0) { + debug("config line %s", batchline); + bargc = 1; + input = batchline; + bargv[bargc] = next_token(&input, " \t\r\n"); + while ((bargv[bargc] != NULL) && + (bargc < 14)) { + bargc++; + bargv[bargc] = next_token(&input, " \t\r\n"); } + + bargv[0] = argv[0]; + argv0 = argv[0]; + + reorder_args(bargc, (char **)bargv); + parse_args(ISC_TRUE, ISC_TRUE, bargc, + (char **)bargv); } - } else if (strncmp(rv[0], "-t", 2) == 0) { - if (have_host) { - if (rv[0][2] != 0) { - strncpy(lookup->rttext, &rv[0][2], - MXRD); - } else { - strncpy(lookup->rttext, rv[1], - MXRD); - rv++; + fclose(batchfp); + } +#endif + } + + lookup = default_lookup; + + rc = argc; + rv = argv; + for (rc--, rv++; rc > 0; rc--, rv++) { + debug("main parsing %s", rv[0]); + if (strncmp(rv[0], "%", 1) == 0) + break; + if (strncmp(rv[0], "@", 1) == 0) { + srv = make_server(&rv[0][1]); + ISC_LIST_APPEND(lookup->my_server_list, + srv, link); + } else if (rv[0][0] == '+') { + plus_option(&rv[0][1], is_batchfile, + lookup); + } else if (rv[0][0] == '-') { + if (rc <= 1) { + if (dash_option(&rv[0][1], NULL, + &lookup, &open_type_class)) { rc--; + rv++; } - } - } else if (strncmp(rv[0], "-f", 2) == 0) { - if (rv[0][2] != 0) { - batchname = &rv[0][2]; - } else { - batchname = rv[1]; - rv++; - rc--; - } - } else if (strncmp(rv[0], "-y", 2) == 0) { - if (rv[0][2] != 0) - ptr = &rv[0][2]; - else { - ptr = rv[1]; - rv++; - rc--; - } - ptr = strtok(ptr,":"); - if (ptr == NULL) { - show_usage(); - exit(exitcode); - } - strncpy(keynametext, ptr, MXNAME); - ptr = strtok(NULL, ""); - if (ptr == NULL) { - show_usage(); - exit(exitcode); - } - strncpy(keysecret, ptr, MXNAME); - } else if (strncmp(rv[0], "-p", 2) == 0) { - if (rv[0][2] != 0) { - port = atoi(&rv[0][2]); - } else { - port = atoi(rv[1]); - rv++; - rc--; - } - } else if (strncmp(rv[0], "-b", 2) == 0) { - if (rv[0][2] != 0) { - strncpy(address, &rv[0][2], - MXRD); } else { - strncpy(address, rv[1], - MXRD); - rv++; - rc--; + if (dash_option(&rv[0][1], rv[1], + &lookup, &open_type_class)) { + rc--; + rv++; + } } - get_address(address, 0, &bind_address); - specified_source = ISC_TRUE; - } else if (strncmp(rv[0], "-h", 2) == 0) { - show_usage(); - exit(exitcode); - } else if (strcmp(rv[0], "-memdebug") == 0) { - isc_mem_debugging = ISC_TRUE; - } else if (strcmp(rv[0], "-debug") == 0) { - debugging = ISC_TRUE; - } else if (strncmp(rv[0], "-x", 2) == 0) { + } else { /* - * XXXMWS Only works for ipv4 now. - * Can't use inet_pton here, since we allow - * partial addresses. + * Anything which isn't an option */ - if (rc == 1) { - show_usage(); - exit(exitcode); - } - n = sscanf(rv[1], "%d.%d.%d.%d", &adrs[0], &adrs[1], - &adrs[2], &adrs[3]); - if (n == 0) - show_usage(); - lookup = isc_mem_allocate(mctx, - sizeof(struct dig_lookup)); - if (lookup == NULL) - fatal("Memory allocation failure"); - lookup->pending = ISC_FALSE; - lookup->textname[0] = 0; - for (i = n - 1; i >= 0; i--) { - snprintf(batchline, MXNAME/8, "%d.", - adrs[i]); - strncat(lookup->textname, batchline, MXNAME); - } - strncat(lookup->textname, "in-addr.arpa.", MXNAME); - debug("looking up %s", lookup->textname); - strcpy(lookup->rttext, "ptr"); - strcpy(lookup->rctext, "in"); - lookup->namespace[0] = 0; - lookup->sendspace = NULL; - lookup->sendmsg = NULL; - lookup->name = NULL; - lookup->oname = NULL; - lookup->timer = NULL; - lookup->xfr_q = NULL; - lookup->origin = NULL; - lookup->querysig = NULL; - lookup->use_my_server_list = ISC_FALSE; - lookup->trace = trace; - lookup->trace_root = ISC_TF(trace || ns_search_only); - lookup->ns_search_only = ns_search_only; - lookup->doing_xfr = ISC_FALSE; - lookup->ixfr_serial = 0; - lookup->defname = ISC_FALSE; - lookup->identify = identify; - lookup->recurse = recurse; - lookup->aaonly = aaonly; - lookup->adflag = adflag; - lookup->cdflag = cdflag; - lookup->retries = tries; - lookup->udpsize = bufsize; - lookup->nsfound = 0; - lookup->comments = comments; - lookup->tcp_mode = tcpmode; - lookup->stats = stats; - lookup->section_question = section_question; - lookup->section_answer = section_answer; - lookup->section_authority = section_authority; - lookup->section_additional = section_additional; - lookup->new_search = ISC_TRUE; - ISC_LIST_INIT(lookup->q); - lookup->origin = NULL; - ISC_LIST_INIT(lookup->my_server_list); - ISC_LIST_APPEND(lookup_list, lookup, link); - have_host = ISC_TRUE; - rv++; - rc--; - } else { - if (have_host) { - ENSURE(lookup != NULL); + if (open_type_class) { + tr.base = rv[0]; + tr.length = strlen(rv[0]); if (strncmp(rv[0], "ixfr=", 5) == 0) { - strcpy(lookup->rttext, "ixfr"); - lookup->ixfr_serial = + lookup->rdtype = dns_rdatatype_ixfr; + lookup->ixfr_serial = atoi(&rv[0][5]); continue; } - if (istype(rv[0])) { - strncpy(lookup->rttext, rv[0], MXRD); + result = dns_rdatatype_fromtext(&rdtype, + (isc_textregion_t *)&tr); + if ((result == ISC_R_SUCCESS) && + (rdtype != dns_rdatatype_ixfr)) { + lookup->rdtype = rdtype; continue; - } else if (isclass(rv[0])) { - strncpy(lookup->rctext, rv[0], - MXRD); + } + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + lookup->rdclass = rdclass; continue; } } - lookup = isc_mem_allocate(mctx, - sizeof(struct dig_lookup)); - if (lookup == NULL) - fatal("Memory allocation failure"); - lookup->pending = ISC_FALSE; - strncpy(lookup->textname, rv[0], MXNAME-1); - lookup->rttext[0] = 0; - lookup->rctext[0] = 0; - lookup->namespace[0] = 0; - lookup->sendspace = NULL; - lookup->sendmsg = NULL; - lookup->name = NULL; - lookup->oname = NULL; - lookup->timer = NULL; - lookup->xfr_q = NULL; - lookup->origin = NULL; - lookup->querysig = NULL; - lookup->use_my_server_list = ISC_FALSE; - lookup->doing_xfr = ISC_FALSE; - lookup->ixfr_serial = 0; - lookup->defname = ISC_FALSE; - lookup->trace_root = ISC_TF(trace || ns_search_only); - lookup->trace = trace; - lookup->ns_search_only = ns_search_only; - lookup->identify = identify; - lookup->recurse = recurse; - lookup->aaonly = aaonly; - lookup->adflag = adflag; - lookup->cdflag = cdflag; - lookup->retries = tries; - lookup->udpsize = bufsize; - lookup->nsfound = 0; - lookup->comments = comments; - lookup->tcp_mode = tcpmode; - lookup->stats = stats; - lookup->section_question = section_question; - lookup->section_answer = section_answer; - lookup->section_authority = section_authority; - lookup->section_additional = section_additional; - lookup->new_search = ISC_TRUE; - ISC_LIST_INIT(lookup->q); - ISC_LIST_APPEND(lookup_list, lookup, link); - lookup->origin = NULL; - ISC_LIST_INIT(lookup->my_server_list); - have_host = ISC_TRUE; - debug("looking up %s", lookup->textname); + if (!config_only) { + lookup = clone_lookup(default_lookup, + ISC_TRUE); + if (firstarg) { + printgreeting(argc, argv, lookup); + firstarg = ISC_FALSE; + } + strncpy(lookup->textname, rv[0], + sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1]=0; + lookup->trace_root = ISC_TF(lookup->trace || + lookup->ns_search_only); + lookup->new_search = ISC_TRUE; + ISC_LIST_APPEND(lookup_list, lookup, link); + debug("looking up %s", lookup->textname); + } + /* XXX Error message */ } } - if (batchname != NULL) { - fp = fopen(batchname, "r"); - if (fp == NULL) { + /* + * If we have a batchfile, seed the lookup list with the + * first entry, then trust the callback in dighost_shutdown + * to get the rest + */ + if ((batchname != NULL) && !(is_batchfile)) { + if (strcmp(batchname, "-") == 0) + batchfp = stdin; + else + batchfp = fopen(batchname, "r"); + if (batchfp == NULL) { perror(batchname); - if (exitcode < 10) - exitcode = 10; + if (exitcode < 8) + exitcode = 8; fatal("Couldn't open specified batch file"); } - while (fgets(batchline, sizeof(batchline), fp) != 0) { - debug("batch line %s", batchline); + /* XXX Remove code dup from shutdown code */ + next_line: + if (fgets(batchline, sizeof(batchline), batchfp) != 0) { bargc = 1; - bargv[bargc] = strtok(batchline, " \t\r\n"); - while ((bargv[bargc] != NULL) && (bargc < 14 )) { + debug("batch line %s", batchline); + if (batchline[0] == '\r' || batchline[0] == '\n' + || batchline[0] == '#' || batchline[0] == ';') + goto next_line; + input = batchline; + bargv[bargc] = next_token(&input, " \t\r\n"); + while ((bargv[bargc] != NULL) && (bargc < 14)) { bargc++; - bargv[bargc] = strtok(NULL, " \t\r\n"); + bargv[bargc] = next_token(&input, " \t\r\n"); } - /* - * This silliness (instead of ``bargv[0] = "dig";'') - * dances around the const string issue. If in - * the future the 2nd argument to strncpy() is made - * longer than three characters, don't forget to resize - * bargv0 to accommodate it. - */ - strncpy(bargv0, "dig", sizeof(bargv0)); - bargv[0] = bargv0; + bargv[0] = argv[0]; + argv0 = argv[0]; reorder_args(bargc, (char **)bargv); - parse_args(ISC_TRUE, bargc, (char **)bargv); + parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); } } - if (lookup_list.head == NULL) { - lookup = isc_mem_allocate(mctx, sizeof(struct dig_lookup)); - if (lookup == NULL) - fatal("Memory allocation failure"); - lookup->pending = ISC_FALSE; - lookup->rctext[0] = 0; - lookup->namespace[0] = 0; - lookup->sendspace = NULL; - lookup->sendmsg = NULL; - lookup->name = NULL; - lookup->oname = NULL; - lookup->timer = NULL; - lookup->xfr_q = NULL; - lookup->origin = NULL; - lookup->querysig = NULL; - lookup->use_my_server_list = ISC_FALSE; - lookup->doing_xfr = ISC_FALSE; - lookup->ixfr_serial = 0; - lookup->defname = ISC_FALSE; - lookup->trace_root = ISC_TF(trace || ns_search_only); - lookup->trace = trace; - lookup->ns_search_only = ns_search_only; - lookup->identify = identify; - lookup->recurse = recurse; - lookup->aaonly = aaonly; - lookup->adflag = adflag; - lookup->cdflag = cdflag; - lookup->retries = tries; - lookup->udpsize = bufsize; - lookup->nsfound = 0; - lookup->comments = comments; - lookup->tcp_mode = tcpmode; - lookup->stats = stats; - lookup->section_question = section_question; - lookup->section_answer = section_answer; - lookup->section_authority = section_authority; - lookup->section_additional = section_additional; + /* + * If no lookup specified, search for root + */ + if ((lookup_list.head == NULL) && !config_only) { + lookup = clone_lookup(default_lookup, ISC_TRUE); + lookup->trace_root = ISC_TF(lookup->trace || + lookup->ns_search_only); lookup->new_search = ISC_TRUE; - ISC_LIST_INIT(lookup->q); - ISC_LIST_INIT(lookup->my_server_list); strcpy(lookup->textname, "."); - strcpy(lookup->rttext, "NS"); - lookup->rctext[0] = 0; + lookup->rdtype = dns_rdatatype_ns; ISC_LIST_APPEND(lookup_list, lookup, link); } - if (!is_batchfile) - printgreeting(argc, argv); +} + +/* + * Callback from dighost.c to allow program-specific shutdown code. Here, + * Here, we're possibly reading from a batch file, then shutting down for + * real if there's nothing in the batch file to read. + */ +void +dighost_shutdown(void) { + char batchline[MXNAME]; + int bargc; + char *bargv[16]; + char *input; + + + if (batchname == NULL) { + isc_app_shutdown(); + return; + } + + if (feof(batchfp)) { + batchname = NULL; + isc_app_shutdown(); + if (batchfp != stdin) + fclose(batchfp); + return; + } + + if (fgets(batchline, sizeof(batchline), batchfp) != 0) { + debug("batch line %s", batchline); + bargc = 1; + input = batchline; + bargv[bargc] = next_token(&input, " \t\r\n"); + while ((bargv[bargc] != NULL) && (bargc < 14)) { + bargc++; + bargv[bargc] = next_token(&input, " \t\r\n"); + } + + bargv[0] = argv0; + + reorder_args(bargc, (char **)bargv); + parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); + start_lookup(); + } else { + batchname = NULL; + if (batchfp != stdin) + fclose(batchfp); + isc_app_shutdown(); + return; + } } int main(int argc, char **argv) { isc_result_t result; + dig_server_t *s, *s2; ISC_LIST_INIT(lookup_list); ISC_LIST_INIT(server_list); @@ -1244,28 +1276,35 @@ main(int argc, char **argv) { debug("main()"); progname = argv[0]; + result = isc_app_start(); + check_result(result, "isc_app_start"); setup_libs(); - parse_args(ISC_FALSE, argc, argv); + parse_args(ISC_FALSE, ISC_FALSE, argc, argv); setup_system(); result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); check_result(result, "isc_app_onrun"); isc_app_run(); - /* - * XXXMWS This code should really NOT be bypassed. However, - * until the proper code can be added to handle SIGTERM/INT - * correctly, just exit out "hard" and deal as best we can. - */ -#if 0 - if (taskmgr != NULL) { - debug ("Freeing taskmgr"); - isc_taskmgr_destroy(&taskmgr); - } - if (isc_mem_debugging) + s = ISC_LIST_HEAD(default_lookup->my_server_list); + while (s != NULL) { + debug("freeing server %p belonging to %p", + s, default_lookup); + s2 = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(default_lookup->my_server_list, + (dig_server_t *)s2, link); + isc_mem_free(mctx, s2); + } + if (isc_mem_debugging != 0) isc_mem_stats(mctx, stderr); - if (mctx != NULL) - isc_mem_destroy(&mctx); + isc_mem_free(mctx, default_lookup); + if (batchname != NULL) { + if (batchfp != stdin) + fclose(batchfp); + batchname = NULL; + } + cancel_all(); + destroy_libs(); isc_app_finish(); -#endif return (exitcode); } diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index f6aea0ba957..41a8a84d652 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -1,21 +1,21 @@ /* * Copyright (C) 2000 Internet Software Consortium. - * + * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dighost.c,v 1.58.2.11 2000/09/15 22:56:12 gson Exp $ */ +/* $Id: dighost.c,v 1.58.2.12 2000/10/06 19:08:03 mws Exp $ */ /* * Notice to programmers: Do not use this code as an example of how to @@ -52,7 +52,6 @@ extern int h_errno; #include #include #include -#include #include #include #include @@ -64,18 +63,20 @@ extern int h_errno; #include ISC_LIST(dig_lookup_t) lookup_list; -ISC_LIST(dig_server_t) server_list; +dig_serverlist_t server_list; ISC_LIST(dig_searchlist_t) search_list; isc_boolean_t have_ipv6 = ISC_FALSE, specified_source = ISC_FALSE, free_now = ISC_FALSE, - show_details = ISC_FALSE, + cancel_now = ISC_FALSE, usesearch = ISC_FALSE, qr = ISC_FALSE, is_dst_up = ISC_FALSE, - ignore = ISC_FALSE; + have_domain = ISC_FALSE, + is_blocking =ISC_FALSE, + show_packets = ISC_FALSE; in_port_t port = 53; unsigned int timeout = 0; @@ -86,31 +87,76 @@ isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; isc_sockaddr_t bind_address; isc_sockaddr_t bind_any; -char *rootspace[BUFSIZE]; isc_buffer_t rootbuf; int sendcount = 0; +int recvcount = 0; int sockcount = 0; int ndots = -1; -int tries = 3; +int tries = 2; int lookup_counter = 0; char fixeddomain[MXNAME] = ""; -int exitcode = 9; +/* + * Exit Codes: + * 0 Everything went well, including things like NXDOMAIN + * 1 Usage error + * 7 Got too many RR's or Names + * 8 Couldn't open batch file + * 9 No reply from server + * 10 Internal error + */ +int exitcode = 0; char keynametext[MXNAME]; +char keyfile[MXNAME] = ""; char keysecret[MXNAME] = ""; dns_name_t keyname; -dns_tsig_keyring_t *keyring = NULL; isc_buffer_t *namebuf = NULL; dns_tsigkey_t *key = NULL; isc_boolean_t validated = ISC_TRUE; isc_entropy_t *entp = NULL; isc_mempool_t *commctx = NULL; -extern isc_boolean_t isc_mem_debugging; isc_boolean_t debugging = ISC_FALSE; char *progname = NULL; +isc_mutex_t lookup_lock; +dig_lookup_t *current_lookup = NULL; +isc_uint32_t name_limit = INT_MAX; +isc_uint32_t rr_limit = INT_MAX; -static isc_boolean_t +/* + * Apply and clear locks at the event level in global task. + * Can I get rid of these using shutdown events? XXX + */ +#define LOCK_LOOKUP {\ + debug("lock_lookup %s:%d", __FILE__, __LINE__);\ + check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\ + debug("success");\ +} +#define UNLOCK_LOOKUP {\ + debug("unlock_lookup %s:%d", __FILE__, __LINE__);\ + check_result(isc_mutex_unlock((&lookup_lock)),\ + "isc_mutex_unlock");\ +} + +static void cancel_lookup(dig_lookup_t *lookup); +static void +recv_done(isc_task_t *task, isc_event_t *event); + +static void +connect_timeout(isc_task_t *task, isc_event_t *event); + +char * +next_token(char **stringp, const char *delim) { + char *res; + + do { + res = strsep(stringp, delim); + if (res == NULL) + break; + } while (*res == '\0'); + return (res); +} + static int count_dots(char *string) { char *s; @@ -130,9 +176,9 @@ hex_dump(isc_buffer_t *b) { unsigned int len; isc_region_t r; - isc_buffer_remainingregion(b, &r); + isc_buffer_usedregion(b, &r); - printf("Printing a buffer with length %d\n", r.length); + printf("%d bytes\n", r.length); for (len = 0; len < r.length; len++) { printf("%02x ", r.base[len]); if (len != 0 && len % 16 == 0) @@ -146,22 +192,13 @@ void fatal(const char *format, ...) { va_list args; - fprintf (stderr, "%s: ", progname); - va_start(args, format); + fprintf(stderr, "%s: ", progname); + va_start(args, format); vfprintf(stderr, format, args); va_end(args); fprintf(stderr, "\n"); - if (exitcode == 0) - exitcode = 8; -#ifdef NEVER - dighost_shutdown(); - free_lists(exitcode); - if (mctx != NULL) { - if (isc_mem_debugging) - isc_mem_stats(mctx, stderr); - isc_mem_destroy(&mctx); - } -#endif + if (exitcode < 10) + exitcode = 10; exit(exitcode); } @@ -170,7 +207,7 @@ debug(const char *format, ...) { va_list args; if (debugging) { - va_start(args, format); + va_start(args, format); vfprintf(stderr, format, args); va_end(args); fprintf(stderr, "\n"); @@ -180,7 +217,6 @@ debug(const char *format, ...) { void check_result(isc_result_t result, const char *msg) { if (result != ISC_R_SUCCESS) { - exitcode = 1; fatal("%s: %s", msg, isc_result_totext(result)); } } @@ -202,98 +238,126 @@ make_server(const char *servname) { fatal("Memory allocation failure in %s:%d", __FILE__, __LINE__); strncpy(srv->servername, servname, MXNAME); + srv->servername[MXNAME-1] = 0; return (srv); } -isc_boolean_t -isclass(char *text) { - /* - * Tests if a field is a class, without needing isc libs - * initialized. This list will have to be manually kept in - * sync with what the libs support. - */ - const char *classlist[] = { "in", "hs", "chaos" }; - const int numclasses = 3; - int i; - - for (i = 0; i < numclasses; i++) - if (strcasecmp(text, classlist[i]) == 0) - return (ISC_TRUE); - - return (ISC_FALSE); -} +/* + * Produce a cloned server list. The dest list must have already had + * ISC_LIST_INIT applied. + */ +void +clone_server_list(dig_serverlist_t src, + dig_serverlist_t *dest) +{ + dig_server_t *srv, *newsrv; -isc_boolean_t -istype(char *text) { - /* - * Tests if a field is a type, without needing isc libs - * initialized. This list will have to be manually kept in - * sync with what the libs support. - */ - const char *typelist[] = {"a", "ns", "md", "mf", "cname", - "soa", "mb", "mg", "mr", "null", - "wks", "ptr", "hinfo", "minfo", - "mx", "txt", "rp", "afsdb", - "x25", "isdn", "rt", "nsap", - "nsap-ptr", "sig", "key", "px", - "gpos", "aaaa", "loc", "nxt", - "srv", "naptr", "kx", "cert", - "a6", "dname", "opt", "unspec", - "tkey", "tsig", "axfr", "any"}; - const int numtypes = 42; - int i; - - for (i = 0; i < numtypes; i++) { - if (strcasecmp(text, typelist[i]) == 0) - return (ISC_TRUE); + debug("clone_server_list()"); + srv = ISC_LIST_HEAD(src); + while (srv != NULL) { + newsrv = make_server(srv->servername); + ISC_LIST_ENQUEUE(*dest, newsrv, link); + srv = ISC_LIST_NEXT(srv, link); } - return (ISC_FALSE); } +/* + * Create an empty lookup structure, which holds all the information needed + * to get an answer to a user's question. This structure contains two + * linked lists: the server list (servers to query) and the query list + * (outstanding queries which have been made to the listed servers). + */ dig_lookup_t * -requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { +make_empty_lookup(void) { dig_lookup_t *looknew; - dig_server_t *s, *srv; - debug("requeue_lookup()"); + debug("make_empty_lookup()"); - if (free_now) - return(ISC_R_SUCCESS); + INSIST(!free_now); - lookup_counter++; - if (lookup_counter > LOOKUP_LIMIT) - fatal("Too many lookups"); looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup)); if (looknew == NULL) fatal("Memory allocation failure in %s:%d", __FILE__, __LINE__); - looknew->pending = ISC_FALSE; - strncpy(looknew->textname, lookold-> textname, MXNAME); - strncpy(looknew->rttext, lookold-> rttext, 32); - strncpy(looknew->rctext, lookold-> rctext, 32); - looknew->namespace[0] = 0; + looknew->pending = ISC_TRUE; + looknew->textname[0] = 0; + looknew->cmdline[0] = 0; /* Not copied in clone_lookup! */ + looknew->rdtype = dns_rdatatype_a; + looknew->rdclass = dns_rdataclass_in; looknew->sendspace = NULL; looknew->sendmsg = NULL; looknew->name = NULL; looknew->oname = NULL; looknew->timer = NULL; looknew->xfr_q = NULL; + looknew->current_query = NULL; + looknew->doing_xfr = ISC_FALSE; + looknew->ixfr_serial = ISC_FALSE; + looknew->defname = ISC_FALSE; + looknew->trace = ISC_FALSE; + looknew->trace_root = ISC_FALSE; + looknew->identify = ISC_FALSE; + looknew->ignore = ISC_FALSE; + looknew->servfail_stops = ISC_FALSE; + looknew->udpsize = 0; + looknew->recurse = ISC_TRUE; + looknew->aaonly = ISC_FALSE; + looknew->adflag = ISC_FALSE; + looknew->cdflag = ISC_FALSE; + looknew->ns_search_only = ISC_FALSE; + looknew->origin = NULL; + looknew->querysig = NULL; + looknew->retries = tries; + looknew->nsfound = 0; + looknew->tcp_mode = ISC_FALSE; + looknew->nibble = ISC_FALSE; + looknew->comments = ISC_TRUE; + looknew->stats = ISC_TRUE; + looknew->section_question = ISC_TRUE; + looknew->section_answer = ISC_TRUE; + looknew->section_authority = ISC_TRUE; + looknew->section_additional = ISC_TRUE; + looknew->new_search = ISC_FALSE; + ISC_LIST_INIT(looknew->q); + ISC_LIST_INIT(looknew->my_server_list); + return (looknew); +} + +/* + * Clone a lookup, perhaps copying the server list. This does not clone + * the query list, since it will be regenerated by the setup_lookup() + * function, nor does it queue up the new lookup for processing. + * Caution: If you don't clone the servers, you MUST clone the server + * list seperately from somewhere else, or construct it by hand. + */ +dig_lookup_t * +clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { + dig_lookup_t *looknew; + + debug("clone_lookup()"); + + INSIST(!free_now); + + looknew = make_empty_lookup(); + INSIST(looknew != NULL); + strncpy(looknew->textname, lookold-> textname, MXNAME); + looknew->textname[MXNAME-1]=0; + looknew->rdtype = lookold->rdtype; + looknew->rdclass = lookold->rdclass; looknew->doing_xfr = lookold->doing_xfr; looknew->ixfr_serial = lookold->ixfr_serial; looknew->defname = lookold->defname; looknew->trace = lookold->trace; looknew->trace_root = lookold->trace_root; looknew->identify = lookold->identify; + looknew->ignore = lookold->ignore; + looknew->servfail_stops = lookold->servfail_stops; looknew->udpsize = lookold->udpsize; looknew->recurse = lookold->recurse; - looknew->aaonly = lookold->aaonly; + looknew->aaonly = lookold->aaonly; looknew->adflag = lookold->adflag; looknew->cdflag = lookold->cdflag; looknew->ns_search_only = lookold->ns_search_only; - looknew->origin = NULL; - looknew->querysig = NULL; - looknew->retries = tries; - looknew->nsfound = 0; looknew->tcp_mode = lookold->tcp_mode; looknew->comments = lookold->comments; looknew->stats = lookold->stats; @@ -301,39 +365,153 @@ requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { looknew->section_answer = lookold->section_answer; looknew->section_authority = lookold->section_authority; looknew->section_additional = lookold->section_additional; - looknew->new_search = ISC_FALSE; - ISC_LIST_INIT(looknew->my_server_list); - ISC_LIST_INIT(looknew->q); + looknew->retries = lookold->retries; + + if (servers) + clone_server_list(lookold->my_server_list, + &looknew->my_server_list); + return (looknew); +} + +/* + * Requeue a lookup for further processing, perhaps copying the server + * list. The new lookup structure is returned to the caller, and is + * queued for processing. If servers are not cloned in the requeue, they + * must be added before allowing the current event to complete, since the + * completion of the event may result in the next entry on the lookup + * queue getting run. + */ +dig_lookup_t * +requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { + dig_lookup_t *looknew; + + debug("requeue_lookup()"); + + lookup_counter++; + if (lookup_counter > LOOKUP_LIMIT) + fatal("Too many lookups"); + + looknew = clone_lookup(lookold, servers); + INSIST(looknew != NULL); - looknew->use_my_server_list = ISC_FALSE; - if (servers) { - looknew->use_my_server_list = lookold->use_my_server_list; - if (looknew->use_my_server_list) { - s = ISC_LIST_HEAD(lookold->my_server_list); - while (s != NULL) { - srv = isc_mem_allocate(mctx, - sizeof(struct dig_server)); - if (srv == NULL) - fatal("Memory allocation failure " - "in %s:%d", __FILE__, __LINE__); - strncpy(srv->servername, s->servername, - MXNAME); - ISC_LIST_ENQUEUE(looknew->my_server_list, srv, - link); - s = ISC_LIST_NEXT(s, link); - } - } - } debug("before insertion, init@%p " "-> %p, new@%p -> %p", lookold, lookold->link.next, looknew, looknew->link.next); - ISC_LIST_INSERTAFTER(lookup_list, lookold, looknew, link); + ISC_LIST_PREPEND(lookup_list, looknew, link); debug("after insertion, init -> " - "%p, new = %p, new -> %p", + "%p, new = %p, new -> %p", lookold, looknew, looknew->link.next); return (looknew); -} +} + + +static void +setup_text_key(void) { + isc_result_t result; + isc_buffer_t secretbuf; + int secretsize; + unsigned char *secretstore; + isc_stdtime_t now; + + debug("setup_text_key()"); + result = isc_buffer_allocate(mctx, &namebuf, MXNAME); + check_result(result, "isc_buffer_allocate"); + dns_name_init(&keyname, NULL); + check_result(result, "dns_name_init"); + isc_buffer_putstr(namebuf, keynametext); + secretsize = strlen(keysecret) * 3 / 4; + secretstore = isc_mem_allocate(mctx, secretsize); + if (secretstore == NULL) + fatal("Memory allocation failure in %s:%d", + __FILE__, __LINE__); + isc_buffer_init(&secretbuf, secretstore, secretsize); + result = isc_base64_decodestring(mctx, keysecret, + &secretbuf); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", + keynametext, isc_result_totext(result)); + goto failure; + } + secretsize = isc_buffer_usedlength(&secretbuf); + isc_stdtime_get(&now); + + result = dns_name_fromtext(&keyname, namebuf, + dns_rootname, ISC_FALSE, + namebuf); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", + keynametext, dns_result_totext(result)); + goto failure; + } + result = dns_tsigkey_create(&keyname, dns_tsig_hmacmd5_name, + secretstore, secretsize, + ISC_TRUE, NULL, now, now, mctx, + NULL, &key); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", + keynametext, dns_result_totext(result)); + } + failure: + isc_mem_free(mctx, secretstore); + dns_name_invalidate(&keyname); + isc_buffer_free(&namebuf); +} + + +static void +setup_file_key(void) { + isc_result_t result; + isc_buffer_t secretbuf; + unsigned char *secretstore = NULL; + int secretlen; + dst_key_t *dstkey = NULL; + isc_stdtime_t now; + + debug("setup_file_key()"); + result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE, + mctx, &dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "Couldn't read key from %s: %s\n", + keyfile, isc_result_totext(result)); + goto failure; + } + /* + * Get key size in bits, convert to bytes, rounding up (?) + */ + secretlen = (dst_key_size(dstkey) + 7) >> 3; + secretstore = isc_mem_allocate(mctx, secretlen); + if (secretstore == NULL) + fatal("out of memory"); + isc_buffer_init(&secretbuf, secretstore, secretlen); + result = dst_key_tobuffer(dstkey, &secretbuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "Couldn't read key from %s: %s\n", + keyfile, isc_result_totext(result)); + goto failure; + } + isc_stdtime_get(&now); + dns_name_init(&keyname, NULL); + dns_name_clone(dst_key_name(dstkey), &keyname); + result = dns_tsigkey_create(&keyname, dns_tsig_hmacmd5_name, + secretstore, secretlen, + ISC_TRUE, NULL, now, now, mctx, + NULL, &key); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", + keynametext, dns_result_totext(result)); + } + failure: + if (dstkey != NULL) + dst_key_free(&dstkey); + if (secretstore != NULL) + isc_mem_free(mctx, secretstore); +} + +/* + * Setup the system as a whole, reading key information and resolv.conf + * settings. + */ void setup_system(void) { char rcinput[MXNAME]; @@ -341,16 +519,9 @@ setup_system(void) { char *ptr; dig_server_t *srv; dig_searchlist_t *search; - dig_lookup_t *l; isc_boolean_t get_servers; - isc_result_t result; - isc_buffer_t secretsrc; - isc_buffer_t secretbuf; - int secretsize; - unsigned char *secretstore; - isc_lex_t *lex = NULL; - isc_stdtime_t now; - + char *input; + debug("setup_system()"); if (fixeddomain[0] != 0) { @@ -359,41 +530,34 @@ setup_system(void) { if (search == NULL) fatal("Memory allocation failure in %s:%d", __FILE__, __LINE__); - strncpy(search->origin, fixeddomain, MXNAME - 1); + strncpy(search->origin, fixeddomain, + sizeof(search->origin)); + search->origin[sizeof(search->origin)-1]=0; + /* XXX Check ordering, with search -vs- domain */ ISC_LIST_PREPEND(search_list, search, link); } free_now = ISC_FALSE; get_servers = ISC_TF(server_list.head == NULL); fp = fopen(RESOLVCONF, "r"); + /* XXX Use lwres resolv.conf reader */ if (fp != NULL) { while (fgets(rcinput, MXNAME, fp) != 0) { - ptr = strtok(rcinput, " \t\r\n"); + input = rcinput; + ptr = next_token(&input, " \t\r\n"); if (ptr != NULL) { if (get_servers && strcasecmp(ptr, "nameserver") == 0) { debug("got a nameserver line"); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr != NULL) { - srv = isc_mem_allocate(mctx, - sizeof(struct dig_server)); - if (srv == NULL) - fatal("Memory " - "allocation " - "failure in " - "%s:%d", - __FILE__, - __LINE__); - strncpy((char *)srv-> - servername, - ptr, - MXNAME - 1); - ISC_LIST_APPEND - (server_list, - srv, link); + srv = make_server(ptr); + ISC_LIST_APPEND + (server_list, + srv, link); } } else if (strcasecmp(ptr, "options") == 0) { - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr != NULL) { if((strncasecmp(ptr, "ndots:", 6) == 0) && @@ -405,10 +569,11 @@ setup_system(void) { ndots); } } - } else if ((strcasecmp(ptr, "search") == 0) - && usesearch){ - while ((ptr = strtok(NULL, " \t\r\n")) + } else if (strcasecmp(ptr, "search") == 0){ + while ((ptr = next_token(&input, " \t\r\n")) != NULL) { + debug("adding search %s", + ptr); search = isc_mem_allocate( mctx, sizeof(struct dig_server)); @@ -416,12 +581,13 @@ setup_system(void) { fatal("Memory " "allocation " "failure in %s:" - "%d", __FILE__, + "%d", __FILE__, __LINE__); strncpy(search-> origin, ptr, - MXNAME - 1); + MXNAME); + search->origin[MXNAME-1]=0; ISC_LIST_APPEND (search_list, search, @@ -429,7 +595,8 @@ setup_system(void) { } } else if ((strcasecmp(ptr, "domain") == 0) && (fixeddomain[0] == 0 )){ - while ((ptr = strtok(NULL, " \t\r\n")) + have_domain = ISC_TRUE; + while ((ptr = next_token(&input, " \t\r\n")) != NULL) { search = isc_mem_allocate( mctx, sizeof(struct @@ -438,12 +605,13 @@ setup_system(void) { fatal("Memory " "allocation " "failure in %s:" - "%d", __FILE__, + "%d", __FILE__, __LINE__); strncpy(search-> origin, ptr, MXNAME - 1); + search->origin[MXNAME-1]=0; ISC_LIST_PREPEND (search_list, search, @@ -459,89 +627,19 @@ setup_system(void) { ndots = 1; if (server_list.head == NULL) { - srv = isc_mem_allocate(mctx, sizeof(dig_server_t)); - if (srv == NULL) - fatal("Memory allocation failure"); - strcpy(srv->servername, "127.0.0.1"); + srv = make_server("127.0.0.1"); ISC_LIST_APPEND(server_list, srv, link); } - for (l = ISC_LIST_HEAD(lookup_list) ; - l != NULL; - l = ISC_LIST_NEXT(l, link) ) { - l -> origin = ISC_LIST_HEAD(search_list); - } - - if (keysecret[0] != 0) { - debug("keyring"); - result = dns_tsigkeyring_create(mctx, &keyring); - check_result(result, "dns_tsigkeyring_create"); - debug("buffer"); - result = isc_buffer_allocate(mctx, &namebuf, MXNAME); - check_result(result, "isc_buffer_allocate"); - debug("name"); - dns_name_init(&keyname, NULL); - check_result(result, "dns_name_init"); - isc_buffer_putstr(namebuf, keynametext); - secretsize = strlen(keysecret) * 3 / 4; - debug("secretstore"); - secretstore = isc_mem_allocate(mctx, secretsize); - if (secretstore == NULL) - fatal("Memory allocation failure in %s:%d", - __FILE__, __LINE__); - isc_buffer_init(&secretsrc, keysecret, strlen(keysecret)); - isc_buffer_add(&secretsrc, strlen(keysecret)); - isc_buffer_init(&secretbuf, secretstore, secretsize); - debug("lex"); - result = isc_lex_create(mctx, strlen(keysecret), &lex); - check_result(result, "isc_lex_create"); - result = isc_lex_openbuffer(lex, &secretsrc); - check_result(result, "isc_lex_openbuffer"); - result = isc_base64_tobuffer(lex, &secretbuf, -1); - if (result != ISC_R_SUCCESS) { - printf(";; Couldn't create key %s: %s\n", - keynametext, isc_result_totext(result)); - isc_lex_close(lex); - isc_lex_destroy(&lex); - goto SYSSETUP_FAIL; - } - secretsize = isc_buffer_usedlength(&secretbuf); - debug("close"); - isc_lex_close(lex); - isc_lex_destroy(&lex); - isc_stdtime_get(&now); - - debug("namefromtext"); - result = dns_name_fromtext(&keyname, namebuf, - dns_rootname, ISC_FALSE, - namebuf); - if (result != ISC_R_SUCCESS) { - printf (";; Couldn't create key %s: %s\n", - keynametext, dns_result_totext(result)); - goto SYSSETUP_FAIL; - } - debug("tsigkey"); - result = dns_tsigkey_create(&keyname, dns_tsig_hmacmd5_name, - secretstore, secretsize, - ISC_TRUE, NULL, now, now, mctx, - keyring, &key); - if (result != ISC_R_SUCCESS) { - printf(";; Couldn't create key %s: %s\n", - keynametext, dns_result_totext(result)); - } - isc_mem_free(mctx, secretstore); - dns_name_invalidate(&keyname); - isc_buffer_free(&namebuf); - return; - SYSSETUP_FAIL: - isc_mem_free(mctx, secretstore); - dns_name_invalidate(&keyname); - isc_buffer_free(&namebuf); - dns_tsigkeyring_destroy(&keyring); - return; - } + if (keyfile[0] != 0) + setup_file_key(); + else if (keysecret[0] != 0) + setup_text_key(); } - + +/* + * Setup the ISC and DNS libraries for use by the system. + */ void setup_libs(void) { isc_result_t result; @@ -555,9 +653,6 @@ setup_libs(void) { */ srandom(getpid() + (int)&setup_libs); - result = isc_app_start(); - check_result(result, "isc_app_start"); - result = isc_net_probeipv4(); check_result(result, "isc_net_probeipv4"); @@ -596,8 +691,17 @@ setup_libs(void) { */ isc_mempool_setfreemax(commctx, 6); isc_mempool_setfillcount(commctx, 2); + + result = isc_mutex_init(&lookup_lock); + check_result(result, "isc_mutex_init"); + + dns_result_register(); } +/* + * Add EDNS0 option record to a message. Currently, the only supported + * option is UDP buffer size. + */ static void add_opt(dns_message_t *msg, isc_uint16_t udpsize) { dns_rdataset_t *rdataset = NULL; @@ -613,7 +717,7 @@ add_opt(dns_message_t *msg, isc_uint16_t udpsize) { check_result(result, "dns_message_gettemprdatalist"); result = dns_message_gettemprdata(msg, &rdata); check_result(result, "dns_message_gettemprdata"); - + debug("setting udp size of %d", udpsize); rdatalist->type = dns_rdatatype_opt; rdatalist->covers = 0; @@ -628,6 +732,10 @@ add_opt(dns_message_t *msg, isc_uint16_t udpsize) { check_result(result, "dns_message_setopt"); } +/* + * Add a question section to a message, asking for the specified name, + * type, and class. + */ static void add_question(dns_message_t *message, dns_name_t *name, dns_rdataclass_t rdclass, dns_rdatatype_t rdtype) @@ -635,7 +743,7 @@ add_question(dns_message_t *message, dns_name_t *name, dns_rdataset_t *rdataset; isc_result_t result; - debug("add_question()"); + debug("add_question()"); rdataset = NULL; result = dns_message_gettemprdataset(message, &rdataset); check_result(result, "dns_message_gettemprdataset()"); @@ -645,76 +753,177 @@ add_question(dns_message_t *message, dns_name_t *name, } /* - * Return ISC_TRUE if we're in the process of shutting down on the - * return. + * Check if we're done with all the queued lookups, which is true iff + * all sockets, sends, and recvs are accounted for (counters == 0), + * and the lookup list is empty. + * If we are done, pass control back out to dighost_shutdown() (which is + * part of dig.c, host.c, or nslookup.c) to either shutdown the system as + * a whole or reseed the lookup list. + */ +static void +check_if_done(void) { + debug("check_if_done()"); + debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full"); + if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL && + sendcount == 0) { + INSIST(sockcount == 0); + INSIST(recvcount == 0); + debug("shutting down"); + dighost_shutdown(); + } +} + +/* + * Clear out a query when we're done with it. WARNING: This routine + * WILL invalidate the query pointer. + */ +static void +clear_query(dig_query_t *query) { + dig_lookup_t *lookup; + + REQUIRE(query != NULL); + + debug("clear_query(%p)",query); + + lookup = query->lookup; + + if (lookup->current_query == query) + lookup->current_query = NULL; + + ISC_LIST_UNLINK(lookup->q, query, link); + if (ISC_LINK_LINKED(&query->recvbuf, link)) + ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf, + link); + if (ISC_LINK_LINKED(&query->lengthbuf, link)) + ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf, + link); + INSIST(query->recvspace != NULL); + if (query->sock != NULL) { + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + } + isc_mempool_put(commctx, query->recvspace); + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_invalidate(&query->lengthbuf); + isc_mem_free(mctx, query); +} + +/* + * Try and clear out a lookup if we're done with it. Return ISC_TRUE if + * the lookup was successfully cleared. If ISC_TRUE is returned, the + * lookup pointer has been invalidated. */ static isc_boolean_t -check_next_lookup(dig_lookup_t *lookup) { - dig_lookup_t *next; - dig_query_t *query; - isc_boolean_t still_working=ISC_FALSE; - - if (free_now) - return (ISC_TRUE); +try_clear_lookup(dig_lookup_t *lookup) { + dig_server_t *s; + dig_query_t *q; + void *ptr; - debug("check_next_lookup(%p)", lookup); - for (query = ISC_LIST_HEAD(lookup->q); - query != NULL; - query = ISC_LIST_NEXT(query, link)) { - if (query->working) { - debug("still have a worker", stderr); - still_working=ISC_TRUE; + REQUIRE(lookup != NULL); + + debug("try_clear_lookup(%p)", lookup); + + if (ISC_LIST_HEAD(lookup->q) != NULL) { + if (debugging) { + q = ISC_LIST_HEAD(lookup->q); + while (q != NULL) { + debug("query to %s still pending", + q->servname); + q = ISC_LIST_NEXT(q, link); + } + return (ISC_FALSE); } } - if (still_working) - return (ISC_FALSE); + /* + * At this point, we know there are no queries on the lookup, + * so can make it go away also. + */ + debug("cleared"); + s = ISC_LIST_HEAD(lookup->my_server_list); + while (s != NULL) { + debug("freeing server %p belonging to %p", + s, lookup); + ptr = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(lookup->my_server_list, + (dig_server_t *)ptr, link); + isc_mem_free(mctx, ptr); + } + if (lookup->sendmsg != NULL) + dns_message_destroy(&lookup->sendmsg); + if (lookup->querysig != NULL) { + debug("freeing buffer %p", lookup->querysig); + isc_buffer_free(&lookup->querysig); + } + if (lookup->timer != NULL) + isc_timer_detach(&lookup->timer); + if (lookup->sendspace != NULL) + isc_mempool_put(commctx, lookup->sendspace); - debug("have %d retries left for %s", - lookup->retries-1, lookup->textname); - debug("lookup %s pending", lookup->pending ? "is" : "is not"); + isc_mem_free(mctx, lookup); + return (ISC_TRUE); +} - next = ISC_LIST_NEXT(lookup, link); - - if (lookup->tcp_mode) { - if (next == NULL) { - debug("shutting down", stderr); - dighost_shutdown(); - return (ISC_TRUE); - } - if (next->sendmsg == NULL) { - debug("setting up for TCP"); - setup_lookup(next); - do_lookup(next); - } + +/* + * If we can, start the next lookup in the queue running. + * This assumes that the lookup on the head of the queue hasn't been + * started yet. It also removes the lookup from the head of the queue, + * setting the current_lookup pointer pointing to it. + */ +void +start_lookup(void) { + debug("start_lookup()"); + if (cancel_now) + return; + + /* + * If there's a current lookup running, we really shouldn't get + * here. + */ + INSIST(current_lookup == NULL); + + current_lookup = ISC_LIST_HEAD(lookup_list); + /* + * Put the current lookup somewhere so cancel_all can find it + */ + if (current_lookup != NULL) { + ISC_LIST_DEQUEUE(lookup_list, current_lookup, link); + setup_lookup(current_lookup); + do_lookup(current_lookup); } else { - if (!lookup->pending) { - if (next == NULL) { - debug("shutting down", stderr); - dighost_shutdown(); - return (ISC_TRUE); - } - if (next->sendmsg == NULL) { - debug("setting up for UDP"); - setup_lookup(next); - do_lookup(next); - } - } else { - if (lookup->retries > 1) { - debug("retrying"); - lookup->retries --; - if (lookup->timer != NULL) - isc_timer_detach(&lookup->timer); - send_udp(lookup); - } else { - debug("cancelling"); - return(cancel_lookup(lookup)); - } - } + check_if_done(); } - return (ISC_FALSE); } +/* + * If we can, clear the current lookup and start the next one running. + * This calls try_clear_lookup, so may invalidate the lookup pointer. + */ +static void +check_next_lookup(dig_lookup_t *lookup) { + + INSIST(!free_now); + + debug("check_next_lookup(%p)", lookup); + if (ISC_LIST_HEAD(lookup->q) != NULL) { + debug("still have a worker"); + return; + } + if (try_clear_lookup(lookup)) { + current_lookup = NULL; + start_lookup(); + } +} + +/* + * Create and queue a new lookup as a followup to the current lookup, + * based on the supplied message and section. This is used in trace and + * name server search modes to start a new lookup using servers from + * NS records in a reply. + */ static void followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section) { @@ -729,16 +938,17 @@ followup_lookup(dns_message_t *msg, dig_query_t *query, isc_boolean_t success = ISC_FALSE; int len; - debug("followup_lookup()"); - if (free_now) - return; + INSIST(!free_now); + + debug("followup_lookup()"); result = dns_message_firstname(msg,section); + if (result != ISC_R_SUCCESS) { debug("firstname returned %s", isc_result_totext(result)); if ((section == DNS_SECTION_ANSWER) && (query->lookup->trace || query->lookup->ns_search_only)) - followup_lookup (msg, query, DNS_SECTION_AUTHORITY); + followup_lookup(msg, query, DNS_SECTION_AUTHORITY); return; } @@ -757,7 +967,7 @@ followup_lookup(dns_message_t *msg, dig_query_t *query, rdata.type); if ((rdata.type == dns_rdatatype_ns) && (!query->lookup->trace_root || - (query->lookup->nsfound < ROOTNS))) + (query->lookup->nsfound < MXSERV))) { query->lookup->nsfound++; result = isc_buffer_allocate(mctx, &b, @@ -780,13 +990,12 @@ followup_lookup(dns_message_t *msg, dig_query_t *query, if (!success) { success = ISC_TRUE; lookup_counter++; + cancel_lookup(query->lookup); lookup = requeue_lookup (query->lookup, ISC_FALSE); lookup->doing_xfr = ISC_FALSE; lookup->defname = ISC_FALSE; - lookup->use_my_server_list = - ISC_TRUE; if (section == DNS_SECTION_ANSWER) { lookup->trace = @@ -803,20 +1012,11 @@ followup_lookup(dns_message_t *msg, dig_query_t *query, lookup->ns_search_only; } lookup->trace_root = ISC_FALSE; - ISC_LIST_INIT(lookup-> - my_server_list); } - srv = isc_mem_allocate(mctx, - sizeof(struct dig_server)); - if (srv == NULL) - fatal("Memory allocation " - "failure in %s:%d", - __FILE__, __LINE__); - strncpy(srv->servername, - (char *)r.base, len); - srv->servername[len] = 0; + r.base[len] = 0; + srv = make_server((char *)r.base); debug("adding server %s", - srv->servername); + srv->servername); ISC_LIST_APPEND (lookup->my_server_list, srv, link); @@ -825,7 +1025,7 @@ followup_lookup(dns_message_t *msg, dig_query_t *query, loopresult = dns_rdataset_next(rdataset); } } - result = dns_message_nextname (msg, section); + result = dns_message_nextname(msg, section); if (result != ISC_R_SUCCESS) break; } @@ -834,30 +1034,43 @@ followup_lookup(dns_message_t *msg, dig_query_t *query, followup_lookup(msg, query, DNS_SECTION_AUTHORITY); } -static void +/* + * Create and queue a new lookup using the next origin from the origin + * list, read in setup_system(). + */ +static isc_boolean_t next_origin(dns_message_t *msg, dig_query_t *query) { dig_lookup_t *lookup; UNUSED(msg); - debug("next_origin()"); - if (free_now) - return; + INSIST(!free_now); + + debug("next_origin()"); debug("following up %s", query->lookup->textname); - if (query->lookup->origin == NULL) { + if (!usesearch) + /* + * We're not using a search list, so don't even think + * about finding the next entry. + */ + return (ISC_FALSE); + if (query->lookup->origin == NULL) /* * Then we just did rootorg; there's nothing left. */ - debug("made it to the root with nowhere to go"); - return; - } + return (ISC_FALSE); + cancel_lookup(query->lookup); lookup = requeue_lookup(query->lookup, ISC_TRUE); lookup->defname = ISC_FALSE; lookup->origin = ISC_LIST_NEXT(query->lookup->origin, link); + return (ISC_TRUE); } - +/* + * Insert an SOA record into the sendmessage in a lookup. Used for + * creating IXFR queries. + */ static void insert_soa(dig_lookup_t *lookup) { isc_result_t result; @@ -866,7 +1079,7 @@ insert_soa(dig_lookup_t *lookup) { dns_rdatalist_t *rdatalist = NULL; dns_rdataset_t *rdataset = NULL; dns_name_t *soaname = NULL; - + debug("insert_soa()"); soa.mctx = mctx; soa.serial = lookup->ixfr_serial; @@ -874,7 +1087,7 @@ insert_soa(dig_lookup_t *lookup) { soa.retry = 1; soa.expire = 1; soa.minimum = 1; - soa.common.rdclass = dns_rdataclass_in; + soa.common.rdclass = lookup->rdclass; soa.common.rdtype = dns_rdatatype_soa; dns_name_init(&soa.origin, NULL); @@ -882,26 +1095,27 @@ insert_soa(dig_lookup_t *lookup) { dns_name_clone(lookup->name, &soa.origin); dns_name_clone(lookup->name, &soa.mname); - + isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore, - MXNAME); + sizeof(lookup->rdatastore)); result = dns_message_gettemprdata(lookup->sendmsg, &rdata); check_result(result, "dns_message_gettemprdata"); - result = dns_rdata_fromstruct(rdata, dns_rdataclass_in, + + result = dns_rdata_fromstruct(rdata, lookup->rdclass, dns_rdatatype_soa, &soa, &lookup->rdatabuf); check_result(result, "isc_rdata_fromstruct"); result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist); check_result(result, "dns_message_gettemprdatalist"); - + result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset); check_result(result, "dns_message_gettemprdataset"); dns_rdatalist_init(rdatalist); rdatalist->type = dns_rdatatype_soa; - rdatalist->rdclass = dns_rdataclass_in; + rdatalist->rdclass = lookup->rdclass; rdatalist->covers = dns_rdatatype_soa; rdatalist->ttl = 1; ISC_LIST_INIT(rdatalist->rdata); @@ -919,29 +1133,26 @@ insert_soa(dig_lookup_t *lookup) { dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY); } +/* + * Setup the supplied lookup structure, making it ready to start sending + * queries to servers. Create and initialize the message to be sent as + * well as the query structures and buffer space for the replies. If the + * server list is empty, clone it from the system default list. + */ void setup_lookup(dig_lookup_t *lookup) { - isc_result_t result, res2; + isc_result_t result; int len; - dns_rdatatype_t rdtype; - dns_rdataclass_t rdclass; dig_server_t *serv; dig_query_t *query; isc_region_t r; - isc_constregion_t tr; isc_buffer_t b; char store[MXNAME]; - - REQUIRE(lookup != NULL); - debug("setup_lookup(%p)",lookup); - - if (free_now) - return; + REQUIRE(lookup != NULL); + INSIST(!free_now); - debug("setting up for looking up %s @%p->%p", - lookup->textname, lookup, - lookup->link.next); + debug("setup_lookup(%p)", lookup); result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &lookup->sendmsg); @@ -952,6 +1163,10 @@ setup_lookup(dig_lookup_t *lookup) { lookup_counter = 0; } + if (ISC_LIST_EMPTY(lookup->my_server_list)) { + debug("cloning server list"); + clone_server_list(server_list, &lookup->my_server_list); + } result = dns_message_gettempname(lookup->sendmsg, &lookup->name); check_result(result, "dns_message_gettempname"); dns_name_init(lookup->name, NULL); @@ -961,15 +1176,26 @@ setup_lookup(dig_lookup_t *lookup) { isc_buffer_init(&lookup->onamebuf, lookup->onamespace, sizeof(lookup->onamespace)); + /* + * If the name has too many dots, force the origin to be NULL + * (which produces an absolute lookup). Otherwise, take the origin + * we have if there's one in the struct already. If it's NULL, + * take the first entry in the searchlist iff either usesearch + * is TRUE or we got a domain line in the resolv.conf file. + */ + /* XXX New search here? */ if ((count_dots(lookup->textname) >= ndots) || lookup->defname) - lookup->origin = NULL; /* Force root lookup */ - debug("lookup->origin = %p", lookup->origin); + lookup->origin = NULL; /* Force abs lookup */ + else if (lookup->origin == NULL && lookup->new_search && + (usesearch || have_domain)) + lookup->origin = ISC_LIST_HEAD(search_list); if (lookup->origin != NULL) { debug("trying origin %s", lookup->origin->origin); result = dns_message_gettempname(lookup->sendmsg, &lookup->oname); check_result(result, "dns_message_gettempname"); dns_name_init(lookup->oname, NULL); + /* XXX Helper funct to conv char* to name? */ len = strlen(lookup->origin->origin); isc_buffer_init(&b, lookup->origin->origin, len); isc_buffer_add(&b, len); @@ -980,26 +1206,26 @@ setup_lookup(dig_lookup_t *lookup) { &lookup->name); dns_message_puttempname(lookup->sendmsg, &lookup->oname); - fatal("%s is not a legal name syntax (%s)", + fatal("'%s' is not in legal name syntax (%s)", lookup->origin->origin, dns_result_totext(result)); } - if (!lookup->trace_root) { + if (lookup->trace_root) { + dns_name_clone(dns_rootname, lookup->name); + } else { len = strlen(lookup->textname); isc_buffer_init(&b, lookup->textname, len); isc_buffer_add(&b, len); result = dns_name_fromtext(lookup->name, &b, - lookup->oname, ISC_FALSE, + lookup->oname, ISC_FALSE, &lookup->namebuf); - } else { - dns_name_clone(dns_rootname, lookup->name); - } + } if (result != ISC_R_SUCCESS) { dns_message_puttempname(lookup->sendmsg, &lookup->name); dns_message_puttempname(lookup->sendmsg, &lookup->oname); - fatal("%s is not a legal name syntax (%s)", + fatal("'%s' is not in legal name syntax (%s)", lookup->textname, dns_result_totext(result)); } dns_message_puttempname(lookup->sendmsg, &lookup->oname); @@ -1020,23 +1246,17 @@ setup_lookup(dig_lookup_t *lookup) { dns_message_puttempname(lookup->sendmsg, &lookup->name); isc_buffer_init(&b, store, MXNAME); - res2 = dns_name_totext(dns_rootname, ISC_FALSE, &b); - check_result(res2, "dns_name_totext"); - isc_buffer_usedregion(&b, &r); - fatal("%s/%.*s is not a legal name syntax " - "(%s)", lookup->textname, (int)r.length, - (char *)r.base, dns_result_totext(result)); + fatal("'%s' is not a legal name syntax " + "(%s)", lookup->textname, + dns_result_totext(result)); } - } - isc_buffer_init(&b, store, MXNAME); + } + isc_buffer_init(&b, store, sizeof(store)); + /* XXX Move some of this into function, dns_name_format. */ dns_name_totext(lookup->name, ISC_FALSE, &b); isc_buffer_usedregion(&b, &r); trying((int)r.length, (char *)r.base, lookup); - ENSURE(dns_name_isabsolute(lookup->name)); - if (lookup->rctext[0] == 0) - strcpy(lookup->rctext, "IN"); - if (lookup->rttext[0] == 0) - strcpy(lookup->rttext, "A"); + INSIST(dns_name_isabsolute(lookup->name)); lookup->sendmsg->id = (unsigned short)(random() & 0xFFFF); lookup->sendmsg->opcode = dns_opcode_query; @@ -1050,6 +1270,7 @@ setup_lookup(dig_lookup_t *lookup) { lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD; } + /* XXX aaflag */ if (lookup->aaonly) { debug("AA query"); lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA; @@ -1068,45 +1289,32 @@ setup_lookup(dig_lookup_t *lookup) { dns_message_addname(lookup->sendmsg, lookup->name, DNS_SECTION_QUESTION); - if (lookup->trace_root) { - debug("doing trace_root"); - tr.base = "SOA"; - tr.length = 3; - } else { - tr.base = lookup->rttext; - tr.length = strlen(lookup->rttext); - } - debug("data type is %s", lookup->rttext); - result = dns_rdatatype_fromtext(&rdtype, (isc_textregion_t *)&tr); - check_result(result, "dns_rdatatype_fromtext"); - if ((rdtype == dns_rdatatype_axfr) || - (rdtype == dns_rdatatype_ixfr)) { + if (lookup->trace_root) + lookup->rdtype = dns_rdatatype_soa; + + if ((lookup->rdtype == dns_rdatatype_axfr) || + (lookup->rdtype == dns_rdatatype_ixfr)) { lookup->doing_xfr = ISC_TRUE; /* * Force TCP mode if we're doing an xfr. + * XXX UDP ixfr's would be useful */ lookup->tcp_mode = ISC_TRUE; } - if (lookup->trace_root) { - tr.base = "IN"; - tr.length = 2; - } else { - tr.base = lookup->rctext; - tr.length = strlen(lookup->rctext); - } - result = dns_rdataclass_fromtext(&rdclass, (isc_textregion_t *)&tr); - check_result(result, "dns_rdataclass_fromtext"); - add_question(lookup->sendmsg, lookup->name, rdclass, rdtype); + add_question(lookup->sendmsg, lookup->name, lookup->rdclass, + lookup->rdtype); - if (rdtype == dns_rdatatype_ixfr) + /* XXX add_soa */ + if (lookup->rdtype == dns_rdatatype_ixfr) insert_soa(lookup); + /* XXX Insist this? */ + lookup->tsigctx = NULL; + lookup->querysig = NULL; if (key != NULL) { debug("initializing keys"); result = dns_message_settsigkey(lookup->sendmsg, key); check_result(result, "dns_message_settsigkey"); - lookup->tsigctx = NULL; - lookup->querysig = NULL; } lookup->sendspace = isc_mempool_get(commctx); @@ -1117,9 +1325,9 @@ setup_lookup(dig_lookup_t *lookup) { isc_buffer_init(&lookup->sendbuf, lookup->sendspace, COMMSIZE); result = dns_message_renderbegin(lookup->sendmsg, &lookup->sendbuf); check_result(result, "dns_message_renderbegin"); - if (lookup->udpsize > 0) { + if (lookup->udpsize > 0) add_opt(lookup->sendmsg, lookup->udpsize); - } + result = dns_message_rendersection(lookup->sendmsg, DNS_SECTION_QUESTION, 0); check_result(result, "dns_message_rendersection"); @@ -1132,11 +1340,8 @@ setup_lookup(dig_lookup_t *lookup) { lookup->pending = ISC_FALSE; - if (lookup->use_my_server_list) - serv = ISC_LIST_HEAD(lookup->my_server_list); - else - serv = ISC_LIST_HEAD(server_list); - for (; serv != NULL; + for (serv = ISC_LIST_HEAD(lookup->my_server_list); + serv != NULL; serv = ISC_LIST_NEXT(serv, link)) { query = isc_mem_allocate(mctx, sizeof(dig_query_t)); if (query == NULL) @@ -1145,14 +1350,15 @@ setup_lookup(dig_lookup_t *lookup) { debug("create query %p linked to lookup %p", query, lookup); query->lookup = lookup; - query->working = ISC_FALSE; query->waiting_connect = ISC_FALSE; + query->recv_made = ISC_FALSE; query->first_pass = ISC_TRUE; query->first_soa_rcvd = ISC_FALSE; query->second_rr_rcvd = ISC_FALSE; query->second_rr_serial = 0; query->servname = serv->servername; - ISC_LIST_INIT(query->sendlist); + query->name_count = 0; + query->rr_count = 0; ISC_LIST_INIT(query->recvlist); ISC_LIST_INIT(query->lengthlist); query->sock = NULL; @@ -1166,208 +1372,355 @@ setup_lookup(dig_lookup_t *lookup) { ISC_LIST_ENQUEUE(lookup->q, query, link); } + /* XXX qrflag, print_query, etc... */ if (!ISC_LIST_EMPTY(lookup->q) && qr) { printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg, ISC_TRUE); } -} +} +/* + * Event handler for send completion. Track send counter, and clear out + * the query if the send was canceled. + */ static void -send_done(isc_task_t *task, isc_event_t *event) { - UNUSED(task); +send_done(isc_task_t *_task, isc_event_t *event) { + REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); + + UNUSED(_task); + + LOCK_LOOKUP; isc_event_free(&event); debug("send_done()"); + sendcount--; + debug("sendcount=%d", sendcount); + INSIST(sendcount >= 0); + check_if_done(); + UNLOCK_LOOKUP; } /* - * Return ISC_TRUE if we're in the process of shutting down + * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding + * IO sockets. The cancel handlers should take care of cleaning up the + * query and lookup structures */ -static isc_boolean_t +static void cancel_lookup(dig_lookup_t *lookup) { - dig_query_t *query = NULL; + dig_query_t *query, *next; debug("cancel_lookup()"); - for (query = ISC_LIST_HEAD(lookup->q); - query != NULL; - query = ISC_LIST_NEXT(query, link)) { - if (query->working) { - debug("cancelling a worker"); - } + query = ISC_LIST_HEAD(lookup->q); + while (query != NULL) { + next = ISC_LIST_NEXT(query, link); if (query->sock != NULL) { isc_socket_cancel(query->sock, global_task, ISC_SOCKCANCEL_ALL); - isc_socket_detach(&query->sock); - sockcount--; - debug("socket = %d", sockcount); + check_if_done(); + } else { + clear_query(query); } + query = next; } + if (lookup->timer != NULL) + isc_timer_detach(&lookup->timer); lookup->pending = ISC_FALSE; lookup->retries = 0; - return(check_next_lookup(lookup)); } static void -recv_done(isc_task_t *task, isc_event_t *event); +bringup_timer(dig_query_t *query, unsigned int default_timeout) { + dig_lookup_t *l; + unsigned int local_timeout; + isc_result_t result; + + debug("bringup_timer()"); + /* + * If the timer already exists, that means we're calling this + * a second time (for a retry). Don't need to recreate it, + * just reset it. + */ + l = query->lookup; + if (ISC_LIST_NEXT(query, link) != NULL) + local_timeout = SERVER_TIMEOUT; + else { + if (timeout == 0) { + local_timeout = default_timeout; + } else + local_timeout = timeout; + } + debug("have local timeout of %d", local_timeout); + isc_interval_set(&l->interval, local_timeout, 0); + if (l->timer != NULL) + isc_timer_detach(&l->timer); + result = isc_timer_create(timermgr, + isc_timertype_once, + NULL, + &l->interval, + global_task, + connect_timeout, + l, &l->timer); + check_result(result, "isc_timer_create"); +} static void -connect_timeout(isc_task_t *task, isc_event_t *event); +connect_done(isc_task_t *task, isc_event_t *event); -void -send_udp(dig_lookup_t *lookup) { - dig_query_t *query; +/* + * Unlike send_udp, this can't be called multiple times with the same + * query. When we retry TCP, we requeue the whole lookup, which should + * start anew. + */ +static void +send_tcp_connect(dig_query_t *query) { isc_result_t result; - unsigned int local_timeout; + dig_query_t *next; + dig_lookup_t *l; - debug("send_udp()"); + debug("send_tcp_connect(%lx)", query); - if (timeout != INT_MAX) { - if (timeout == 0) { - if (lookup->tcp_mode) - local_timeout = TCP_TIMEOUT; - else - local_timeout = UDP_TIMEOUT; - } else - local_timeout = timeout; - debug ("have local timeout of %d", local_timeout); - isc_interval_set(&lookup->interval, local_timeout, 0); - result = isc_timer_create(timermgr, isc_timertype_once, NULL, - &lookup->interval, global_task, - connect_timeout, lookup, - &lookup->timer); - check_result(result, "isc_timer_create"); - } -for (query = ISC_LIST_HEAD(lookup->q); - query != NULL; - query = ISC_LIST_NEXT(query, link)) { - debug("working on lookup %p, query %p", - query->lookup, query); - ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link); - query->working = ISC_TRUE; + l = query->lookup; + query->waiting_connect = ISC_TRUE; + query->lookup->current_query = query; + get_address(query->servname, port, &query->sockaddr); + + if (specified_source && + (isc_sockaddr_pf(&query->sockaddr) != + isc_sockaddr_pf(&bind_address))) { + printf(";; Skipping server %s, incompatible " + "address family\n", query->servname); + query->waiting_connect = ISC_FALSE; + next = ISC_LIST_NEXT(query, link); + l = query->lookup; + clear_query(query); + if (next == NULL) { + printf(";; No acceptable nameservers\n"); + check_next_lookup(l); + return; + } + send_tcp_connect(next); + return; + } + INSIST(query->sock == NULL); + result = isc_socket_create(socketmgr, + isc_sockaddr_pf(&query->sockaddr), + isc_sockettype_tcp, &query->sock) ; + check_result(result, "isc_socket_create"); + sockcount++; + debug("sockcount=%d",sockcount); + if (specified_source) + result = isc_socket_bind(query->sock, &bind_address); + else { + if (isc_sockaddr_pf(&query->sockaddr) == AF_INET) + isc_sockaddr_any(&bind_any); + else + isc_sockaddr_any6(&bind_any); + result = isc_socket_bind(query->sock, &bind_any); + } + check_result(result, "isc_socket_bind"); + bringup_timer(query, TCP_TIMEOUT); + result = isc_socket_connect(query->sock, &query->sockaddr, + global_task, connect_done, query); + check_result(result, "isc_socket_connect"); + /* + * If we're doing a nameserver search, we need to immediately + * bring up all the queries. Do it here. + */ + if (l->ns_search_only) { + debug("sending next, since searching"); + next = ISC_LIST_NEXT(query, link); + if (next != NULL) + send_tcp_connect(next); + } +} + +/* + * Send a UDP packet to the remote nameserver, possible starting the + * recv action as well. Also make sure that the timer is running and + * is properly reset. + */ +static void +send_udp(dig_query_t *query) { + dig_lookup_t *l = NULL; + dig_query_t *next; + isc_result_t result; + + debug("send_udp(%lx)", query); + + l = query->lookup; + bringup_timer(query, UDP_TIMEOUT); + l->current_query = query; + debug("working on lookup %p, query %p", + query->lookup, query); + if (!query->recv_made) { + /* XXX Check the sense of this, need assertion? */ + query->waiting_connect = ISC_FALSE; + get_address(query->servname, port, &query->sockaddr); + + result = isc_socket_create(socketmgr, + isc_sockaddr_pf(&query->sockaddr), + isc_sockettype_udp, &query->sock); + check_result(result, "isc_socket_create"); + sockcount++; + debug("sockcount=%d", sockcount); + if (specified_source) { + result = isc_socket_bind(query->sock, &bind_address); + } else { + isc_sockaddr_anyofpf(&bind_any, + isc_sockaddr_pf(&query->sockaddr)); + result = isc_socket_bind(query->sock, &bind_any); + } + check_result(result, "isc_socket_bind"); + + query->recv_made = ISC_TRUE; + ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, + link); debug("recving with lookup=%p, query=%p, sock=%p", - query->lookup, query, - query->sock); - result = isc_socket_recvv(query->sock, &query->recvlist, 1, - global_task, recv_done, query); + query->lookup, query, + query->sock); + result = isc_socket_recvv(query->sock, + &query->recvlist, 1, + global_task, recv_done, + query); check_result(result, "isc_socket_recvv"); - sendcount++; - debug("sent count number %d", sendcount); - ISC_LIST_ENQUEUE(query->sendlist, &lookup->sendbuf, link); - debug("sending a request"); - result = isc_time_now(&query->time_sent); - check_result(result, "isc_time_now"); - ENSURE(query->sock != NULL); - result = isc_socket_sendtov(query->sock, &query->sendlist, - global_task, send_done, query, - &query->sockaddr, NULL); - check_result(result, "isc_socket_sendtov"); + recvcount++; + debug("recvcount=%d", recvcount); + } + ISC_LIST_INIT(query->sendlist); + ISC_LIST_ENQUEUE(query->sendlist, &l->sendbuf, + link); + debug("sending a request"); + result = isc_time_now(&query->time_sent); + check_result(result, "isc_time_now"); + INSIST(query->sock != NULL); + result = isc_socket_sendtov(query->sock, &query->sendlist, + global_task, send_done, query, + &query->sockaddr, NULL); + check_result(result, "isc_socket_sendtov"); + sendcount++; + /* + * If we're doing a nameserver search, we need to immediately + * bring up all the queries. Do it here. + */ + if (l->ns_search_only) { + debug("sending next, since searching"); + next = ISC_LIST_NEXT(query, link); + if (next != NULL) + send_udp(next); } } /* - * connect_timeout is used for both UDP recieves and TCP connects. + * IO timeout handler, used for both connect and recv timeouts. If + * retries are still allowed, either resend the UDP packet or queue a + * new TCP lookup. Otherwise, cancel the lookup. */ static void connect_timeout(isc_task_t *task, isc_event_t *event) { - dig_lookup_t *lookup=NULL; - dig_query_t *q=NULL; - isc_result_t result; - isc_buffer_t *b=NULL; - isc_region_t r; + dig_lookup_t *l=NULL; + dig_query_t *query=NULL, *cq; + UNUSED(task); REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE); debug("connect_timeout()"); - lookup = event->ev_arg; + LOCK_LOOKUP; + l = event->ev_arg; + query = l->current_query; isc_event_free(&event); - debug("buffer allocate connect_timeout"); - result = isc_buffer_allocate(mctx, &b, 256); - check_result(result, "isc_buffer_allocate"); - for (q = ISC_LIST_HEAD(lookup->q); - q != NULL; - q = ISC_LIST_NEXT(q, link)) { - if (q->working) { - if (!free_now) { - isc_buffer_clear(b); - result = isc_sockaddr_totext(&q->sockaddr, b); - check_result(result, "isc_sockaddr_totext"); - isc_buffer_usedregion(b, &r); - if ((q->lookup->retries > 1) && - (!q->lookup->tcp_mode)) - printf(";; Connection to server %.*s " - "for %s timed out. " - "Retrying %d.\n", - (int)r.length, r.base, - q->lookup->textname, - q->lookup->retries-1); - else { - printf(";; Connection to " - "server %.*s " - "for %s timed out. " - "Giving up.\n", - (int)r.length, r.base, - q->lookup->textname); - } - } - isc_socket_cancel(q->sock, task, - ISC_SOCKCANCEL_ALL); + INSIST(!free_now); + + if ((query != NULL) && (query->lookup->current_query != NULL) && + (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) { + debug("trying next server..."); + cq = query->lookup->current_query; + if (!l->tcp_mode) + send_udp(ISC_LIST_NEXT(cq, link)); + else + send_tcp_connect(ISC_LIST_NEXT(cq, link)); + UNLOCK_LOOKUP; + return; + } + + if (l->retries > 1) { + if (!l->tcp_mode) { + l->retries--; + debug("resending UDP request to first server"); + send_udp(ISC_LIST_HEAD(l->q)); + } else { + debug("making new TCP request, %d tries left", + l->retries); + cancel_lookup(l); + l->retries--; + requeue_lookup(l, ISC_TRUE); } } - ENSURE(lookup->timer != NULL); - isc_timer_detach(&lookup->timer); - isc_buffer_free(&b); - debug("done with connect_timeout()"); + else { + printf(";; connection timed out; no servers could be " + "reached\n"); + cancel_lookup(l); + } + UNLOCK_LOOKUP; } +/* + * Event handler for the TCP recv which gets the length header of TCP + * packets. Start the next recv of length bytes. + */ static void -tcp_length_done(isc_task_t *task, isc_event_t *event) { +tcp_length_done(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent; isc_buffer_t *b=NULL; isc_region_t r; isc_result_t result; dig_query_t *query=NULL; + dig_lookup_t *l; isc_uint16_t length; - REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); - - UNUSED(task); - - debug("tcp_length_done()"); - - if (free_now) { - isc_event_free(&event); - return; - } - - sevent = (isc_socketevent_t *)event; + REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); + INSIST(!free_now); + + UNUSED(task); + + debug("tcp_length_done()"); + LOCK_LOOKUP; + sevent = (isc_socketevent_t *)event; query = event->ev_arg; + recvcount--; + INSIST(recvcount >= 0); + if (sevent->result == ISC_R_CANCELED) { - query->working = ISC_FALSE; isc_event_free(&event); - check_next_lookup(query->lookup); + l = query->lookup; + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; return; } if (sevent->result != ISC_R_SUCCESS) { - debug("buffer allocate connect_timeout"); result = isc_buffer_allocate(mctx, &b, 256); check_result(result, "isc_buffer_allocate"); result = isc_sockaddr_totext(&query->sockaddr, b); check_result(result, "isc_sockaddr_totext"); isc_buffer_usedregion(b, &r); - printf("%.*s: %s\n", (int)r.length, r.base, + printf(";; communications error to %.*s: %s\n", + (int)r.length, r.base, isc_result_totext(sevent->result)); isc_buffer_free(&b); - query->working = ISC_FALSE; - sockcount--; - debug("socket = %d",sockcount); + l = query->lookup; isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d",sockcount); + INSIST(sockcount >= 0); isc_event_free(&event); - check_next_lookup(query->lookup); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; return; } b = ISC_LIST_HEAD(sevent->bufferlist); @@ -1391,33 +1744,43 @@ tcp_length_done(isc_task_t *task, isc_event_t *event) { result = isc_socket_recvv(query->sock, &query->recvlist, length, task, recv_done, query); check_result(result, "isc_socket_recvv"); - debug("resubmitted recv request with length %d", length); + recvcount++; + debug("resubmitted recv request with length %d, recvcount=%d", + length, recvcount); isc_event_free(&event); + UNLOCK_LOOKUP; } +/* + * For transfers that involve multiple recvs (XFR's in particular), + * launch the next recv. + */ static void launch_next_query(dig_query_t *query, isc_boolean_t include_question) { isc_result_t result; + dig_lookup_t *l; - debug("launch_next_query()"); + INSIST(!free_now); - if (free_now) - return; + debug("launch_next_query()"); if (!query->lookup->pending) { debug("ignoring launch_next_query because !pending"); - sockcount--; - debug("socket = %d", sockcount); isc_socket_detach(&query->sock); - query->working = ISC_FALSE; + sockcount--; + debug("sockcount=%d", sockcount); + INSIST(sockcount >= 0); query->waiting_connect = ISC_FALSE; - check_next_lookup(query->lookup); + l = query->lookup; + clear_query(query); + check_next_lookup(l); return; } isc_buffer_clear(&query->slbuf); isc_buffer_clear(&query->lengthbuf); isc_buffer_putuint16(&query->slbuf, query->lookup->sendbuf.used); + ISC_LIST_INIT(query->sendlist); ISC_LIST_ENQUEUE(query->sendlist, &query->slbuf, link); if (include_question) { ISC_LIST_ENQUEUE(query->sendlist, &query->lookup->sendbuf, @@ -1428,103 +1791,117 @@ launch_next_query(dig_query_t *query, isc_boolean_t include_question) { result = isc_socket_recvv(query->sock, &query->lengthlist, 0, global_task, tcp_length_done, query); check_result(result, "isc_socket_recvv"); - sendcount++; + recvcount++; + debug("recvcount=%d",recvcount); if (!query->first_soa_rcvd) { - debug("sending a request"); + debug("sending a request in launch_next_query"); result = isc_time_now(&query->time_sent); check_result(result, "isc_time_now"); result = isc_socket_sendv(query->sock, &query->sendlist, global_task, send_done, query); - check_result(result, "isc_socket_recvv"); + check_result(result, "isc_socket_sendv"); + sendcount++; + debug("sendcount=%d", sendcount); } query->waiting_connect = ISC_FALSE; +#if 0 check_next_lookup(query->lookup); +#endif return; } - + +/* + * Event handler for TCP connect complete. Make sure the connection was + * successful, then pass into launch_next_query to actually send the + * question. + */ static void connect_done(isc_task_t *task, isc_event_t *event) { isc_result_t result; isc_socketevent_t *sevent = NULL; - dig_query_t *query = NULL; + dig_query_t *query = NULL, *next; + dig_lookup_t *l; isc_buffer_t *b = NULL; isc_region_t r; UNUSED(task); REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); + INSIST(!free_now); debug("connect_done()"); - if (free_now) { - isc_event_free(&event); - return; - } - + LOCK_LOOKUP; sevent = (isc_socketevent_t *)event; query = sevent->ev_arg; - REQUIRE(query->waiting_connect); + INSIST(query->waiting_connect); query->waiting_connect = ISC_FALSE; - if (sevent->result == ISC_R_CANCELED) { - debug("in cancel handler"); - query->working = ISC_FALSE; - query->waiting_connect = ISC_FALSE; - isc_event_free(&event); - check_next_lookup(query->lookup); - return; - } + if (sevent->result == ISC_R_CANCELED) { + debug("in cancel handler"); + isc_socket_detach(&query->sock); + sockcount--; + INSIST(sockcount >= 0); + debug("sockcount=%d", sockcount); + query->waiting_connect = ISC_FALSE; + isc_event_free(&event); + l = query->lookup; + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } if (sevent->result != ISC_R_SUCCESS) { - debug("buffer allocate connect_timeout"); + debug("unsuccessful connection: %s", + isc_result_totext(sevent->result)); result = isc_buffer_allocate(mctx, &b, 256); check_result(result, "isc_buffer_allocate"); result = isc_sockaddr_totext(&query->sockaddr, b); check_result(result, "isc_sockaddr_totext"); isc_buffer_usedregion(b, &r); - printf(";; Connection to server %.*s for %s failed: %s.\n", - (int)r.length, r.base, query->lookup->textname, - isc_result_totext(sevent->result)); + /* XXX isc_sockaddr_format */ + if (sevent->result != ISC_R_CANCELED) + printf(";; Connection to %.*s(%s) for %s failed: " + "%s.\n", (int)r.length, r.base, + query->servname, query->lookup->textname, + isc_result_totext(sevent->result)); + isc_socket_detach(&query->sock); + sockcount--; + INSIST(sockcount >= 0); + /* XXX Clean up exitcodes */ if (exitcode < 9) exitcode = 9; + debug("sockcount=%d", sockcount); isc_buffer_free(&b); - query->working = ISC_FALSE; query->waiting_connect = ISC_FALSE; isc_event_free(&event); - check_next_lookup(query->lookup); + l = query->lookup; + if (l->current_query != NULL) + next = ISC_LIST_NEXT(l->current_query, link); + else + next = NULL; + clear_query(query); + if (next != NULL) { + bringup_timer(next, TCP_TIMEOUT); + send_tcp_connect(next); + } else { + check_next_lookup(l); + } + UNLOCK_LOOKUP; return; } launch_next_query(query, ISC_TRUE); isc_event_free(&event); + UNLOCK_LOOKUP; } - -#if 0 -static isc_boolean_t -msg_contains_soa(dns_message_t *msg, dig_query_t *query) { - isc_result_t result; - dns_name_t *name=NULL; - - debug("msg_contains_soa()"); - - result = dns_message_findname(msg, DNS_SECTION_ANSWER, - query->lookup->name, dns_rdatatype_soa, - 0, &name, NULL); - if (result == ISC_R_SUCCESS) { - debug("found SOA", stderr); - return (ISC_TRUE); - } else { - debug("didn't find SOA, result=%d:%s", - result, dns_result_totext(result)); - return (ISC_FALSE); - } - -} -#endif - /* - * Returns true if we should call cancel_lookup(). This is a hack. + * Check if the ongoing XFR needs more data before it's complete, using + * the semantics of IXFR and AXFR protocols. Much of the complexity of + * this routine comes from determining when an IXFR is complete. + * ISC_FALSE means more data is on the way, and the recv has been issued. */ static isc_boolean_t check_for_more_data(dig_query_t *query, dns_message_t *msg, @@ -1536,7 +1913,8 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, isc_result_t result; isc_buffer_t b; isc_region_t r; - char *abspace[MXNAME]; + char abspace[MXNAME]; + isc_boolean_t atlimit=ISC_FALSE; debug("check_for_more_data()"); @@ -1548,18 +1926,15 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, * rr's in the message, acting as necessary whenever we hit * an SOA rr. */ - + result = dns_message_firstname(msg, DNS_SECTION_ANSWER); if (result != ISC_R_SUCCESS) { puts("; Transfer failed."); - query->working = ISC_FALSE; return (ISC_TRUE); } -#ifdef NEVER - check_result(result, "dns_message_firstname"); -#endif do { - dns_name_t *name = NULL; + dns_name_t *name; + name = NULL; dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); for (rdataset = ISC_LIST_HEAD(name->list); @@ -1569,6 +1944,9 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, if (result != ISC_R_SUCCESS) continue; do { + query->rr_count++; + if (query->rr_count >= rr_limit) + atlimit = ISC_TRUE; dns_rdataset_current(rdataset, &rdata); /* * If this is the first rr, make sure @@ -1579,7 +1957,6 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, puts("; Transfer failed. " "Didn't start with " "SOA answer."); - query->working = ISC_FALSE; return (ISC_TRUE); } if ((!query->second_rr_rcvd) && @@ -1613,12 +1990,25 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, if (query->lookup->ixfr_serial >= soa.serial) { dns_rdata_freestruct(&soa); - goto xfr_done; + goto doexit; } dns_rdata_freestruct(&soa); goto next_rdata; } + if (query->lookup->rdtype == + dns_rdatatype_axfr) { + debug("doing axfr, got second SOA"); + dns_rdata_freestruct(&soa); + goto doexit; + } if (!query->second_rr_rcvd) { + if (soa.serial == + query->first_rr_serial) { + debug("doing ixfr, got " + "empty zone"); + dns_rdata_freestruct(&soa); + goto doexit; + } debug("this is the second %d", query->lookup->ixfr_serial); query->second_rr_rcvd = ISC_TRUE; @@ -1635,19 +2025,8 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, * AXFR, and we're done. */ debug("done, since axfr"); - xfr_done: - isc_buffer_init(&b, abspace, MXNAME); - result = isc_sockaddr_totext(&sevent-> - address, - &b); - check_result(result, - "isc_sockaddr_totext"); - isc_buffer_usedregion(&b, &r); - received(b.used, r.length, - (char *)r.base, query); - query->working = ISC_FALSE; dns_rdata_freestruct(&soa); - return (ISC_TRUE); + goto doexit; } /* * If we get to this point, we're doing an @@ -1664,7 +2043,7 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, } debug("done with ixfr"); dns_rdata_freestruct(&soa); - goto xfr_done; + goto doexit; } debug("meaningless soa %d", soa.serial); @@ -1673,12 +2052,36 @@ check_for_more_data(dig_query_t *query, dns_message_t *msg, result = dns_rdataset_next(rdataset); } while (result == ISC_R_SUCCESS); } + query->name_count++; + if (query->name_count >= name_limit) { + debug("name_count(%d) > name_limit(%d)", + query->name_count, name_limit); + atlimit = ISC_TRUE; + } result = dns_message_nextname(msg, DNS_SECTION_ANSWER); } while (result == ISC_R_SUCCESS); + if (atlimit) { + doexit: + isc_buffer_init(&b, abspace, MXNAME); + result = isc_sockaddr_totext(&sevent->address, &b); + check_result(result, + "isc_sockaddr_totext"); + isc_buffer_usedregion(&b, &r); + received(b.used, r.length, + (char *)r.base, query); + if (atlimit) + if (exitcode < 7) + exitcode = 7; + return (ISC_TRUE); + } launch_next_query(query, ISC_FALSE); return (ISC_FALSE); } +/* + * Event handler for recv complete. Perform whatever actions are necessary, + * based on the specifics of the user's request. + */ static void recv_done(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = NULL; @@ -1689,49 +2092,42 @@ recv_done(isc_task_t *task, isc_event_t *event) { isc_buffer_t ab; char abspace[MXNAME]; isc_region_t r; - dig_lookup_t *n; + dig_lookup_t *n, *l; isc_boolean_t docancel = ISC_FALSE; - isc_boolean_t result_bool; unsigned int local_timeout; - + UNUSED(task); + INSIST(!free_now); + if (show_packets) + puts(";; begin of DNS packet"); debug("recv_done()"); - if (free_now) { - isc_event_free(&event); - return; - } + LOCK_LOOKUP; + recvcount--; + debug("recvcount=%d", recvcount); + INSIST(recvcount >= 0); query = event->ev_arg; debug("lookup=%p, query=%p", query->lookup, query); - if (free_now) { - debug("bailing out, since freeing now"); - isc_event_free(&event); - return; - } + l = query->lookup; - sendcount--; - debug("in recv_done, counter down to %d", sendcount); REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); sevent = (isc_socketevent_t *)event; - if ((query->lookup->tcp_mode) && - (query->lookup->timer != NULL)) - isc_timer_touch(query->lookup->timer); - if (!query->lookup->pending && !query->lookup->ns_search_only) { - + if ((l->tcp_mode) && (l->timer != NULL)) + isc_timer_touch(l->timer); + if ((!l->pending && !l->ns_search_only) + || cancel_now) { debug("no longer pending. Got %s", isc_result_totext(sevent->result)); - query->working = ISC_FALSE; query->waiting_connect = ISC_FALSE; - + isc_event_free(&event); - /* - * In this case, we don't actually use result_bool - */ - result_bool = cancel_lookup(query->lookup); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; return; } @@ -1741,86 +2137,117 @@ recv_done(isc_task_t *task, isc_event_t *event) { result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg); check_result(result, "dns_message_create"); - + if (key != NULL) { - debug("querysig 1 is %p", query->lookup->querysig); - if (query->lookup->querysig == NULL) { + if (l->querysig == NULL) { debug("getting initial querysig"); result = dns_message_getquerytsig( - query->lookup->sendmsg, - mctx, &query->lookup->querysig); + l->sendmsg, + mctx, &l->querysig); check_result(result, "dns_message_getquerytsig"); } result = dns_message_setquerytsig(msg, - query->lookup->querysig); + l->querysig); check_result(result, "dns_message_setquerytsig"); result = dns_message_settsigkey(msg, key); check_result(result, "dns_message_settsigkey"); - msg->tsigctx = query->lookup->tsigctx; - if (query->lookup->msgcounter != 0) + msg->tsigctx = l->tsigctx; + if (l->msgcounter != 0) msg->tcp_continuation = 1; - query->lookup->msgcounter++; + l->msgcounter++; } debug("before parse starts"); result = dns_message_parse(msg, b, ISC_TRUE); if (result != ISC_R_SUCCESS) { - printf(";; Got bad UDP packet:\n"); + printf(";; Got bad packet: %s\n", + dns_result_totext(result)); hex_dump(b); - query->working = ISC_FALSE; query->waiting_connect = ISC_FALSE; dns_message_destroy(&msg); isc_event_free(&event); - cancel_lookup(query->lookup); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; return; } - if (((msg->flags & DNS_MESSAGEFLAG_TC) != 0) - && !query->lookup->tcp_mode && !ignore) { - printf(";; Truncated, retrying in TCP mode.\n"); - n = requeue_lookup(query->lookup, ISC_TRUE); - n->tcp_mode = ISC_TRUE; - query->working = ISC_FALSE; - query->waiting_connect = ISC_FALSE; - dns_message_destroy(&msg); - isc_event_free(&event); - cancel_lookup(query->lookup); - return; + if (((msg->flags & DNS_MESSAGEFLAG_TC) != 0) + && ! l->ignore && !l->tcp_mode) { + printf(";; Truncated, retrying in TCP mode.\n"); + n = requeue_lookup(l, ISC_TRUE); + n->tcp_mode = ISC_TRUE; + dns_message_destroy(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if ((msg->rcode == dns_rcode_servfail) && + l->servfail_stops) { + dig_query_t *next = ISC_LIST_NEXT(query, link); + if (l->current_query == query) + l->current_query = NULL; + if (next != NULL) { + debug("sending query %lx\n", next); + if (l->tcp_mode) + send_tcp_connect(next); + else + send_udp(next); + } + /* + * If our query is at the head of the list and there + * is no next, we're the only one left, so fall + * through to print the message. + */ + if ((ISC_LIST_HEAD(l->q) != query) || + (ISC_LIST_NEXT(query, link) != NULL)) { + printf(";; Got SERVFAIL reply from %s, " + "trying next server\n", + query->servname); + clear_query(query); + check_next_lookup(l); + dns_message_destroy(&msg); + isc_event_free(&event); + UNLOCK_LOOKUP; + return; + } } + if (key != NULL) { - debug("querysig 2 is %p", query->lookup->querysig); - debug("before verify"); result = dns_tsig_verify(&query->recvbuf, msg, - NULL, keyring); - debug("after verify"); + NULL, NULL); if (result != ISC_R_SUCCESS) { printf(";; Couldn't verify signature: %s\n", dns_result_totext(result)); validated = ISC_FALSE; } - query->lookup->tsigctx = msg->tsigctx; - if (query->lookup->querysig != NULL) { + l->tsigctx = msg->tsigctx; + if (l->querysig != NULL) { debug("freeing querysig buffer %p", - query->lookup->querysig); - isc_buffer_free(&query->lookup->querysig); + l->querysig); + isc_buffer_free(&l->querysig); } result = dns_message_getquerytsig(msg, mctx, - &query->lookup->querysig); + &l->querysig); check_result(result,"dns_message_getquerytsig"); - debug("querysig 3 is %p", query->lookup->querysig); + debug("querysig 3 is %p", l->querysig); } debug("after parse"); - if (query->lookup->xfr_q == NULL) { - query->lookup->xfr_q = query; + if (l->xfr_q == NULL) { + l->xfr_q = query; /* * Once we are in the XFR message, increase * the timeout to much longer, so brief network * outages won't cause the XFR to abort */ if ((timeout != INT_MAX) && - (query->lookup->timer != NULL) && - query->lookup->doing_xfr ) { + (l->timer != NULL) && + l->doing_xfr ) { if (timeout == 0) { - if (query->lookup->tcp_mode) + if (l->tcp_mode) local_timeout = TCP_TIMEOUT; else local_timeout = UDP_TIMEOUT; @@ -1830,74 +2257,94 @@ recv_done(isc_task_t *task, isc_event_t *event) { else local_timeout = INT_MAX; } - debug ("have local timeout of %d", - local_timeout); - isc_interval_set(&query->lookup->interval, + debug("have local timeout of %d", + local_timeout); + isc_interval_set(&l->interval, local_timeout, 0); - result = isc_timer_reset(query->lookup->timer, + result = isc_timer_reset(l->timer, isc_timertype_once, NULL, - &query->lookup->interval, + &l->interval, ISC_FALSE); check_result(result, "isc_timer_reset"); } } - if (query->lookup->xfr_q == query) { - if ((query->lookup->trace)|| - (query->lookup->ns_search_only)) { + if (l->xfr_q == query) { + if ((l->trace)|| + (l->ns_search_only)) { debug("in TRACE code"); - if (show_details || - (((dns_message_firstname(msg, - DNS_SECTION_ANSWER) - == ISC_R_SUCCESS)) && - !query->lookup->trace_root)) { - printmessage(query, msg, ISC_TRUE); - } + printmessage(query, msg, ISC_TRUE); if ((msg->rcode != 0) && - (query->lookup->origin != NULL)) { - next_origin(msg, query); + (l->origin != NULL)) { + if (!next_origin(msg, query)) { + printmessage(query, msg, + ISC_TRUE); + isc_buffer_init(&ab, abspace, + MXNAME); + result = isc_sockaddr_totext( + &sevent->address, + &ab); + check_result(result, + "isc_sockaddr_totext"); + isc_buffer_usedregion(&ab, &r); + received(b->used, r.length, + (char *)r.base, + query); + } } else { result = dns_message_firstname (msg,DNS_SECTION_ANSWER); if ((result != ISC_R_SUCCESS) || - query->lookup->trace_root) + l->trace_root) followup_lookup(msg, query, DNS_SECTION_AUTHORITY); } } else if ((msg->rcode != 0) && - (query->lookup->origin != NULL)) { - next_origin(msg, query); - if (show_details) { - printmessage(query, msg, ISC_TRUE); + (l->origin != NULL)) { + if (!next_origin(msg, query)) { + printmessage(query, msg, + ISC_TRUE); + isc_buffer_init(&ab, abspace, MXNAME); + result = isc_sockaddr_totext( + &sevent->address, + &ab); + check_result(result, + "isc_sockaddr_totext"); + isc_buffer_usedregion(&ab, &r); + received(b->used, r.length, + (char *)r.base, + query); } } else { if (query->first_soa_rcvd && - query->lookup->doing_xfr) + l->doing_xfr) printmessage(query, msg, ISC_FALSE); else printmessage(query, msg, ISC_TRUE); } } else if ((dns_message_firstname(msg, DNS_SECTION_ANSWER) == ISC_R_SUCCESS) && - query->lookup->ns_search_only && - !query->lookup->trace_root ) { + l->ns_search_only && + !l->trace_root ) { printmessage(query, msg, ISC_TRUE); } - - if (query->lookup->pending) + + if (l->pending) debug("still pending."); - if (query->lookup->doing_xfr) { - if (query != query->lookup->xfr_q) { + if (l->doing_xfr) { + if (query != l->xfr_q) { dns_message_destroy(&msg); isc_event_free (&event); - query->working = ISC_FALSE; query->waiting_connect = ISC_FALSE; + UNLOCK_LOOKUP; return; } docancel = check_for_more_data(query, msg, sevent); if (docancel) { dns_message_destroy(&msg); - result_bool = cancel_lookup(query->lookup); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); } if (msg != NULL) dns_message_destroy(&msg); @@ -1905,53 +2352,63 @@ recv_done(isc_task_t *task, isc_event_t *event) { } else { if ((msg->rcode == 0) || - (query->lookup->origin == NULL)) { + (l->origin == NULL)) { isc_buffer_init(&ab, abspace, MXNAME); result = isc_sockaddr_totext(&sevent->address, &ab); check_result(result, "isc_sockaddr_totext"); isc_buffer_usedregion(&ab, &r); - if ((dns_message_firstname(msg, - DNS_SECTION_ANSWER) - == ISC_R_SUCCESS) || - query->lookup->trace ) { - received(b->used, r.length, - (char *)r.base, - query); - } + received(b->used, r.length, + (char *)r.base, + query); } - query->working = ISC_FALSE; query->lookup->pending = ISC_FALSE; - result_bool = ISC_FALSE; if (!query->lookup->ns_search_only || query->lookup->trace_root) { dns_message_destroy(&msg); - result_bool = cancel_lookup(query->lookup); + cancel_lookup(l); } if (msg != NULL) dns_message_destroy(&msg); isc_event_free(&event); - if ((!free_now) && (!result_bool)) - check_next_lookup(query->lookup); + clear_query(query); + check_next_lookup(l); } + UNLOCK_LOOKUP; return; } /* * In truth, we should never get into the CANCELED routine, since * the cancel_lookup() routine clears the pending flag. + * XXX Is this true anymore, since the bulk changes? */ if (sevent->result == ISC_R_CANCELED) { - debug("in cancel handler"); - query->working = ISC_FALSE; + debug("in recv cancel handler"); query->waiting_connect = ISC_FALSE; isc_event_free(&event); - check_next_lookup(query->lookup); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; return; } - fatal("recv_done got result %s", - isc_result_totext(sevent->result)); + printf(";; communications error: %s\n", + isc_result_totext(sevent->result)); + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d",sockcount); + INSIST(sockcount >= 0); + isc_event_free(&event); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; } +/* + * Turn a name into an address, using system-supplied routines. This is + * used in looking up server names, etc... and needs to use system-supplied + * routines, since they may be using a non-DNS system for these lookups. + */ void get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { struct in_addr in4; @@ -1971,7 +2428,10 @@ get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { isc_sockaddr_fromin(sockaddr, &in4, port); else { #if defined(HAVE_ADDRINFO) && defined(HAVE_GETADDRINFO) + debug ("before getaddrinfo()"); + is_blocking = ISC_TRUE; result = getaddrinfo(host, NULL, NULL, &res); + is_blocking = ISC_FALSE; if (result != 0) { fatal("Couldn't find server '%s': %s", host, gai_strerror(result)); @@ -1981,7 +2441,10 @@ get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { isc_sockaddr_setport(sockaddr, port); freeaddrinfo(res); #else + debug ("before gethostbyname()"); + is_blocking = ISC_TRUE; he = gethostbyname(host); + is_blocking = ISC_FALSE; if (he == NULL) fatal("Couldn't find server '%s' (h_errno=%d)", host, h_errno); @@ -1993,173 +2456,140 @@ get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { } } -static void -do_lookup_tcp(dig_lookup_t *lookup) { - dig_query_t *query; - isc_result_t result; - unsigned int local_timeout; - - debug("do_lookup_tcp()"); - lookup->pending = ISC_TRUE; - if (timeout != INT_MAX) { - if (timeout == 0) { - if (lookup->tcp_mode) - local_timeout = TCP_TIMEOUT; - else - local_timeout = UDP_TIMEOUT; - } else - local_timeout = timeout; - debug ("have local timeout of %d", local_timeout); - isc_interval_set(&lookup->interval, local_timeout, 0); - result = isc_timer_create(timermgr, isc_timertype_once, NULL, - &lookup->interval, global_task, - connect_timeout, lookup, - &lookup->timer); - check_result(result, "isc_timer_create"); - } - - for (query = ISC_LIST_HEAD(lookup->q); - query != NULL; - query = ISC_LIST_NEXT(query, link)) { - query->working = ISC_TRUE; - query->waiting_connect = ISC_TRUE; - get_address(query->servname, port, &query->sockaddr); - - sockcount++; - debug("socket = %d",sockcount); - ENSURE(query->sock == NULL); - result = isc_socket_create(socketmgr, - isc_sockaddr_pf(&query->sockaddr), - isc_sockettype_tcp, &query->sock) ; - check_result(result, "isc_socket_create"); - if (specified_source) - result = isc_socket_bind(query->sock, &bind_address); - else { - if (isc_sockaddr_pf(&query->sockaddr) == AF_INET) - isc_sockaddr_any(&bind_any); - else - isc_sockaddr_any6(&bind_any); - result = isc_socket_bind(query->sock, &bind_any); - } - check_result(result, "isc_socket_bind"); - result = isc_socket_connect(query->sock, &query->sockaddr, - global_task, connect_done, query); - check_result(result, "isc_socket_connect"); - } -} - -static void -do_lookup_udp(dig_lookup_t *lookup) { - dig_query_t *query; - isc_result_t result; - - debug("do_lookup_udp()"); - ENSURE(!lookup->tcp_mode); - lookup->pending = ISC_TRUE; - - for (query = ISC_LIST_HEAD(lookup->q); - query != NULL; - query = ISC_LIST_NEXT(query, link)) { - query->working = ISC_TRUE; - query->waiting_connect = ISC_FALSE; - get_address(query->servname, port, &query->sockaddr); - - sockcount++; - debug("socket = %d", sockcount); - result = isc_socket_create(socketmgr, - isc_sockaddr_pf(&query->sockaddr), - isc_sockettype_udp, &query->sock); - check_result(result, "isc_socket_create"); - if (specified_source) - result = isc_socket_bind(query->sock, &bind_address); - else { - if (isc_sockaddr_pf(&query->sockaddr) == AF_INET) - isc_sockaddr_any(&bind_any); - else - isc_sockaddr_any6(&bind_any); - result = isc_socket_bind(query->sock, &bind_any); - } - check_result(result, "isc_socket_bind"); - } - - send_udp(lookup); -} - +/* + * Initiate either a TCP or UDP lookup + */ void do_lookup(dig_lookup_t *lookup) { REQUIRE(lookup != NULL); debug("do_lookup()"); + lookup->pending = ISC_TRUE; if (lookup->tcp_mode) - do_lookup_tcp(lookup); + send_tcp_connect(ISC_LIST_HEAD(lookup->q)); else - do_lookup_udp(lookup); -} - -void -start_lookup(void) { - dig_lookup_t *lookup; - - debug("start_lookup()"); - - if (free_now) - return; - - lookup = ISC_LIST_HEAD(lookup_list); - if (lookup != NULL) { - setup_lookup(lookup); - do_lookup(lookup); - } + send_udp(ISC_LIST_HEAD(lookup->q)); } +/* + * Start everything in action upon task startup. + */ void onrun_callback(isc_task_t *task, isc_event_t *event) { UNUSED(task); + isc_event_free(&event); + LOCK_LOOKUP; start_lookup(); + UNLOCK_LOOKUP; } +/* + * Make everything on the lookup queue go away. Mainly used by the + * SIGINT handler. + */ void -free_lists(void) { - void *ptr; - dig_lookup_t *l; - dig_query_t *q; - dig_server_t *s; - dig_searchlist_t *o; +cancel_all(void) { + dig_lookup_t *l, *n; + dig_query_t *q, *nq; - debug("free_lists()"); + debug("cancel_all()"); - if (free_now) + if (is_blocking) { + /* + * If we get here while another thread is blocking, there's + * really nothing we can do to make a clean shutdown + * without waiting for the block to complete. The only + * way to get the system down now is to just exit out, + * and trust the OS to clean up for us. + */ + fputs ("Abort.\n",stderr); + exit(1); + } + LOCK_LOOKUP; + if (free_now) { + UNLOCK_LOOKUP; return; - - free_now = ISC_TRUE; - - l = ISC_LIST_HEAD(lookup_list); - while (l != NULL) { - if (l->timer != NULL) - isc_timer_detach(&l->timer); - q = ISC_LIST_HEAD(l->q); + } + cancel_now = ISC_TRUE; + if (current_lookup != NULL) { + if (current_lookup->timer != NULL) + isc_timer_detach(¤t_lookup->timer); + q = ISC_LIST_HEAD(current_lookup->q); while (q != NULL) { debug("cancelling query %p, belonging to %p", - q, l); + q, current_lookup); + nq = ISC_LIST_NEXT(q, link); if (q->sock != NULL) { isc_socket_cancel(q->sock, NULL, ISC_SOCKCANCEL_ALL); - isc_socket_detach(&q->sock); - sockcount--; - debug("socket = %d",sockcount); + } else { + clear_query (q); } - q = ISC_LIST_NEXT(q, link); + q = nq; } - l = ISC_LIST_NEXT(l, link); } + l = ISC_LIST_HEAD(lookup_list); + while (l != NULL) { + n = ISC_LIST_NEXT(l, link); + ISC_LIST_DEQUEUE(lookup_list, l, link); + try_clear_lookup(l); + l = n; + } + UNLOCK_LOOKUP; +} + +/* + * Destroy all of the libs we are using, and get everything ready for a + * clean shutdown. + */ +void +destroy_libs(void) { + void *ptr; + dig_server_t *s; + dig_searchlist_t *o; + + debug("destroy_libs()"); + if (is_blocking) { + /* + * If we get here while another thread is blocking, there's + * really nothing we can do to make a clean shutdown + * without waiting for the block to complete. The only + * way to get the system down now is to just exit out, + * and trust the OS to clean up for us. + */ + fputs ("Abort.\n",stderr); + exit(1); + } + if (global_task != NULL) { + debug("freeing task"); + isc_task_detach(&global_task); + } + /* + * The taskmgr_destroy() call blocks until all events are cleared + * from the task. + */ + if (taskmgr != NULL) { + debug("freeing taskmgr"); + isc_taskmgr_destroy(&taskmgr); + } + LOCK_LOOKUP; + REQUIRE(sockcount == 0); + REQUIRE(recvcount == 0); + REQUIRE(sendcount == 0); + + INSIST(ISC_LIST_HEAD(lookup_list) == NULL); + INSIST(current_lookup == NULL); + INSIST(!free_now); + + free_now = ISC_TRUE; + s = ISC_LIST_HEAD(server_list); while (s != NULL) { debug("freeing global server %p", s); ptr = s; s = ISC_LIST_NEXT(s, link); - debug("ptr is now %p", ptr); isc_mem_free(mctx, ptr); } o = ISC_LIST_HEAD(search_list); @@ -2169,6 +2599,10 @@ free_lists(void) { o = ISC_LIST_NEXT(o, link); isc_mem_free(mctx, ptr); } + if (commctx != NULL) { + debug("freeing commctx"); + isc_mempool_destroy(&commctx); + } if (socketmgr != NULL) { debug("freeing socketmgr"); isc_socketmgr_destroy(&socketmgr); @@ -2177,67 +2611,13 @@ free_lists(void) { debug("freeing timermgr"); isc_timermgr_destroy(&timermgr); } - if (global_task != NULL) { - debug("freeing task"); - isc_task_detach(&global_task); - } if (key != NULL) { debug("freeing key %p", key); - dns_tsigkey_setdeleted(key); dns_tsigkey_detach(&key); } if (namebuf != NULL) isc_buffer_free(&namebuf); - l = ISC_LIST_HEAD(lookup_list); - while (l != NULL) { - q = ISC_LIST_HEAD(l->q); - while (q != NULL) { - debug("freeing query %p, belonging to %p", - q, l); - if (ISC_LINK_LINKED(&q->recvbuf, link)) - ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf, - link); - if (ISC_LINK_LINKED(&q->lengthbuf, link)) - ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf, - link); - INSIST(q->recvspace != NULL); - isc_mempool_put(commctx, q->recvspace); - isc_buffer_invalidate(&q->recvbuf); - isc_buffer_invalidate(&q->lengthbuf); - ptr = q; - q = ISC_LIST_NEXT(q, link); - isc_mem_free(mctx, ptr); - } - if (l->use_my_server_list) { - s = ISC_LIST_HEAD(l->my_server_list); - while (s != NULL) { - debug("freeing server %p belonging to %p", - s, l); - ptr = s; - s = ISC_LIST_NEXT(s, link); - isc_mem_free(mctx, ptr); - - } - } - if (l->sendmsg != NULL) - dns_message_destroy(&l->sendmsg); - if (l->sendspace != NULL) - isc_mempool_put(commctx, l->sendspace); - if (l->querysig != NULL) { - debug("freeing buffer %p", l->querysig); - isc_buffer_free(&l->querysig); - } - - ptr = l; - l = ISC_LIST_NEXT(l, link); - isc_mem_free(mctx, ptr); - } - - if (keyring != NULL) { - debug("freeing keyring %p", keyring); - dns_tsigkeyring_destroy(&keyring); - } if (is_dst_up) { debug("destroy DST lib"); dst_lib_destroy(); @@ -2247,8 +2627,11 @@ free_lists(void) { debug("detach from entropy"); isc_entropy_detach(&entp); } - if (commctx != NULL) { - debug("freeing commctx"); - isc_mempool_destroy(&commctx); - } + + UNLOCK_LOOKUP; + DESTROYLOCK(&lookup_lock); + if (isc_mem_debugging != 0) + isc_mem_stats(mctx, stderr); + if (mctx != NULL) + isc_mem_destroy(&mctx); } diff --git a/bin/dig/host.c b/bin/dig/host.c index 4f51277c9f0..643dc4c5adb 100644 --- a/bin/dig/host.c +++ b/bin/dig/host.c @@ -1,21 +1,21 @@ /* * Copyright (C) 2000 Internet Software Consortium. - * + * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: host.c,v 1.29.2.6 2000/09/15 22:56:14 gson Exp $ */ +/* $Id: host.c,v 1.29.2.7 2000/10/06 19:08:05 mws Exp $ */ #include #include @@ -25,14 +25,19 @@ extern int h_errno; #include #include +#include #include #include #include +#include +#include #include #include #include +#include #include +#include #include @@ -40,30 +45,17 @@ extern ISC_LIST(dig_lookup_t) lookup_list; extern ISC_LIST(dig_server_t) server_list; extern ISC_LIST(dig_searchlist_t) search_list; -extern isc_boolean_t have_ipv6, show_details, debugging; -extern in_port_t port; +extern isc_boolean_t debugging; extern unsigned int timeout; extern isc_mem_t *mctx; -extern dns_messageid_t id; -extern dns_name_t rootorg; -extern char *rootspace[BUFSIZE]; -extern isc_buffer_t rootbuf; -extern int sendcount; extern int ndots; extern int tries; extern isc_boolean_t usesearch; extern int lookup_counter; -extern int exitcode; -extern isc_taskmgr_t *taskmgr; extern char *progname; extern isc_task_t *global_task; -isc_boolean_t - short_form = ISC_TRUE, - filter = ISC_FALSE, - showallsoa = ISC_FALSE, - tcpmode = ISC_FALSE, - listed_server = ISC_FALSE; +isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE; static const char *opcodetext[] = { "QUERY", @@ -112,7 +104,7 @@ static const char *rtypetext[] = { "MF", /* 4 */ "is an alias for", /* 5 */ "SOA", /* 6 */ - "MB", /* 7 */ + "MB", /* 7 */ "MG", /* 8 */ "MR", /* 9 */ "NULL", /* 10 */ @@ -213,13 +205,14 @@ static const char *rtypetext[] = { static void show_usage(void) { fputs( -"Usage: host [-aCdlrTwv] [-c class] [-N ndots] [-t type] [-W time]\n" +"Usage: host [-aCdlrTwv] [-c class] [-n] [-N ndots] [-t type] [-W time]\n" " [-R number] hostname [server]\n" " -a is equivalent to -v -t *\n" " -c specifies query class for non-IN data\n" " -C compares SOA records on authorative nameservers\n" " -d is equivalent to -v\n" " -l lists all hosts in a domain, using AXFR\n" +" -n Use the nibble form of IPv6 reverse lookup\n" " -N changes the number of dots allowed before root lookup is done\n" " -r disables recursive processing\n" " -R specifies number of retries for UDP packets\n" @@ -228,12 +221,11 @@ show_usage(void) { " -v enables verbose output\n" " -w specifies to wait forever for a reply\n" " -W specifies how long to wait for a reply\n", stderr); - exit(exitcode); -} + exit(1); +} void dighost_shutdown(void) { - free_lists(); isc_app_shutdown(); } @@ -243,7 +235,7 @@ received(int bytes, int frmsize, char *frm, dig_query_t *query) { isc_result_t result; int diff; - if ((!short_form) || (show_details)) { + if (!short_form) { result = isc_time_now(&now); check_result(result, "isc_time_now"); diff = isc_time_microdiff(&now, &query->time_sent); @@ -305,7 +297,7 @@ printsection(dns_message_t *msg, dns_section_t sectionid, isc_boolean_t first; isc_boolean_t no_rdata; const char *rtt; - + if (sectionid == DNS_SECTION_QUESTION) no_rdata = ISC_TRUE; else @@ -349,7 +341,7 @@ printsection(dns_message_t *msg, dns_section_t sectionid, #else UNUSED(first); /* Shut up compiler. */ #endif - } else { + } else { loopresult = dns_rdataset_first(rdataset); while (loopresult == ISC_R_SUCCESS) { dns_rdataset_current(rdataset, &rdata); @@ -376,14 +368,14 @@ printsection(dns_message_t *msg, dns_section_t sectionid, else printf("%.*s", (int)r.length, (char *)r.base); } - + result = dns_message_nextname(msg, sectionid); if (result == ISC_R_NOMORE) break; else if (result != ISC_R_SUCCESS) return (result); } - + return (ISC_R_SUCCESS); } @@ -397,7 +389,7 @@ printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner, char t[4096]; UNUSED(msg); - if (headers) + if (headers) printf(";; %s SECTION:\n", set_name); isc_buffer_init(&target, t, sizeof(t)); @@ -423,13 +415,19 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { UNUSED(headers); - /* - * Exitcode 9 means we timed out, but if we're printing a message, - * we much have recovered. Go ahead and reset it to code 0, and - * call this a success. - */ - if (exitcode == 9) - exitcode = 0; + if (listed_server) { + printf("Using domain server:\n"); + printf("Name: %s\n", query->servname); + result = isc_buffer_allocate(mctx, &b, MXNAME); + check_result(result, "isc_buffer_allocate"); + result = isc_sockaddr_totext(&query->sockaddr, b); + check_result(result, "isc_sockaddr_totext"); + printf("Address: %.*s\n", + (int)isc_buffer_usedlength(b), + (char*)isc_buffer_base(b)); + isc_buffer_free(&b); + printf("Aliases: \n\n"); + } if (msg->rcode != 0) { result = isc_buffer_allocate(mctx, &b, MXNAME); @@ -508,21 +506,8 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { ISC_TF(!short_form), query); if (result != ISC_R_SUCCESS) return (result); - } else { - if ((short_form) && (listed_server)) { - printf("Using domain server:\n"); - printf("Name: %s\n", query->servname); - result = isc_buffer_allocate(mctx, &b, MXNAME); - check_result(result, "isc_buffer_allocate"); - result = isc_sockaddr_totext(&query->sockaddr, b); - check_result(result, "isc_sockaddr_totext"); - printf("Address: %.*s\n", - (int)isc_buffer_usedlength(b), - (char*)isc_buffer_base(b)); - isc_buffer_free(&b); - printf("Aliases: \n\n"); - } } + if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) && !short_form) { printf("\n"); @@ -554,42 +539,65 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { static void parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { - isc_boolean_t recursion = ISC_TRUE; char hostname[MXNAME]; - char querytype[32] = ""; - char queryclass[32] = ""; dig_server_t *srv; dig_lookup_t *lookup; int i, c, n, adrs[4]; char store[MXNAME]; + isc_textregion_t tr; + isc_result_t result; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; UNUSED(is_batchfile); - while ((c = isc_commandline_parse(argc, argv, "lvwrdt:c:aTCN:R:W:D")) + lookup = make_empty_lookup(); + + while ((c = isc_commandline_parse(argc, argv, "lvwrdt:c:aTCN:R:W:Dn")) != EOF) { switch (c) { case 'l': - tcpmode = ISC_TRUE; - filter = ISC_TRUE; - strcpy(querytype, "axfr"); + lookup->tcp_mode = ISC_TRUE; + lookup->rdtype = dns_rdatatype_axfr; break; case 'v': case 'd': short_form = ISC_FALSE; break; case 'r': - recursion = ISC_FALSE; + lookup->recurse = ISC_FALSE; break; case 't': - strncpy (querytype, isc_commandline_argument, 32); + tr.base = isc_commandline_argument; + tr.length = strlen(isc_commandline_argument); + result = dns_rdatatype_fromtext(&rdtype, + (isc_textregion_t *)&tr); + + if (result != ISC_R_SUCCESS) + fprintf (stderr,"Warning: invalid type: %s\n", + isc_commandline_argument); + else + lookup->rdtype = rdtype; break; case 'c': - strncpy (queryclass, isc_commandline_argument, 32); + tr.base = isc_commandline_argument; + tr.length = strlen(isc_commandline_argument); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + + if (result != ISC_R_SUCCESS) + fprintf (stderr,"Warning: invalid class: %s\n", + isc_commandline_argument); + else + lookup->rdclass = rdclass; break; case 'a': - strcpy (querytype, "any"); + lookup->rdtype = dns_rdatatype_any; short_form = ISC_FALSE; break; + case 'n': + lookup->nibble = ISC_TRUE; + break; case 'w': /* * The timer routines are coded such that @@ -608,19 +616,17 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { tries = 1; break; case 'T': - tcpmode = ISC_TRUE; + lookup->tcp_mode = ISC_TRUE; break; case 'C': debug("showing all SOAs"); - if (querytype[0] == 0) - strcpy(querytype, "soa"); - if (queryclass[0] == 0) - strcpy(queryclass, "in"); - showallsoa = ISC_TRUE; - show_details = ISC_TRUE; + lookup->rdtype = dns_rdatatype_soa; + lookup->rdclass = dns_rdataclass_in; + lookup->ns_search_only = ISC_TRUE; + lookup->trace_root = ISC_TRUE; break; case 'N': - debug("setting NDOTS to %s", + debug("setting NDOTS to %s", isc_commandline_argument); ndots = atoi(isc_commandline_argument); break; @@ -632,33 +638,22 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { if (isc_commandline_index >= argc) { show_usage(); } - strncpy(hostname, argv[isc_commandline_index], MXNAME); + strncpy(hostname, argv[isc_commandline_index], sizeof(hostname)); + hostname[sizeof(hostname)-1]=0; if (argc > isc_commandline_index + 1) { - srv = isc_mem_allocate(mctx, sizeof(struct dig_server)); - if (srv == NULL) - fatal("Memory allocation failure."); - strncpy(srv->servername, - argv[isc_commandline_index+1], MXNAME-1); + srv = make_server(argv[isc_commandline_index+1]); debug("server is %s", srv->servername); ISC_LIST_APPEND(server_list, srv, link); listed_server = ISC_TRUE; } - - lookup = isc_mem_allocate(mctx, sizeof(struct dig_lookup)); - if (lookup == NULL) - fatal("Memory allocation failure."); + lookup->pending = ISC_FALSE; - /* - * XXXMWS Add IPv6 translation here, probably using inet_pton - * to extract the formatted text. - */ if (strspn(hostname, "0123456789.") == strlen(hostname)) { lookup->textname[0] = 0; n = sscanf(hostname, "%d.%d.%d.%d", &adrs[0], &adrs[1], &adrs[2], &adrs[3]); if (n == 0) { show_usage(); - exit(exitcode); } for (i = n - 1; i >= 0; i--) { snprintf(store, MXNAME/8, "%d.", @@ -666,47 +661,36 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { strncat(lookup->textname, store, MXNAME); } strncat(lookup->textname, "in-addr.arpa.", MXNAME); - if (querytype[0] == 0) - strcpy(querytype, "ptr"); + lookup->rdtype = dns_rdatatype_ptr; + } else if (strspn(hostname, "0123456789abcdef.:") == strlen(hostname)) + { + isc_netaddr_t addr; + dns_fixedname_t fname; + isc_buffer_t b; + + addr.family = AF_INET6; + n = inet_pton(AF_INET6, hostname, &addr.type.in6); + if (n <= 0) + goto notv6; + dns_fixedname_init(&fname); + result = dns_byaddr_createptrname(&addr, lookup->nibble, + dns_fixedname_name(&fname)); + if (result != ISC_R_SUCCESS) + show_usage(); + isc_buffer_init(&b, lookup->textname, sizeof lookup->textname); + result = dns_name_totext(dns_fixedname_name(&fname), + ISC_FALSE, &b); + isc_buffer_putuint8(&b, 0); + if (result != ISC_R_SUCCESS) + show_usage(); + lookup->rdtype = dns_rdatatype_ptr; } else { - strncpy(lookup->textname, hostname, MXNAME); + notv6: + strncpy(lookup->textname, hostname, sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1]=0; } - if (querytype[0] == 0) - strcpy(querytype, "a"); - if (queryclass[0] == 0) - strcpy(queryclass, "in"); - strncpy(lookup->rttext, querytype, 32); - strncpy(lookup->rctext, queryclass, 32); - lookup->namespace[0] = 0; - lookup->sendspace = NULL; - lookup->sendmsg = NULL; - lookup->name = NULL; - lookup->oname = NULL; - lookup->timer = NULL; - lookup->xfr_q = NULL; - lookup->origin = NULL; - lookup->querysig = NULL; - lookup->doing_xfr = ISC_FALSE; - lookup->ixfr_serial = 0; - lookup->defname = ISC_FALSE; - lookup->identify = ISC_FALSE; - lookup->recurse = recursion; - lookup->ns_search_only = showallsoa; - lookup->use_my_server_list = ISC_FALSE; - lookup->retries = tries; - lookup->udpsize = 0; - lookup->nsfound = 0; - lookup->trace = ISC_FALSE; - lookup->trace_root = showallsoa; - lookup->tcp_mode = tcpmode; lookup->new_search = ISC_TRUE; - lookup->aaonly = ISC_FALSE; - lookup->adflag = ISC_FALSE; - lookup->cdflag = ISC_FALSE; - ISC_LIST_INIT(lookup->q); ISC_LIST_APPEND(lookup_list, lookup, link); - lookup->origin = NULL; - ISC_LIST_INIT(lookup->my_server_list); usesearch = ISC_TRUE; } @@ -721,28 +705,17 @@ main(int argc, char **argv) { debug("main()"); progname = argv[0]; + result = isc_app_start(); + check_result(result, "isc_app_start"); setup_libs(); parse_args(ISC_FALSE, argc, argv); setup_system(); result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); check_result(result, "isc_app_onrun"); isc_app_run(); - /* - * XXXMWS This code should really NOT be bypassed. However, - * until the proper code can be added to handle SIGTERM/INT - * correctly, just exit out "hard" and deal as best we can. - */ -#if 0 - if (taskmgr != NULL) { - debug("freeing taskmgr"); - isc_taskmgr_destroy(&taskmgr); - } - if (isc_mem_debugging) - isc_mem_stats(mctx, stderr); + cancel_all(); + destroy_libs(); isc_app_finish(); - if (mctx != NULL) - isc_mem_destroy(&mctx); -#endif return (0); } diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index fa85a9c7c6c..fe409b1e855 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -1,21 +1,21 @@ /* * Copyright (C) 2000 Internet Software Consortium. - * + * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.h,v 1.25.2.4 2000/08/07 23:50:17 gson Exp $ */ +/* $Id: dig.h,v 1.25.2.5 2000/10/06 19:08:08 mws Exp $ */ #ifndef DIG_H #define DIG_H @@ -32,8 +32,8 @@ #include #include -#define MXSERV 4 -#define MXNAME 1005 +#define MXSERV 6 +#define MXNAME (1024) #define MXRD 32 #define BUFSIZE 512 #define COMMSIZE 0xffff @@ -43,8 +43,10 @@ /* * Default timeout values */ -#define TCP_TIMEOUT 60 -#define UDP_TIMEOUT 30 +#define TCP_TIMEOUT 10 +#define UDP_TIMEOUT 5 + +#define SERVER_TIMEOUT 1 #define LOOKUP_LIMIT 64 /* @@ -66,6 +68,7 @@ ISC_LANG_BEGINDECLS typedef struct dig_lookup dig_lookup_t; typedef struct dig_query dig_query_t; typedef struct dig_server dig_server_t; +typedef ISC_LIST(dig_server_t) dig_serverlist_t; typedef struct dig_searchlist dig_searchlist_t; struct dig_lookup { @@ -74,8 +77,8 @@ struct dig_lookup { waiting_connect, doing_xfr, ns_search_only, - use_my_server_list, identify, + ignore, recurse, aaonly, adflag, @@ -84,16 +87,19 @@ struct dig_lookup { trace_root, defname, tcp_mode, + nibble, comments, stats, section_question, section_answer, section_authority, section_additional, + servfail_stops, new_search; char textname[MXNAME]; /* Name we're going to be looking up */ - char rttext[MXRD]; /* rdata type text */ - char rctext[MXRD]; /* rdata class text */ + char cmdline[MXNAME]; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; char namespace[BUFSIZE]; char onamespace[BUFSIZE]; isc_buffer_t namebuf; @@ -107,7 +113,8 @@ struct dig_lookup { dns_name_t *oname; ISC_LINK(dig_lookup_t) link; ISC_LIST(dig_query_t) q; - ISC_LIST(dig_server_t) my_server_list; + dig_query_t *current_query; + dig_serverlist_t my_server_list; dig_searchlist_t *origin; dig_query_t *xfr_q; int retries; @@ -123,15 +130,16 @@ struct dig_lookup { struct dig_query { dig_lookup_t *lookup; - isc_boolean_t working, - waiting_connect, + isc_boolean_t waiting_connect, first_pass, first_soa_rcvd, second_rr_rcvd, - first_repeat_rcvd; + first_repeat_rcvd, + recv_made; isc_uint32_t first_rr_serial; isc_uint32_t second_rr_serial; - int retries; + isc_uint32_t rr_count; + isc_uint32_t name_count; char *servname; isc_bufferlist_t sendlist, recvlist, @@ -173,12 +181,6 @@ debug(const char *format, ...); void check_result(isc_result_t result, const char *msg); -isc_boolean_t -isclass(char *text); - -isc_boolean_t -istype(char *text); - void setup_lookup(dig_lookup_t *lookup); @@ -191,9 +193,6 @@ start_lookup(void); void onrun_callback(isc_task_t *task, isc_event_t *event); -void -send_udp(dig_lookup_t *lookup); - int dhmain(int argc, char **argv); @@ -203,15 +202,28 @@ setup_libs(void); void setup_system(void); -void -free_lists(void); - dig_lookup_t * requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers); +dig_lookup_t * +make_empty_lookup(void); + +dig_lookup_t * +clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers); + dig_server_t * make_server(const char *servname); +void +clone_server_list(dig_serverlist_t src, + dig_serverlist_t *dest); + +void +cancel_all(void); + +void +destroy_libs(void); + /* * Routines needed in dig.c and host.c. */ @@ -227,6 +239,9 @@ trying(int frmsize, char *frm, dig_lookup_t *lookup); void dighost_shutdown(void); +char * +next_token(char **stringp, const char *delim); + ISC_LANG_ENDDECLS #endif diff --git a/bin/dig/nslookup.c b/bin/dig/nslookup.c index f00fc3a0f71..fd9a0da6ae3 100644 --- a/bin/dig/nslookup.c +++ b/bin/dig/nslookup.c @@ -1,21 +1,21 @@ /* * Copyright (C) 2000 Internet Software Consortium. - * + * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nslookup.c,v 1.20.2.8 2000/09/15 22:56:15 gson Exp $ */ +/* $Id: nslookup.c,v 1.20.2.9 2000/10/06 19:08:06 mws Exp $ */ #include @@ -23,21 +23,24 @@ extern int h_errno; -#include -#include -#include -#include -#include -#include #include #include #include -#include -#include +#include #include #include #include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include @@ -45,8 +48,8 @@ extern ISC_LIST(dig_lookup_t) lookup_list; extern ISC_LIST(dig_server_t) server_list; extern ISC_LIST(dig_searchlist_t) search_list; -extern isc_boolean_t have_ipv6, show_details, - usesearch, trace, qr, debugging; +extern isc_boolean_t have_ipv6, + usesearch, trace, qr, debugging, is_blocking; extern in_port_t port; extern unsigned int timeout; extern isc_mem_t *mctx; @@ -60,7 +63,7 @@ extern int lookup_counter; extern char fixeddomain[MXNAME]; extern int exitcode; extern isc_taskmgr_t *taskmgr; -extern isc_mempool_t *commctx; +extern isc_task_t *global_task; extern char *progname; isc_boolean_t short_form = ISC_TRUE, printcmd = ISC_TRUE, @@ -75,11 +78,10 @@ isc_boolean_t identify = ISC_FALSE, section_answer = ISC_TRUE, section_authority = ISC_TRUE, section_additional = ISC_TRUE, recurse = ISC_TRUE, defname = ISC_TRUE, aaonly = ISC_FALSE; -isc_mutex_t lock; -isc_condition_t cond; isc_boolean_t busy = ISC_FALSE, in_use = ISC_FALSE; char defclass[MXRD] = "IN"; char deftype[MXRD] = "A"; +isc_event_t *global_event = NULL; static const char *rcodetext[] = { "NOERROR", @@ -109,7 +111,7 @@ static const char *rtypetext[] = { "mf = ", /* 4 */ "canonical name = ", /* 5 */ "soa = ", /* 6 */ - "mb = ", /* 7 */ + "mb = ", /* 7 */ "mg = ", /* 8 */ "mr = ", /* 9 */ "rtype_10 = ", /* 10 */ @@ -146,41 +148,45 @@ static const char *rtypetext[] = { "optional = "}; /* 41 */ +static void flush_lookup_list(void); +static void getinput(isc_task_t *task, isc_event_t *event); + static void show_usage(void) { - fputs ( -"Usage:\n" -, stderr); -} + fputs("Usage:\n", stderr); +} void dighost_shutdown(void) { + isc_event_t *event = global_event; - debug ("dighost_dhutdown()"); - isc_mutex_lock(&lock); - busy = ISC_FALSE; - debug ("signalling out"); - isc_condition_signal(&cond); - isc_mutex_unlock(&lock); + flush_lookup_list(); + debug("dighost_shutdown()"); + + if (!in_use) { + isc_app_shutdown(); + return; + } + isc_task_send(global_task, &event); } + void received(int bytes, int frmsize, char *frm, dig_query_t *query) { - UNUSED (bytes); - UNUSED (frmsize); - UNUSED (frm); - UNUSED (query); + UNUSED(bytes); + UNUSED(frmsize); + UNUSED(frm); + UNUSED(query); } void trying(int frmsize, char *frm, dig_lookup_t *lookup) { - UNUSED (frmsize); - UNUSED (frm); - UNUSED (lookup); + UNUSED(frmsize); + UNUSED(frm); + UNUSED(lookup); } - static isc_result_t printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_section_t section) { @@ -190,20 +196,13 @@ printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_rdataset_t *rdataset = NULL; dns_rdata_t rdata; char *ptr; + char *input; - UNUSED (query); - UNUSED (headers); + UNUSED(query); + UNUSED(headers); debug("printsection()"); - /* - * Exitcode 9 means we timed out, but if we're printing a message, - * we much have recovered. Go ahead and reset it to code 0, and - * call this a success. - */ - if (exitcode == 9) - exitcode = 0; - result = dns_message_firstname(msg, section); if (result == ISC_R_NOMORE) return (ISC_R_SUCCESS); @@ -213,7 +212,7 @@ printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, check_result(result, "isc_buffer_allocate"); for (;;) { name = NULL; - dns_message_currentname(msg, section, + dns_message_currentname(msg, section, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -261,41 +260,41 @@ printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, check_result(result, "dns_rdata_totext"); ((char *)isc_buffer_used(b))[0]=0; - ptr = strtok(isc_buffer_base(b), - " \t\r\n"); + input = isc_buffer_base(b); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\torigin = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tmail addr = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tserial = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\trefresh = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tretry = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\texpire = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tminimum = %s\n", @@ -310,24 +309,24 @@ printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, check_result(result, "dns_name_totext"); if (rdata.type <= 41) - printf ("%.*s\t%s", + printf("%.*s\t%s", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b), rtypetext[rdata.type]); else - printf ("%.*s\trdata_%d = ", + printf("%.*s\trdata_%d = ", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b), rdata.type); isc_buffer_clear(b); - result = dns_rdata_totext(&rdata, + result = dns_rdata_totext(&rdata, NULL, b); check_result(result, "dns_rdata_totext"); printf("%.*s\n", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); - } + } loopresult = dns_rdataset_next(rdataset); } } @@ -352,32 +351,25 @@ detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_rdataset_t *rdataset = NULL; dns_rdata_t rdata; char *ptr; + char *input; - UNUSED (query); + UNUSED(query); debug("detailsection()"); - /* - * Exitcode 9 means we timed out, but if we're printing a message, - * we much have recovered. Go ahead and reset it to code 0, and - * call this a success. - */ - if (exitcode == 9) - exitcode = 0; - if (headers) { switch (section) { case DNS_SECTION_QUESTION: - puts (" QUESTIONS:"); + puts(" QUESTIONS:"); break; case DNS_SECTION_ANSWER: - puts (" ANSWERS:"); + puts(" ANSWERS:"); break; case DNS_SECTION_AUTHORITY: - puts (" AUTHORITY RECORDS:"); + puts(" AUTHORITY RECORDS:"); break; case DNS_SECTION_ADDITIONAL: - puts (" ADDITIONAL RECORDS:"); + puts(" ADDITIONAL RECORDS:"); break; } } @@ -391,7 +383,7 @@ detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, check_result(result, "isc_buffer_allocate"); for (;;) { name = NULL; - dns_message_currentname(msg, section, + dns_message_currentname(msg, section, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -417,41 +409,41 @@ detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, check_result(result, "dns_rdata_totext"); ((char *)isc_buffer_used(b))[0]=0; - ptr = strtok(isc_buffer_base(b), - " \t\r\n"); + input = isc_buffer_base(b); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\torigin = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tmail addr = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tserial = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\trefresh = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tretry = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\texpire = %s\n", ptr); - ptr = strtok(NULL, " \t\r\n"); + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) break; printf("\tminimum = %s\n", @@ -460,20 +452,20 @@ detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, default: isc_buffer_clear(b); if (rdata.type <= 41) - printf ("\t%s", + printf("\t%s", rtypetext[rdata.type]); else - printf ("\trdata_%d = ", + printf("\trdata_%d = ", rdata.type); isc_buffer_clear(b); - result = dns_rdata_totext(&rdata, + result = dns_rdata_totext(&rdata, NULL, b); check_result(result, "dns_rdata_totext"); printf("%.*s\n", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); - } + } loopresult = dns_rdataset_next(rdataset); } } @@ -495,9 +487,8 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { isc_region_t r; isc_result_t result; - debug ("printmessage()"); - - debug ("continuing on with rcode != 0"); + debug("printmessage()"); + debug("continuing on with rcode != 0"); result = isc_buffer_allocate(mctx, &b, MXNAME); check_result(result, "isc_buffer_allocate"); printf("Server:\t\t%s\n", query->servname); @@ -507,6 +498,7 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { (char*)isc_buffer_base(b)); isc_buffer_free(&b); puts(""); + if (msg->rcode != 0) { result = isc_buffer_allocate(mctx, &b, MXNAME); check_result(result, "isc_buffer_allocate"); @@ -518,26 +510,30 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { (int)r.length, (char*)r.base, rcodetext[msg->rcode]); isc_buffer_free(&b); - debug ("returning with rcode == 0"); + debug("returning with rcode == 0"); return (ISC_R_SUCCESS); } if (!short_form){ - puts ("------------"); + puts("------------"); /* detailheader(query, msg);*/ detailsection(query, msg, headers, DNS_SECTION_QUESTION); detailsection(query, msg, headers, DNS_SECTION_ANSWER); detailsection(query, msg, headers, DNS_SECTION_AUTHORITY); detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL); - puts ("------------"); + puts("------------"); } - + if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) - puts ("Non-authorative answer:"); - printsection(query, msg, headers, DNS_SECTION_ANSWER); - + puts("Non-authorative answer:"); + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) + printsection(query, msg, headers, DNS_SECTION_ANSWER); + else + printf("*** Can't find %s: No answer\n", + query->lookup->textname); + if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && - (strcasecmp(query->lookup->rttext,"a") != 0)) { - puts ("\nAuthorative answers can be found from:"); + (query->lookup->rdtype != dns_rdatatype_a)) { + puts("\nAuthorative answers can be found from:"); printsection(query, msg, headers, DNS_SECTION_AUTHORITY); printsection(query, msg, headers, @@ -547,21 +543,21 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { } static void -show_settings(isc_boolean_t full) { +show_settings(isc_boolean_t full, isc_boolean_t serv_only) { dig_server_t *srv; isc_sockaddr_t sockaddr; isc_buffer_t *b = NULL; isc_result_t result; - + srv = ISC_LIST_HEAD(server_list); while (srv != NULL) { result = isc_buffer_allocate(mctx, &b, MXNAME); check_result(result, "isc_buffer_allocate"); - get_address(srv->servername, 53, &sockaddr); + get_address(srv->servername, port, &sockaddr); result = isc_sockaddr_totext(&sockaddr, b); check_result(result, "isc_sockaddr_totext"); - printf ("Default server: %s\nAddress: %.*s\n", + printf("Default server: %s\nAddress: %.*s\n", srv->servername, (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); isc_buffer_free(&b); @@ -569,19 +565,21 @@ show_settings(isc_boolean_t full) { return; srv = ISC_LIST_NEXT(srv, link); } - printf ("\n\tSet options:\n"); - printf ("\t %s\t\t\t%s\t\t%s\n", + if (serv_only) + return; + printf("\n\tSet options:\n"); + printf("\t %s\t\t\t%s\t\t%s\n", tcpmode?"vc":"novc", short_form?"nodebug":"debug", debugging?"d2":"nod2"); - printf ("\t %s\t\t%s\t\t%s\n", + printf("\t %s\t\t%s\t%s\n", defname?"defname":"nodefname", - usesearch?"search":"nosearch", + usesearch?"search ":"nosearch", recurse?"recurse":"norecurse"); - printf ("\t timeout = %d\t\tretry = %d\tport = %d\n", + printf("\t timeout = %d\t\tretry = %d\tport = %d\n", timeout, tries, port); - printf ("\t querytype = %-8s\tclass=%s\n",deftype, defclass); + printf("\t querytype = %-8s\tclass = %s\n", deftype, defclass); #if 0 - printf ("\t domain = %s\n", fixeddomain); + printf("\t domain = %s\n", fixeddomain); #endif } @@ -591,7 +589,7 @@ testtype(char *typetext) { isc_result_t result; isc_textregion_t tr; dns_rdatatype_t rdtype; - + tr.base = typetext; tr.length = strlen(typetext); result = dns_rdatatype_fromtext(&rdtype, &tr); @@ -620,40 +618,44 @@ testclass(char *typetext) { } } +static void +safecpy(char *dest, char *src, int size) { + strncpy(dest, src, size); + dest[size-1]=0; +} + static void setoption(char *opt) { - dig_server_t *srv; - - if (strncasecmp(opt,"all",4) == 0) { - show_settings(ISC_TRUE); + if (strncasecmp(opt, "all", 4) == 0) { + show_settings(ISC_TRUE, ISC_FALSE); } else if (strncasecmp(opt, "class=", 6) == 0) { if (testclass(&opt[6])) - strncpy(defclass, &opt[6], MXRD); + safecpy(defclass, &opt[6], MXRD); } else if (strncasecmp(opt, "cl=", 3) == 0) { if (testclass(&opt[3])) - strncpy(defclass, &opt[3], MXRD); + safecpy(defclass, &opt[3], MXRD); } else if (strncasecmp(opt, "type=", 5) == 0) { if (testtype(&opt[5])) - strncpy(deftype, &opt[5], MXRD); + safecpy(deftype, &opt[3], MXRD); } else if (strncasecmp(opt, "ty=", 3) == 0) { if (testtype(&opt[3])) - strncpy(deftype, &opt[3], MXRD); + safecpy(deftype, &opt[3], MXRD); } else if (strncasecmp(opt, "querytype=", 10) == 0) { if (testtype(&opt[10])) - strncpy(deftype, &opt[10], MXRD); + safecpy(deftype, &opt[10], MXRD); } else if (strncasecmp(opt, "query=", 6) == 0) { if (testtype(&opt[6])) - strncpy(deftype, &opt[6], MXRD); + safecpy(deftype, &opt[6], MXRD); } else if (strncasecmp(opt, "qu=", 3) == 0) { if (testtype(&opt[3])) - strncpy(deftype, &opt[3], MXRD); + safecpy(deftype, &opt[3], MXRD); #if 0 /* XXXMWS domain= doesn't work now. */ } else if (strncasecmp(opt, "domain=", 7) == 0) { - strncpy(fixeddomain, &opt[7], MXNAME); + safecpy(fixeddomain, &opt[7], MXNAME); } else if (strncasecmp(opt, "do=", 3) == 0) { - strncpy(fixeddomain, &opt[3], MXNAME); + safecpy(fixeddomain, &opt[3], MXNAME); #endif } else if (strncasecmp(opt, "port=", 5) == 0) { port = atoi(&opt[5]); @@ -679,61 +681,95 @@ setoption(char *opt) { debugging = ISC_TRUE; } else if (strncasecmp(opt, "nod2", 4) == 0) { debugging = ISC_FALSE; + } else if (strncasecmp(opt, "search",3) == 0) { + usesearch = ISC_TRUE; + } else if (strncasecmp(opt, "nosearch",5) == 0) { + usesearch = ISC_FALSE; } else if (strncasecmp(opt, "sil",3) == 0) { deprecation_msg = ISC_FALSE; } else { - srv = make_server(opt); - debug("server is %s", srv->servername); - ISC_LIST_APPEND(server_list, srv, link); + printf("*** Invalid option: %s\n", opt); } } static dig_lookup_t* addlookup(char *opt) { dig_lookup_t *lookup; + isc_result_t result; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; - debug ("addlookup()"); - lookup = isc_mem_allocate(mctx, sizeof(struct dig_lookup)); - if (lookup == NULL) - fatal("Memory allocation failure."); - lookup->pending = ISC_FALSE; - strncpy(lookup->textname, opt, MXNAME-1); - if (istype(deftype)) - strncpy(lookup->rttext, deftype, MXNAME); - else { - strcpy(lookup->rttext, "a"); - printf ("unknown query type: %s\n",deftype); + debug("addlookup()"); + tr.base = deftype; + tr.length = strlen(deftype); + result = dns_rdatatype_fromtext(&rdtype, &tr); + if (result != ISC_R_SUCCESS) { + printf("unknown query type: %s\n", deftype); + rdclass = dns_rdatatype_a; } - if (isclass(defclass)) - strncpy(lookup->rctext, defclass, MXNAME); - else { - strcpy(lookup->rctext, "in"); - printf ("unknown query class: %s\n",defclass); + tr.base = defclass; + tr.length = strlen(defclass); + result = dns_rdataclass_fromtext(&rdclass, &tr); + if (result != ISC_R_SUCCESS) { + printf("unknown query class: %s\n", defclass); + rdclass = dns_rdataclass_in; } - lookup->namespace[0]=0; - lookup->sendspace = NULL; - lookup->sendmsg=NULL; - lookup->name=NULL; - lookup->oname=NULL; - lookup->timer = NULL; - lookup->xfr_q = NULL; - lookup->origin = NULL; - lookup->querysig = NULL; - lookup->use_my_server_list = ISC_FALSE; - lookup->doing_xfr = ISC_FALSE; - lookup->ixfr_serial = 0; - lookup->defname = ISC_FALSE; + lookup = make_empty_lookup(); + if (strspn(opt, "0123456789.") == strlen(opt)) { + int n, i, adrs[4]; + char store[MXNAME]; + + lookup->textname[0] = 0; + n = sscanf(opt, "%d.%d.%d.%d", &adrs[0], &adrs[1], + &adrs[2], &adrs[3]); + if (n == 0) { + show_usage(); + } + for (i = n - 1; i >= 0; i--) { + snprintf(store, MXNAME/8, "%d.", + adrs[i]); + strncat(lookup->textname, store, MXNAME); + } + strncat(lookup->textname, "in-addr.arpa.", MXNAME); + lookup->rdtype = dns_rdatatype_ptr; + } else if (strspn(opt, "0123456789abcdef.:") == strlen(opt)) + { + isc_netaddr_t addr; + dns_fixedname_t fname; + isc_buffer_t b; + int n; + + addr.family = AF_INET6; + n = inet_pton(AF_INET6, opt, &addr.type.in6); + if (n <= 0) + goto notv6; + dns_fixedname_init(&fname); + result = dns_byaddr_createptrname(&addr, lookup->nibble, + dns_fixedname_name(&fname)); + if (result != ISC_R_SUCCESS) + show_usage(); + isc_buffer_init(&b, lookup->textname, sizeof lookup->textname); + result = dns_name_totext(dns_fixedname_name(&fname), + ISC_FALSE, &b); + isc_buffer_putuint8(&b, 0); + if (result != ISC_R_SUCCESS) + show_usage(); + lookup->rdtype = dns_rdatatype_ptr; + } else { + notv6: + safecpy(lookup->textname, opt, MXNAME-1); + lookup->rdtype = rdtype; + } + lookup->rdclass = rdclass; lookup->trace = ISC_TF(trace || ns_search_only); lookup->trace_root = trace; lookup->ns_search_only = ns_search_only; lookup->identify = identify; lookup->recurse = recurse; lookup->aaonly = aaonly; - lookup->adflag = ISC_FALSE; - lookup->cdflag = ISC_FALSE; lookup->retries = tries; lookup->udpsize = bufsize; - lookup->nsfound = 0; lookup->comments = comments; lookup->tcp_mode = tcpmode; lookup->stats = stats; @@ -754,7 +790,7 @@ static void flush_server_list(void) { dig_server_t *s, *ps; - debug ("flush_lookup_list()"); + debug("flush_server_list()"); s = ISC_LIST_HEAD(server_list); while (s != NULL) { ps = s; @@ -762,10 +798,9 @@ flush_server_list(void) { ISC_LIST_DEQUEUE(server_list, ps, link); isc_mem_free(mctx, ps); } - } -/* +/* * This works on the global server list, instead of on a per-lookup * server list, since the change is persistent. */ @@ -773,53 +808,65 @@ static void setsrv(char *opt) { dig_server_t *srv; + if (opt == NULL) { + return; + } flush_server_list(); srv=isc_mem_allocate(mctx, sizeof(struct dig_server)); if (srv == NULL) fatal("Memory allocation failure."); - strncpy(srv->servername, opt, MXNAME-1); + safecpy(srv->servername, opt, MXNAME-1); ISC_LIST_APPEND(server_list, srv, link); } static void get_next_command(void) { - char input[COMMSIZE]; + char *buf; char *ptr, *arg; + char *input; + buf = isc_mem_allocate(mctx, COMMSIZE); + if (buf == NULL) + fatal("Memory allocation failure."); fputs("> ", stderr); - ptr = fgets(input, COMMSIZE, stdin); + is_blocking = ISC_TRUE; + ptr = fgets(buf, COMMSIZE, stdin); + is_blocking = ISC_FALSE; if (ptr == NULL) { in_use = ISC_FALSE; - return; + goto cleanup; } - ptr = strtok(input, " \t\r\n"); + input = buf; + ptr = next_token(&input, " \t\r\n"); if (ptr == NULL) - return; - arg = strtok(NULL, " \t\r\n"); + goto cleanup; + arg = next_token(&input, " \t\r\n"); if ((strcasecmp(ptr, "set") == 0) && (arg != NULL)) setoption(arg); else if ((strcasecmp(ptr, "server") == 0) || (strcasecmp(ptr, "lserver") == 0)) { - printf("Server:\t%s\n", arg); setsrv(arg); + show_settings(ISC_TRUE, ISC_TRUE); } else if (strcasecmp(ptr, "exit") == 0) { in_use = ISC_FALSE; - return; + goto cleanup; } else if (strcasecmp(ptr, "help") == 0 || strcasecmp(ptr, "?") == 0) { printf("The '%s' command is not yet implemented.\n", ptr); - return; + goto cleanup; } else if (strcasecmp(ptr, "finger") == 0 || strcasecmp(ptr, "root") == 0 || strcasecmp(ptr, "ls") == 0 || strcasecmp(ptr, "view") == 0) { printf("The '%s' command is not implemented.\n", ptr); - return; - } else + goto cleanup; + } else addlookup(ptr); + cleanup: + isc_mem_free(mctx, buf); } static void @@ -828,7 +875,7 @@ parse_args(int argc, char **argv) { isc_boolean_t have_lookup = ISC_FALSE; for (argc--, argv++; argc > 0; argc--, argv++) { - debug ("main parsing %s", argv[0]); + debug("main parsing %s", argv[0]); if (argv[0][0] == '-') { if ((argv[0][1] == 'h') && (argv[0][2] == 0)) { @@ -873,8 +920,6 @@ flush_lookup_list(void) { if (ISC_LINK_LINKED(&q->lengthbuf, link)) ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf, link); - INSIST(q->recvspace != NULL); - isc_mempool_put(commctx, q->recvspace); isc_buffer_invalidate(&q->recvbuf); isc_buffer_invalidate(&q->lengthbuf); qp = q; @@ -882,20 +927,16 @@ flush_lookup_list(void) { ISC_LIST_DEQUEUE(l->q, qp, link); isc_mem_free(mctx, qp); } - if (l->use_my_server_list) { - s = ISC_LIST_HEAD(l->my_server_list); - while (s != NULL) { - sp = s; - s = ISC_LIST_NEXT(s, link); - ISC_LIST_DEQUEUE(l->my_server_list, sp, link); - isc_mem_free(mctx, sp); + s = ISC_LIST_HEAD(l->my_server_list); + while (s != NULL) { + sp = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(l->my_server_list, sp, link); + isc_mem_free(mctx, sp); - } } if (l->sendmsg != NULL) dns_message_destroy(&l->sendmsg); - if (l->sendspace != NULL) - isc_mempool_put(commctx, l->sendspace); if (l->timer != NULL) isc_timer_detach(&l->timer); lp = l; @@ -903,7 +944,22 @@ flush_lookup_list(void) { ISC_LIST_DEQUEUE(lookup_list, lp, link); isc_mem_free(mctx, lp); } -} +} + +static void +getinput(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + if (global_event == NULL) + global_event = event; + while (in_use) { + get_next_command(); + if (ISC_LIST_HEAD(lookup_list) != NULL) { + start_lookup(); + return; + } + } + isc_app_shutdown(); +} int main(int argc, char **argv) { @@ -913,68 +969,38 @@ main(int argc, char **argv) { ISC_LIST_INIT(server_list); ISC_LIST_INIT(search_list); + result = isc_app_start(); + check_result(result, "isc_app_start"); + setup_libs(); progname = argv[0]; - result = isc_mutex_init(&lock); - check_result(result, "isc_mutex_init"); - result = isc_condition_init(&cond); - check_result(result, "isc_condition_init"); - result = isc_mutex_trylock(&lock); - check_result(result, "isc_mutex_trylock"); parse_args(argc, argv); if (deprecation_msg) { - puts ( + fputs( "Note: nslookup is deprecated and may be removed from future releases.\n" "Consider using the `dig' or `host' programs instead. Run nslookup with\n" -"the `-sil[ent]' option to prevent this message from appearing.\n"); +"the `-sil[ent]' option to prevent this message from appearing.\n", stderr); } setup_system(); - if (in_use) { - busy = ISC_TRUE; - start_lookup(); - while (busy) { - result = isc_condition_wait(&cond, &lock); - check_result(result, "isc_condition_wait"); - } - flush_lookup_list(); - in_use = ISC_FALSE; - } else { - show_settings(ISC_FALSE); - in_use = ISC_TRUE; - } + if (in_use) + result = isc_app_onrun(mctx, global_task, onrun_callback, + NULL); + else + result = isc_app_onrun(mctx, global_task, getinput, NULL); + check_result(result, "isc_app_onrun"); + in_use = ISC_TF(!in_use); - while (in_use) { - get_next_command(); - if (ISC_LIST_HEAD(lookup_list) != NULL) { - busy = ISC_TRUE; - start_lookup(); - while (busy) { - result = isc_condition_wait(&cond, &lock); - check_result(result, "isc_condition_wait"); - } - debug ("out of the condition wait"); - flush_lookup_list(); - } - } + (void)isc_app_run(); - puts (""); - debug ("done, and starting to shut down"); - free_lists(); - isc_mutex_destroy(&lock); - isc_condition_destroy(&cond); - if (taskmgr != NULL) { - debug ("freeing taskmgr"); - isc_taskmgr_destroy(&taskmgr); - } - if (isc_mem_debugging) - isc_mem_stats(mctx, stderr); + puts(""); + debug("done, and starting to shut down"); + if (global_event != NULL) + isc_event_free(&global_event); + destroy_libs(); isc_app_finish(); - if (mctx != NULL) - isc_mem_destroy(&mctx); - + return (0); } -