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