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