nslookup.c revision 225361
1135446Strhodes/*
2225361Sdougb * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2000-2003  Internet Software Consortium.
4135446Strhodes *
5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18225361Sdougb/* $Id: nslookup.c,v 1.127.38.2 2011-02-28 01:19:58 tbox Exp $ */
19135446Strhodes
20135446Strhodes#include <config.h>
21135446Strhodes
22135446Strhodes#include <stdlib.h>
23135446Strhodes
24135446Strhodes#include <isc/app.h>
25135446Strhodes#include <isc/buffer.h>
26135446Strhodes#include <isc/commandline.h>
27135446Strhodes#include <isc/event.h>
28135446Strhodes#include <isc/parseint.h>
29193149Sdougb#include <isc/print.h>
30135446Strhodes#include <isc/string.h>
31135446Strhodes#include <isc/timer.h>
32135446Strhodes#include <isc/util.h>
33135446Strhodes#include <isc/task.h>
34135446Strhodes#include <isc/netaddr.h>
35135446Strhodes
36135446Strhodes#include <dns/message.h>
37135446Strhodes#include <dns/name.h>
38135446Strhodes#include <dns/fixedname.h>
39135446Strhodes#include <dns/rdata.h>
40135446Strhodes#include <dns/rdataclass.h>
41135446Strhodes#include <dns/rdataset.h>
42135446Strhodes#include <dns/rdatastruct.h>
43135446Strhodes#include <dns/rdatatype.h>
44135446Strhodes#include <dns/byaddr.h>
45135446Strhodes
46135446Strhodes#include <dig/dig.h>
47135446Strhodes
48135446Strhodesstatic isc_boolean_t short_form = ISC_TRUE,
49135446Strhodes	tcpmode = ISC_FALSE,
50135446Strhodes	identify = ISC_FALSE, stats = ISC_TRUE,
51135446Strhodes	comments = ISC_TRUE, section_question = ISC_TRUE,
52135446Strhodes	section_answer = ISC_TRUE, section_authority = ISC_TRUE,
53135446Strhodes	section_additional = ISC_TRUE, recurse = ISC_TRUE,
54170222Sdougb	aaonly = ISC_FALSE, nofail = ISC_TRUE;
55170222Sdougb
56135446Strhodesstatic isc_boolean_t in_use = ISC_FALSE;
57135446Strhodesstatic char defclass[MXRD] = "IN";
58135446Strhodesstatic char deftype[MXRD] = "A";
59135446Strhodesstatic isc_event_t *global_event = NULL;
60135446Strhodes
61135446Strhodesstatic char domainopt[DNS_NAME_MAXTEXT];
62135446Strhodes
63135446Strhodesstatic const char *rcodetext[] = {
64135446Strhodes	"NOERROR",
65135446Strhodes	"FORMERR",
66135446Strhodes	"SERVFAIL",
67135446Strhodes	"NXDOMAIN",
68135446Strhodes	"NOTIMP",
69135446Strhodes	"REFUSED",
70135446Strhodes	"YXDOMAIN",
71135446Strhodes	"YXRRSET",
72135446Strhodes	"NXRRSET",
73135446Strhodes	"NOTAUTH",
74135446Strhodes	"NOTZONE",
75135446Strhodes	"RESERVED11",
76135446Strhodes	"RESERVED12",
77135446Strhodes	"RESERVED13",
78135446Strhodes	"RESERVED14",
79135446Strhodes	"RESERVED15",
80135446Strhodes	"BADVERS"
81135446Strhodes};
82135446Strhodes
83135446Strhodesstatic const char *rtypetext[] = {
84135446Strhodes	"rtype_0 = ",			/* 0 */
85135446Strhodes	"internet address = ",		/* 1 */
86135446Strhodes	"nameserver = ",		/* 2 */
87135446Strhodes	"md = ",			/* 3 */
88135446Strhodes	"mf = ",			/* 4 */
89135446Strhodes	"canonical name = ",		/* 5 */
90135446Strhodes	"soa = ",			/* 6 */
91135446Strhodes	"mb = ",			/* 7 */
92135446Strhodes	"mg = ",			/* 8 */
93135446Strhodes	"mr = ",			/* 9 */
94135446Strhodes	"rtype_10 = ",			/* 10 */
95135446Strhodes	"protocol = ",			/* 11 */
96135446Strhodes	"name = ",			/* 12 */
97135446Strhodes	"hinfo = ",			/* 13 */
98135446Strhodes	"minfo = ",			/* 14 */
99135446Strhodes	"mail exchanger = ",		/* 15 */
100135446Strhodes	"text = ",			/* 16 */
101135446Strhodes	"rp = ",       			/* 17 */
102135446Strhodes	"afsdb = ",			/* 18 */
103135446Strhodes	"x25 address = ",		/* 19 */
104135446Strhodes	"isdn address = ",		/* 20 */
105135446Strhodes	"rt = ",			/* 21 */
106135446Strhodes	"nsap = ",			/* 22 */
107135446Strhodes	"nsap_ptr = ",			/* 23 */
108135446Strhodes	"signature = ",			/* 24 */
109135446Strhodes	"key = ",			/* 25 */
110135446Strhodes	"px = ",			/* 26 */
111135446Strhodes	"gpos = ",			/* 27 */
112135446Strhodes	"has AAAA address ",		/* 28 */
113135446Strhodes	"loc = ",			/* 29 */
114135446Strhodes	"next = ",			/* 30 */
115135446Strhodes	"rtype_31 = ",			/* 31 */
116135446Strhodes	"rtype_32 = ",			/* 32 */
117135446Strhodes	"service = ",			/* 33 */
118135446Strhodes	"rtype_34 = ",			/* 34 */
119135446Strhodes	"naptr = ",			/* 35 */
120135446Strhodes	"kx = ",			/* 36 */
121135446Strhodes	"cert = ",			/* 37 */
122135446Strhodes	"v6 address = ",		/* 38 */
123135446Strhodes	"dname = ",			/* 39 */
124135446Strhodes	"rtype_40 = ",			/* 40 */
125135446Strhodes	"optional = "			/* 41 */
126135446Strhodes};
127135446Strhodes
128135446Strhodes#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
129135446Strhodes
130135446Strhodesstatic void flush_lookup_list(void);
131135446Strhodesstatic void getinput(isc_task_t *task, isc_event_t *event);
132135446Strhodes
133193149Sdougbstatic char *
134193149Sdougbrcode_totext(dns_rcode_t rcode)
135193149Sdougb{
136193149Sdougb	static char buf[sizeof("?65535")];
137193149Sdougb	union {
138193149Sdougb		const char *consttext;
139193149Sdougb		char *deconsttext;
140193149Sdougb	} totext;
141193149Sdougb
142193149Sdougb	if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
143193149Sdougb		snprintf(buf, sizeof(buf), "?%u", rcode);
144193149Sdougb		totext.deconsttext = buf;
145193149Sdougb	} else
146193149Sdougb		totext.consttext = rcodetext[rcode];
147193149Sdougb	return totext.deconsttext;
148193149Sdougb}
149193149Sdougb
150135446Strhodesvoid
151135446Strhodesdighost_shutdown(void) {
152135446Strhodes	isc_event_t *event = global_event;
153135446Strhodes
154135446Strhodes	flush_lookup_list();
155135446Strhodes	debug("dighost_shutdown()");
156135446Strhodes
157135446Strhodes	if (!in_use) {
158135446Strhodes		isc_app_shutdown();
159135446Strhodes		return;
160135446Strhodes	}
161135446Strhodes
162135446Strhodes	isc_task_send(global_task, &event);
163135446Strhodes}
164135446Strhodes
165135446Strhodesstatic void
166135446Strhodesprintsoa(dns_rdata_t *rdata) {
167135446Strhodes	dns_rdata_soa_t soa;
168135446Strhodes	isc_result_t result;
169135446Strhodes	char namebuf[DNS_NAME_FORMATSIZE];
170135446Strhodes
171135446Strhodes	result = dns_rdata_tostruct(rdata, &soa, NULL);
172135446Strhodes	check_result(result, "dns_rdata_tostruct");
173135446Strhodes
174135446Strhodes	dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
175135446Strhodes	printf("\torigin = %s\n", namebuf);
176135446Strhodes	dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
177135446Strhodes	printf("\tmail addr = %s\n", namebuf);
178135446Strhodes	printf("\tserial = %u\n", soa.serial);
179135446Strhodes	printf("\trefresh = %u\n", soa.refresh);
180135446Strhodes	printf("\tretry = %u\n", soa.retry);
181135446Strhodes	printf("\texpire = %u\n", soa.expire);
182135446Strhodes	printf("\tminimum = %u\n", soa.minimum);
183135446Strhodes	dns_rdata_freestruct(&soa);
184135446Strhodes}
185135446Strhodes
186135446Strhodesstatic void
187135446Strhodesprinta(dns_rdata_t *rdata) {
188135446Strhodes	isc_result_t result;
189135446Strhodes	char text[sizeof("255.255.255.255")];
190135446Strhodes	isc_buffer_t b;
191135446Strhodes
192135446Strhodes	isc_buffer_init(&b, text, sizeof(text));
193135446Strhodes	result = dns_rdata_totext(rdata, NULL, &b);
194135446Strhodes	check_result(result, "dns_rdata_totext");
195135446Strhodes	printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
196135446Strhodes	       (char *)isc_buffer_base(&b));
197135446Strhodes}
198135446Strhodes#ifdef DIG_SIGCHASE
199135446Strhodes/* Just for compatibility : not use in host program */
200135446Strhodesisc_result_t
201135446Strhodesprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
202135446Strhodes	      isc_buffer_t *target)
203135446Strhodes{
204135446Strhodes	UNUSED(owner_name);
205135446Strhodes	UNUSED(rdataset);
206135446Strhodes	UNUSED(target);
207135446Strhodes	return(ISC_FALSE);
208135446Strhodes}
209135446Strhodes#endif
210135446Strhodesstatic void
211135446Strhodesprintrdata(dns_rdata_t *rdata) {
212135446Strhodes	isc_result_t result;
213135446Strhodes	isc_buffer_t *b = NULL;
214135446Strhodes	unsigned int size = 1024;
215135446Strhodes	isc_boolean_t done = ISC_FALSE;
216135446Strhodes
217135446Strhodes	if (rdata->type < N_KNOWN_RRTYPES)
218135446Strhodes		printf("%s", rtypetext[rdata->type]);
219135446Strhodes	else
220135446Strhodes		printf("rdata_%d = ", rdata->type);
221135446Strhodes
222135446Strhodes	while (!done) {
223135446Strhodes		result = isc_buffer_allocate(mctx, &b, size);
224135446Strhodes		if (result != ISC_R_SUCCESS)
225135446Strhodes			check_result(result, "isc_buffer_allocate");
226135446Strhodes		result = dns_rdata_totext(rdata, NULL, b);
227135446Strhodes		if (result == ISC_R_SUCCESS) {
228135446Strhodes			printf("%.*s\n", (int)isc_buffer_usedlength(b),
229135446Strhodes			       (char *)isc_buffer_base(b));
230135446Strhodes			done = ISC_TRUE;
231135446Strhodes		} else if (result != ISC_R_NOSPACE)
232135446Strhodes			check_result(result, "dns_rdata_totext");
233135446Strhodes		isc_buffer_free(&b);
234135446Strhodes		size *= 2;
235135446Strhodes	}
236135446Strhodes}
237135446Strhodes
238135446Strhodesstatic isc_result_t
239135446Strhodesprintsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
240135446Strhodes	     dns_section_t section) {
241135446Strhodes	isc_result_t result, loopresult;
242135446Strhodes	dns_name_t *name;
243135446Strhodes	dns_rdataset_t *rdataset = NULL;
244135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
245135446Strhodes	char namebuf[DNS_NAME_FORMATSIZE];
246135446Strhodes
247135446Strhodes	UNUSED(query);
248135446Strhodes	UNUSED(headers);
249135446Strhodes
250135446Strhodes	debug("printsection()");
251135446Strhodes
252135446Strhodes	result = dns_message_firstname(msg, section);
253135446Strhodes	if (result == ISC_R_NOMORE)
254135446Strhodes		return (ISC_R_SUCCESS);
255135446Strhodes	else if (result != ISC_R_SUCCESS)
256135446Strhodes		return (result);
257135446Strhodes	for (;;) {
258135446Strhodes		name = NULL;
259135446Strhodes		dns_message_currentname(msg, section,
260135446Strhodes					&name);
261135446Strhodes		for (rdataset = ISC_LIST_HEAD(name->list);
262135446Strhodes		     rdataset != NULL;
263135446Strhodes		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
264135446Strhodes			loopresult = dns_rdataset_first(rdataset);
265135446Strhodes			while (loopresult == ISC_R_SUCCESS) {
266135446Strhodes				dns_rdataset_current(rdataset, &rdata);
267135446Strhodes				switch (rdata.type) {
268135446Strhodes				case dns_rdatatype_a:
269135446Strhodes					if (section != DNS_SECTION_ANSWER)
270135446Strhodes						goto def_short_section;
271135446Strhodes					dns_name_format(name, namebuf,
272135446Strhodes							sizeof(namebuf));
273135446Strhodes					printf("Name:\t%s\n", namebuf);
274135446Strhodes					printa(&rdata);
275135446Strhodes					break;
276135446Strhodes				case dns_rdatatype_soa:
277135446Strhodes					dns_name_format(name, namebuf,
278135446Strhodes							sizeof(namebuf));
279135446Strhodes					printf("%s\n", namebuf);
280135446Strhodes					printsoa(&rdata);
281135446Strhodes					break;
282135446Strhodes				default:
283135446Strhodes				def_short_section:
284135446Strhodes					dns_name_format(name, namebuf,
285135446Strhodes							sizeof(namebuf));
286135446Strhodes					printf("%s\t", namebuf);
287135446Strhodes					printrdata(&rdata);
288135446Strhodes					break;
289135446Strhodes				}
290135446Strhodes				dns_rdata_reset(&rdata);
291135446Strhodes				loopresult = dns_rdataset_next(rdataset);
292135446Strhodes			}
293135446Strhodes		}
294135446Strhodes		result = dns_message_nextname(msg, section);
295135446Strhodes		if (result == ISC_R_NOMORE)
296135446Strhodes			break;
297135446Strhodes		else if (result != ISC_R_SUCCESS) {
298135446Strhodes			return (result);
299135446Strhodes		}
300135446Strhodes	}
301135446Strhodes	return (ISC_R_SUCCESS);
302135446Strhodes}
303135446Strhodes
304135446Strhodesstatic isc_result_t
305135446Strhodesdetailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
306135446Strhodes	     dns_section_t section) {
307135446Strhodes	isc_result_t result, loopresult;
308135446Strhodes	dns_name_t *name;
309135446Strhodes	dns_rdataset_t *rdataset = NULL;
310135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
311135446Strhodes	char namebuf[DNS_NAME_FORMATSIZE];
312135446Strhodes
313135446Strhodes	UNUSED(query);
314135446Strhodes
315135446Strhodes	debug("detailsection()");
316135446Strhodes
317135446Strhodes	if (headers) {
318135446Strhodes		switch (section) {
319135446Strhodes		case DNS_SECTION_QUESTION:
320135446Strhodes			puts("    QUESTIONS:");
321135446Strhodes			break;
322135446Strhodes		case DNS_SECTION_ANSWER:
323135446Strhodes			puts("    ANSWERS:");
324135446Strhodes			break;
325135446Strhodes		case DNS_SECTION_AUTHORITY:
326135446Strhodes			puts("    AUTHORITY RECORDS:");
327135446Strhodes			break;
328135446Strhodes		case DNS_SECTION_ADDITIONAL:
329135446Strhodes			puts("    ADDITIONAL RECORDS:");
330135446Strhodes			break;
331135446Strhodes		}
332135446Strhodes	}
333135446Strhodes
334135446Strhodes	result = dns_message_firstname(msg, section);
335135446Strhodes	if (result == ISC_R_NOMORE)
336135446Strhodes		return (ISC_R_SUCCESS);
337135446Strhodes	else if (result != ISC_R_SUCCESS)
338135446Strhodes		return (result);
339135446Strhodes	for (;;) {
340135446Strhodes		name = NULL;
341135446Strhodes		dns_message_currentname(msg, section,
342135446Strhodes					&name);
343135446Strhodes		for (rdataset = ISC_LIST_HEAD(name->list);
344135446Strhodes		     rdataset != NULL;
345135446Strhodes		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
346135446Strhodes			if (section == DNS_SECTION_QUESTION) {
347135446Strhodes				dns_name_format(name, namebuf,
348135446Strhodes						sizeof(namebuf));
349135446Strhodes				printf("\t%s, ", namebuf);
350135446Strhodes				dns_rdatatype_format(rdataset->type,
351135446Strhodes						     namebuf,
352135446Strhodes						     sizeof(namebuf));
353135446Strhodes				printf("type = %s, ", namebuf);
354135446Strhodes				dns_rdataclass_format(rdataset->rdclass,
355135446Strhodes						      namebuf,
356135446Strhodes						      sizeof(namebuf));
357135446Strhodes				printf("class = %s\n", namebuf);
358135446Strhodes			}
359135446Strhodes			loopresult = dns_rdataset_first(rdataset);
360135446Strhodes			while (loopresult == ISC_R_SUCCESS) {
361135446Strhodes				dns_rdataset_current(rdataset, &rdata);
362135446Strhodes
363135446Strhodes				dns_name_format(name, namebuf,
364135446Strhodes						sizeof(namebuf));
365135446Strhodes				printf("    ->  %s\n", namebuf);
366135446Strhodes
367135446Strhodes				switch (rdata.type) {
368135446Strhodes				case dns_rdatatype_soa:
369135446Strhodes					printsoa(&rdata);
370135446Strhodes					break;
371135446Strhodes				default:
372135446Strhodes					printf("\t");
373135446Strhodes					printrdata(&rdata);
374135446Strhodes				}
375135446Strhodes				dns_rdata_reset(&rdata);
376204619Sdougb				printf("\tttl = %u\n", rdataset->ttl);
377135446Strhodes				loopresult = dns_rdataset_next(rdataset);
378135446Strhodes			}
379135446Strhodes		}
380135446Strhodes		result = dns_message_nextname(msg, section);
381135446Strhodes		if (result == ISC_R_NOMORE)
382135446Strhodes			break;
383135446Strhodes		else if (result != ISC_R_SUCCESS) {
384135446Strhodes			return (result);
385135446Strhodes		}
386135446Strhodes	}
387135446Strhodes	return (ISC_R_SUCCESS);
388135446Strhodes}
389135446Strhodes
390135446Strhodesvoid
391135446Strhodesreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query)
392135446Strhodes{
393135446Strhodes	UNUSED(bytes);
394135446Strhodes	UNUSED(from);
395135446Strhodes	UNUSED(query);
396135446Strhodes}
397135446Strhodes
398135446Strhodesvoid
399135446Strhodestrying(char *frm, dig_lookup_t *lookup) {
400135446Strhodes	UNUSED(frm);
401135446Strhodes	UNUSED(lookup);
402135446Strhodes
403135446Strhodes}
404135446Strhodes
405135446Strhodesisc_result_t
406135446Strhodesprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
407193149Sdougb	char servtext[ISC_SOCKADDR_FORMATSIZE];
408135446Strhodes
409135446Strhodes	debug("printmessage()");
410135446Strhodes
411135446Strhodes	isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
412143731Sdougb	printf("Server:\t\t%s\n", query->userarg);
413135446Strhodes	printf("Address:\t%s\n", servtext);
414193149Sdougb
415135446Strhodes	puts("");
416135446Strhodes
417135446Strhodes	if (!short_form) {
418135446Strhodes		isc_boolean_t headers = ISC_TRUE;
419135446Strhodes		puts("------------");
420135446Strhodes		/*		detailheader(query, msg);*/
421135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_QUESTION);
422135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_ANSWER);
423135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_AUTHORITY);
424135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL);
425135446Strhodes		puts("------------");
426135446Strhodes	}
427135446Strhodes
428135446Strhodes	if (msg->rcode != 0) {
429135446Strhodes		char nametext[DNS_NAME_FORMATSIZE];
430135446Strhodes		dns_name_format(query->lookup->name,
431135446Strhodes				nametext, sizeof(nametext));
432174187Sdougb		printf("** server can't find %s: %s\n",
433174187Sdougb		       (msg->rcode != dns_rcode_nxdomain) ? nametext :
434193149Sdougb		       query->lookup->textname, rcode_totext(msg->rcode));
435135446Strhodes		debug("returning with rcode == 0");
436135446Strhodes		return (ISC_R_SUCCESS);
437135446Strhodes	}
438135446Strhodes
439135446Strhodes	if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
440135446Strhodes		puts("Non-authoritative answer:");
441135446Strhodes	if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
442135446Strhodes		printsection(query, msg, headers, DNS_SECTION_ANSWER);
443135446Strhodes	else
444135446Strhodes		printf("*** Can't find %s: No answer\n",
445135446Strhodes		       query->lookup->textname);
446135446Strhodes
447135446Strhodes	if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
448135446Strhodes	    (query->lookup->rdtype != dns_rdatatype_a)) {
449135446Strhodes		puts("\nAuthoritative answers can be found from:");
450135446Strhodes		printsection(query, msg, headers,
451135446Strhodes			     DNS_SECTION_AUTHORITY);
452135446Strhodes		printsection(query, msg, headers,
453135446Strhodes			     DNS_SECTION_ADDITIONAL);
454135446Strhodes	}
455135446Strhodes	return (ISC_R_SUCCESS);
456135446Strhodes}
457135446Strhodes
458135446Strhodesstatic void
459135446Strhodesshow_settings(isc_boolean_t full, isc_boolean_t serv_only) {
460135446Strhodes	dig_server_t *srv;
461135446Strhodes	isc_sockaddr_t sockaddr;
462135446Strhodes	dig_searchlist_t *listent;
463193149Sdougb	isc_result_t result;
464135446Strhodes
465135446Strhodes	srv = ISC_LIST_HEAD(server_list);
466135446Strhodes
467135446Strhodes	while (srv != NULL) {
468135446Strhodes		char sockstr[ISC_SOCKADDR_FORMATSIZE];
469135446Strhodes
470193149Sdougb		result = get_address(srv->servername, port, &sockaddr);
471193149Sdougb		check_result(result, "get_address");
472193149Sdougb
473135446Strhodes		isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
474135446Strhodes		printf("Default server: %s\nAddress: %s\n",
475143731Sdougb			srv->userarg, sockstr);
476135446Strhodes		if (!full)
477135446Strhodes			return;
478135446Strhodes		srv = ISC_LIST_NEXT(srv, link);
479135446Strhodes	}
480135446Strhodes	if (serv_only)
481135446Strhodes		return;
482135446Strhodes	printf("\nSet options:\n");
483135446Strhodes	printf("  %s\t\t\t%s\t\t%s\n",
484135446Strhodes	       tcpmode ? "vc" : "novc",
485135446Strhodes	       short_form ? "nodebug" : "debug",
486135446Strhodes	       debugging ? "d2" : "nod2");
487135446Strhodes	printf("  %s\t\t%s\n",
488135446Strhodes	       usesearch ? "search" : "nosearch",
489135446Strhodes	       recurse ? "recurse" : "norecurse");
490135446Strhodes	printf("  timeout = %d\t\tretry = %d\tport = %d\n",
491135446Strhodes	       timeout, tries, port);
492135446Strhodes	printf("  querytype = %-8s\tclass = %s\n", deftype, defclass);
493135446Strhodes	printf("  srchlist = ");
494135446Strhodes	for (listent = ISC_LIST_HEAD(search_list);
495135446Strhodes	     listent != NULL;
496135446Strhodes	     listent = ISC_LIST_NEXT(listent, link)) {
497135446Strhodes		     printf("%s", listent->origin);
498135446Strhodes		     if (ISC_LIST_NEXT(listent, link) != NULL)
499135446Strhodes			     printf("/");
500135446Strhodes	}
501135446Strhodes	printf("\n");
502135446Strhodes}
503135446Strhodes
504135446Strhodesstatic isc_boolean_t
505135446Strhodestesttype(char *typetext) {
506135446Strhodes	isc_result_t result;
507135446Strhodes	isc_textregion_t tr;
508135446Strhodes	dns_rdatatype_t rdtype;
509135446Strhodes
510135446Strhodes	tr.base = typetext;
511135446Strhodes	tr.length = strlen(typetext);
512135446Strhodes	result = dns_rdatatype_fromtext(&rdtype, &tr);
513135446Strhodes	if (result == ISC_R_SUCCESS)
514135446Strhodes		return (ISC_TRUE);
515135446Strhodes	else {
516135446Strhodes		printf("unknown query type: %s\n", typetext);
517135446Strhodes		return (ISC_FALSE);
518135446Strhodes	}
519135446Strhodes}
520135446Strhodes
521135446Strhodesstatic isc_boolean_t
522135446Strhodestestclass(char *typetext) {
523135446Strhodes	isc_result_t result;
524135446Strhodes	isc_textregion_t tr;
525135446Strhodes	dns_rdataclass_t rdclass;
526135446Strhodes
527135446Strhodes	tr.base = typetext;
528135446Strhodes	tr.length = strlen(typetext);
529135446Strhodes	result = dns_rdataclass_fromtext(&rdclass, &tr);
530193149Sdougb	if (result == ISC_R_SUCCESS)
531135446Strhodes		return (ISC_TRUE);
532135446Strhodes	else {
533135446Strhodes		printf("unknown query class: %s\n", typetext);
534135446Strhodes		return (ISC_FALSE);
535135446Strhodes	}
536135446Strhodes}
537135446Strhodes
538135446Strhodesstatic void
539135446Strhodesset_port(const char *value) {
540135446Strhodes	isc_uint32_t n;
541135446Strhodes	isc_result_t result = parse_uint(&n, value, 65535, "port");
542135446Strhodes	if (result == ISC_R_SUCCESS)
543135446Strhodes		port = (isc_uint16_t) n;
544135446Strhodes}
545135446Strhodes
546135446Strhodesstatic void
547135446Strhodesset_timeout(const char *value) {
548135446Strhodes	isc_uint32_t n;
549135446Strhodes	isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
550135446Strhodes	if (result == ISC_R_SUCCESS)
551135446Strhodes		timeout = n;
552135446Strhodes}
553135446Strhodes
554135446Strhodesstatic void
555135446Strhodesset_tries(const char *value) {
556135446Strhodes	isc_uint32_t n;
557135446Strhodes	isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
558135446Strhodes	if (result == ISC_R_SUCCESS)
559135446Strhodes		tries = n;
560135446Strhodes}
561135446Strhodes
562135446Strhodesstatic void
563135446Strhodessetoption(char *opt) {
564135446Strhodes	if (strncasecmp(opt, "all", 4) == 0) {
565135446Strhodes		show_settings(ISC_TRUE, ISC_FALSE);
566135446Strhodes	} else if (strncasecmp(opt, "class=", 6) == 0) {
567135446Strhodes		if (testclass(&opt[6]))
568225361Sdougb			strlcpy(defclass, &opt[6], sizeof(defclass));
569135446Strhodes	} else if (strncasecmp(opt, "cl=", 3) == 0) {
570135446Strhodes		if (testclass(&opt[3]))
571225361Sdougb			strlcpy(defclass, &opt[3], sizeof(defclass));
572135446Strhodes	} else if (strncasecmp(opt, "type=", 5) == 0) {
573135446Strhodes		if (testtype(&opt[5]))
574225361Sdougb			strlcpy(deftype, &opt[5], sizeof(deftype));
575135446Strhodes	} else if (strncasecmp(opt, "ty=", 3) == 0) {
576135446Strhodes		if (testtype(&opt[3]))
577225361Sdougb			strlcpy(deftype, &opt[3], sizeof(deftype));
578135446Strhodes	} else if (strncasecmp(opt, "querytype=", 10) == 0) {
579135446Strhodes		if (testtype(&opt[10]))
580225361Sdougb			strlcpy(deftype, &opt[10], sizeof(deftype));
581135446Strhodes	} else if (strncasecmp(opt, "query=", 6) == 0) {
582135446Strhodes		if (testtype(&opt[6]))
583225361Sdougb			strlcpy(deftype, &opt[6], sizeof(deftype));
584135446Strhodes	} else if (strncasecmp(opt, "qu=", 3) == 0) {
585135446Strhodes		if (testtype(&opt[3]))
586225361Sdougb			strlcpy(deftype, &opt[3], sizeof(deftype));
587135446Strhodes	} else if (strncasecmp(opt, "q=", 2) == 0) {
588135446Strhodes		if (testtype(&opt[2]))
589225361Sdougb			strlcpy(deftype, &opt[2], sizeof(deftype));
590135446Strhodes	} else if (strncasecmp(opt, "domain=", 7) == 0) {
591225361Sdougb		strlcpy(domainopt, &opt[7], sizeof(domainopt));
592135446Strhodes		set_search_domain(domainopt);
593135446Strhodes		usesearch = ISC_TRUE;
594135446Strhodes	} else if (strncasecmp(opt, "do=", 3) == 0) {
595225361Sdougb		strlcpy(domainopt, &opt[3], sizeof(domainopt));
596135446Strhodes		set_search_domain(domainopt);
597135446Strhodes		usesearch = ISC_TRUE;
598135446Strhodes	} else if (strncasecmp(opt, "port=", 5) == 0) {
599135446Strhodes		set_port(&opt[5]);
600135446Strhodes	} else if (strncasecmp(opt, "po=", 3) == 0) {
601135446Strhodes		set_port(&opt[3]);
602135446Strhodes	} else if (strncasecmp(opt, "timeout=", 8) == 0) {
603135446Strhodes		set_timeout(&opt[8]);
604135446Strhodes	} else if (strncasecmp(opt, "t=", 2) == 0) {
605135446Strhodes		set_timeout(&opt[2]);
606193149Sdougb	} else if (strncasecmp(opt, "rec", 3) == 0) {
607135446Strhodes		recurse = ISC_TRUE;
608135446Strhodes	} else if (strncasecmp(opt, "norec", 5) == 0) {
609135446Strhodes		recurse = ISC_FALSE;
610135446Strhodes	} else if (strncasecmp(opt, "retry=", 6) == 0) {
611135446Strhodes		set_tries(&opt[6]);
612135446Strhodes	} else if (strncasecmp(opt, "ret=", 4) == 0) {
613135446Strhodes		set_tries(&opt[4]);
614193149Sdougb	} else if (strncasecmp(opt, "def", 3) == 0) {
615135446Strhodes		usesearch = ISC_TRUE;
616135446Strhodes	} else if (strncasecmp(opt, "nodef", 5) == 0) {
617135446Strhodes		usesearch = ISC_FALSE;
618193149Sdougb	} else if (strncasecmp(opt, "vc", 3) == 0) {
619135446Strhodes		tcpmode = ISC_TRUE;
620135446Strhodes	} else if (strncasecmp(opt, "novc", 5) == 0) {
621135446Strhodes		tcpmode = ISC_FALSE;
622193149Sdougb	} else if (strncasecmp(opt, "deb", 3) == 0) {
623135446Strhodes		short_form = ISC_FALSE;
624170222Sdougb		showsearch = ISC_TRUE;
625135446Strhodes	} else if (strncasecmp(opt, "nodeb", 5) == 0) {
626135446Strhodes		short_form = ISC_TRUE;
627170222Sdougb		showsearch = ISC_FALSE;
628193149Sdougb	} else if (strncasecmp(opt, "d2", 2) == 0) {
629135446Strhodes		debugging = ISC_TRUE;
630135446Strhodes	} else if (strncasecmp(opt, "nod2", 4) == 0) {
631135446Strhodes		debugging = ISC_FALSE;
632135446Strhodes	} else if (strncasecmp(opt, "search", 3) == 0) {
633135446Strhodes		usesearch = ISC_TRUE;
634135446Strhodes	} else if (strncasecmp(opt, "nosearch", 5) == 0) {
635135446Strhodes		usesearch = ISC_FALSE;
636135446Strhodes	} else if (strncasecmp(opt, "sil", 3) == 0) {
637135446Strhodes		/* deprecation_msg = ISC_FALSE; */
638170222Sdougb	} else if (strncasecmp(opt, "fail", 3) == 0) {
639170222Sdougb		nofail=ISC_FALSE;
640170222Sdougb	} else if (strncasecmp(opt, "nofail", 3) == 0) {
641170222Sdougb		nofail=ISC_TRUE;
642135446Strhodes	} else {
643193149Sdougb		printf("*** Invalid option: %s\n", opt);
644135446Strhodes	}
645135446Strhodes}
646135446Strhodes
647135446Strhodesstatic void
648135446Strhodesaddlookup(char *opt) {
649135446Strhodes	dig_lookup_t *lookup;
650135446Strhodes	isc_result_t result;
651135446Strhodes	isc_textregion_t tr;
652135446Strhodes	dns_rdatatype_t rdtype;
653135446Strhodes	dns_rdataclass_t rdclass;
654135446Strhodes	char store[MXNAME];
655135446Strhodes
656135446Strhodes	debug("addlookup()");
657135446Strhodes	tr.base = deftype;
658135446Strhodes	tr.length = strlen(deftype);
659135446Strhodes	result = dns_rdatatype_fromtext(&rdtype, &tr);
660135446Strhodes	if (result != ISC_R_SUCCESS) {
661135446Strhodes		printf("unknown query type: %s\n", deftype);
662135446Strhodes		rdclass = dns_rdatatype_a;
663135446Strhodes	}
664135446Strhodes	tr.base = defclass;
665135446Strhodes	tr.length = strlen(defclass);
666135446Strhodes	result = dns_rdataclass_fromtext(&rdclass, &tr);
667135446Strhodes	if (result != ISC_R_SUCCESS) {
668135446Strhodes		printf("unknown query class: %s\n", defclass);
669135446Strhodes		rdclass = dns_rdataclass_in;
670135446Strhodes	}
671135446Strhodes	lookup = make_empty_lookup();
672135446Strhodes	if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
673135446Strhodes	    == ISC_R_SUCCESS) {
674225361Sdougb		strlcpy(lookup->textname, store, sizeof(lookup->textname));
675135446Strhodes		lookup->rdtype = dns_rdatatype_ptr;
676135446Strhodes		lookup->rdtypeset = ISC_TRUE;
677135446Strhodes	} else {
678225361Sdougb		strlcpy(lookup->textname, opt, sizeof(lookup->textname));
679135446Strhodes		lookup->rdtype = rdtype;
680135446Strhodes		lookup->rdtypeset = ISC_TRUE;
681135446Strhodes	}
682135446Strhodes	lookup->rdclass = rdclass;
683135446Strhodes	lookup->rdclassset = ISC_TRUE;
684135446Strhodes	lookup->trace = ISC_FALSE;
685135446Strhodes	lookup->trace_root = lookup->trace;
686135446Strhodes	lookup->ns_search_only = ISC_FALSE;
687135446Strhodes	lookup->identify = identify;
688135446Strhodes	lookup->recurse = recurse;
689135446Strhodes	lookup->aaonly = aaonly;
690135446Strhodes	lookup->retries = tries;
691135446Strhodes	lookup->udpsize = 0;
692135446Strhodes	lookup->comments = comments;
693135446Strhodes	lookup->tcp_mode = tcpmode;
694135446Strhodes	lookup->stats = stats;
695135446Strhodes	lookup->section_question = section_question;
696135446Strhodes	lookup->section_answer = section_answer;
697135446Strhodes	lookup->section_authority = section_authority;
698135446Strhodes	lookup->section_additional = section_additional;
699135446Strhodes	lookup->new_search = ISC_TRUE;
700170222Sdougb	if (nofail)
701170222Sdougb		lookup->servfail_stops = ISC_FALSE;
702135446Strhodes	ISC_LIST_INIT(lookup->q);
703135446Strhodes	ISC_LINK_INIT(lookup, link);
704135446Strhodes	ISC_LIST_APPEND(lookup_list, lookup, link);
705135446Strhodes	lookup->origin = NULL;
706135446Strhodes	ISC_LIST_INIT(lookup->my_server_list);
707135446Strhodes	debug("looking up %s", lookup->textname);
708135446Strhodes}
709135446Strhodes
710135446Strhodesstatic void
711135446Strhodesget_next_command(void) {
712135446Strhodes	char *buf;
713135446Strhodes	char *ptr, *arg;
714135446Strhodes	char *input;
715135446Strhodes
716135446Strhodes	fflush(stdout);
717135446Strhodes	buf = isc_mem_allocate(mctx, COMMSIZE);
718135446Strhodes	if (buf == NULL)
719135446Strhodes		fatal("memory allocation failure");
720135446Strhodes	fputs("> ", stderr);
721165071Sdougb	fflush(stderr);
722135446Strhodes	isc_app_block();
723135446Strhodes	ptr = fgets(buf, COMMSIZE, stdin);
724135446Strhodes	isc_app_unblock();
725135446Strhodes	if (ptr == NULL) {
726135446Strhodes		in_use = ISC_FALSE;
727135446Strhodes		goto cleanup;
728135446Strhodes	}
729135446Strhodes	input = buf;
730135446Strhodes	ptr = next_token(&input, " \t\r\n");
731135446Strhodes	if (ptr == NULL)
732135446Strhodes		goto cleanup;
733135446Strhodes	arg = next_token(&input, " \t\r\n");
734135446Strhodes	if ((strcasecmp(ptr, "set") == 0) &&
735135446Strhodes	    (arg != NULL))
736135446Strhodes		setoption(arg);
737135446Strhodes	else if ((strcasecmp(ptr, "server") == 0) ||
738135446Strhodes		 (strcasecmp(ptr, "lserver") == 0)) {
739143731Sdougb		isc_app_block();
740135446Strhodes		set_nameserver(arg);
741170222Sdougb		check_ra = ISC_FALSE;
742143731Sdougb		isc_app_unblock();
743135446Strhodes		show_settings(ISC_TRUE, ISC_TRUE);
744135446Strhodes	} else if (strcasecmp(ptr, "exit") == 0) {
745135446Strhodes		in_use = ISC_FALSE;
746135446Strhodes		goto cleanup;
747135446Strhodes	} else if (strcasecmp(ptr, "help") == 0 ||
748135446Strhodes		   strcasecmp(ptr, "?") == 0) {
749135446Strhodes		printf("The '%s' command is not yet implemented.\n", ptr);
750135446Strhodes		goto cleanup;
751135446Strhodes	} else if (strcasecmp(ptr, "finger") == 0 ||
752135446Strhodes		   strcasecmp(ptr, "root") == 0 ||
753135446Strhodes		   strcasecmp(ptr, "ls") == 0 ||
754135446Strhodes		   strcasecmp(ptr, "view") == 0) {
755135446Strhodes		printf("The '%s' command is not implemented.\n", ptr);
756135446Strhodes		goto cleanup;
757135446Strhodes	} else
758135446Strhodes		addlookup(ptr);
759135446Strhodes cleanup:
760135446Strhodes	isc_mem_free(mctx, buf);
761135446Strhodes}
762135446Strhodes
763135446Strhodesstatic void
764135446Strhodesparse_args(int argc, char **argv) {
765135446Strhodes	isc_boolean_t have_lookup = ISC_FALSE;
766135446Strhodes
767135446Strhodes	usesearch = ISC_TRUE;
768135446Strhodes	for (argc--, argv++; argc > 0; argc--, argv++) {
769135446Strhodes		debug("main parsing %s", argv[0]);
770135446Strhodes		if (argv[0][0] == '-') {
771135446Strhodes			if (argv[0][1] != 0)
772135446Strhodes				setoption(&argv[0][1]);
773135446Strhodes			else
774135446Strhodes				have_lookup = ISC_TRUE;
775135446Strhodes		} else {
776135446Strhodes			if (!have_lookup) {
777135446Strhodes				have_lookup = ISC_TRUE;
778135446Strhodes				in_use = ISC_TRUE;
779135446Strhodes				addlookup(argv[0]);
780170222Sdougb			} else {
781170222Sdougb				set_nameserver(argv[0]);
782170222Sdougb				check_ra = ISC_FALSE;
783135446Strhodes			}
784135446Strhodes		}
785135446Strhodes	}
786135446Strhodes}
787135446Strhodes
788135446Strhodesstatic void
789135446Strhodesflush_lookup_list(void) {
790135446Strhodes	dig_lookup_t *l, *lp;
791135446Strhodes	dig_query_t *q, *qp;
792135446Strhodes	dig_server_t *s, *sp;
793135446Strhodes
794135446Strhodes	lookup_counter = 0;
795135446Strhodes	l = ISC_LIST_HEAD(lookup_list);
796135446Strhodes	while (l != NULL) {
797135446Strhodes		q = ISC_LIST_HEAD(l->q);
798135446Strhodes		while (q != NULL) {
799135446Strhodes			if (q->sock != NULL) {
800135446Strhodes				isc_socket_cancel(q->sock, NULL,
801135446Strhodes						  ISC_SOCKCANCEL_ALL);
802135446Strhodes				isc_socket_detach(&q->sock);
803135446Strhodes			}
804135446Strhodes			if (ISC_LINK_LINKED(&q->recvbuf, link))
805135446Strhodes				ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
806135446Strhodes						 link);
807135446Strhodes			if (ISC_LINK_LINKED(&q->lengthbuf, link))
808135446Strhodes				ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
809135446Strhodes						 link);
810135446Strhodes			isc_buffer_invalidate(&q->recvbuf);
811135446Strhodes			isc_buffer_invalidate(&q->lengthbuf);
812135446Strhodes			qp = q;
813135446Strhodes			q = ISC_LIST_NEXT(q, link);
814135446Strhodes			ISC_LIST_DEQUEUE(l->q, qp, link);
815135446Strhodes			isc_mem_free(mctx, qp);
816135446Strhodes		}
817135446Strhodes		s = ISC_LIST_HEAD(l->my_server_list);
818135446Strhodes		while (s != NULL) {
819135446Strhodes			sp = s;
820135446Strhodes			s = ISC_LIST_NEXT(s, link);
821135446Strhodes			ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
822135446Strhodes			isc_mem_free(mctx, sp);
823135446Strhodes
824135446Strhodes		}
825135446Strhodes		if (l->sendmsg != NULL)
826135446Strhodes			dns_message_destroy(&l->sendmsg);
827135446Strhodes		if (l->timer != NULL)
828135446Strhodes			isc_timer_detach(&l->timer);
829135446Strhodes		lp = l;
830135446Strhodes		l = ISC_LIST_NEXT(l, link);
831135446Strhodes		ISC_LIST_DEQUEUE(lookup_list, lp, link);
832135446Strhodes		isc_mem_free(mctx, lp);
833135446Strhodes	}
834135446Strhodes}
835135446Strhodes
836135446Strhodesstatic void
837135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) {
838135446Strhodes	UNUSED(task);
839135446Strhodes	if (global_event == NULL)
840135446Strhodes		global_event = event;
841135446Strhodes	while (in_use) {
842135446Strhodes		get_next_command();
843135446Strhodes		if (ISC_LIST_HEAD(lookup_list) != NULL) {
844135446Strhodes			start_lookup();
845135446Strhodes			return;
846135446Strhodes		}
847135446Strhodes	}
848135446Strhodes	isc_app_shutdown();
849135446Strhodes}
850135446Strhodes
851135446Strhodesint
852135446Strhodesmain(int argc, char **argv) {
853135446Strhodes	isc_result_t result;
854135446Strhodes
855135446Strhodes	ISC_LIST_INIT(lookup_list);
856135446Strhodes	ISC_LIST_INIT(server_list);
857135446Strhodes	ISC_LIST_INIT(search_list);
858135446Strhodes
859170222Sdougb	check_ra = ISC_TRUE;
860170222Sdougb
861135446Strhodes	result = isc_app_start();
862135446Strhodes	check_result(result, "isc_app_start");
863135446Strhodes
864135446Strhodes	setup_libs();
865135446Strhodes	progname = argv[0];
866135446Strhodes
867135446Strhodes	parse_args(argc, argv);
868135446Strhodes
869135446Strhodes	setup_system();
870135446Strhodes	if (domainopt[0] != '\0')
871135446Strhodes		set_search_domain(domainopt);
872135446Strhodes	if (in_use)
873135446Strhodes		result = isc_app_onrun(mctx, global_task, onrun_callback,
874135446Strhodes				       NULL);
875135446Strhodes	else
876135446Strhodes		result = isc_app_onrun(mctx, global_task, getinput, NULL);
877135446Strhodes	check_result(result, "isc_app_onrun");
878135446Strhodes	in_use = ISC_TF(!in_use);
879135446Strhodes
880135446Strhodes	(void)isc_app_run();
881135446Strhodes
882135446Strhodes	puts("");
883135446Strhodes	debug("done, and starting to shut down");
884135446Strhodes	if (global_event != NULL)
885135446Strhodes		isc_event_free(&global_event);
886135446Strhodes	cancel_all();
887135446Strhodes	destroy_libs();
888135446Strhodes	isc_app_finish();
889135446Strhodes
890135446Strhodes	return (0);
891135446Strhodes}
892