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