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