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