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