/* * 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: nslookup.c,v 1.40 2000/09/01 22:45:16 bwelling Exp $ */ #include #include extern int h_errno; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern ISC_LIST(dig_lookup_t) lookup_list; extern ISC_LIST(dig_server_t) server_list; extern ISC_LIST(dig_searchlist_t) search_list; extern isc_boolean_t have_ipv6, show_details, usesearch, trace, qr, debugging; extern in_port_t port; extern unsigned int timeout; extern isc_mem_t *mctx; extern dns_messageid_t id; extern char *rootspace[BUFSIZE]; extern isc_buffer_t rootbuf; extern int sendcount; extern int ndots; extern int tries; extern int lookup_counter; extern char fixeddomain[MXNAME]; extern int exitcode; extern isc_taskmgr_t *taskmgr; extern char *progname; isc_boolean_t short_form = ISC_TRUE, printcmd = ISC_TRUE, filter = ISC_FALSE, showallsoa = ISC_FALSE, tcpmode = ISC_FALSE, deprecation_msg = ISC_TRUE; 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; 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"; static const char *rcodetext[] = { "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMPL", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", "RESERVED11", "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", "BADVERS" }; static const char *rtypetext[] = { "rtype_0 = ", /* 0 */ "internet address = ", /* 1 */ "nameserver = ", /* 2 */ "md = ", /* 3 */ "mf = ", /* 4 */ "canonical name = ", /* 5 */ "soa = ", /* 6 */ "mb = ", /* 7 */ "mg = ", /* 8 */ "mr = ", /* 9 */ "rtype_10 = ", /* 10 */ "protocol = ", /* 11 */ "name = ", /* 12 */ "hinfo = ", /* 13 */ "minfo = ", /* 14 */ "mail exchanger = ", /* 15 */ "text = ", /* 16 */ "rp = ", /* 17 */ "afsdb = ", /* 18 */ "x25 address = ", /* 19 */ "isdn address = ", /* 20 */ "rt = ", /* 21 */ "nsap = ", /* 22 */ "nsap_ptr = ", /* 23 */ "signature = ", /* 24 */ "key = ", /* 25 */ "px = ", /* 26 */ "gpos = ", /* 27 */ "has AAAA address", /* 28 */ "loc = ", /* 29 */ "next = ", /* 30 */ "rtype_31 = ", /* 31 */ "rtype_32 = ", /* 32 */ "service = ", /* 33 */ "rtype_34 = ", /* 34 */ "naptr = ", /* 35 */ "kx = ", /* 36 */ "cert = ", /* 37 */ "v6 address = ", /* 38 */ "dname = ", /* 39 */ "rtype_40 = ", /* 40 */ "optional = "}; /* 41 */ static void show_usage(void) { fputs("Usage:\n", stderr); } void dighost_shutdown(void) { debug("dighost_shutdown()"); LOCK(&lock); busy = ISC_FALSE; debug("signalling out"); isc_condition_signal(&cond); UNLOCK(&lock); } void received(int bytes, int frmsize, char *frm, dig_query_t *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); } static isc_result_t printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_section_t section) { isc_result_t result, loopresult; isc_buffer_t *b = NULL; dns_name_t *name; dns_rdataset_t *rdataset = NULL; dns_rdata_t rdata; char *ptr; UNUSED(query); UNUSED(headers); debug("printsection()"); result = dns_message_firstname(msg, section); if (result == ISC_R_NOMORE) return (ISC_R_SUCCESS); else if (result != ISC_R_SUCCESS) return (result); result = isc_buffer_allocate(mctx, &b, MXNAME); check_result(result, "isc_buffer_allocate"); for (;;) { name = NULL; dns_message_currentname(msg, section, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { loopresult = dns_rdataset_first(rdataset); while (loopresult == ISC_R_SUCCESS) { dns_rdataset_current(rdataset, &rdata); switch (rdata.type) { case dns_rdatatype_a: if (section != DNS_SECTION_ANSWER) goto def_short_section; isc_buffer_clear(b); result = dns_name_totext(name, ISC_TRUE, b); check_result(result, "dns_name_totext"); printf("Name:\t%.*s\n", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); isc_buffer_clear(b); result = dns_rdata_totext(&rdata, NULL, b); check_result(result, "dns_rdata_totext"); printf("Address: %.*s\n", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); break; case dns_rdatatype_soa: isc_buffer_clear(b); result = dns_name_totext(name, ISC_TRUE, b); check_result(result, "dns_name_totext"); printf("%.*s\n", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); isc_buffer_clear(b); result = dns_rdata_totext(&rdata, NULL, b); check_result(result, "dns_rdata_totext"); ((char *)isc_buffer_used(b))[0]=0; ptr = strtok(isc_buffer_base(b), " \t\r\n"); if (ptr == NULL) break; printf("\torigin = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tmail addr = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tserial = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\trefresh = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tretry = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\texpire = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tminimum = %s\n", ptr); break; default: def_short_section: isc_buffer_clear(b); result = dns_name_totext(name, ISC_TRUE, b); check_result(result, "dns_name_totext"); if (rdata.type <= 41) printf("%.*s\t%s", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b), rtypetext[rdata.type]); else 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, 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); } } result = dns_message_nextname(msg, section); if (result == ISC_R_NOMORE) break; else if (result != ISC_R_SUCCESS) { isc_buffer_free (&b); return (result); } } isc_buffer_free(&b); return (ISC_R_SUCCESS); } static isc_result_t detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_section_t section) { isc_result_t result, loopresult; isc_buffer_t *b = NULL; dns_name_t *name; dns_rdataset_t *rdataset = NULL; dns_rdata_t rdata; char *ptr; UNUSED(query); debug("detailsection()"); if (headers) { switch (section) { case DNS_SECTION_QUESTION: puts(" QUESTIONS:"); break; case DNS_SECTION_ANSWER: puts(" ANSWERS:"); break; case DNS_SECTION_AUTHORITY: puts(" AUTHORITY RECORDS:"); break; case DNS_SECTION_ADDITIONAL: puts(" ADDITIONAL RECORDS:"); break; } } result = dns_message_firstname(msg, section); if (result == ISC_R_NOMORE) return (ISC_R_SUCCESS); else if (result != ISC_R_SUCCESS) return (result); result = isc_buffer_allocate(mctx, &b, MXNAME); check_result(result, "isc_buffer_allocate"); for (;;) { name = NULL; dns_message_currentname(msg, section, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { loopresult = dns_rdataset_first(rdataset); while (loopresult == ISC_R_SUCCESS) { dns_rdataset_current(rdataset, &rdata); isc_buffer_clear(b); result = dns_name_totext(name, ISC_TRUE, b); check_result(result, "dns_name_totext"); printf(" -> %.*s\n", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); switch (rdata.type) { case dns_rdatatype_soa: isc_buffer_clear(b); result = dns_rdata_totext(&rdata, NULL, b); check_result(result, "dns_rdata_totext"); ((char *)isc_buffer_used(b))[0]=0; ptr = strtok(isc_buffer_base(b), " \t\r\n"); if (ptr == NULL) break; printf("\torigin = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tmail addr = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tserial = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\trefresh = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tretry = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\texpire = %s\n", ptr); ptr = strtok(NULL, " \t\r\n"); if (ptr == NULL) break; printf("\tminimum = %s\n", ptr); break; default: isc_buffer_clear(b); if (rdata.type <= 41) printf("\t%s", rtypetext[rdata.type]); else printf("\trdata_%d = ", rdata.type); isc_buffer_clear(b); 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); } } result = dns_message_nextname(msg, section); if (result == ISC_R_NOMORE) break; else if (result != ISC_R_SUCCESS) { isc_buffer_free (&b); return (result); } } isc_buffer_free(&b); return (ISC_R_SUCCESS); } isc_result_t printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { isc_buffer_t *b = NULL; isc_region_t r; isc_result_t result; debug("printmessage()"); if (msg->rcode != 0) { result = isc_buffer_allocate(mctx, &b, MXNAME); check_result(result, "isc_buffer_allocate"); result = dns_name_totext(query->lookup->name, ISC_FALSE, b); check_result(result, "dns_name_totext"); isc_buffer_usedregion(b, &r); printf("** server can't find %.*s: %s\n", (int)r.length, (char*)r.base, rcodetext[msg->rcode]); isc_buffer_free(&b); debug("returning with rcode == 0"); return (ISC_R_SUCCESS); } 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); result = isc_sockaddr_totext(&query->sockaddr, b); check_result(result, "isc_sockaddr_totext"); printf("Address:\t%.*s\n", (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); isc_buffer_free(&b); puts(""); if (!short_form){ 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("------------"); } if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) puts("Non-authorative answer:"); printsection(query, msg, headers, DNS_SECTION_ANSWER); if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && (query->lookup->rdtype != dns_rdatatype_a)) { puts("\nAuthorative answers can be found from:"); printsection(query, msg, headers, DNS_SECTION_AUTHORITY); printsection(query, msg, headers, DNS_SECTION_ADDITIONAL); } return (ISC_R_SUCCESS); } static void show_settings(isc_boolean_t full) { 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); result = isc_sockaddr_totext(&sockaddr, b); check_result(result, "isc_sockaddr_totext"); printf("Default server: %s\nAddress: %.*s\n", srv->servername, (int)isc_buffer_usedlength(b), (char*)isc_buffer_base(b)); isc_buffer_free(&b); if (!full) return; srv = ISC_LIST_NEXT(srv, link); } 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%s\n", defname?"defname":"nodefname", usesearch?"search ":"nosearch", recurse?"recurse":"norecurse"); printf("\t timeout = %d\t\tretry = %d\tport = %d\n", timeout, tries, port); printf("\t querytype = %-8s\tclass = %s\n",deftype, defclass); #if 0 printf("\t domain = %s\n", fixeddomain); #endif } static isc_boolean_t testtype(char *typetext) { isc_result_t result; isc_textregion_t tr; dns_rdatatype_t rdtype; tr.base = typetext; tr.length = strlen(typetext); result = dns_rdatatype_fromtext(&rdtype, &tr); return (ISC_TF(result == ISC_R_SUCCESS)); } static isc_boolean_t testclass(char *typetext) { isc_result_t result; isc_textregion_t tr; dns_rdataclass_t rdclass; tr.base = typetext; tr.length = strlen(typetext); result = dns_rdataclass_fromtext(&rdclass, &tr); return (ISC_TF(result == ISC_R_SUCCESS)); } static void setoption(char *opt) { dig_server_t *srv; if (strncasecmp(opt,"all",4) == 0) { show_settings(ISC_TRUE); } else if (strncasecmp(opt, "class=", 6) == 0) { strncpy(defclass, &opt[6], MXRD); } else if (strncasecmp(opt, "cl=", 3) == 0) { strncpy(defclass, &opt[3], MXRD); } else if (strncasecmp(opt, "type=", 5) == 0) { if (testtype(&opt[5])) strncpy(deftype, &opt[5], MXRD); } else if (strncasecmp(opt, "ty=", 3) == 0) { if (testclass(&opt[3])) strncpy(defclass, &opt[3], MXRD); } else if (strncasecmp(opt, "querytype=", 10) == 0) { strncpy(deftype, &opt[10], MXRD); } else if (strncasecmp(opt, "query=", 6) == 0) { strncpy(deftype, &opt[6], MXRD); } else if (strncasecmp(opt, "qu=", 3) == 0) { strncpy(deftype, &opt[3], MXRD); #if 0 /* XXXMWS domain= doesn't work now. */ } else if (strncasecmp(opt, "domain=", 7) == 0) { strncpy(fixeddomain, &opt[7], MXNAME); } else if (strncasecmp(opt, "do=", 3) == 0) { strncpy(fixeddomain, &opt[3], MXNAME); #endif } else if (strncasecmp(opt, "port=", 5) == 0) { port = atoi(&opt[5]); } else if (strncasecmp(opt, "po=", 3) == 0) { port = atoi(&opt[3]); } else if (strncasecmp(opt, "timeout=", 8) == 0) { timeout = atoi(&opt[8]); } else if (strncasecmp(opt, "t=", 2) == 0) { timeout = atoi(&opt[2]); } else if (strncasecmp(opt, "retry=", 6) == 0) { tries = atoi(&opt[6]); } else if (strncasecmp(opt, "ret=", 4) == 0) { tries = atoi(&opt[4]); } else if (strncasecmp(opt, "def", 3) == 0) { defname = ISC_TRUE; } else if (strncasecmp(opt, "nodef", 5) == 0) { defname = ISC_FALSE; } else if (strncasecmp(opt, "deb", 3) == 0) { short_form = ISC_FALSE; } else if (strncasecmp(opt, "nodeb", 5) == 0) { short_form = ISC_TRUE; } else if (strncasecmp(opt, "d2", 2) == 0) { debugging = ISC_TRUE; } else if (strncasecmp(opt, "nod2", 4) == 0) { debugging = 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); } } 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()"); tr.base = deftype; tr.length = strlen(deftype); result = dns_rdatatype_fromtext(&rdtype, &tr); INSIST(result == ISC_R_SUCCESS); tr.base = defclass; tr.length = strlen(defclass); result = dns_rdataclass_fromtext(&rdclass, &tr); INSIST(result == ISC_R_SUCCESS); lookup = make_empty_lookup(); strncpy(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->retries = tries; lookup->udpsize = bufsize; 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); debug("looking up %s", lookup->textname); return (lookup); } static void flush_server_list(void) { dig_server_t *s, *ps; debug("flush_lookup_list()"); s = ISC_LIST_HEAD(server_list); while (s != NULL) { ps = s; s = ISC_LIST_NEXT(s, link); 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. */ static void setsrv(char *opt) { dig_server_t *srv; 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); ISC_LIST_APPEND(server_list, srv, link); } static void get_next_command(void) { char input[COMMSIZE]; char *ptr, *arg; fputs("> ", stderr); ptr = fgets(input, COMMSIZE, stdin); if (ptr == NULL) { in_use = ISC_FALSE; return; } ptr = strtok(input, " \t\r\n"); if (ptr == NULL) return; arg = strtok(NULL, " \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); } else if (strcasecmp(ptr, "exit") == 0) { in_use = ISC_FALSE; return; } else if (strcasecmp(ptr, "help") == 0 || strcasecmp(ptr, "?") == 0) { printf("The '%s' command is not yet implemented.\n", ptr); return; } 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 addlookup(ptr); } static void parse_args(int argc, char **argv) { dig_lookup_t *lookup = NULL; isc_boolean_t have_lookup = ISC_FALSE; for (argc--, argv++; argc > 0; argc--, argv++) { debug("main parsing %s", argv[0]); if (argv[0][0] == '-') { if ((argv[0][1] == 'h') && (argv[0][2] == 0)) { show_usage(); exit (1); } if (argv[0][1] != 0) setoption(&argv[0][1]); else have_lookup = ISC_TRUE; } else { if (!have_lookup) { have_lookup = ISC_TRUE; in_use = ISC_TRUE; lookup = addlookup(argv[0]); } else setsrv(argv[0]); } } } static void flush_lookup_list(void) { dig_lookup_t *l, *lp; dig_query_t *q, *qp; dig_server_t *s, *sp; lookup_counter = 0; l = ISC_LIST_HEAD(lookup_list); while (l != NULL) { q = ISC_LIST_HEAD(l->q); while (q != NULL) { if (q->sock != NULL) { isc_socket_cancel(q->sock, NULL, ISC_SOCKCANCEL_ALL); isc_socket_detach(&q->sock); } 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); isc_buffer_invalidate(&q->recvbuf); isc_buffer_invalidate(&q->lengthbuf); qp = q; q = ISC_LIST_NEXT(q, link); ISC_LIST_DEQUEUE(l->q, qp, link); isc_mem_free(mctx, qp); } 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->timer != NULL) isc_timer_detach(&l->timer); lp = l; l = ISC_LIST_NEXT(l, link); ISC_LIST_DEQUEUE(lookup_list, lp, link); isc_mem_free(mctx, lp); } } int main(int argc, char **argv) { isc_result_t result; ISC_LIST_INIT(lookup_list); ISC_LIST_INIT(server_list); ISC_LIST_INIT(search_list); 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"); LOCK(&lock); parse_args(argc, argv); if (deprecation_msg) { 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", 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; } 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(); } } puts(""); debug("done, and starting to shut down"); destroy_libs(); UNLOCK(&lock); DESTROYLOCK(&lock); isc_condition_destroy(&cond); if (taskmgr != NULL) { debug("freeing taskmgr"); isc_taskmgr_destroy(&taskmgr); } if (isc_mem_debugging != 0) isc_mem_stats(mctx, stderr); isc_app_finish(); if (mctx != NULL) isc_mem_destroy(&mctx); return (0); }