2 * Copyright (C) 2004, 2005 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.13 2005/07/04 03:29:45 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 static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE;
44 static isc_boolean_t default_lookups = ISC_TRUE;
45 static int seen_error = -1;
46 static isc_boolean_t list_addresses = ISC_TRUE;
47 static dns_rdatatype_t list_type = dns_rdatatype_a;
49 static const char *opcodetext[] = {
68 static const char *rcodetext[] = {
93 struct rtype rtypes[] = {
96 { 5, "is an alias for" },
97 { 11, "has well known services" },
98 { 12, "domain name pointer" },
99 { 13, "host information" },
100 { 15, "mail is handled by" },
101 { 16, "descriptive text" },
102 { 19, "x25 address" },
103 { 20, "ISDN address" },
104 { 24, "has signature" },
106 { 28, "has IPv6 address" },
114 "Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]\n"
115 " [-R number] hostname [server]\n"
116 " -a is equivalent to -v -t *\n"
117 " -c specifies query class for non-IN data\n"
118 " -C compares SOA records on authoritative nameservers\n"
119 " -d is equivalent to -v\n"
120 " -l lists all hosts in a domain, using AXFR\n"
121 " -i IP6.INT reverse lookups\n"
122 " -N changes the number of dots allowed before root lookup is done\n"
123 " -r disables recursive processing\n"
124 " -R specifies number of retries for UDP packets\n"
125 " -t specifies the query type\n"
126 " -T enables TCP/IP mode\n"
127 " -v enables verbose output\n"
128 " -w specifies to wait forever for a reply\n"
129 " -W specifies how long to wait for a reply\n"
130 " -4 use IPv4 query transport only\n"
131 " -6 use IPv6 query transport only\n", stderr);
136 dighost_shutdown(void) {
141 received(int bytes, isc_sockaddr_t *from, dig_query_t *query) {
146 char fromtext[ISC_SOCKADDR_FORMATSIZE];
147 isc_sockaddr_format(from, fromtext, sizeof(fromtext));
149 diff = (int) isc_time_microdiff(&now, &query->time_sent);
150 printf("Received %u bytes from %s in %d ms\n",
151 bytes, fromtext, diff/1000);
156 trying(char *frm, dig_lookup_t *lookup) {
160 printf("Trying \"%s\"\n", frm);
164 say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
167 isc_buffer_t *b = NULL;
168 char namestr[DNS_NAME_FORMATSIZE];
171 unsigned int bufsize = BUFSIZ;
173 dns_name_format(name, namestr, sizeof(namestr));
175 result = isc_buffer_allocate(mctx, &b, bufsize);
176 check_result(result, "isc_buffer_allocate");
177 result = dns_rdata_totext(rdata, NULL, b);
178 if (result == ISC_R_NOSPACE) {
183 check_result(result, "dns_rdata_totext");
184 isc_buffer_usedregion(b, &r);
185 if (query->lookup->identify_previous_line) {
186 printf("Nameserver %s:\n\t",
189 printf("%s %s %.*s", namestr,
190 msg, (int)r.length, (char *)r.base);
191 if (query->lookup->identify) {
192 printf(" on server %s", query->servname);
198 /* Just for compatibility : not use in host program */
200 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
201 isc_buffer_t *target)
210 printsection(dns_message_t *msg, dns_section_t sectionid,
211 const char *section_name, isc_boolean_t headers,
214 dns_name_t *name, *print_name;
215 dns_rdataset_t *rdataset;
216 dns_rdata_t rdata = DNS_RDATA_INIT;
218 isc_result_t result, loopresult;
220 dns_name_t empty_name;
223 isc_boolean_t no_rdata;
225 if (sectionid == DNS_SECTION_QUESTION)
228 no_rdata = ISC_FALSE;
231 printf(";; %s SECTION:\n", section_name);
233 dns_name_init(&empty_name, NULL);
235 result = dns_message_firstname(msg, sectionid);
236 if (result == ISC_R_NOMORE)
237 return (ISC_R_SUCCESS);
238 else if (result != ISC_R_SUCCESS)
243 dns_message_currentname(msg, sectionid, &name);
245 isc_buffer_init(&target, t, sizeof(t));
249 for (rdataset = ISC_LIST_HEAD(name->list);
251 rdataset = ISC_LIST_NEXT(rdataset, link)) {
252 if (query->lookup->rdtype == dns_rdatatype_axfr &&
253 !((!list_addresses &&
254 (list_type == dns_rdatatype_any ||
255 rdataset->type == list_type)) ||
257 (rdataset->type == dns_rdatatype_a ||
258 rdataset->type == dns_rdatatype_aaaa ||
259 rdataset->type == dns_rdatatype_ns ||
260 rdataset->type == dns_rdatatype_ptr))))
263 result = dns_rdataset_totext(rdataset,
268 if (result != ISC_R_SUCCESS)
272 print_name = &empty_name;
276 UNUSED(first); /* Shut up compiler. */
279 loopresult = dns_rdataset_first(rdataset);
280 while (loopresult == ISC_R_SUCCESS) {
283 char typebuf[DNS_RDATATYPE_FORMATSIZE];
284 char typebuf2[DNS_RDATATYPE_FORMATSIZE
286 dns_rdataset_current(rdataset, &rdata);
288 for (t = rtypes; t->text != NULL; t++) {
289 if (t->type == rdata.type) {
295 dns_rdatatype_format(rdata.type,
298 snprintf(typebuf2, sizeof(typebuf2),
299 "has %s record", typebuf);
302 say_message(print_name, rtt,
304 dns_rdata_reset(&rdata);
306 dns_rdataset_next(rdataset);
311 isc_buffer_usedregion(&target, &r);
313 printf(";%.*s", (int)r.length,
316 printf("%.*s", (int)r.length, (char *)r.base);
319 result = dns_message_nextname(msg, sectionid);
320 if (result == ISC_R_NOMORE)
322 else if (result != ISC_R_SUCCESS)
326 return (ISC_R_SUCCESS);
330 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
331 const char *set_name, isc_boolean_t headers)
340 printf(";; %s SECTION:\n", set_name);
342 isc_buffer_init(&target, t, sizeof(t));
344 result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
346 if (result != ISC_R_SUCCESS)
348 isc_buffer_usedregion(&target, &r);
349 printf("%.*s", (int)r.length, (char *)r.base);
351 return (ISC_R_SUCCESS);
355 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
356 isc_boolean_t did_flag = ISC_FALSE;
357 dns_rdataset_t *opt, *tsig = NULL;
358 dns_name_t *tsigname;
359 isc_result_t result = ISC_R_SUCCESS;
365 * We get called multiple times.
366 * Preserve any existing error status.
368 force_error = (seen_error == 1) ? 1 : 0;
371 char sockstr[ISC_SOCKADDR_FORMATSIZE];
373 printf("Using domain server:\n");
374 printf("Name: %s\n", query->userarg);
375 isc_sockaddr_format(&query->sockaddr, sockstr,
377 printf("Address: %s\n", sockstr);
378 printf("Aliases: \n\n");
381 if (msg->rcode != 0) {
382 char namestr[DNS_NAME_FORMATSIZE];
383 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
384 printf("Host %s not found: %d(%s)\n", namestr,
385 msg->rcode, rcodetext[msg->rcode]);
386 return (ISC_R_SUCCESS);
389 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
390 char namestr[DNS_NAME_FORMATSIZE];
391 dig_lookup_t *lookup;
393 /* Add AAAA and MX lookups. */
395 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
396 lookup = clone_lookup(query->lookup, ISC_FALSE);
397 if (lookup != NULL) {
398 strncpy(lookup->textname, namestr,
399 sizeof(lookup->textname));
400 lookup->textname[sizeof(lookup->textname)-1] = 0;
401 lookup->rdtype = dns_rdatatype_aaaa;
402 lookup->rdtypeset = ISC_TRUE;
403 lookup->origin = NULL;
404 lookup->retries = tries;
405 ISC_LIST_APPEND(lookup_list, lookup, link);
407 lookup = clone_lookup(query->lookup, ISC_FALSE);
408 if (lookup != NULL) {
409 strncpy(lookup->textname, namestr,
410 sizeof(lookup->textname));
411 lookup->textname[sizeof(lookup->textname)-1] = 0;
412 lookup->rdtype = dns_rdatatype_mx;
413 lookup->rdtypeset = ISC_TRUE;
414 lookup->origin = NULL;
415 lookup->retries = tries;
416 ISC_LIST_APPEND(lookup_list, lookup, link);
421 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
422 opcodetext[msg->opcode], rcodetext[msg->rcode],
424 printf(";; flags: ");
425 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
429 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
430 printf("%saa", did_flag ? " " : "");
433 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
434 printf("%stc", did_flag ? " " : "");
437 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
438 printf("%srd", did_flag ? " " : "");
441 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
442 printf("%sra", did_flag ? " " : "");
445 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
446 printf("%sad", did_flag ? " " : "");
449 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
450 printf("%scd", did_flag ? " " : "");
453 printf("; QUERY: %u, ANSWER: %u, "
454 "AUTHORITY: %u, ADDITIONAL: %u\n",
455 msg->counts[DNS_SECTION_QUESTION],
456 msg->counts[DNS_SECTION_ANSWER],
457 msg->counts[DNS_SECTION_AUTHORITY],
458 msg->counts[DNS_SECTION_ADDITIONAL]);
459 opt = dns_message_getopt(msg);
461 printf(";; EDNS: version: %u, udp=%u\n",
462 (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
463 (unsigned int)opt->rdclass);
465 tsig = dns_message_gettsig(msg, &tsigname);
467 printf(";; PSEUDOSECTIONS: TSIG\n");
469 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
472 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
474 if (result != ISC_R_SUCCESS)
477 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
480 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
481 ISC_TF(!short_form), query);
482 if (result != ISC_R_SUCCESS)
486 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
489 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
491 if (result != ISC_R_SUCCESS)
494 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
497 result = printsection(msg, DNS_SECTION_ADDITIONAL,
498 "ADDITIONAL", ISC_TRUE, query);
499 if (result != ISC_R_SUCCESS)
502 if ((tsig != NULL) && !short_form) {
504 result = printrdata(msg, tsig, tsigname,
505 "PSEUDOSECTION TSIG", ISC_TRUE);
506 if (result != ISC_R_SUCCESS)
512 if (short_form && !default_lookups &&
513 ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
514 char namestr[DNS_NAME_FORMATSIZE];
515 char typestr[DNS_RDATATYPE_FORMATSIZE];
516 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
517 dns_rdatatype_format(query->lookup->rdtype, typestr,
519 printf("%s has no %s record\n", namestr, typestr);
521 seen_error = force_error;
526 parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
527 char hostname[MXNAME];
528 dig_lookup_t *lookup;
532 isc_result_t result = ISC_R_SUCCESS;
533 dns_rdatatype_t rdtype;
534 dns_rdataclass_t rdclass;
535 isc_uint32_t serial = 0;
537 UNUSED(is_batchfile);
539 lookup = make_empty_lookup();
541 while ((c = isc_commandline_parse(argc, argv, "lvwrdt:c:aTCN:R:W:Dni46"))
545 lookup->tcp_mode = ISC_TRUE;
546 lookup->rdtype = dns_rdatatype_axfr;
547 lookup->rdtypeset = ISC_TRUE;
552 short_form = ISC_FALSE;
555 lookup->recurse = ISC_FALSE;
558 if (strncasecmp(isc_commandline_argument,
560 rdtype = dns_rdatatype_ixfr;
561 /* XXXMPA add error checking */
562 serial = strtoul(isc_commandline_argument + 5,
564 result = ISC_R_SUCCESS;
566 tr.base = isc_commandline_argument;
567 tr.length = strlen(isc_commandline_argument);
568 result = dns_rdatatype_fromtext(&rdtype,
569 (isc_textregion_t *)&tr);
572 if (result != ISC_R_SUCCESS) {
574 fatal("invalid type: %s\n",
575 isc_commandline_argument);
577 if (!lookup->rdtypeset ||
578 lookup->rdtype != dns_rdatatype_axfr)
579 lookup->rdtype = rdtype;
580 lookup->rdtypeset = ISC_TRUE;
581 if (rdtype == dns_rdatatype_axfr) {
583 list_type = dns_rdatatype_any;
584 short_form = ISC_FALSE;
585 lookup->tcp_mode = ISC_TRUE;
586 } else if (rdtype == dns_rdatatype_ixfr) {
587 lookup->ixfr_serial = serial;
591 list_addresses = ISC_FALSE;
592 default_lookups = ISC_FALSE;
595 tr.base = isc_commandline_argument;
596 tr.length = strlen(isc_commandline_argument);
597 result = dns_rdataclass_fromtext(&rdclass,
598 (isc_textregion_t *)&tr);
600 if (result != ISC_R_SUCCESS) {
602 fatal("invalid class: %s\n",
603 isc_commandline_argument);
605 lookup->rdclass = rdclass;
606 lookup->rdclassset = ISC_TRUE;
608 default_lookups = ISC_FALSE;
611 if (!lookup->rdtypeset ||
612 lookup->rdtype != dns_rdatatype_axfr)
613 lookup->rdtype = dns_rdatatype_any;
614 list_type = dns_rdatatype_any;
615 list_addresses = ISC_FALSE;
616 lookup->rdtypeset = ISC_TRUE;
617 short_form = ISC_FALSE;
618 default_lookups = ISC_FALSE;
621 lookup->ip6_int = ISC_TRUE;
628 * The timer routines are coded such that
629 * timeout==MAXINT doesn't enable the timer
634 timeout = atoi(isc_commandline_argument);
639 tries = atoi(isc_commandline_argument) + 1;
644 lookup->tcp_mode = ISC_TRUE;
647 debug("showing all SOAs");
648 lookup->rdtype = dns_rdatatype_ns;
649 lookup->rdtypeset = ISC_TRUE;
650 lookup->rdclass = dns_rdataclass_in;
651 lookup->rdclassset = ISC_TRUE;
652 lookup->ns_search_only = ISC_TRUE;
653 lookup->trace_root = ISC_TRUE;
654 lookup->identify_previous_line = ISC_TRUE;
655 default_lookups = ISC_FALSE;
658 debug("setting NDOTS to %s",
659 isc_commandline_argument);
660 ndots = atoi(isc_commandline_argument);
663 debugging = ISC_TRUE;
667 isc_net_disableipv6();
668 have_ipv6 = ISC_FALSE;
670 fatal("can't find IPv4 networking");
674 isc_net_disableipv4();
675 have_ipv4 = ISC_FALSE;
677 fatal("can't find IPv6 networking");
682 lookup->retries = tries;
684 if (isc_commandline_index >= argc)
687 strncpy(hostname, argv[isc_commandline_index], sizeof(hostname));
688 hostname[sizeof(hostname)-1]=0;
689 if (argc > isc_commandline_index + 1) {
690 set_nameserver(argv[isc_commandline_index+1]);
691 debug("server is %s", argv[isc_commandline_index+1]);
692 listed_server = ISC_TRUE;
695 lookup->pending = ISC_FALSE;
696 if (get_reverse(store, sizeof(store), hostname,
697 lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) {
698 strncpy(lookup->textname, store, sizeof(lookup->textname));
699 lookup->textname[sizeof(lookup->textname)-1] = 0;
700 lookup->rdtype = dns_rdatatype_ptr;
701 lookup->rdtypeset = ISC_TRUE;
702 default_lookups = ISC_FALSE;
704 strncpy(lookup->textname, hostname, sizeof(lookup->textname));
705 lookup->textname[sizeof(lookup->textname)-1]=0;
707 lookup->new_search = ISC_TRUE;
708 ISC_LIST_APPEND(lookup_list, lookup, link);
710 usesearch = ISC_TRUE;
714 main(int argc, char **argv) {
719 ISC_LIST_INIT(lookup_list);
720 ISC_LIST_INIT(server_list);
721 ISC_LIST_INIT(search_list);
727 result = isc_app_start();
728 check_result(result, "isc_app_start");
730 parse_args(ISC_FALSE, argc, argv);
732 result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
733 check_result(result, "isc_app_onrun");
738 return ((seen_error == 0) ? 0 : 1);