Annotation of src/usr.bin/dig/dig.c, Revision 1.15
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.15 ! florian 17: /* $Id: dig.c,v 1.14 2020/09/14 08:37:08 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:
62: static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE,
63: ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE,
64: multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE,
65: onesoa = ISC_FALSE, use_usec = ISC_FALSE, nocrypto = ISC_FALSE,
66: ipv4only = ISC_FALSE, ipv6only = ISC_FALSE;
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
172: received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
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:
337: static isc_boolean_t
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))
352: return (ISC_TRUE);
353: }
354: return (ISC_FALSE);
355: }
356:
357: /*
358: * Callback from dighost.c to print the reply from a server
359: */
360: static isc_result_t
361: printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
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;
599: static isc_boolean_t first = ISC_TRUE;
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" : "");
626: first = ISC_FALSE;
627: strlcat(lookup->cmdline, append,
628: sizeof(lookup->cmdline));
629: }
630: }
631: }
632:
633: static void
634: plus_option(const char *option, isc_boolean_t is_batchfile,
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;
643: isc_boolean_t state = ISC_TRUE;
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;
656: state = ISC_FALSE;
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");
754: noclass = ISC_TF(!state);
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");
777: nocrypto = ISC_TF(!state);
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) {
952: lookup->trace_root = ISC_TRUE;
953: lookup->recurse = ISC_TRUE;
954: lookup->identify = ISC_TRUE;
955: lookup->stats = ISC_FALSE;
956: lookup->comments = ISC_FALSE;
957: lookup->section_additional = ISC_FALSE;
958: lookup->section_authority = ISC_FALSE;
959: lookup->section_question = ISC_FALSE;
960: lookup->rdtype = dns_rdatatype_ns;
961: lookup->rdtypeset = ISC_TRUE;
962: short_form = ISC_TRUE;
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) {
1076: printcmd = ISC_FALSE;
1077: lookup->section_additional = ISC_FALSE;
1078: lookup->section_answer = ISC_TRUE;
1079: lookup->section_authority = ISC_FALSE;
1080: lookup->section_question = ISC_FALSE;
1081: lookup->comments = ISC_FALSE;
1082: lookup->stats = ISC_FALSE;
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: }
1168: result = parse_netprefix(&lookup->ecs_addr, value);
1169: if (result != ISC_R_SUCCESS)
1170: fatal("Couldn't parse client");
1171: break;
1172: default:
1173: goto invalid_option;
1174: }
1175: break;
1176: case 't':
1177: switch (cmd[1]) {
1178: case 'c': /* tcp */
1179: FULLCHECK("tcp");
1180: if (!is_batchfile) {
1181: lookup->tcp_mode = state;
1182: lookup->tcp_mode_set = ISC_TRUE;
1183: }
1184: break;
1185: case 'i': /* timeout */
1186: FULLCHECK("timeout");
1187: if (value == NULL)
1188: goto need_value;
1189: if (!state)
1190: goto invalid_option;
1.13 florian 1191: timeout = strtonum(value, 0, MAXTIMEOUT, &errstr);
1192: if (errstr != NULL)
1193: fatal("timeout is %s: '%s'", errstr, value);
1.1 florian 1194: if (timeout == 0)
1195: timeout = 1;
1196: break;
1197: case 'r':
1198: switch (cmd[2]) {
1199: case 'a': /* trace */
1200: FULLCHECK("trace");
1201: lookup->trace = state;
1202: lookup->trace_root = state;
1203: if (state) {
1204: lookup->recurse = ISC_FALSE;
1205: lookup->identify = ISC_TRUE;
1206: lookup->comments = ISC_FALSE;
1207: rrcomments = 0;
1208: lookup->stats = ISC_FALSE;
1209: lookup->section_additional = ISC_FALSE;
1210: lookup->section_authority = ISC_TRUE;
1211: lookup->section_question = ISC_FALSE;
1212: lookup->dnssec = ISC_TRUE;
1213: usesearch = ISC_FALSE;
1214: }
1215: break;
1216: case 'i': /* tries */
1217: FULLCHECK("tries");
1218: if (value == NULL)
1219: goto need_value;
1220: if (!state)
1221: goto invalid_option;
1.13 florian 1222: lookup->retries = strtonum(value, 0, MAXTRIES,
1223: &errstr);
1224: if (errstr != NULL)
1225: fatal("tries is %s: '%s'", errstr,
1226: value);
1.1 florian 1227: if (lookup->retries == 0)
1228: lookup->retries = 1;
1229: break;
1230: default:
1231: goto invalid_option;
1232: }
1233: break;
1234: case 't': /* ttlid */
1235: FULLCHECK("ttlid");
1236: nottl = ISC_TF(!state);
1237: break;
1238: default:
1239: goto invalid_option;
1240: }
1241: break;
1242: case 'v':
1243: FULLCHECK("vc");
1244: if (!is_batchfile) {
1245: lookup->tcp_mode = state;
1246: lookup->tcp_mode_set = ISC_TRUE;
1247: }
1248: break;
1249: default:
1250: invalid_option:
1251: need_value:
1252: fprintf(stderr, "Invalid option: +%s\n",
1253: option);
1254: usage();
1255: }
1256: return;
1257: }
1258:
1259: /*%
1260: * #ISC_TRUE returned if value was used
1261: */
1262: static const char *single_dash_opts = "46dhinuv";
1263: static const char *dash_opts = "46bcdfhikmnptvyx";
1264: static isc_boolean_t
1265: dash_option(char *option, char *next, dig_lookup_t **lookup,
1266: isc_boolean_t *open_type_class, isc_boolean_t *need_clone,
1267: isc_boolean_t config_only, int argc, char **argv,
1268: isc_boolean_t *firstarg)
1269: {
1270: char opt, *value, *ptr, *ptr2, *ptr3;
1271: isc_result_t result;
1272: isc_boolean_t value_from_next;
1273: isc_textregion_t tr;
1274: dns_rdatatype_t rdtype;
1275: dns_rdataclass_t rdclass;
1276: char textname[MXNAME];
1277: struct in_addr in4;
1278: struct in6_addr in6;
1279: in_port_t srcport;
1280: char *hash, *cmd;
1281: uint32_t num;
1.13 florian 1282: const char *errstr;
1.1 florian 1283:
1284: while (strpbrk(option, single_dash_opts) == &option[0]) {
1285: /*
1286: * Since the -[46dhinuv] options do not take an argument,
1287: * account for them (in any number and/or combination)
1288: * if they appear as the first character(s) of a q-opt.
1289: */
1290: opt = option[0];
1291: switch (opt) {
1292: case '4':
1.15 ! florian 1293: if (have_ipv4)
1.1 florian 1294: have_ipv6 = ISC_FALSE;
1.15 ! florian 1295: else
1.1 florian 1296: fatal("can't find IPv4 networking");
1297: break;
1298: case '6':
1.15 ! florian 1299: if (have_ipv6)
1.1 florian 1300: have_ipv4 = ISC_FALSE;
1.15 ! florian 1301: else
1.1 florian 1302: fatal("can't find IPv6 networking");
1303: break;
1304: case 'd':
1305: ptr = strpbrk(&option[1], dash_opts);
1306: if (ptr != &option[1]) {
1307: cmd = option;
1308: FULLCHECK("debug");
1309: debugging = ISC_TRUE;
1310: return (ISC_FALSE);
1311: } else
1312: debugging = ISC_TRUE;
1313: break;
1314: case 'h':
1315: help();
1316: exit(0);
1317: break;
1318: case 'i':
1319: ip6_int = ISC_TRUE;
1320: break;
1321: case 'n':
1322: /* deprecated */
1323: break;
1324: case 'u':
1325: use_usec = ISC_TRUE;
1326: break;
1327: case 'v':
1328: version();
1329: exit(0);
1330: break;
1331: }
1332: if (strlen(option) > 1U)
1333: option = &option[1];
1334: else
1335: return (ISC_FALSE);
1336: }
1337: opt = option[0];
1338: if (strlen(option) > 1U) {
1339: value_from_next = ISC_FALSE;
1340: value = &option[1];
1341: } else {
1342: value_from_next = ISC_TRUE;
1343: value = next;
1344: }
1345: if (value == NULL)
1346: goto invalid_option;
1347: switch (opt) {
1348: case 'b':
1349: hash = strchr(value, '#');
1350: if (hash != NULL) {
1.13 florian 1351: num = strtonum(hash + 1, 0, MAXPORT, &errstr);
1352: if (errstr != NULL)
1353: fatal("port number is %s: '%s'", errstr,
1354: hash + 1);
1.1 florian 1355: srcport = num;
1356: *hash = '\0';
1357: } else
1358: srcport = 0;
1.15 ! florian 1359: if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1)
1.1 florian 1360: isc_sockaddr_fromin6(&bind_address, &in6, srcport);
1.15 ! florian 1361: else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1)
1.1 florian 1362: isc_sockaddr_fromin(&bind_address, &in4, srcport);
1.15 ! florian 1363: else
1.1 florian 1364: fatal("invalid address %s", value);
1.15 ! florian 1365:
1.1 florian 1366: if (hash != NULL)
1367: *hash = '#';
1368: specified_source = ISC_TRUE;
1369: return (value_from_next);
1370: case 'c':
1371: if ((*lookup)->rdclassset) {
1372: fprintf(stderr, ";; Warning, extra class option\n");
1373: }
1374: *open_type_class = ISC_FALSE;
1375: tr.base = value;
1376: tr.length = (unsigned int) strlen(value);
1377: result = dns_rdataclass_fromtext(&rdclass,
1378: (isc_textregion_t *)&tr);
1379: if (result == ISC_R_SUCCESS) {
1380: (*lookup)->rdclass = rdclass;
1381: (*lookup)->rdclassset = ISC_TRUE;
1382: } else
1383: fprintf(stderr, ";; Warning, ignoring "
1384: "invalid class %s\n",
1385: value);
1386: return (value_from_next);
1387: case 'f':
1388: batchname = value;
1389: return (value_from_next);
1390: case 'k':
1391: strlcpy(keyfile, value, sizeof(keyfile));
1392: return (value_from_next);
1393: case 'p':
1.13 florian 1394: num = strtonum(value, 0, MAXPORT, &errstr);
1395: if (errstr != NULL)
1396: fatal("port number is %s: '%s'", errstr, value);
1.1 florian 1397: port = num;
1398: return (value_from_next);
1399: case 'q':
1400: if (!config_only) {
1401: if (*need_clone)
1402: (*lookup) = clone_lookup(default_lookup,
1403: ISC_TRUE);
1404: *need_clone = ISC_TRUE;
1405: strlcpy((*lookup)->textname, value,
1406: sizeof((*lookup)->textname));
1407: (*lookup)->trace_root = ISC_TF((*lookup)->trace ||
1408: (*lookup)->ns_search_only);
1409: (*lookup)->new_search = ISC_TRUE;
1410: if (*firstarg) {
1411: printgreeting(argc, argv, *lookup);
1412: *firstarg = ISC_FALSE;
1413: }
1414: ISC_LIST_APPEND(lookup_list, (*lookup), link);
1415: debug("looking up %s", (*lookup)->textname);
1416: }
1417: return (value_from_next);
1418: case 't':
1419: *open_type_class = ISC_FALSE;
1420: if (strncasecmp(value, "ixfr=", 5) == 0) {
1421: rdtype = dns_rdatatype_ixfr;
1422: result = ISC_R_SUCCESS;
1423: } else {
1424: tr.base = value;
1425: tr.length = (unsigned int) strlen(value);
1426: result = dns_rdatatype_fromtext(&rdtype,
1427: (isc_textregion_t *)&tr);
1428: if (result == ISC_R_SUCCESS &&
1429: rdtype == dns_rdatatype_ixfr) {
1430: result = DNS_R_UNKNOWN;
1431: }
1432: }
1433: if (result == ISC_R_SUCCESS) {
1434: if ((*lookup)->rdtypeset) {
1435: fprintf(stderr, ";; Warning, "
1436: "extra type option\n");
1437: }
1438: if (rdtype == dns_rdatatype_ixfr) {
1439: uint32_t serial;
1440: (*lookup)->rdtype = dns_rdatatype_ixfr;
1441: (*lookup)->rdtypeset = ISC_TRUE;
1.13 florian 1442: serial = strtonum(&value[5], 0, MAXSERIAL,
1443: &errstr);
1444: if (errstr != NULL)
1445: fatal("serial number is %s: '%s'",
1446: errstr, &value[5]);
1.1 florian 1447: (*lookup)->ixfr_serial = serial;
1448: (*lookup)->section_question = plusquest;
1449: (*lookup)->comments = pluscomm;
1450: if (!(*lookup)->tcp_mode_set)
1451: (*lookup)->tcp_mode = ISC_TRUE;
1452: } else {
1453: (*lookup)->rdtype = rdtype;
1454: if (!config_only)
1455: (*lookup)->rdtypeset = ISC_TRUE;
1456: if (rdtype == dns_rdatatype_axfr) {
1457: (*lookup)->section_question = plusquest;
1458: (*lookup)->comments = pluscomm;
1459: }
1460: (*lookup)->ixfr_serial = ISC_FALSE;
1461: }
1462: } else
1463: fprintf(stderr, ";; Warning, ignoring "
1464: "invalid type %s\n",
1465: value);
1466: return (value_from_next);
1467: case 'y':
1468: ptr = next_token(&value, ":"); /* hmac type or name */
1469: if (ptr == NULL) {
1470: usage();
1471: }
1472: ptr2 = next_token(&value, ":"); /* name or secret */
1473: if (ptr2 == NULL)
1474: usage();
1475: ptr3 = next_token(&value, ":"); /* secret or NULL */
1476: if (ptr3 != NULL) {
1477: parse_hmac(ptr);
1478: ptr = ptr2;
1479: ptr2 = ptr3;
1480: } else {
1481: hmacname = DNS_TSIG_HMACSHA256_NAME;
1482: digestbits = 0;
1483: }
1484: strlcpy(keynametext, ptr, sizeof(keynametext));
1485: strlcpy(keysecret, ptr2, sizeof(keysecret));
1486: return (value_from_next);
1487: case 'x':
1488: if (*need_clone)
1489: *lookup = clone_lookup(default_lookup, ISC_TRUE);
1490: *need_clone = ISC_TRUE;
1491: if (get_reverse(textname, sizeof(textname), value,
1492: ip6_int, ISC_FALSE) == ISC_R_SUCCESS) {
1493: strlcpy((*lookup)->textname, textname,
1494: sizeof((*lookup)->textname));
1495: debug("looking up %s", (*lookup)->textname);
1496: (*lookup)->trace_root = ISC_TF((*lookup)->trace ||
1497: (*lookup)->ns_search_only);
1498: (*lookup)->ip6_int = ip6_int;
1499: if (!(*lookup)->rdtypeset)
1500: (*lookup)->rdtype = dns_rdatatype_ptr;
1501: if (!(*lookup)->rdclassset)
1502: (*lookup)->rdclass = dns_rdataclass_in;
1503: (*lookup)->new_search = ISC_TRUE;
1504: if (*firstarg) {
1505: printgreeting(argc, argv, *lookup);
1506: *firstarg = ISC_FALSE;
1507: }
1508: ISC_LIST_APPEND(lookup_list, *lookup, link);
1509: } else {
1510: fprintf(stderr, "Invalid IP address %s\n", value);
1511: exit(1);
1512: }
1513: return (value_from_next);
1514: invalid_option:
1515: default:
1516: fprintf(stderr, "Invalid option: -%s\n", option);
1517: usage();
1518: }
1519: /* NOTREACHED */
1520: return (ISC_FALSE);
1521: }
1522:
1523: /*%
1524: * Because we may be trying to do memory allocation recording, we're going
1525: * to need to parse the arguments for the -m *before* we start the main
1526: * argument parsing routine.
1527: *
1528: * I'd prefer not to have to do this, but I am not quite sure how else to
1529: * fix the problem. Argument parsing in dig involves memory allocation
1530: * by its nature, so it can't be done in the main argument parser.
1531: */
1532: static void
1533: preparse_args(int argc, char **argv) {
1534: int rc;
1535: char **rv;
1536: char *option;
1537:
1538: rc = argc;
1539: rv = argv;
1540: for (rc--, rv++; rc > 0; rc--, rv++) {
1541: if (rv[0][0] != '-')
1542: continue;
1543: option = &rv[0][1];
1544: while (strpbrk(option, single_dash_opts) == &option[0]) {
1545: switch (option[0]) {
1546: case '4':
1547: if (ipv6only)
1548: fatal("only one of -4 and -6 allowed");
1549: ipv4only = ISC_TRUE;
1550: break;
1551: case '6':
1552: if (ipv4only)
1553: fatal("only one of -4 and -6 allowed");
1554: ipv6only = ISC_TRUE;
1555: break;
1556: }
1557: option = &option[1];
1558: }
1559: }
1560: }
1561:
1562: static void
1563: parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
1564: int argc, char **argv)
1565: {
1566: isc_result_t result;
1567: isc_textregion_t tr;
1568: isc_boolean_t firstarg = ISC_TRUE;
1569: dig_lookup_t *lookup = NULL;
1570: dns_rdatatype_t rdtype;
1571: dns_rdataclass_t rdclass;
1572: isc_boolean_t open_type_class = ISC_TRUE;
1573: char batchline[MXNAME];
1574: int bargc;
1575: char *bargv[64];
1576: int rc;
1577: char **rv;
1578: char *input;
1579: int i;
1580: isc_boolean_t need_clone = ISC_TRUE;
1.13 florian 1581: const char *errstr;
1.1 florian 1582:
1583: /*
1584: * The semantics for parsing the args is a bit complex; if
1585: * we don't have a host yet, make the arg apply globally,
1586: * otherwise make it apply to the latest host. This is
1587: * a bit different than the previous versions, but should
1588: * form a consistent user interface.
1589: *
1590: * First, create a "default lookup" which won't actually be used
1591: * anywhere, except for cloning into new lookups
1592: */
1593:
1594: debug("parse_args()");
1595: if (!is_batchfile) {
1596: debug("making new lookup");
1597: default_lookup = make_empty_lookup();
1598: default_lookup->adflag = ISC_TRUE;
1599: default_lookup->edns = 0;
1600: }
1601:
1602: if (is_batchfile && !config_only) {
1603: /* Processing '-f batchfile'. */
1604: lookup = clone_lookup(default_lookup, ISC_TRUE);
1605: need_clone = ISC_FALSE;
1606: } else
1607: lookup = default_lookup;
1608:
1609: rc = argc;
1610: rv = argv;
1611: for (rc--, rv++; rc > 0; rc--, rv++) {
1612: debug("main parsing %s", rv[0]);
1613: if (strncmp(rv[0], "%", 1) == 0)
1614: break;
1615: if (rv[0][0] == '@') {
1616:
1617: if (is_batchfile && !config_only) {
1618: addresscount = getaddresses(lookup, &rv[0][1],
1619: &result);
1620: if (result != ISC_R_SUCCESS) {
1621: fprintf(stderr, "couldn't get address "
1622: "for '%s': %s: skipping "
1623: "lookup\n", &rv[0][1],
1624: isc_result_totext(result));
1625: if (ISC_LINK_LINKED(lookup, link))
1626: ISC_LIST_DEQUEUE(lookup_list,
1627: lookup, link);
1628: destroy_lookup(lookup);
1629: return;
1630: }
1631: } else
1632: addresscount = getaddresses(lookup, &rv[0][1],
1633: NULL);
1634: } else if (rv[0][0] == '+') {
1635: plus_option(&rv[0][1], is_batchfile,
1636: lookup);
1637: } else if (rv[0][0] == '-') {
1638: if (rc <= 1) {
1639: if (dash_option(&rv[0][1], NULL,
1640: &lookup, &open_type_class,
1641: &need_clone, config_only,
1642: argc, argv, &firstarg)) {
1643: rc--;
1644: rv++;
1645: }
1646: } else {
1647: if (dash_option(&rv[0][1], rv[1],
1648: &lookup, &open_type_class,
1649: &need_clone, config_only,
1650: argc, argv, &firstarg)) {
1651: rc--;
1652: rv++;
1653: }
1654: }
1655: } else {
1656: /*
1657: * Anything which isn't an option
1658: */
1659: if (open_type_class) {
1660: if (strncasecmp(rv[0], "ixfr=", 5) == 0) {
1661: rdtype = dns_rdatatype_ixfr;
1662: result = ISC_R_SUCCESS;
1663: } else {
1664: tr.base = rv[0];
1665: tr.length =
1666: (unsigned int) strlen(rv[0]);
1667: result = dns_rdatatype_fromtext(&rdtype,
1668: (isc_textregion_t *)&tr);
1669: if (result == ISC_R_SUCCESS &&
1670: rdtype == dns_rdatatype_ixfr) {
1671: fprintf(stderr, ";; Warning, "
1672: "ixfr requires a "
1673: "serial number\n");
1674: continue;
1675: }
1676: }
1677: if (result == ISC_R_SUCCESS) {
1678: if (lookup->rdtypeset) {
1679: fprintf(stderr, ";; Warning, "
1680: "extra type option\n");
1681: }
1682: if (rdtype == dns_rdatatype_ixfr) {
1683: uint32_t serial;
1684: lookup->rdtype =
1685: dns_rdatatype_ixfr;
1686: lookup->rdtypeset = ISC_TRUE;
1.13 florian 1687: serial = strtonum(&rv[0][5], 0,
1688: MAXSERIAL, &errstr);
1689: if (errstr != NULL)
1690: fatal("serial number "
1691: "is %s: '%s'",
1692: errstr, &rv[0][5]);
1.1 florian 1693: lookup->ixfr_serial = serial;
1694: lookup->section_question =
1695: plusquest;
1696: lookup->comments = pluscomm;
1697: if (!lookup->tcp_mode_set)
1698: lookup->tcp_mode = ISC_TRUE;
1699: } else {
1700: lookup->rdtype = rdtype;
1701: lookup->rdtypeset = ISC_TRUE;
1702: if (rdtype ==
1703: dns_rdatatype_axfr) {
1704: lookup->section_question =
1705: plusquest;
1706: lookup->comments = pluscomm;
1707: }
1708: lookup->ixfr_serial = ISC_FALSE;
1709: }
1710: continue;
1711: }
1712: result = dns_rdataclass_fromtext(&rdclass,
1713: (isc_textregion_t *)&tr);
1714: if (result == ISC_R_SUCCESS) {
1715: if (lookup->rdclassset) {
1716: fprintf(stderr, ";; Warning, "
1717: "extra class option\n");
1718: }
1719: lookup->rdclass = rdclass;
1720: lookup->rdclassset = ISC_TRUE;
1721: continue;
1722: }
1723: }
1724:
1725: if (!config_only) {
1726: if (need_clone)
1727: lookup = clone_lookup(default_lookup,
1728: ISC_TRUE);
1729: need_clone = ISC_TRUE;
1730: strlcpy(lookup->textname, rv[0],
1731: sizeof(lookup->textname));
1732: lookup->trace_root = ISC_TF(lookup->trace ||
1733: lookup->ns_search_only);
1734: lookup->new_search = ISC_TRUE;
1735: if (firstarg) {
1736: printgreeting(argc, argv, lookup);
1737: firstarg = ISC_FALSE;
1738: }
1739: ISC_LIST_APPEND(lookup_list, lookup, link);
1740: debug("looking up %s", lookup->textname);
1741: }
1742: /* XXX Error message */
1743: }
1744: }
1745:
1746: /*
1747: * If we have a batchfile, seed the lookup list with the
1748: * first entry, then trust the callback in dighost_shutdown
1749: * to get the rest
1750: */
1751: if ((batchname != NULL) && !(is_batchfile)) {
1752: if (strcmp(batchname, "-") == 0)
1753: batchfp = stdin;
1754: else
1755: batchfp = fopen(batchname, "r");
1756: if (batchfp == NULL) {
1757: perror(batchname);
1758: if (exitcode < 8)
1759: exitcode = 8;
1760: fatal("couldn't open specified batch file");
1761: }
1762: /* XXX Remove code dup from shutdown code */
1763: next_line:
1.9 jsg 1764: if (fgets(batchline, sizeof(batchline), batchfp) != NULL) {
1.1 florian 1765: bargc = 1;
1766: debug("batch line %s", batchline);
1767: if (batchline[0] == '\r' || batchline[0] == '\n'
1768: || batchline[0] == '#' || batchline[0] == ';')
1769: goto next_line;
1770: input = batchline;
1771: bargv[bargc] = next_token(&input, " \t\r\n");
1772: while ((bargc < 14) && (bargv[bargc] != NULL)) {
1773: bargc++;
1774: bargv[bargc] = next_token(&input, " \t\r\n");
1775: }
1776:
1777: bargv[0] = argv[0];
1778: argv0 = argv[0];
1779:
1780: for(i = 0; i < bargc; i++)
1781: debug("batch argv %d: %s", i, bargv[i]);
1782: parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
1783: return;
1784: }
1785: return;
1786: }
1787: /*
1788: * If no lookup specified, search for root
1789: */
1790: if ((lookup_list.head == NULL) && !config_only) {
1791: if (need_clone)
1792: lookup = clone_lookup(default_lookup, ISC_TRUE);
1793: need_clone = ISC_TRUE;
1794: lookup->trace_root = ISC_TF(lookup->trace ||
1795: lookup->ns_search_only);
1796: lookup->new_search = ISC_TRUE;
1797: strlcpy(lookup->textname, ".", sizeof(lookup->textname));
1798: lookup->rdtype = dns_rdatatype_ns;
1799: lookup->rdtypeset = ISC_TRUE;
1800: if (firstarg) {
1801: printgreeting(argc, argv, lookup);
1802: firstarg = ISC_FALSE;
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]);
1851: parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
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:
1894: void dig_query_setup(isc_boolean_t is_batchfile, isc_boolean_t config_only,
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);
1912: usesearch = ISC_TRUE;
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);
1950: dig_query_setup(ISC_FALSE, ISC_FALSE, argc, argv);
1951: dig_startup();
1952: dig_shutdown();
1953:
1954: return (exitcode);
1955: }