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