nslookup.c revision 143731
1135446Strhodes/*
2135446Strhodes * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2000-2003  Internet Software Consortium.
4135446Strhodes *
5135446Strhodes * Permission to use, copy, modify, and 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
18143731Sdougb/* $Id: nslookup.c,v 1.90.2.4.2.8 2004/09/06 01:33:05 marka 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>
29135446Strhodes#include <isc/string.h>
30135446Strhodes#include <isc/timer.h>
31135446Strhodes#include <isc/util.h>
32135446Strhodes#include <isc/task.h>
33135446Strhodes#include <isc/netaddr.h>
34135446Strhodes
35135446Strhodes#include <dns/message.h>
36135446Strhodes#include <dns/name.h>
37135446Strhodes#include <dns/fixedname.h>
38135446Strhodes#include <dns/rdata.h>
39135446Strhodes#include <dns/rdataclass.h>
40135446Strhodes#include <dns/rdataset.h>
41135446Strhodes#include <dns/rdatastruct.h>
42135446Strhodes#include <dns/rdatatype.h>
43135446Strhodes#include <dns/byaddr.h>
44135446Strhodes
45135446Strhodes#include <dig/dig.h>
46135446Strhodes
47135446Strhodesextern ISC_LIST(dig_lookup_t) lookup_list;
48135446Strhodesextern dig_serverlist_t server_list;
49135446Strhodesextern ISC_LIST(dig_searchlist_t) search_list;
50135446Strhodes
51135446Strhodesextern isc_boolean_t usesearch, debugging;
52135446Strhodesextern in_port_t port;
53135446Strhodesextern unsigned int timeout;
54135446Strhodesextern isc_mem_t *mctx;
55135446Strhodesextern int tries;
56135446Strhodesextern int lookup_counter;
57135446Strhodesextern isc_task_t *global_task;
58135446Strhodesextern char *progname;
59135446Strhodes
60135446Strhodesstatic isc_boolean_t short_form = ISC_TRUE,
61135446Strhodes	tcpmode = ISC_FALSE,
62135446Strhodes	identify = ISC_FALSE, stats = ISC_TRUE,
63135446Strhodes	comments = ISC_TRUE, section_question = ISC_TRUE,
64135446Strhodes	section_answer = ISC_TRUE, section_authority = ISC_TRUE,
65135446Strhodes	section_additional = ISC_TRUE, recurse = ISC_TRUE,
66135446Strhodes	aaonly = ISC_FALSE;
67135446Strhodesstatic isc_boolean_t in_use = ISC_FALSE;
68135446Strhodesstatic char defclass[MXRD] = "IN";
69135446Strhodesstatic char deftype[MXRD] = "A";
70135446Strhodesstatic isc_event_t *global_event = NULL;
71135446Strhodes
72135446Strhodesstatic char domainopt[DNS_NAME_MAXTEXT];
73135446Strhodes
74135446Strhodesstatic const char *rcodetext[] = {
75135446Strhodes	"NOERROR",
76135446Strhodes	"FORMERR",
77135446Strhodes	"SERVFAIL",
78135446Strhodes	"NXDOMAIN",
79135446Strhodes	"NOTIMP",
80135446Strhodes	"REFUSED",
81135446Strhodes	"YXDOMAIN",
82135446Strhodes	"YXRRSET",
83135446Strhodes	"NXRRSET",
84135446Strhodes	"NOTAUTH",
85135446Strhodes	"NOTZONE",
86135446Strhodes	"RESERVED11",
87135446Strhodes	"RESERVED12",
88135446Strhodes	"RESERVED13",
89135446Strhodes	"RESERVED14",
90135446Strhodes	"RESERVED15",
91135446Strhodes	"BADVERS"
92135446Strhodes};
93135446Strhodes
94135446Strhodesstatic const char *rtypetext[] = {
95135446Strhodes	"rtype_0 = ",			/* 0 */
96135446Strhodes	"internet address = ",		/* 1 */
97135446Strhodes	"nameserver = ",		/* 2 */
98135446Strhodes	"md = ",			/* 3 */
99135446Strhodes	"mf = ",			/* 4 */
100135446Strhodes	"canonical name = ",		/* 5 */
101135446Strhodes	"soa = ",			/* 6 */
102135446Strhodes	"mb = ",			/* 7 */
103135446Strhodes	"mg = ",			/* 8 */
104135446Strhodes	"mr = ",			/* 9 */
105135446Strhodes	"rtype_10 = ",			/* 10 */
106135446Strhodes	"protocol = ",			/* 11 */
107135446Strhodes	"name = ",			/* 12 */
108135446Strhodes	"hinfo = ",			/* 13 */
109135446Strhodes	"minfo = ",			/* 14 */
110135446Strhodes	"mail exchanger = ",		/* 15 */
111135446Strhodes	"text = ",			/* 16 */
112135446Strhodes	"rp = ",       			/* 17 */
113135446Strhodes	"afsdb = ",			/* 18 */
114135446Strhodes	"x25 address = ",		/* 19 */
115135446Strhodes	"isdn address = ",		/* 20 */
116135446Strhodes	"rt = ",			/* 21 */
117135446Strhodes	"nsap = ",			/* 22 */
118135446Strhodes	"nsap_ptr = ",			/* 23 */
119135446Strhodes	"signature = ",			/* 24 */
120135446Strhodes	"key = ",			/* 25 */
121135446Strhodes	"px = ",			/* 26 */
122135446Strhodes	"gpos = ",			/* 27 */
123135446Strhodes	"has AAAA address ",		/* 28 */
124135446Strhodes	"loc = ",			/* 29 */
125135446Strhodes	"next = ",			/* 30 */
126135446Strhodes	"rtype_31 = ",			/* 31 */
127135446Strhodes	"rtype_32 = ",			/* 32 */
128135446Strhodes	"service = ",			/* 33 */
129135446Strhodes	"rtype_34 = ",			/* 34 */
130135446Strhodes	"naptr = ",			/* 35 */
131135446Strhodes	"kx = ",			/* 36 */
132135446Strhodes	"cert = ",			/* 37 */
133135446Strhodes	"v6 address = ",		/* 38 */
134135446Strhodes	"dname = ",			/* 39 */
135135446Strhodes	"rtype_40 = ",			/* 40 */
136135446Strhodes	"optional = "			/* 41 */
137135446Strhodes};
138135446Strhodes
139135446Strhodes#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
140135446Strhodes
141135446Strhodesstatic void flush_lookup_list(void);
142135446Strhodesstatic void getinput(isc_task_t *task, isc_event_t *event);
143135446Strhodes
144135446Strhodesvoid
145135446Strhodesdighost_shutdown(void) {
146135446Strhodes	isc_event_t *event = global_event;
147135446Strhodes
148135446Strhodes	flush_lookup_list();
149135446Strhodes	debug("dighost_shutdown()");
150135446Strhodes
151135446Strhodes	if (!in_use) {
152135446Strhodes		isc_app_shutdown();
153135446Strhodes		return;
154135446Strhodes	}
155135446Strhodes
156135446Strhodes	isc_task_send(global_task, &event);
157135446Strhodes}
158135446Strhodes
159135446Strhodesstatic void
160135446Strhodesprintsoa(dns_rdata_t *rdata) {
161135446Strhodes	dns_rdata_soa_t soa;
162135446Strhodes	isc_result_t result;
163135446Strhodes	char namebuf[DNS_NAME_FORMATSIZE];
164135446Strhodes
165135446Strhodes	result = dns_rdata_tostruct(rdata, &soa, NULL);
166135446Strhodes	check_result(result, "dns_rdata_tostruct");
167135446Strhodes
168135446Strhodes	dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
169135446Strhodes	printf("\torigin = %s\n", namebuf);
170135446Strhodes	dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
171135446Strhodes	printf("\tmail addr = %s\n", namebuf);
172135446Strhodes	printf("\tserial = %u\n", soa.serial);
173135446Strhodes	printf("\trefresh = %u\n", soa.refresh);
174135446Strhodes	printf("\tretry = %u\n", soa.retry);
175135446Strhodes	printf("\texpire = %u\n", soa.expire);
176135446Strhodes	printf("\tminimum = %u\n", soa.minimum);
177135446Strhodes	dns_rdata_freestruct(&soa);
178135446Strhodes}
179135446Strhodes
180135446Strhodesstatic void
181135446Strhodesprinta(dns_rdata_t *rdata) {
182135446Strhodes	isc_result_t result;
183135446Strhodes	char text[sizeof("255.255.255.255")];
184135446Strhodes	isc_buffer_t b;
185135446Strhodes
186135446Strhodes	isc_buffer_init(&b, text, sizeof(text));
187135446Strhodes	result = dns_rdata_totext(rdata, NULL, &b);
188135446Strhodes	check_result(result, "dns_rdata_totext");
189135446Strhodes	printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
190135446Strhodes	       (char *)isc_buffer_base(&b));
191135446Strhodes}
192135446Strhodes#ifdef DIG_SIGCHASE
193135446Strhodes/* Just for compatibility : not use in host program */
194135446Strhodesisc_result_t
195135446Strhodesprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
196135446Strhodes	      isc_buffer_t *target)
197135446Strhodes{
198135446Strhodes	UNUSED(owner_name);
199135446Strhodes	UNUSED(rdataset);
200135446Strhodes	UNUSED(target);
201135446Strhodes	return(ISC_FALSE);
202135446Strhodes}
203135446Strhodes#endif
204135446Strhodesstatic void
205135446Strhodesprintrdata(dns_rdata_t *rdata) {
206135446Strhodes	isc_result_t result;
207135446Strhodes	isc_buffer_t *b = NULL;
208135446Strhodes	unsigned int size = 1024;
209135446Strhodes	isc_boolean_t done = ISC_FALSE;
210135446Strhodes
211135446Strhodes	if (rdata->type < N_KNOWN_RRTYPES)
212135446Strhodes		printf("%s", rtypetext[rdata->type]);
213135446Strhodes	else
214135446Strhodes		printf("rdata_%d = ", rdata->type);
215135446Strhodes
216135446Strhodes	while (!done) {
217135446Strhodes		result = isc_buffer_allocate(mctx, &b, size);
218135446Strhodes		if (result != ISC_R_SUCCESS)
219135446Strhodes			check_result(result, "isc_buffer_allocate");
220135446Strhodes		result = dns_rdata_totext(rdata, NULL, b);
221135446Strhodes		if (result == ISC_R_SUCCESS) {
222135446Strhodes			printf("%.*s\n", (int)isc_buffer_usedlength(b),
223135446Strhodes			       (char *)isc_buffer_base(b));
224135446Strhodes			done = ISC_TRUE;
225135446Strhodes		} else if (result != ISC_R_NOSPACE)
226135446Strhodes			check_result(result, "dns_rdata_totext");
227135446Strhodes		isc_buffer_free(&b);
228135446Strhodes		size *= 2;
229135446Strhodes	}
230135446Strhodes}
231135446Strhodes
232135446Strhodesstatic isc_result_t
233135446Strhodesprintsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
234135446Strhodes	     dns_section_t section) {
235135446Strhodes	isc_result_t result, loopresult;
236135446Strhodes	dns_name_t *name;
237135446Strhodes	dns_rdataset_t *rdataset = NULL;
238135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
239135446Strhodes	char namebuf[DNS_NAME_FORMATSIZE];
240135446Strhodes
241135446Strhodes	UNUSED(query);
242135446Strhodes	UNUSED(headers);
243135446Strhodes
244135446Strhodes	debug("printsection()");
245135446Strhodes
246135446Strhodes	result = dns_message_firstname(msg, section);
247135446Strhodes	if (result == ISC_R_NOMORE)
248135446Strhodes		return (ISC_R_SUCCESS);
249135446Strhodes	else if (result != ISC_R_SUCCESS)
250135446Strhodes		return (result);
251135446Strhodes	for (;;) {
252135446Strhodes		name = NULL;
253135446Strhodes		dns_message_currentname(msg, section,
254135446Strhodes					&name);
255135446Strhodes		for (rdataset = ISC_LIST_HEAD(name->list);
256135446Strhodes		     rdataset != NULL;
257135446Strhodes		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
258135446Strhodes			loopresult = dns_rdataset_first(rdataset);
259135446Strhodes			while (loopresult == ISC_R_SUCCESS) {
260135446Strhodes				dns_rdataset_current(rdataset, &rdata);
261135446Strhodes				switch (rdata.type) {
262135446Strhodes				case dns_rdatatype_a:
263135446Strhodes					if (section != DNS_SECTION_ANSWER)
264135446Strhodes						goto def_short_section;
265135446Strhodes					dns_name_format(name, namebuf,
266135446Strhodes							sizeof(namebuf));
267135446Strhodes					printf("Name:\t%s\n", namebuf);
268135446Strhodes					printa(&rdata);
269135446Strhodes					break;
270135446Strhodes				case dns_rdatatype_soa:
271135446Strhodes					dns_name_format(name, namebuf,
272135446Strhodes							sizeof(namebuf));
273135446Strhodes					printf("%s\n", namebuf);
274135446Strhodes					printsoa(&rdata);
275135446Strhodes					break;
276135446Strhodes				default:
277135446Strhodes				def_short_section:
278135446Strhodes					dns_name_format(name, namebuf,
279135446Strhodes							sizeof(namebuf));
280135446Strhodes					printf("%s\t", namebuf);
281135446Strhodes					printrdata(&rdata);
282135446Strhodes					break;
283135446Strhodes				}
284135446Strhodes				dns_rdata_reset(&rdata);
285135446Strhodes				loopresult = dns_rdataset_next(rdataset);
286135446Strhodes			}
287135446Strhodes		}
288135446Strhodes		result = dns_message_nextname(msg, section);
289135446Strhodes		if (result == ISC_R_NOMORE)
290135446Strhodes			break;
291135446Strhodes		else if (result != ISC_R_SUCCESS) {
292135446Strhodes			return (result);
293135446Strhodes		}
294135446Strhodes	}
295135446Strhodes	return (ISC_R_SUCCESS);
296135446Strhodes}
297135446Strhodes
298135446Strhodesstatic isc_result_t
299135446Strhodesdetailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
300135446Strhodes	     dns_section_t section) {
301135446Strhodes	isc_result_t result, loopresult;
302135446Strhodes	dns_name_t *name;
303135446Strhodes	dns_rdataset_t *rdataset = NULL;
304135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
305135446Strhodes	char namebuf[DNS_NAME_FORMATSIZE];
306135446Strhodes
307135446Strhodes	UNUSED(query);
308135446Strhodes
309135446Strhodes	debug("detailsection()");
310135446Strhodes
311135446Strhodes	if (headers) {
312135446Strhodes		switch (section) {
313135446Strhodes		case DNS_SECTION_QUESTION:
314135446Strhodes			puts("    QUESTIONS:");
315135446Strhodes			break;
316135446Strhodes		case DNS_SECTION_ANSWER:
317135446Strhodes			puts("    ANSWERS:");
318135446Strhodes			break;
319135446Strhodes		case DNS_SECTION_AUTHORITY:
320135446Strhodes			puts("    AUTHORITY RECORDS:");
321135446Strhodes			break;
322135446Strhodes		case DNS_SECTION_ADDITIONAL:
323135446Strhodes			puts("    ADDITIONAL RECORDS:");
324135446Strhodes			break;
325135446Strhodes		}
326135446Strhodes	}
327135446Strhodes
328135446Strhodes	result = dns_message_firstname(msg, section);
329135446Strhodes	if (result == ISC_R_NOMORE)
330135446Strhodes		return (ISC_R_SUCCESS);
331135446Strhodes	else if (result != ISC_R_SUCCESS)
332135446Strhodes		return (result);
333135446Strhodes	for (;;) {
334135446Strhodes		name = NULL;
335135446Strhodes		dns_message_currentname(msg, section,
336135446Strhodes					&name);
337135446Strhodes		for (rdataset = ISC_LIST_HEAD(name->list);
338135446Strhodes		     rdataset != NULL;
339135446Strhodes		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
340135446Strhodes			if (section == DNS_SECTION_QUESTION) {
341135446Strhodes				dns_name_format(name, namebuf,
342135446Strhodes						sizeof(namebuf));
343135446Strhodes				printf("\t%s, ", namebuf);
344135446Strhodes				dns_rdatatype_format(rdataset->type,
345135446Strhodes						     namebuf,
346135446Strhodes						     sizeof(namebuf));
347135446Strhodes				printf("type = %s, ", namebuf);
348135446Strhodes				dns_rdataclass_format(rdataset->rdclass,
349135446Strhodes						      namebuf,
350135446Strhodes						      sizeof(namebuf));
351135446Strhodes				printf("class = %s\n", namebuf);
352135446Strhodes			}
353135446Strhodes			loopresult = dns_rdataset_first(rdataset);
354135446Strhodes			while (loopresult == ISC_R_SUCCESS) {
355135446Strhodes				dns_rdataset_current(rdataset, &rdata);
356135446Strhodes
357135446Strhodes				dns_name_format(name, namebuf,
358135446Strhodes						sizeof(namebuf));
359135446Strhodes				printf("    ->  %s\n", namebuf);
360135446Strhodes
361135446Strhodes				switch (rdata.type) {
362135446Strhodes				case dns_rdatatype_soa:
363135446Strhodes					printsoa(&rdata);
364135446Strhodes					break;
365135446Strhodes				default:
366135446Strhodes					printf("\t");
367135446Strhodes					printrdata(&rdata);
368135446Strhodes				}
369135446Strhodes				dns_rdata_reset(&rdata);
370135446Strhodes				loopresult = dns_rdataset_next(rdataset);
371135446Strhodes			}
372135446Strhodes		}
373135446Strhodes		result = dns_message_nextname(msg, section);
374135446Strhodes		if (result == ISC_R_NOMORE)
375135446Strhodes			break;
376135446Strhodes		else if (result != ISC_R_SUCCESS) {
377135446Strhodes			return (result);
378135446Strhodes		}
379135446Strhodes	}
380135446Strhodes	return (ISC_R_SUCCESS);
381135446Strhodes}
382135446Strhodes
383135446Strhodesvoid
384135446Strhodesreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query)
385135446Strhodes{
386135446Strhodes	UNUSED(bytes);
387135446Strhodes	UNUSED(from);
388135446Strhodes	UNUSED(query);
389135446Strhodes}
390135446Strhodes
391135446Strhodesvoid
392135446Strhodestrying(char *frm, dig_lookup_t *lookup) {
393135446Strhodes	UNUSED(frm);
394135446Strhodes	UNUSED(lookup);
395135446Strhodes
396135446Strhodes}
397135446Strhodes
398135446Strhodesisc_result_t
399135446Strhodesprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
400135446Strhodes	char servtext[ISC_SOCKADDR_FORMATSIZE];
401135446Strhodes
402135446Strhodes	debug("printmessage()");
403135446Strhodes
404135446Strhodes	isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
405143731Sdougb	printf("Server:\t\t%s\n", query->userarg);
406135446Strhodes	printf("Address:\t%s\n", servtext);
407135446Strhodes
408135446Strhodes	puts("");
409135446Strhodes
410135446Strhodes	if (!short_form) {
411135446Strhodes		isc_boolean_t headers = ISC_TRUE;
412135446Strhodes		puts("------------");
413135446Strhodes		/*		detailheader(query, msg);*/
414135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_QUESTION);
415135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_ANSWER);
416135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_AUTHORITY);
417135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL);
418135446Strhodes		puts("------------");
419135446Strhodes	}
420135446Strhodes
421135446Strhodes	if (msg->rcode != 0) {
422135446Strhodes		char nametext[DNS_NAME_FORMATSIZE];
423135446Strhodes		dns_name_format(query->lookup->name,
424135446Strhodes				nametext, sizeof(nametext));
425135446Strhodes		printf("** server can't find %s: %s\n", nametext,
426135446Strhodes		       rcodetext[msg->rcode]);
427135446Strhodes		debug("returning with rcode == 0");
428135446Strhodes		return (ISC_R_SUCCESS);
429135446Strhodes	}
430135446Strhodes
431135446Strhodes	if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
432135446Strhodes		puts("Non-authoritative answer:");
433135446Strhodes	if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
434135446Strhodes		printsection(query, msg, headers, DNS_SECTION_ANSWER);
435135446Strhodes	else
436135446Strhodes		printf("*** Can't find %s: No answer\n",
437135446Strhodes		       query->lookup->textname);
438135446Strhodes
439135446Strhodes	if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
440135446Strhodes	    (query->lookup->rdtype != dns_rdatatype_a)) {
441135446Strhodes		puts("\nAuthoritative answers can be found from:");
442135446Strhodes		printsection(query, msg, headers,
443135446Strhodes			     DNS_SECTION_AUTHORITY);
444135446Strhodes		printsection(query, msg, headers,
445135446Strhodes			     DNS_SECTION_ADDITIONAL);
446135446Strhodes	}
447135446Strhodes	return (ISC_R_SUCCESS);
448135446Strhodes}
449135446Strhodes
450135446Strhodesstatic void
451135446Strhodesshow_settings(isc_boolean_t full, isc_boolean_t serv_only) {
452135446Strhodes	dig_server_t *srv;
453135446Strhodes	isc_sockaddr_t sockaddr;
454135446Strhodes	dig_searchlist_t *listent;
455135446Strhodes
456135446Strhodes	srv = ISC_LIST_HEAD(server_list);
457135446Strhodes
458135446Strhodes	while (srv != NULL) {
459135446Strhodes		char sockstr[ISC_SOCKADDR_FORMATSIZE];
460135446Strhodes
461135446Strhodes		get_address(srv->servername, port, &sockaddr);
462135446Strhodes		isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
463135446Strhodes		printf("Default server: %s\nAddress: %s\n",
464143731Sdougb			srv->userarg, sockstr);
465135446Strhodes		if (!full)
466135446Strhodes			return;
467135446Strhodes		srv = ISC_LIST_NEXT(srv, link);
468135446Strhodes	}
469135446Strhodes	if (serv_only)
470135446Strhodes		return;
471135446Strhodes	printf("\nSet options:\n");
472135446Strhodes	printf("  %s\t\t\t%s\t\t%s\n",
473135446Strhodes	       tcpmode ? "vc" : "novc",
474135446Strhodes	       short_form ? "nodebug" : "debug",
475135446Strhodes	       debugging ? "d2" : "nod2");
476135446Strhodes	printf("  %s\t\t%s\n",
477135446Strhodes	       usesearch ? "search" : "nosearch",
478135446Strhodes	       recurse ? "recurse" : "norecurse");
479135446Strhodes	printf("  timeout = %d\t\tretry = %d\tport = %d\n",
480135446Strhodes	       timeout, tries, port);
481135446Strhodes	printf("  querytype = %-8s\tclass = %s\n", deftype, defclass);
482135446Strhodes	printf("  srchlist = ");
483135446Strhodes	for (listent = ISC_LIST_HEAD(search_list);
484135446Strhodes	     listent != NULL;
485135446Strhodes	     listent = ISC_LIST_NEXT(listent, link)) {
486135446Strhodes		     printf("%s", listent->origin);
487135446Strhodes		     if (ISC_LIST_NEXT(listent, link) != NULL)
488135446Strhodes			     printf("/");
489135446Strhodes	}
490135446Strhodes	printf("\n");
491135446Strhodes}
492135446Strhodes
493135446Strhodesstatic isc_boolean_t
494135446Strhodestesttype(char *typetext) {
495135446Strhodes	isc_result_t result;
496135446Strhodes	isc_textregion_t tr;
497135446Strhodes	dns_rdatatype_t rdtype;
498135446Strhodes
499135446Strhodes	tr.base = typetext;
500135446Strhodes	tr.length = strlen(typetext);
501135446Strhodes	result = dns_rdatatype_fromtext(&rdtype, &tr);
502135446Strhodes	if (result == ISC_R_SUCCESS)
503135446Strhodes		return (ISC_TRUE);
504135446Strhodes	else {
505135446Strhodes		printf("unknown query type: %s\n", typetext);
506135446Strhodes		return (ISC_FALSE);
507135446Strhodes	}
508135446Strhodes}
509135446Strhodes
510135446Strhodesstatic isc_boolean_t
511135446Strhodestestclass(char *typetext) {
512135446Strhodes	isc_result_t result;
513135446Strhodes	isc_textregion_t tr;
514135446Strhodes	dns_rdataclass_t rdclass;
515135446Strhodes
516135446Strhodes	tr.base = typetext;
517135446Strhodes	tr.length = strlen(typetext);
518135446Strhodes	result = dns_rdataclass_fromtext(&rdclass, &tr);
519135446Strhodes	if (result == ISC_R_SUCCESS)
520135446Strhodes		return (ISC_TRUE);
521135446Strhodes	else {
522135446Strhodes		printf("unknown query class: %s\n", typetext);
523135446Strhodes		return (ISC_FALSE);
524135446Strhodes	}
525135446Strhodes}
526135446Strhodes
527135446Strhodesstatic void
528135446Strhodessafecpy(char *dest, char *src, int size) {
529135446Strhodes	strncpy(dest, src, size);
530135446Strhodes	dest[size-1] = 0;
531135446Strhodes}
532135446Strhodes
533135446Strhodesstatic isc_result_t
534135446Strhodesparse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
535135446Strhodes	   const char *desc) {
536135446Strhodes	isc_uint32_t n;
537135446Strhodes	isc_result_t result = isc_parse_uint32(&n, value, 10);
538135446Strhodes	if (result == ISC_R_SUCCESS && n > max)
539135446Strhodes		result = ISC_R_RANGE;
540135446Strhodes	if (result != ISC_R_SUCCESS) {
541135446Strhodes		printf("invalid %s '%s': %s\n", desc,
542135446Strhodes		       value, isc_result_totext(result));
543135446Strhodes		return result;
544135446Strhodes	}
545135446Strhodes	*uip = n;
546135446Strhodes	return (ISC_R_SUCCESS);
547135446Strhodes}
548135446Strhodes
549135446Strhodesstatic void
550135446Strhodesset_port(const char *value) {
551135446Strhodes	isc_uint32_t n;
552135446Strhodes	isc_result_t result = parse_uint(&n, value, 65535, "port");
553135446Strhodes	if (result == ISC_R_SUCCESS)
554135446Strhodes		port = (isc_uint16_t) n;
555135446Strhodes}
556135446Strhodes
557135446Strhodesstatic void
558135446Strhodesset_timeout(const char *value) {
559135446Strhodes	isc_uint32_t n;
560135446Strhodes	isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
561135446Strhodes	if (result == ISC_R_SUCCESS)
562135446Strhodes		timeout = n;
563135446Strhodes}
564135446Strhodes
565135446Strhodesstatic void
566135446Strhodesset_tries(const char *value) {
567135446Strhodes	isc_uint32_t n;
568135446Strhodes	isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
569135446Strhodes	if (result == ISC_R_SUCCESS)
570135446Strhodes		tries = n;
571135446Strhodes}
572135446Strhodes
573135446Strhodesstatic void
574135446Strhodessetoption(char *opt) {
575135446Strhodes	if (strncasecmp(opt, "all", 4) == 0) {
576135446Strhodes		show_settings(ISC_TRUE, ISC_FALSE);
577135446Strhodes	} else if (strncasecmp(opt, "class=", 6) == 0) {
578135446Strhodes		if (testclass(&opt[6]))
579135446Strhodes			safecpy(defclass, &opt[6], sizeof(defclass));
580135446Strhodes	} else if (strncasecmp(opt, "cl=", 3) == 0) {
581135446Strhodes		if (testclass(&opt[3]))
582135446Strhodes			safecpy(defclass, &opt[3], sizeof(defclass));
583135446Strhodes	} else if (strncasecmp(opt, "type=", 5) == 0) {
584135446Strhodes		if (testtype(&opt[5]))
585135446Strhodes			safecpy(deftype, &opt[5], sizeof(deftype));
586135446Strhodes	} else if (strncasecmp(opt, "ty=", 3) == 0) {
587135446Strhodes		if (testtype(&opt[3]))
588135446Strhodes			safecpy(deftype, &opt[3], sizeof(deftype));
589135446Strhodes	} else if (strncasecmp(opt, "querytype=", 10) == 0) {
590135446Strhodes		if (testtype(&opt[10]))
591135446Strhodes			safecpy(deftype, &opt[10], sizeof(deftype));
592135446Strhodes	} else if (strncasecmp(opt, "query=", 6) == 0) {
593135446Strhodes		if (testtype(&opt[6]))
594135446Strhodes			safecpy(deftype, &opt[6], sizeof(deftype));
595135446Strhodes	} else if (strncasecmp(opt, "qu=", 3) == 0) {
596135446Strhodes		if (testtype(&opt[3]))
597135446Strhodes			safecpy(deftype, &opt[3], sizeof(deftype));
598135446Strhodes	} else if (strncasecmp(opt, "q=", 2) == 0) {
599135446Strhodes		if (testtype(&opt[2]))
600135446Strhodes			safecpy(deftype, &opt[2], sizeof(deftype));
601135446Strhodes	} else if (strncasecmp(opt, "domain=", 7) == 0) {
602135446Strhodes		safecpy(domainopt, &opt[7], sizeof(domainopt));
603135446Strhodes		set_search_domain(domainopt);
604135446Strhodes		usesearch = ISC_TRUE;
605135446Strhodes	} else if (strncasecmp(opt, "do=", 3) == 0) {
606135446Strhodes		safecpy(domainopt, &opt[3], sizeof(domainopt));
607135446Strhodes		set_search_domain(domainopt);
608135446Strhodes		usesearch = ISC_TRUE;
609135446Strhodes	} else if (strncasecmp(opt, "port=", 5) == 0) {
610135446Strhodes		set_port(&opt[5]);
611135446Strhodes	} else if (strncasecmp(opt, "po=", 3) == 0) {
612135446Strhodes		set_port(&opt[3]);
613135446Strhodes	} else if (strncasecmp(opt, "timeout=", 8) == 0) {
614135446Strhodes		set_timeout(&opt[8]);
615135446Strhodes	} else if (strncasecmp(opt, "t=", 2) == 0) {
616135446Strhodes		set_timeout(&opt[2]);
617135446Strhodes 	} else if (strncasecmp(opt, "rec", 3) == 0) {
618135446Strhodes		recurse = ISC_TRUE;
619135446Strhodes	} else if (strncasecmp(opt, "norec", 5) == 0) {
620135446Strhodes		recurse = ISC_FALSE;
621135446Strhodes	} else if (strncasecmp(opt, "retry=", 6) == 0) {
622135446Strhodes		set_tries(&opt[6]);
623135446Strhodes	} else if (strncasecmp(opt, "ret=", 4) == 0) {
624135446Strhodes		set_tries(&opt[4]);
625135446Strhodes 	} else if (strncasecmp(opt, "def", 3) == 0) {
626135446Strhodes		usesearch = ISC_TRUE;
627135446Strhodes	} else if (strncasecmp(opt, "nodef", 5) == 0) {
628135446Strhodes		usesearch = ISC_FALSE;
629135446Strhodes 	} else if (strncasecmp(opt, "vc", 3) == 0) {
630135446Strhodes		tcpmode = ISC_TRUE;
631135446Strhodes	} else if (strncasecmp(opt, "novc", 5) == 0) {
632135446Strhodes		tcpmode = ISC_FALSE;
633135446Strhodes 	} else if (strncasecmp(opt, "deb", 3) == 0) {
634135446Strhodes		short_form = ISC_FALSE;
635135446Strhodes	} else if (strncasecmp(opt, "nodeb", 5) == 0) {
636135446Strhodes		short_form = ISC_TRUE;
637135446Strhodes 	} else if (strncasecmp(opt, "d2", 2) == 0) {
638135446Strhodes		debugging = ISC_TRUE;
639135446Strhodes	} else if (strncasecmp(opt, "nod2", 4) == 0) {
640135446Strhodes		debugging = ISC_FALSE;
641135446Strhodes	} else if (strncasecmp(opt, "search", 3) == 0) {
642135446Strhodes		usesearch = ISC_TRUE;
643135446Strhodes	} else if (strncasecmp(opt, "nosearch", 5) == 0) {
644135446Strhodes		usesearch = ISC_FALSE;
645135446Strhodes	} else if (strncasecmp(opt, "sil", 3) == 0) {
646135446Strhodes		/* deprecation_msg = ISC_FALSE; */
647135446Strhodes	} else {
648135446Strhodes		printf("*** Invalid option: %s\n", opt);
649135446Strhodes	}
650135446Strhodes}
651135446Strhodes
652135446Strhodesstatic void
653135446Strhodesaddlookup(char *opt) {
654135446Strhodes	dig_lookup_t *lookup;
655135446Strhodes	isc_result_t result;
656135446Strhodes	isc_textregion_t tr;
657135446Strhodes	dns_rdatatype_t rdtype;
658135446Strhodes	dns_rdataclass_t rdclass;
659135446Strhodes	char store[MXNAME];
660135446Strhodes
661135446Strhodes	debug("addlookup()");
662135446Strhodes	tr.base = deftype;
663135446Strhodes	tr.length = strlen(deftype);
664135446Strhodes	result = dns_rdatatype_fromtext(&rdtype, &tr);
665135446Strhodes	if (result != ISC_R_SUCCESS) {
666135446Strhodes		printf("unknown query type: %s\n", deftype);
667135446Strhodes		rdclass = dns_rdatatype_a;
668135446Strhodes	}
669135446Strhodes	tr.base = defclass;
670135446Strhodes	tr.length = strlen(defclass);
671135446Strhodes	result = dns_rdataclass_fromtext(&rdclass, &tr);
672135446Strhodes	if (result != ISC_R_SUCCESS) {
673135446Strhodes		printf("unknown query class: %s\n", defclass);
674135446Strhodes		rdclass = dns_rdataclass_in;
675135446Strhodes	}
676135446Strhodes	lookup = make_empty_lookup();
677135446Strhodes	if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
678135446Strhodes	    == ISC_R_SUCCESS) {
679135446Strhodes		safecpy(lookup->textname, store, sizeof(lookup->textname));
680135446Strhodes		lookup->rdtype = dns_rdatatype_ptr;
681135446Strhodes		lookup->rdtypeset = ISC_TRUE;
682135446Strhodes	} else {
683135446Strhodes		safecpy(lookup->textname, opt, sizeof(lookup->textname));
684135446Strhodes		lookup->rdtype = rdtype;
685135446Strhodes		lookup->rdtypeset = ISC_TRUE;
686135446Strhodes	}
687135446Strhodes	lookup->rdclass = rdclass;
688135446Strhodes	lookup->rdclassset = ISC_TRUE;
689135446Strhodes	lookup->trace = ISC_FALSE;
690135446Strhodes	lookup->trace_root = lookup->trace;
691135446Strhodes	lookup->ns_search_only = ISC_FALSE;
692135446Strhodes	lookup->identify = identify;
693135446Strhodes	lookup->recurse = recurse;
694135446Strhodes	lookup->aaonly = aaonly;
695135446Strhodes	lookup->retries = tries;
696135446Strhodes	lookup->udpsize = 0;
697135446Strhodes	lookup->comments = comments;
698135446Strhodes	lookup->tcp_mode = tcpmode;
699135446Strhodes	lookup->stats = stats;
700135446Strhodes	lookup->section_question = section_question;
701135446Strhodes	lookup->section_answer = section_answer;
702135446Strhodes	lookup->section_authority = section_authority;
703135446Strhodes	lookup->section_additional = section_additional;
704135446Strhodes	lookup->new_search = ISC_TRUE;
705135446Strhodes	ISC_LIST_INIT(lookup->q);
706135446Strhodes	ISC_LINK_INIT(lookup, link);
707135446Strhodes	ISC_LIST_APPEND(lookup_list, lookup, link);
708135446Strhodes	lookup->origin = NULL;
709135446Strhodes	ISC_LIST_INIT(lookup->my_server_list);
710135446Strhodes	debug("looking up %s", lookup->textname);
711135446Strhodes}
712135446Strhodes
713135446Strhodesstatic void
714135446Strhodesget_next_command(void) {
715135446Strhodes	char *buf;
716135446Strhodes	char *ptr, *arg;
717135446Strhodes	char *input;
718135446Strhodes
719135446Strhodes	fflush(stdout);
720135446Strhodes	buf = isc_mem_allocate(mctx, COMMSIZE);
721135446Strhodes	if (buf == NULL)
722135446Strhodes		fatal("memory allocation failure");
723135446Strhodes	fputs("> ", stderr);
724135446Strhodes	isc_app_block();
725135446Strhodes	ptr = fgets(buf, COMMSIZE, stdin);
726135446Strhodes	isc_app_unblock();
727135446Strhodes	if (ptr == NULL) {
728135446Strhodes		in_use = ISC_FALSE;
729135446Strhodes		goto cleanup;
730135446Strhodes	}
731135446Strhodes	input = buf;
732135446Strhodes	ptr = next_token(&input, " \t\r\n");
733135446Strhodes	if (ptr == NULL)
734135446Strhodes		goto cleanup;
735135446Strhodes	arg = next_token(&input, " \t\r\n");
736135446Strhodes	if ((strcasecmp(ptr, "set") == 0) &&
737135446Strhodes	    (arg != NULL))
738135446Strhodes		setoption(arg);
739135446Strhodes	else if ((strcasecmp(ptr, "server") == 0) ||
740135446Strhodes		 (strcasecmp(ptr, "lserver") == 0)) {
741143731Sdougb		isc_app_block();
742135446Strhodes		set_nameserver(arg);
743143731Sdougb		isc_app_unblock();
744135446Strhodes		show_settings(ISC_TRUE, ISC_TRUE);
745135446Strhodes	} else if (strcasecmp(ptr, "exit") == 0) {
746135446Strhodes		in_use = ISC_FALSE;
747135446Strhodes		goto cleanup;
748135446Strhodes	} else if (strcasecmp(ptr, "help") == 0 ||
749135446Strhodes		   strcasecmp(ptr, "?") == 0) {
750135446Strhodes		printf("The '%s' command is not yet implemented.\n", ptr);
751135446Strhodes		goto cleanup;
752135446Strhodes	} else if (strcasecmp(ptr, "finger") == 0 ||
753135446Strhodes		   strcasecmp(ptr, "root") == 0 ||
754135446Strhodes		   strcasecmp(ptr, "ls") == 0 ||
755135446Strhodes		   strcasecmp(ptr, "view") == 0) {
756135446Strhodes		printf("The '%s' command is not implemented.\n", ptr);
757135446Strhodes		goto cleanup;
758135446Strhodes	} else
759135446Strhodes		addlookup(ptr);
760135446Strhodes cleanup:
761135446Strhodes	isc_mem_free(mctx, buf);
762135446Strhodes}
763135446Strhodes
764135446Strhodesstatic void
765135446Strhodesparse_args(int argc, char **argv) {
766135446Strhodes	isc_boolean_t have_lookup = ISC_FALSE;
767135446Strhodes
768135446Strhodes	usesearch = ISC_TRUE;
769135446Strhodes	for (argc--, argv++; argc > 0; argc--, argv++) {
770135446Strhodes		debug("main parsing %s", argv[0]);
771135446Strhodes		if (argv[0][0] == '-') {
772135446Strhodes			if (argv[0][1] != 0)
773135446Strhodes				setoption(&argv[0][1]);
774135446Strhodes			else
775135446Strhodes				have_lookup = ISC_TRUE;
776135446Strhodes		} else {
777135446Strhodes			if (!have_lookup) {
778135446Strhodes				have_lookup = ISC_TRUE;
779135446Strhodes				in_use = ISC_TRUE;
780135446Strhodes				addlookup(argv[0]);
781135446Strhodes			}
782135446Strhodes			else
783135446Strhodes				set_nameserver(argv[0]);
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
859135446Strhodes	result = isc_app_start();
860135446Strhodes	check_result(result, "isc_app_start");
861135446Strhodes
862135446Strhodes	setup_libs();
863135446Strhodes	progname = argv[0];
864135446Strhodes
865135446Strhodes	parse_args(argc, argv);
866135446Strhodes
867135446Strhodes	setup_system();
868135446Strhodes	if (domainopt[0] != '\0')
869135446Strhodes		set_search_domain(domainopt);
870135446Strhodes	if (in_use)
871135446Strhodes		result = isc_app_onrun(mctx, global_task, onrun_callback,
872135446Strhodes				       NULL);
873135446Strhodes	else
874135446Strhodes		result = isc_app_onrun(mctx, global_task, getinput, NULL);
875135446Strhodes	check_result(result, "isc_app_onrun");
876135446Strhodes	in_use = ISC_TF(!in_use);
877135446Strhodes
878135446Strhodes	(void)isc_app_run();
879135446Strhodes
880135446Strhodes	puts("");
881135446Strhodes	debug("done, and starting to shut down");
882135446Strhodes	if (global_event != NULL)
883135446Strhodes		isc_event_free(&global_event);
884135446Strhodes	cancel_all();
885135446Strhodes	destroy_libs();
886135446Strhodes	isc_app_finish();
887135446Strhodes
888135446Strhodes	return (0);
889135446Strhodes}
890