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