nslookup.c revision cc48bb397fa6ba889f25157840492e68114dec8f
/*
* 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.37 2000/09/01 21:54:23 bwelling Exp $ */
#include <config.h>
#include <stdlib.h>
extern int h_errno;
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/commandline.h>
#include <isc/condition.h>
#include <isc/mutex.h>
#include <isc/string.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <isc/task.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_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()");
isc_mutex_lock(&lock);
busy = ISC_FALSE;
debug("signalling out");
isc_condition_signal(&cond);
isc_mutex_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) {
in_use = ISC_FALSE;
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
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");
result = isc_mutex_trylock(&lock);
check_result(result, "isc_mutex_trylock");
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();
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);
}