Reviewed by myself and Brian.
# 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@
CINCLUDES = -I${srcdir}/include ${DNS_INCLUDES} ${ISC_INCLUDES}
-CDEFINES =
+CDEFINES = -DVERSION=\"${VERSION}\"
CWARNINGS =
DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_OPENSSL_LIBS@
OBJS = dig.@O@ dighost.@O@ host.@O@ nslookup.@O@
-UOBJS =
+UOBJS =
SRCS = dig.c dighost.c host.c nslookup.c
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}
/*
* 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 <config.h>
#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
#include <isc/app.h>
+#include <isc/netaddr.h>
#include <isc/string.h>
#include <isc/util.h>
#include <isc/task.h>
+#include <dns/byaddr.h>
+#include <dns/fixedname.h>
#include <dns/message.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdatatype.h>
+#include <dns/rdataclass.h>
#include <dig/dig.h>
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) { \
}
-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;
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",
" {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"
" +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"
" +[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;
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 "
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);
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;
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)
dns_name_t empty_name;
char t[4096];
dns_rdata_t rdata;
-
+
UNUSED(flags);
dns_name_init(&empty_name, NULL);
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;
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;
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
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;
printf("%scd", did_flag ? " " : "");
did_flag = ISC_TRUE;
}
-
+
printf("; QUERY: %u, ANSWER: %u, "
"AUTHORITY: %u, ADDITIONAL: %u\n",
msg->counts[DNS_SECTION_QUESTION],
result = dns_message_pseudosectiontotext(msg,
DNS_PSEUDOSECTION_OPT,
flags, buf);
- check_result(result,
+ check_result(result,
"dns_message_pseudosectiontotext");
}
}
}
check_result(result, "dns_message_sectiontotext");
}
- }
+ }
if (query->lookup->section_answer) {
if (!short_form) {
answer_again:
result = short_answer(msg, flags, buf, query);
check_result(result, "short_answer");
}
- }
+ }
if (query->lookup->section_authority) {
if (!short_form) {
authority_again:
}
check_result(result, "dns_message_sectiontotext");
}
- }
+ }
if (query->lookup->section_additional) {
if (!short_form) {
additional_again:
msg,
DNS_PSEUDOSECTION_SIG0,
flags, buf);
-
+
check_result(result,
"dns_message_pseudosectiontotext");
}
}
- }
+ }
if (headers && query->lookup->comments && !short_form)
printf("\n");
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" : "");
}
}
/*
* 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);
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);
}
/*
* 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
#include <isc/base64.h>
#include <isc/entropy.h>
#include <isc/lang.h>
-#include <isc/lex.h>
#include <isc/netdb.h>
#include <isc/result.h>
#include <isc/string.h>
#include <dig/dig.h>
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;
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;
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)
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);
}
va_list args;
if (debugging) {
- va_start(args, format);
+ va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
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));
}
}
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;
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];
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) {
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) &&
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));
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,
}
} 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
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,
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;
*/
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");
*/
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;
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;
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)
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()");
}
/*
- * 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) {
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;
}
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,
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 =
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);
loopresult = dns_rdataset_next(rdataset);
}
}
- result = dns_message_nextname (msg, section);
+ result = dns_message_nextname(msg, section);
if (result != ISC_R_SUCCESS)
break;
}
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;
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;
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);
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);
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);
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);
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);
&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);
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;
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
}
+ /* XXX aaflag */
if (lookup->aaonly) {
debug("AA query");
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
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);
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");
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)
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;
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);
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,
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,
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()");
* 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);
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
puts("; Transfer failed. "
"Didn't start with "
"SOA answer.");
- query->working = ISC_FALSE;
return (ISC_TRUE);
}
if ((!query->second_rr_rcvd) &&
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;
* 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
}
debug("done with ixfr");
dns_rdata_freestruct(&soa);
- goto xfr_done;
+ goto doexit;
}
debug("meaningless soa %d",
soa.serial);
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;
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;
}
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;
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);
}
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;
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));
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);
}
}
-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);
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);
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();
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);
}
/*
* 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 <config.h>
#include <stdlib.h>
#include <isc/app.h>
#include <isc/commandline.h>
+#include <isc/netaddr.h>
#include <isc/string.h>
#include <isc/util.h>
#include <isc/task.h>
+#include <dns/byaddr.h>
+#include <dns/fixedname.h>
#include <dns/message.h>
#include <dns/name.h>
#include <dns/rdata.h>
+#include <dns/rdataclass.h>
#include <dns/rdataset.h>
+#include <dns/rdatatype.h>
#include <dig/dig.h>
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",
"MF", /* 4 */
"is an alias for", /* 5 */
"SOA", /* 6 */
- "MB", /* 7 */
+ "MB", /* 7 */
"MG", /* 8 */
"MR", /* 9 */
"NULL", /* 10 */
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"
" -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();
}
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);
isc_boolean_t first;
isc_boolean_t no_rdata;
const char *rtt;
-
+
if (sectionid == DNS_SECTION_QUESTION)
no_rdata = ISC_TRUE;
else
#else
UNUSED(first); /* Shut up compiler. */
#endif
- } else {
+ } else {
loopresult = dns_rdataset_first(rdataset);
while (loopresult == ISC_R_SUCCESS) {
dns_rdataset_current(rdataset, &rdata);
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);
}
char t[4096];
UNUSED(msg);
- if (headers)
+ if (headers)
printf(";; %s SECTION:\n", set_name);
isc_buffer_init(&target, t, sizeof(t));
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);
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");
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
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;
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.",
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;
}
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);
}
/*
* 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
#include <isc/sockaddr.h>
#include <isc/socket.h>
-#define MXSERV 4
-#define MXNAME 1005
+#define MXSERV 6
+#define MXNAME (1024)
#define MXRD 32
#define BUFSIZE 512
#define COMMSIZE 0xffff
/*
* 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
/*
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 {
waiting_connect,
doing_xfr,
ns_search_only,
- use_my_server_list,
identify,
+ ignore,
recurse,
aaonly,
adflag,
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;
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;
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,
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);
void
onrun_callback(isc_task_t *task, isc_event_t *event);
-void
-send_udp(dig_lookup_t *lookup);
-
int
dhmain(int argc, char **argv);
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.
*/
void
dighost_shutdown(void);
+char *
+next_token(char **stringp, const char *delim);
+
ISC_LANG_ENDDECLS
#endif
/*
* 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 <config.h>
extern int h_errno;
-#include <dns/message.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataset.h>
-#include <dns/rdatatype.h>
-#include <dns/rdataclass.h>
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/commandline.h>
-#include <isc/condition.h>
-#include <isc/mutex.h>
+#include <isc/event.h>
#include <isc/string.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <isc/task.h>
+#include <isc/netaddr.h>
+
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/fixedname.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdataset.h>
+#include <dns/rdatatype.h>
+#include <dns/byaddr.h>
#include <dig/dig.h>
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;
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,
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",
"mf = ", /* 4 */
"canonical name = ", /* 5 */
"soa = ", /* 6 */
- "mb = ", /* 7 */
+ "mb = ", /* 7 */
"mg = ", /* 8 */
"mr = ", /* 9 */
"rtype_10 = ", /* 10 */
"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) {
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);
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;
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",
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);
}
}
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;
}
}
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;
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",
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);
}
}
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);
(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");
(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,
}
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);
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
}
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);
}
}
+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]);
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;
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;
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.
*/
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
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)) {
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;
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;
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) {
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);
}
-