Annotation of src/usr.bin/dig/dig.c, Revision 1.1
1.1 ! florian 1: /*
! 2: * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
! 3: *
! 4: * Permission to use, copy, modify, and/or distribute this software for any
! 5: * purpose with or without fee is hereby granted, provided that the above
! 6: * copyright notice and this permission notice appear in all copies.
! 7: *
! 8: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
! 9: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
! 10: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
! 11: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
! 12: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
! 13: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
! 14: * PERFORMANCE OF THIS SOFTWARE.
! 15: */
! 16:
! 17: /* $Id: dig.c,v 1.44 2020/01/28 17:17:04 florian Exp $ */
! 18:
! 19: /*! \file */
! 20: #include <sys/cdefs.h>
! 21:
! 22: #include <stdlib.h>
! 23: #include <time.h>
! 24: #include <unistd.h>
! 25: #include <ctype.h>
! 26:
! 27: #include <isc/app.h>
! 28: #include <isc/netaddr.h>
! 29: #include <isc/parseint.h>
! 30:
! 31: #include <string.h>
! 32: #include <isc/task.h>
! 33: #include <isc/util.h>
! 34:
! 35: #include <dns/byaddr.h>
! 36: #include <dns/fixedname.h>
! 37: #include <dns/masterdump.h>
! 38: #include <dns/message.h>
! 39: #include <dns/name.h>
! 40: #include <dns/rdata.h>
! 41: #include <dns/rdataset.h>
! 42: #include <dns/rdatatype.h>
! 43: #include <dns/rdataclass.h>
! 44: #include <dns/result.h>
! 45: #include <dns/tsig.h>
! 46:
! 47: #include "dig.h"
! 48:
! 49: #define ADD_STRING(b, s) { \
! 50: if (strlen(s) >= isc_buffer_availablelength(b)) \
! 51: return (ISC_R_NOSPACE); \
! 52: else \
! 53: isc_buffer_putstr(b, s); \
! 54: }
! 55:
! 56: #define DIG_MAX_ADDRESSES 20
! 57:
! 58: #ifndef DNS_NAME_INITABSOLUTE
! 59: #define DNS_NAME_INITABSOLUTE(A,B) { \
! 60: DNS_NAME_MAGIC, \
! 61: A, sizeof(A), sizeof(B), \
! 62: DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \
! 63: B, NULL, { (void *)-1, (void *)-1}, \
! 64: {NULL, NULL} \
! 65: }
! 66: #endif
! 67:
! 68: dig_lookup_t *default_lookup = NULL;
! 69:
! 70: static char *batchname = NULL;
! 71: static FILE *batchfp = NULL;
! 72: static char *argv0;
! 73: static int addresscount = 0;
! 74:
! 75: static char domainopt[DNS_NAME_MAXTEXT];
! 76: static char sitvalue[256];
! 77:
! 78: static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE,
! 79: ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE,
! 80: multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE,
! 81: onesoa = ISC_FALSE, use_usec = ISC_FALSE, nocrypto = ISC_FALSE,
! 82: ipv4only = ISC_FALSE, ipv6only = ISC_FALSE;
! 83: static uint32_t splitwidth = 0xffffffff;
! 84:
! 85: /*% rrcomments are neither explicitly enabled nor disabled by default */
! 86: static int rrcomments = 0;
! 87:
! 88: /*% opcode text */
! 89: static const char * const opcodetext[] = {
! 90: "QUERY",
! 91: "IQUERY",
! 92: "STATUS",
! 93: "RESERVED3",
! 94: "NOTIFY",
! 95: "UPDATE",
! 96: "RESERVED6",
! 97: "RESERVED7",
! 98: "RESERVED8",
! 99: "RESERVED9",
! 100: "RESERVED10",
! 101: "RESERVED11",
! 102: "RESERVED12",
! 103: "RESERVED13",
! 104: "RESERVED14",
! 105: "RESERVED15"
! 106: };
! 107:
! 108: /*% return code text */
! 109: static const char * const rcodetext[] = {
! 110: "NOERROR",
! 111: "FORMERR",
! 112: "SERVFAIL",
! 113: "NXDOMAIN",
! 114: "NOTIMP",
! 115: "REFUSED",
! 116: "YXDOMAIN",
! 117: "YXRRSET",
! 118: "NXRRSET",
! 119: "NOTAUTH",
! 120: "NOTZONE",
! 121: "RESERVED11",
! 122: "RESERVED12",
! 123: "RESERVED13",
! 124: "RESERVED14",
! 125: "RESERVED15",
! 126: "BADVERS"
! 127: };
! 128:
! 129: /*% safe rcodetext[] */
! 130: static const char *
! 131: rcode_totext(dns_rcode_t rcode)
! 132: {
! 133: static char buf[sizeof("?65535")];
! 134:
! 135: if (rcode == dns_rcode_badcookie)
! 136: return ("BADCOOKIE");
! 137: if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
! 138: snprintf(buf, sizeof(buf), "?%u", rcode);
! 139: return (buf);
! 140: }
! 141: return (rcodetext[rcode]);
! 142: }
! 143:
! 144: /*% print usage */
! 145: static void
! 146: print_usage(FILE *fp) {
! 147: fputs(
! 148: "usage: dig [@server] [-46hiuv] [-b address[#port]] [-c class] [-f file]\n"
! 149: " [-k keyfile] [-p port] [-q name] [-t type] [-x addr]\n"
! 150: " [-y [hmac:]name:key] [name] [type] [class]\n"
! 151: " +[no]aaonly +[no]additional +[no]adflag +[no]all +[no]answer\n"
! 152: " +[no]authority +[no]besteffort +bufsize=# +[no]cdflag +[no]class\n"
! 153: " +[no]cmd +[no]comments +[no]cookie[=value] +[no]crypto +[no]dnssec\n"
! 154: " +domain=name +[no]edns[=#] +ednsflags[=#] +[no]ednsnegotiation\n"
! 155: " +[no]ednsopt[=code[:value]] +[no]expire +[no]fail +[no]identify\n"
! 156: " +[no]ignore +[no]keepopen +[no]multiline +ndots=# +[no]nsid\n"
! 157: " +[no]nssearch +[no]onesoa +[no]opcode=# +[no]qr +[no]question\n"
! 158: " +[no]recurse +retry=# +[no]rrcomments +[no]search +[no]short\n"
! 159: " +[no]showsearch +[no]split=# +[no]stats +[no]subnet=addr[/prefix]\n"
! 160: " +[no]tcp +timeout=# +[no]trace +tries=# +[no]ttlid +[no]vc\n", fp);
! 161: }
! 162:
! 163: static __dead void
! 164: usage(void);
! 165:
! 166: static void
! 167: usage(void) {
! 168: print_usage(stderr);
! 169: exit(1);
! 170: }
! 171:
! 172: /*% version */
! 173: static void
! 174: version(void) {
! 175: fputs("dig " VERSION "\n", stderr);
! 176: }
! 177:
! 178: /*% help */
! 179: static void
! 180: help(void) {
! 181: print_usage(stdout);
! 182: }
! 183:
! 184: /*%
! 185: * Callback from dighost.c to print the received message.
! 186: */
! 187: static void
! 188: received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
! 189: uint64_t diff;
! 190: time_t tnow;
! 191: struct tm tmnow;
! 192: char time_str[100];
! 193: char fromtext[ISC_SOCKADDR_FORMATSIZE];
! 194:
! 195: isc_sockaddr_format(from, fromtext, sizeof(fromtext));
! 196:
! 197: if (query->lookup->stats && !short_form) {
! 198: diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
! 199: if (use_usec)
! 200: printf(";; Query time: %ld usec\n", (long) diff);
! 201: else
! 202: printf(";; Query time: %ld msec\n", (long) diff / 1000);
! 203: printf(";; SERVER: %s(%s)\n", fromtext, query->servname);
! 204: time(&tnow);
! 205: tmnow = *localtime(&tnow);
! 206:
! 207: if (strftime(time_str, sizeof(time_str),
! 208: "%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U)
! 209: printf(";; WHEN: %s\n", time_str);
! 210: if (query->lookup->doing_xfr) {
! 211: printf(";; XFR size: %u records (messages %u, "
! 212: "bytes %llu)\n",
! 213: query->rr_count, query->msg_count,
! 214: query->byte_count);
! 215: } else {
! 216: printf(";; MSG SIZE rcvd: %u\n", bytes);
! 217: }
! 218: if (tsigkey != NULL) {
! 219: if (!validated)
! 220: puts(";; WARNING -- Some TSIG could not "
! 221: "be validated");
! 222: }
! 223: if ((tsigkey == NULL) && (keysecret[0] != 0)) {
! 224: puts(";; WARNING -- TSIG key was not used.");
! 225: }
! 226: puts("");
! 227: } else if (query->lookup->identify && !short_form) {
! 228: diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
! 229: if (use_usec)
! 230: printf(";; Received %llu bytes "
! 231: "from %s(%s) in %ld us\n\n",
! 232: query->lookup->doing_xfr
! 233: ? query->byte_count
! 234: : (uint64_t)bytes,
! 235: fromtext, query->userarg, (long) diff);
! 236: else
! 237: printf(";; Received %llu bytes "
! 238: "from %s(%s) in %ld ms\n\n",
! 239: query->lookup->doing_xfr
! 240: ? query->byte_count
! 241: : (uint64_t)bytes,
! 242: fromtext, query->userarg, (long) diff / 1000);
! 243: }
! 244: }
! 245:
! 246: /*
! 247: * Callback from dighost.c to print that it is trying a server.
! 248: * Not used in dig.
! 249: * XXX print_trying
! 250: */
! 251: static void
! 252: trying(char *frm, dig_lookup_t *lookup) {
! 253: UNUSED(frm);
! 254: UNUSED(lookup);
! 255: }
! 256:
! 257: /*%
! 258: * Internal print routine used to print short form replies.
! 259: */
! 260: static isc_result_t
! 261: say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) {
! 262: isc_result_t result;
! 263: uint64_t diff;
! 264: char store[sizeof(" in 18446744073709551616 us.")];
! 265: unsigned int styleflags = 0;
! 266:
! 267: if (query->lookup->trace || query->lookup->ns_search_only) {
! 268: result = dns_rdatatype_totext(rdata->type, buf);
! 269: if (result != ISC_R_SUCCESS)
! 270: return (result);
! 271: ADD_STRING(buf, " ");
! 272: }
! 273:
! 274: /* Turn on rrcomments if explicitly enabled */
! 275: if (rrcomments > 0)
! 276: styleflags |= DNS_STYLEFLAG_RRCOMMENT;
! 277: if (nocrypto)
! 278: styleflags |= DNS_STYLEFLAG_NOCRYPTO;
! 279: result = dns_rdata_tofmttext(rdata, NULL, styleflags, 0,
! 280: splitwidth, " ", buf);
! 281: if (result == ISC_R_NOSPACE)
! 282: return (result);
! 283: check_result(result, "dns_rdata_totext");
! 284: if (query->lookup->identify) {
! 285:
! 286: diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
! 287: ADD_STRING(buf, " from server ");
! 288: ADD_STRING(buf, query->servname);
! 289: if (use_usec)
! 290: snprintf(store, sizeof(store), " in %llu us.", diff);
! 291: else
! 292: snprintf(store, sizeof(store), " in %llu ms.", diff / 1000);
! 293: ADD_STRING(buf, store);
! 294: }
! 295: ADD_STRING(buf, "\n");
! 296: return (ISC_R_SUCCESS);
! 297: }
! 298:
! 299: /*%
! 300: * short_form message print handler. Calls above say_message()
! 301: */
! 302: static isc_result_t
! 303: short_answer(dns_message_t *msg, dns_messagetextflag_t flags,
! 304: isc_buffer_t *buf, dig_query_t *query)
! 305: {
! 306: dns_name_t *name;
! 307: dns_rdataset_t *rdataset;
! 308: isc_result_t result, loopresult;
! 309: dns_name_t empty_name;
! 310: dns_rdata_t rdata = DNS_RDATA_INIT;
! 311:
! 312: UNUSED(flags);
! 313:
! 314: dns_name_init(&empty_name, NULL);
! 315: result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
! 316: if (result == ISC_R_NOMORE)
! 317: return (ISC_R_SUCCESS);
! 318: else if (result != ISC_R_SUCCESS)
! 319: return (result);
! 320:
! 321: for (;;) {
! 322: name = NULL;
! 323: dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
! 324:
! 325: for (rdataset = ISC_LIST_HEAD(name->list);
! 326: rdataset != NULL;
! 327: rdataset = ISC_LIST_NEXT(rdataset, link)) {
! 328: loopresult = dns_rdataset_first(rdataset);
! 329: while (loopresult == ISC_R_SUCCESS) {
! 330: dns_rdataset_current(rdataset, &rdata);
! 331: result = say_message(&rdata, query,
! 332: buf);
! 333: if (result == ISC_R_NOSPACE)
! 334: return (result);
! 335: check_result(result, "say_message");
! 336: loopresult = dns_rdataset_next(rdataset);
! 337: dns_rdata_reset(&rdata);
! 338: }
! 339: }
! 340: result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
! 341: if (result == ISC_R_NOMORE)
! 342: break;
! 343: else if (result != ISC_R_SUCCESS)
! 344: return (result);
! 345: }
! 346:
! 347: return (ISC_R_SUCCESS);
! 348: }
! 349:
! 350: static isc_boolean_t
! 351: isdotlocal(dns_message_t *msg) {
! 352: isc_result_t result;
! 353: static unsigned char local_ndata[] = { "\005local\0" };
! 354: static unsigned char local_offsets[] = { 0, 6 };
! 355: static dns_name_t local =
! 356: DNS_NAME_INITABSOLUTE(local_ndata, local_offsets);
! 357:
! 358: for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
! 359: result == ISC_R_SUCCESS;
! 360: result = dns_message_nextname(msg, DNS_SECTION_QUESTION))
! 361: {
! 362: dns_name_t *name = NULL;
! 363: dns_message_currentname(msg, DNS_SECTION_QUESTION, &name);
! 364: if (dns_name_issubdomain(name, &local))
! 365: return (ISC_TRUE);
! 366: }
! 367: return (ISC_FALSE);
! 368: }
! 369:
! 370: /*
! 371: * Callback from dighost.c to print the reply from a server
! 372: */
! 373: static isc_result_t
! 374: printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
! 375: isc_result_t result;
! 376: dns_messagetextflag_t flags;
! 377: isc_buffer_t *buf = NULL;
! 378: unsigned int len = OUTPUTBUF;
! 379: dns_master_style_t *style = NULL;
! 380: unsigned int styleflags = 0;
! 381:
! 382: styleflags |= DNS_STYLEFLAG_REL_OWNER;
! 383: if (query->lookup->comments)
! 384: styleflags |= DNS_STYLEFLAG_COMMENT;
! 385: /* Turn on rrcomments if explicitly enabled */
! 386: if (rrcomments > 0)
! 387: styleflags |= DNS_STYLEFLAG_RRCOMMENT;
! 388: if (nottl)
! 389: styleflags |= DNS_STYLEFLAG_NO_TTL;
! 390: if (noclass)
! 391: styleflags |= DNS_STYLEFLAG_NO_CLASS;
! 392: if (nocrypto)
! 393: styleflags |= DNS_STYLEFLAG_NOCRYPTO;
! 394: if (multiline) {
! 395: styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
! 396: styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
! 397: styleflags |= DNS_STYLEFLAG_REL_DATA;
! 398: styleflags |= DNS_STYLEFLAG_OMIT_TTL;
! 399: styleflags |= DNS_STYLEFLAG_TTL;
! 400: styleflags |= DNS_STYLEFLAG_MULTILINE;
! 401: /* Turn on rrcomments unless explicitly disabled */
! 402: if (rrcomments >= 0)
! 403: styleflags |= DNS_STYLEFLAG_RRCOMMENT;
! 404: }
! 405: if (multiline || (nottl && noclass))
! 406: result = dns_master_stylecreate2(&style, styleflags,
! 407: 24, 24, 24, 32, 80, 8,
! 408: splitwidth);
! 409: else if (nottl || noclass)
! 410: result = dns_master_stylecreate2(&style, styleflags,
! 411: 24, 24, 32, 40, 80, 8,
! 412: splitwidth);
! 413: else
! 414: result = dns_master_stylecreate2(&style, styleflags,
! 415: 24, 32, 40, 48, 80, 8,
! 416: splitwidth);
! 417: check_result(result, "dns_master_stylecreate");
! 418:
! 419: if (query->lookup->cmdline[0] != 0) {
! 420: if (!short_form)
! 421: fputs(query->lookup->cmdline, stdout);
! 422: query->lookup->cmdline[0]=0;
! 423: }
! 424: debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders",
! 425: query->lookup->comments ? "comments" : "nocomments",
! 426: short_form ? "short_form" : "long_form");
! 427:
! 428: flags = 0;
! 429: if (!headers) {
! 430: flags |= DNS_MESSAGETEXTFLAG_NOHEADERS;
! 431: flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
! 432: }
! 433: if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr)
! 434: flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA :
! 435: DNS_MESSAGETEXTFLAG_OMITSOA;
! 436: if (!query->lookup->comments)
! 437: flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
! 438:
! 439: result = isc_buffer_allocate(&buf, len);
! 440: check_result(result, "isc_buffer_allocate");
! 441:
! 442: if (query->lookup->comments && !short_form) {
! 443: if (query->lookup->cmdline[0] != 0)
! 444: printf("; %s\n", query->lookup->cmdline);
! 445: if (msg == query->lookup->sendmsg)
! 446: printf(";; Sending:\n");
! 447: else
! 448: printf(";; Got answer:\n");
! 449:
! 450: if (headers) {
! 451: if (isdotlocal(msg)) {
! 452: printf(";; WARNING: .local is reserved for "
! 453: "Multicast DNS\n;; You are currently "
! 454: "testing what happens when an mDNS "
! 455: "query is leaked to DNS\n");
! 456: }
! 457: printf(";; ->>HEADER<<- opcode: %s, status: %s, "
! 458: "id: %u\n",
! 459: opcodetext[msg->opcode],
! 460: rcode_totext(msg->rcode),
! 461: msg->id);
! 462: printf(";; flags:");
! 463: if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
! 464: printf(" qr");
! 465: if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
! 466: printf(" aa");
! 467: if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
! 468: printf(" tc");
! 469: if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
! 470: printf(" rd");
! 471: if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
! 472: printf(" ra");
! 473: if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
! 474: printf(" ad");
! 475: if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
! 476: printf(" cd");
! 477: if ((msg->flags & 0x0040U) != 0)
! 478: printf("; MBZ: 0x4");
! 479:
! 480: printf("; QUERY: %u, ANSWER: %u, "
! 481: "AUTHORITY: %u, ADDITIONAL: %u\n",
! 482: msg->counts[DNS_SECTION_QUESTION],
! 483: msg->counts[DNS_SECTION_ANSWER],
! 484: msg->counts[DNS_SECTION_AUTHORITY],
! 485: msg->counts[DNS_SECTION_ADDITIONAL]);
! 486:
! 487: if (msg != query->lookup->sendmsg &&
! 488: (msg->flags & DNS_MESSAGEFLAG_RD) != 0 &&
! 489: (msg->flags & DNS_MESSAGEFLAG_RA) == 0)
! 490: printf(";; WARNING: recursion requested "
! 491: "but not available\n");
! 492: }
! 493: if (msg != query->lookup->sendmsg &&
! 494: query->lookup->edns != -1 && msg->opt == NULL &&
! 495: (msg->rcode == dns_rcode_formerr ||
! 496: msg->rcode == dns_rcode_notimp))
! 497: printf("\n;; WARNING: EDNS query returned status "
! 498: "%s - retry with '%s+noedns'\n",
! 499: rcode_totext(msg->rcode),
! 500: query->lookup->dnssec ? "+nodnssec ": "");
! 501: if (msg != query->lookup->sendmsg && extrabytes != 0U)
! 502: printf(";; WARNING: Message has %u extra byte%s at "
! 503: "end\n", extrabytes, extrabytes != 0 ? "s" : "");
! 504: }
! 505:
! 506: repopulate_buffer:
! 507:
! 508: if (query->lookup->comments && headers && !short_form) {
! 509: result = dns_message_pseudosectiontotext(msg,
! 510: DNS_PSEUDOSECTION_OPT,
! 511: style, flags, buf);
! 512: if (result == ISC_R_NOSPACE) {
! 513: buftoosmall:
! 514: len += OUTPUTBUF;
! 515: isc_buffer_free(&buf);
! 516: result = isc_buffer_allocate(&buf, len);
! 517: if (result == ISC_R_SUCCESS)
! 518: goto repopulate_buffer;
! 519: else
! 520: goto cleanup;
! 521: }
! 522: check_result(result,
! 523: "dns_message_pseudosectiontotext");
! 524: }
! 525:
! 526: if (query->lookup->section_question && headers) {
! 527: if (!short_form) {
! 528: result = dns_message_sectiontotext(msg,
! 529: DNS_SECTION_QUESTION,
! 530: style, flags, buf);
! 531: if (result == ISC_R_NOSPACE)
! 532: goto buftoosmall;
! 533: check_result(result, "dns_message_sectiontotext");
! 534: }
! 535: }
! 536: if (query->lookup->section_answer) {
! 537: if (!short_form) {
! 538: result = dns_message_sectiontotext(msg,
! 539: DNS_SECTION_ANSWER,
! 540: style, flags, buf);
! 541: if (result == ISC_R_NOSPACE)
! 542: goto buftoosmall;
! 543: check_result(result, "dns_message_sectiontotext");
! 544: } else {
! 545: result = short_answer(msg, flags, buf, query);
! 546: if (result == ISC_R_NOSPACE)
! 547: goto buftoosmall;
! 548: check_result(result, "short_answer");
! 549: }
! 550: }
! 551: if (query->lookup->section_authority) {
! 552: if (!short_form) {
! 553: result = dns_message_sectiontotext(msg,
! 554: DNS_SECTION_AUTHORITY,
! 555: style, flags, buf);
! 556: if (result == ISC_R_NOSPACE)
! 557: goto buftoosmall;
! 558: check_result(result, "dns_message_sectiontotext");
! 559: }
! 560: }
! 561: if (query->lookup->section_additional) {
! 562: if (!short_form) {
! 563: result = dns_message_sectiontotext(msg,
! 564: DNS_SECTION_ADDITIONAL,
! 565: style, flags, buf);
! 566: if (result == ISC_R_NOSPACE)
! 567: goto buftoosmall;
! 568: check_result(result, "dns_message_sectiontotext");
! 569: /*
! 570: * Only print the signature on the first record.
! 571: */
! 572: if (headers) {
! 573: result = dns_message_pseudosectiontotext(
! 574: msg,
! 575: DNS_PSEUDOSECTION_TSIG,
! 576: style, flags, buf);
! 577: if (result == ISC_R_NOSPACE)
! 578: goto buftoosmall;
! 579: check_result(result,
! 580: "dns_message_pseudosectiontotext");
! 581: result = dns_message_pseudosectiontotext(
! 582: msg,
! 583: DNS_PSEUDOSECTION_SIG0,
! 584: style, flags, buf);
! 585: if (result == ISC_R_NOSPACE)
! 586: goto buftoosmall;
! 587: check_result(result,
! 588: "dns_message_pseudosectiontotext");
! 589: }
! 590: }
! 591: }
! 592:
! 593: if (headers && query->lookup->comments && !short_form)
! 594: printf("\n");
! 595:
! 596: printf("%.*s", (int)isc_buffer_usedlength(buf),
! 597: (char *)isc_buffer_base(buf));
! 598: isc_buffer_free(&buf);
! 599:
! 600: cleanup:
! 601: if (style != NULL)
! 602: dns_master_styledestroy(&style);
! 603: return (result);
! 604: }
! 605:
! 606: /*%
! 607: * print the greeting message when the program first starts up.
! 608: */
! 609: static void
! 610: printgreeting(int argc, char **argv, dig_lookup_t *lookup) {
! 611: int i;
! 612: static isc_boolean_t first = ISC_TRUE;
! 613: char append[MXNAME];
! 614:
! 615: if (printcmd) {
! 616: snprintf(lookup->cmdline, sizeof(lookup->cmdline),
! 617: "%s; <<>> dig " VERSION " <<>>",
! 618: first?"\n":"");
! 619: i = 1;
! 620: while (i < argc) {
! 621: snprintf(append, sizeof(append), " %s", argv[i++]);
! 622: strlcat(lookup->cmdline, append,
! 623: sizeof(lookup->cmdline));
! 624: }
! 625: strlcat(lookup->cmdline, "\n", sizeof(lookup->cmdline));
! 626: if (first && addresscount != 0) {
! 627: snprintf(append, sizeof(append),
! 628: "; (%d server%s found)\n",
! 629: addresscount,
! 630: addresscount > 1 ? "s" : "");
! 631: strlcat(lookup->cmdline, append,
! 632: sizeof(lookup->cmdline));
! 633: }
! 634: if (first) {
! 635: snprintf(append, sizeof(append),
! 636: ";; global options:%s%s\n",
! 637: short_form ? " +short" : "",
! 638: printcmd ? " +cmd" : "");
! 639: first = ISC_FALSE;
! 640: strlcat(lookup->cmdline, append,
! 641: sizeof(lookup->cmdline));
! 642: }
! 643: }
! 644: }
! 645:
! 646: /*%
! 647: * We're not using isc_commandline_parse() here since the command line
! 648: * syntax of dig is quite a bit different from that which can be described
! 649: * by that routine.
! 650: * XXX doc options
! 651: */
! 652:
! 653: static void
! 654: plus_option(const char *option, isc_boolean_t is_batchfile,
! 655: dig_lookup_t *lookup)
! 656: {
! 657: isc_result_t result;
! 658: char option_store[256];
! 659: char *cmd, *value, *ptr, *code;
! 660: uint32_t num;
! 661: isc_boolean_t state = ISC_TRUE;
! 662: size_t n;
! 663:
! 664: strlcpy(option_store, option, sizeof(option_store));
! 665: ptr = option_store;
! 666: cmd = next_token(&ptr, "=");
! 667: if (cmd == NULL) {
! 668: printf(";; Invalid option %s\n", option_store);
! 669: return;
! 670: }
! 671: value = ptr;
! 672: if (strncasecmp(cmd, "no", 2)==0) {
! 673: cmd += 2;
! 674: state = ISC_FALSE;
! 675: }
! 676:
! 677: #define FULLCHECK(A) \
! 678: do { \
! 679: size_t _l = strlen(cmd); \
! 680: if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \
! 681: goto invalid_option; \
! 682: } while (0)
! 683: #define FULLCHECK2(A, B) \
! 684: do { \
! 685: size_t _l = strlen(cmd); \
! 686: if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \
! 687: (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \
! 688: goto invalid_option; \
! 689: } while (0)
! 690:
! 691: switch (cmd[0]) {
! 692: case 'a':
! 693: switch (cmd[1]) {
! 694: case 'a': /* aaonly / aaflag */
! 695: FULLCHECK2("aaonly", "aaflag");
! 696: lookup->aaonly = state;
! 697: break;
! 698: case 'd':
! 699: switch (cmd[2]) {
! 700: case 'd': /* additional */
! 701: FULLCHECK("additional");
! 702: lookup->section_additional = state;
! 703: break;
! 704: case 'f': /* adflag */
! 705: case '\0': /* +ad is a synonym for +adflag */
! 706: FULLCHECK("adflag");
! 707: lookup->adflag = state;
! 708: break;
! 709: default:
! 710: goto invalid_option;
! 711: }
! 712: break;
! 713: case 'l': /* all */
! 714: FULLCHECK("all");
! 715: lookup->section_question = state;
! 716: lookup->section_authority = state;
! 717: lookup->section_answer = state;
! 718: lookup->section_additional = state;
! 719: lookup->comments = state;
! 720: lookup->stats = state;
! 721: printcmd = state;
! 722: break;
! 723: case 'n': /* answer */
! 724: FULLCHECK("answer");
! 725: lookup->section_answer = state;
! 726: break;
! 727: case 'u': /* authority */
! 728: FULLCHECK("authority");
! 729: lookup->section_authority = state;
! 730: break;
! 731: default:
! 732: goto invalid_option;
! 733: }
! 734: break;
! 735: case 'b':
! 736: switch (cmd[1]) {
! 737: case 'e':/* besteffort */
! 738: FULLCHECK("besteffort");
! 739: lookup->besteffort = state;
! 740: break;
! 741: case 'u':/* bufsize */
! 742: FULLCHECK("bufsize");
! 743: if (value == NULL)
! 744: goto need_value;
! 745: if (!state)
! 746: goto invalid_option;
! 747: result = parse_uint(&num, value, COMMSIZE,
! 748: "buffer size");
! 749: if (result != ISC_R_SUCCESS)
! 750: fatal("Couldn't parse buffer size");
! 751: lookup->udpsize = num;
! 752: break;
! 753: default:
! 754: goto invalid_option;
! 755: }
! 756: break;
! 757: case 'c':
! 758: switch (cmd[1]) {
! 759: case 'd':/* cdflag */
! 760: switch (cmd[2]) {
! 761: case 'f': /* cdflag */
! 762: case '\0': /* +cd is a synonym for +cdflag */
! 763: FULLCHECK("cdflag");
! 764: lookup->cdflag = state;
! 765: break;
! 766: default:
! 767: goto invalid_option;
! 768: }
! 769: break;
! 770: case 'l': /* class */
! 771: /* keep +cl for backwards compatibility */
! 772: FULLCHECK2("cl", "class");
! 773: noclass = ISC_TF(!state);
! 774: break;
! 775: case 'm': /* cmd */
! 776: FULLCHECK("cmd");
! 777: printcmd = state;
! 778: break;
! 779: case 'o': /* comments */
! 780: switch (cmd[2]) {
! 781: case 'o':
! 782: FULLCHECK("cookie");
! 783: goto sit;
! 784: case 'm':
! 785: FULLCHECK("comments");
! 786: lookup->comments = state;
! 787: if (lookup == default_lookup)
! 788: pluscomm = state;
! 789: break;
! 790: default:
! 791: goto invalid_option;
! 792: }
! 793: break;
! 794: case 'r':
! 795: FULLCHECK("crypto");
! 796: nocrypto = ISC_TF(!state);
! 797: break;
! 798: default:
! 799: goto invalid_option;
! 800: }
! 801: break;
! 802: case 'd':
! 803: switch (cmd[1]) {
! 804: case 'e': /* defname */
! 805: FULLCHECK("defname");
! 806: if (!lookup->trace) {
! 807: usesearch = state;
! 808: }
! 809: break;
! 810: case 'n': /* dnssec */
! 811: FULLCHECK("dnssec");
! 812: if (state && lookup->edns == -1)
! 813: lookup->edns = 0;
! 814: lookup->dnssec = state;
! 815: break;
! 816: case 'o': /* domain */
! 817: FULLCHECK("domain");
! 818: if (value == NULL)
! 819: goto need_value;
! 820: if (!state)
! 821: goto invalid_option;
! 822: strlcpy(domainopt, value, sizeof(domainopt));
! 823: break;
! 824: default:
! 825: goto invalid_option;
! 826: }
! 827: break;
! 828: case 'e':
! 829: switch (cmd[1]) {
! 830: case 'd':
! 831: switch(cmd[2]) {
! 832: case 'n':
! 833: switch (cmd[3]) {
! 834: case 's':
! 835: switch (cmd[4]) {
! 836: case 0:
! 837: FULLCHECK("edns");
! 838: if (!state) {
! 839: lookup->edns = -1;
! 840: break;
! 841: }
! 842: if (value == NULL) {
! 843: lookup->edns = 0;
! 844: break;
! 845: }
! 846: result = parse_uint(&num,
! 847: value,
! 848: 255,
! 849: "edns");
! 850: if (result != ISC_R_SUCCESS)
! 851: fatal("Couldn't parse "
! 852: "edns");
! 853: lookup->edns = num;
! 854: break;
! 855: case 'f':
! 856: FULLCHECK("ednsflags");
! 857: if (!state) {
! 858: lookup->ednsflags = 0;
! 859: break;
! 860: }
! 861: if (value == NULL) {
! 862: lookup->ednsflags = 0;
! 863: break;
! 864: }
! 865: result = parse_xint(&num,
! 866: value,
! 867: 0xffff,
! 868: "ednsflags");
! 869: if (result != ISC_R_SUCCESS)
! 870: fatal("Couldn't parse "
! 871: "ednsflags");
! 872: lookup->ednsflags = num;
! 873: break;
! 874: case 'n':
! 875: FULLCHECK("ednsnegotiation");
! 876: lookup->ednsneg = state;
! 877: break;
! 878: case 'o':
! 879: FULLCHECK("ednsopt");
! 880: if (!state) {
! 881: lookup->ednsoptscnt = 0;
! 882: break;
! 883: }
! 884: if (value == NULL)
! 885: fatal("ednsopt no "
! 886: "code point "
! 887: "specified");
! 888: code = next_token(&value, ":");
! 889: save_opt(lookup, code, value);
! 890: break;
! 891: default:
! 892: goto invalid_option;
! 893: }
! 894: break;
! 895: default:
! 896: goto invalid_option;
! 897: }
! 898: break;
! 899: default:
! 900: goto invalid_option;
! 901: }
! 902: break;
! 903: case 'x':
! 904: FULLCHECK("expire");
! 905: lookup->expire = state;
! 906: break;
! 907: default:
! 908: goto invalid_option;
! 909: }
! 910: break;
! 911: case 'f': /* fail */
! 912: FULLCHECK("fail");
! 913: lookup->servfail_stops = state;
! 914: break;
! 915: case 'i':
! 916: switch (cmd[1]) {
! 917: case 'd': /* identify */
! 918: switch (cmd[2]) {
! 919: case 'e':
! 920: FULLCHECK("identify");
! 921: lookup->identify = state;
! 922: break;
! 923: case 'n':
! 924: FULLCHECK("idnout");
! 925: fprintf(stderr, ";; IDN support not enabled\n");
! 926: break;
! 927: default:
! 928: goto invalid_option;
! 929: }
! 930: break;
! 931: case 'g': /* ignore */
! 932: default: /*
! 933: * Inherits default for compatibility (+[no]i*).
! 934: */
! 935: FULLCHECK("ignore");
! 936: lookup->ignore = state;
! 937: }
! 938: break;
! 939: case 'k':
! 940: FULLCHECK("keepopen");
! 941: keep_open = state;
! 942: break;
! 943: case 'm': /* multiline */
! 944: FULLCHECK("multiline");
! 945: multiline = state;
! 946: break;
! 947: case 'n':
! 948: switch (cmd[1]) {
! 949: case 'd': /* ndots */
! 950: FULLCHECK("ndots");
! 951: if (value == NULL)
! 952: goto need_value;
! 953: if (!state)
! 954: goto invalid_option;
! 955: result = parse_uint(&num, value, MAXNDOTS, "ndots");
! 956: if (result != ISC_R_SUCCESS)
! 957: fatal("Couldn't parse ndots");
! 958: ndots = num;
! 959: break;
! 960: case 's':
! 961: switch (cmd[2]) {
! 962: case 'i': /* nsid */
! 963: FULLCHECK("nsid");
! 964: if (state && lookup->edns == -1)
! 965: lookup->edns = 0;
! 966: lookup->nsid = state;
! 967: break;
! 968: case 's': /* nssearch */
! 969: FULLCHECK("nssearch");
! 970: lookup->ns_search_only = state;
! 971: if (state) {
! 972: lookup->trace_root = ISC_TRUE;
! 973: lookup->recurse = ISC_TRUE;
! 974: lookup->identify = ISC_TRUE;
! 975: lookup->stats = ISC_FALSE;
! 976: lookup->comments = ISC_FALSE;
! 977: lookup->section_additional = ISC_FALSE;
! 978: lookup->section_authority = ISC_FALSE;
! 979: lookup->section_question = ISC_FALSE;
! 980: lookup->rdtype = dns_rdatatype_ns;
! 981: lookup->rdtypeset = ISC_TRUE;
! 982: short_form = ISC_TRUE;
! 983: rrcomments = 0;
! 984: }
! 985: break;
! 986: default:
! 987: goto invalid_option;
! 988: }
! 989: break;
! 990: default:
! 991: goto invalid_option;
! 992: }
! 993: break;
! 994: case 'o':
! 995: switch (cmd[1]) {
! 996: case 'n':
! 997: FULLCHECK("onesoa");
! 998: onesoa = state;
! 999: break;
! 1000: case 'p':
! 1001: FULLCHECK("opcode");
! 1002: if (!state) {
! 1003: lookup->opcode = 0; /* default - query */
! 1004: break;
! 1005: }
! 1006: if (value == NULL)
! 1007: goto need_value;
! 1008: for (num = 0;
! 1009: num < sizeof(opcodetext)/sizeof(opcodetext[0]);
! 1010: num++) {
! 1011: if (strcasecmp(opcodetext[num], value) == 0)
! 1012: break;
! 1013: }
! 1014: if (num < 16) {
! 1015: lookup->opcode = (dns_opcode_t)num;
! 1016: break;
! 1017: }
! 1018: result = parse_uint(&num, value, 15, "opcode");
! 1019: if (result != ISC_R_SUCCESS)
! 1020: fatal("Couldn't parse opcode");
! 1021: lookup->opcode = (dns_opcode_t)num;
! 1022: break;
! 1023: default:
! 1024: goto invalid_option;
! 1025: }
! 1026: break;
! 1027: case 'q':
! 1028: switch (cmd[1]) {
! 1029: case 'r': /* qr */
! 1030: FULLCHECK("qr");
! 1031: qr = state;
! 1032: break;
! 1033: case 'u': /* question */
! 1034: FULLCHECK("question");
! 1035: lookup->section_question = state;
! 1036: if (lookup == default_lookup)
! 1037: plusquest = state;
! 1038: break;
! 1039: default:
! 1040: goto invalid_option;
! 1041: }
! 1042: break;
! 1043: case 'r':
! 1044: switch (cmd[1]) {
! 1045: case 'd': /* rdflag */
! 1046: FULLCHECK("rdflag");
! 1047: lookup->recurse = state;
! 1048: break;
! 1049: case 'e':
! 1050: switch (cmd[2]) {
! 1051: case 'c': /* recurse */
! 1052: FULLCHECK("recurse");
! 1053: lookup->recurse = state;
! 1054: break;
! 1055: case 't': /* retry / retries */
! 1056: FULLCHECK2("retry", "retries");
! 1057: if (value == NULL)
! 1058: goto need_value;
! 1059: if (!state)
! 1060: goto invalid_option;
! 1061: result = parse_uint(&lookup->retries, value,
! 1062: MAXTRIES - 1, "retries");
! 1063: if (result != ISC_R_SUCCESS)
! 1064: fatal("Couldn't parse retries");
! 1065: lookup->retries++;
! 1066: break;
! 1067: default:
! 1068: goto invalid_option;
! 1069: }
! 1070: break;
! 1071: case 'r': /* rrcomments */
! 1072: FULLCHECK("rrcomments");
! 1073: rrcomments = state ? 1 : -1;
! 1074: break;
! 1075: default:
! 1076: goto invalid_option;
! 1077: }
! 1078: break;
! 1079: case 's':
! 1080: switch (cmd[1]) {
! 1081: case 'e': /* search */
! 1082: FULLCHECK("search");
! 1083: if (!lookup->trace) {
! 1084: usesearch = state;
! 1085: }
! 1086: break;
! 1087: case 'h':
! 1088: if (cmd[2] != 'o')
! 1089: goto invalid_option;
! 1090: switch (cmd[3]) {
! 1091: case 'r': /* short */
! 1092: FULLCHECK("short");
! 1093: short_form = state;
! 1094: if (state) {
! 1095: printcmd = ISC_FALSE;
! 1096: lookup->section_additional = ISC_FALSE;
! 1097: lookup->section_answer = ISC_TRUE;
! 1098: lookup->section_authority = ISC_FALSE;
! 1099: lookup->section_question = ISC_FALSE;
! 1100: lookup->comments = ISC_FALSE;
! 1101: lookup->stats = ISC_FALSE;
! 1102: rrcomments = -1;
! 1103: }
! 1104: break;
! 1105: case 'w': /* showsearch */
! 1106: FULLCHECK("showsearch");
! 1107: if (!lookup->trace) {
! 1108: showsearch = state;
! 1109: usesearch = state;
! 1110: }
! 1111: break;
! 1112: default:
! 1113: goto invalid_option;
! 1114: }
! 1115: break;
! 1116: case 'i':
! 1117: switch (cmd[2]) {
! 1118: case 't': /* sit */
! 1119: FULLCHECK("sit");
! 1120: sit:
! 1121: if (state && lookup->edns == -1)
! 1122: lookup->edns = 0;
! 1123: lookup->sit = state;
! 1124: if (value != NULL) {
! 1125: n = strlcpy(sitvalue, value,
! 1126: sizeof(sitvalue));
! 1127: if (n >= sizeof(sitvalue))
! 1128: fatal("SIT data too large");
! 1129: lookup->sitvalue = sitvalue;
! 1130: } else
! 1131: lookup->sitvalue = NULL;
! 1132: break;
! 1133: default:
! 1134: goto invalid_option;
! 1135: }
! 1136: break;
! 1137: case 'p': /* split */
! 1138: FULLCHECK("split");
! 1139: if (value != NULL && !state)
! 1140: goto invalid_option;
! 1141: if (!state) {
! 1142: splitwidth = 0;
! 1143: break;
! 1144: } else if (value == NULL)
! 1145: break;
! 1146:
! 1147: result = parse_uint(&splitwidth, value,
! 1148: 1023, "split");
! 1149: if ((splitwidth % 4) != 0U) {
! 1150: splitwidth = ((splitwidth + 3) / 4) * 4;
! 1151: fprintf(stderr, ";; Warning, split must be "
! 1152: "a multiple of 4; adjusting "
! 1153: "to %u\n", splitwidth);
! 1154: }
! 1155: /*
! 1156: * There is an adjustment done in the
! 1157: * totext_<rrtype>() functions which causes
! 1158: * splitwidth to shrink. This is okay when we're
! 1159: * using the default width but incorrect in this
! 1160: * case, so we correct for it
! 1161: */
! 1162: if (splitwidth)
! 1163: splitwidth += 3;
! 1164: if (result != ISC_R_SUCCESS)
! 1165: fatal("Couldn't parse split");
! 1166: break;
! 1167: case 't': /* stats */
! 1168: FULLCHECK("stats");
! 1169: lookup->stats = state;
! 1170: break;
! 1171: case 'u': /* subnet */
! 1172: FULLCHECK("subnet");
! 1173: if (state && value == NULL)
! 1174: goto need_value;
! 1175: if (!state) {
! 1176: if (lookup->ecs_addr != NULL) {
! 1177: free(lookup->ecs_addr);
! 1178: lookup->ecs_addr = NULL;
! 1179: }
! 1180: break;
! 1181: }
! 1182: if (lookup->edns == -1)
! 1183: lookup->edns = 0;
! 1184: if (lookup->ecs_addr != NULL) {
! 1185: free(lookup->ecs_addr);
! 1186: lookup->ecs_addr = NULL;
! 1187: }
! 1188: result = parse_netprefix(&lookup->ecs_addr, value);
! 1189: if (result != ISC_R_SUCCESS)
! 1190: fatal("Couldn't parse client");
! 1191: break;
! 1192: default:
! 1193: goto invalid_option;
! 1194: }
! 1195: break;
! 1196: case 't':
! 1197: switch (cmd[1]) {
! 1198: case 'c': /* tcp */
! 1199: FULLCHECK("tcp");
! 1200: if (!is_batchfile) {
! 1201: lookup->tcp_mode = state;
! 1202: lookup->tcp_mode_set = ISC_TRUE;
! 1203: }
! 1204: break;
! 1205: case 'i': /* timeout */
! 1206: FULLCHECK("timeout");
! 1207: if (value == NULL)
! 1208: goto need_value;
! 1209: if (!state)
! 1210: goto invalid_option;
! 1211: result = parse_uint(&timeout, value, MAXTIMEOUT,
! 1212: "timeout");
! 1213: if (result != ISC_R_SUCCESS)
! 1214: fatal("Couldn't parse timeout");
! 1215: if (timeout == 0)
! 1216: timeout = 1;
! 1217: break;
! 1218: case 'r':
! 1219: switch (cmd[2]) {
! 1220: case 'a': /* trace */
! 1221: FULLCHECK("trace");
! 1222: lookup->trace = state;
! 1223: lookup->trace_root = state;
! 1224: if (state) {
! 1225: lookup->recurse = ISC_FALSE;
! 1226: lookup->identify = ISC_TRUE;
! 1227: lookup->comments = ISC_FALSE;
! 1228: rrcomments = 0;
! 1229: lookup->stats = ISC_FALSE;
! 1230: lookup->section_additional = ISC_FALSE;
! 1231: lookup->section_authority = ISC_TRUE;
! 1232: lookup->section_question = ISC_FALSE;
! 1233: lookup->dnssec = ISC_TRUE;
! 1234: usesearch = ISC_FALSE;
! 1235: }
! 1236: break;
! 1237: case 'i': /* tries */
! 1238: FULLCHECK("tries");
! 1239: if (value == NULL)
! 1240: goto need_value;
! 1241: if (!state)
! 1242: goto invalid_option;
! 1243: result = parse_uint(&lookup->retries, value,
! 1244: MAXTRIES, "tries");
! 1245: if (result != ISC_R_SUCCESS)
! 1246: fatal("Couldn't parse tries");
! 1247: if (lookup->retries == 0)
! 1248: lookup->retries = 1;
! 1249: break;
! 1250: default:
! 1251: goto invalid_option;
! 1252: }
! 1253: break;
! 1254: case 't': /* ttlid */
! 1255: FULLCHECK("ttlid");
! 1256: nottl = ISC_TF(!state);
! 1257: break;
! 1258: default:
! 1259: goto invalid_option;
! 1260: }
! 1261: break;
! 1262: case 'v':
! 1263: FULLCHECK("vc");
! 1264: if (!is_batchfile) {
! 1265: lookup->tcp_mode = state;
! 1266: lookup->tcp_mode_set = ISC_TRUE;
! 1267: }
! 1268: break;
! 1269: default:
! 1270: invalid_option:
! 1271: need_value:
! 1272: fprintf(stderr, "Invalid option: +%s\n",
! 1273: option);
! 1274: usage();
! 1275: }
! 1276: return;
! 1277: }
! 1278:
! 1279: /*%
! 1280: * #ISC_TRUE returned if value was used
! 1281: */
! 1282: static const char *single_dash_opts = "46dhinuv";
! 1283: static const char *dash_opts = "46bcdfhikmnptvyx";
! 1284: static isc_boolean_t
! 1285: dash_option(char *option, char *next, dig_lookup_t **lookup,
! 1286: isc_boolean_t *open_type_class, isc_boolean_t *need_clone,
! 1287: isc_boolean_t config_only, int argc, char **argv,
! 1288: isc_boolean_t *firstarg)
! 1289: {
! 1290: char opt, *value, *ptr, *ptr2, *ptr3;
! 1291: isc_result_t result;
! 1292: isc_boolean_t value_from_next;
! 1293: isc_textregion_t tr;
! 1294: dns_rdatatype_t rdtype;
! 1295: dns_rdataclass_t rdclass;
! 1296: char textname[MXNAME];
! 1297: struct in_addr in4;
! 1298: struct in6_addr in6;
! 1299: in_port_t srcport;
! 1300: char *hash, *cmd;
! 1301: uint32_t num;
! 1302:
! 1303: while (strpbrk(option, single_dash_opts) == &option[0]) {
! 1304: /*
! 1305: * Since the -[46dhinuv] options do not take an argument,
! 1306: * account for them (in any number and/or combination)
! 1307: * if they appear as the first character(s) of a q-opt.
! 1308: */
! 1309: opt = option[0];
! 1310: switch (opt) {
! 1311: case '4':
! 1312: if (have_ipv4) {
! 1313: isc_net_disableipv6();
! 1314: have_ipv6 = ISC_FALSE;
! 1315: } else {
! 1316: fatal("can't find IPv4 networking");
! 1317: /* NOTREACHED */
! 1318: return (ISC_FALSE);
! 1319: }
! 1320: break;
! 1321: case '6':
! 1322: if (have_ipv6) {
! 1323: isc_net_disableipv4();
! 1324: have_ipv4 = ISC_FALSE;
! 1325: } else {
! 1326: fatal("can't find IPv6 networking");
! 1327: /* NOTREACHED */
! 1328: return (ISC_FALSE);
! 1329: }
! 1330: break;
! 1331: case 'd':
! 1332: ptr = strpbrk(&option[1], dash_opts);
! 1333: if (ptr != &option[1]) {
! 1334: cmd = option;
! 1335: FULLCHECK("debug");
! 1336: debugging = ISC_TRUE;
! 1337: return (ISC_FALSE);
! 1338: } else
! 1339: debugging = ISC_TRUE;
! 1340: break;
! 1341: case 'h':
! 1342: help();
! 1343: exit(0);
! 1344: break;
! 1345: case 'i':
! 1346: ip6_int = ISC_TRUE;
! 1347: break;
! 1348: case 'n':
! 1349: /* deprecated */
! 1350: break;
! 1351: case 'u':
! 1352: use_usec = ISC_TRUE;
! 1353: break;
! 1354: case 'v':
! 1355: version();
! 1356: exit(0);
! 1357: break;
! 1358: }
! 1359: if (strlen(option) > 1U)
! 1360: option = &option[1];
! 1361: else
! 1362: return (ISC_FALSE);
! 1363: }
! 1364: opt = option[0];
! 1365: if (strlen(option) > 1U) {
! 1366: value_from_next = ISC_FALSE;
! 1367: value = &option[1];
! 1368: } else {
! 1369: value_from_next = ISC_TRUE;
! 1370: value = next;
! 1371: }
! 1372: if (value == NULL)
! 1373: goto invalid_option;
! 1374: switch (opt) {
! 1375: case 'b':
! 1376: hash = strchr(value, '#');
! 1377: if (hash != NULL) {
! 1378: result = parse_uint(&num, hash + 1, MAXPORT,
! 1379: "port number");
! 1380: if (result != ISC_R_SUCCESS)
! 1381: fatal("Couldn't parse port number");
! 1382: srcport = num;
! 1383: *hash = '\0';
! 1384: } else
! 1385: srcport = 0;
! 1386: if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) {
! 1387: isc_sockaddr_fromin6(&bind_address, &in6, srcport);
! 1388: isc_net_disableipv4();
! 1389: } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) {
! 1390: isc_sockaddr_fromin(&bind_address, &in4, srcport);
! 1391: isc_net_disableipv6();
! 1392: } else {
! 1393: if (hash != NULL)
! 1394: *hash = '#';
! 1395: fatal("invalid address %s", value);
! 1396: }
! 1397: if (hash != NULL)
! 1398: *hash = '#';
! 1399: specified_source = ISC_TRUE;
! 1400: return (value_from_next);
! 1401: case 'c':
! 1402: if ((*lookup)->rdclassset) {
! 1403: fprintf(stderr, ";; Warning, extra class option\n");
! 1404: }
! 1405: *open_type_class = ISC_FALSE;
! 1406: tr.base = value;
! 1407: tr.length = (unsigned int) strlen(value);
! 1408: result = dns_rdataclass_fromtext(&rdclass,
! 1409: (isc_textregion_t *)&tr);
! 1410: if (result == ISC_R_SUCCESS) {
! 1411: (*lookup)->rdclass = rdclass;
! 1412: (*lookup)->rdclassset = ISC_TRUE;
! 1413: } else
! 1414: fprintf(stderr, ";; Warning, ignoring "
! 1415: "invalid class %s\n",
! 1416: value);
! 1417: return (value_from_next);
! 1418: case 'f':
! 1419: batchname = value;
! 1420: return (value_from_next);
! 1421: case 'k':
! 1422: strlcpy(keyfile, value, sizeof(keyfile));
! 1423: return (value_from_next);
! 1424: case 'p':
! 1425: result = parse_uint(&num, value, MAXPORT, "port number");
! 1426: if (result != ISC_R_SUCCESS)
! 1427: fatal("Couldn't parse port number");
! 1428: port = num;
! 1429: return (value_from_next);
! 1430: case 'q':
! 1431: if (!config_only) {
! 1432: if (*need_clone)
! 1433: (*lookup) = clone_lookup(default_lookup,
! 1434: ISC_TRUE);
! 1435: *need_clone = ISC_TRUE;
! 1436: strlcpy((*lookup)->textname, value,
! 1437: sizeof((*lookup)->textname));
! 1438: (*lookup)->trace_root = ISC_TF((*lookup)->trace ||
! 1439: (*lookup)->ns_search_only);
! 1440: (*lookup)->new_search = ISC_TRUE;
! 1441: if (*firstarg) {
! 1442: printgreeting(argc, argv, *lookup);
! 1443: *firstarg = ISC_FALSE;
! 1444: }
! 1445: ISC_LIST_APPEND(lookup_list, (*lookup), link);
! 1446: debug("looking up %s", (*lookup)->textname);
! 1447: }
! 1448: return (value_from_next);
! 1449: case 't':
! 1450: *open_type_class = ISC_FALSE;
! 1451: if (strncasecmp(value, "ixfr=", 5) == 0) {
! 1452: rdtype = dns_rdatatype_ixfr;
! 1453: result = ISC_R_SUCCESS;
! 1454: } else {
! 1455: tr.base = value;
! 1456: tr.length = (unsigned int) strlen(value);
! 1457: result = dns_rdatatype_fromtext(&rdtype,
! 1458: (isc_textregion_t *)&tr);
! 1459: if (result == ISC_R_SUCCESS &&
! 1460: rdtype == dns_rdatatype_ixfr) {
! 1461: result = DNS_R_UNKNOWN;
! 1462: }
! 1463: }
! 1464: if (result == ISC_R_SUCCESS) {
! 1465: if ((*lookup)->rdtypeset) {
! 1466: fprintf(stderr, ";; Warning, "
! 1467: "extra type option\n");
! 1468: }
! 1469: if (rdtype == dns_rdatatype_ixfr) {
! 1470: uint32_t serial;
! 1471: (*lookup)->rdtype = dns_rdatatype_ixfr;
! 1472: (*lookup)->rdtypeset = ISC_TRUE;
! 1473: result = parse_uint(&serial, &value[5],
! 1474: MAXSERIAL, "serial number");
! 1475: if (result != ISC_R_SUCCESS)
! 1476: fatal("Couldn't parse serial number");
! 1477: (*lookup)->ixfr_serial = serial;
! 1478: (*lookup)->section_question = plusquest;
! 1479: (*lookup)->comments = pluscomm;
! 1480: if (!(*lookup)->tcp_mode_set)
! 1481: (*lookup)->tcp_mode = ISC_TRUE;
! 1482: } else {
! 1483: (*lookup)->rdtype = rdtype;
! 1484: if (!config_only)
! 1485: (*lookup)->rdtypeset = ISC_TRUE;
! 1486: if (rdtype == dns_rdatatype_axfr) {
! 1487: (*lookup)->section_question = plusquest;
! 1488: (*lookup)->comments = pluscomm;
! 1489: }
! 1490: (*lookup)->ixfr_serial = ISC_FALSE;
! 1491: }
! 1492: } else
! 1493: fprintf(stderr, ";; Warning, ignoring "
! 1494: "invalid type %s\n",
! 1495: value);
! 1496: return (value_from_next);
! 1497: case 'y':
! 1498: ptr = next_token(&value, ":"); /* hmac type or name */
! 1499: if (ptr == NULL) {
! 1500: usage();
! 1501: }
! 1502: ptr2 = next_token(&value, ":"); /* name or secret */
! 1503: if (ptr2 == NULL)
! 1504: usage();
! 1505: ptr3 = next_token(&value, ":"); /* secret or NULL */
! 1506: if (ptr3 != NULL) {
! 1507: parse_hmac(ptr);
! 1508: ptr = ptr2;
! 1509: ptr2 = ptr3;
! 1510: } else {
! 1511: hmacname = DNS_TSIG_HMACSHA256_NAME;
! 1512: digestbits = 0;
! 1513: }
! 1514: strlcpy(keynametext, ptr, sizeof(keynametext));
! 1515: strlcpy(keysecret, ptr2, sizeof(keysecret));
! 1516: return (value_from_next);
! 1517: case 'x':
! 1518: if (*need_clone)
! 1519: *lookup = clone_lookup(default_lookup, ISC_TRUE);
! 1520: *need_clone = ISC_TRUE;
! 1521: if (get_reverse(textname, sizeof(textname), value,
! 1522: ip6_int, ISC_FALSE) == ISC_R_SUCCESS) {
! 1523: strlcpy((*lookup)->textname, textname,
! 1524: sizeof((*lookup)->textname));
! 1525: debug("looking up %s", (*lookup)->textname);
! 1526: (*lookup)->trace_root = ISC_TF((*lookup)->trace ||
! 1527: (*lookup)->ns_search_only);
! 1528: (*lookup)->ip6_int = ip6_int;
! 1529: if (!(*lookup)->rdtypeset)
! 1530: (*lookup)->rdtype = dns_rdatatype_ptr;
! 1531: if (!(*lookup)->rdclassset)
! 1532: (*lookup)->rdclass = dns_rdataclass_in;
! 1533: (*lookup)->new_search = ISC_TRUE;
! 1534: if (*firstarg) {
! 1535: printgreeting(argc, argv, *lookup);
! 1536: *firstarg = ISC_FALSE;
! 1537: }
! 1538: ISC_LIST_APPEND(lookup_list, *lookup, link);
! 1539: } else {
! 1540: fprintf(stderr, "Invalid IP address %s\n", value);
! 1541: exit(1);
! 1542: }
! 1543: return (value_from_next);
! 1544: invalid_option:
! 1545: default:
! 1546: fprintf(stderr, "Invalid option: -%s\n", option);
! 1547: usage();
! 1548: }
! 1549: /* NOTREACHED */
! 1550: return (ISC_FALSE);
! 1551: }
! 1552:
! 1553: /*%
! 1554: * Because we may be trying to do memory allocation recording, we're going
! 1555: * to need to parse the arguments for the -m *before* we start the main
! 1556: * argument parsing routine.
! 1557: *
! 1558: * I'd prefer not to have to do this, but I am not quite sure how else to
! 1559: * fix the problem. Argument parsing in dig involves memory allocation
! 1560: * by its nature, so it can't be done in the main argument parser.
! 1561: */
! 1562: static void
! 1563: preparse_args(int argc, char **argv) {
! 1564: int rc;
! 1565: char **rv;
! 1566: char *option;
! 1567:
! 1568: rc = argc;
! 1569: rv = argv;
! 1570: for (rc--, rv++; rc > 0; rc--, rv++) {
! 1571: if (rv[0][0] != '-')
! 1572: continue;
! 1573: option = &rv[0][1];
! 1574: while (strpbrk(option, single_dash_opts) == &option[0]) {
! 1575: switch (option[0]) {
! 1576: case '4':
! 1577: if (ipv6only)
! 1578: fatal("only one of -4 and -6 allowed");
! 1579: ipv4only = ISC_TRUE;
! 1580: break;
! 1581: case '6':
! 1582: if (ipv4only)
! 1583: fatal("only one of -4 and -6 allowed");
! 1584: ipv6only = ISC_TRUE;
! 1585: break;
! 1586: }
! 1587: option = &option[1];
! 1588: }
! 1589: }
! 1590: }
! 1591:
! 1592: static void
! 1593: parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
! 1594: int argc, char **argv)
! 1595: {
! 1596: isc_result_t result;
! 1597: isc_textregion_t tr;
! 1598: isc_boolean_t firstarg = ISC_TRUE;
! 1599: dig_lookup_t *lookup = NULL;
! 1600: dns_rdatatype_t rdtype;
! 1601: dns_rdataclass_t rdclass;
! 1602: isc_boolean_t open_type_class = ISC_TRUE;
! 1603: char batchline[MXNAME];
! 1604: int bargc;
! 1605: char *bargv[64];
! 1606: int rc;
! 1607: char **rv;
! 1608: #ifndef NOPOSIX
! 1609: char *homedir;
! 1610: char rcfile[256];
! 1611: #endif
! 1612: char *input;
! 1613: int i;
! 1614: isc_boolean_t need_clone = ISC_TRUE;
! 1615:
! 1616: /*
! 1617: * The semantics for parsing the args is a bit complex; if
! 1618: * we don't have a host yet, make the arg apply globally,
! 1619: * otherwise make it apply to the latest host. This is
! 1620: * a bit different than the previous versions, but should
! 1621: * form a consistent user interface.
! 1622: *
! 1623: * First, create a "default lookup" which won't actually be used
! 1624: * anywhere, except for cloning into new lookups
! 1625: */
! 1626:
! 1627: debug("parse_args()");
! 1628: if (!is_batchfile) {
! 1629: debug("making new lookup");
! 1630: default_lookup = make_empty_lookup();
! 1631: default_lookup->adflag = ISC_TRUE;
! 1632: default_lookup->edns = 0;
! 1633:
! 1634: #ifndef NOPOSIX
! 1635: /*
! 1636: * Treat ${HOME}/.digrc as a special batchfile
! 1637: */
! 1638: INSIST(batchfp == NULL);
! 1639: homedir = getenv("HOME");
! 1640: if (homedir != NULL) {
! 1641: unsigned int n;
! 1642: n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc",
! 1643: homedir);
! 1644: if (n < sizeof(rcfile))
! 1645: batchfp = fopen(rcfile, "r");
! 1646: }
! 1647: if (batchfp != NULL) {
! 1648: while (fgets(batchline, sizeof(batchline),
! 1649: batchfp) != 0) {
! 1650: debug("config line %s", batchline);
! 1651: bargc = 1;
! 1652: input = batchline;
! 1653: bargv[bargc] = next_token(&input, " \t\r\n");
! 1654: while ((bargc < 62) && (bargv[bargc] != NULL)) {
! 1655: bargc++;
! 1656: bargv[bargc] =
! 1657: next_token(&input, " \t\r\n");
! 1658: }
! 1659:
! 1660: bargv[0] = argv[0];
! 1661: argv0 = argv[0];
! 1662:
! 1663: for(i = 0; i < bargc; i++)
! 1664: debug(".digrc argv %d: %s",
! 1665: i, bargv[i]);
! 1666: parse_args(ISC_TRUE, ISC_TRUE, bargc,
! 1667: (char **)bargv);
! 1668: }
! 1669: fclose(batchfp);
! 1670: }
! 1671: #endif
! 1672: }
! 1673:
! 1674: if (is_batchfile && !config_only) {
! 1675: /* Processing '-f batchfile'. */
! 1676: lookup = clone_lookup(default_lookup, ISC_TRUE);
! 1677: need_clone = ISC_FALSE;
! 1678: } else
! 1679: lookup = default_lookup;
! 1680:
! 1681: rc = argc;
! 1682: rv = argv;
! 1683: for (rc--, rv++; rc > 0; rc--, rv++) {
! 1684: debug("main parsing %s", rv[0]);
! 1685: if (strncmp(rv[0], "%", 1) == 0)
! 1686: break;
! 1687: if (rv[0][0] == '@') {
! 1688:
! 1689: if (is_batchfile && !config_only) {
! 1690: addresscount = getaddresses(lookup, &rv[0][1],
! 1691: &result);
! 1692: if (result != ISC_R_SUCCESS) {
! 1693: fprintf(stderr, "couldn't get address "
! 1694: "for '%s': %s: skipping "
! 1695: "lookup\n", &rv[0][1],
! 1696: isc_result_totext(result));
! 1697: if (ISC_LINK_LINKED(lookup, link))
! 1698: ISC_LIST_DEQUEUE(lookup_list,
! 1699: lookup, link);
! 1700: destroy_lookup(lookup);
! 1701: return;
! 1702: }
! 1703: } else
! 1704: addresscount = getaddresses(lookup, &rv[0][1],
! 1705: NULL);
! 1706: } else if (rv[0][0] == '+') {
! 1707: plus_option(&rv[0][1], is_batchfile,
! 1708: lookup);
! 1709: } else if (rv[0][0] == '-') {
! 1710: if (rc <= 1) {
! 1711: if (dash_option(&rv[0][1], NULL,
! 1712: &lookup, &open_type_class,
! 1713: &need_clone, config_only,
! 1714: argc, argv, &firstarg)) {
! 1715: rc--;
! 1716: rv++;
! 1717: }
! 1718: } else {
! 1719: if (dash_option(&rv[0][1], rv[1],
! 1720: &lookup, &open_type_class,
! 1721: &need_clone, config_only,
! 1722: argc, argv, &firstarg)) {
! 1723: rc--;
! 1724: rv++;
! 1725: }
! 1726: }
! 1727: } else {
! 1728: /*
! 1729: * Anything which isn't an option
! 1730: */
! 1731: if (open_type_class) {
! 1732: if (strncasecmp(rv[0], "ixfr=", 5) == 0) {
! 1733: rdtype = dns_rdatatype_ixfr;
! 1734: result = ISC_R_SUCCESS;
! 1735: } else {
! 1736: tr.base = rv[0];
! 1737: tr.length =
! 1738: (unsigned int) strlen(rv[0]);
! 1739: result = dns_rdatatype_fromtext(&rdtype,
! 1740: (isc_textregion_t *)&tr);
! 1741: if (result == ISC_R_SUCCESS &&
! 1742: rdtype == dns_rdatatype_ixfr) {
! 1743: fprintf(stderr, ";; Warning, "
! 1744: "ixfr requires a "
! 1745: "serial number\n");
! 1746: continue;
! 1747: }
! 1748: }
! 1749: if (result == ISC_R_SUCCESS) {
! 1750: if (lookup->rdtypeset) {
! 1751: fprintf(stderr, ";; Warning, "
! 1752: "extra type option\n");
! 1753: }
! 1754: if (rdtype == dns_rdatatype_ixfr) {
! 1755: uint32_t serial;
! 1756: lookup->rdtype =
! 1757: dns_rdatatype_ixfr;
! 1758: lookup->rdtypeset = ISC_TRUE;
! 1759: result = parse_uint(&serial,
! 1760: &rv[0][5],
! 1761: MAXSERIAL,
! 1762: "serial number");
! 1763: if (result != ISC_R_SUCCESS)
! 1764: fatal("Couldn't parse "
! 1765: "serial number");
! 1766: lookup->ixfr_serial = serial;
! 1767: lookup->section_question =
! 1768: plusquest;
! 1769: lookup->comments = pluscomm;
! 1770: if (!lookup->tcp_mode_set)
! 1771: lookup->tcp_mode = ISC_TRUE;
! 1772: } else {
! 1773: lookup->rdtype = rdtype;
! 1774: lookup->rdtypeset = ISC_TRUE;
! 1775: if (rdtype ==
! 1776: dns_rdatatype_axfr) {
! 1777: lookup->section_question =
! 1778: plusquest;
! 1779: lookup->comments = pluscomm;
! 1780: }
! 1781: lookup->ixfr_serial = ISC_FALSE;
! 1782: }
! 1783: continue;
! 1784: }
! 1785: result = dns_rdataclass_fromtext(&rdclass,
! 1786: (isc_textregion_t *)&tr);
! 1787: if (result == ISC_R_SUCCESS) {
! 1788: if (lookup->rdclassset) {
! 1789: fprintf(stderr, ";; Warning, "
! 1790: "extra class option\n");
! 1791: }
! 1792: lookup->rdclass = rdclass;
! 1793: lookup->rdclassset = ISC_TRUE;
! 1794: continue;
! 1795: }
! 1796: }
! 1797:
! 1798: if (!config_only) {
! 1799: if (need_clone)
! 1800: lookup = clone_lookup(default_lookup,
! 1801: ISC_TRUE);
! 1802: need_clone = ISC_TRUE;
! 1803: strlcpy(lookup->textname, rv[0],
! 1804: sizeof(lookup->textname));
! 1805: lookup->trace_root = ISC_TF(lookup->trace ||
! 1806: lookup->ns_search_only);
! 1807: lookup->new_search = ISC_TRUE;
! 1808: if (firstarg) {
! 1809: printgreeting(argc, argv, lookup);
! 1810: firstarg = ISC_FALSE;
! 1811: }
! 1812: ISC_LIST_APPEND(lookup_list, lookup, link);
! 1813: debug("looking up %s", lookup->textname);
! 1814: }
! 1815: /* XXX Error message */
! 1816: }
! 1817: }
! 1818:
! 1819: /*
! 1820: * If we have a batchfile, seed the lookup list with the
! 1821: * first entry, then trust the callback in dighost_shutdown
! 1822: * to get the rest
! 1823: */
! 1824: if ((batchname != NULL) && !(is_batchfile)) {
! 1825: if (strcmp(batchname, "-") == 0)
! 1826: batchfp = stdin;
! 1827: else
! 1828: batchfp = fopen(batchname, "r");
! 1829: if (batchfp == NULL) {
! 1830: perror(batchname);
! 1831: if (exitcode < 8)
! 1832: exitcode = 8;
! 1833: fatal("couldn't open specified batch file");
! 1834: }
! 1835: /* XXX Remove code dup from shutdown code */
! 1836: next_line:
! 1837: if (fgets(batchline, sizeof(batchline), batchfp) != 0) {
! 1838: bargc = 1;
! 1839: debug("batch line %s", batchline);
! 1840: if (batchline[0] == '\r' || batchline[0] == '\n'
! 1841: || batchline[0] == '#' || batchline[0] == ';')
! 1842: goto next_line;
! 1843: input = batchline;
! 1844: bargv[bargc] = next_token(&input, " \t\r\n");
! 1845: while ((bargc < 14) && (bargv[bargc] != NULL)) {
! 1846: bargc++;
! 1847: bargv[bargc] = next_token(&input, " \t\r\n");
! 1848: }
! 1849:
! 1850: bargv[0] = argv[0];
! 1851: argv0 = argv[0];
! 1852:
! 1853: for(i = 0; i < bargc; i++)
! 1854: debug("batch argv %d: %s", i, bargv[i]);
! 1855: parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
! 1856: return;
! 1857: }
! 1858: return;
! 1859: }
! 1860: /*
! 1861: * If no lookup specified, search for root
! 1862: */
! 1863: if ((lookup_list.head == NULL) && !config_only) {
! 1864: if (need_clone)
! 1865: lookup = clone_lookup(default_lookup, ISC_TRUE);
! 1866: need_clone = ISC_TRUE;
! 1867: lookup->trace_root = ISC_TF(lookup->trace ||
! 1868: lookup->ns_search_only);
! 1869: lookup->new_search = ISC_TRUE;
! 1870: strlcpy(lookup->textname, ".", sizeof(lookup->textname));
! 1871: lookup->rdtype = dns_rdatatype_ns;
! 1872: lookup->rdtypeset = ISC_TRUE;
! 1873: if (firstarg) {
! 1874: printgreeting(argc, argv, lookup);
! 1875: firstarg = ISC_FALSE;
! 1876: }
! 1877: ISC_LIST_APPEND(lookup_list, lookup, link);
! 1878: }
! 1879: if (!need_clone)
! 1880: destroy_lookup(lookup);
! 1881: }
! 1882:
! 1883: /*
! 1884: * Callback from dighost.c to allow program-specific shutdown code.
! 1885: * Here, we're possibly reading from a batch file, then shutting down
! 1886: * for real if there's nothing in the batch file to read.
! 1887: */
! 1888: static void
! 1889: query_finished(void) {
! 1890: char batchline[MXNAME];
! 1891: int bargc;
! 1892: char *bargv[16];
! 1893: char *input;
! 1894: int i;
! 1895:
! 1896: if (batchname == NULL) {
! 1897: isc_app_shutdown();
! 1898: return;
! 1899: }
! 1900:
! 1901: fflush(stdout);
! 1902: if (feof(batchfp)) {
! 1903: batchname = NULL;
! 1904: isc_app_shutdown();
! 1905: if (batchfp != stdin)
! 1906: fclose(batchfp);
! 1907: return;
! 1908: }
! 1909:
! 1910: if (fgets(batchline, sizeof(batchline), batchfp) != 0) {
! 1911: debug("batch line %s", batchline);
! 1912: bargc = 1;
! 1913: input = batchline;
! 1914: bargv[bargc] = next_token(&input, " \t\r\n");
! 1915: while ((bargc < 14) && (bargv[bargc] != NULL)) {
! 1916: bargc++;
! 1917: bargv[bargc] = next_token(&input, " \t\r\n");
! 1918: }
! 1919:
! 1920: bargv[0] = argv0;
! 1921:
! 1922: for(i = 0; i < bargc; i++)
! 1923: debug("batch argv %d: %s", i, bargv[i]);
! 1924: parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
! 1925: start_lookup();
! 1926: } else {
! 1927: batchname = NULL;
! 1928: if (batchfp != stdin)
! 1929: fclose(batchfp);
! 1930: isc_app_shutdown();
! 1931: return;
! 1932: }
! 1933: }
! 1934:
! 1935: void dig_setup(int argc, char **argv)
! 1936: {
! 1937: isc_result_t result;
! 1938:
! 1939: ISC_LIST_INIT(lookup_list);
! 1940: ISC_LIST_INIT(server_list);
! 1941: ISC_LIST_INIT(search_list);
! 1942:
! 1943: if (pledge("stdio rpath inet dns", NULL) == -1) {
! 1944: perror("pledge");
! 1945: exit(1);
! 1946: }
! 1947:
! 1948: debug("dig_setup()");
! 1949:
! 1950: /* setup dighost callbacks */
! 1951: dighost_printmessage = printmessage;
! 1952: dighost_received = received;
! 1953: dighost_trying = trying;
! 1954: dighost_shutdown = query_finished;
! 1955:
! 1956: progname = argv[0];
! 1957: preparse_args(argc, argv);
! 1958:
! 1959: result = isc_app_start();
! 1960: check_result(result, "isc_app_start");
! 1961:
! 1962: setup_libs();
! 1963: setup_system(ipv4only, ipv6only);
! 1964: }
! 1965:
! 1966: void dig_query_setup(isc_boolean_t is_batchfile, isc_boolean_t config_only,
! 1967: int argc, char **argv)
! 1968: {
! 1969: debug("dig_query_setup");
! 1970:
! 1971: parse_args(is_batchfile, config_only, argc, argv);
! 1972: if (keyfile[0] != 0)
! 1973: setup_file_key();
! 1974: else if (keysecret[0] != 0)
! 1975: setup_text_key();
! 1976:
! 1977: if (pledge("stdio inet dns", NULL) == -1) {
! 1978: perror("pledge");
! 1979: exit(1);
! 1980: }
! 1981:
! 1982: if (domainopt[0] != '\0') {
! 1983: set_search_domain(domainopt);
! 1984: usesearch = ISC_TRUE;
! 1985: }
! 1986: }
! 1987:
! 1988: void dig_startup() {
! 1989: isc_result_t result;
! 1990:
! 1991: debug("dig_startup()");
! 1992:
! 1993: result = isc_app_onrun(global_task, onrun_callback, NULL);
! 1994: check_result(result, "isc_app_onrun");
! 1995: isc_app_run();
! 1996: }
! 1997:
! 1998: void dig_query_start()
! 1999: {
! 2000: start_lookup();
! 2001: }
! 2002:
! 2003: void
! 2004: dig_shutdown() {
! 2005: destroy_lookup(default_lookup);
! 2006: if (batchname != NULL) {
! 2007: if (batchfp != stdin)
! 2008: fclose(batchfp);
! 2009: batchname = NULL;
! 2010: }
! 2011:
! 2012: cancel_all();
! 2013: destroy_libs();
! 2014: isc_app_finish();
! 2015: }
! 2016:
! 2017: /*% Main processing routine for dig */
! 2018: int
! 2019: main(int argc, char **argv) {
! 2020: extern char *__progname;
! 2021:
! 2022: if (strcmp("host", __progname) == 0)
! 2023: return host_main(argc, argv);
! 2024: if (strcmp("nslookup", __progname) == 0)
! 2025: return nslookup_main(argc, argv);
! 2026:
! 2027: dig_setup(argc, argv);
! 2028: dig_query_setup(ISC_FALSE, ISC_FALSE, argc, argv);
! 2029: dig_startup();
! 2030: dig_shutdown();
! 2031:
! 2032: return (exitcode);
! 2033: }