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