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