1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 /*! \file */
13
14 #include <config.h>
15
16 #include <inttypes.h>
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <limits.h>
20
21 #ifdef HAVE_LOCALE_H
22 #include <locale.h>
23 #endif
24
25 #ifdef WITH_IDNKIT
26 #include <idn/result.h>
27 #include <idn/log.h>
28 #include <idn/resconf.h>
29 #include <idn/api.h>
30 #endif
31
32 #include <isc/app.h>
33 #include <isc/commandline.h>
34 #include <isc/netaddr.h>
35 #include <isc/print.h>
36 #include <isc/string.h>
37 #include <isc/util.h>
38 #include <isc/task.h>
39 #include <isc/stdlib.h>
40
41 #include <dns/byaddr.h>
42 #include <dns/fixedname.h>
43 #include <dns/message.h>
44 #include <dns/name.h>
45 #include <dns/rdata.h>
46 #include <dns/rdataclass.h>
47 #include <dns/rdataset.h>
48 #include <dns/rdatatype.h>
49 #include <dns/rdatastruct.h>
50
51 #include <dig/dig.h>
52
53 static bool short_form = true, listed_server = false;
54 static bool default_lookups = true;
55 static int seen_error = -1;
56 static bool list_addresses = true;
57 static dns_rdatatype_t list_type = dns_rdatatype_a;
58 static bool printed_server = false;
59 static bool ipv4only = false, ipv6only = false;
60
61 static const char *opcodetext[] = {
62 "QUERY",
63 "IQUERY",
64 "STATUS",
65 "RESERVED3",
66 "NOTIFY",
67 "UPDATE",
68 "RESERVED6",
69 "RESERVED7",
70 "RESERVED8",
71 "RESERVED9",
72 "RESERVED10",
73 "RESERVED11",
74 "RESERVED12",
75 "RESERVED13",
76 "RESERVED14",
77 "RESERVED15"
78 };
79
80 static const char *rcodetext[] = {
81 "NOERROR",
82 "FORMERR",
83 "SERVFAIL",
84 "NXDOMAIN",
85 "NOTIMP",
86 "REFUSED",
87 "YXDOMAIN",
88 "YXRRSET",
89 "NXRRSET",
90 "NOTAUTH",
91 "NOTZONE",
92 "RESERVED11",
93 "RESERVED12",
94 "RESERVED13",
95 "RESERVED14",
96 "RESERVED15",
97 "BADVERS"
98 };
99
100 struct rtype {
101 unsigned int type;
102 const char *text;
103 };
104
105 struct rtype rtypes[] = {
106 { 1, "has address" },
107 { 2, "name server" },
108 { 5, "is an alias for" },
109 { 11, "has well known services" },
110 { 12, "domain name pointer" },
111 { 13, "host information" },
112 { 15, "mail is handled by" },
113 { 16, "descriptive text" },
114 { 19, "x25 address" },
115 { 20, "ISDN address" },
116 { 24, "has signature" },
117 { 25, "has key" },
118 { 28, "has IPv6 address" },
119 { 29, "location" },
120 { 0, NULL }
121 };
122
123 static char *
rcode_totext(dns_rcode_t rcode)124 rcode_totext(dns_rcode_t rcode)
125 {
126 static char buf[sizeof("?65535")];
127 union {
128 const char *consttext;
129 char *deconsttext;
130 } totext;
131
132 if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
133 snprintf(buf, sizeof(buf), "?%u", rcode);
134 totext.deconsttext = buf;
135 } else
136 totext.consttext = rcodetext[rcode];
137 return totext.deconsttext;
138 }
139
140 ISC_PLATFORM_NORETURN_PRE static void
141 show_usage(void) ISC_PLATFORM_NORETURN_POST;
142
143 static void
show_usage(void)144 show_usage(void) {
145 fputs(
146 "Usage: host [-aCdilrTvVw] [-c class] [-N ndots] [-t type] [-W time]\n"
147 " [-R number] [-m flag] hostname [server]\n"
148 " -a is equivalent to -v -t ANY\n"
149 " -c specifies query class for non-IN data\n"
150 " -C compares SOA records on authoritative nameservers\n"
151 " -d is equivalent to -v\n"
152 " -i IP6.INT reverse lookups\n"
153 " -l lists all hosts in a domain, using AXFR\n"
154 " -m set memory debugging flag (trace|record|usage)\n"
155 " -N changes the number of dots allowed before root lookup is done\n"
156 " -p specifies the port on the server to query\n"
157 " -r disables recursive processing\n"
158 " -R specifies number of retries for UDP packets\n"
159 " -s a SERVFAIL response should stop query\n"
160 " -t specifies the query type\n"
161 " -T enables TCP/IP mode\n"
162 " -U enables UDP mode\n"
163 " -v enables verbose output\n"
164 " -V print version number and exit\n"
165 " -w specifies to wait forever for a reply\n"
166 " -W specifies how long to wait for a reply\n"
167 " -4 use IPv4 query transport only\n"
168 " -6 use IPv6 query transport only\n", stderr);
169 exit(1);
170 }
171
172 static void
host_shutdown(void)173 host_shutdown(void) {
174 (void) isc_app_shutdown();
175 }
176
177 static void
received(unsigned int bytes,isc_sockaddr_t * from,dig_query_t * query)178 received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
179 isc_time_t now;
180 int diff;
181
182 if (!short_form) {
183 char fromtext[ISC_SOCKADDR_FORMATSIZE];
184 isc_sockaddr_format(from, fromtext, sizeof(fromtext));
185 TIME_NOW(&now);
186 diff = (int) isc_time_microdiff(&now, &query->time_sent);
187 printf("Received %u bytes from %s in %d ms\n",
188 bytes, fromtext, diff/1000);
189 }
190 }
191
192 static void
trying(char * frm,dig_lookup_t * lookup)193 trying(char *frm, dig_lookup_t *lookup) {
194 UNUSED(lookup);
195
196 if (!short_form)
197 printf("Trying \"%s\"\n", frm);
198 }
199
200 static void
say_message(dns_name_t * name,const char * msg,dns_rdata_t * rdata,dig_query_t * query)201 say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
202 dig_query_t *query)
203 {
204 isc_buffer_t *b = NULL;
205 char namestr[DNS_NAME_FORMATSIZE];
206 isc_region_t r;
207 isc_result_t result;
208 unsigned int bufsize = BUFSIZ;
209
210 dns_name_format(name, namestr, sizeof(namestr));
211 retry:
212 result = isc_buffer_allocate(mctx, &b, bufsize);
213 check_result(result, "isc_buffer_allocate");
214 result = dns_rdata_totext(rdata, NULL, b);
215 if (result == ISC_R_NOSPACE) {
216 isc_buffer_free(&b);
217 bufsize *= 2;
218 goto retry;
219 }
220 check_result(result, "dns_rdata_totext");
221 isc_buffer_usedregion(b, &r);
222 if (query->lookup->identify_previous_line) {
223 printf("Nameserver %s:\n\t",
224 query->servname);
225 }
226 printf("%s %s %.*s", namestr,
227 msg, (int)r.length, (char *)r.base);
228 if (query->lookup->identify) {
229 printf(" on server %s", query->servname);
230 }
231 printf("\n");
232 isc_buffer_free(&b);
233 }
234 #ifdef DIG_SIGCHASE
235 /* Just for compatibility : not use in host program */
236 static isc_result_t
printrdataset(dns_name_t * owner_name,dns_rdataset_t * rdataset,isc_buffer_t * target)237 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
238 isc_buffer_t *target)
239 {
240 UNUSED(owner_name);
241 UNUSED(rdataset);
242 UNUSED(target);
243 return(false);
244 }
245 #endif
246 static isc_result_t
printsection(dns_message_t * msg,dns_section_t sectionid,const char * section_name,bool headers,dig_query_t * query)247 printsection(dns_message_t *msg, dns_section_t sectionid,
248 const char *section_name, bool headers,
249 dig_query_t *query)
250 {
251 dns_name_t *name, *print_name;
252 dns_rdataset_t *rdataset;
253 dns_rdata_t rdata = DNS_RDATA_INIT;
254 isc_buffer_t target;
255 isc_result_t result, loopresult;
256 isc_region_t r;
257 dns_name_t empty_name;
258 char tbuf[4096];
259 bool first;
260 bool no_rdata;
261
262 if (sectionid == DNS_SECTION_QUESTION)
263 no_rdata = true;
264 else
265 no_rdata = false;
266
267 if (headers)
268 printf(";; %s SECTION:\n", section_name);
269
270 dns_name_init(&empty_name, NULL);
271
272 result = dns_message_firstname(msg, sectionid);
273 if (result == ISC_R_NOMORE)
274 return (ISC_R_SUCCESS);
275 else if (result != ISC_R_SUCCESS)
276 return (result);
277
278 for (;;) {
279 name = NULL;
280 dns_message_currentname(msg, sectionid, &name);
281
282 isc_buffer_init(&target, tbuf, sizeof(tbuf));
283 first = true;
284 print_name = name;
285
286 for (rdataset = ISC_LIST_HEAD(name->list);
287 rdataset != NULL;
288 rdataset = ISC_LIST_NEXT(rdataset, link)) {
289 if (query->lookup->rdtype == dns_rdatatype_axfr &&
290 !((!list_addresses &&
291 (list_type == dns_rdatatype_any ||
292 rdataset->type == list_type)) ||
293 (list_addresses &&
294 (rdataset->type == dns_rdatatype_a ||
295 rdataset->type == dns_rdatatype_aaaa ||
296 rdataset->type == dns_rdatatype_ns ||
297 rdataset->type == dns_rdatatype_ptr))))
298 continue;
299 if (!short_form) {
300 result = dns_rdataset_totext(rdataset,
301 print_name,
302 false,
303 no_rdata,
304 &target);
305 if (result != ISC_R_SUCCESS)
306 return (result);
307 #ifdef USEINITALWS
308 if (first) {
309 print_name = &empty_name;
310 first = false;
311 }
312 #else
313 UNUSED(first); /* Shut up compiler. */
314 #endif
315 } else {
316 loopresult = dns_rdataset_first(rdataset);
317 while (loopresult == ISC_R_SUCCESS) {
318 struct rtype *t;
319 const char *rtt;
320 char typebuf[DNS_RDATATYPE_FORMATSIZE];
321 char typebuf2[DNS_RDATATYPE_FORMATSIZE
322 + 20];
323 dns_rdataset_current(rdataset, &rdata);
324
325 for (t = rtypes; t->text != NULL; t++) {
326 if (t->type == rdata.type) {
327 rtt = t->text;
328 goto found;
329 }
330 }
331
332 dns_rdatatype_format(rdata.type,
333 typebuf,
334 sizeof(typebuf));
335 snprintf(typebuf2, sizeof(typebuf2),
336 "has %s record", typebuf);
337 rtt = typebuf2;
338 found:
339 say_message(print_name, rtt,
340 &rdata, query);
341 dns_rdata_reset(&rdata);
342 loopresult =
343 dns_rdataset_next(rdataset);
344 }
345 }
346 }
347 if (!short_form) {
348 isc_buffer_usedregion(&target, &r);
349 if (no_rdata)
350 printf(";%.*s", (int)r.length,
351 (char *)r.base);
352 else
353 printf("%.*s", (int)r.length, (char *)r.base);
354 }
355
356 result = dns_message_nextname(msg, sectionid);
357 if (result == ISC_R_NOMORE)
358 break;
359 else if (result != ISC_R_SUCCESS)
360 return (result);
361 }
362
363 return (ISC_R_SUCCESS);
364 }
365
366 static isc_result_t
printrdata(dns_message_t * msg,dns_rdataset_t * rdataset,dns_name_t * owner,const char * set_name,bool headers)367 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
368 const char *set_name, bool headers)
369 {
370 isc_buffer_t target;
371 isc_result_t result;
372 isc_region_t r;
373 char tbuf[4096];
374
375 UNUSED(msg);
376 if (headers)
377 printf(";; %s SECTION:\n", set_name);
378
379 isc_buffer_init(&target, tbuf, sizeof(tbuf));
380
381 result = dns_rdataset_totext(rdataset, owner, false, false,
382 &target);
383 if (result != ISC_R_SUCCESS)
384 return (result);
385 isc_buffer_usedregion(&target, &r);
386 printf("%.*s", (int)r.length, (char *)r.base);
387
388 return (ISC_R_SUCCESS);
389 }
390
391 static void
chase_cnamechain(dns_message_t * msg,dns_name_t * qname)392 chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
393 isc_result_t result;
394 dns_rdataset_t *rdataset;
395 dns_rdata_cname_t cname;
396 dns_rdata_t rdata = DNS_RDATA_INIT;
397 unsigned int i = msg->counts[DNS_SECTION_ANSWER];
398
399 while (i-- > 0) {
400 rdataset = NULL;
401 result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
402 dns_rdatatype_cname, 0, NULL,
403 &rdataset);
404 if (result != ISC_R_SUCCESS)
405 return;
406 result = dns_rdataset_first(rdataset);
407 check_result(result, "dns_rdataset_first");
408 dns_rdata_reset(&rdata);
409 dns_rdataset_current(rdataset, &rdata);
410 result = dns_rdata_tostruct(&rdata, &cname, NULL);
411 check_result(result, "dns_rdata_tostruct");
412 dns_name_copy(&cname.cname, qname, NULL);
413 dns_rdata_freestruct(&cname);
414 }
415 }
416
417 static isc_result_t
printmessage(dig_query_t * query,dns_message_t * msg,bool headers)418 printmessage(dig_query_t *query, dns_message_t *msg, bool headers) {
419 bool did_flag = false;
420 dns_rdataset_t *opt, *tsig = NULL;
421 dns_name_t *tsigname;
422 isc_result_t result = ISC_R_SUCCESS;
423 int force_error;
424
425 UNUSED(headers);
426
427 /*
428 * We get called multiple times.
429 * Preserve any existing error status.
430 */
431 force_error = (seen_error == 1) ? 1 : 0;
432 seen_error = 1;
433 if (listed_server && !printed_server) {
434 char sockstr[ISC_SOCKADDR_FORMATSIZE];
435
436 printf("Using domain server:\n");
437 printf("Name: %s\n", query->userarg);
438 isc_sockaddr_format(&query->sockaddr, sockstr,
439 sizeof(sockstr));
440 printf("Address: %s\n", sockstr);
441 printf("Aliases: \n\n");
442 printed_server = true;
443 }
444
445 if (msg->rcode != 0) {
446 char namestr[DNS_NAME_FORMATSIZE];
447 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
448
449 if (query->lookup->identify_previous_line)
450 printf("Nameserver %s:\n\t%s not found: %d(%s)\n",
451 query->servname,
452 (msg->rcode != dns_rcode_nxdomain) ? namestr :
453 query->lookup->textname, msg->rcode,
454 rcode_totext(msg->rcode));
455 else
456 printf("Host %s not found: %d(%s)\n",
457 (msg->rcode != dns_rcode_nxdomain) ? namestr :
458 query->lookup->textname, msg->rcode,
459 rcode_totext(msg->rcode));
460 return (ISC_R_SUCCESS);
461 }
462
463 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
464 char namestr[DNS_NAME_FORMATSIZE];
465 dig_lookup_t *lookup;
466 dns_fixedname_t fixed;
467 dns_name_t *name;
468
469 /* Add AAAA and MX lookups. */
470 name = dns_fixedname_initname(&fixed);
471 dns_name_copy(query->lookup->name, name, NULL);
472 chase_cnamechain(msg, name);
473 dns_name_format(name, namestr, sizeof(namestr));
474 lookup = clone_lookup(query->lookup, false);
475 if (lookup != NULL) {
476 strlcpy(lookup->textname, namestr,
477 sizeof(lookup->textname));
478 lookup->rdtype = dns_rdatatype_aaaa;
479 lookup->rdtypeset = true;
480 lookup->origin = NULL;
481 lookup->retries = tries;
482 ISC_LIST_APPEND(lookup_list, lookup, link);
483 }
484 lookup = clone_lookup(query->lookup, false);
485 if (lookup != NULL) {
486 strlcpy(lookup->textname, namestr,
487 sizeof(lookup->textname));
488 lookup->rdtype = dns_rdatatype_mx;
489 lookup->rdtypeset = true;
490 lookup->origin = NULL;
491 lookup->retries = tries;
492 ISC_LIST_APPEND(lookup_list, lookup, link);
493 }
494 }
495
496 if (!short_form) {
497 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
498 opcodetext[msg->opcode], rcode_totext(msg->rcode),
499 msg->id);
500 printf(";; flags: ");
501 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
502 printf("qr");
503 did_flag = true;
504 }
505 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
506 printf("%saa", did_flag ? " " : "");
507 did_flag = true;
508 }
509 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
510 printf("%stc", did_flag ? " " : "");
511 did_flag = true;
512 }
513 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
514 printf("%srd", did_flag ? " " : "");
515 did_flag = true;
516 }
517 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
518 printf("%sra", did_flag ? " " : "");
519 did_flag = true;
520 }
521 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
522 printf("%sad", did_flag ? " " : "");
523 did_flag = true;
524 }
525 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
526 printf("%scd", did_flag ? " " : "");
527 did_flag = true;
528 POST(did_flag);
529 }
530 printf("; QUERY: %u, ANSWER: %u, "
531 "AUTHORITY: %u, ADDITIONAL: %u\n",
532 msg->counts[DNS_SECTION_QUESTION],
533 msg->counts[DNS_SECTION_ANSWER],
534 msg->counts[DNS_SECTION_AUTHORITY],
535 msg->counts[DNS_SECTION_ADDITIONAL]);
536 opt = dns_message_getopt(msg);
537 if (opt != NULL)
538 printf(";; EDNS: version: %u, udp=%u\n",
539 (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
540 (unsigned int)opt->rdclass);
541 tsigname = NULL;
542 tsig = dns_message_gettsig(msg, &tsigname);
543 if (tsig != NULL)
544 printf(";; PSEUDOSECTIONS: TSIG\n");
545 }
546 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
547 !short_form) {
548 printf("\n");
549 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
550 true, query);
551 if (result != ISC_R_SUCCESS)
552 return (result);
553 }
554 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
555 if (!short_form)
556 printf("\n");
557 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
558 !short_form, query);
559 if (result != ISC_R_SUCCESS)
560 return (result);
561 }
562
563 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
564 !short_form) {
565 printf("\n");
566 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
567 true, query);
568 if (result != ISC_R_SUCCESS)
569 return (result);
570 }
571 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
572 !short_form) {
573 printf("\n");
574 result = printsection(msg, DNS_SECTION_ADDITIONAL,
575 "ADDITIONAL", true, query);
576 if (result != ISC_R_SUCCESS)
577 return (result);
578 }
579 if ((tsig != NULL) && !short_form) {
580 printf("\n");
581 result = printrdata(msg, tsig, tsigname,
582 "PSEUDOSECTION TSIG", true);
583 if (result != ISC_R_SUCCESS)
584 return (result);
585 }
586 if (!short_form)
587 printf("\n");
588
589 if (short_form && !default_lookups &&
590 ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
591 char namestr[DNS_NAME_FORMATSIZE];
592 char typestr[DNS_RDATATYPE_FORMATSIZE];
593 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
594 dns_rdatatype_format(query->lookup->rdtype, typestr,
595 sizeof(typestr));
596 printf("%s has no %s record\n", namestr, typestr);
597 }
598 seen_error = force_error;
599 return (result);
600 }
601
602 static const char * optstring = "46ac:dilnm:p:rst:vVwCDN:R:TUW:";
603
604 /*% version */
605 static void
version(void)606 version(void) {
607 fputs("host " VERSION "\n", stderr);
608 }
609
610 static void
pre_parse_args(int argc,char ** argv)611 pre_parse_args(int argc, char **argv) {
612 int c;
613
614 while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) {
615 switch (c) {
616 case 'm':
617 memdebugging = true;
618 if (strcasecmp("trace", isc_commandline_argument) == 0)
619 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
620 else if (strcasecmp("record",
621 isc_commandline_argument) == 0)
622 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
623 else if (strcasecmp("usage",
624 isc_commandline_argument) == 0)
625 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
626 break;
627
628 case '4':
629 if (ipv6only)
630 fatal("only one of -4 and -6 allowed");
631 ipv4only = true;
632 break;
633 case '6':
634 if (ipv4only)
635 fatal("only one of -4 and -6 allowed");
636 ipv6only = true;
637 break;
638 case 'a': break;
639 case 'c': break;
640 case 'C': break;
641 case 'd': break;
642 case 'D':
643 if (debugging)
644 debugtiming = true;
645 debugging = true;
646 break;
647 case 'i': break;
648 case 'l': break;
649 case 'n': break;
650 case 'N': break;
651 case 'p': break;
652 case 'r': break;
653 case 'R': break;
654 case 's': break;
655 case 't': break;
656 case 'T': break;
657 case 'U': break;
658 case 'v': break;
659 case 'V':
660 version();
661 exit(0);
662 break;
663 case 'w': break;
664 case 'W': break;
665 default:
666 show_usage();
667 }
668 }
669 isc_commandline_reset = true;
670 isc_commandline_index = 1;
671 }
672
673 static void
parse_args(bool is_batchfile,int argc,char ** argv)674 parse_args(bool is_batchfile, int argc, char **argv) {
675 char hostname[MXNAME];
676 dig_lookup_t *lookup;
677 int c;
678 char store[MXNAME];
679 isc_textregion_t tr;
680 isc_result_t result = ISC_R_SUCCESS;
681 dns_rdatatype_t rdtype;
682 dns_rdataclass_t rdclass;
683 uint32_t serial = 0;
684
685 UNUSED(is_batchfile);
686
687 lookup = make_empty_lookup();
688
689 lookup->servfail_stops = false;
690 lookup->besteffort = false;
691 lookup->comments = false;
692 short_form = !verbose;
693
694 while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) {
695 switch (c) {
696 case 'l':
697 lookup->tcp_mode = true;
698 lookup->rdtype = dns_rdatatype_axfr;
699 lookup->rdtypeset = true;
700 fatalexit = 3;
701 break;
702 case 'v':
703 case 'd':
704 short_form = false;
705 break;
706 case 'r':
707 lookup->recurse = false;
708 break;
709 case 't':
710 if (strncasecmp(isc_commandline_argument,
711 "ixfr=", 5) == 0) {
712 rdtype = dns_rdatatype_ixfr;
713 /* XXXMPA add error checking */
714 serial = strtoul(isc_commandline_argument + 5,
715 NULL, 10);
716 result = ISC_R_SUCCESS;
717 } else {
718 tr.base = isc_commandline_argument;
719 tr.length = strlen(isc_commandline_argument);
720 result = dns_rdatatype_fromtext(&rdtype,
721 (isc_textregion_t *)&tr);
722 }
723
724 if (result != ISC_R_SUCCESS) {
725 fatalexit = 2;
726 fatal("invalid type: %s\n",
727 isc_commandline_argument);
728 }
729 if (!lookup->rdtypeset ||
730 lookup->rdtype != dns_rdatatype_axfr)
731 lookup->rdtype = rdtype;
732 lookup->rdtypeset = true;
733 #ifdef WITH_IDNKIT
734 idnoptions = 0;
735 #endif
736 if (rdtype == dns_rdatatype_axfr) {
737 /* -l -t any -v */
738 list_type = dns_rdatatype_any;
739 short_form = false;
740 lookup->tcp_mode = true;
741 } else if (rdtype == dns_rdatatype_ixfr) {
742 lookup->ixfr_serial = serial;
743 lookup->tcp_mode = true;
744 list_type = rdtype;
745 } else if (rdtype == dns_rdatatype_any) {
746 if (!lookup->tcp_mode_set)
747 lookup->tcp_mode = true;
748 #ifdef WITH_IDNKIT
749 } else if (rdtype == dns_rdatatype_a ||
750 rdtype == dns_rdatatype_aaaa ||
751 rdtype == dns_rdatatype_mx) {
752 idnoptions = IDN_ASCCHECK;
753 list_type = rdtype;
754 #endif
755 } else
756 list_type = rdtype;
757 list_addresses = false;
758 default_lookups = false;
759 break;
760 case 'c':
761 tr.base = isc_commandline_argument;
762 tr.length = strlen(isc_commandline_argument);
763 result = dns_rdataclass_fromtext(&rdclass,
764 (isc_textregion_t *)&tr);
765
766 if (result != ISC_R_SUCCESS) {
767 fatalexit = 2;
768 fatal("invalid class: %s\n",
769 isc_commandline_argument);
770 } else {
771 lookup->rdclass = rdclass;
772 lookup->rdclassset = true;
773 }
774 default_lookups = false;
775 break;
776 case 'a':
777 if (!lookup->rdtypeset ||
778 lookup->rdtype != dns_rdatatype_axfr)
779 lookup->rdtype = dns_rdatatype_any;
780 #ifdef WITH_IDNKIT
781 idnoptions = 0;
782 #endif
783 list_type = dns_rdatatype_any;
784 list_addresses = false;
785 lookup->rdtypeset = true;
786 short_form = false;
787 default_lookups = false;
788 break;
789 case 'i':
790 lookup->ip6_int = true;
791 break;
792 case 'n':
793 /* deprecated */
794 break;
795 case 'm':
796 /* Handled by pre_parse_args(). */
797 break;
798 case 'w':
799 /*
800 * The timer routines are coded such that
801 * timeout==MAXINT doesn't enable the timer
802 */
803 timeout = INT_MAX;
804 break;
805 case 'W':
806 timeout = atoi(isc_commandline_argument);
807 if (timeout < 1)
808 timeout = 1;
809 break;
810 case 'R':
811 tries = atoi(isc_commandline_argument) + 1;
812 if (tries < 2)
813 tries = 2;
814 break;
815 case 'T':
816 lookup->tcp_mode = true;
817 lookup->tcp_mode_set = true;
818 break;
819 case 'U':
820 lookup->tcp_mode = false;
821 lookup->tcp_mode_set = true;
822 break;
823 case 'C':
824 debug("showing all SOAs");
825 lookup->rdtype = dns_rdatatype_ns;
826 lookup->rdtypeset = true;
827 lookup->rdclass = dns_rdataclass_in;
828 lookup->rdclassset = true;
829 lookup->ns_search_only = true;
830 lookup->trace_root = true;
831 lookup->identify_previous_line = true;
832 default_lookups = false;
833 break;
834 case 'N':
835 debug("setting NDOTS to %s",
836 isc_commandline_argument);
837 ndots = atoi(isc_commandline_argument);
838 break;
839 case 'D':
840 /* Handled by pre_parse_args(). */
841 break;
842 case '4':
843 /* Handled by pre_parse_args(). */
844 break;
845 case '6':
846 /* Handled by pre_parse_args(). */
847 break;
848 case 's':
849 lookup->servfail_stops = true;
850 break;
851 case 'p':
852 port = atoi(isc_commandline_argument);
853 break;
854 }
855 }
856
857 lookup->retries = tries;
858
859 if (isc_commandline_index >= argc)
860 show_usage();
861
862 strlcpy(hostname, argv[isc_commandline_index], sizeof(hostname));
863
864 if (argc > isc_commandline_index + 1) {
865 set_nameserver(argv[isc_commandline_index+1]);
866 debug("server is %s", argv[isc_commandline_index+1]);
867 listed_server = true;
868 } else
869 check_ra = true;
870
871 lookup->pending = false;
872 if (get_reverse(store, sizeof(store), hostname,
873 lookup->ip6_int, true) == ISC_R_SUCCESS) {
874 strlcpy(lookup->textname, store, sizeof(lookup->textname));
875 lookup->rdtype = dns_rdatatype_ptr;
876 lookup->rdtypeset = true;
877 default_lookups = false;
878 } else {
879 strlcpy(lookup->textname, hostname, sizeof(lookup->textname));
880 usesearch = true;
881 }
882 lookup->new_search = true;
883 ISC_LIST_APPEND(lookup_list, lookup, link);
884 }
885
886 int
main(int argc,char ** argv)887 main(int argc, char **argv) {
888 isc_result_t result;
889
890 tries = 2;
891
892 ISC_LIST_INIT(lookup_list);
893 ISC_LIST_INIT(server_list);
894 ISC_LIST_INIT(search_list);
895
896 fatalexit = 1;
897 #ifdef WITH_IDNKIT
898 idnoptions = IDN_ASCCHECK;
899 #endif
900
901 /* setup dighost callbacks */
902 #ifdef DIG_SIGCHASE
903 dighost_printrdataset = printrdataset;
904 #endif
905 dighost_printmessage = printmessage;
906 dighost_received = received;
907 dighost_trying = trying;
908 dighost_shutdown = host_shutdown;
909
910 debug("main()");
911 progname = argv[0];
912 pre_parse_args(argc, argv);
913 result = isc_app_start();
914 check_result(result, "isc_app_start");
915 setup_libs();
916 setup_system(ipv4only, ipv6only);
917 parse_args(false, argc, argv);
918 if (keyfile[0] != 0)
919 setup_file_key();
920 else if (keysecret[0] != 0)
921 setup_text_key();
922 result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
923 check_result(result, "isc_app_onrun");
924 isc_app_run();
925 cancel_all();
926 destroy_libs();
927 isc_app_finish();
928 return ((seen_error == 0) ? 0 : 1);
929 }
930