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