1135446Strhodes/* 2254402Serwin * Copyright (C) 2004-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: dig.c,v 1.245 2011/12/07 17:23:28 each Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes#include <stdlib.h> 24135446Strhodes#include <time.h> 25135446Strhodes#include <ctype.h> 26135446Strhodes 27135446Strhodes#include <isc/app.h> 28135446Strhodes#include <isc/netaddr.h> 29135446Strhodes#include <isc/parseint.h> 30135446Strhodes#include <isc/print.h> 31135446Strhodes#include <isc/string.h> 32135446Strhodes#include <isc/util.h> 33135446Strhodes#include <isc/task.h> 34135446Strhodes 35135446Strhodes#include <dns/byaddr.h> 36135446Strhodes#include <dns/fixedname.h> 37135446Strhodes#include <dns/masterdump.h> 38135446Strhodes#include <dns/message.h> 39135446Strhodes#include <dns/name.h> 40135446Strhodes#include <dns/rdata.h> 41135446Strhodes#include <dns/rdataset.h> 42135446Strhodes#include <dns/rdatatype.h> 43135446Strhodes#include <dns/rdataclass.h> 44135446Strhodes#include <dns/result.h> 45170222Sdougb#include <dns/tsig.h> 46135446Strhodes 47135446Strhodes#include <dig/dig.h> 48135446Strhodes 49135446Strhodes#define ADD_STRING(b, s) { \ 50135446Strhodes if (strlen(s) >= isc_buffer_availablelength(b)) \ 51186462Sdougb return (ISC_R_NOSPACE); \ 52135446Strhodes else \ 53135446Strhodes isc_buffer_putstr(b, s); \ 54135446Strhodes} 55135446Strhodes 56143731Sdougb#define DIG_MAX_ADDRESSES 20 57135446Strhodes 58135446Strhodesdig_lookup_t *default_lookup = NULL; 59135446Strhodes 60135446Strhodesstatic char *batchname = NULL; 61135446Strhodesstatic FILE *batchfp = NULL; 62135446Strhodesstatic char *argv0; 63143731Sdougbstatic int addresscount = 0; 64135446Strhodes 65135446Strhodesstatic char domainopt[DNS_NAME_MAXTEXT]; 66135446Strhodes 67135446Strhodesstatic isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE, 68135446Strhodes ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE, 69224092Sdougb multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE, 70254897Serwin onesoa = ISC_FALSE, rrcomments = ISC_FALSE; 71254897Serwinstatic isc_uint32_t splitwidth = 0xffffffff; 72135446Strhodes 73170222Sdougb/*% opcode text */ 74186462Sdougbstatic const char * const opcodetext[] = { 75135446Strhodes "QUERY", 76135446Strhodes "IQUERY", 77135446Strhodes "STATUS", 78135446Strhodes "RESERVED3", 79135446Strhodes "NOTIFY", 80135446Strhodes "UPDATE", 81135446Strhodes "RESERVED6", 82135446Strhodes "RESERVED7", 83135446Strhodes "RESERVED8", 84135446Strhodes "RESERVED9", 85135446Strhodes "RESERVED10", 86135446Strhodes "RESERVED11", 87135446Strhodes "RESERVED12", 88135446Strhodes "RESERVED13", 89135446Strhodes "RESERVED14", 90135446Strhodes "RESERVED15" 91135446Strhodes}; 92135446Strhodes 93170222Sdougb/*% return code text */ 94186462Sdougbstatic const char * const rcodetext[] = { 95135446Strhodes "NOERROR", 96135446Strhodes "FORMERR", 97135446Strhodes "SERVFAIL", 98135446Strhodes "NXDOMAIN", 99135446Strhodes "NOTIMP", 100135446Strhodes "REFUSED", 101135446Strhodes "YXDOMAIN", 102135446Strhodes "YXRRSET", 103135446Strhodes "NXRRSET", 104135446Strhodes "NOTAUTH", 105135446Strhodes "NOTZONE", 106135446Strhodes "RESERVED11", 107135446Strhodes "RESERVED12", 108135446Strhodes "RESERVED13", 109135446Strhodes "RESERVED14", 110135446Strhodes "RESERVED15", 111135446Strhodes "BADVERS" 112135446Strhodes}; 113135446Strhodes 114193149Sdougb/*% safe rcodetext[] */ 115193149Sdougbstatic char * 116193149Sdougbrcode_totext(dns_rcode_t rcode) 117193149Sdougb{ 118193149Sdougb static char buf[sizeof("?65535")]; 119193149Sdougb union { 120193149Sdougb const char *consttext; 121193149Sdougb char *deconsttext; 122193149Sdougb } totext; 123193149Sdougb 124193149Sdougb if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 125193149Sdougb snprintf(buf, sizeof(buf), "?%u", rcode); 126193149Sdougb totext.deconsttext = buf; 127193149Sdougb } else 128193149Sdougb totext.consttext = rcodetext[rcode]; 129193149Sdougb return totext.deconsttext; 130193149Sdougb} 131193149Sdougb 132170222Sdougb/*% print usage */ 133135446Strhodesstatic void 134135446Strhodesprint_usage(FILE *fp) { 135135446Strhodes fputs( 136135446Strhodes"Usage: dig [@global-server] [domain] [q-type] [q-class] {q-opt}\n" 137135446Strhodes" {global-d-opt} host [@local-server] {local-d-opt}\n" 138135446Strhodes" [ host [@local-server] {local-d-opt} [...]]\n", fp); 139135446Strhodes} 140135446Strhodes 141224092SdougbISC_PLATFORM_NORETURN_PRE static void 142224092Sdougbusage(void) ISC_PLATFORM_NORETURN_POST; 143224092Sdougb 144135446Strhodesstatic void 145135446Strhodesusage(void) { 146135446Strhodes print_usage(stderr); 147135446Strhodes fputs("\nUse \"dig -h\" (or \"dig -h | more\") " 148135446Strhodes "for complete list of options\n", stderr); 149135446Strhodes exit(1); 150135446Strhodes} 151135446Strhodes 152170222Sdougb/*% version */ 153135446Strhodesstatic void 154135446Strhodesversion(void) { 155135446Strhodes fputs("DiG " VERSION "\n", stderr); 156135446Strhodes} 157135446Strhodes 158170222Sdougb/*% help */ 159135446Strhodesstatic void 160135446Strhodeshelp(void) { 161135446Strhodes print_usage(stdout); 162135446Strhodes fputs( 163135446Strhodes"Where: domain is in the Domain Name System\n" 164135446Strhodes" q-class is one of (in,hs,ch,...) [default: in]\n" 165135446Strhodes" q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n" 166135446Strhodes" (Use ixfr=version for type ixfr)\n" 167135446Strhodes" q-opt is one of:\n" 168186462Sdougb" -x dot-notation (shortcut for reverse lookups)\n" 169186462Sdougb" -i (use IP6.INT for IPv6 reverse lookups)\n" 170135446Strhodes" -f filename (batch mode)\n" 171135446Strhodes" -b address[#port] (bind to source address/port)\n" 172135446Strhodes" -p port (specify port number)\n" 173170222Sdougb" -q name (specify query name)\n" 174135446Strhodes" -t type (specify query type)\n" 175135446Strhodes" -c class (specify query class)\n" 176135446Strhodes" -k keyfile (specify tsig key file)\n" 177170222Sdougb" -y [hmac:]name:key (specify named base64 tsig key)\n" 178135446Strhodes" -4 (use IPv4 query transport only)\n" 179135446Strhodes" -6 (use IPv6 query transport only)\n" 180186462Sdougb" -m (enable memory usage debugging)\n" 181135446Strhodes" d-opt is of the form +keyword[=value], where keyword is:\n" 182135446Strhodes" +[no]vc (TCP mode)\n" 183135446Strhodes" +[no]tcp (TCP mode, alternate syntax)\n" 184135446Strhodes" +time=### (Set query timeout) [5]\n" 185135446Strhodes" +tries=### (Set number of UDP attempts) [3]\n" 186135446Strhodes" +retry=### (Set number of UDP retries) [2]\n" 187135446Strhodes" +domain=### (Set default domainname)\n" 188135446Strhodes" +bufsize=### (Set EDNS0 Max UDP packet size)\n" 189135446Strhodes" +ndots=### (Set NDOTS value)\n" 190254402Serwin" +[no]edns[=###] (Set EDNS version) [0]\n" 191135446Strhodes" +[no]search (Set whether to use searchlist)\n" 192170222Sdougb" +[no]showsearch (Search with intermediate results)\n" 193135446Strhodes" +[no]defname (Ditto)\n" 194135446Strhodes" +[no]recurse (Recursive mode)\n" 195135446Strhodes" +[no]ignore (Don't revert to TCP for TC responses.)" 196135446Strhodes"\n" 197135446Strhodes" +[no]fail (Don't try next server on SERVFAIL)\n" 198135446Strhodes" +[no]besteffort (Try to parse even illegal messages)\n" 199135446Strhodes" +[no]aaonly (Set AA flag in query (+[no]aaflag))\n" 200135446Strhodes" +[no]adflag (Set AD flag in query)\n" 201135446Strhodes" +[no]cdflag (Set CD flag in query)\n" 202135446Strhodes" +[no]cl (Control display of class in records)\n" 203135446Strhodes" +[no]cmd (Control display of command line)\n" 204135446Strhodes" +[no]comments (Control display of comment lines)\n" 205254897Serwin" +[no]rrcomments (Control display of per-record " 206254897Serwin "comments)\n" 207135446Strhodes" +[no]question (Control display of question)\n" 208135446Strhodes" +[no]answer (Control display of answer)\n" 209135446Strhodes" +[no]authority (Control display of authority)\n" 210135446Strhodes" +[no]additional (Control display of additional)\n" 211135446Strhodes" +[no]stats (Control display of statistics)\n" 212135446Strhodes" +[no]short (Disable everything except short\n" 213135446Strhodes" form of answer)\n" 214135446Strhodes" +[no]ttlid (Control display of ttls in records)\n" 215135446Strhodes" +[no]all (Set or clear all display flags)\n" 216135446Strhodes" +[no]qr (Print question before sending)\n" 217135446Strhodes" +[no]nssearch (Search all authoritative nameservers)\n" 218135446Strhodes" +[no]identify (ID responders in short answers)\n" 219254897Serwin" +[no]trace (Trace delegation down from root [+dnssec])\n" 220135446Strhodes" +[no]dnssec (Request DNSSEC records)\n" 221193149Sdougb" +[no]nsid (Request Name Server ID)\n" 222135446Strhodes#ifdef DIG_SIGCHASE 223135446Strhodes" +[no]sigchase (Chase DNSSEC signatures)\n" 224135446Strhodes" +trusted-key=#### (Trusted Key when chasing DNSSEC sigs)\n" 225135446Strhodes#if DIG_SIGCHASE_TD 226135446Strhodes" +[no]topdown (Do DNSSEC validation top down mode)\n" 227135446Strhodes#endif 228135446Strhodes#endif 229254897Serwin" +[no]split=## (Split hex/base64 fields into chunks)\n" 230135446Strhodes" +[no]multiline (Print records in an expanded format)\n" 231224092Sdougb" +[no]onesoa (AXFR prints only one soa record)\n" 232262706Serwin" +[no]keepopen (Keep the TCP socket open between queries)\n" 233135446Strhodes" global d-opts and servers (before host name) affect all queries.\n" 234135446Strhodes" local d-opts and servers (after host name) affect only that lookup.\n" 235135446Strhodes" -h (print help and exit)\n" 236135446Strhodes" -v (print version and exit)\n", 237135446Strhodes stdout); 238135446Strhodes} 239135446Strhodes 240170222Sdougb/*% 241135446Strhodes * Callback from dighost.c to print the received message. 242135446Strhodes */ 243135446Strhodesvoid 244135446Strhodesreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query) { 245135446Strhodes isc_uint64_t diff; 246135446Strhodes isc_time_t now; 247135446Strhodes time_t tnow; 248254402Serwin struct tm tmnow; 249254402Serwin char time_str[100]; 250135446Strhodes char fromtext[ISC_SOCKADDR_FORMATSIZE]; 251135446Strhodes 252135446Strhodes isc_sockaddr_format(from, fromtext, sizeof(fromtext)); 253135446Strhodes 254135446Strhodes TIME_NOW(&now); 255135446Strhodes 256135446Strhodes if (query->lookup->stats && !short_form) { 257135446Strhodes diff = isc_time_microdiff(&now, &query->time_sent); 258135446Strhodes printf(";; Query time: %ld msec\n", (long int)diff/1000); 259135446Strhodes printf(";; SERVER: %s(%s)\n", fromtext, query->servname); 260135446Strhodes time(&tnow); 261254402Serwin tmnow = *localtime(&tnow); 262254402Serwin if (strftime(time_str, sizeof(time_str), 263254402Serwin "%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U) 264254402Serwin printf(";; WHEN: %s\n", time_str); 265135446Strhodes if (query->lookup->doing_xfr) { 266170222Sdougb printf(";; XFR size: %u records (messages %u, " 267170222Sdougb "bytes %" ISC_PRINT_QUADFORMAT "u)\n", 268170222Sdougb query->rr_count, query->msg_count, 269170222Sdougb query->byte_count); 270135446Strhodes } else { 271170222Sdougb printf(";; MSG SIZE rcvd: %u\n", bytes); 272135446Strhodes } 273135446Strhodes if (key != NULL) { 274135446Strhodes if (!validated) 275135446Strhodes puts(";; WARNING -- Some TSIG could not " 276135446Strhodes "be validated"); 277135446Strhodes } 278135446Strhodes if ((key == NULL) && (keysecret[0] != 0)) { 279135446Strhodes puts(";; WARNING -- TSIG key was not used."); 280135446Strhodes } 281135446Strhodes puts(""); 282135446Strhodes } else if (query->lookup->identify && !short_form) { 283135446Strhodes diff = isc_time_microdiff(&now, &query->time_sent); 284170222Sdougb printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes " 285170222Sdougb "from %s(%s) in %d ms\n\n", 286170222Sdougb query->lookup->doing_xfr ? 287170222Sdougb query->byte_count : (isc_uint64_t)bytes, 288254402Serwin fromtext, query->userarg, 289135446Strhodes (int)diff/1000); 290135446Strhodes } 291135446Strhodes} 292135446Strhodes 293135446Strhodes/* 294135446Strhodes * Callback from dighost.c to print that it is trying a server. 295135446Strhodes * Not used in dig. 296135446Strhodes * XXX print_trying 297135446Strhodes */ 298135446Strhodesvoid 299135446Strhodestrying(char *frm, dig_lookup_t *lookup) { 300135446Strhodes UNUSED(frm); 301135446Strhodes UNUSED(lookup); 302135446Strhodes} 303135446Strhodes 304170222Sdougb/*% 305135446Strhodes * Internal print routine used to print short form replies. 306135446Strhodes */ 307135446Strhodesstatic isc_result_t 308135446Strhodessay_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { 309135446Strhodes isc_result_t result; 310135446Strhodes isc_uint64_t diff; 311135446Strhodes isc_time_t now; 312135446Strhodes char store[sizeof("12345678901234567890")]; 313135446Strhodes 314135446Strhodes if (query->lookup->trace || query->lookup->ns_search_only) { 315135446Strhodes result = dns_rdatatype_totext(rdata->type, buf); 316135446Strhodes if (result != ISC_R_SUCCESS) 317135446Strhodes return (result); 318135446Strhodes ADD_STRING(buf, " "); 319135446Strhodes } 320135446Strhodes result = dns_rdata_totext(rdata, NULL, buf); 321218384Sdougb if (result == ISC_R_NOSPACE) 322218384Sdougb return (result); 323135446Strhodes check_result(result, "dns_rdata_totext"); 324135446Strhodes if (query->lookup->identify) { 325135446Strhodes TIME_NOW(&now); 326135446Strhodes diff = isc_time_microdiff(&now, &query->time_sent); 327135446Strhodes ADD_STRING(buf, " from server "); 328135446Strhodes ADD_STRING(buf, query->servname); 329135446Strhodes snprintf(store, 19, " in %d ms.", (int)diff/1000); 330135446Strhodes ADD_STRING(buf, store); 331135446Strhodes } 332135446Strhodes ADD_STRING(buf, "\n"); 333135446Strhodes return (ISC_R_SUCCESS); 334135446Strhodes} 335135446Strhodes 336170222Sdougb/*% 337135446Strhodes * short_form message print handler. Calls above say_message() 338135446Strhodes */ 339135446Strhodesstatic isc_result_t 340135446Strhodesshort_answer(dns_message_t *msg, dns_messagetextflag_t flags, 341135446Strhodes isc_buffer_t *buf, dig_query_t *query) 342135446Strhodes{ 343135446Strhodes dns_name_t *name; 344135446Strhodes dns_rdataset_t *rdataset; 345135446Strhodes isc_result_t result, loopresult; 346135446Strhodes dns_name_t empty_name; 347135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 348135446Strhodes 349135446Strhodes UNUSED(flags); 350135446Strhodes 351135446Strhodes dns_name_init(&empty_name, NULL); 352135446Strhodes result = dns_message_firstname(msg, DNS_SECTION_ANSWER); 353135446Strhodes if (result == ISC_R_NOMORE) 354135446Strhodes return (ISC_R_SUCCESS); 355135446Strhodes else if (result != ISC_R_SUCCESS) 356135446Strhodes return (result); 357135446Strhodes 358135446Strhodes for (;;) { 359135446Strhodes name = NULL; 360135446Strhodes dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); 361135446Strhodes 362135446Strhodes for (rdataset = ISC_LIST_HEAD(name->list); 363135446Strhodes rdataset != NULL; 364135446Strhodes rdataset = ISC_LIST_NEXT(rdataset, link)) { 365135446Strhodes loopresult = dns_rdataset_first(rdataset); 366135446Strhodes while (loopresult == ISC_R_SUCCESS) { 367135446Strhodes dns_rdataset_current(rdataset, &rdata); 368135446Strhodes result = say_message(&rdata, query, 369135446Strhodes buf); 370218384Sdougb if (result == ISC_R_NOSPACE) 371218384Sdougb return (result); 372135446Strhodes check_result(result, "say_message"); 373135446Strhodes loopresult = dns_rdataset_next(rdataset); 374135446Strhodes dns_rdata_reset(&rdata); 375135446Strhodes } 376135446Strhodes } 377135446Strhodes result = dns_message_nextname(msg, DNS_SECTION_ANSWER); 378135446Strhodes if (result == ISC_R_NOMORE) 379135446Strhodes break; 380135446Strhodes else if (result != ISC_R_SUCCESS) 381135446Strhodes return (result); 382135446Strhodes } 383135446Strhodes 384135446Strhodes return (ISC_R_SUCCESS); 385135446Strhodes} 386135446Strhodes#ifdef DIG_SIGCHASE 387135446Strhodesisc_result_t 388135446Strhodesprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, 389135446Strhodes isc_buffer_t *target) 390135446Strhodes{ 391135446Strhodes isc_result_t result; 392135446Strhodes dns_master_style_t *style = NULL; 393135446Strhodes unsigned int styleflags = 0; 394135446Strhodes 395135446Strhodes if (rdataset == NULL || owner_name == NULL || target == NULL) 396135446Strhodes return(ISC_FALSE); 397135446Strhodes 398135446Strhodes styleflags |= DNS_STYLEFLAG_REL_OWNER; 399135446Strhodes if (nottl) 400135446Strhodes styleflags |= DNS_STYLEFLAG_NO_TTL; 401135446Strhodes if (noclass) 402135446Strhodes styleflags |= DNS_STYLEFLAG_NO_CLASS; 403254897Serwin if (rrcomments) 404254897Serwin styleflags |= DNS_STYLEFLAG_RRCOMMENT; 405135446Strhodes if (multiline) { 406135446Strhodes styleflags |= DNS_STYLEFLAG_OMIT_OWNER; 407135446Strhodes styleflags |= DNS_STYLEFLAG_OMIT_CLASS; 408135446Strhodes styleflags |= DNS_STYLEFLAG_REL_DATA; 409135446Strhodes styleflags |= DNS_STYLEFLAG_OMIT_TTL; 410135446Strhodes styleflags |= DNS_STYLEFLAG_TTL; 411135446Strhodes styleflags |= DNS_STYLEFLAG_MULTILINE; 412135446Strhodes styleflags |= DNS_STYLEFLAG_COMMENT; 413254897Serwin styleflags |= DNS_STYLEFLAG_RRCOMMENT; 414135446Strhodes } 415254897Serwin 416135446Strhodes if (multiline || (nottl && noclass)) 417254897Serwin result = dns_master_stylecreate2(&style, styleflags, 418254897Serwin 24, 24, 24, 32, 80, 8, 419254897Serwin splitwidth, mctx); 420135446Strhodes else if (nottl || noclass) 421254897Serwin result = dns_master_stylecreate2(&style, styleflags, 422254897Serwin 24, 24, 32, 40, 80, 8, 423254897Serwin splitwidth, mctx); 424186462Sdougb else 425254897Serwin result = dns_master_stylecreate2(&style, styleflags, 426254897Serwin 24, 32, 40, 48, 80, 8, 427254897Serwin splitwidth, mctx); 428135446Strhodes check_result(result, "dns_master_stylecreate"); 429135446Strhodes 430135446Strhodes result = dns_master_rdatasettotext(owner_name, rdataset, style, target); 431135446Strhodes 432135446Strhodes if (style != NULL) 433135446Strhodes dns_master_styledestroy(&style, mctx); 434186462Sdougb 435135446Strhodes return(result); 436135446Strhodes} 437135446Strhodes#endif 438135446Strhodes 439135446Strhodes/* 440135446Strhodes * Callback from dighost.c to print the reply from a server 441135446Strhodes */ 442135446Strhodesisc_result_t 443135446Strhodesprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 444135446Strhodes isc_result_t result; 445135446Strhodes dns_messagetextflag_t flags; 446135446Strhodes isc_buffer_t *buf = NULL; 447135446Strhodes unsigned int len = OUTPUTBUF; 448135446Strhodes dns_master_style_t *style = NULL; 449135446Strhodes unsigned int styleflags = 0; 450135446Strhodes 451135446Strhodes styleflags |= DNS_STYLEFLAG_REL_OWNER; 452254897Serwin if (query->lookup->comments) 453254897Serwin styleflags |= DNS_STYLEFLAG_COMMENT; 454254897Serwin if (rrcomments) 455254897Serwin styleflags |= DNS_STYLEFLAG_RRCOMMENT; 456135446Strhodes if (nottl) 457135446Strhodes styleflags |= DNS_STYLEFLAG_NO_TTL; 458135446Strhodes if (noclass) 459135446Strhodes styleflags |= DNS_STYLEFLAG_NO_CLASS; 460135446Strhodes if (multiline) { 461135446Strhodes styleflags |= DNS_STYLEFLAG_OMIT_OWNER; 462135446Strhodes styleflags |= DNS_STYLEFLAG_OMIT_CLASS; 463135446Strhodes styleflags |= DNS_STYLEFLAG_REL_DATA; 464135446Strhodes styleflags |= DNS_STYLEFLAG_OMIT_TTL; 465135446Strhodes styleflags |= DNS_STYLEFLAG_TTL; 466135446Strhodes styleflags |= DNS_STYLEFLAG_MULTILINE; 467254897Serwin styleflags |= DNS_STYLEFLAG_RRCOMMENT; 468135446Strhodes } 469135446Strhodes if (multiline || (nottl && noclass)) 470254897Serwin result = dns_master_stylecreate2(&style, styleflags, 471254897Serwin 24, 24, 24, 32, 80, 8, 472254897Serwin splitwidth, mctx); 473135446Strhodes else if (nottl || noclass) 474254897Serwin result = dns_master_stylecreate2(&style, styleflags, 475254897Serwin 24, 24, 32, 40, 80, 8, 476254897Serwin splitwidth, mctx); 477186462Sdougb else 478254897Serwin result = dns_master_stylecreate2(&style, styleflags, 479254897Serwin 24, 32, 40, 48, 80, 8, 480254897Serwin splitwidth, mctx); 481135446Strhodes check_result(result, "dns_master_stylecreate"); 482135446Strhodes 483135446Strhodes if (query->lookup->cmdline[0] != 0) { 484135446Strhodes if (!short_form) 485135446Strhodes fputs(query->lookup->cmdline, stdout); 486135446Strhodes query->lookup->cmdline[0]=0; 487135446Strhodes } 488135446Strhodes debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders", 489135446Strhodes query->lookup->comments ? "comments" : "nocomments", 490135446Strhodes short_form ? "short_form" : "long_form"); 491135446Strhodes 492135446Strhodes flags = 0; 493135446Strhodes if (!headers) { 494135446Strhodes flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; 495135446Strhodes flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 496135446Strhodes } 497224092Sdougb if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr) 498224092Sdougb flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA : 499224092Sdougb DNS_MESSAGETEXTFLAG_OMITSOA; 500135446Strhodes if (!query->lookup->comments) 501135446Strhodes flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 502135446Strhodes 503135446Strhodes result = isc_buffer_allocate(mctx, &buf, len); 504135446Strhodes check_result(result, "isc_buffer_allocate"); 505135446Strhodes 506135446Strhodes if (query->lookup->comments && !short_form) { 507135446Strhodes if (query->lookup->cmdline[0] != 0) 508135446Strhodes printf("; %s\n", query->lookup->cmdline); 509135446Strhodes if (msg == query->lookup->sendmsg) 510135446Strhodes printf(";; Sending:\n"); 511135446Strhodes else 512135446Strhodes printf(";; Got answer:\n"); 513135446Strhodes 514135446Strhodes if (headers) { 515135446Strhodes printf(";; ->>HEADER<<- opcode: %s, status: %s, " 516135446Strhodes "id: %u\n", 517193149Sdougb opcodetext[msg->opcode], 518193149Sdougb rcode_totext(msg->rcode), 519135446Strhodes msg->id); 520135446Strhodes printf(";; flags:"); 521135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) 522135446Strhodes printf(" qr"); 523135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) 524135446Strhodes printf(" aa"); 525135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) 526135446Strhodes printf(" tc"); 527135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) 528135446Strhodes printf(" rd"); 529135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) 530135446Strhodes printf(" ra"); 531135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) 532135446Strhodes printf(" ad"); 533135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) 534135446Strhodes printf(" cd"); 535218384Sdougb if ((msg->flags & 0x0040U) != 0) 536218384Sdougb printf("; MBZ: 0x4"); 537135446Strhodes 538135446Strhodes printf("; QUERY: %u, ANSWER: %u, " 539135446Strhodes "AUTHORITY: %u, ADDITIONAL: %u\n", 540135446Strhodes msg->counts[DNS_SECTION_QUESTION], 541135446Strhodes msg->counts[DNS_SECTION_ANSWER], 542135446Strhodes msg->counts[DNS_SECTION_AUTHORITY], 543135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL]); 544170222Sdougb 545170222Sdougb if (msg != query->lookup->sendmsg && 546170222Sdougb (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && 547170222Sdougb (msg->flags & DNS_MESSAGEFLAG_RA) == 0) 548170222Sdougb printf(";; WARNING: recursion requested " 549170222Sdougb "but not available\n"); 550135446Strhodes } 551254402Serwin if (msg != query->lookup->sendmsg && 552254402Serwin query->lookup->edns != -1 && msg->opt == NULL && 553254402Serwin (msg->rcode == dns_rcode_formerr || 554254402Serwin msg->rcode == dns_rcode_notimp)) 555254402Serwin printf("\n;; WARNING: EDNS query returned status " 556262706Serwin "%s - retry with '%s+noedns'\n", 557262706Serwin rcode_totext(msg->rcode), 558262706Serwin query->lookup->dnssec ? "+nodnssec ": ""); 559170222Sdougb if (msg != query->lookup->sendmsg && extrabytes != 0U) 560262706Serwin printf(";; WARNING: Message has %u extra byte%s at " 561170222Sdougb "end\n", extrabytes, extrabytes != 0 ? "s" : ""); 562135446Strhodes } 563135446Strhodes 564135446Strhodesrepopulate_buffer: 565135446Strhodes 566135446Strhodes if (query->lookup->comments && headers && !short_form) { 567135446Strhodes result = dns_message_pseudosectiontotext(msg, 568135446Strhodes DNS_PSEUDOSECTION_OPT, 569135446Strhodes style, flags, buf); 570135446Strhodes if (result == ISC_R_NOSPACE) { 571135446Strhodesbuftoosmall: 572135446Strhodes len += OUTPUTBUF; 573135446Strhodes isc_buffer_free(&buf); 574135446Strhodes result = isc_buffer_allocate(mctx, &buf, len); 575135446Strhodes if (result == ISC_R_SUCCESS) 576135446Strhodes goto repopulate_buffer; 577135446Strhodes else 578135446Strhodes goto cleanup; 579135446Strhodes } 580135446Strhodes check_result(result, 581135446Strhodes "dns_message_pseudosectiontotext"); 582135446Strhodes } 583135446Strhodes 584135446Strhodes if (query->lookup->section_question && headers) { 585135446Strhodes if (!short_form) { 586135446Strhodes result = dns_message_sectiontotext(msg, 587135446Strhodes DNS_SECTION_QUESTION, 588135446Strhodes style, flags, buf); 589135446Strhodes if (result == ISC_R_NOSPACE) 590135446Strhodes goto buftoosmall; 591135446Strhodes check_result(result, "dns_message_sectiontotext"); 592135446Strhodes } 593135446Strhodes } 594135446Strhodes if (query->lookup->section_answer) { 595135446Strhodes if (!short_form) { 596135446Strhodes result = dns_message_sectiontotext(msg, 597135446Strhodes DNS_SECTION_ANSWER, 598135446Strhodes style, flags, buf); 599135446Strhodes if (result == ISC_R_NOSPACE) 600135446Strhodes goto buftoosmall; 601135446Strhodes check_result(result, "dns_message_sectiontotext"); 602135446Strhodes } else { 603135446Strhodes result = short_answer(msg, flags, buf, query); 604135446Strhodes if (result == ISC_R_NOSPACE) 605135446Strhodes goto buftoosmall; 606135446Strhodes check_result(result, "short_answer"); 607135446Strhodes } 608135446Strhodes } 609135446Strhodes if (query->lookup->section_authority) { 610135446Strhodes if (!short_form) { 611135446Strhodes result = dns_message_sectiontotext(msg, 612135446Strhodes DNS_SECTION_AUTHORITY, 613135446Strhodes style, flags, buf); 614135446Strhodes if (result == ISC_R_NOSPACE) 615135446Strhodes goto buftoosmall; 616135446Strhodes check_result(result, "dns_message_sectiontotext"); 617135446Strhodes } 618135446Strhodes } 619135446Strhodes if (query->lookup->section_additional) { 620135446Strhodes if (!short_form) { 621135446Strhodes result = dns_message_sectiontotext(msg, 622135446Strhodes DNS_SECTION_ADDITIONAL, 623135446Strhodes style, flags, buf); 624135446Strhodes if (result == ISC_R_NOSPACE) 625135446Strhodes goto buftoosmall; 626135446Strhodes check_result(result, "dns_message_sectiontotext"); 627135446Strhodes /* 628135446Strhodes * Only print the signature on the first record. 629135446Strhodes */ 630135446Strhodes if (headers) { 631135446Strhodes result = dns_message_pseudosectiontotext( 632135446Strhodes msg, 633135446Strhodes DNS_PSEUDOSECTION_TSIG, 634135446Strhodes style, flags, buf); 635135446Strhodes if (result == ISC_R_NOSPACE) 636135446Strhodes goto buftoosmall; 637135446Strhodes check_result(result, 638135446Strhodes "dns_message_pseudosectiontotext"); 639135446Strhodes result = dns_message_pseudosectiontotext( 640135446Strhodes msg, 641135446Strhodes DNS_PSEUDOSECTION_SIG0, 642135446Strhodes style, flags, buf); 643135446Strhodes if (result == ISC_R_NOSPACE) 644135446Strhodes goto buftoosmall; 645135446Strhodes check_result(result, 646135446Strhodes "dns_message_pseudosectiontotext"); 647135446Strhodes } 648135446Strhodes } 649135446Strhodes } 650153816Sdougb 651135446Strhodes if (headers && query->lookup->comments && !short_form) 652135446Strhodes printf("\n"); 653135446Strhodes 654135446Strhodes printf("%.*s", (int)isc_buffer_usedlength(buf), 655135446Strhodes (char *)isc_buffer_base(buf)); 656135446Strhodes isc_buffer_free(&buf); 657135446Strhodes 658135446Strhodescleanup: 659135446Strhodes if (style != NULL) 660135446Strhodes dns_master_styledestroy(&style, mctx); 661135446Strhodes return (result); 662135446Strhodes} 663135446Strhodes 664170222Sdougb/*% 665135446Strhodes * print the greeting message when the program first starts up. 666135446Strhodes */ 667135446Strhodesstatic void 668135446Strhodesprintgreeting(int argc, char **argv, dig_lookup_t *lookup) { 669135446Strhodes int i; 670135446Strhodes int remaining; 671135446Strhodes static isc_boolean_t first = ISC_TRUE; 672135446Strhodes char append[MXNAME]; 673135446Strhodes 674135446Strhodes if (printcmd) { 675135446Strhodes lookup->cmdline[sizeof(lookup->cmdline) - 1] = 0; 676135446Strhodes snprintf(lookup->cmdline, sizeof(lookup->cmdline), 677135446Strhodes "%s; <<>> DiG " VERSION " <<>>", 678135446Strhodes first?"\n":""); 679135446Strhodes i = 1; 680135446Strhodes while (i < argc) { 681135446Strhodes snprintf(append, sizeof(append), " %s", argv[i++]); 682135446Strhodes remaining = sizeof(lookup->cmdline) - 683135446Strhodes strlen(lookup->cmdline) - 1; 684135446Strhodes strncat(lookup->cmdline, append, remaining); 685135446Strhodes } 686135446Strhodes remaining = sizeof(lookup->cmdline) - 687135446Strhodes strlen(lookup->cmdline) - 1; 688135446Strhodes strncat(lookup->cmdline, "\n", remaining); 689143731Sdougb if (first && addresscount != 0) { 690143731Sdougb snprintf(append, sizeof(append), 691143731Sdougb "; (%d server%s found)\n", 692143731Sdougb addresscount, 693143731Sdougb addresscount > 1 ? "s" : ""); 694143731Sdougb remaining = sizeof(lookup->cmdline) - 695143731Sdougb strlen(lookup->cmdline) - 1; 696143731Sdougb strncat(lookup->cmdline, append, remaining); 697143731Sdougb } 698135446Strhodes if (first) { 699186462Sdougb snprintf(append, sizeof(append), 700193149Sdougb ";; global options:%s%s\n", 701193149Sdougb short_form ? " +short" : "", 702193149Sdougb printcmd ? " +cmd" : ""); 703135446Strhodes first = ISC_FALSE; 704135446Strhodes remaining = sizeof(lookup->cmdline) - 705135446Strhodes strlen(lookup->cmdline) - 1; 706135446Strhodes strncat(lookup->cmdline, append, remaining); 707135446Strhodes } 708135446Strhodes } 709135446Strhodes} 710135446Strhodes 711170222Sdougb/*% 712135446Strhodes * We're not using isc_commandline_parse() here since the command line 713135446Strhodes * syntax of dig is quite a bit different from that which can be described 714135446Strhodes * by that routine. 715135446Strhodes * XXX doc options 716135446Strhodes */ 717135446Strhodes 718135446Strhodesstatic void 719135446Strhodesplus_option(char *option, isc_boolean_t is_batchfile, 720135446Strhodes dig_lookup_t *lookup) 721135446Strhodes{ 722224092Sdougb isc_result_t result; 723135446Strhodes char option_store[256]; 724135446Strhodes char *cmd, *value, *ptr; 725224092Sdougb isc_uint32_t num; 726135446Strhodes isc_boolean_t state = ISC_TRUE; 727135446Strhodes#ifdef DIG_SIGCHASE 728135446Strhodes size_t n; 729135446Strhodes#endif 730135446Strhodes 731135446Strhodes strncpy(option_store, option, sizeof(option_store)); 732135446Strhodes option_store[sizeof(option_store)-1]=0; 733135446Strhodes ptr = option_store; 734135446Strhodes cmd = next_token(&ptr,"="); 735135446Strhodes if (cmd == NULL) { 736135446Strhodes printf(";; Invalid option %s\n", option_store); 737135446Strhodes return; 738135446Strhodes } 739135446Strhodes value = ptr; 740135446Strhodes if (strncasecmp(cmd, "no", 2)==0) { 741135446Strhodes cmd += 2; 742135446Strhodes state = ISC_FALSE; 743135446Strhodes } 744135446Strhodes 745135446Strhodes#define FULLCHECK(A) \ 746135446Strhodes do { \ 747135446Strhodes size_t _l = strlen(cmd); \ 748135446Strhodes if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ 749135446Strhodes goto invalid_option; \ 750135446Strhodes } while (0) 751135446Strhodes#define FULLCHECK2(A, B) \ 752135446Strhodes do { \ 753135446Strhodes size_t _l = strlen(cmd); \ 754135446Strhodes if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ 755135446Strhodes (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ 756135446Strhodes goto invalid_option; \ 757135446Strhodes } while (0) 758135446Strhodes 759135446Strhodes switch (cmd[0]) { 760135446Strhodes case 'a': 761135446Strhodes switch (cmd[1]) { 762135446Strhodes case 'a': /* aaonly / aaflag */ 763135446Strhodes FULLCHECK2("aaonly", "aaflag"); 764135446Strhodes lookup->aaonly = state; 765135446Strhodes break; 766186462Sdougb case 'd': 767135446Strhodes switch (cmd[2]) { 768135446Strhodes case 'd': /* additional */ 769135446Strhodes FULLCHECK("additional"); 770135446Strhodes lookup->section_additional = state; 771135446Strhodes break; 772135446Strhodes case 'f': /* adflag */ 773224092Sdougb case '\0': /* +ad is a synonym for +adflag */ 774135446Strhodes FULLCHECK("adflag"); 775135446Strhodes lookup->adflag = state; 776135446Strhodes break; 777135446Strhodes default: 778135446Strhodes goto invalid_option; 779135446Strhodes } 780135446Strhodes break; 781135446Strhodes case 'l': /* all */ 782135446Strhodes FULLCHECK("all"); 783135446Strhodes lookup->section_question = state; 784135446Strhodes lookup->section_authority = state; 785135446Strhodes lookup->section_answer = state; 786135446Strhodes lookup->section_additional = state; 787135446Strhodes lookup->comments = state; 788254897Serwin rrcomments = state; 789135446Strhodes lookup->stats = state; 790135446Strhodes printcmd = state; 791135446Strhodes break; 792135446Strhodes case 'n': /* answer */ 793135446Strhodes FULLCHECK("answer"); 794135446Strhodes lookup->section_answer = state; 795135446Strhodes break; 796135446Strhodes case 'u': /* authority */ 797135446Strhodes FULLCHECK("authority"); 798135446Strhodes lookup->section_authority = state; 799135446Strhodes break; 800135446Strhodes default: 801135446Strhodes goto invalid_option; 802135446Strhodes } 803135446Strhodes break; 804135446Strhodes case 'b': 805135446Strhodes switch (cmd[1]) { 806135446Strhodes case 'e':/* besteffort */ 807135446Strhodes FULLCHECK("besteffort"); 808135446Strhodes lookup->besteffort = state; 809135446Strhodes break; 810135446Strhodes case 'u':/* bufsize */ 811135446Strhodes FULLCHECK("bufsize"); 812135446Strhodes if (value == NULL) 813135446Strhodes goto need_value; 814135446Strhodes if (!state) 815135446Strhodes goto invalid_option; 816224092Sdougb result = parse_uint(&num, value, COMMSIZE, 817224092Sdougb "buffer size"); 818224092Sdougb if (result != ISC_R_SUCCESS) 819224092Sdougb fatal("Couldn't parse buffer size"); 820224092Sdougb lookup->udpsize = num; 821135446Strhodes break; 822135446Strhodes default: 823135446Strhodes goto invalid_option; 824135446Strhodes } 825135446Strhodes break; 826135446Strhodes case 'c': 827135446Strhodes switch (cmd[1]) { 828135446Strhodes case 'd':/* cdflag */ 829224092Sdougb switch (cmd[2]) { 830224092Sdougb case 'f': /* cdflag */ 831224092Sdougb case '\0': /* +cd is a synonym for +cdflag */ 832224092Sdougb FULLCHECK("cdflag"); 833224092Sdougb lookup->cdflag = state; 834224092Sdougb break; 835224092Sdougb default: 836224092Sdougb goto invalid_option; 837224092Sdougb } 838135446Strhodes break; 839135446Strhodes case 'l': /* cl */ 840135446Strhodes FULLCHECK("cl"); 841153816Sdougb noclass = ISC_TF(!state); 842135446Strhodes break; 843135446Strhodes case 'm': /* cmd */ 844135446Strhodes FULLCHECK("cmd"); 845135446Strhodes printcmd = state; 846135446Strhodes break; 847135446Strhodes case 'o': /* comments */ 848135446Strhodes FULLCHECK("comments"); 849135446Strhodes lookup->comments = state; 850135446Strhodes if (lookup == default_lookup) 851135446Strhodes pluscomm = state; 852135446Strhodes break; 853135446Strhodes default: 854135446Strhodes goto invalid_option; 855135446Strhodes } 856135446Strhodes break; 857135446Strhodes case 'd': 858135446Strhodes switch (cmd[1]) { 859135446Strhodes case 'e': /* defname */ 860135446Strhodes FULLCHECK("defname"); 861193149Sdougb if (!lookup->trace) { 862193149Sdougb usesearch = state; 863193149Sdougb } 864135446Strhodes break; 865186462Sdougb case 'n': /* dnssec */ 866135446Strhodes FULLCHECK("dnssec"); 867170222Sdougb if (state && lookup->edns == -1) 868170222Sdougb lookup->edns = 0; 869135446Strhodes lookup->dnssec = state; 870135446Strhodes break; 871186462Sdougb case 'o': /* domain */ 872135446Strhodes FULLCHECK("domain"); 873135446Strhodes if (value == NULL) 874135446Strhodes goto need_value; 875135446Strhodes if (!state) 876135446Strhodes goto invalid_option; 877135446Strhodes strncpy(domainopt, value, sizeof(domainopt)); 878135446Strhodes domainopt[sizeof(domainopt)-1] = '\0'; 879135446Strhodes break; 880135446Strhodes default: 881135446Strhodes goto invalid_option; 882135446Strhodes } 883135446Strhodes break; 884170222Sdougb case 'e': 885170222Sdougb FULLCHECK("edns"); 886170222Sdougb if (!state) { 887170222Sdougb lookup->edns = -1; 888170222Sdougb break; 889170222Sdougb } 890254402Serwin if (value == NULL) { 891254402Serwin lookup->edns = 0; 892254402Serwin break; 893254402Serwin } 894224092Sdougb result = parse_uint(&num, value, 255, "edns"); 895224092Sdougb if (result != ISC_R_SUCCESS) 896224092Sdougb fatal("Couldn't parse edns"); 897224092Sdougb lookup->edns = num; 898170222Sdougb break; 899135446Strhodes case 'f': /* fail */ 900135446Strhodes FULLCHECK("fail"); 901135446Strhodes lookup->servfail_stops = state; 902135446Strhodes break; 903135446Strhodes case 'i': 904135446Strhodes switch (cmd[1]) { 905135446Strhodes case 'd': /* identify */ 906135446Strhodes FULLCHECK("identify"); 907135446Strhodes lookup->identify = state; 908135446Strhodes break; 909135446Strhodes case 'g': /* ignore */ 910193149Sdougb default: /* Inherits default for compatibility */ 911135446Strhodes FULLCHECK("ignore"); 912135446Strhodes lookup->ignore = ISC_TRUE; 913135446Strhodes } 914135446Strhodes break; 915262706Serwin case 'k': 916262706Serwin FULLCHECK("keepopen"); 917262706Serwin keep_open = state; 918262706Serwin break; 919135446Strhodes case 'm': /* multiline */ 920135446Strhodes FULLCHECK("multiline"); 921135446Strhodes multiline = state; 922135446Strhodes break; 923135446Strhodes case 'n': 924135446Strhodes switch (cmd[1]) { 925135446Strhodes case 'd': /* ndots */ 926135446Strhodes FULLCHECK("ndots"); 927135446Strhodes if (value == NULL) 928135446Strhodes goto need_value; 929135446Strhodes if (!state) 930135446Strhodes goto invalid_option; 931224092Sdougb result = parse_uint(&num, value, MAXNDOTS, "ndots"); 932224092Sdougb if (result != ISC_R_SUCCESS) 933224092Sdougb fatal("Couldn't parse ndots"); 934224092Sdougb ndots = num; 935135446Strhodes break; 936193149Sdougb case 's': 937193149Sdougb switch (cmd[2]) { 938193149Sdougb case 'i': /* nsid */ 939193149Sdougb FULLCHECK("nsid"); 940193149Sdougb if (state && lookup->edns == -1) 941193149Sdougb lookup->edns = 0; 942193149Sdougb lookup->nsid = state; 943193149Sdougb break; 944193149Sdougb case 's': /* nssearch */ 945193149Sdougb FULLCHECK("nssearch"); 946193149Sdougb lookup->ns_search_only = state; 947193149Sdougb if (state) { 948193149Sdougb lookup->trace_root = ISC_TRUE; 949193149Sdougb lookup->recurse = ISC_TRUE; 950193149Sdougb lookup->identify = ISC_TRUE; 951193149Sdougb lookup->stats = ISC_FALSE; 952193149Sdougb lookup->comments = ISC_FALSE; 953254897Serwin rrcomments = ISC_FALSE; 954193149Sdougb lookup->section_additional = ISC_FALSE; 955193149Sdougb lookup->section_authority = ISC_FALSE; 956193149Sdougb lookup->section_question = ISC_FALSE; 957193149Sdougb lookup->rdtype = dns_rdatatype_ns; 958193149Sdougb lookup->rdtypeset = ISC_TRUE; 959193149Sdougb short_form = ISC_TRUE; 960193149Sdougb } 961193149Sdougb break; 962193149Sdougb default: 963193149Sdougb goto invalid_option; 964135446Strhodes } 965135446Strhodes break; 966135446Strhodes default: 967135446Strhodes goto invalid_option; 968135446Strhodes } 969135446Strhodes break; 970224092Sdougb case 'o': 971224092Sdougb FULLCHECK("onesoa"); 972224092Sdougb onesoa = state; 973224092Sdougb break; 974186462Sdougb case 'q': 975135446Strhodes switch (cmd[1]) { 976135446Strhodes case 'r': /* qr */ 977135446Strhodes FULLCHECK("qr"); 978135446Strhodes qr = state; 979135446Strhodes break; 980135446Strhodes case 'u': /* question */ 981135446Strhodes FULLCHECK("question"); 982135446Strhodes lookup->section_question = state; 983135446Strhodes if (lookup == default_lookup) 984135446Strhodes plusquest = state; 985135446Strhodes break; 986135446Strhodes default: 987135446Strhodes goto invalid_option; 988135446Strhodes } 989135446Strhodes break; 990135446Strhodes case 'r': 991135446Strhodes switch (cmd[1]) { 992135446Strhodes case 'e': 993135446Strhodes switch (cmd[2]) { 994135446Strhodes case 'c': /* recurse */ 995135446Strhodes FULLCHECK("recurse"); 996135446Strhodes lookup->recurse = state; 997135446Strhodes break; 998135446Strhodes case 't': /* retry / retries */ 999135446Strhodes FULLCHECK2("retry", "retries"); 1000135446Strhodes if (value == NULL) 1001135446Strhodes goto need_value; 1002135446Strhodes if (!state) 1003135446Strhodes goto invalid_option; 1004224092Sdougb result = parse_uint(&lookup->retries, value, 1005224092Sdougb MAXTRIES - 1, "retries"); 1006224092Sdougb if (result != ISC_R_SUCCESS) 1007224092Sdougb fatal("Couldn't parse retries"); 1008135446Strhodes lookup->retries++; 1009135446Strhodes break; 1010135446Strhodes default: 1011135446Strhodes goto invalid_option; 1012135446Strhodes } 1013135446Strhodes break; 1014254897Serwin case 'r': /* rrcomments */ 1015254897Serwin FULLCHECK("rrcomments"); 1016254897Serwin rrcomments = state; 1017254897Serwin break; 1018135446Strhodes default: 1019135446Strhodes goto invalid_option; 1020135446Strhodes } 1021135446Strhodes break; 1022135446Strhodes case 's': 1023135446Strhodes switch (cmd[1]) { 1024135446Strhodes case 'e': /* search */ 1025135446Strhodes FULLCHECK("search"); 1026193149Sdougb if (!lookup->trace) { 1027193149Sdougb usesearch = state; 1028193149Sdougb } 1029135446Strhodes break; 1030170222Sdougb case 'h': 1031170222Sdougb if (cmd[2] != 'o') 1032170222Sdougb goto invalid_option; 1033170222Sdougb switch (cmd[3]) { 1034170222Sdougb case 'r': /* short */ 1035170222Sdougb FULLCHECK("short"); 1036170222Sdougb short_form = state; 1037170222Sdougb if (state) { 1038170222Sdougb printcmd = ISC_FALSE; 1039170222Sdougb lookup->section_additional = ISC_FALSE; 1040170222Sdougb lookup->section_answer = ISC_TRUE; 1041170222Sdougb lookup->section_authority = ISC_FALSE; 1042170222Sdougb lookup->section_question = ISC_FALSE; 1043170222Sdougb lookup->comments = ISC_FALSE; 1044254897Serwin rrcomments = ISC_FALSE; 1045170222Sdougb lookup->stats = ISC_FALSE; 1046170222Sdougb } 1047170222Sdougb break; 1048170222Sdougb case 'w': /* showsearch */ 1049170222Sdougb FULLCHECK("showsearch"); 1050193149Sdougb if (!lookup->trace) { 1051193149Sdougb showsearch = state; 1052193149Sdougb usesearch = state; 1053193149Sdougb } 1054170222Sdougb break; 1055170222Sdougb default: 1056170222Sdougb goto invalid_option; 1057135446Strhodes } 1058135446Strhodes break; 1059135446Strhodes#ifdef DIG_SIGCHASE 1060135446Strhodes case 'i': /* sigchase */ 1061186462Sdougb FULLCHECK("sigchase"); 1062135446Strhodes lookup->sigchase = state; 1063135446Strhodes if (lookup->sigchase) 1064135446Strhodes lookup->dnssec = ISC_TRUE; 1065186462Sdougb break; 1066135446Strhodes#endif 1067254897Serwin case 'p': /* split */ 1068254897Serwin FULLCHECK("split"); 1069254897Serwin if (value != NULL && !state) 1070254897Serwin goto invalid_option; 1071254897Serwin if (!state) { 1072254897Serwin splitwidth = 0; 1073254897Serwin break; 1074254897Serwin } else if (value == NULL) 1075254897Serwin break; 1076254897Serwin 1077254897Serwin result = parse_uint(&splitwidth, value, 1078254897Serwin 1023, "split"); 1079254897Serwin if (splitwidth % 4 != 0) { 1080254897Serwin splitwidth = ((splitwidth + 3) / 4) * 4; 1081254897Serwin fprintf(stderr, ";; Warning, split must be " 1082254897Serwin "a multiple of 4; adjusting " 1083254897Serwin "to %d\n", splitwidth); 1084254897Serwin } 1085254897Serwin /* 1086254897Serwin * There is an adjustment done in the 1087254897Serwin * totext_<rrtype>() functions which causes 1088254897Serwin * splitwidth to shrink. This is okay when we're 1089254897Serwin * using the default width but incorrect in this 1090254897Serwin * case, so we correct for it 1091254897Serwin */ 1092254897Serwin if (splitwidth) 1093254897Serwin splitwidth += 3; 1094254897Serwin if (result != ISC_R_SUCCESS) 1095254897Serwin fatal("Couldn't parse retries"); 1096254897Serwin break; 1097135446Strhodes case 't': /* stats */ 1098135446Strhodes FULLCHECK("stats"); 1099135446Strhodes lookup->stats = state; 1100135446Strhodes break; 1101135446Strhodes default: 1102135446Strhodes goto invalid_option; 1103135446Strhodes } 1104135446Strhodes break; 1105135446Strhodes case 't': 1106135446Strhodes switch (cmd[1]) { 1107135446Strhodes case 'c': /* tcp */ 1108135446Strhodes FULLCHECK("tcp"); 1109135446Strhodes if (!is_batchfile) 1110135446Strhodes lookup->tcp_mode = state; 1111135446Strhodes break; 1112135446Strhodes case 'i': /* timeout */ 1113135446Strhodes FULLCHECK("timeout"); 1114135446Strhodes if (value == NULL) 1115135446Strhodes goto need_value; 1116135446Strhodes if (!state) 1117135446Strhodes goto invalid_option; 1118224092Sdougb result = parse_uint(&timeout, value, MAXTIMEOUT, 1119224092Sdougb "timeout"); 1120224092Sdougb if (result != ISC_R_SUCCESS) 1121224092Sdougb fatal("Couldn't parse timeout"); 1122135446Strhodes if (timeout == 0) 1123135446Strhodes timeout = 1; 1124135446Strhodes break; 1125135446Strhodes#if DIG_SIGCHASE_TD 1126186462Sdougb case 'o': /* topdown */ 1127135446Strhodes FULLCHECK("topdown"); 1128135446Strhodes lookup->do_topdown = state; 1129135446Strhodes break; 1130135446Strhodes#endif 1131135446Strhodes case 'r': 1132135446Strhodes switch (cmd[2]) { 1133135446Strhodes case 'a': /* trace */ 1134135446Strhodes FULLCHECK("trace"); 1135135446Strhodes lookup->trace = state; 1136135446Strhodes lookup->trace_root = state; 1137135446Strhodes if (state) { 1138135446Strhodes lookup->recurse = ISC_FALSE; 1139135446Strhodes lookup->identify = ISC_TRUE; 1140135446Strhodes lookup->comments = ISC_FALSE; 1141254897Serwin rrcomments = ISC_FALSE; 1142135446Strhodes lookup->stats = ISC_FALSE; 1143135446Strhodes lookup->section_additional = ISC_FALSE; 1144135446Strhodes lookup->section_authority = ISC_TRUE; 1145143731Sdougb lookup->section_question = ISC_FALSE; 1146254897Serwin lookup->dnssec = ISC_TRUE; 1147193149Sdougb usesearch = ISC_FALSE; 1148135446Strhodes } 1149135446Strhodes break; 1150135446Strhodes case 'i': /* tries */ 1151135446Strhodes FULLCHECK("tries"); 1152135446Strhodes if (value == NULL) 1153135446Strhodes goto need_value; 1154135446Strhodes if (!state) 1155135446Strhodes goto invalid_option; 1156224092Sdougb result = parse_uint(&lookup->retries, value, 1157224092Sdougb MAXTRIES, "tries"); 1158224092Sdougb if (result != ISC_R_SUCCESS) 1159224092Sdougb fatal("Couldn't parse tries"); 1160135446Strhodes if (lookup->retries == 0) 1161135446Strhodes lookup->retries = 1; 1162135446Strhodes break; 1163135446Strhodes#ifdef DIG_SIGCHASE 1164135446Strhodes case 'u': /* trusted-key */ 1165143731Sdougb FULLCHECK("trusted-key"); 1166186462Sdougb if (value == NULL) 1167135446Strhodes goto need_value; 1168135446Strhodes if (!state) 1169135446Strhodes goto invalid_option; 1170135446Strhodes n = strlcpy(trustedkey, ptr, 1171135446Strhodes sizeof(trustedkey)); 1172135446Strhodes if (n >= sizeof(trustedkey)) 1173135446Strhodes fatal("trusted key too large"); 1174135446Strhodes break; 1175135446Strhodes#endif 1176135446Strhodes default: 1177135446Strhodes goto invalid_option; 1178135446Strhodes } 1179135446Strhodes break; 1180135446Strhodes case 't': /* ttlid */ 1181135446Strhodes FULLCHECK("ttlid"); 1182153816Sdougb nottl = ISC_TF(!state); 1183135446Strhodes break; 1184135446Strhodes default: 1185135446Strhodes goto invalid_option; 1186135446Strhodes } 1187135446Strhodes break; 1188135446Strhodes case 'v': 1189135446Strhodes FULLCHECK("vc"); 1190135446Strhodes if (!is_batchfile) 1191135446Strhodes lookup->tcp_mode = state; 1192135446Strhodes break; 1193135446Strhodes default: 1194135446Strhodes invalid_option: 1195135446Strhodes need_value: 1196135446Strhodes fprintf(stderr, "Invalid option: +%s\n", 1197135446Strhodes option); 1198135446Strhodes usage(); 1199135446Strhodes } 1200135446Strhodes return; 1201135446Strhodes} 1202135446Strhodes 1203170222Sdougb/*% 1204170222Sdougb * #ISC_TRUE returned if value was used 1205135446Strhodes */ 1206135446Strhodesstatic const char *single_dash_opts = "46dhimnv"; 1207135446Strhodesstatic const char *dash_opts = "46bcdfhikmnptvyx"; 1208135446Strhodesstatic isc_boolean_t 1209135446Strhodesdash_option(char *option, char *next, dig_lookup_t **lookup, 1210174187Sdougb isc_boolean_t *open_type_class, isc_boolean_t *need_clone, 1211174187Sdougb isc_boolean_t config_only, int argc, char **argv, 1212174187Sdougb isc_boolean_t *firstarg) 1213135446Strhodes{ 1214170222Sdougb char opt, *value, *ptr, *ptr2, *ptr3; 1215135446Strhodes isc_result_t result; 1216135446Strhodes isc_boolean_t value_from_next; 1217135446Strhodes isc_textregion_t tr; 1218135446Strhodes dns_rdatatype_t rdtype; 1219135446Strhodes dns_rdataclass_t rdclass; 1220135446Strhodes char textname[MXNAME]; 1221135446Strhodes struct in_addr in4; 1222135446Strhodes struct in6_addr in6; 1223135446Strhodes in_port_t srcport; 1224135446Strhodes char *hash, *cmd; 1225224092Sdougb isc_uint32_t num; 1226135446Strhodes 1227135446Strhodes while (strpbrk(option, single_dash_opts) == &option[0]) { 1228135446Strhodes /* 1229135446Strhodes * Since the -[46dhimnv] options do not take an argument, 1230135446Strhodes * account for them (in any number and/or combination) 1231135446Strhodes * if they appear as the first character(s) of a q-opt. 1232135446Strhodes */ 1233135446Strhodes opt = option[0]; 1234135446Strhodes switch (opt) { 1235135446Strhodes case '4': 1236135446Strhodes if (have_ipv4) { 1237135446Strhodes isc_net_disableipv6(); 1238135446Strhodes have_ipv6 = ISC_FALSE; 1239135446Strhodes } else { 1240135446Strhodes fatal("can't find IPv4 networking"); 1241224092Sdougb /* NOTREACHED */ 1242135446Strhodes return (ISC_FALSE); 1243135446Strhodes } 1244135446Strhodes break; 1245135446Strhodes case '6': 1246135446Strhodes if (have_ipv6) { 1247135446Strhodes isc_net_disableipv4(); 1248135446Strhodes have_ipv4 = ISC_FALSE; 1249135446Strhodes } else { 1250135446Strhodes fatal("can't find IPv6 networking"); 1251224092Sdougb /* NOTREACHED */ 1252135446Strhodes return (ISC_FALSE); 1253135446Strhodes } 1254135446Strhodes break; 1255135446Strhodes case 'd': 1256135446Strhodes ptr = strpbrk(&option[1], dash_opts); 1257135446Strhodes if (ptr != &option[1]) { 1258135446Strhodes cmd = option; 1259135446Strhodes FULLCHECK("debug"); 1260135446Strhodes debugging = ISC_TRUE; 1261135446Strhodes return (ISC_FALSE); 1262135446Strhodes } else 1263135446Strhodes debugging = ISC_TRUE; 1264135446Strhodes break; 1265135446Strhodes case 'h': 1266135446Strhodes help(); 1267135446Strhodes exit(0); 1268135446Strhodes break; 1269135446Strhodes case 'i': 1270135446Strhodes ip6_int = ISC_TRUE; 1271135446Strhodes break; 1272135446Strhodes case 'm': /* memdebug */ 1273135446Strhodes /* memdebug is handled in preparse_args() */ 1274135446Strhodes break; 1275135446Strhodes case 'n': 1276135446Strhodes /* deprecated */ 1277135446Strhodes break; 1278135446Strhodes case 'v': 1279135446Strhodes version(); 1280135446Strhodes exit(0); 1281135446Strhodes break; 1282135446Strhodes } 1283135446Strhodes if (strlen(option) > 1U) 1284135446Strhodes option = &option[1]; 1285135446Strhodes else 1286135446Strhodes return (ISC_FALSE); 1287135446Strhodes } 1288135446Strhodes opt = option[0]; 1289135446Strhodes if (strlen(option) > 1U) { 1290135446Strhodes value_from_next = ISC_FALSE; 1291135446Strhodes value = &option[1]; 1292135446Strhodes } else { 1293135446Strhodes value_from_next = ISC_TRUE; 1294135446Strhodes value = next; 1295135446Strhodes } 1296135446Strhodes if (value == NULL) 1297135446Strhodes goto invalid_option; 1298135446Strhodes switch (opt) { 1299135446Strhodes case 'b': 1300135446Strhodes hash = strchr(value, '#'); 1301135446Strhodes if (hash != NULL) { 1302224092Sdougb result = parse_uint(&num, hash + 1, MAXPORT, 1303224092Sdougb "port number"); 1304224092Sdougb if (result != ISC_R_SUCCESS) 1305224092Sdougb fatal("Couldn't parse port number"); 1306224092Sdougb srcport = num; 1307135446Strhodes *hash = '\0'; 1308135446Strhodes } else 1309135446Strhodes srcport = 0; 1310135446Strhodes if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { 1311135446Strhodes isc_sockaddr_fromin6(&bind_address, &in6, srcport); 1312135446Strhodes isc_net_disableipv4(); 1313135446Strhodes } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { 1314135446Strhodes isc_sockaddr_fromin(&bind_address, &in4, srcport); 1315135446Strhodes isc_net_disableipv6(); 1316135446Strhodes } else { 1317135446Strhodes if (hash != NULL) 1318135446Strhodes *hash = '#'; 1319135446Strhodes fatal("invalid address %s", value); 1320135446Strhodes } 1321135446Strhodes if (hash != NULL) 1322135446Strhodes *hash = '#'; 1323135446Strhodes specified_source = ISC_TRUE; 1324135446Strhodes return (value_from_next); 1325135446Strhodes case 'c': 1326135446Strhodes if ((*lookup)->rdclassset) { 1327135446Strhodes fprintf(stderr, ";; Warning, extra class option\n"); 1328135446Strhodes } 1329135446Strhodes *open_type_class = ISC_FALSE; 1330135446Strhodes tr.base = value; 1331135446Strhodes tr.length = strlen(value); 1332135446Strhodes result = dns_rdataclass_fromtext(&rdclass, 1333135446Strhodes (isc_textregion_t *)&tr); 1334135446Strhodes if (result == ISC_R_SUCCESS) { 1335135446Strhodes (*lookup)->rdclass = rdclass; 1336135446Strhodes (*lookup)->rdclassset = ISC_TRUE; 1337135446Strhodes } else 1338135446Strhodes fprintf(stderr, ";; Warning, ignoring " 1339135446Strhodes "invalid class %s\n", 1340135446Strhodes value); 1341135446Strhodes return (value_from_next); 1342135446Strhodes case 'f': 1343135446Strhodes batchname = value; 1344135446Strhodes return (value_from_next); 1345135446Strhodes case 'k': 1346135446Strhodes strncpy(keyfile, value, sizeof(keyfile)); 1347135446Strhodes keyfile[sizeof(keyfile)-1]=0; 1348135446Strhodes return (value_from_next); 1349135446Strhodes case 'p': 1350224092Sdougb result = parse_uint(&num, value, MAXPORT, "port number"); 1351224092Sdougb if (result != ISC_R_SUCCESS) 1352224092Sdougb fatal("Couldn't parse port number"); 1353224092Sdougb port = num; 1354135446Strhodes return (value_from_next); 1355170222Sdougb case 'q': 1356170222Sdougb if (!config_only) { 1357174187Sdougb if (*need_clone) 1358174187Sdougb (*lookup) = clone_lookup(default_lookup, 1359174187Sdougb ISC_TRUE); 1360174187Sdougb *need_clone = ISC_TRUE; 1361186462Sdougb strncpy((*lookup)->textname, value, 1362170222Sdougb sizeof((*lookup)->textname)); 1363170222Sdougb (*lookup)->textname[sizeof((*lookup)->textname)-1]=0; 1364170222Sdougb (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1365170222Sdougb (*lookup)->ns_search_only); 1366170222Sdougb (*lookup)->new_search = ISC_TRUE; 1367174187Sdougb if (*firstarg) { 1368174187Sdougb printgreeting(argc, argv, *lookup); 1369174187Sdougb *firstarg = ISC_FALSE; 1370174187Sdougb } 1371170222Sdougb ISC_LIST_APPEND(lookup_list, (*lookup), link); 1372170222Sdougb debug("looking up %s", (*lookup)->textname); 1373170222Sdougb } 1374170222Sdougb return (value_from_next); 1375135446Strhodes case 't': 1376135446Strhodes *open_type_class = ISC_FALSE; 1377135446Strhodes if (strncasecmp(value, "ixfr=", 5) == 0) { 1378135446Strhodes rdtype = dns_rdatatype_ixfr; 1379135446Strhodes result = ISC_R_SUCCESS; 1380135446Strhodes } else { 1381135446Strhodes tr.base = value; 1382135446Strhodes tr.length = strlen(value); 1383135446Strhodes result = dns_rdatatype_fromtext(&rdtype, 1384135446Strhodes (isc_textregion_t *)&tr); 1385135446Strhodes if (result == ISC_R_SUCCESS && 1386135446Strhodes rdtype == dns_rdatatype_ixfr) { 1387135446Strhodes result = DNS_R_UNKNOWN; 1388135446Strhodes } 1389135446Strhodes } 1390135446Strhodes if (result == ISC_R_SUCCESS) { 1391135446Strhodes if ((*lookup)->rdtypeset) { 1392135446Strhodes fprintf(stderr, ";; Warning, " 1393135446Strhodes "extra type option\n"); 1394135446Strhodes } 1395135446Strhodes if (rdtype == dns_rdatatype_ixfr) { 1396224092Sdougb isc_uint32_t serial; 1397135446Strhodes (*lookup)->rdtype = dns_rdatatype_ixfr; 1398135446Strhodes (*lookup)->rdtypeset = ISC_TRUE; 1399224092Sdougb result = parse_uint(&serial, &value[5], 1400224092Sdougb MAXSERIAL, "serial number"); 1401224092Sdougb if (result != ISC_R_SUCCESS) 1402224092Sdougb fatal("Couldn't parse serial number"); 1403224092Sdougb (*lookup)->ixfr_serial = serial; 1404135446Strhodes (*lookup)->section_question = plusquest; 1405135446Strhodes (*lookup)->comments = pluscomm; 1406193149Sdougb (*lookup)->tcp_mode = ISC_TRUE; 1407135446Strhodes } else { 1408135446Strhodes (*lookup)->rdtype = rdtype; 1409135446Strhodes (*lookup)->rdtypeset = ISC_TRUE; 1410135446Strhodes if (rdtype == dns_rdatatype_axfr) { 1411135446Strhodes (*lookup)->section_question = plusquest; 1412135446Strhodes (*lookup)->comments = pluscomm; 1413135446Strhodes } 1414135446Strhodes (*lookup)->ixfr_serial = ISC_FALSE; 1415135446Strhodes } 1416135446Strhodes } else 1417135446Strhodes fprintf(stderr, ";; Warning, ignoring " 1418135446Strhodes "invalid type %s\n", 1419135446Strhodes value); 1420135446Strhodes return (value_from_next); 1421135446Strhodes case 'y': 1422170222Sdougb ptr = next_token(&value,":"); /* hmac type or name */ 1423135446Strhodes if (ptr == NULL) { 1424135446Strhodes usage(); 1425135446Strhodes } 1426170222Sdougb ptr2 = next_token(&value, ":"); /* name or secret */ 1427170222Sdougb if (ptr2 == NULL) 1428170222Sdougb usage(); 1429170222Sdougb ptr3 = next_token(&value,":"); /* secret or NULL */ 1430186462Sdougb if (ptr3 != NULL) { 1431224092Sdougb parse_hmac(ptr); 1432170222Sdougb ptr = ptr2; 1433170222Sdougb ptr2 = ptr3; 1434170222Sdougb } else { 1435170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 1436170222Sdougb digestbits = 0; 1437170222Sdougb } 1438135446Strhodes strncpy(keynametext, ptr, sizeof(keynametext)); 1439135446Strhodes keynametext[sizeof(keynametext)-1]=0; 1440170222Sdougb strncpy(keysecret, ptr2, sizeof(keysecret)); 1441135446Strhodes keysecret[sizeof(keysecret)-1]=0; 1442135446Strhodes return (value_from_next); 1443135446Strhodes case 'x': 1444174187Sdougb if (*need_clone) 1445174187Sdougb *lookup = clone_lookup(default_lookup, ISC_TRUE); 1446174187Sdougb *need_clone = ISC_TRUE; 1447135446Strhodes if (get_reverse(textname, sizeof(textname), value, 1448135446Strhodes ip6_int, ISC_FALSE) == ISC_R_SUCCESS) { 1449135446Strhodes strncpy((*lookup)->textname, textname, 1450135446Strhodes sizeof((*lookup)->textname)); 1451135446Strhodes debug("looking up %s", (*lookup)->textname); 1452135446Strhodes (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1453135446Strhodes (*lookup)->ns_search_only); 1454135446Strhodes (*lookup)->ip6_int = ip6_int; 1455135446Strhodes if (!(*lookup)->rdtypeset) 1456135446Strhodes (*lookup)->rdtype = dns_rdatatype_ptr; 1457135446Strhodes if (!(*lookup)->rdclassset) 1458135446Strhodes (*lookup)->rdclass = dns_rdataclass_in; 1459135446Strhodes (*lookup)->new_search = ISC_TRUE; 1460174187Sdougb if (*firstarg) { 1461174187Sdougb printgreeting(argc, argv, *lookup); 1462174187Sdougb *firstarg = ISC_FALSE; 1463174187Sdougb } 1464135446Strhodes ISC_LIST_APPEND(lookup_list, *lookup, link); 1465135446Strhodes } else { 1466135446Strhodes fprintf(stderr, "Invalid IP address %s\n", value); 1467135446Strhodes exit(1); 1468135446Strhodes } 1469135446Strhodes return (value_from_next); 1470135446Strhodes invalid_option: 1471135446Strhodes default: 1472135446Strhodes fprintf(stderr, "Invalid option: -%s\n", option); 1473135446Strhodes usage(); 1474135446Strhodes } 1475224092Sdougb /* NOTREACHED */ 1476135446Strhodes return (ISC_FALSE); 1477135446Strhodes} 1478135446Strhodes 1479170222Sdougb/*% 1480135446Strhodes * Because we may be trying to do memory allocation recording, we're going 1481135446Strhodes * to need to parse the arguments for the -m *before* we start the main 1482135446Strhodes * argument parsing routine. 1483170222Sdougb * 1484135446Strhodes * I'd prefer not to have to do this, but I am not quite sure how else to 1485135446Strhodes * fix the problem. Argument parsing in dig involves memory allocation 1486135446Strhodes * by its nature, so it can't be done in the main argument parser. 1487135446Strhodes */ 1488135446Strhodesstatic void 1489135446Strhodespreparse_args(int argc, char **argv) { 1490135446Strhodes int rc; 1491135446Strhodes char **rv; 1492135446Strhodes char *option; 1493135446Strhodes 1494135446Strhodes rc = argc; 1495135446Strhodes rv = argv; 1496135446Strhodes for (rc--, rv++; rc > 0; rc--, rv++) { 1497135446Strhodes if (rv[0][0] != '-') 1498135446Strhodes continue; 1499135446Strhodes option = &rv[0][1]; 1500135446Strhodes while (strpbrk(option, single_dash_opts) == &option[0]) { 1501135446Strhodes if (option[0] == 'm') { 1502135446Strhodes memdebugging = ISC_TRUE; 1503135446Strhodes isc_mem_debugging = ISC_MEM_DEBUGTRACE | 1504135446Strhodes ISC_MEM_DEBUGRECORD; 1505135446Strhodes return; 1506135446Strhodes } 1507135446Strhodes option = &option[1]; 1508135446Strhodes } 1509135446Strhodes } 1510135446Strhodes} 1511135446Strhodes 1512135446Strhodesstatic void 1513135446Strhodesparse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, 1514135446Strhodes int argc, char **argv) { 1515135446Strhodes isc_result_t result; 1516135446Strhodes isc_textregion_t tr; 1517135446Strhodes isc_boolean_t firstarg = ISC_TRUE; 1518135446Strhodes dig_lookup_t *lookup = NULL; 1519135446Strhodes dns_rdatatype_t rdtype; 1520135446Strhodes dns_rdataclass_t rdclass; 1521135446Strhodes isc_boolean_t open_type_class = ISC_TRUE; 1522135446Strhodes char batchline[MXNAME]; 1523135446Strhodes int bargc; 1524135446Strhodes char *bargv[64]; 1525135446Strhodes int rc; 1526135446Strhodes char **rv; 1527135446Strhodes#ifndef NOPOSIX 1528135446Strhodes char *homedir; 1529135446Strhodes char rcfile[256]; 1530135446Strhodes#endif 1531135446Strhodes char *input; 1532174187Sdougb int i; 1533174187Sdougb isc_boolean_t need_clone = ISC_TRUE; 1534135446Strhodes 1535135446Strhodes /* 1536135446Strhodes * The semantics for parsing the args is a bit complex; if 1537135446Strhodes * we don't have a host yet, make the arg apply globally, 1538135446Strhodes * otherwise make it apply to the latest host. This is 1539135446Strhodes * a bit different than the previous versions, but should 1540135446Strhodes * form a consistent user interface. 1541135446Strhodes * 1542135446Strhodes * First, create a "default lookup" which won't actually be used 1543135446Strhodes * anywhere, except for cloning into new lookups 1544135446Strhodes */ 1545135446Strhodes 1546135446Strhodes debug("parse_args()"); 1547135446Strhodes if (!is_batchfile) { 1548135446Strhodes debug("making new lookup"); 1549135446Strhodes default_lookup = make_empty_lookup(); 1550254897Serwin default_lookup->adflag = ISC_TRUE; 1551254897Serwin default_lookup->edns = 0; 1552135446Strhodes 1553135446Strhodes#ifndef NOPOSIX 1554135446Strhodes /* 1555135446Strhodes * Treat ${HOME}/.digrc as a special batchfile 1556135446Strhodes */ 1557135446Strhodes INSIST(batchfp == NULL); 1558135446Strhodes homedir = getenv("HOME"); 1559135446Strhodes if (homedir != NULL) { 1560135446Strhodes unsigned int n; 1561135446Strhodes n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc", 1562186462Sdougb homedir); 1563135446Strhodes if (n < sizeof(rcfile)) 1564135446Strhodes batchfp = fopen(rcfile, "r"); 1565135446Strhodes } 1566135446Strhodes if (batchfp != NULL) { 1567135446Strhodes while (fgets(batchline, sizeof(batchline), 1568135446Strhodes batchfp) != 0) { 1569135446Strhodes debug("config line %s", batchline); 1570135446Strhodes bargc = 1; 1571135446Strhodes input = batchline; 1572135446Strhodes bargv[bargc] = next_token(&input, " \t\r\n"); 1573135446Strhodes while ((bargv[bargc] != NULL) && 1574135446Strhodes (bargc < 62)) { 1575135446Strhodes bargc++; 1576135446Strhodes bargv[bargc] = 1577135446Strhodes next_token(&input, " \t\r\n"); 1578135446Strhodes } 1579135446Strhodes 1580135446Strhodes bargv[0] = argv[0]; 1581135446Strhodes argv0 = argv[0]; 1582135446Strhodes 1583174187Sdougb for(i = 0; i < bargc; i++) 1584174187Sdougb debug(".digrc argv %d: %s", 1585174187Sdougb i, bargv[i]); 1586135446Strhodes parse_args(ISC_TRUE, ISC_TRUE, bargc, 1587135446Strhodes (char **)bargv); 1588135446Strhodes } 1589135446Strhodes fclose(batchfp); 1590135446Strhodes } 1591135446Strhodes#endif 1592135446Strhodes } 1593135446Strhodes 1594174187Sdougb if (is_batchfile && !config_only) { 1595174187Sdougb /* Processing '-f batchfile'. */ 1596174187Sdougb lookup = clone_lookup(default_lookup, ISC_TRUE); 1597174187Sdougb need_clone = ISC_FALSE; 1598174187Sdougb } else 1599174187Sdougb lookup = default_lookup; 1600135446Strhodes 1601135446Strhodes rc = argc; 1602135446Strhodes rv = argv; 1603135446Strhodes for (rc--, rv++; rc > 0; rc--, rv++) { 1604135446Strhodes debug("main parsing %s", rv[0]); 1605135446Strhodes if (strncmp(rv[0], "%", 1) == 0) 1606135446Strhodes break; 1607135446Strhodes if (strncmp(rv[0], "@", 1) == 0) { 1608234010Sdougb addresscount = getaddresses(lookup, &rv[0][1], NULL); 1609135446Strhodes } else if (rv[0][0] == '+') { 1610135446Strhodes plus_option(&rv[0][1], is_batchfile, 1611135446Strhodes lookup); 1612135446Strhodes } else if (rv[0][0] == '-') { 1613135446Strhodes if (rc <= 1) { 1614135446Strhodes if (dash_option(&rv[0][1], NULL, 1615170222Sdougb &lookup, &open_type_class, 1616174187Sdougb &need_clone, config_only, 1617174187Sdougb argc, argv, &firstarg)) { 1618135446Strhodes rc--; 1619135446Strhodes rv++; 1620135446Strhodes } 1621135446Strhodes } else { 1622135446Strhodes if (dash_option(&rv[0][1], rv[1], 1623170222Sdougb &lookup, &open_type_class, 1624174187Sdougb &need_clone, config_only, 1625174187Sdougb argc, argv, &firstarg)) { 1626135446Strhodes rc--; 1627135446Strhodes rv++; 1628135446Strhodes } 1629135446Strhodes } 1630135446Strhodes } else { 1631135446Strhodes /* 1632135446Strhodes * Anything which isn't an option 1633135446Strhodes */ 1634135446Strhodes if (open_type_class) { 1635165071Sdougb if (strncasecmp(rv[0], "ixfr=", 5) == 0) { 1636135446Strhodes rdtype = dns_rdatatype_ixfr; 1637135446Strhodes result = ISC_R_SUCCESS; 1638135446Strhodes } else { 1639135446Strhodes tr.base = rv[0]; 1640135446Strhodes tr.length = strlen(rv[0]); 1641135446Strhodes result = dns_rdatatype_fromtext(&rdtype, 1642186462Sdougb (isc_textregion_t *)&tr); 1643135446Strhodes if (result == ISC_R_SUCCESS && 1644135446Strhodes rdtype == dns_rdatatype_ixfr) { 1645135446Strhodes fprintf(stderr, ";; Warning, " 1646135446Strhodes "ixfr requires a " 1647135446Strhodes "serial number\n"); 1648135446Strhodes continue; 1649135446Strhodes } 1650135446Strhodes } 1651135446Strhodes if (result == ISC_R_SUCCESS) { 1652135446Strhodes if (lookup->rdtypeset) { 1653135446Strhodes fprintf(stderr, ";; Warning, " 1654135446Strhodes "extra type option\n"); 1655135446Strhodes } 1656135446Strhodes if (rdtype == dns_rdatatype_ixfr) { 1657224092Sdougb isc_uint32_t serial; 1658135446Strhodes lookup->rdtype = 1659135446Strhodes dns_rdatatype_ixfr; 1660135446Strhodes lookup->rdtypeset = ISC_TRUE; 1661224092Sdougb result = parse_uint(&serial, 1662224092Sdougb &rv[0][5], 1663224092Sdougb MAXSERIAL, 1664224092Sdougb "serial number"); 1665224092Sdougb if (result != ISC_R_SUCCESS) 1666224092Sdougb fatal("Couldn't parse " 1667224092Sdougb "serial number"); 1668224092Sdougb lookup->ixfr_serial = serial; 1669135446Strhodes lookup->section_question = 1670135446Strhodes plusquest; 1671135446Strhodes lookup->comments = pluscomm; 1672193149Sdougb lookup->tcp_mode = ISC_TRUE; 1673135446Strhodes } else { 1674135446Strhodes lookup->rdtype = rdtype; 1675135446Strhodes lookup->rdtypeset = ISC_TRUE; 1676135446Strhodes if (rdtype == 1677135446Strhodes dns_rdatatype_axfr) { 1678135446Strhodes lookup->section_question = 1679135446Strhodes plusquest; 1680135446Strhodes lookup->comments = pluscomm; 1681135446Strhodes } 1682135446Strhodes lookup->ixfr_serial = ISC_FALSE; 1683135446Strhodes } 1684135446Strhodes continue; 1685135446Strhodes } 1686135446Strhodes result = dns_rdataclass_fromtext(&rdclass, 1687135446Strhodes (isc_textregion_t *)&tr); 1688135446Strhodes if (result == ISC_R_SUCCESS) { 1689135446Strhodes if (lookup->rdclassset) { 1690135446Strhodes fprintf(stderr, ";; Warning, " 1691135446Strhodes "extra class option\n"); 1692135446Strhodes } 1693135446Strhodes lookup->rdclass = rdclass; 1694135446Strhodes lookup->rdclassset = ISC_TRUE; 1695135446Strhodes continue; 1696135446Strhodes } 1697135446Strhodes } 1698174187Sdougb 1699135446Strhodes if (!config_only) { 1700174187Sdougb if (need_clone) 1701174187Sdougb lookup = clone_lookup(default_lookup, 1702174187Sdougb ISC_TRUE); 1703174187Sdougb need_clone = ISC_TRUE; 1704186462Sdougb strncpy(lookup->textname, rv[0], 1705135446Strhodes sizeof(lookup->textname)); 1706135446Strhodes lookup->textname[sizeof(lookup->textname)-1]=0; 1707135446Strhodes lookup->trace_root = ISC_TF(lookup->trace || 1708135446Strhodes lookup->ns_search_only); 1709135446Strhodes lookup->new_search = ISC_TRUE; 1710174187Sdougb if (firstarg) { 1711174187Sdougb printgreeting(argc, argv, lookup); 1712174187Sdougb firstarg = ISC_FALSE; 1713174187Sdougb } 1714135446Strhodes ISC_LIST_APPEND(lookup_list, lookup, link); 1715135446Strhodes debug("looking up %s", lookup->textname); 1716135446Strhodes } 1717135446Strhodes /* XXX Error message */ 1718135446Strhodes } 1719135446Strhodes } 1720174187Sdougb 1721135446Strhodes /* 1722135446Strhodes * If we have a batchfile, seed the lookup list with the 1723135446Strhodes * first entry, then trust the callback in dighost_shutdown 1724135446Strhodes * to get the rest 1725135446Strhodes */ 1726135446Strhodes if ((batchname != NULL) && !(is_batchfile)) { 1727135446Strhodes if (strcmp(batchname, "-") == 0) 1728135446Strhodes batchfp = stdin; 1729135446Strhodes else 1730135446Strhodes batchfp = fopen(batchname, "r"); 1731135446Strhodes if (batchfp == NULL) { 1732135446Strhodes perror(batchname); 1733135446Strhodes if (exitcode < 8) 1734135446Strhodes exitcode = 8; 1735135446Strhodes fatal("couldn't open specified batch file"); 1736135446Strhodes } 1737135446Strhodes /* XXX Remove code dup from shutdown code */ 1738135446Strhodes next_line: 1739135446Strhodes if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 1740135446Strhodes bargc = 1; 1741135446Strhodes debug("batch line %s", batchline); 1742135446Strhodes if (batchline[0] == '\r' || batchline[0] == '\n' 1743135446Strhodes || batchline[0] == '#' || batchline[0] == ';') 1744135446Strhodes goto next_line; 1745135446Strhodes input = batchline; 1746135446Strhodes bargv[bargc] = next_token(&input, " \t\r\n"); 1747135446Strhodes while ((bargv[bargc] != NULL) && (bargc < 14)) { 1748135446Strhodes bargc++; 1749135446Strhodes bargv[bargc] = next_token(&input, " \t\r\n"); 1750135446Strhodes } 1751135446Strhodes 1752135446Strhodes bargv[0] = argv[0]; 1753135446Strhodes argv0 = argv[0]; 1754135446Strhodes 1755174187Sdougb for(i = 0; i < bargc; i++) 1756174187Sdougb debug("batch argv %d: %s", i, bargv[i]); 1757135446Strhodes parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 1758174187Sdougb return; 1759135446Strhodes } 1760174187Sdougb return; 1761135446Strhodes } 1762135446Strhodes /* 1763135446Strhodes * If no lookup specified, search for root 1764135446Strhodes */ 1765135446Strhodes if ((lookup_list.head == NULL) && !config_only) { 1766174187Sdougb if (need_clone) 1767174187Sdougb lookup = clone_lookup(default_lookup, ISC_TRUE); 1768174187Sdougb need_clone = ISC_TRUE; 1769135446Strhodes lookup->trace_root = ISC_TF(lookup->trace || 1770135446Strhodes lookup->ns_search_only); 1771135446Strhodes lookup->new_search = ISC_TRUE; 1772135446Strhodes strcpy(lookup->textname, "."); 1773135446Strhodes lookup->rdtype = dns_rdatatype_ns; 1774135446Strhodes lookup->rdtypeset = ISC_TRUE; 1775135446Strhodes if (firstarg) { 1776135446Strhodes printgreeting(argc, argv, lookup); 1777135446Strhodes firstarg = ISC_FALSE; 1778135446Strhodes } 1779135446Strhodes ISC_LIST_APPEND(lookup_list, lookup, link); 1780135446Strhodes } 1781174187Sdougb if (!need_clone) 1782174187Sdougb destroy_lookup(lookup); 1783135446Strhodes} 1784135446Strhodes 1785135446Strhodes/* 1786135446Strhodes * Callback from dighost.c to allow program-specific shutdown code. 1787135446Strhodes * Here, we're possibly reading from a batch file, then shutting down 1788135446Strhodes * for real if there's nothing in the batch file to read. 1789135446Strhodes */ 1790135446Strhodesvoid 1791135446Strhodesdighost_shutdown(void) { 1792135446Strhodes char batchline[MXNAME]; 1793135446Strhodes int bargc; 1794135446Strhodes char *bargv[16]; 1795135446Strhodes char *input; 1796174187Sdougb int i; 1797135446Strhodes 1798135446Strhodes if (batchname == NULL) { 1799135446Strhodes isc_app_shutdown(); 1800135446Strhodes return; 1801135446Strhodes } 1802135446Strhodes 1803135446Strhodes fflush(stdout); 1804135446Strhodes if (feof(batchfp)) { 1805135446Strhodes batchname = NULL; 1806135446Strhodes isc_app_shutdown(); 1807135446Strhodes if (batchfp != stdin) 1808135446Strhodes fclose(batchfp); 1809135446Strhodes return; 1810135446Strhodes } 1811135446Strhodes 1812135446Strhodes if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 1813135446Strhodes debug("batch line %s", batchline); 1814135446Strhodes bargc = 1; 1815135446Strhodes input = batchline; 1816135446Strhodes bargv[bargc] = next_token(&input, " \t\r\n"); 1817135446Strhodes while ((bargv[bargc] != NULL) && (bargc < 14)) { 1818135446Strhodes bargc++; 1819135446Strhodes bargv[bargc] = next_token(&input, " \t\r\n"); 1820135446Strhodes } 1821135446Strhodes 1822135446Strhodes bargv[0] = argv0; 1823135446Strhodes 1824174187Sdougb for(i = 0; i < bargc; i++) 1825174187Sdougb debug("batch argv %d: %s", i, bargv[i]); 1826135446Strhodes parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 1827135446Strhodes start_lookup(); 1828135446Strhodes } else { 1829135446Strhodes batchname = NULL; 1830135446Strhodes if (batchfp != stdin) 1831135446Strhodes fclose(batchfp); 1832135446Strhodes isc_app_shutdown(); 1833135446Strhodes return; 1834135446Strhodes } 1835135446Strhodes} 1836135446Strhodes 1837170222Sdougb/*% Main processing routine for dig */ 1838135446Strhodesint 1839135446Strhodesmain(int argc, char **argv) { 1840135446Strhodes isc_result_t result; 1841135446Strhodes 1842135446Strhodes ISC_LIST_INIT(lookup_list); 1843135446Strhodes ISC_LIST_INIT(server_list); 1844135446Strhodes ISC_LIST_INIT(search_list); 1845135446Strhodes 1846135446Strhodes debug("main()"); 1847135446Strhodes preparse_args(argc, argv); 1848135446Strhodes progname = argv[0]; 1849135446Strhodes result = isc_app_start(); 1850135446Strhodes check_result(result, "isc_app_start"); 1851135446Strhodes setup_libs(); 1852135446Strhodes parse_args(ISC_FALSE, ISC_FALSE, argc, argv); 1853135446Strhodes setup_system(); 1854135446Strhodes if (domainopt[0] != '\0') { 1855135446Strhodes set_search_domain(domainopt); 1856135446Strhodes usesearch = ISC_TRUE; 1857135446Strhodes } 1858135446Strhodes result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); 1859135446Strhodes check_result(result, "isc_app_onrun"); 1860135446Strhodes isc_app_run(); 1861174187Sdougb destroy_lookup(default_lookup); 1862135446Strhodes if (batchname != NULL) { 1863135446Strhodes if (batchfp != stdin) 1864135446Strhodes fclose(batchfp); 1865135446Strhodes batchname = NULL; 1866135446Strhodes } 1867135446Strhodes#ifdef DIG_SIGCHASE 1868135446Strhodes clean_trustedkey(); 1869135446Strhodes#endif 1870135446Strhodes cancel_all(); 1871135446Strhodes destroy_libs(); 1872135446Strhodes isc_app_finish(); 1873135446Strhodes return (exitcode); 1874135446Strhodes} 1875