1/*
2 * Copyright (C) 2004-2013  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: nslookup.c,v 1.130 2011/12/16 23:01:16 each Exp $ */
19
20#include <config.h>
21
22#include <stdlib.h>
23#include <unistd.h>
24
25#include <isc/app.h>
26#include <isc/buffer.h>
27#include <isc/commandline.h>
28#include <isc/event.h>
29#include <isc/parseint.h>
30#include <isc/print.h>
31#include <isc/string.h>
32#include <isc/timer.h>
33#include <isc/util.h>
34#include <isc/task.h>
35#include <isc/netaddr.h>
36
37#include <dns/message.h>
38#include <dns/name.h>
39#include <dns/fixedname.h>
40#include <dns/rdata.h>
41#include <dns/rdataclass.h>
42#include <dns/rdataset.h>
43#include <dns/rdatastruct.h>
44#include <dns/rdatatype.h>
45#include <dns/byaddr.h>
46
47#include <dig/dig.h>
48
49#if defined(HAVE_READLINE)
50#include <readline/readline.h>
51#include <readline/history.h>
52#endif
53
54static isc_boolean_t short_form = ISC_TRUE,
55	tcpmode = ISC_FALSE,
56	identify = ISC_FALSE, stats = ISC_TRUE,
57	comments = ISC_TRUE, section_question = ISC_TRUE,
58	section_answer = ISC_TRUE, section_authority = ISC_TRUE,
59	section_additional = ISC_TRUE, recurse = ISC_TRUE,
60	aaonly = ISC_FALSE, nofail = ISC_TRUE;
61
62static isc_boolean_t interactive;
63
64static isc_boolean_t in_use = ISC_FALSE;
65static char defclass[MXRD] = "IN";
66static char deftype[MXRD] = "A";
67static isc_event_t *global_event = NULL;
68static int query_error = 1, print_error = 0;
69
70static char domainopt[DNS_NAME_MAXTEXT];
71
72static const char *rcodetext[] = {
73	"NOERROR",
74	"FORMERR",
75	"SERVFAIL",
76	"NXDOMAIN",
77	"NOTIMP",
78	"REFUSED",
79	"YXDOMAIN",
80	"YXRRSET",
81	"NXRRSET",
82	"NOTAUTH",
83	"NOTZONE",
84	"RESERVED11",
85	"RESERVED12",
86	"RESERVED13",
87	"RESERVED14",
88	"RESERVED15",
89	"BADVERS"
90};
91
92static const char *rtypetext[] = {
93	"rtype_0 = ",			/* 0 */
94	"internet address = ",		/* 1 */
95	"nameserver = ",		/* 2 */
96	"md = ",			/* 3 */
97	"mf = ",			/* 4 */
98	"canonical name = ",		/* 5 */
99	"soa = ",			/* 6 */
100	"mb = ",			/* 7 */
101	"mg = ",			/* 8 */
102	"mr = ",			/* 9 */
103	"rtype_10 = ",			/* 10 */
104	"protocol = ",			/* 11 */
105	"name = ",			/* 12 */
106	"hinfo = ",			/* 13 */
107	"minfo = ",			/* 14 */
108	"mail exchanger = ",		/* 15 */
109	"text = ",			/* 16 */
110	"rp = ",       			/* 17 */
111	"afsdb = ",			/* 18 */
112	"x25 address = ",		/* 19 */
113	"isdn address = ",		/* 20 */
114	"rt = ",			/* 21 */
115	"nsap = ",			/* 22 */
116	"nsap_ptr = ",			/* 23 */
117	"signature = ",			/* 24 */
118	"key = ",			/* 25 */
119	"px = ",			/* 26 */
120	"gpos = ",			/* 27 */
121	"has AAAA address ",		/* 28 */
122	"loc = ",			/* 29 */
123	"next = ",			/* 30 */
124	"rtype_31 = ",			/* 31 */
125	"rtype_32 = ",			/* 32 */
126	"service = ",			/* 33 */
127	"rtype_34 = ",			/* 34 */
128	"naptr = ",			/* 35 */
129	"kx = ",			/* 36 */
130	"cert = ",			/* 37 */
131	"v6 address = ",		/* 38 */
132	"dname = ",			/* 39 */
133	"rtype_40 = ",			/* 40 */
134	"optional = "			/* 41 */
135};
136
137#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
138
139static void flush_lookup_list(void);
140static void getinput(isc_task_t *task, isc_event_t *event);
141
142static char *
143rcode_totext(dns_rcode_t rcode)
144{
145	static char buf[sizeof("?65535")];
146	union {
147		const char *consttext;
148		char *deconsttext;
149	} totext;
150
151	if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
152		snprintf(buf, sizeof(buf), "?%u", rcode);
153		totext.deconsttext = buf;
154	} else
155		totext.consttext = rcodetext[rcode];
156	return totext.deconsttext;
157}
158
159void
160dighost_shutdown(void) {
161	isc_event_t *event = global_event;
162
163	flush_lookup_list();
164	debug("dighost_shutdown()");
165
166	if (!in_use) {
167		isc_app_shutdown();
168		return;
169	}
170
171	isc_task_send(global_task, &event);
172}
173
174static void
175printsoa(dns_rdata_t *rdata) {
176	dns_rdata_soa_t soa;
177	isc_result_t result;
178	char namebuf[DNS_NAME_FORMATSIZE];
179
180	result = dns_rdata_tostruct(rdata, &soa, NULL);
181	check_result(result, "dns_rdata_tostruct");
182
183	dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
184	printf("\torigin = %s\n", namebuf);
185	dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
186	printf("\tmail addr = %s\n", namebuf);
187	printf("\tserial = %u\n", soa.serial);
188	printf("\trefresh = %u\n", soa.refresh);
189	printf("\tretry = %u\n", soa.retry);
190	printf("\texpire = %u\n", soa.expire);
191	printf("\tminimum = %u\n", soa.minimum);
192	dns_rdata_freestruct(&soa);
193}
194
195static void
196printa(dns_rdata_t *rdata) {
197	isc_result_t result;
198	char text[sizeof("255.255.255.255")];
199	isc_buffer_t b;
200
201	isc_buffer_init(&b, text, sizeof(text));
202	result = dns_rdata_totext(rdata, NULL, &b);
203	check_result(result, "dns_rdata_totext");
204	printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
205	       (char *)isc_buffer_base(&b));
206}
207#ifdef DIG_SIGCHASE
208/* Just for compatibility : not use in host program */
209isc_result_t
210printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
211	      isc_buffer_t *target)
212{
213	UNUSED(owner_name);
214	UNUSED(rdataset);
215	UNUSED(target);
216	return(ISC_FALSE);
217}
218#endif
219static void
220printrdata(dns_rdata_t *rdata) {
221	isc_result_t result;
222	isc_buffer_t *b = NULL;
223	unsigned int size = 1024;
224	isc_boolean_t done = ISC_FALSE;
225
226	if (rdata->type < N_KNOWN_RRTYPES)
227		printf("%s", rtypetext[rdata->type]);
228	else
229		printf("rdata_%d = ", rdata->type);
230
231	while (!done) {
232		result = isc_buffer_allocate(mctx, &b, size);
233		if (result != ISC_R_SUCCESS)
234			check_result(result, "isc_buffer_allocate");
235		result = dns_rdata_totext(rdata, NULL, b);
236		if (result == ISC_R_SUCCESS) {
237			printf("%.*s\n", (int)isc_buffer_usedlength(b),
238			       (char *)isc_buffer_base(b));
239			done = ISC_TRUE;
240		} else if (result != ISC_R_NOSPACE)
241			check_result(result, "dns_rdata_totext");
242		isc_buffer_free(&b);
243		size *= 2;
244	}
245}
246
247static isc_result_t
248printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
249	     dns_section_t section) {
250	isc_result_t result, loopresult;
251	dns_name_t *name;
252	dns_rdataset_t *rdataset = NULL;
253	dns_rdata_t rdata = DNS_RDATA_INIT;
254	char namebuf[DNS_NAME_FORMATSIZE];
255
256	UNUSED(query);
257	UNUSED(headers);
258
259	debug("printsection()");
260
261	result = dns_message_firstname(msg, section);
262	if (result == ISC_R_NOMORE)
263		return (ISC_R_SUCCESS);
264	else if (result != ISC_R_SUCCESS)
265		return (result);
266	for (;;) {
267		name = NULL;
268		dns_message_currentname(msg, section,
269					&name);
270		for (rdataset = ISC_LIST_HEAD(name->list);
271		     rdataset != NULL;
272		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
273			loopresult = dns_rdataset_first(rdataset);
274			while (loopresult == ISC_R_SUCCESS) {
275				dns_rdataset_current(rdataset, &rdata);
276				switch (rdata.type) {
277				case dns_rdatatype_a:
278					if (section != DNS_SECTION_ANSWER)
279						goto def_short_section;
280					dns_name_format(name, namebuf,
281							sizeof(namebuf));
282					printf("Name:\t%s\n", namebuf);
283					printa(&rdata);
284					break;
285				case dns_rdatatype_soa:
286					dns_name_format(name, namebuf,
287							sizeof(namebuf));
288					printf("%s\n", namebuf);
289					printsoa(&rdata);
290					break;
291				default:
292				def_short_section:
293					dns_name_format(name, namebuf,
294							sizeof(namebuf));
295					printf("%s\t", namebuf);
296					printrdata(&rdata);
297					break;
298				}
299				dns_rdata_reset(&rdata);
300				loopresult = dns_rdataset_next(rdataset);
301			}
302		}
303		result = dns_message_nextname(msg, section);
304		if (result == ISC_R_NOMORE)
305			break;
306		else if (result != ISC_R_SUCCESS) {
307			return (result);
308		}
309	}
310	return (ISC_R_SUCCESS);
311}
312
313static isc_result_t
314detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
315	     dns_section_t section) {
316	isc_result_t result, loopresult;
317	dns_name_t *name;
318	dns_rdataset_t *rdataset = NULL;
319	dns_rdata_t rdata = DNS_RDATA_INIT;
320	char namebuf[DNS_NAME_FORMATSIZE];
321
322	UNUSED(query);
323
324	debug("detailsection()");
325
326	if (headers) {
327		switch (section) {
328		case DNS_SECTION_QUESTION:
329			puts("    QUESTIONS:");
330			break;
331		case DNS_SECTION_ANSWER:
332			puts("    ANSWERS:");
333			break;
334		case DNS_SECTION_AUTHORITY:
335			puts("    AUTHORITY RECORDS:");
336			break;
337		case DNS_SECTION_ADDITIONAL:
338			puts("    ADDITIONAL RECORDS:");
339			break;
340		}
341	}
342
343	result = dns_message_firstname(msg, section);
344	if (result == ISC_R_NOMORE)
345		return (ISC_R_SUCCESS);
346	else if (result != ISC_R_SUCCESS)
347		return (result);
348	for (;;) {
349		name = NULL;
350		dns_message_currentname(msg, section,
351					&name);
352		for (rdataset = ISC_LIST_HEAD(name->list);
353		     rdataset != NULL;
354		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
355			if (section == DNS_SECTION_QUESTION) {
356				dns_name_format(name, namebuf,
357						sizeof(namebuf));
358				printf("\t%s, ", namebuf);
359				dns_rdatatype_format(rdataset->type,
360						     namebuf,
361						     sizeof(namebuf));
362				printf("type = %s, ", namebuf);
363				dns_rdataclass_format(rdataset->rdclass,
364						      namebuf,
365						      sizeof(namebuf));
366				printf("class = %s\n", namebuf);
367			}
368			loopresult = dns_rdataset_first(rdataset);
369			while (loopresult == ISC_R_SUCCESS) {
370				dns_rdataset_current(rdataset, &rdata);
371
372				dns_name_format(name, namebuf,
373						sizeof(namebuf));
374				printf("    ->  %s\n", namebuf);
375
376				switch (rdata.type) {
377				case dns_rdatatype_soa:
378					printsoa(&rdata);
379					break;
380				default:
381					printf("\t");
382					printrdata(&rdata);
383				}
384				dns_rdata_reset(&rdata);
385				printf("\tttl = %u\n", rdataset->ttl);
386				loopresult = dns_rdataset_next(rdataset);
387			}
388		}
389		result = dns_message_nextname(msg, section);
390		if (result == ISC_R_NOMORE)
391			break;
392		else if (result != ISC_R_SUCCESS) {
393			return (result);
394		}
395	}
396	return (ISC_R_SUCCESS);
397}
398
399void
400received(int bytes, isc_sockaddr_t *from, dig_query_t *query)
401{
402	UNUSED(bytes);
403	UNUSED(from);
404	UNUSED(query);
405}
406
407void
408trying(char *frm, dig_lookup_t *lookup) {
409	UNUSED(frm);
410	UNUSED(lookup);
411
412}
413
414isc_result_t
415printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
416	char servtext[ISC_SOCKADDR_FORMATSIZE];
417
418	/* I've we've gotten this far, we've reached a server. */
419	query_error = 0;
420
421	debug("printmessage()");
422
423	isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
424	printf("Server:\t\t%s\n", query->userarg);
425	printf("Address:\t%s\n", servtext);
426
427	puts("");
428
429	if (!short_form) {
430		isc_boolean_t headers = ISC_TRUE;
431		puts("------------");
432		/*		detailheader(query, msg);*/
433		detailsection(query, msg, headers, DNS_SECTION_QUESTION);
434		detailsection(query, msg, headers, DNS_SECTION_ANSWER);
435		detailsection(query, msg, headers, DNS_SECTION_AUTHORITY);
436		detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL);
437		puts("------------");
438	}
439
440	if (msg->rcode != 0) {
441		char nametext[DNS_NAME_FORMATSIZE];
442		dns_name_format(query->lookup->name,
443				nametext, sizeof(nametext));
444		printf("** server can't find %s: %s\n",
445		       nametext, rcode_totext(msg->rcode));
446		debug("returning with rcode == 0");
447
448		/* the lookup failed */
449		print_error |= 1;
450		return (ISC_R_SUCCESS);
451	}
452
453	if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
454		puts("Non-authoritative answer:");
455	if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
456		printsection(query, msg, headers, DNS_SECTION_ANSWER);
457	else
458		printf("*** Can't find %s: No answer\n",
459		       query->lookup->textname);
460
461	if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
462	    (query->lookup->rdtype != dns_rdatatype_a)) {
463		puts("\nAuthoritative answers can be found from:");
464		printsection(query, msg, headers,
465			     DNS_SECTION_AUTHORITY);
466		printsection(query, msg, headers,
467			     DNS_SECTION_ADDITIONAL);
468	}
469	return (ISC_R_SUCCESS);
470}
471
472static void
473show_settings(isc_boolean_t full, isc_boolean_t serv_only) {
474	dig_server_t *srv;
475	isc_sockaddr_t sockaddr;
476	dig_searchlist_t *listent;
477	isc_result_t result;
478
479	srv = ISC_LIST_HEAD(server_list);
480
481	while (srv != NULL) {
482		char sockstr[ISC_SOCKADDR_FORMATSIZE];
483
484		result = get_address(srv->servername, port, &sockaddr);
485		check_result(result, "get_address");
486
487		isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
488		printf("Default server: %s\nAddress: %s\n",
489			srv->userarg, sockstr);
490		if (!full)
491			return;
492		srv = ISC_LIST_NEXT(srv, link);
493	}
494	if (serv_only)
495		return;
496	printf("\nSet options:\n");
497	printf("  %s\t\t\t%s\t\t%s\n",
498	       tcpmode ? "vc" : "novc",
499	       short_form ? "nodebug" : "debug",
500	       debugging ? "d2" : "nod2");
501	printf("  %s\t\t%s\n",
502	       usesearch ? "search" : "nosearch",
503	       recurse ? "recurse" : "norecurse");
504	printf("  timeout = %d\t\tretry = %d\tport = %d\tndots = %d\n",
505	       timeout, tries, port, ndots);
506	printf("  querytype = %-8s\tclass = %s\n", deftype, defclass);
507	printf("  srchlist = ");
508	for (listent = ISC_LIST_HEAD(search_list);
509	     listent != NULL;
510	     listent = ISC_LIST_NEXT(listent, link)) {
511		     printf("%s", listent->origin);
512		     if (ISC_LIST_NEXT(listent, link) != NULL)
513			     printf("/");
514	}
515	printf("\n");
516}
517
518static isc_boolean_t
519testtype(char *typetext) {
520	isc_result_t result;
521	isc_textregion_t tr;
522	dns_rdatatype_t rdtype;
523
524	tr.base = typetext;
525	tr.length = strlen(typetext);
526	result = dns_rdatatype_fromtext(&rdtype, &tr);
527	if (result == ISC_R_SUCCESS)
528		return (ISC_TRUE);
529	else {
530		printf("unknown query type: %s\n", typetext);
531		return (ISC_FALSE);
532	}
533}
534
535static isc_boolean_t
536testclass(char *typetext) {
537	isc_result_t result;
538	isc_textregion_t tr;
539	dns_rdataclass_t rdclass;
540
541	tr.base = typetext;
542	tr.length = strlen(typetext);
543	result = dns_rdataclass_fromtext(&rdclass, &tr);
544	if (result == ISC_R_SUCCESS)
545		return (ISC_TRUE);
546	else {
547		printf("unknown query class: %s\n", typetext);
548		return (ISC_FALSE);
549	}
550}
551
552static void
553set_port(const char *value) {
554	isc_uint32_t n;
555	isc_result_t result = parse_uint(&n, value, 65535, "port");
556	if (result == ISC_R_SUCCESS)
557		port = (isc_uint16_t) n;
558}
559
560static void
561set_timeout(const char *value) {
562	isc_uint32_t n;
563	isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
564	if (result == ISC_R_SUCCESS)
565		timeout = n;
566}
567
568static void
569set_tries(const char *value) {
570	isc_uint32_t n;
571	isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
572	if (result == ISC_R_SUCCESS)
573		tries = n;
574}
575
576static void
577set_ndots(const char *value) {
578	isc_uint32_t n;
579	isc_result_t result = parse_uint(&n, value, 128, "ndots");
580	if (result == ISC_R_SUCCESS)
581		ndots = n;
582}
583
584static void
585setoption(char *opt) {
586	if (strncasecmp(opt, "all", 4) == 0) {
587		show_settings(ISC_TRUE, ISC_FALSE);
588	} else if (strncasecmp(opt, "class=", 6) == 0) {
589		if (testclass(&opt[6]))
590			strlcpy(defclass, &opt[6], sizeof(defclass));
591	} else if (strncasecmp(opt, "cl=", 3) == 0) {
592		if (testclass(&opt[3]))
593			strlcpy(defclass, &opt[3], sizeof(defclass));
594	} else if (strncasecmp(opt, "type=", 5) == 0) {
595		if (testtype(&opt[5]))
596			strlcpy(deftype, &opt[5], sizeof(deftype));
597	} else if (strncasecmp(opt, "ty=", 3) == 0) {
598		if (testtype(&opt[3]))
599			strlcpy(deftype, &opt[3], sizeof(deftype));
600	} else if (strncasecmp(opt, "querytype=", 10) == 0) {
601		if (testtype(&opt[10]))
602			strlcpy(deftype, &opt[10], sizeof(deftype));
603	} else if (strncasecmp(opt, "query=", 6) == 0) {
604		if (testtype(&opt[6]))
605			strlcpy(deftype, &opt[6], sizeof(deftype));
606	} else if (strncasecmp(opt, "qu=", 3) == 0) {
607		if (testtype(&opt[3]))
608			strlcpy(deftype, &opt[3], sizeof(deftype));
609	} else if (strncasecmp(opt, "q=", 2) == 0) {
610		if (testtype(&opt[2]))
611			strlcpy(deftype, &opt[2], sizeof(deftype));
612	} else if (strncasecmp(opt, "domain=", 7) == 0) {
613		strlcpy(domainopt, &opt[7], sizeof(domainopt));
614		set_search_domain(domainopt);
615		usesearch = ISC_TRUE;
616	} else if (strncasecmp(opt, "do=", 3) == 0) {
617		strlcpy(domainopt, &opt[3], sizeof(domainopt));
618		set_search_domain(domainopt);
619		usesearch = ISC_TRUE;
620	} else if (strncasecmp(opt, "port=", 5) == 0) {
621		set_port(&opt[5]);
622	} else if (strncasecmp(opt, "po=", 3) == 0) {
623		set_port(&opt[3]);
624	} else if (strncasecmp(opt, "timeout=", 8) == 0) {
625		set_timeout(&opt[8]);
626	} else if (strncasecmp(opt, "t=", 2) == 0) {
627		set_timeout(&opt[2]);
628	} else if (strncasecmp(opt, "rec", 3) == 0) {
629		recurse = ISC_TRUE;
630	} else if (strncasecmp(opt, "norec", 5) == 0) {
631		recurse = ISC_FALSE;
632	} else if (strncasecmp(opt, "retry=", 6) == 0) {
633		set_tries(&opt[6]);
634	} else if (strncasecmp(opt, "ret=", 4) == 0) {
635		set_tries(&opt[4]);
636	} else if (strncasecmp(opt, "def", 3) == 0) {
637		usesearch = ISC_TRUE;
638	} else if (strncasecmp(opt, "nodef", 5) == 0) {
639		usesearch = ISC_FALSE;
640	} else if (strncasecmp(opt, "vc", 3) == 0) {
641		tcpmode = ISC_TRUE;
642	} else if (strncasecmp(opt, "novc", 5) == 0) {
643		tcpmode = ISC_FALSE;
644	} else if (strncasecmp(opt, "deb", 3) == 0) {
645		short_form = ISC_FALSE;
646		showsearch = ISC_TRUE;
647	} else if (strncasecmp(opt, "nodeb", 5) == 0) {
648		short_form = ISC_TRUE;
649		showsearch = ISC_FALSE;
650	} else if (strncasecmp(opt, "d2", 2) == 0) {
651		debugging = ISC_TRUE;
652	} else if (strncasecmp(opt, "nod2", 4) == 0) {
653		debugging = ISC_FALSE;
654	} else if (strncasecmp(opt, "search", 3) == 0) {
655		usesearch = ISC_TRUE;
656	} else if (strncasecmp(opt, "nosearch", 5) == 0) {
657		usesearch = ISC_FALSE;
658	} else if (strncasecmp(opt, "sil", 3) == 0) {
659		/* deprecation_msg = ISC_FALSE; */
660	} else if (strncasecmp(opt, "fail", 3) == 0) {
661		nofail=ISC_FALSE;
662	} else if (strncasecmp(opt, "nofail", 3) == 0) {
663		nofail=ISC_TRUE;
664	} else if (strncasecmp(opt, "ndots=", 6) == 0) {
665		set_ndots(&opt[6]);
666	} else {
667		printf("*** Invalid option: %s\n", opt);
668	}
669}
670
671static void
672addlookup(char *opt) {
673	dig_lookup_t *lookup;
674	isc_result_t result;
675	isc_textregion_t tr;
676	dns_rdatatype_t rdtype;
677	dns_rdataclass_t rdclass;
678	char store[MXNAME];
679
680	debug("addlookup()");
681	tr.base = deftype;
682	tr.length = strlen(deftype);
683	result = dns_rdatatype_fromtext(&rdtype, &tr);
684	if (result != ISC_R_SUCCESS) {
685		printf("unknown query type: %s\n", deftype);
686		rdclass = dns_rdatatype_a;
687	}
688	tr.base = defclass;
689	tr.length = strlen(defclass);
690	result = dns_rdataclass_fromtext(&rdclass, &tr);
691	if (result != ISC_R_SUCCESS) {
692		printf("unknown query class: %s\n", defclass);
693		rdclass = dns_rdataclass_in;
694	}
695	lookup = make_empty_lookup();
696	if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
697	    == ISC_R_SUCCESS) {
698		strlcpy(lookup->textname, store, sizeof(lookup->textname));
699		lookup->rdtype = dns_rdatatype_ptr;
700		lookup->rdtypeset = ISC_TRUE;
701	} else {
702		strlcpy(lookup->textname, opt, sizeof(lookup->textname));
703		lookup->rdtype = rdtype;
704		lookup->rdtypeset = ISC_TRUE;
705	}
706	lookup->rdclass = rdclass;
707	lookup->rdclassset = ISC_TRUE;
708	lookup->trace = ISC_FALSE;
709	lookup->trace_root = lookup->trace;
710	lookup->ns_search_only = ISC_FALSE;
711	lookup->identify = identify;
712	lookup->recurse = recurse;
713	lookup->aaonly = aaonly;
714	lookup->retries = tries;
715	lookup->udpsize = 0;
716	lookup->comments = comments;
717	lookup->tcp_mode = tcpmode;
718	lookup->stats = stats;
719	lookup->section_question = section_question;
720	lookup->section_answer = section_answer;
721	lookup->section_authority = section_authority;
722	lookup->section_additional = section_additional;
723	lookup->new_search = ISC_TRUE;
724	if (nofail)
725		lookup->servfail_stops = ISC_FALSE;
726	ISC_LIST_INIT(lookup->q);
727	ISC_LINK_INIT(lookup, link);
728	ISC_LIST_APPEND(lookup_list, lookup, link);
729	lookup->origin = NULL;
730	ISC_LIST_INIT(lookup->my_server_list);
731	debug("looking up %s", lookup->textname);
732}
733
734static void
735do_next_command(char *input) {
736	char *ptr, *arg;
737
738	ptr = next_token(&input, " \t\r\n");
739	if (ptr == NULL)
740		return;
741	arg = next_token(&input, " \t\r\n");
742	if ((strcasecmp(ptr, "set") == 0) &&
743	    (arg != NULL))
744		setoption(arg);
745	else if ((strcasecmp(ptr, "server") == 0) ||
746		 (strcasecmp(ptr, "lserver") == 0)) {
747		isc_app_block();
748		set_nameserver(arg);
749		check_ra = ISC_FALSE;
750		isc_app_unblock();
751		show_settings(ISC_TRUE, ISC_TRUE);
752	} else if (strcasecmp(ptr, "exit") == 0) {
753		in_use = ISC_FALSE;
754	} else if (strcasecmp(ptr, "help") == 0 ||
755		   strcasecmp(ptr, "?") == 0) {
756		printf("The '%s' command is not yet implemented.\n", ptr);
757	} else if (strcasecmp(ptr, "finger") == 0 ||
758		   strcasecmp(ptr, "root") == 0 ||
759		   strcasecmp(ptr, "ls") == 0 ||
760		   strcasecmp(ptr, "view") == 0) {
761		printf("The '%s' command is not implemented.\n", ptr);
762	} else
763		addlookup(ptr);
764}
765
766static void
767get_next_command(void) {
768	char *buf;
769	char *ptr;
770
771	fflush(stdout);
772	buf = isc_mem_allocate(mctx, COMMSIZE);
773	if (buf == NULL)
774		fatal("memory allocation failure");
775	isc_app_block();
776	if (interactive) {
777#ifdef HAVE_READLINE
778		ptr = readline("> ");
779		if (ptr != NULL)
780			add_history(ptr);
781#else
782		fputs("> ", stderr);
783		fflush(stderr);
784		ptr = fgets(buf, COMMSIZE, stdin);
785#endif
786	} else
787		ptr = fgets(buf, COMMSIZE, stdin);
788	isc_app_unblock();
789	if (ptr == NULL) {
790		in_use = ISC_FALSE;
791	} else
792		do_next_command(ptr);
793#ifdef HAVE_READLINE
794	if (interactive)
795		free(ptr);
796#endif
797	isc_mem_free(mctx, buf);
798}
799
800static void
801parse_args(int argc, char **argv) {
802	isc_boolean_t have_lookup = ISC_FALSE;
803
804	usesearch = ISC_TRUE;
805	for (argc--, argv++; argc > 0; argc--, argv++) {
806		debug("main parsing %s", argv[0]);
807		if (argv[0][0] == '-') {
808			if (argv[0][1] != 0)
809				setoption(&argv[0][1]);
810			else
811				have_lookup = ISC_TRUE;
812		} else {
813			if (!have_lookup) {
814				have_lookup = ISC_TRUE;
815				in_use = ISC_TRUE;
816				addlookup(argv[0]);
817			} else {
818				set_nameserver(argv[0]);
819				check_ra = ISC_FALSE;
820			}
821		}
822	}
823}
824
825static void
826flush_lookup_list(void) {
827	dig_lookup_t *l, *lp;
828	dig_query_t *q, *qp;
829	dig_server_t *s, *sp;
830
831	lookup_counter = 0;
832	l = ISC_LIST_HEAD(lookup_list);
833	while (l != NULL) {
834		q = ISC_LIST_HEAD(l->q);
835		while (q != NULL) {
836			if (q->sock != NULL) {
837				isc_socket_cancel(q->sock, NULL,
838						  ISC_SOCKCANCEL_ALL);
839				isc_socket_detach(&q->sock);
840			}
841			if (ISC_LINK_LINKED(&q->recvbuf, link))
842				ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
843						 link);
844			if (ISC_LINK_LINKED(&q->lengthbuf, link))
845				ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
846						 link);
847			isc_buffer_invalidate(&q->recvbuf);
848			isc_buffer_invalidate(&q->lengthbuf);
849			qp = q;
850			q = ISC_LIST_NEXT(q, link);
851			ISC_LIST_DEQUEUE(l->q, qp, link);
852			isc_mem_free(mctx, qp);
853		}
854		s = ISC_LIST_HEAD(l->my_server_list);
855		while (s != NULL) {
856			sp = s;
857			s = ISC_LIST_NEXT(s, link);
858			ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
859			isc_mem_free(mctx, sp);
860
861		}
862		if (l->sendmsg != NULL)
863			dns_message_destroy(&l->sendmsg);
864		if (l->timer != NULL)
865			isc_timer_detach(&l->timer);
866		lp = l;
867		l = ISC_LIST_NEXT(l, link);
868		ISC_LIST_DEQUEUE(lookup_list, lp, link);
869		isc_mem_free(mctx, lp);
870	}
871}
872
873static void
874getinput(isc_task_t *task, isc_event_t *event) {
875	UNUSED(task);
876	if (global_event == NULL)
877		global_event = event;
878	while (in_use) {
879		get_next_command();
880		if (ISC_LIST_HEAD(lookup_list) != NULL) {
881			start_lookup();
882			return;
883		}
884	}
885	isc_app_shutdown();
886}
887
888int
889main(int argc, char **argv) {
890	isc_result_t result;
891
892	interactive = ISC_TF(isatty(0));
893
894	ISC_LIST_INIT(lookup_list);
895	ISC_LIST_INIT(server_list);
896	ISC_LIST_INIT(search_list);
897
898	check_ra = ISC_TRUE;
899
900	result = isc_app_start();
901	check_result(result, "isc_app_start");
902
903	setup_libs();
904	progname = argv[0];
905
906	parse_args(argc, argv);
907
908	setup_system();
909	if (domainopt[0] != '\0')
910		set_search_domain(domainopt);
911	if (in_use)
912		result = isc_app_onrun(mctx, global_task, onrun_callback,
913				       NULL);
914	else
915		result = isc_app_onrun(mctx, global_task, getinput, NULL);
916	check_result(result, "isc_app_onrun");
917	in_use = ISC_TF(!in_use);
918
919	(void)isc_app_run();
920
921	puts("");
922	debug("done, and starting to shut down");
923	if (global_event != NULL)
924		isc_event_free(&global_event);
925	cancel_all();
926	destroy_libs();
927	isc_app_finish();
928
929	return (query_error | print_error);
930}
931