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