2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: host.c,v 1.76.2.5.2.16 2006/05/23 04:43:47 marka Exp $ */
24 #include <isc/commandline.h>
25 #include <isc/netaddr.h>
26 #include <isc/print.h>
27 #include <isc/string.h>
30 #include <isc/stdlib.h>
32 #include <dns/byaddr.h>
33 #include <dns/fixedname.h>
34 #include <dns/message.h>
36 #include <dns/rdata.h>
37 #include <dns/rdataclass.h>
38 #include <dns/rdataset.h>
39 #include <dns/rdatatype.h>
40 #include <dns/rdatastruct.h>
44 static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE;
45 static isc_boolean_t default_lookups = ISC_TRUE;
46 static int seen_error = -1;
47 static isc_boolean_t list_addresses = ISC_TRUE;
48 static dns_rdatatype_t list_type = dns_rdatatype_a;
49 static isc_boolean_t printed_server = ISC_FALSE;
51 static const char *opcodetext[] = {
70 static const char *rcodetext[] = {
95 struct rtype rtypes[] = {
98 { 5, "is an alias for" },
99 { 11, "has well known services" },
100 { 12, "domain name pointer" },
101 { 13, "host information" },
102 { 15, "mail is handled by" },
103 { 16, "descriptive text" },
104 { 19, "x25 address" },
105 { 20, "ISDN address" },
106 { 24, "has signature" },
108 { 28, "has IPv6 address" },
116 "Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]\n"
117 " [-R number] hostname [server]\n"
118 " -a is equivalent to -v -t *\n"
119 " -c specifies query class for non-IN data\n"
120 " -C compares SOA records on authoritative nameservers\n"
121 " -d is equivalent to -v\n"
122 " -l lists all hosts in a domain, using AXFR\n"
123 " -i IP6.INT reverse lookups\n"
124 " -N changes the number of dots allowed before root lookup is done\n"
125 " -r disables recursive processing\n"
126 " -R specifies number of retries for UDP packets\n"
127 " -t specifies the query type\n"
128 " -T enables TCP/IP mode\n"
129 " -v enables verbose output\n"
130 " -w specifies to wait forever for a reply\n"
131 " -W specifies how long to wait for a reply\n"
132 " -4 use IPv4 query transport only\n"
133 " -6 use IPv6 query transport only\n", stderr);
138 dighost_shutdown(void) {
143 received(int bytes, isc_sockaddr_t *from, dig_query_t *query) {
148 char fromtext[ISC_SOCKADDR_FORMATSIZE];
149 isc_sockaddr_format(from, fromtext, sizeof(fromtext));
151 diff = (int) isc_time_microdiff(&now, &query->time_sent);
152 printf("Received %u bytes from %s in %d ms\n",
153 bytes, fromtext, diff/1000);
158 trying(char *frm, dig_lookup_t *lookup) {
162 printf("Trying \"%s\"\n", frm);
166 say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
169 isc_buffer_t *b = NULL;
170 char namestr[DNS_NAME_FORMATSIZE];
173 unsigned int bufsize = BUFSIZ;
175 dns_name_format(name, namestr, sizeof(namestr));
177 result = isc_buffer_allocate(mctx, &b, bufsize);
178 check_result(result, "isc_buffer_allocate");
179 result = dns_rdata_totext(rdata, NULL, b);
180 if (result == ISC_R_NOSPACE) {
185 check_result(result, "dns_rdata_totext");
186 isc_buffer_usedregion(b, &r);
187 if (query->lookup->identify_previous_line) {
188 printf("Nameserver %s:\n\t",
191 printf("%s %s %.*s", namestr,
192 msg, (int)r.length, (char *)r.base);
193 if (query->lookup->identify) {
194 printf(" on server %s", query->servname);
200 /* Just for compatibility : not use in host program */
202 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
203 isc_buffer_t *target)
212 printsection(dns_message_t *msg, dns_section_t sectionid,
213 const char *section_name, isc_boolean_t headers,
216 dns_name_t *name, *print_name;
217 dns_rdataset_t *rdataset;
218 dns_rdata_t rdata = DNS_RDATA_INIT;
220 isc_result_t result, loopresult;
222 dns_name_t empty_name;
225 isc_boolean_t no_rdata;
227 if (sectionid == DNS_SECTION_QUESTION)
230 no_rdata = ISC_FALSE;
233 printf(";; %s SECTION:\n", section_name);
235 dns_name_init(&empty_name, NULL);
237 result = dns_message_firstname(msg, sectionid);
238 if (result == ISC_R_NOMORE)
239 return (ISC_R_SUCCESS);
240 else if (result != ISC_R_SUCCESS)
245 dns_message_currentname(msg, sectionid, &name);
247 isc_buffer_init(&target, t, sizeof(t));
251 for (rdataset = ISC_LIST_HEAD(name->list);
253 rdataset = ISC_LIST_NEXT(rdataset, link)) {
254 if (query->lookup->rdtype == dns_rdatatype_axfr &&
255 !((!list_addresses &&
256 (list_type == dns_rdatatype_any ||
257 rdataset->type == list_type)) ||
259 (rdataset->type == dns_rdatatype_a ||
260 rdataset->type == dns_rdatatype_aaaa ||
261 rdataset->type == dns_rdatatype_ns ||
262 rdataset->type == dns_rdatatype_ptr))))
265 result = dns_rdataset_totext(rdataset,
270 if (result != ISC_R_SUCCESS)
274 print_name = &empty_name;
278 UNUSED(first); /* Shut up compiler. */
281 loopresult = dns_rdataset_first(rdataset);
282 while (loopresult == ISC_R_SUCCESS) {
285 char typebuf[DNS_RDATATYPE_FORMATSIZE];
286 char typebuf2[DNS_RDATATYPE_FORMATSIZE
288 dns_rdataset_current(rdataset, &rdata);
290 for (t = rtypes; t->text != NULL; t++) {
291 if (t->type == rdata.type) {
297 dns_rdatatype_format(rdata.type,
300 snprintf(typebuf2, sizeof(typebuf2),
301 "has %s record", typebuf);
304 say_message(print_name, rtt,
306 dns_rdata_reset(&rdata);
308 dns_rdataset_next(rdataset);
313 isc_buffer_usedregion(&target, &r);
315 printf(";%.*s", (int)r.length,
318 printf("%.*s", (int)r.length, (char *)r.base);
321 result = dns_message_nextname(msg, sectionid);
322 if (result == ISC_R_NOMORE)
324 else if (result != ISC_R_SUCCESS)
328 return (ISC_R_SUCCESS);
332 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
333 const char *set_name, isc_boolean_t headers)
342 printf(";; %s SECTION:\n", set_name);
344 isc_buffer_init(&target, t, sizeof(t));
346 result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
348 if (result != ISC_R_SUCCESS)
350 isc_buffer_usedregion(&target, &r);
351 printf("%.*s", (int)r.length, (char *)r.base);
353 return (ISC_R_SUCCESS);
357 chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
359 dns_rdataset_t *rdataset;
360 dns_rdata_cname_t cname;
361 dns_rdata_t rdata = DNS_RDATA_INIT;
362 unsigned int i = msg->counts[DNS_SECTION_ANSWER];
366 result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
367 dns_rdatatype_cname, 0, NULL,
369 if (result != ISC_R_SUCCESS)
371 result = dns_rdataset_first(rdataset);
372 check_result(result, "dns_rdataset_first");
373 dns_rdata_reset(&rdata);
374 dns_rdataset_current(rdataset, &rdata);
375 result = dns_rdata_tostruct(&rdata, &cname, NULL);
376 check_result(result, "dns_rdata_tostruct");
377 dns_name_copy(&cname.cname, qname, NULL);
378 dns_rdata_freestruct(&cname);
383 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
384 isc_boolean_t did_flag = ISC_FALSE;
385 dns_rdataset_t *opt, *tsig = NULL;
386 dns_name_t *tsigname;
387 isc_result_t result = ISC_R_SUCCESS;
393 * We get called multiple times.
394 * Preserve any existing error status.
396 force_error = (seen_error == 1) ? 1 : 0;
398 if (listed_server && !printed_server) {
399 char sockstr[ISC_SOCKADDR_FORMATSIZE];
401 printf("Using domain server:\n");
402 printf("Name: %s\n", query->userarg);
403 isc_sockaddr_format(&query->sockaddr, sockstr,
405 printf("Address: %s\n", sockstr);
406 printf("Aliases: \n\n");
407 printed_server = ISC_TRUE;
410 if (msg->rcode != 0) {
411 char namestr[DNS_NAME_FORMATSIZE];
412 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
413 printf("Host %s not found: %d(%s)\n", namestr,
414 msg->rcode, rcodetext[msg->rcode]);
415 return (ISC_R_SUCCESS);
418 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
419 char namestr[DNS_NAME_FORMATSIZE];
420 dig_lookup_t *lookup;
421 dns_fixedname_t fixed;
424 /* Add AAAA and MX lookups. */
425 dns_fixedname_init(&fixed);
426 name = dns_fixedname_name(&fixed);
427 dns_name_copy(query->lookup->name, name, NULL);
428 chase_cnamechain(msg, name);
429 dns_name_format(name, namestr, sizeof(namestr));
430 lookup = clone_lookup(query->lookup, ISC_FALSE);
431 if (lookup != NULL) {
432 strncpy(lookup->textname, namestr,
433 sizeof(lookup->textname));
434 lookup->textname[sizeof(lookup->textname)-1] = 0;
435 lookup->rdtype = dns_rdatatype_aaaa;
436 lookup->rdtypeset = ISC_TRUE;
437 lookup->origin = NULL;
438 lookup->retries = tries;
439 ISC_LIST_APPEND(lookup_list, lookup, link);
441 lookup = clone_lookup(query->lookup, ISC_FALSE);
442 if (lookup != NULL) {
443 strncpy(lookup->textname, namestr,
444 sizeof(lookup->textname));
445 lookup->textname[sizeof(lookup->textname)-1] = 0;
446 lookup->rdtype = dns_rdatatype_mx;
447 lookup->rdtypeset = ISC_TRUE;
448 lookup->origin = NULL;
449 lookup->retries = tries;
450 ISC_LIST_APPEND(lookup_list, lookup, link);
455 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
456 opcodetext[msg->opcode], rcodetext[msg->rcode],
458 printf(";; flags: ");
459 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
463 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
464 printf("%saa", did_flag ? " " : "");
467 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
468 printf("%stc", did_flag ? " " : "");
471 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
472 printf("%srd", did_flag ? " " : "");
475 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
476 printf("%sra", did_flag ? " " : "");
479 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
480 printf("%sad", did_flag ? " " : "");
483 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
484 printf("%scd", did_flag ? " " : "");
487 printf("; QUERY: %u, ANSWER: %u, "
488 "AUTHORITY: %u, ADDITIONAL: %u\n",
489 msg->counts[DNS_SECTION_QUESTION],
490 msg->counts[DNS_SECTION_ANSWER],
491 msg->counts[DNS_SECTION_AUTHORITY],
492 msg->counts[DNS_SECTION_ADDITIONAL]);
493 opt = dns_message_getopt(msg);
495 printf(";; EDNS: version: %u, udp=%u\n",
496 (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
497 (unsigned int)opt->rdclass);
499 tsig = dns_message_gettsig(msg, &tsigname);
501 printf(";; PSEUDOSECTIONS: TSIG\n");
503 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
506 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
508 if (result != ISC_R_SUCCESS)
511 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
514 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
515 ISC_TF(!short_form), query);
516 if (result != ISC_R_SUCCESS)
520 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
523 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
525 if (result != ISC_R_SUCCESS)
528 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
531 result = printsection(msg, DNS_SECTION_ADDITIONAL,
532 "ADDITIONAL", ISC_TRUE, query);
533 if (result != ISC_R_SUCCESS)
536 if ((tsig != NULL) && !short_form) {
538 result = printrdata(msg, tsig, tsigname,
539 "PSEUDOSECTION TSIG", ISC_TRUE);
540 if (result != ISC_R_SUCCESS)
546 if (short_form && !default_lookups &&
547 ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
548 char namestr[DNS_NAME_FORMATSIZE];
549 char typestr[DNS_RDATATYPE_FORMATSIZE];
550 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
551 dns_rdatatype_format(query->lookup->rdtype, typestr,
553 printf("%s has no %s record\n", namestr, typestr);
555 seen_error = force_error;
560 parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
561 char hostname[MXNAME];
562 dig_lookup_t *lookup;
566 isc_result_t result = ISC_R_SUCCESS;
567 dns_rdatatype_t rdtype;
568 dns_rdataclass_t rdclass;
569 isc_uint32_t serial = 0;
571 UNUSED(is_batchfile);
573 lookup = make_empty_lookup();
575 while ((c = isc_commandline_parse(argc, argv, "lvwrdt:c:aTCN:R:W:Dni46"))
579 lookup->tcp_mode = ISC_TRUE;
580 lookup->rdtype = dns_rdatatype_axfr;
581 lookup->rdtypeset = ISC_TRUE;
586 short_form = ISC_FALSE;
589 lookup->recurse = ISC_FALSE;
592 if (strncasecmp(isc_commandline_argument,
594 rdtype = dns_rdatatype_ixfr;
595 /* XXXMPA add error checking */
596 serial = strtoul(isc_commandline_argument + 5,
598 result = ISC_R_SUCCESS;
600 tr.base = isc_commandline_argument;
601 tr.length = strlen(isc_commandline_argument);
602 result = dns_rdatatype_fromtext(&rdtype,
603 (isc_textregion_t *)&tr);
606 if (result != ISC_R_SUCCESS) {
608 fatal("invalid type: %s\n",
609 isc_commandline_argument);
611 if (!lookup->rdtypeset ||
612 lookup->rdtype != dns_rdatatype_axfr)
613 lookup->rdtype = rdtype;
614 lookup->rdtypeset = ISC_TRUE;
615 if (rdtype == dns_rdatatype_axfr) {
617 list_type = dns_rdatatype_any;
618 short_form = ISC_FALSE;
619 lookup->tcp_mode = ISC_TRUE;
620 } else if (rdtype == dns_rdatatype_ixfr) {
621 lookup->ixfr_serial = serial;
625 list_addresses = ISC_FALSE;
626 default_lookups = ISC_FALSE;
629 tr.base = isc_commandline_argument;
630 tr.length = strlen(isc_commandline_argument);
631 result = dns_rdataclass_fromtext(&rdclass,
632 (isc_textregion_t *)&tr);
634 if (result != ISC_R_SUCCESS) {
636 fatal("invalid class: %s\n",
637 isc_commandline_argument);
639 lookup->rdclass = rdclass;
640 lookup->rdclassset = ISC_TRUE;
642 default_lookups = ISC_FALSE;
645 if (!lookup->rdtypeset ||
646 lookup->rdtype != dns_rdatatype_axfr)
647 lookup->rdtype = dns_rdatatype_any;
648 list_type = dns_rdatatype_any;
649 list_addresses = ISC_FALSE;
650 lookup->rdtypeset = ISC_TRUE;
651 short_form = ISC_FALSE;
652 default_lookups = ISC_FALSE;
655 lookup->ip6_int = ISC_TRUE;
662 * The timer routines are coded such that
663 * timeout==MAXINT doesn't enable the timer
668 timeout = atoi(isc_commandline_argument);
673 tries = atoi(isc_commandline_argument) + 1;
678 lookup->tcp_mode = ISC_TRUE;
681 debug("showing all SOAs");
682 lookup->rdtype = dns_rdatatype_ns;
683 lookup->rdtypeset = ISC_TRUE;
684 lookup->rdclass = dns_rdataclass_in;
685 lookup->rdclassset = ISC_TRUE;
686 lookup->ns_search_only = ISC_TRUE;
687 lookup->trace_root = ISC_TRUE;
688 lookup->identify_previous_line = ISC_TRUE;
689 default_lookups = ISC_FALSE;
692 debug("setting NDOTS to %s",
693 isc_commandline_argument);
694 ndots = atoi(isc_commandline_argument);
697 debugging = ISC_TRUE;
701 isc_net_disableipv6();
702 have_ipv6 = ISC_FALSE;
704 fatal("can't find IPv4 networking");
708 isc_net_disableipv4();
709 have_ipv4 = ISC_FALSE;
711 fatal("can't find IPv6 networking");
716 lookup->retries = tries;
718 if (isc_commandline_index >= argc)
721 strncpy(hostname, argv[isc_commandline_index], sizeof(hostname));
722 hostname[sizeof(hostname)-1]=0;
723 if (argc > isc_commandline_index + 1) {
724 set_nameserver(argv[isc_commandline_index+1]);
725 debug("server is %s", argv[isc_commandline_index+1]);
726 listed_server = ISC_TRUE;
729 lookup->pending = ISC_FALSE;
730 if (get_reverse(store, sizeof(store), hostname,
731 lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) {
732 strncpy(lookup->textname, store, sizeof(lookup->textname));
733 lookup->textname[sizeof(lookup->textname)-1] = 0;
734 lookup->rdtype = dns_rdatatype_ptr;
735 lookup->rdtypeset = ISC_TRUE;
736 default_lookups = ISC_FALSE;
738 strncpy(lookup->textname, hostname, sizeof(lookup->textname));
739 lookup->textname[sizeof(lookup->textname)-1]=0;
741 lookup->new_search = ISC_TRUE;
742 ISC_LIST_APPEND(lookup_list, lookup, link);
744 usesearch = ISC_TRUE;
748 main(int argc, char **argv) {
753 ISC_LIST_INIT(lookup_list);
754 ISC_LIST_INIT(server_list);
755 ISC_LIST_INIT(search_list);
761 result = isc_app_start();
762 check_result(result, "isc_app_start");
764 parse_args(ISC_FALSE, argc, argv);
766 result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
767 check_result(result, "isc_app_onrun");
772 return ((seen_error == 0) ? 0 : 1);