nslookup.c revision 193149
1135446Strhodes/*
2193149Sdougb * Copyright (C) 2004-2007, 2009  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
18193149Sdougb/* $Id: nslookup.c,v 1.117.334.4 2009/05/06 11:41:57 fdupont 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);
376135446Strhodes				loopresult = dns_rdataset_next(rdataset);
377135446Strhodes			}
378135446Strhodes		}
379135446Strhodes		result = dns_message_nextname(msg, section);
380135446Strhodes		if (result == ISC_R_NOMORE)
381135446Strhodes			break;
382135446Strhodes		else if (result != ISC_R_SUCCESS) {
383135446Strhodes			return (result);
384135446Strhodes		}
385135446Strhodes	}
386135446Strhodes	return (ISC_R_SUCCESS);
387135446Strhodes}
388135446Strhodes
389135446Strhodesvoid
390135446Strhodesreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query)
391135446Strhodes{
392135446Strhodes	UNUSED(bytes);
393135446Strhodes	UNUSED(from);
394135446Strhodes	UNUSED(query);
395135446Strhodes}
396135446Strhodes
397135446Strhodesvoid
398135446Strhodestrying(char *frm, dig_lookup_t *lookup) {
399135446Strhodes	UNUSED(frm);
400135446Strhodes	UNUSED(lookup);
401135446Strhodes
402135446Strhodes}
403135446Strhodes
404135446Strhodesisc_result_t
405135446Strhodesprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
406193149Sdougb	char servtext[ISC_SOCKADDR_FORMATSIZE];
407135446Strhodes
408135446Strhodes	debug("printmessage()");
409135446Strhodes
410135446Strhodes	isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
411143731Sdougb	printf("Server:\t\t%s\n", query->userarg);
412135446Strhodes	printf("Address:\t%s\n", servtext);
413193149Sdougb
414135446Strhodes	puts("");
415135446Strhodes
416135446Strhodes	if (!short_form) {
417135446Strhodes		isc_boolean_t headers = ISC_TRUE;
418135446Strhodes		puts("------------");
419135446Strhodes		/*		detailheader(query, msg);*/
420135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_QUESTION);
421135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_ANSWER);
422135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_AUTHORITY);
423135446Strhodes		detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL);
424135446Strhodes		puts("------------");
425135446Strhodes	}
426135446Strhodes
427135446Strhodes	if (msg->rcode != 0) {
428135446Strhodes		char nametext[DNS_NAME_FORMATSIZE];
429135446Strhodes		dns_name_format(query->lookup->name,
430135446Strhodes				nametext, sizeof(nametext));
431174187Sdougb		printf("** server can't find %s: %s\n",
432174187Sdougb		       (msg->rcode != dns_rcode_nxdomain) ? nametext :
433193149Sdougb		       query->lookup->textname, rcode_totext(msg->rcode));
434135446Strhodes		debug("returning with rcode == 0");
435135446Strhodes		return (ISC_R_SUCCESS);
436135446Strhodes	}
437135446Strhodes
438135446Strhodes	if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
439135446Strhodes		puts("Non-authoritative answer:");
440135446Strhodes	if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
441135446Strhodes		printsection(query, msg, headers, DNS_SECTION_ANSWER);
442135446Strhodes	else
443135446Strhodes		printf("*** Can't find %s: No answer\n",
444135446Strhodes		       query->lookup->textname);
445135446Strhodes
446135446Strhodes	if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
447135446Strhodes	    (query->lookup->rdtype != dns_rdatatype_a)) {
448135446Strhodes		puts("\nAuthoritative answers can be found from:");
449135446Strhodes		printsection(query, msg, headers,
450135446Strhodes			     DNS_SECTION_AUTHORITY);
451135446Strhodes		printsection(query, msg, headers,
452135446Strhodes			     DNS_SECTION_ADDITIONAL);
453135446Strhodes	}
454135446Strhodes	return (ISC_R_SUCCESS);
455135446Strhodes}
456135446Strhodes
457135446Strhodesstatic void
458135446Strhodesshow_settings(isc_boolean_t full, isc_boolean_t serv_only) {
459135446Strhodes	dig_server_t *srv;
460135446Strhodes	isc_sockaddr_t sockaddr;
461135446Strhodes	dig_searchlist_t *listent;
462193149Sdougb	isc_result_t result;
463135446Strhodes
464135446Strhodes	srv = ISC_LIST_HEAD(server_list);
465135446Strhodes
466135446Strhodes	while (srv != NULL) {
467135446Strhodes		char sockstr[ISC_SOCKADDR_FORMATSIZE];
468135446Strhodes
469193149Sdougb		result = get_address(srv->servername, port, &sockaddr);
470193149Sdougb		check_result(result, "get_address");
471193149Sdougb
472135446Strhodes		isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
473135446Strhodes		printf("Default server: %s\nAddress: %s\n",
474143731Sdougb			srv->userarg, sockstr);
475135446Strhodes		if (!full)
476135446Strhodes			return;
477135446Strhodes		srv = ISC_LIST_NEXT(srv, link);
478135446Strhodes	}
479135446Strhodes	if (serv_only)
480135446Strhodes		return;
481135446Strhodes	printf("\nSet options:\n");
482135446Strhodes	printf("  %s\t\t\t%s\t\t%s\n",
483135446Strhodes	       tcpmode ? "vc" : "novc",
484135446Strhodes	       short_form ? "nodebug" : "debug",
485135446Strhodes	       debugging ? "d2" : "nod2");
486135446Strhodes	printf("  %s\t\t%s\n",
487135446Strhodes	       usesearch ? "search" : "nosearch",
488135446Strhodes	       recurse ? "recurse" : "norecurse");
489135446Strhodes	printf("  timeout = %d\t\tretry = %d\tport = %d\n",
490135446Strhodes	       timeout, tries, port);
491135446Strhodes	printf("  querytype = %-8s\tclass = %s\n", deftype, defclass);
492135446Strhodes	printf("  srchlist = ");
493135446Strhodes	for (listent = ISC_LIST_HEAD(search_list);
494135446Strhodes	     listent != NULL;
495135446Strhodes	     listent = ISC_LIST_NEXT(listent, link)) {
496135446Strhodes		     printf("%s", listent->origin);
497135446Strhodes		     if (ISC_LIST_NEXT(listent, link) != NULL)
498135446Strhodes			     printf("/");
499135446Strhodes	}
500135446Strhodes	printf("\n");
501135446Strhodes}
502135446Strhodes
503135446Strhodesstatic isc_boolean_t
504135446Strhodestesttype(char *typetext) {
505135446Strhodes	isc_result_t result;
506135446Strhodes	isc_textregion_t tr;
507135446Strhodes	dns_rdatatype_t rdtype;
508135446Strhodes
509135446Strhodes	tr.base = typetext;
510135446Strhodes	tr.length = strlen(typetext);
511135446Strhodes	result = dns_rdatatype_fromtext(&rdtype, &tr);
512135446Strhodes	if (result == ISC_R_SUCCESS)
513135446Strhodes		return (ISC_TRUE);
514135446Strhodes	else {
515135446Strhodes		printf("unknown query type: %s\n", typetext);
516135446Strhodes		return (ISC_FALSE);
517135446Strhodes	}
518135446Strhodes}
519135446Strhodes
520135446Strhodesstatic isc_boolean_t
521135446Strhodestestclass(char *typetext) {
522135446Strhodes	isc_result_t result;
523135446Strhodes	isc_textregion_t tr;
524135446Strhodes	dns_rdataclass_t rdclass;
525135446Strhodes
526135446Strhodes	tr.base = typetext;
527135446Strhodes	tr.length = strlen(typetext);
528135446Strhodes	result = dns_rdataclass_fromtext(&rdclass, &tr);
529193149Sdougb	if (result == ISC_R_SUCCESS)
530135446Strhodes		return (ISC_TRUE);
531135446Strhodes	else {
532135446Strhodes		printf("unknown query class: %s\n", typetext);
533135446Strhodes		return (ISC_FALSE);
534135446Strhodes	}
535135446Strhodes}
536135446Strhodes
537135446Strhodesstatic void
538135446Strhodessafecpy(char *dest, char *src, int size) {
539135446Strhodes	strncpy(dest, src, size);
540135446Strhodes	dest[size-1] = 0;
541135446Strhodes}
542135446Strhodes
543135446Strhodesstatic isc_result_t
544135446Strhodesparse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
545135446Strhodes	   const char *desc) {
546135446Strhodes	isc_uint32_t n;
547135446Strhodes	isc_result_t result = isc_parse_uint32(&n, value, 10);
548135446Strhodes	if (result == ISC_R_SUCCESS && n > max)
549135446Strhodes		result = ISC_R_RANGE;
550135446Strhodes	if (result != ISC_R_SUCCESS) {
551135446Strhodes		printf("invalid %s '%s': %s\n", desc,
552135446Strhodes		       value, isc_result_totext(result));
553135446Strhodes		return result;
554135446Strhodes	}
555135446Strhodes	*uip = n;
556135446Strhodes	return (ISC_R_SUCCESS);
557135446Strhodes}
558135446Strhodes
559135446Strhodesstatic void
560135446Strhodesset_port(const char *value) {
561135446Strhodes	isc_uint32_t n;
562135446Strhodes	isc_result_t result = parse_uint(&n, value, 65535, "port");
563135446Strhodes	if (result == ISC_R_SUCCESS)
564135446Strhodes		port = (isc_uint16_t) n;
565135446Strhodes}
566135446Strhodes
567135446Strhodesstatic void
568135446Strhodesset_timeout(const char *value) {
569135446Strhodes	isc_uint32_t n;
570135446Strhodes	isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
571135446Strhodes	if (result == ISC_R_SUCCESS)
572135446Strhodes		timeout = n;
573135446Strhodes}
574135446Strhodes
575135446Strhodesstatic void
576135446Strhodesset_tries(const char *value) {
577135446Strhodes	isc_uint32_t n;
578135446Strhodes	isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
579135446Strhodes	if (result == ISC_R_SUCCESS)
580135446Strhodes		tries = n;
581135446Strhodes}
582135446Strhodes
583135446Strhodesstatic void
584135446Strhodessetoption(char *opt) {
585135446Strhodes	if (strncasecmp(opt, "all", 4) == 0) {
586135446Strhodes		show_settings(ISC_TRUE, ISC_FALSE);
587135446Strhodes	} else if (strncasecmp(opt, "class=", 6) == 0) {
588135446Strhodes		if (testclass(&opt[6]))
589135446Strhodes			safecpy(defclass, &opt[6], sizeof(defclass));
590135446Strhodes	} else if (strncasecmp(opt, "cl=", 3) == 0) {
591135446Strhodes		if (testclass(&opt[3]))
592135446Strhodes			safecpy(defclass, &opt[3], sizeof(defclass));
593135446Strhodes	} else if (strncasecmp(opt, "type=", 5) == 0) {
594135446Strhodes		if (testtype(&opt[5]))
595135446Strhodes			safecpy(deftype, &opt[5], sizeof(deftype));
596135446Strhodes	} else if (strncasecmp(opt, "ty=", 3) == 0) {
597135446Strhodes		if (testtype(&opt[3]))
598135446Strhodes			safecpy(deftype, &opt[3], sizeof(deftype));
599135446Strhodes	} else if (strncasecmp(opt, "querytype=", 10) == 0) {
600135446Strhodes		if (testtype(&opt[10]))
601135446Strhodes			safecpy(deftype, &opt[10], sizeof(deftype));
602135446Strhodes	} else if (strncasecmp(opt, "query=", 6) == 0) {
603135446Strhodes		if (testtype(&opt[6]))
604135446Strhodes			safecpy(deftype, &opt[6], sizeof(deftype));
605135446Strhodes	} else if (strncasecmp(opt, "qu=", 3) == 0) {
606135446Strhodes		if (testtype(&opt[3]))
607135446Strhodes			safecpy(deftype, &opt[3], sizeof(deftype));
608135446Strhodes	} else if (strncasecmp(opt, "q=", 2) == 0) {
609135446Strhodes		if (testtype(&opt[2]))
610135446Strhodes			safecpy(deftype, &opt[2], sizeof(deftype));
611135446Strhodes	} else if (strncasecmp(opt, "domain=", 7) == 0) {
612135446Strhodes		safecpy(domainopt, &opt[7], sizeof(domainopt));
613135446Strhodes		set_search_domain(domainopt);
614135446Strhodes		usesearch = ISC_TRUE;
615135446Strhodes	} else if (strncasecmp(opt, "do=", 3) == 0) {
616135446Strhodes		safecpy(domainopt, &opt[3], sizeof(domainopt));
617135446Strhodes		set_search_domain(domainopt);
618135446Strhodes		usesearch = ISC_TRUE;
619135446Strhodes	} else if (strncasecmp(opt, "port=", 5) == 0) {
620135446Strhodes		set_port(&opt[5]);
621135446Strhodes	} else if (strncasecmp(opt, "po=", 3) == 0) {
622135446Strhodes		set_port(&opt[3]);
623135446Strhodes	} else if (strncasecmp(opt, "timeout=", 8) == 0) {
624135446Strhodes		set_timeout(&opt[8]);
625135446Strhodes	} else if (strncasecmp(opt, "t=", 2) == 0) {
626135446Strhodes		set_timeout(&opt[2]);
627193149Sdougb	} else if (strncasecmp(opt, "rec", 3) == 0) {
628135446Strhodes		recurse = ISC_TRUE;
629135446Strhodes	} else if (strncasecmp(opt, "norec", 5) == 0) {
630135446Strhodes		recurse = ISC_FALSE;
631135446Strhodes	} else if (strncasecmp(opt, "retry=", 6) == 0) {
632135446Strhodes		set_tries(&opt[6]);
633135446Strhodes	} else if (strncasecmp(opt, "ret=", 4) == 0) {
634135446Strhodes		set_tries(&opt[4]);
635193149Sdougb	} else if (strncasecmp(opt, "def", 3) == 0) {
636135446Strhodes		usesearch = ISC_TRUE;
637135446Strhodes	} else if (strncasecmp(opt, "nodef", 5) == 0) {
638135446Strhodes		usesearch = ISC_FALSE;
639193149Sdougb	} else if (strncasecmp(opt, "vc", 3) == 0) {
640135446Strhodes		tcpmode = ISC_TRUE;
641135446Strhodes	} else if (strncasecmp(opt, "novc", 5) == 0) {
642135446Strhodes		tcpmode = ISC_FALSE;
643193149Sdougb	} else if (strncasecmp(opt, "deb", 3) == 0) {
644135446Strhodes		short_form = ISC_FALSE;
645170222Sdougb		showsearch = ISC_TRUE;
646135446Strhodes	} else if (strncasecmp(opt, "nodeb", 5) == 0) {
647135446Strhodes		short_form = ISC_TRUE;
648170222Sdougb		showsearch = ISC_FALSE;
649193149Sdougb	} else if (strncasecmp(opt, "d2", 2) == 0) {
650135446Strhodes		debugging = ISC_TRUE;
651135446Strhodes	} else if (strncasecmp(opt, "nod2", 4) == 0) {
652135446Strhodes		debugging = ISC_FALSE;
653135446Strhodes	} else if (strncasecmp(opt, "search", 3) == 0) {
654135446Strhodes		usesearch = ISC_TRUE;
655135446Strhodes	} else if (strncasecmp(opt, "nosearch", 5) == 0) {
656135446Strhodes		usesearch = ISC_FALSE;
657135446Strhodes	} else if (strncasecmp(opt, "sil", 3) == 0) {
658135446Strhodes		/* deprecation_msg = ISC_FALSE; */
659170222Sdougb	} else if (strncasecmp(opt, "fail", 3) == 0) {
660170222Sdougb		nofail=ISC_FALSE;
661170222Sdougb	} else if (strncasecmp(opt, "nofail", 3) == 0) {
662170222Sdougb		nofail=ISC_TRUE;
663135446Strhodes	} else {
664193149Sdougb		printf("*** Invalid option: %s\n", opt);
665135446Strhodes	}
666135446Strhodes}
667135446Strhodes
668135446Strhodesstatic void
669135446Strhodesaddlookup(char *opt) {
670135446Strhodes	dig_lookup_t *lookup;
671135446Strhodes	isc_result_t result;
672135446Strhodes	isc_textregion_t tr;
673135446Strhodes	dns_rdatatype_t rdtype;
674135446Strhodes	dns_rdataclass_t rdclass;
675135446Strhodes	char store[MXNAME];
676135446Strhodes
677135446Strhodes	debug("addlookup()");
678135446Strhodes	tr.base = deftype;
679135446Strhodes	tr.length = strlen(deftype);
680135446Strhodes	result = dns_rdatatype_fromtext(&rdtype, &tr);
681135446Strhodes	if (result != ISC_R_SUCCESS) {
682135446Strhodes		printf("unknown query type: %s\n", deftype);
683135446Strhodes		rdclass = dns_rdatatype_a;
684135446Strhodes	}
685135446Strhodes	tr.base = defclass;
686135446Strhodes	tr.length = strlen(defclass);
687135446Strhodes	result = dns_rdataclass_fromtext(&rdclass, &tr);
688135446Strhodes	if (result != ISC_R_SUCCESS) {
689135446Strhodes		printf("unknown query class: %s\n", defclass);
690135446Strhodes		rdclass = dns_rdataclass_in;
691135446Strhodes	}
692135446Strhodes	lookup = make_empty_lookup();
693135446Strhodes	if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
694135446Strhodes	    == ISC_R_SUCCESS) {
695135446Strhodes		safecpy(lookup->textname, store, sizeof(lookup->textname));
696135446Strhodes		lookup->rdtype = dns_rdatatype_ptr;
697135446Strhodes		lookup->rdtypeset = ISC_TRUE;
698135446Strhodes	} else {
699135446Strhodes		safecpy(lookup->textname, opt, sizeof(lookup->textname));
700135446Strhodes		lookup->rdtype = rdtype;
701135446Strhodes		lookup->rdtypeset = ISC_TRUE;
702135446Strhodes	}
703135446Strhodes	lookup->rdclass = rdclass;
704135446Strhodes	lookup->rdclassset = ISC_TRUE;
705135446Strhodes	lookup->trace = ISC_FALSE;
706135446Strhodes	lookup->trace_root = lookup->trace;
707135446Strhodes	lookup->ns_search_only = ISC_FALSE;
708135446Strhodes	lookup->identify = identify;
709135446Strhodes	lookup->recurse = recurse;
710135446Strhodes	lookup->aaonly = aaonly;
711135446Strhodes	lookup->retries = tries;
712135446Strhodes	lookup->udpsize = 0;
713135446Strhodes	lookup->comments = comments;
714135446Strhodes	lookup->tcp_mode = tcpmode;
715135446Strhodes	lookup->stats = stats;
716135446Strhodes	lookup->section_question = section_question;
717135446Strhodes	lookup->section_answer = section_answer;
718135446Strhodes	lookup->section_authority = section_authority;
719135446Strhodes	lookup->section_additional = section_additional;
720135446Strhodes	lookup->new_search = ISC_TRUE;
721170222Sdougb	if (nofail)
722170222Sdougb		lookup->servfail_stops = ISC_FALSE;
723135446Strhodes	ISC_LIST_INIT(lookup->q);
724135446Strhodes	ISC_LINK_INIT(lookup, link);
725135446Strhodes	ISC_LIST_APPEND(lookup_list, lookup, link);
726135446Strhodes	lookup->origin = NULL;
727135446Strhodes	ISC_LIST_INIT(lookup->my_server_list);
728135446Strhodes	debug("looking up %s", lookup->textname);
729135446Strhodes}
730135446Strhodes
731135446Strhodesstatic void
732135446Strhodesget_next_command(void) {
733135446Strhodes	char *buf;
734135446Strhodes	char *ptr, *arg;
735135446Strhodes	char *input;
736135446Strhodes
737135446Strhodes	fflush(stdout);
738135446Strhodes	buf = isc_mem_allocate(mctx, COMMSIZE);
739135446Strhodes	if (buf == NULL)
740135446Strhodes		fatal("memory allocation failure");
741135446Strhodes	fputs("> ", stderr);
742165071Sdougb	fflush(stderr);
743135446Strhodes	isc_app_block();
744135446Strhodes	ptr = fgets(buf, COMMSIZE, stdin);
745135446Strhodes	isc_app_unblock();
746135446Strhodes	if (ptr == NULL) {
747135446Strhodes		in_use = ISC_FALSE;
748135446Strhodes		goto cleanup;
749135446Strhodes	}
750135446Strhodes	input = buf;
751135446Strhodes	ptr = next_token(&input, " \t\r\n");
752135446Strhodes	if (ptr == NULL)
753135446Strhodes		goto cleanup;
754135446Strhodes	arg = next_token(&input, " \t\r\n");
755135446Strhodes	if ((strcasecmp(ptr, "set") == 0) &&
756135446Strhodes	    (arg != NULL))
757135446Strhodes		setoption(arg);
758135446Strhodes	else if ((strcasecmp(ptr, "server") == 0) ||
759135446Strhodes		 (strcasecmp(ptr, "lserver") == 0)) {
760143731Sdougb		isc_app_block();
761135446Strhodes		set_nameserver(arg);
762170222Sdougb		check_ra = ISC_FALSE;
763143731Sdougb		isc_app_unblock();
764135446Strhodes		show_settings(ISC_TRUE, ISC_TRUE);
765135446Strhodes	} else if (strcasecmp(ptr, "exit") == 0) {
766135446Strhodes		in_use = ISC_FALSE;
767135446Strhodes		goto cleanup;
768135446Strhodes	} else if (strcasecmp(ptr, "help") == 0 ||
769135446Strhodes		   strcasecmp(ptr, "?") == 0) {
770135446Strhodes		printf("The '%s' command is not yet implemented.\n", ptr);
771135446Strhodes		goto cleanup;
772135446Strhodes	} else if (strcasecmp(ptr, "finger") == 0 ||
773135446Strhodes		   strcasecmp(ptr, "root") == 0 ||
774135446Strhodes		   strcasecmp(ptr, "ls") == 0 ||
775135446Strhodes		   strcasecmp(ptr, "view") == 0) {
776135446Strhodes		printf("The '%s' command is not implemented.\n", ptr);
777135446Strhodes		goto cleanup;
778135446Strhodes	} else
779135446Strhodes		addlookup(ptr);
780135446Strhodes cleanup:
781135446Strhodes	isc_mem_free(mctx, buf);
782135446Strhodes}
783135446Strhodes
784135446Strhodesstatic void
785135446Strhodesparse_args(int argc, char **argv) {
786135446Strhodes	isc_boolean_t have_lookup = ISC_FALSE;
787135446Strhodes
788135446Strhodes	usesearch = ISC_TRUE;
789135446Strhodes	for (argc--, argv++; argc > 0; argc--, argv++) {
790135446Strhodes		debug("main parsing %s", argv[0]);
791135446Strhodes		if (argv[0][0] == '-') {
792135446Strhodes			if (argv[0][1] != 0)
793135446Strhodes				setoption(&argv[0][1]);
794135446Strhodes			else
795135446Strhodes				have_lookup = ISC_TRUE;
796135446Strhodes		} else {
797135446Strhodes			if (!have_lookup) {
798135446Strhodes				have_lookup = ISC_TRUE;
799135446Strhodes				in_use = ISC_TRUE;
800135446Strhodes				addlookup(argv[0]);
801170222Sdougb			} else {
802170222Sdougb				set_nameserver(argv[0]);
803170222Sdougb				check_ra = ISC_FALSE;
804135446Strhodes			}
805135446Strhodes		}
806135446Strhodes	}
807135446Strhodes}
808135446Strhodes
809135446Strhodesstatic void
810135446Strhodesflush_lookup_list(void) {
811135446Strhodes	dig_lookup_t *l, *lp;
812135446Strhodes	dig_query_t *q, *qp;
813135446Strhodes	dig_server_t *s, *sp;
814135446Strhodes
815135446Strhodes	lookup_counter = 0;
816135446Strhodes	l = ISC_LIST_HEAD(lookup_list);
817135446Strhodes	while (l != NULL) {
818135446Strhodes		q = ISC_LIST_HEAD(l->q);
819135446Strhodes		while (q != NULL) {
820135446Strhodes			if (q->sock != NULL) {
821135446Strhodes				isc_socket_cancel(q->sock, NULL,
822135446Strhodes						  ISC_SOCKCANCEL_ALL);
823135446Strhodes				isc_socket_detach(&q->sock);
824135446Strhodes			}
825135446Strhodes			if (ISC_LINK_LINKED(&q->recvbuf, link))
826135446Strhodes				ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
827135446Strhodes						 link);
828135446Strhodes			if (ISC_LINK_LINKED(&q->lengthbuf, link))
829135446Strhodes				ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
830135446Strhodes						 link);
831135446Strhodes			isc_buffer_invalidate(&q->recvbuf);
832135446Strhodes			isc_buffer_invalidate(&q->lengthbuf);
833135446Strhodes			qp = q;
834135446Strhodes			q = ISC_LIST_NEXT(q, link);
835135446Strhodes			ISC_LIST_DEQUEUE(l->q, qp, link);
836135446Strhodes			isc_mem_free(mctx, qp);
837135446Strhodes		}
838135446Strhodes		s = ISC_LIST_HEAD(l->my_server_list);
839135446Strhodes		while (s != NULL) {
840135446Strhodes			sp = s;
841135446Strhodes			s = ISC_LIST_NEXT(s, link);
842135446Strhodes			ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
843135446Strhodes			isc_mem_free(mctx, sp);
844135446Strhodes
845135446Strhodes		}
846135446Strhodes		if (l->sendmsg != NULL)
847135446Strhodes			dns_message_destroy(&l->sendmsg);
848135446Strhodes		if (l->timer != NULL)
849135446Strhodes			isc_timer_detach(&l->timer);
850135446Strhodes		lp = l;
851135446Strhodes		l = ISC_LIST_NEXT(l, link);
852135446Strhodes		ISC_LIST_DEQUEUE(lookup_list, lp, link);
853135446Strhodes		isc_mem_free(mctx, lp);
854135446Strhodes	}
855135446Strhodes}
856135446Strhodes
857135446Strhodesstatic void
858135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) {
859135446Strhodes	UNUSED(task);
860135446Strhodes	if (global_event == NULL)
861135446Strhodes		global_event = event;
862135446Strhodes	while (in_use) {
863135446Strhodes		get_next_command();
864135446Strhodes		if (ISC_LIST_HEAD(lookup_list) != NULL) {
865135446Strhodes			start_lookup();
866135446Strhodes			return;
867135446Strhodes		}
868135446Strhodes	}
869135446Strhodes	isc_app_shutdown();
870135446Strhodes}
871135446Strhodes
872135446Strhodesint
873135446Strhodesmain(int argc, char **argv) {
874135446Strhodes	isc_result_t result;
875135446Strhodes
876135446Strhodes	ISC_LIST_INIT(lookup_list);
877135446Strhodes	ISC_LIST_INIT(server_list);
878135446Strhodes	ISC_LIST_INIT(search_list);
879135446Strhodes
880170222Sdougb	check_ra = ISC_TRUE;
881170222Sdougb
882135446Strhodes	result = isc_app_start();
883135446Strhodes	check_result(result, "isc_app_start");
884135446Strhodes
885135446Strhodes	setup_libs();
886135446Strhodes	progname = argv[0];
887135446Strhodes
888135446Strhodes	parse_args(argc, argv);
889135446Strhodes
890135446Strhodes	setup_system();
891135446Strhodes	if (domainopt[0] != '\0')
892135446Strhodes		set_search_domain(domainopt);
893135446Strhodes	if (in_use)
894135446Strhodes		result = isc_app_onrun(mctx, global_task, onrun_callback,
895135446Strhodes				       NULL);
896135446Strhodes	else
897135446Strhodes		result = isc_app_onrun(mctx, global_task, getinput, NULL);
898135446Strhodes	check_result(result, "isc_app_onrun");
899135446Strhodes	in_use = ISC_TF(!in_use);
900135446Strhodes
901135446Strhodes	(void)isc_app_run();
902135446Strhodes
903135446Strhodes	puts("");
904135446Strhodes	debug("done, and starting to shut down");
905135446Strhodes	if (global_event != NULL)
906135446Strhodes		isc_event_free(&global_event);
907135446Strhodes	cancel_all();
908135446Strhodes	destroy_libs();
909135446Strhodes	isc_app_finish();
910135446Strhodes
911135446Strhodes	return (0);
912135446Strhodes}
913