]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/bin/dig/host.c
MFC: r253983-253984
[FreeBSD/stable/8.git] / contrib / bind9 / bin / dig / host.c
1 /*
2  * Copyright (C) 2004-2007, 2009-2013  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: host.c,v 1.124.40.3 2011/03/11 06:46:59 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <limits.h>
25
26 #ifdef HAVE_LOCALE_H
27 #include <locale.h>
28 #endif
29
30 #ifdef WITH_IDN
31 #include <idn/result.h>
32 #include <idn/log.h>
33 #include <idn/resconf.h>
34 #include <idn/api.h>
35 #endif
36
37 #include <isc/app.h>
38 #include <isc/commandline.h>
39 #include <isc/netaddr.h>
40 #include <isc/print.h>
41 #include <isc/string.h>
42 #include <isc/util.h>
43 #include <isc/task.h>
44 #include <isc/stdlib.h>
45
46 #include <dns/byaddr.h>
47 #include <dns/fixedname.h>
48 #include <dns/message.h>
49 #include <dns/name.h>
50 #include <dns/rdata.h>
51 #include <dns/rdataclass.h>
52 #include <dns/rdataset.h>
53 #include <dns/rdatatype.h>
54 #include <dns/rdatastruct.h>
55
56 #include <dig/dig.h>
57
58 static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE;
59 static isc_boolean_t default_lookups = ISC_TRUE;
60 static int seen_error = -1;
61 static isc_boolean_t list_addresses = ISC_TRUE;
62 static dns_rdatatype_t list_type = dns_rdatatype_a;
63 static isc_boolean_t printed_server = ISC_FALSE;
64
65 static const char *opcodetext[] = {
66         "QUERY",
67         "IQUERY",
68         "STATUS",
69         "RESERVED3",
70         "NOTIFY",
71         "UPDATE",
72         "RESERVED6",
73         "RESERVED7",
74         "RESERVED8",
75         "RESERVED9",
76         "RESERVED10",
77         "RESERVED11",
78         "RESERVED12",
79         "RESERVED13",
80         "RESERVED14",
81         "RESERVED15"
82 };
83
84 static const char *rcodetext[] = {
85         "NOERROR",
86         "FORMERR",
87         "SERVFAIL",
88         "NXDOMAIN",
89         "NOTIMP",
90         "REFUSED",
91         "YXDOMAIN",
92         "YXRRSET",
93         "NXRRSET",
94         "NOTAUTH",
95         "NOTZONE",
96         "RESERVED11",
97         "RESERVED12",
98         "RESERVED13",
99         "RESERVED14",
100         "RESERVED15",
101         "BADVERS"
102 };
103
104 struct rtype {
105         unsigned int type;
106         const char *text;
107 };
108
109 struct rtype rtypes[] = {
110         { 1,    "has address" },
111         { 2,    "name server" },
112         { 5,    "is an alias for" },
113         { 11,   "has well known services" },
114         { 12,   "domain name pointer" },
115         { 13,   "host information" },
116         { 15,   "mail is handled by" },
117         { 16,   "descriptive text" },
118         { 19,   "x25 address" },
119         { 20,   "ISDN address" },
120         { 24,   "has signature" },
121         { 25,   "has key" },
122         { 28,   "has IPv6 address" },
123         { 29,   "location" },
124         { 0, NULL }
125 };
126
127 static char *
128 rcode_totext(dns_rcode_t rcode)
129 {
130         static char buf[sizeof("?65535")];
131         union {
132                 const char *consttext;
133                 char *deconsttext;
134         } totext;
135
136         if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
137                 snprintf(buf, sizeof(buf), "?%u", rcode);
138                 totext.deconsttext = buf;
139         } else
140                 totext.consttext = rcodetext[rcode];
141         return totext.deconsttext;
142 }
143
144 ISC_PLATFORM_NORETURN_PRE static void
145 show_usage(void) ISC_PLATFORM_NORETURN_POST;
146
147 static void
148 show_usage(void) {
149         fputs(
150 "Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]\n"
151 "            [-R number] [-m flag] hostname [server]\n"
152 "       -a is equivalent to -v -t ANY\n"
153 "       -c specifies query class for non-IN data\n"
154 "       -C compares SOA records on authoritative nameservers\n"
155 "       -d is equivalent to -v\n"
156 "       -l lists all hosts in a domain, using AXFR\n"
157 "       -i IP6.INT reverse lookups\n"
158 "       -N changes the number of dots allowed before root lookup is done\n"
159 "       -r disables recursive processing\n"
160 "       -R specifies number of retries for UDP packets\n"
161 "       -s a SERVFAIL response should stop query\n"
162 "       -t specifies the query type\n"
163 "       -T enables TCP/IP mode\n"
164 "       -v enables verbose output\n"
165 "       -w specifies to wait forever for a reply\n"
166 "       -W specifies how long to wait for a reply\n"
167 "       -4 use IPv4 query transport only\n"
168 "       -6 use IPv6 query transport only\n"
169 "       -m set memory debugging flag (trace|record|usage)\n", stderr);
170         exit(1);
171 }
172
173 void
174 dighost_shutdown(void) {
175         isc_app_shutdown();
176 }
177
178 void
179 received(int bytes, isc_sockaddr_t *from, dig_query_t *query) {
180         isc_time_t now;
181         int diff;
182
183         if (!short_form) {
184                 char fromtext[ISC_SOCKADDR_FORMATSIZE];
185                 isc_sockaddr_format(from, fromtext, sizeof(fromtext));
186                 TIME_NOW(&now);
187                 diff = (int) isc_time_microdiff(&now, &query->time_sent);
188                 printf("Received %u bytes from %s in %d ms\n",
189                        bytes, fromtext, diff/1000);
190         }
191 }
192
193 void
194 trying(char *frm, dig_lookup_t *lookup) {
195         UNUSED(lookup);
196
197         if (!short_form)
198                 printf("Trying \"%s\"\n", frm);
199 }
200
201 static void
202 say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
203             dig_query_t *query)
204 {
205         isc_buffer_t *b = NULL;
206         char namestr[DNS_NAME_FORMATSIZE];
207         isc_region_t r;
208         isc_result_t result;
209         unsigned int bufsize = BUFSIZ;
210
211         dns_name_format(name, namestr, sizeof(namestr));
212  retry:
213         result = isc_buffer_allocate(mctx, &b, bufsize);
214         check_result(result, "isc_buffer_allocate");
215         result = dns_rdata_totext(rdata, NULL, b);
216         if (result == ISC_R_NOSPACE) {
217                 isc_buffer_free(&b);
218                 bufsize *= 2;
219                 goto retry;
220         }
221         check_result(result, "dns_rdata_totext");
222         isc_buffer_usedregion(b, &r);
223         if (query->lookup->identify_previous_line) {
224                 printf("Nameserver %s:\n\t",
225                         query->servname);
226         }
227         printf("%s %s %.*s", namestr,
228                msg, (int)r.length, (char *)r.base);
229         if (query->lookup->identify) {
230                 printf(" on server %s", query->servname);
231         }
232         printf("\n");
233         isc_buffer_free(&b);
234 }
235 #ifdef DIG_SIGCHASE
236 /* Just for compatibility : not use in host program */
237 isc_result_t
238 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
239               isc_buffer_t *target)
240 {
241   UNUSED(owner_name);
242   UNUSED(rdataset);
243   UNUSED(target);
244   return(ISC_FALSE);
245 }
246 #endif
247 static isc_result_t
248 printsection(dns_message_t *msg, dns_section_t sectionid,
249              const char *section_name, isc_boolean_t headers,
250              dig_query_t *query)
251 {
252         dns_name_t *name, *print_name;
253         dns_rdataset_t *rdataset;
254         dns_rdata_t rdata = DNS_RDATA_INIT;
255         isc_buffer_t target;
256         isc_result_t result, loopresult;
257         isc_region_t r;
258         dns_name_t empty_name;
259         char t[4096];
260         isc_boolean_t first;
261         isc_boolean_t no_rdata;
262
263         if (sectionid == DNS_SECTION_QUESTION)
264                 no_rdata = ISC_TRUE;
265         else
266                 no_rdata = ISC_FALSE;
267
268         if (headers)
269                 printf(";; %s SECTION:\n", section_name);
270
271         dns_name_init(&empty_name, NULL);
272
273         result = dns_message_firstname(msg, sectionid);
274         if (result == ISC_R_NOMORE)
275                 return (ISC_R_SUCCESS);
276         else if (result != ISC_R_SUCCESS)
277                 return (result);
278
279         for (;;) {
280                 name = NULL;
281                 dns_message_currentname(msg, sectionid, &name);
282
283                 isc_buffer_init(&target, t, sizeof(t));
284                 first = ISC_TRUE;
285                 print_name = name;
286
287                 for (rdataset = ISC_LIST_HEAD(name->list);
288                      rdataset != NULL;
289                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
290                         if (query->lookup->rdtype == dns_rdatatype_axfr &&
291                             !((!list_addresses &&
292                                (list_type == dns_rdatatype_any ||
293                                 rdataset->type == list_type)) ||
294                               (list_addresses &&
295                                (rdataset->type == dns_rdatatype_a ||
296                                 rdataset->type == dns_rdatatype_aaaa ||
297                                 rdataset->type == dns_rdatatype_ns ||
298                                 rdataset->type == dns_rdatatype_ptr))))
299                                 continue;
300                         if (!short_form) {
301                                 result = dns_rdataset_totext(rdataset,
302                                                              print_name,
303                                                              ISC_FALSE,
304                                                              no_rdata,
305                                                              &target);
306                                 if (result != ISC_R_SUCCESS)
307                                         return (result);
308 #ifdef USEINITALWS
309                                 if (first) {
310                                         print_name = &empty_name;
311                                         first = ISC_FALSE;
312                                 }
313 #else
314                                 UNUSED(first); /* Shut up compiler. */
315 #endif
316                         } else {
317                                 loopresult = dns_rdataset_first(rdataset);
318                                 while (loopresult == ISC_R_SUCCESS) {
319                                         struct rtype *t;
320                                         const char *rtt;
321                                         char typebuf[DNS_RDATATYPE_FORMATSIZE];
322                                         char typebuf2[DNS_RDATATYPE_FORMATSIZE
323                                                      + 20];
324                                         dns_rdataset_current(rdataset, &rdata);
325
326                                         for (t = rtypes; t->text != NULL; t++) {
327                                                 if (t->type == rdata.type) {
328                                                         rtt = t->text;
329                                                         goto found;
330                                                 }
331                                         }
332
333                                         dns_rdatatype_format(rdata.type,
334                                                              typebuf,
335                                                              sizeof(typebuf));
336                                         snprintf(typebuf2, sizeof(typebuf2),
337                                                  "has %s record", typebuf);
338                                         rtt = typebuf2;
339                                 found:
340                                         say_message(print_name, rtt,
341                                                     &rdata, query);
342                                         dns_rdata_reset(&rdata);
343                                         loopresult =
344                                                 dns_rdataset_next(rdataset);
345                                 }
346                         }
347                 }
348                 if (!short_form) {
349                         isc_buffer_usedregion(&target, &r);
350                         if (no_rdata)
351                                 printf(";%.*s", (int)r.length,
352                                        (char *)r.base);
353                         else
354                                 printf("%.*s", (int)r.length, (char *)r.base);
355                 }
356
357                 result = dns_message_nextname(msg, sectionid);
358                 if (result == ISC_R_NOMORE)
359                         break;
360                 else if (result != ISC_R_SUCCESS)
361                         return (result);
362         }
363
364         return (ISC_R_SUCCESS);
365 }
366
367 static isc_result_t
368 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
369            const char *set_name, isc_boolean_t headers)
370 {
371         isc_buffer_t target;
372         isc_result_t result;
373         isc_region_t r;
374         char t[4096];
375
376         UNUSED(msg);
377         if (headers)
378                 printf(";; %s SECTION:\n", set_name);
379
380         isc_buffer_init(&target, t, sizeof(t));
381
382         result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
383                                      &target);
384         if (result != ISC_R_SUCCESS)
385                 return (result);
386         isc_buffer_usedregion(&target, &r);
387         printf("%.*s", (int)r.length, (char *)r.base);
388
389         return (ISC_R_SUCCESS);
390 }
391
392 static void
393 chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
394         isc_result_t result;
395         dns_rdataset_t *rdataset;
396         dns_rdata_cname_t cname;
397         dns_rdata_t rdata = DNS_RDATA_INIT;
398         unsigned int i = msg->counts[DNS_SECTION_ANSWER];
399
400         while (i-- > 0) {
401                 rdataset = NULL;
402                 result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
403                                               dns_rdatatype_cname, 0, NULL,
404                                               &rdataset);
405                 if (result != ISC_R_SUCCESS)
406                         return;
407                 result = dns_rdataset_first(rdataset);
408                 check_result(result, "dns_rdataset_first");
409                 dns_rdata_reset(&rdata);
410                 dns_rdataset_current(rdataset, &rdata);
411                 result = dns_rdata_tostruct(&rdata, &cname, NULL);
412                 check_result(result, "dns_rdata_tostruct");
413                 dns_name_copy(&cname.cname, qname, NULL);
414                 dns_rdata_freestruct(&cname);
415         }
416 }
417
418 isc_result_t
419 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
420         isc_boolean_t did_flag = ISC_FALSE;
421         dns_rdataset_t *opt, *tsig = NULL;
422         dns_name_t *tsigname;
423         isc_result_t result = ISC_R_SUCCESS;
424         int force_error;
425
426         UNUSED(headers);
427
428         /*
429          * We get called multiple times.
430          * Preserve any existing error status.
431          */
432         force_error = (seen_error == 1) ? 1 : 0;
433         seen_error = 1;
434         if (listed_server && !printed_server) {
435                 char sockstr[ISC_SOCKADDR_FORMATSIZE];
436
437                 printf("Using domain server:\n");
438                 printf("Name: %s\n", query->userarg);
439                 isc_sockaddr_format(&query->sockaddr, sockstr,
440                                     sizeof(sockstr));
441                 printf("Address: %s\n", sockstr);
442                 printf("Aliases: \n\n");
443                 printed_server = ISC_TRUE;
444         }
445
446         if (msg->rcode != 0) {
447                 char namestr[DNS_NAME_FORMATSIZE];
448                 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
449
450                 if (query->lookup->identify_previous_line)
451                         printf("Nameserver %s:\n\t%s not found: %d(%s)\n",
452                                query->servname,
453                                (msg->rcode != dns_rcode_nxdomain) ? namestr :
454                                query->lookup->textname, msg->rcode,
455                                rcode_totext(msg->rcode));
456                 else
457                         printf("Host %s not found: %d(%s)\n",
458                                (msg->rcode != dns_rcode_nxdomain) ? namestr :
459                                query->lookup->textname, msg->rcode,
460                                rcode_totext(msg->rcode));
461                 return (ISC_R_SUCCESS);
462         }
463
464         if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
465                 char namestr[DNS_NAME_FORMATSIZE];
466                 dig_lookup_t *lookup;
467                 dns_fixedname_t fixed;
468                 dns_name_t *name;
469
470                 /* Add AAAA and MX lookups. */
471                 dns_fixedname_init(&fixed);
472                 name = dns_fixedname_name(&fixed);
473                 dns_name_copy(query->lookup->name, name, NULL);
474                 chase_cnamechain(msg, name);
475                 dns_name_format(name, namestr, sizeof(namestr));
476                 lookup = clone_lookup(query->lookup, ISC_FALSE);
477                 if (lookup != NULL) {
478                         strncpy(lookup->textname, namestr,
479                                 sizeof(lookup->textname));
480                         lookup->textname[sizeof(lookup->textname)-1] = 0;
481                         lookup->rdtype = dns_rdatatype_aaaa;
482                         lookup->rdtypeset = ISC_TRUE;
483                         lookup->origin = NULL;
484                         lookup->retries = tries;
485                         ISC_LIST_APPEND(lookup_list, lookup, link);
486                 }
487                 lookup = clone_lookup(query->lookup, ISC_FALSE);
488                 if (lookup != NULL) {
489                         strncpy(lookup->textname, namestr,
490                                 sizeof(lookup->textname));
491                         lookup->textname[sizeof(lookup->textname)-1] = 0;
492                         lookup->rdtype = dns_rdatatype_mx;
493                         lookup->rdtypeset = ISC_TRUE;
494                         lookup->origin = NULL;
495                         lookup->retries = tries;
496                         ISC_LIST_APPEND(lookup_list, lookup, link);
497                 }
498         }
499
500         if (!short_form) {
501                 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
502                        opcodetext[msg->opcode], rcode_totext(msg->rcode),
503                        msg->id);
504                 printf(";; flags: ");
505                 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
506                         printf("qr");
507                         did_flag = ISC_TRUE;
508                 }
509                 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
510                         printf("%saa", did_flag ? " " : "");
511                         did_flag = ISC_TRUE;
512                 }
513                 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
514                         printf("%stc", did_flag ? " " : "");
515                         did_flag = ISC_TRUE;
516                 }
517                 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
518                         printf("%srd", did_flag ? " " : "");
519                         did_flag = ISC_TRUE;
520                 }
521                 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
522                         printf("%sra", did_flag ? " " : "");
523                         did_flag = ISC_TRUE;
524                 }
525                 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
526                         printf("%sad", did_flag ? " " : "");
527                         did_flag = ISC_TRUE;
528                 }
529                 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
530                         printf("%scd", did_flag ? " " : "");
531                         did_flag = ISC_TRUE;
532                         POST(did_flag);
533                 }
534                 printf("; QUERY: %u, ANSWER: %u, "
535                        "AUTHORITY: %u, ADDITIONAL: %u\n",
536                        msg->counts[DNS_SECTION_QUESTION],
537                        msg->counts[DNS_SECTION_ANSWER],
538                        msg->counts[DNS_SECTION_AUTHORITY],
539                        msg->counts[DNS_SECTION_ADDITIONAL]);
540                 opt = dns_message_getopt(msg);
541                 if (opt != NULL)
542                         printf(";; EDNS: version: %u, udp=%u\n",
543                                (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
544                                (unsigned int)opt->rdclass);
545                 tsigname = NULL;
546                 tsig = dns_message_gettsig(msg, &tsigname);
547                 if (tsig != NULL)
548                         printf(";; PSEUDOSECTIONS: TSIG\n");
549         }
550         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
551             !short_form) {
552                 printf("\n");
553                 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
554                                       ISC_TRUE, query);
555                 if (result != ISC_R_SUCCESS)
556                         return (result);
557         }
558         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
559                 if (!short_form)
560                         printf("\n");
561                 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
562                                       ISC_TF(!short_form), query);
563                 if (result != ISC_R_SUCCESS)
564                         return (result);
565         }
566
567         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
568             !short_form) {
569                 printf("\n");
570                 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
571                                       ISC_TRUE, query);
572                 if (result != ISC_R_SUCCESS)
573                         return (result);
574         }
575         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
576             !short_form) {
577                 printf("\n");
578                 result = printsection(msg, DNS_SECTION_ADDITIONAL,
579                                       "ADDITIONAL", ISC_TRUE, query);
580                 if (result != ISC_R_SUCCESS)
581                         return (result);
582         }
583         if ((tsig != NULL) && !short_form) {
584                 printf("\n");
585                 result = printrdata(msg, tsig, tsigname,
586                                     "PSEUDOSECTION TSIG", ISC_TRUE);
587                 if (result != ISC_R_SUCCESS)
588                         return (result);
589         }
590         if (!short_form)
591                 printf("\n");
592
593         if (short_form && !default_lookups &&
594             ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
595                 char namestr[DNS_NAME_FORMATSIZE];
596                 char typestr[DNS_RDATATYPE_FORMATSIZE];
597                 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
598                 dns_rdatatype_format(query->lookup->rdtype, typestr,
599                                      sizeof(typestr));
600                 printf("%s has no %s record\n", namestr, typestr);
601         }
602         seen_error = force_error;
603         return (result);
604 }
605
606 static const char * optstring = "46ac:dilnm:rst:vwCDN:R:TW:";
607
608 static void
609 pre_parse_args(int argc, char **argv) {
610         int c;
611
612         while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) {
613                 switch (c) {
614                 case 'm':
615                         memdebugging = ISC_TRUE;
616                         if (strcasecmp("trace", isc_commandline_argument) == 0)
617                                 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
618                         else if (!strcasecmp("record",
619                                              isc_commandline_argument) == 0)
620                                 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
621                         else if (strcasecmp("usage",
622                                             isc_commandline_argument) == 0)
623                                 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
624                         break;
625
626                 case '4': break;
627                 case '6': break;
628                 case 'a': break;
629                 case 'c': break;
630                 case 'd': break;
631                 case 'i': break;
632                 case 'l': break;
633                 case 'n': break;
634                 case 'r': break;
635                 case 's': break;
636                 case 't': break;
637                 case 'v': break;
638                 case 'w': break;
639                 case 'C': break;
640                 case 'D':
641                         if (debugging)
642                                 debugtiming = ISC_TRUE;
643                         debugging = ISC_TRUE;
644                         break;
645                 case 'N': break;
646                 case 'R': break;
647                 case 'T': break;
648                 case 'W': break;
649                 default:
650                         show_usage();
651                 }
652         }
653         isc_commandline_reset = ISC_TRUE;
654         isc_commandline_index = 1;
655 }
656
657 static void
658 parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
659         char hostname[MXNAME];
660         dig_lookup_t *lookup;
661         int c;
662         char store[MXNAME];
663         isc_textregion_t tr;
664         isc_result_t result = ISC_R_SUCCESS;
665         dns_rdatatype_t rdtype;
666         dns_rdataclass_t rdclass;
667         isc_uint32_t serial = 0;
668
669         UNUSED(is_batchfile);
670
671         lookup = make_empty_lookup();
672
673         lookup->servfail_stops = ISC_FALSE;
674         lookup->comments = ISC_FALSE;
675
676         while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) {
677                 switch (c) {
678                 case 'l':
679                         lookup->tcp_mode = ISC_TRUE;
680                         lookup->rdtype = dns_rdatatype_axfr;
681                         lookup->rdtypeset = ISC_TRUE;
682                         fatalexit = 3;
683                         break;
684                 case 'v':
685                 case 'd':
686                         short_form = ISC_FALSE;
687                         break;
688                 case 'r':
689                         lookup->recurse = ISC_FALSE;
690                         break;
691                 case 't':
692                         if (strncasecmp(isc_commandline_argument,
693                                         "ixfr=", 5) == 0) {
694                                 rdtype = dns_rdatatype_ixfr;
695                                 /* XXXMPA add error checking */
696                                 serial = strtoul(isc_commandline_argument + 5,
697                                                  NULL, 10);
698                                 result = ISC_R_SUCCESS;
699                         } else {
700                                 tr.base = isc_commandline_argument;
701                                 tr.length = strlen(isc_commandline_argument);
702                                 result = dns_rdatatype_fromtext(&rdtype,
703                                                    (isc_textregion_t *)&tr);
704                         }
705
706                         if (result != ISC_R_SUCCESS) {
707                                 fatalexit = 2;
708                                 fatal("invalid type: %s\n",
709                                       isc_commandline_argument);
710                         }
711                         if (!lookup->rdtypeset ||
712                             lookup->rdtype != dns_rdatatype_axfr)
713                                 lookup->rdtype = rdtype;
714                         lookup->rdtypeset = ISC_TRUE;
715 #ifdef WITH_IDN
716                         idnoptions = 0;
717 #endif
718                         if (rdtype == dns_rdatatype_axfr) {
719                                 /* -l -t any -v */
720                                 list_type = dns_rdatatype_any;
721                                 short_form = ISC_FALSE;
722                                 lookup->tcp_mode = ISC_TRUE;
723                         } else if (rdtype == dns_rdatatype_ixfr) {
724                                 lookup->ixfr_serial = serial;
725                                 lookup->tcp_mode = ISC_TRUE;
726                                 list_type = rdtype;
727 #ifdef WITH_IDN
728                         } else if (rdtype == dns_rdatatype_a ||
729                                    rdtype == dns_rdatatype_aaaa ||
730                                    rdtype == dns_rdatatype_mx) {
731                                 idnoptions = IDN_ASCCHECK;
732                                 list_type = rdtype;
733 #endif
734                         } else
735                                 list_type = rdtype;
736                         list_addresses = ISC_FALSE;
737                         default_lookups = ISC_FALSE;
738                         break;
739                 case 'c':
740                         tr.base = isc_commandline_argument;
741                         tr.length = strlen(isc_commandline_argument);
742                         result = dns_rdataclass_fromtext(&rdclass,
743                                                    (isc_textregion_t *)&tr);
744
745                         if (result != ISC_R_SUCCESS) {
746                                 fatalexit = 2;
747                                 fatal("invalid class: %s\n",
748                                       isc_commandline_argument);
749                         } else {
750                                 lookup->rdclass = rdclass;
751                                 lookup->rdclassset = ISC_TRUE;
752                         }
753                         default_lookups = ISC_FALSE;
754                         break;
755                 case 'a':
756                         if (!lookup->rdtypeset ||
757                             lookup->rdtype != dns_rdatatype_axfr)
758                                 lookup->rdtype = dns_rdatatype_any;
759                         list_type = dns_rdatatype_any;
760                         list_addresses = ISC_FALSE;
761                         lookup->rdtypeset = ISC_TRUE;
762                         short_form = ISC_FALSE;
763                         default_lookups = ISC_FALSE;
764                         break;
765                 case 'i':
766                         lookup->ip6_int = ISC_TRUE;
767                         break;
768                 case 'n':
769                         /* deprecated */
770                         break;
771                 case 'm':
772                         /* Handled by pre_parse_args(). */
773                         break;
774                 case 'w':
775                         /*
776                          * The timer routines are coded such that
777                          * timeout==MAXINT doesn't enable the timer
778                          */
779                         timeout = INT_MAX;
780                         break;
781                 case 'W':
782                         timeout = atoi(isc_commandline_argument);
783                         if (timeout < 1)
784                                 timeout = 1;
785                         break;
786                 case 'R':
787                         tries = atoi(isc_commandline_argument) + 1;
788                         if (tries < 2)
789                                 tries = 2;
790                         break;
791                 case 'T':
792                         lookup->tcp_mode = ISC_TRUE;
793                         break;
794                 case 'C':
795                         debug("showing all SOAs");
796                         lookup->rdtype = dns_rdatatype_ns;
797                         lookup->rdtypeset = ISC_TRUE;
798                         lookup->rdclass = dns_rdataclass_in;
799                         lookup->rdclassset = ISC_TRUE;
800                         lookup->ns_search_only = ISC_TRUE;
801                         lookup->trace_root = ISC_TRUE;
802                         lookup->identify_previous_line = ISC_TRUE;
803                         default_lookups = ISC_FALSE;
804                         break;
805                 case 'N':
806                         debug("setting NDOTS to %s",
807                               isc_commandline_argument);
808                         ndots = atoi(isc_commandline_argument);
809                         break;
810                 case 'D':
811                         /* Handled by pre_parse_args(). */
812                         break;
813                 case '4':
814                         if (have_ipv4) {
815                                 isc_net_disableipv6();
816                                 have_ipv6 = ISC_FALSE;
817                         } else
818                                 fatal("can't find IPv4 networking");
819                         break;
820                 case '6':
821                         if (have_ipv6) {
822                                 isc_net_disableipv4();
823                                 have_ipv4 = ISC_FALSE;
824                         } else
825                                 fatal("can't find IPv6 networking");
826                         break;
827                 case 's':
828                         lookup->servfail_stops = ISC_TRUE;
829                         break;
830                 }
831         }
832
833         lookup->retries = tries;
834
835         if (isc_commandline_index >= argc)
836                 show_usage();
837
838         strlcpy(hostname, argv[isc_commandline_index], sizeof(hostname));
839
840         if (argc > isc_commandline_index + 1) {
841                 set_nameserver(argv[isc_commandline_index+1]);
842                 debug("server is %s", argv[isc_commandline_index+1]);
843                 listed_server = ISC_TRUE;
844         } else
845                 check_ra = ISC_TRUE;
846
847         lookup->pending = ISC_FALSE;
848         if (get_reverse(store, sizeof(store), hostname,
849                         lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) {
850                 strncpy(lookup->textname, store, sizeof(lookup->textname));
851                 lookup->textname[sizeof(lookup->textname)-1] = 0;
852                 lookup->rdtype = dns_rdatatype_ptr;
853                 lookup->rdtypeset = ISC_TRUE;
854                 default_lookups = ISC_FALSE;
855         } else {
856                 strncpy(lookup->textname, hostname, sizeof(lookup->textname));
857                 lookup->textname[sizeof(lookup->textname)-1]=0;
858                 usesearch = ISC_TRUE;
859         }
860         lookup->new_search = ISC_TRUE;
861         ISC_LIST_APPEND(lookup_list, lookup, link);
862 }
863
864 int
865 main(int argc, char **argv) {
866         isc_result_t result;
867
868         tries = 2;
869
870         ISC_LIST_INIT(lookup_list);
871         ISC_LIST_INIT(server_list);
872         ISC_LIST_INIT(search_list);
873
874         fatalexit = 1;
875 #ifdef WITH_IDN
876         idnoptions = IDN_ASCCHECK;
877 #endif
878
879         debug("main()");
880         progname = argv[0];
881         pre_parse_args(argc, argv);
882         result = isc_app_start();
883         check_result(result, "isc_app_start");
884         setup_libs();
885         parse_args(ISC_FALSE, argc, argv);
886         setup_system();
887         result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
888         check_result(result, "isc_app_onrun");
889         isc_app_run();
890         cancel_all();
891         destroy_libs();
892         isc_app_finish();
893         return ((seen_error == 0) ? 0 : 1);
894 }