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