1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2007, 2009-2013 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18254897Serwin/* $Id: host.c,v 1.127 2011/03/11 06:11:20 marka Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23174187Sdougb#include <stdlib.h> 24135446Strhodes#include <limits.h> 25135446Strhodes 26174187Sdougb#ifdef HAVE_LOCALE_H 27174187Sdougb#include <locale.h> 28174187Sdougb#endif 29174187Sdougb 30174187Sdougb#ifdef WITH_IDN 31174187Sdougb#include <idn/result.h> 32174187Sdougb#include <idn/log.h> 33174187Sdougb#include <idn/resconf.h> 34174187Sdougb#include <idn/api.h> 35174187Sdougb#endif 36174187Sdougb 37135446Strhodes#include <isc/app.h> 38135446Strhodes#include <isc/commandline.h> 39135446Strhodes#include <isc/netaddr.h> 40135446Strhodes#include <isc/print.h> 41135446Strhodes#include <isc/string.h> 42135446Strhodes#include <isc/util.h> 43135446Strhodes#include <isc/task.h> 44135446Strhodes#include <isc/stdlib.h> 45135446Strhodes 46135446Strhodes#include <dns/byaddr.h> 47135446Strhodes#include <dns/fixedname.h> 48135446Strhodes#include <dns/message.h> 49135446Strhodes#include <dns/name.h> 50135446Strhodes#include <dns/rdata.h> 51135446Strhodes#include <dns/rdataclass.h> 52135446Strhodes#include <dns/rdataset.h> 53135446Strhodes#include <dns/rdatatype.h> 54165071Sdougb#include <dns/rdatastruct.h> 55135446Strhodes 56135446Strhodes#include <dig/dig.h> 57135446Strhodes 58135446Strhodesstatic isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE; 59135446Strhodesstatic isc_boolean_t default_lookups = ISC_TRUE; 60135446Strhodesstatic int seen_error = -1; 61135446Strhodesstatic isc_boolean_t list_addresses = ISC_TRUE; 62135446Strhodesstatic dns_rdatatype_t list_type = dns_rdatatype_a; 63165071Sdougbstatic isc_boolean_t printed_server = ISC_FALSE; 64135446Strhodes 65135446Strhodesstatic const char *opcodetext[] = { 66135446Strhodes "QUERY", 67135446Strhodes "IQUERY", 68135446Strhodes "STATUS", 69135446Strhodes "RESERVED3", 70135446Strhodes "NOTIFY", 71135446Strhodes "UPDATE", 72135446Strhodes "RESERVED6", 73135446Strhodes "RESERVED7", 74135446Strhodes "RESERVED8", 75135446Strhodes "RESERVED9", 76135446Strhodes "RESERVED10", 77135446Strhodes "RESERVED11", 78135446Strhodes "RESERVED12", 79135446Strhodes "RESERVED13", 80135446Strhodes "RESERVED14", 81135446Strhodes "RESERVED15" 82135446Strhodes}; 83135446Strhodes 84135446Strhodesstatic const char *rcodetext[] = { 85135446Strhodes "NOERROR", 86135446Strhodes "FORMERR", 87135446Strhodes "SERVFAIL", 88135446Strhodes "NXDOMAIN", 89135446Strhodes "NOTIMP", 90135446Strhodes "REFUSED", 91135446Strhodes "YXDOMAIN", 92135446Strhodes "YXRRSET", 93135446Strhodes "NXRRSET", 94135446Strhodes "NOTAUTH", 95135446Strhodes "NOTZONE", 96135446Strhodes "RESERVED11", 97135446Strhodes "RESERVED12", 98135446Strhodes "RESERVED13", 99135446Strhodes "RESERVED14", 100135446Strhodes "RESERVED15", 101135446Strhodes "BADVERS" 102135446Strhodes}; 103135446Strhodes 104135446Strhodesstruct rtype { 105135446Strhodes unsigned int type; 106135446Strhodes const char *text; 107135446Strhodes}; 108135446Strhodes 109135446Strhodesstruct rtype rtypes[] = { 110135446Strhodes { 1, "has address" }, 111135446Strhodes { 2, "name server" }, 112135446Strhodes { 5, "is an alias for" }, 113135446Strhodes { 11, "has well known services" }, 114135446Strhodes { 12, "domain name pointer" }, 115135446Strhodes { 13, "host information" }, 116135446Strhodes { 15, "mail is handled by" }, 117135446Strhodes { 16, "descriptive text" }, 118135446Strhodes { 19, "x25 address" }, 119135446Strhodes { 20, "ISDN address" }, 120135446Strhodes { 24, "has signature" }, 121135446Strhodes { 25, "has key" }, 122135446Strhodes { 28, "has IPv6 address" }, 123135446Strhodes { 29, "location" }, 124135446Strhodes { 0, NULL } 125135446Strhodes}; 126135446Strhodes 127193149Sdougbstatic char * 128193149Sdougbrcode_totext(dns_rcode_t rcode) 129193149Sdougb{ 130193149Sdougb static char buf[sizeof("?65535")]; 131193149Sdougb union { 132193149Sdougb const char *consttext; 133193149Sdougb char *deconsttext; 134193149Sdougb } totext; 135193149Sdougb 136193149Sdougb if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 137193149Sdougb snprintf(buf, sizeof(buf), "?%u", rcode); 138193149Sdougb totext.deconsttext = buf; 139193149Sdougb } else 140193149Sdougb totext.consttext = rcodetext[rcode]; 141193149Sdougb return totext.deconsttext; 142193149Sdougb} 143193149Sdougb 144224092SdougbISC_PLATFORM_NORETURN_PRE static void 145224092Sdougbshow_usage(void) ISC_PLATFORM_NORETURN_POST; 146224092Sdougb 147135446Strhodesstatic void 148135446Strhodesshow_usage(void) { 149135446Strhodes fputs( 150135446Strhodes"Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]\n" 151170222Sdougb" [-R number] [-m flag] hostname [server]\n" 152170222Sdougb" -a is equivalent to -v -t ANY\n" 153135446Strhodes" -c specifies query class for non-IN data\n" 154135446Strhodes" -C compares SOA records on authoritative nameservers\n" 155135446Strhodes" -d is equivalent to -v\n" 156135446Strhodes" -l lists all hosts in a domain, using AXFR\n" 157135446Strhodes" -i IP6.INT reverse lookups\n" 158135446Strhodes" -N changes the number of dots allowed before root lookup is done\n" 159135446Strhodes" -r disables recursive processing\n" 160135446Strhodes" -R specifies number of retries for UDP packets\n" 161170222Sdougb" -s a SERVFAIL response should stop query\n" 162135446Strhodes" -t specifies the query type\n" 163135446Strhodes" -T enables TCP/IP mode\n" 164135446Strhodes" -v enables verbose output\n" 165135446Strhodes" -w specifies to wait forever for a reply\n" 166135446Strhodes" -W specifies how long to wait for a reply\n" 167135446Strhodes" -4 use IPv4 query transport only\n" 168170222Sdougb" -6 use IPv6 query transport only\n" 169170222Sdougb" -m set memory debugging flag (trace|record|usage)\n", stderr); 170135446Strhodes exit(1); 171135446Strhodes} 172135446Strhodes 173135446Strhodesvoid 174135446Strhodesdighost_shutdown(void) { 175135446Strhodes isc_app_shutdown(); 176135446Strhodes} 177135446Strhodes 178135446Strhodesvoid 179135446Strhodesreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query) { 180135446Strhodes isc_time_t now; 181135446Strhodes int diff; 182135446Strhodes 183135446Strhodes if (!short_form) { 184135446Strhodes char fromtext[ISC_SOCKADDR_FORMATSIZE]; 185135446Strhodes isc_sockaddr_format(from, fromtext, sizeof(fromtext)); 186135446Strhodes TIME_NOW(&now); 187135446Strhodes diff = (int) isc_time_microdiff(&now, &query->time_sent); 188135446Strhodes printf("Received %u bytes from %s in %d ms\n", 189135446Strhodes bytes, fromtext, diff/1000); 190135446Strhodes } 191135446Strhodes} 192135446Strhodes 193135446Strhodesvoid 194135446Strhodestrying(char *frm, dig_lookup_t *lookup) { 195135446Strhodes UNUSED(lookup); 196135446Strhodes 197135446Strhodes if (!short_form) 198135446Strhodes printf("Trying \"%s\"\n", frm); 199135446Strhodes} 200135446Strhodes 201135446Strhodesstatic void 202135446Strhodessay_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata, 203135446Strhodes dig_query_t *query) 204135446Strhodes{ 205135446Strhodes isc_buffer_t *b = NULL; 206135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 207135446Strhodes isc_region_t r; 208135446Strhodes isc_result_t result; 209135446Strhodes unsigned int bufsize = BUFSIZ; 210135446Strhodes 211135446Strhodes dns_name_format(name, namestr, sizeof(namestr)); 212135446Strhodes retry: 213135446Strhodes result = isc_buffer_allocate(mctx, &b, bufsize); 214135446Strhodes check_result(result, "isc_buffer_allocate"); 215135446Strhodes result = dns_rdata_totext(rdata, NULL, b); 216135446Strhodes if (result == ISC_R_NOSPACE) { 217135446Strhodes isc_buffer_free(&b); 218135446Strhodes bufsize *= 2; 219135446Strhodes goto retry; 220135446Strhodes } 221135446Strhodes check_result(result, "dns_rdata_totext"); 222135446Strhodes isc_buffer_usedregion(b, &r); 223135446Strhodes if (query->lookup->identify_previous_line) { 224135446Strhodes printf("Nameserver %s:\n\t", 225135446Strhodes query->servname); 226135446Strhodes } 227135446Strhodes printf("%s %s %.*s", namestr, 228135446Strhodes msg, (int)r.length, (char *)r.base); 229135446Strhodes if (query->lookup->identify) { 230135446Strhodes printf(" on server %s", query->servname); 231135446Strhodes } 232135446Strhodes printf("\n"); 233135446Strhodes isc_buffer_free(&b); 234135446Strhodes} 235135446Strhodes#ifdef DIG_SIGCHASE 236135446Strhodes/* Just for compatibility : not use in host program */ 237135446Strhodesisc_result_t 238135446Strhodesprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, 239135446Strhodes isc_buffer_t *target) 240135446Strhodes{ 241135446Strhodes UNUSED(owner_name); 242135446Strhodes UNUSED(rdataset); 243135446Strhodes UNUSED(target); 244135446Strhodes return(ISC_FALSE); 245135446Strhodes} 246135446Strhodes#endif 247135446Strhodesstatic isc_result_t 248135446Strhodesprintsection(dns_message_t *msg, dns_section_t sectionid, 249135446Strhodes const char *section_name, isc_boolean_t headers, 250135446Strhodes dig_query_t *query) 251135446Strhodes{ 252135446Strhodes dns_name_t *name, *print_name; 253135446Strhodes dns_rdataset_t *rdataset; 254135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 255135446Strhodes isc_buffer_t target; 256135446Strhodes isc_result_t result, loopresult; 257135446Strhodes isc_region_t r; 258135446Strhodes dns_name_t empty_name; 259135446Strhodes char t[4096]; 260135446Strhodes isc_boolean_t first; 261135446Strhodes isc_boolean_t no_rdata; 262135446Strhodes 263135446Strhodes if (sectionid == DNS_SECTION_QUESTION) 264135446Strhodes no_rdata = ISC_TRUE; 265135446Strhodes else 266135446Strhodes no_rdata = ISC_FALSE; 267135446Strhodes 268135446Strhodes if (headers) 269135446Strhodes printf(";; %s SECTION:\n", section_name); 270135446Strhodes 271135446Strhodes dns_name_init(&empty_name, NULL); 272135446Strhodes 273135446Strhodes result = dns_message_firstname(msg, sectionid); 274135446Strhodes if (result == ISC_R_NOMORE) 275135446Strhodes return (ISC_R_SUCCESS); 276135446Strhodes else if (result != ISC_R_SUCCESS) 277135446Strhodes return (result); 278135446Strhodes 279135446Strhodes for (;;) { 280135446Strhodes name = NULL; 281135446Strhodes dns_message_currentname(msg, sectionid, &name); 282135446Strhodes 283135446Strhodes isc_buffer_init(&target, t, sizeof(t)); 284135446Strhodes first = ISC_TRUE; 285135446Strhodes print_name = name; 286135446Strhodes 287135446Strhodes for (rdataset = ISC_LIST_HEAD(name->list); 288135446Strhodes rdataset != NULL; 289135446Strhodes rdataset = ISC_LIST_NEXT(rdataset, link)) { 290135446Strhodes if (query->lookup->rdtype == dns_rdatatype_axfr && 291135446Strhodes !((!list_addresses && 292135446Strhodes (list_type == dns_rdatatype_any || 293193149Sdougb rdataset->type == list_type)) || 294135446Strhodes (list_addresses && 295135446Strhodes (rdataset->type == dns_rdatatype_a || 296193149Sdougb rdataset->type == dns_rdatatype_aaaa || 297135446Strhodes rdataset->type == dns_rdatatype_ns || 298135446Strhodes rdataset->type == dns_rdatatype_ptr)))) 299135446Strhodes continue; 300135446Strhodes if (!short_form) { 301135446Strhodes result = dns_rdataset_totext(rdataset, 302135446Strhodes print_name, 303135446Strhodes ISC_FALSE, 304135446Strhodes no_rdata, 305135446Strhodes &target); 306135446Strhodes if (result != ISC_R_SUCCESS) 307135446Strhodes return (result); 308135446Strhodes#ifdef USEINITALWS 309135446Strhodes if (first) { 310135446Strhodes print_name = &empty_name; 311135446Strhodes first = ISC_FALSE; 312135446Strhodes } 313135446Strhodes#else 314135446Strhodes UNUSED(first); /* Shut up compiler. */ 315135446Strhodes#endif 316135446Strhodes } else { 317135446Strhodes loopresult = dns_rdataset_first(rdataset); 318135446Strhodes while (loopresult == ISC_R_SUCCESS) { 319135446Strhodes struct rtype *t; 320135446Strhodes const char *rtt; 321135446Strhodes char typebuf[DNS_RDATATYPE_FORMATSIZE]; 322135446Strhodes char typebuf2[DNS_RDATATYPE_FORMATSIZE 323135446Strhodes + 20]; 324135446Strhodes dns_rdataset_current(rdataset, &rdata); 325135446Strhodes 326135446Strhodes for (t = rtypes; t->text != NULL; t++) { 327135446Strhodes if (t->type == rdata.type) { 328135446Strhodes rtt = t->text; 329135446Strhodes goto found; 330135446Strhodes } 331135446Strhodes } 332135446Strhodes 333135446Strhodes dns_rdatatype_format(rdata.type, 334135446Strhodes typebuf, 335135446Strhodes sizeof(typebuf)); 336135446Strhodes snprintf(typebuf2, sizeof(typebuf2), 337135446Strhodes "has %s record", typebuf); 338135446Strhodes rtt = typebuf2; 339135446Strhodes found: 340135446Strhodes say_message(print_name, rtt, 341135446Strhodes &rdata, query); 342135446Strhodes dns_rdata_reset(&rdata); 343135446Strhodes loopresult = 344135446Strhodes dns_rdataset_next(rdataset); 345135446Strhodes } 346135446Strhodes } 347135446Strhodes } 348135446Strhodes if (!short_form) { 349135446Strhodes isc_buffer_usedregion(&target, &r); 350135446Strhodes if (no_rdata) 351135446Strhodes printf(";%.*s", (int)r.length, 352135446Strhodes (char *)r.base); 353135446Strhodes else 354135446Strhodes printf("%.*s", (int)r.length, (char *)r.base); 355135446Strhodes } 356135446Strhodes 357135446Strhodes result = dns_message_nextname(msg, sectionid); 358135446Strhodes if (result == ISC_R_NOMORE) 359135446Strhodes break; 360135446Strhodes else if (result != ISC_R_SUCCESS) 361135446Strhodes return (result); 362135446Strhodes } 363135446Strhodes 364135446Strhodes return (ISC_R_SUCCESS); 365135446Strhodes} 366135446Strhodes 367135446Strhodesstatic isc_result_t 368135446Strhodesprintrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner, 369135446Strhodes const char *set_name, isc_boolean_t headers) 370135446Strhodes{ 371135446Strhodes isc_buffer_t target; 372135446Strhodes isc_result_t result; 373135446Strhodes isc_region_t r; 374135446Strhodes char t[4096]; 375135446Strhodes 376135446Strhodes UNUSED(msg); 377135446Strhodes if (headers) 378135446Strhodes printf(";; %s SECTION:\n", set_name); 379135446Strhodes 380135446Strhodes isc_buffer_init(&target, t, sizeof(t)); 381135446Strhodes 382135446Strhodes result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE, 383135446Strhodes &target); 384135446Strhodes if (result != ISC_R_SUCCESS) 385135446Strhodes return (result); 386135446Strhodes isc_buffer_usedregion(&target, &r); 387135446Strhodes printf("%.*s", (int)r.length, (char *)r.base); 388135446Strhodes 389135446Strhodes return (ISC_R_SUCCESS); 390135446Strhodes} 391135446Strhodes 392165071Sdougbstatic void 393165071Sdougbchase_cnamechain(dns_message_t *msg, dns_name_t *qname) { 394165071Sdougb isc_result_t result; 395165071Sdougb dns_rdataset_t *rdataset; 396165071Sdougb dns_rdata_cname_t cname; 397165071Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 398165071Sdougb unsigned int i = msg->counts[DNS_SECTION_ANSWER]; 399165071Sdougb 400193149Sdougb while (i-- > 0) { 401165071Sdougb rdataset = NULL; 402165071Sdougb result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 403165071Sdougb dns_rdatatype_cname, 0, NULL, 404165071Sdougb &rdataset); 405165071Sdougb if (result != ISC_R_SUCCESS) 406165071Sdougb return; 407165071Sdougb result = dns_rdataset_first(rdataset); 408165071Sdougb check_result(result, "dns_rdataset_first"); 409165071Sdougb dns_rdata_reset(&rdata); 410165071Sdougb dns_rdataset_current(rdataset, &rdata); 411165071Sdougb result = dns_rdata_tostruct(&rdata, &cname, NULL); 412165071Sdougb check_result(result, "dns_rdata_tostruct"); 413165071Sdougb dns_name_copy(&cname.cname, qname, NULL); 414165071Sdougb dns_rdata_freestruct(&cname); 415165071Sdougb } 416165071Sdougb} 417165071Sdougb 418135446Strhodesisc_result_t 419135446Strhodesprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 420135446Strhodes isc_boolean_t did_flag = ISC_FALSE; 421135446Strhodes dns_rdataset_t *opt, *tsig = NULL; 422135446Strhodes dns_name_t *tsigname; 423135446Strhodes isc_result_t result = ISC_R_SUCCESS; 424135446Strhodes int force_error; 425135446Strhodes 426135446Strhodes UNUSED(headers); 427135446Strhodes 428135446Strhodes /* 429135446Strhodes * We get called multiple times. 430135446Strhodes * Preserve any existing error status. 431135446Strhodes */ 432135446Strhodes force_error = (seen_error == 1) ? 1 : 0; 433135446Strhodes seen_error = 1; 434165071Sdougb if (listed_server && !printed_server) { 435135446Strhodes char sockstr[ISC_SOCKADDR_FORMATSIZE]; 436135446Strhodes 437135446Strhodes printf("Using domain server:\n"); 438143731Sdougb printf("Name: %s\n", query->userarg); 439135446Strhodes isc_sockaddr_format(&query->sockaddr, sockstr, 440135446Strhodes sizeof(sockstr)); 441135446Strhodes printf("Address: %s\n", sockstr); 442135446Strhodes printf("Aliases: \n\n"); 443165071Sdougb printed_server = ISC_TRUE; 444135446Strhodes } 445135446Strhodes 446135446Strhodes if (msg->rcode != 0) { 447135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 448135446Strhodes dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 449254402Serwin 450254402Serwin if (query->lookup->identify_previous_line) 451254402Serwin printf("Nameserver %s:\n\t%s not found: %d(%s)\n", 452254402Serwin query->servname, 453254402Serwin (msg->rcode != dns_rcode_nxdomain) ? namestr : 454254402Serwin query->lookup->textname, msg->rcode, 455254402Serwin rcode_totext(msg->rcode)); 456254402Serwin else 457254402Serwin printf("Host %s not found: %d(%s)\n", 458254402Serwin (msg->rcode != dns_rcode_nxdomain) ? namestr : 459254402Serwin query->lookup->textname, msg->rcode, 460254402Serwin rcode_totext(msg->rcode)); 461135446Strhodes return (ISC_R_SUCCESS); 462135446Strhodes } 463135446Strhodes 464135446Strhodes if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) { 465135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 466135446Strhodes dig_lookup_t *lookup; 467165071Sdougb dns_fixedname_t fixed; 468165071Sdougb dns_name_t *name; 469135446Strhodes 470135446Strhodes /* Add AAAA and MX lookups. */ 471165071Sdougb dns_fixedname_init(&fixed); 472165071Sdougb name = dns_fixedname_name(&fixed); 473165071Sdougb dns_name_copy(query->lookup->name, name, NULL); 474165071Sdougb chase_cnamechain(msg, name); 475165071Sdougb dns_name_format(name, namestr, sizeof(namestr)); 476135446Strhodes lookup = clone_lookup(query->lookup, ISC_FALSE); 477135446Strhodes if (lookup != NULL) { 478135446Strhodes strncpy(lookup->textname, namestr, 479135446Strhodes sizeof(lookup->textname)); 480135446Strhodes lookup->textname[sizeof(lookup->textname)-1] = 0; 481135446Strhodes lookup->rdtype = dns_rdatatype_aaaa; 482193149Sdougb lookup->rdtypeset = ISC_TRUE; 483135446Strhodes lookup->origin = NULL; 484135446Strhodes lookup->retries = tries; 485135446Strhodes ISC_LIST_APPEND(lookup_list, lookup, link); 486135446Strhodes } 487135446Strhodes lookup = clone_lookup(query->lookup, ISC_FALSE); 488135446Strhodes if (lookup != NULL) { 489135446Strhodes strncpy(lookup->textname, namestr, 490135446Strhodes sizeof(lookup->textname)); 491135446Strhodes lookup->textname[sizeof(lookup->textname)-1] = 0; 492135446Strhodes lookup->rdtype = dns_rdatatype_mx; 493193149Sdougb lookup->rdtypeset = ISC_TRUE; 494135446Strhodes lookup->origin = NULL; 495135446Strhodes lookup->retries = tries; 496135446Strhodes ISC_LIST_APPEND(lookup_list, lookup, link); 497135446Strhodes } 498135446Strhodes } 499135446Strhodes 500135446Strhodes if (!short_form) { 501135446Strhodes printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", 502193149Sdougb opcodetext[msg->opcode], rcode_totext(msg->rcode), 503135446Strhodes msg->id); 504135446Strhodes printf(";; flags: "); 505135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { 506135446Strhodes printf("qr"); 507135446Strhodes did_flag = ISC_TRUE; 508135446Strhodes } 509135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { 510135446Strhodes printf("%saa", did_flag ? " " : ""); 511135446Strhodes did_flag = ISC_TRUE; 512135446Strhodes } 513135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { 514135446Strhodes printf("%stc", did_flag ? " " : ""); 515135446Strhodes did_flag = ISC_TRUE; 516135446Strhodes } 517135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { 518135446Strhodes printf("%srd", did_flag ? " " : ""); 519135446Strhodes did_flag = ISC_TRUE; 520135446Strhodes } 521135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { 522135446Strhodes printf("%sra", did_flag ? " " : ""); 523135446Strhodes did_flag = ISC_TRUE; 524135446Strhodes } 525135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { 526135446Strhodes printf("%sad", did_flag ? " " : ""); 527135446Strhodes did_flag = ISC_TRUE; 528135446Strhodes } 529135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { 530135446Strhodes printf("%scd", did_flag ? " " : ""); 531135446Strhodes did_flag = ISC_TRUE; 532225361Sdougb POST(did_flag); 533135446Strhodes } 534135446Strhodes printf("; QUERY: %u, ANSWER: %u, " 535135446Strhodes "AUTHORITY: %u, ADDITIONAL: %u\n", 536135446Strhodes msg->counts[DNS_SECTION_QUESTION], 537135446Strhodes msg->counts[DNS_SECTION_ANSWER], 538135446Strhodes msg->counts[DNS_SECTION_AUTHORITY], 539135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL]); 540135446Strhodes opt = dns_message_getopt(msg); 541135446Strhodes if (opt != NULL) 542135446Strhodes printf(";; EDNS: version: %u, udp=%u\n", 543135446Strhodes (unsigned int)((opt->ttl & 0x00ff0000) >> 16), 544135446Strhodes (unsigned int)opt->rdclass); 545135446Strhodes tsigname = NULL; 546135446Strhodes tsig = dns_message_gettsig(msg, &tsigname); 547135446Strhodes if (tsig != NULL) 548135446Strhodes printf(";; PSEUDOSECTIONS: TSIG\n"); 549135446Strhodes } 550135446Strhodes if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) && 551135446Strhodes !short_form) { 552135446Strhodes printf("\n"); 553135446Strhodes result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION", 554135446Strhodes ISC_TRUE, query); 555135446Strhodes if (result != ISC_R_SUCCESS) 556135446Strhodes return (result); 557135446Strhodes } 558135446Strhodes if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { 559135446Strhodes if (!short_form) 560135446Strhodes printf("\n"); 561135446Strhodes result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER", 562135446Strhodes ISC_TF(!short_form), query); 563135446Strhodes if (result != ISC_R_SUCCESS) 564135446Strhodes return (result); 565135446Strhodes } 566135446Strhodes 567135446Strhodes if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) && 568135446Strhodes !short_form) { 569135446Strhodes printf("\n"); 570135446Strhodes result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY", 571135446Strhodes ISC_TRUE, query); 572135446Strhodes if (result != ISC_R_SUCCESS) 573135446Strhodes return (result); 574135446Strhodes } 575135446Strhodes if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) && 576135446Strhodes !short_form) { 577135446Strhodes printf("\n"); 578135446Strhodes result = printsection(msg, DNS_SECTION_ADDITIONAL, 579135446Strhodes "ADDITIONAL", ISC_TRUE, query); 580135446Strhodes if (result != ISC_R_SUCCESS) 581135446Strhodes return (result); 582135446Strhodes } 583135446Strhodes if ((tsig != NULL) && !short_form) { 584135446Strhodes printf("\n"); 585135446Strhodes result = printrdata(msg, tsig, tsigname, 586135446Strhodes "PSEUDOSECTION TSIG", ISC_TRUE); 587135446Strhodes if (result != ISC_R_SUCCESS) 588135446Strhodes return (result); 589135446Strhodes } 590135446Strhodes if (!short_form) 591135446Strhodes printf("\n"); 592135446Strhodes 593135446Strhodes if (short_form && !default_lookups && 594135446Strhodes ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { 595135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 596135446Strhodes char typestr[DNS_RDATATYPE_FORMATSIZE]; 597135446Strhodes dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 598135446Strhodes dns_rdatatype_format(query->lookup->rdtype, typestr, 599135446Strhodes sizeof(typestr)); 600135446Strhodes printf("%s has no %s record\n", namestr, typestr); 601135446Strhodes } 602135446Strhodes seen_error = force_error; 603135446Strhodes return (result); 604135446Strhodes} 605135446Strhodes 606170222Sdougbstatic const char * optstring = "46ac:dilnm:rst:vwCDN:R:TW:"; 607170222Sdougb 608135446Strhodesstatic void 609170222Sdougbpre_parse_args(int argc, char **argv) { 610170222Sdougb int c; 611170222Sdougb 612170222Sdougb while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { 613170222Sdougb switch (c) { 614170222Sdougb case 'm': 615174187Sdougb memdebugging = ISC_TRUE; 616170222Sdougb if (strcasecmp("trace", isc_commandline_argument) == 0) 617170222Sdougb isc_mem_debugging |= ISC_MEM_DEBUGTRACE; 618170222Sdougb else if (!strcasecmp("record", 619170222Sdougb isc_commandline_argument) == 0) 620170222Sdougb isc_mem_debugging |= ISC_MEM_DEBUGRECORD; 621170222Sdougb else if (strcasecmp("usage", 622170222Sdougb isc_commandline_argument) == 0) 623170222Sdougb isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; 624170222Sdougb break; 625170222Sdougb 626170222Sdougb case '4': break; 627170222Sdougb case '6': break; 628170222Sdougb case 'a': break; 629170222Sdougb case 'c': break; 630170222Sdougb case 'd': break; 631170222Sdougb case 'i': break; 632170222Sdougb case 'l': break; 633170222Sdougb case 'n': break; 634170222Sdougb case 'r': break; 635170222Sdougb case 's': break; 636170222Sdougb case 't': break; 637170222Sdougb case 'v': break; 638170222Sdougb case 'w': break; 639170222Sdougb case 'C': break; 640216175Sdougb case 'D': 641262706Serwin if (debugging) 642262706Serwin debugtiming = ISC_TRUE; 643216175Sdougb debugging = ISC_TRUE; 644216175Sdougb break; 645170222Sdougb case 'N': break; 646170222Sdougb case 'R': break; 647170222Sdougb case 'T': break; 648170222Sdougb case 'W': break; 649170222Sdougb default: 650170222Sdougb show_usage(); 651170222Sdougb } 652170222Sdougb } 653170222Sdougb isc_commandline_reset = ISC_TRUE; 654170222Sdougb isc_commandline_index = 1; 655170222Sdougb} 656170222Sdougb 657170222Sdougbstatic void 658135446Strhodesparse_args(isc_boolean_t is_batchfile, int argc, char **argv) { 659135446Strhodes char hostname[MXNAME]; 660135446Strhodes dig_lookup_t *lookup; 661135446Strhodes int c; 662135446Strhodes char store[MXNAME]; 663135446Strhodes isc_textregion_t tr; 664135446Strhodes isc_result_t result = ISC_R_SUCCESS; 665135446Strhodes dns_rdatatype_t rdtype; 666135446Strhodes dns_rdataclass_t rdclass; 667135446Strhodes isc_uint32_t serial = 0; 668135446Strhodes 669135446Strhodes UNUSED(is_batchfile); 670135446Strhodes 671135446Strhodes lookup = make_empty_lookup(); 672135446Strhodes 673170222Sdougb lookup->servfail_stops = ISC_FALSE; 674170222Sdougb lookup->comments = ISC_FALSE; 675170222Sdougb 676170222Sdougb while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { 677135446Strhodes switch (c) { 678135446Strhodes case 'l': 679135446Strhodes lookup->tcp_mode = ISC_TRUE; 680135446Strhodes lookup->rdtype = dns_rdatatype_axfr; 681135446Strhodes lookup->rdtypeset = ISC_TRUE; 682135446Strhodes fatalexit = 3; 683135446Strhodes break; 684135446Strhodes case 'v': 685135446Strhodes case 'd': 686135446Strhodes short_form = ISC_FALSE; 687135446Strhodes break; 688135446Strhodes case 'r': 689135446Strhodes lookup->recurse = ISC_FALSE; 690135446Strhodes break; 691135446Strhodes case 't': 692135446Strhodes if (strncasecmp(isc_commandline_argument, 693135446Strhodes "ixfr=", 5) == 0) { 694135446Strhodes rdtype = dns_rdatatype_ixfr; 695135446Strhodes /* XXXMPA add error checking */ 696135446Strhodes serial = strtoul(isc_commandline_argument + 5, 697135446Strhodes NULL, 10); 698135446Strhodes result = ISC_R_SUCCESS; 699135446Strhodes } else { 700135446Strhodes tr.base = isc_commandline_argument; 701135446Strhodes tr.length = strlen(isc_commandline_argument); 702135446Strhodes result = dns_rdatatype_fromtext(&rdtype, 703135446Strhodes (isc_textregion_t *)&tr); 704135446Strhodes } 705135446Strhodes 706135446Strhodes if (result != ISC_R_SUCCESS) { 707135446Strhodes fatalexit = 2; 708135446Strhodes fatal("invalid type: %s\n", 709135446Strhodes isc_commandline_argument); 710135446Strhodes } 711135446Strhodes if (!lookup->rdtypeset || 712135446Strhodes lookup->rdtype != dns_rdatatype_axfr) 713135446Strhodes lookup->rdtype = rdtype; 714135446Strhodes lookup->rdtypeset = ISC_TRUE; 715174187Sdougb#ifdef WITH_IDN 716174187Sdougb idnoptions = 0; 717174187Sdougb#endif 718135446Strhodes if (rdtype == dns_rdatatype_axfr) { 719135446Strhodes /* -l -t any -v */ 720135446Strhodes list_type = dns_rdatatype_any; 721135446Strhodes short_form = ISC_FALSE; 722135446Strhodes lookup->tcp_mode = ISC_TRUE; 723135446Strhodes } else if (rdtype == dns_rdatatype_ixfr) { 724135446Strhodes lookup->ixfr_serial = serial; 725193149Sdougb lookup->tcp_mode = ISC_TRUE; 726135446Strhodes list_type = rdtype; 727174187Sdougb#ifdef WITH_IDN 728174187Sdougb } else if (rdtype == dns_rdatatype_a || 729174187Sdougb rdtype == dns_rdatatype_aaaa || 730174187Sdougb rdtype == dns_rdatatype_mx) { 731174187Sdougb idnoptions = IDN_ASCCHECK; 732174187Sdougb list_type = rdtype; 733174187Sdougb#endif 734135446Strhodes } else 735135446Strhodes list_type = rdtype; 736135446Strhodes list_addresses = ISC_FALSE; 737153816Sdougb default_lookups = ISC_FALSE; 738135446Strhodes break; 739135446Strhodes case 'c': 740135446Strhodes tr.base = isc_commandline_argument; 741135446Strhodes tr.length = strlen(isc_commandline_argument); 742135446Strhodes result = dns_rdataclass_fromtext(&rdclass, 743135446Strhodes (isc_textregion_t *)&tr); 744135446Strhodes 745135446Strhodes if (result != ISC_R_SUCCESS) { 746135446Strhodes fatalexit = 2; 747135446Strhodes fatal("invalid class: %s\n", 748135446Strhodes isc_commandline_argument); 749135446Strhodes } else { 750135446Strhodes lookup->rdclass = rdclass; 751135446Strhodes lookup->rdclassset = ISC_TRUE; 752135446Strhodes } 753135446Strhodes default_lookups = ISC_FALSE; 754135446Strhodes break; 755135446Strhodes case 'a': 756135446Strhodes if (!lookup->rdtypeset || 757135446Strhodes lookup->rdtype != dns_rdatatype_axfr) 758135446Strhodes lookup->rdtype = dns_rdatatype_any; 759135446Strhodes list_type = dns_rdatatype_any; 760135446Strhodes list_addresses = ISC_FALSE; 761135446Strhodes lookup->rdtypeset = ISC_TRUE; 762135446Strhodes short_form = ISC_FALSE; 763135446Strhodes default_lookups = ISC_FALSE; 764135446Strhodes break; 765135446Strhodes case 'i': 766135446Strhodes lookup->ip6_int = ISC_TRUE; 767135446Strhodes break; 768135446Strhodes case 'n': 769135446Strhodes /* deprecated */ 770135446Strhodes break; 771170222Sdougb case 'm': 772170222Sdougb /* Handled by pre_parse_args(). */ 773170222Sdougb break; 774135446Strhodes case 'w': 775135446Strhodes /* 776135446Strhodes * The timer routines are coded such that 777135446Strhodes * timeout==MAXINT doesn't enable the timer 778135446Strhodes */ 779135446Strhodes timeout = INT_MAX; 780135446Strhodes break; 781135446Strhodes case 'W': 782135446Strhodes timeout = atoi(isc_commandline_argument); 783135446Strhodes if (timeout < 1) 784135446Strhodes timeout = 1; 785135446Strhodes break; 786135446Strhodes case 'R': 787135446Strhodes tries = atoi(isc_commandline_argument) + 1; 788135446Strhodes if (tries < 2) 789135446Strhodes tries = 2; 790135446Strhodes break; 791135446Strhodes case 'T': 792135446Strhodes lookup->tcp_mode = ISC_TRUE; 793135446Strhodes break; 794135446Strhodes case 'C': 795135446Strhodes debug("showing all SOAs"); 796135446Strhodes lookup->rdtype = dns_rdatatype_ns; 797135446Strhodes lookup->rdtypeset = ISC_TRUE; 798135446Strhodes lookup->rdclass = dns_rdataclass_in; 799135446Strhodes lookup->rdclassset = ISC_TRUE; 800135446Strhodes lookup->ns_search_only = ISC_TRUE; 801135446Strhodes lookup->trace_root = ISC_TRUE; 802135446Strhodes lookup->identify_previous_line = ISC_TRUE; 803135446Strhodes default_lookups = ISC_FALSE; 804135446Strhodes break; 805135446Strhodes case 'N': 806135446Strhodes debug("setting NDOTS to %s", 807135446Strhodes isc_commandline_argument); 808135446Strhodes ndots = atoi(isc_commandline_argument); 809135446Strhodes break; 810135446Strhodes case 'D': 811216175Sdougb /* Handled by pre_parse_args(). */ 812135446Strhodes break; 813135446Strhodes case '4': 814135446Strhodes if (have_ipv4) { 815135446Strhodes isc_net_disableipv6(); 816135446Strhodes have_ipv6 = ISC_FALSE; 817135446Strhodes } else 818135446Strhodes fatal("can't find IPv4 networking"); 819135446Strhodes break; 820135446Strhodes case '6': 821135446Strhodes if (have_ipv6) { 822135446Strhodes isc_net_disableipv4(); 823135446Strhodes have_ipv4 = ISC_FALSE; 824135446Strhodes } else 825135446Strhodes fatal("can't find IPv6 networking"); 826135446Strhodes break; 827170222Sdougb case 's': 828170222Sdougb lookup->servfail_stops = ISC_TRUE; 829170222Sdougb break; 830135446Strhodes } 831135446Strhodes } 832135446Strhodes 833135446Strhodes lookup->retries = tries; 834135446Strhodes 835135446Strhodes if (isc_commandline_index >= argc) 836135446Strhodes show_usage(); 837135446Strhodes 838225361Sdougb strlcpy(hostname, argv[isc_commandline_index], sizeof(hostname)); 839225361Sdougb 840135446Strhodes if (argc > isc_commandline_index + 1) { 841135446Strhodes set_nameserver(argv[isc_commandline_index+1]); 842135446Strhodes debug("server is %s", argv[isc_commandline_index+1]); 843135446Strhodes listed_server = ISC_TRUE; 844170222Sdougb } else 845170222Sdougb check_ra = ISC_TRUE; 846135446Strhodes 847135446Strhodes lookup->pending = ISC_FALSE; 848135446Strhodes if (get_reverse(store, sizeof(store), hostname, 849135446Strhodes lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) { 850135446Strhodes strncpy(lookup->textname, store, sizeof(lookup->textname)); 851135446Strhodes lookup->textname[sizeof(lookup->textname)-1] = 0; 852135446Strhodes lookup->rdtype = dns_rdatatype_ptr; 853135446Strhodes lookup->rdtypeset = ISC_TRUE; 854135446Strhodes default_lookups = ISC_FALSE; 855135446Strhodes } else { 856135446Strhodes strncpy(lookup->textname, hostname, sizeof(lookup->textname)); 857135446Strhodes lookup->textname[sizeof(lookup->textname)-1]=0; 858204619Sdougb usesearch = ISC_TRUE; 859135446Strhodes } 860135446Strhodes lookup->new_search = ISC_TRUE; 861135446Strhodes ISC_LIST_APPEND(lookup_list, lookup, link); 862135446Strhodes} 863135446Strhodes 864135446Strhodesint 865135446Strhodesmain(int argc, char **argv) { 866135446Strhodes isc_result_t result; 867135446Strhodes 868135446Strhodes tries = 2; 869135446Strhodes 870135446Strhodes ISC_LIST_INIT(lookup_list); 871135446Strhodes ISC_LIST_INIT(server_list); 872135446Strhodes ISC_LIST_INIT(search_list); 873193149Sdougb 874135446Strhodes fatalexit = 1; 875174187Sdougb#ifdef WITH_IDN 876174187Sdougb idnoptions = IDN_ASCCHECK; 877174187Sdougb#endif 878135446Strhodes 879135446Strhodes debug("main()"); 880135446Strhodes progname = argv[0]; 881170222Sdougb pre_parse_args(argc, argv); 882135446Strhodes result = isc_app_start(); 883135446Strhodes check_result(result, "isc_app_start"); 884135446Strhodes setup_libs(); 885135446Strhodes parse_args(ISC_FALSE, argc, argv); 886135446Strhodes setup_system(); 887135446Strhodes result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); 888135446Strhodes check_result(result, "isc_app_onrun"); 889135446Strhodes isc_app_run(); 890135446Strhodes cancel_all(); 891135446Strhodes destroy_libs(); 892135446Strhodes isc_app_finish(); 893135446Strhodes return ((seen_error == 0) ? 0 : 1); 894135446Strhodes} 895