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