2 * Copyright (C) 2004 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.9 2004/04/13 03:00:06 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>
43 extern ISC_LIST(dig_lookup_t) lookup_list;
44 extern dig_serverlist_t server_list;
45 extern ISC_LIST(dig_searchlist_t) search_list;
47 extern isc_boolean_t have_ipv4, have_ipv6;
48 extern isc_boolean_t usesearch;
49 extern isc_boolean_t debugging;
50 extern unsigned int timeout;
51 extern isc_mem_t *mctx;
54 extern char *progname;
55 extern isc_task_t *global_task;
58 static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE;
59 static isc_boolean_t default_lookups = ISC_TRUE;
60 static int seen_error = -1;
61 static isc_boolean_t list_addresses = ISC_TRUE;
62 static dns_rdatatype_t list_type = dns_rdatatype_a;
64 static const char *opcodetext[] = {
83 static const char *rcodetext[] = {
108 struct rtype rtypes[] = {
109 { 1, "has address" },
110 { 2, "name server" },
111 { 5, "is an alias for" },
112 { 11, "has well known services" },
113 { 12, "domain name pointer" },
114 { 13, "host information" },
115 { 15, "mail is handled by" },
116 { 16, "descriptive text" },
117 { 19, "x25 address" },
118 { 20, "ISDN address" },
119 { 24, "has signature" },
121 { 28, "has IPv6 address" },
129 "Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]\n"
130 " [-R number] hostname [server]\n"
131 " -a is equivalent to -v -t *\n"
132 " -c specifies query class for non-IN data\n"
133 " -C compares SOA records on authoritative nameservers\n"
134 " -d is equivalent to -v\n"
135 " -l lists all hosts in a domain, using AXFR\n"
136 " -i IP6.INT reverse lookups\n"
137 " -N changes the number of dots allowed before root lookup is done\n"
138 " -r disables recursive processing\n"
139 " -R specifies number of retries for UDP packets\n"
140 " -t specifies the query type\n"
141 " -T enables TCP/IP mode\n"
142 " -v enables verbose output\n"
143 " -w specifies to wait forever for a reply\n"
144 " -W specifies how long to wait for a reply\n"
145 " -4 use IPv4 query transport only\n"
146 " -6 use IPv6 query transport only\n", stderr);
151 dighost_shutdown(void) {
156 received(int bytes, isc_sockaddr_t *from, dig_query_t *query) {
161 char fromtext[ISC_SOCKADDR_FORMATSIZE];
162 isc_sockaddr_format(from, fromtext, sizeof(fromtext));
164 diff = (int) isc_time_microdiff(&now, &query->time_sent);
165 printf("Received %u bytes from %s in %d ms\n",
166 bytes, fromtext, diff/1000);
171 trying(char *frm, dig_lookup_t *lookup) {
175 printf("Trying \"%s\"\n", frm);
179 say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
182 isc_buffer_t *b = NULL;
183 char namestr[DNS_NAME_FORMATSIZE];
186 unsigned int bufsize = BUFSIZ;
188 dns_name_format(name, namestr, sizeof(namestr));
190 result = isc_buffer_allocate(mctx, &b, bufsize);
191 check_result(result, "isc_buffer_allocate");
192 result = dns_rdata_totext(rdata, NULL, b);
193 if (result == ISC_R_NOSPACE) {
198 check_result(result, "dns_rdata_totext");
199 isc_buffer_usedregion(b, &r);
200 if (query->lookup->identify_previous_line) {
201 printf("Nameserver %s:\n\t",
204 printf("%s %s %.*s", namestr,
205 msg, (int)r.length, (char *)r.base);
206 if (query->lookup->identify) {
207 printf(" on server %s", query->servname);
213 /* Just for compatibility : not use in host program */
215 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
216 isc_buffer_t *target)
225 printsection(dns_message_t *msg, dns_section_t sectionid,
226 const char *section_name, isc_boolean_t headers,
229 dns_name_t *name, *print_name;
230 dns_rdataset_t *rdataset;
231 dns_rdata_t rdata = DNS_RDATA_INIT;
233 isc_result_t result, loopresult;
235 dns_name_t empty_name;
238 isc_boolean_t no_rdata;
240 if (sectionid == DNS_SECTION_QUESTION)
243 no_rdata = ISC_FALSE;
246 printf(";; %s SECTION:\n", section_name);
248 dns_name_init(&empty_name, NULL);
250 result = dns_message_firstname(msg, sectionid);
251 if (result == ISC_R_NOMORE)
252 return (ISC_R_SUCCESS);
253 else if (result != ISC_R_SUCCESS)
258 dns_message_currentname(msg, sectionid, &name);
260 isc_buffer_init(&target, t, sizeof(t));
264 for (rdataset = ISC_LIST_HEAD(name->list);
266 rdataset = ISC_LIST_NEXT(rdataset, link)) {
267 if (query->lookup->rdtype == dns_rdatatype_axfr &&
268 !((!list_addresses &&
269 (list_type == dns_rdatatype_any ||
270 rdataset->type == list_type)) ||
272 (rdataset->type == dns_rdatatype_a ||
273 rdataset->type == dns_rdatatype_aaaa ||
274 rdataset->type == dns_rdatatype_ns ||
275 rdataset->type == dns_rdatatype_ptr))))
278 result = dns_rdataset_totext(rdataset,
283 if (result != ISC_R_SUCCESS)
287 print_name = &empty_name;
291 UNUSED(first); /* Shut up compiler. */
294 loopresult = dns_rdataset_first(rdataset);
295 while (loopresult == ISC_R_SUCCESS) {
298 char typebuf[DNS_RDATATYPE_FORMATSIZE];
299 char typebuf2[DNS_RDATATYPE_FORMATSIZE
301 dns_rdataset_current(rdataset, &rdata);
303 for (t = rtypes; t->text != NULL; t++) {
304 if (t->type == rdata.type) {
310 dns_rdatatype_format(rdata.type,
313 snprintf(typebuf2, sizeof(typebuf2),
314 "has %s record", typebuf);
317 say_message(print_name, rtt,
319 dns_rdata_reset(&rdata);
321 dns_rdataset_next(rdataset);
326 isc_buffer_usedregion(&target, &r);
328 printf(";%.*s", (int)r.length,
331 printf("%.*s", (int)r.length, (char *)r.base);
334 result = dns_message_nextname(msg, sectionid);
335 if (result == ISC_R_NOMORE)
337 else if (result != ISC_R_SUCCESS)
341 return (ISC_R_SUCCESS);
345 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
346 const char *set_name, isc_boolean_t headers)
355 printf(";; %s SECTION:\n", set_name);
357 isc_buffer_init(&target, t, sizeof(t));
359 result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
361 if (result != ISC_R_SUCCESS)
363 isc_buffer_usedregion(&target, &r);
364 printf("%.*s", (int)r.length, (char *)r.base);
366 return (ISC_R_SUCCESS);
370 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
371 isc_boolean_t did_flag = ISC_FALSE;
372 dns_rdataset_t *opt, *tsig = NULL;
373 dns_name_t *tsigname;
374 isc_result_t result = ISC_R_SUCCESS;
380 * We get called multiple times.
381 * Preserve any existing error status.
383 force_error = (seen_error == 1) ? 1 : 0;
386 char sockstr[ISC_SOCKADDR_FORMATSIZE];
388 printf("Using domain server:\n");
389 printf("Name: %s\n", query->servname);
390 isc_sockaddr_format(&query->sockaddr, sockstr,
392 printf("Address: %s\n", sockstr);
393 printf("Aliases: \n\n");
396 if (msg->rcode != 0) {
397 char namestr[DNS_NAME_FORMATSIZE];
398 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
399 printf("Host %s not found: %d(%s)\n", namestr,
400 msg->rcode, rcodetext[msg->rcode]);
401 return (ISC_R_SUCCESS);
404 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
405 char namestr[DNS_NAME_FORMATSIZE];
406 dig_lookup_t *lookup;
408 /* Add AAAA and MX lookups. */
410 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
411 lookup = clone_lookup(query->lookup, ISC_FALSE);
412 if (lookup != NULL) {
413 strncpy(lookup->textname, namestr,
414 sizeof(lookup->textname));
415 lookup->textname[sizeof(lookup->textname)-1] = 0;
416 lookup->rdtype = dns_rdatatype_aaaa;
417 lookup->rdtypeset = ISC_TRUE;
418 lookup->origin = NULL;
419 lookup->retries = tries;
420 ISC_LIST_APPEND(lookup_list, lookup, link);
422 lookup = clone_lookup(query->lookup, ISC_FALSE);
423 if (lookup != NULL) {
424 strncpy(lookup->textname, namestr,
425 sizeof(lookup->textname));
426 lookup->textname[sizeof(lookup->textname)-1] = 0;
427 lookup->rdtype = dns_rdatatype_mx;
428 lookup->rdtypeset = ISC_TRUE;
429 lookup->origin = NULL;
430 lookup->retries = tries;
431 ISC_LIST_APPEND(lookup_list, lookup, link);
436 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
437 opcodetext[msg->opcode], rcodetext[msg->rcode],
439 printf(";; flags: ");
440 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
444 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
445 printf("%saa", did_flag ? " " : "");
448 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
449 printf("%stc", did_flag ? " " : "");
452 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
453 printf("%srd", did_flag ? " " : "");
456 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
457 printf("%sra", did_flag ? " " : "");
460 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
461 printf("%sad", did_flag ? " " : "");
464 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
465 printf("%scd", did_flag ? " " : "");
468 printf("; QUERY: %u, ANSWER: %u, "
469 "AUTHORITY: %u, ADDITIONAL: %u\n",
470 msg->counts[DNS_SECTION_QUESTION],
471 msg->counts[DNS_SECTION_ANSWER],
472 msg->counts[DNS_SECTION_AUTHORITY],
473 msg->counts[DNS_SECTION_ADDITIONAL]);
474 opt = dns_message_getopt(msg);
476 printf(";; EDNS: version: %u, udp=%u\n",
477 (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
478 (unsigned int)opt->rdclass);
480 tsig = dns_message_gettsig(msg, &tsigname);
482 printf(";; PSEUDOSECTIONS: TSIG\n");
484 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
487 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
489 if (result != ISC_R_SUCCESS)
492 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
495 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
496 ISC_TF(!short_form), query);
497 if (result != ISC_R_SUCCESS)
501 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
504 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
506 if (result != ISC_R_SUCCESS)
509 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
512 result = printsection(msg, DNS_SECTION_ADDITIONAL,
513 "ADDITIONAL", ISC_TRUE, query);
514 if (result != ISC_R_SUCCESS)
517 if ((tsig != NULL) && !short_form) {
519 result = printrdata(msg, tsig, tsigname,
520 "PSEUDOSECTION TSIG", ISC_TRUE);
521 if (result != ISC_R_SUCCESS)
527 if (short_form && !default_lookups &&
528 ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
529 char namestr[DNS_NAME_FORMATSIZE];
530 char typestr[DNS_RDATATYPE_FORMATSIZE];
531 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
532 dns_rdatatype_format(query->lookup->rdtype, typestr,
534 printf("%s has no %s record\n", namestr, typestr);
536 seen_error = force_error;
541 parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
542 char hostname[MXNAME];
543 dig_lookup_t *lookup;
547 isc_result_t result = ISC_R_SUCCESS;
548 dns_rdatatype_t rdtype;
549 dns_rdataclass_t rdclass;
550 isc_uint32_t serial = 0;
552 UNUSED(is_batchfile);
554 lookup = make_empty_lookup();
556 while ((c = isc_commandline_parse(argc, argv, "lvwrdt:c:aTCN:R:W:Dni46"))
560 lookup->tcp_mode = ISC_TRUE;
561 lookup->rdtype = dns_rdatatype_axfr;
562 lookup->rdtypeset = ISC_TRUE;
567 short_form = ISC_FALSE;
570 lookup->recurse = ISC_FALSE;
573 if (strncasecmp(isc_commandline_argument,
575 rdtype = dns_rdatatype_ixfr;
576 /* XXXMPA add error checking */
577 serial = strtoul(isc_commandline_argument + 5,
579 result = ISC_R_SUCCESS;
581 tr.base = isc_commandline_argument;
582 tr.length = strlen(isc_commandline_argument);
583 result = dns_rdatatype_fromtext(&rdtype,
584 (isc_textregion_t *)&tr);
587 if (result != ISC_R_SUCCESS) {
589 fatal("invalid type: %s\n",
590 isc_commandline_argument);
592 if (!lookup->rdtypeset ||
593 lookup->rdtype != dns_rdatatype_axfr)
594 lookup->rdtype = rdtype;
595 lookup->rdtypeset = ISC_TRUE;
596 if (rdtype == dns_rdatatype_axfr) {
598 list_type = dns_rdatatype_any;
599 short_form = ISC_FALSE;
600 lookup->tcp_mode = ISC_TRUE;
601 } else if (rdtype == dns_rdatatype_ixfr) {
602 lookup->ixfr_serial = serial;
606 list_addresses = ISC_FALSE;
609 tr.base = isc_commandline_argument;
610 tr.length = strlen(isc_commandline_argument);
611 result = dns_rdataclass_fromtext(&rdclass,
612 (isc_textregion_t *)&tr);
614 if (result != ISC_R_SUCCESS) {
616 fatal("invalid class: %s\n",
617 isc_commandline_argument);
619 lookup->rdclass = rdclass;
620 lookup->rdclassset = ISC_TRUE;
622 default_lookups = ISC_FALSE;
625 if (!lookup->rdtypeset ||
626 lookup->rdtype != dns_rdatatype_axfr)
627 lookup->rdtype = dns_rdatatype_any;
628 list_type = dns_rdatatype_any;
629 list_addresses = ISC_FALSE;
630 lookup->rdtypeset = ISC_TRUE;
631 short_form = ISC_FALSE;
632 default_lookups = ISC_FALSE;
635 lookup->ip6_int = ISC_TRUE;
642 * The timer routines are coded such that
643 * timeout==MAXINT doesn't enable the timer
648 timeout = atoi(isc_commandline_argument);
653 tries = atoi(isc_commandline_argument) + 1;
658 lookup->tcp_mode = ISC_TRUE;
661 debug("showing all SOAs");
662 lookup->rdtype = dns_rdatatype_ns;
663 lookup->rdtypeset = ISC_TRUE;
664 lookup->rdclass = dns_rdataclass_in;
665 lookup->rdclassset = ISC_TRUE;
666 lookup->ns_search_only = ISC_TRUE;
667 lookup->trace_root = ISC_TRUE;
668 lookup->identify_previous_line = ISC_TRUE;
669 default_lookups = ISC_FALSE;
672 debug("setting NDOTS to %s",
673 isc_commandline_argument);
674 ndots = atoi(isc_commandline_argument);
677 debugging = ISC_TRUE;
681 isc_net_disableipv6();
682 have_ipv6 = ISC_FALSE;
684 fatal("can't find IPv4 networking");
688 isc_net_disableipv4();
689 have_ipv4 = ISC_FALSE;
691 fatal("can't find IPv6 networking");
696 lookup->retries = tries;
698 if (isc_commandline_index >= argc)
701 strncpy(hostname, argv[isc_commandline_index], sizeof(hostname));
702 hostname[sizeof(hostname)-1]=0;
703 if (argc > isc_commandline_index + 1) {
704 set_nameserver(argv[isc_commandline_index+1]);
705 debug("server is %s", argv[isc_commandline_index+1]);
706 listed_server = ISC_TRUE;
709 lookup->pending = ISC_FALSE;
710 if (get_reverse(store, sizeof(store), hostname,
711 lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) {
712 strncpy(lookup->textname, store, sizeof(lookup->textname));
713 lookup->textname[sizeof(lookup->textname)-1] = 0;
714 lookup->rdtype = dns_rdatatype_ptr;
715 lookup->rdtypeset = ISC_TRUE;
716 default_lookups = ISC_FALSE;
718 strncpy(lookup->textname, hostname, sizeof(lookup->textname));
719 lookup->textname[sizeof(lookup->textname)-1]=0;
721 lookup->new_search = ISC_TRUE;
722 ISC_LIST_APPEND(lookup_list, lookup, link);
724 usesearch = ISC_TRUE;
728 main(int argc, char **argv) {
733 ISC_LIST_INIT(lookup_list);
734 ISC_LIST_INIT(server_list);
735 ISC_LIST_INIT(search_list);
741 result = isc_app_start();
742 check_result(result, "isc_app_start");
744 parse_args(ISC_FALSE, argc, argv);
746 result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
747 check_result(result, "isc_app_onrun");
752 return ((seen_error == 0) ? 0 : 1);