]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/bin/dig/host.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / bin / dig / host.c
1 /*
2  * Copyright (C) 2004-2007, 2009-2011  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                 printf("Host %s not found: %d(%s)\n",
450                        (msg->rcode != dns_rcode_nxdomain) ? namestr :
451                        query->lookup->textname, msg->rcode,
452                        rcode_totext(msg->rcode));
453                 return (ISC_R_SUCCESS);
454         }
455
456         if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
457                 char namestr[DNS_NAME_FORMATSIZE];
458                 dig_lookup_t *lookup;
459                 dns_fixedname_t fixed;
460                 dns_name_t *name;
461
462                 /* Add AAAA and MX lookups. */
463                 dns_fixedname_init(&fixed);
464                 name = dns_fixedname_name(&fixed);
465                 dns_name_copy(query->lookup->name, name, NULL);
466                 chase_cnamechain(msg, name);
467                 dns_name_format(name, namestr, sizeof(namestr));
468                 lookup = clone_lookup(query->lookup, ISC_FALSE);
469                 if (lookup != NULL) {
470                         strncpy(lookup->textname, namestr,
471                                 sizeof(lookup->textname));
472                         lookup->textname[sizeof(lookup->textname)-1] = 0;
473                         lookup->rdtype = dns_rdatatype_aaaa;
474                         lookup->rdtypeset = ISC_TRUE;
475                         lookup->origin = NULL;
476                         lookup->retries = tries;
477                         ISC_LIST_APPEND(lookup_list, lookup, link);
478                 }
479                 lookup = clone_lookup(query->lookup, ISC_FALSE);
480                 if (lookup != NULL) {
481                         strncpy(lookup->textname, namestr,
482                                 sizeof(lookup->textname));
483                         lookup->textname[sizeof(lookup->textname)-1] = 0;
484                         lookup->rdtype = dns_rdatatype_mx;
485                         lookup->rdtypeset = ISC_TRUE;
486                         lookup->origin = NULL;
487                         lookup->retries = tries;
488                         ISC_LIST_APPEND(lookup_list, lookup, link);
489                 }
490         }
491
492         if (!short_form) {
493                 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
494                        opcodetext[msg->opcode], rcode_totext(msg->rcode),
495                        msg->id);
496                 printf(";; flags: ");
497                 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
498                         printf("qr");
499                         did_flag = ISC_TRUE;
500                 }
501                 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
502                         printf("%saa", did_flag ? " " : "");
503                         did_flag = ISC_TRUE;
504                 }
505                 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
506                         printf("%stc", did_flag ? " " : "");
507                         did_flag = ISC_TRUE;
508                 }
509                 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
510                         printf("%srd", did_flag ? " " : "");
511                         did_flag = ISC_TRUE;
512                 }
513                 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
514                         printf("%sra", did_flag ? " " : "");
515                         did_flag = ISC_TRUE;
516                 }
517                 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
518                         printf("%sad", did_flag ? " " : "");
519                         did_flag = ISC_TRUE;
520                 }
521                 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
522                         printf("%scd", did_flag ? " " : "");
523                         did_flag = ISC_TRUE;
524                         POST(did_flag);
525                 }
526                 printf("; QUERY: %u, ANSWER: %u, "
527                        "AUTHORITY: %u, ADDITIONAL: %u\n",
528                        msg->counts[DNS_SECTION_QUESTION],
529                        msg->counts[DNS_SECTION_ANSWER],
530                        msg->counts[DNS_SECTION_AUTHORITY],
531                        msg->counts[DNS_SECTION_ADDITIONAL]);
532                 opt = dns_message_getopt(msg);
533                 if (opt != NULL)
534                         printf(";; EDNS: version: %u, udp=%u\n",
535                                (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
536                                (unsigned int)opt->rdclass);
537                 tsigname = NULL;
538                 tsig = dns_message_gettsig(msg, &tsigname);
539                 if (tsig != NULL)
540                         printf(";; PSEUDOSECTIONS: TSIG\n");
541         }
542         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
543             !short_form) {
544                 printf("\n");
545                 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
546                                       ISC_TRUE, query);
547                 if (result != ISC_R_SUCCESS)
548                         return (result);
549         }
550         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
551                 if (!short_form)
552                         printf("\n");
553                 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
554                                       ISC_TF(!short_form), query);
555                 if (result != ISC_R_SUCCESS)
556                         return (result);
557         }
558
559         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
560             !short_form) {
561                 printf("\n");
562                 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
563                                       ISC_TRUE, query);
564                 if (result != ISC_R_SUCCESS)
565                         return (result);
566         }
567         if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
568             !short_form) {
569                 printf("\n");
570                 result = printsection(msg, DNS_SECTION_ADDITIONAL,
571                                       "ADDITIONAL", ISC_TRUE, query);
572                 if (result != ISC_R_SUCCESS)
573                         return (result);
574         }
575         if ((tsig != NULL) && !short_form) {
576                 printf("\n");
577                 result = printrdata(msg, tsig, tsigname,
578                                     "PSEUDOSECTION TSIG", ISC_TRUE);
579                 if (result != ISC_R_SUCCESS)
580                         return (result);
581         }
582         if (!short_form)
583                 printf("\n");
584
585         if (short_form && !default_lookups &&
586             ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
587                 char namestr[DNS_NAME_FORMATSIZE];
588                 char typestr[DNS_RDATATYPE_FORMATSIZE];
589                 dns_name_format(query->lookup->name, namestr, sizeof(namestr));
590                 dns_rdatatype_format(query->lookup->rdtype, typestr,
591                                      sizeof(typestr));
592                 printf("%s has no %s record\n", namestr, typestr);
593         }
594         seen_error = force_error;
595         return (result);
596 }
597
598 static const char * optstring = "46ac:dilnm:rst:vwCDN:R:TW:";
599
600 static void
601 pre_parse_args(int argc, char **argv) {
602         int c;
603
604         while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) {
605                 switch (c) {
606                 case 'm':
607                         memdebugging = ISC_TRUE;
608                         if (strcasecmp("trace", isc_commandline_argument) == 0)
609                                 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
610                         else if (!strcasecmp("record",
611                                              isc_commandline_argument) == 0)
612                                 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
613                         else if (strcasecmp("usage",
614                                             isc_commandline_argument) == 0)
615                                 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
616                         break;
617
618                 case '4': break;
619                 case '6': break;
620                 case 'a': break;
621                 case 'c': break;
622                 case 'd': break;
623                 case 'i': break;
624                 case 'l': break;
625                 case 'n': break;
626                 case 'r': break;
627                 case 's': break;
628                 case 't': break;
629                 case 'v': break;
630                 case 'w': break;
631                 case 'C': break;
632                 case 'D':
633                         debugging = ISC_TRUE;
634                         break;
635                 case 'N': break;
636                 case 'R': break;
637                 case 'T': break;
638                 case 'W': break;
639                 default:
640                         show_usage();
641                 }
642         }
643         isc_commandline_reset = ISC_TRUE;
644         isc_commandline_index = 1;
645 }
646
647 static void
648 parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
649         char hostname[MXNAME];
650         dig_lookup_t *lookup;
651         int c;
652         char store[MXNAME];
653         isc_textregion_t tr;
654         isc_result_t result = ISC_R_SUCCESS;
655         dns_rdatatype_t rdtype;
656         dns_rdataclass_t rdclass;
657         isc_uint32_t serial = 0;
658
659         UNUSED(is_batchfile);
660
661         lookup = make_empty_lookup();
662
663         lookup->servfail_stops = ISC_FALSE;
664         lookup->comments = ISC_FALSE;
665
666         while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) {
667                 switch (c) {
668                 case 'l':
669                         lookup->tcp_mode = ISC_TRUE;
670                         lookup->rdtype = dns_rdatatype_axfr;
671                         lookup->rdtypeset = ISC_TRUE;
672                         fatalexit = 3;
673                         break;
674                 case 'v':
675                 case 'd':
676                         short_form = ISC_FALSE;
677                         break;
678                 case 'r':
679                         lookup->recurse = ISC_FALSE;
680                         break;
681                 case 't':
682                         if (strncasecmp(isc_commandline_argument,
683                                         "ixfr=", 5) == 0) {
684                                 rdtype = dns_rdatatype_ixfr;
685                                 /* XXXMPA add error checking */
686                                 serial = strtoul(isc_commandline_argument + 5,
687                                                  NULL, 10);
688                                 result = ISC_R_SUCCESS;
689                         } else {
690                                 tr.base = isc_commandline_argument;
691                                 tr.length = strlen(isc_commandline_argument);
692                                 result = dns_rdatatype_fromtext(&rdtype,
693                                                    (isc_textregion_t *)&tr);
694                         }
695
696                         if (result != ISC_R_SUCCESS) {
697                                 fatalexit = 2;
698                                 fatal("invalid type: %s\n",
699                                       isc_commandline_argument);
700                         }
701                         if (!lookup->rdtypeset ||
702                             lookup->rdtype != dns_rdatatype_axfr)
703                                 lookup->rdtype = rdtype;
704                         lookup->rdtypeset = ISC_TRUE;
705 #ifdef WITH_IDN
706                         idnoptions = 0;
707 #endif
708                         if (rdtype == dns_rdatatype_axfr) {
709                                 /* -l -t any -v */
710                                 list_type = dns_rdatatype_any;
711                                 short_form = ISC_FALSE;
712                                 lookup->tcp_mode = ISC_TRUE;
713                         } else if (rdtype == dns_rdatatype_ixfr) {
714                                 lookup->ixfr_serial = serial;
715                                 lookup->tcp_mode = ISC_TRUE;
716                                 list_type = rdtype;
717 #ifdef WITH_IDN
718                         } else if (rdtype == dns_rdatatype_a ||
719                                    rdtype == dns_rdatatype_aaaa ||
720                                    rdtype == dns_rdatatype_mx) {
721                                 idnoptions = IDN_ASCCHECK;
722                                 list_type = rdtype;
723 #endif
724                         } else
725                                 list_type = rdtype;
726                         list_addresses = ISC_FALSE;
727                         default_lookups = ISC_FALSE;
728                         break;
729                 case 'c':
730                         tr.base = isc_commandline_argument;
731                         tr.length = strlen(isc_commandline_argument);
732                         result = dns_rdataclass_fromtext(&rdclass,
733                                                    (isc_textregion_t *)&tr);
734
735                         if (result != ISC_R_SUCCESS) {
736                                 fatalexit = 2;
737                                 fatal("invalid class: %s\n",
738                                       isc_commandline_argument);
739                         } else {
740                                 lookup->rdclass = rdclass;
741                                 lookup->rdclassset = ISC_TRUE;
742                         }
743                         default_lookups = ISC_FALSE;
744                         break;
745                 case 'a':
746                         if (!lookup->rdtypeset ||
747                             lookup->rdtype != dns_rdatatype_axfr)
748                                 lookup->rdtype = dns_rdatatype_any;
749                         list_type = dns_rdatatype_any;
750                         list_addresses = ISC_FALSE;
751                         lookup->rdtypeset = ISC_TRUE;
752                         short_form = ISC_FALSE;
753                         default_lookups = ISC_FALSE;
754                         break;
755                 case 'i':
756                         lookup->ip6_int = ISC_TRUE;
757                         break;
758                 case 'n':
759                         /* deprecated */
760                         break;
761                 case 'm':
762                         /* Handled by pre_parse_args(). */
763                         break;
764                 case 'w':
765                         /*
766                          * The timer routines are coded such that
767                          * timeout==MAXINT doesn't enable the timer
768                          */
769                         timeout = INT_MAX;
770                         break;
771                 case 'W':
772                         timeout = atoi(isc_commandline_argument);
773                         if (timeout < 1)
774                                 timeout = 1;
775                         break;
776                 case 'R':
777                         tries = atoi(isc_commandline_argument) + 1;
778                         if (tries < 2)
779                                 tries = 2;
780                         break;
781                 case 'T':
782                         lookup->tcp_mode = ISC_TRUE;
783                         break;
784                 case 'C':
785                         debug("showing all SOAs");
786                         lookup->rdtype = dns_rdatatype_ns;
787                         lookup->rdtypeset = ISC_TRUE;
788                         lookup->rdclass = dns_rdataclass_in;
789                         lookup->rdclassset = ISC_TRUE;
790                         lookup->ns_search_only = ISC_TRUE;
791                         lookup->trace_root = ISC_TRUE;
792                         lookup->identify_previous_line = ISC_TRUE;
793                         default_lookups = ISC_FALSE;
794                         break;
795                 case 'N':
796                         debug("setting NDOTS to %s",
797                               isc_commandline_argument);
798                         ndots = atoi(isc_commandline_argument);
799                         break;
800                 case 'D':
801                         /* Handled by pre_parse_args(). */
802                         break;
803                 case '4':
804                         if (have_ipv4) {
805                                 isc_net_disableipv6();
806                                 have_ipv6 = ISC_FALSE;
807                         } else
808                                 fatal("can't find IPv4 networking");
809                         break;
810                 case '6':
811                         if (have_ipv6) {
812                                 isc_net_disableipv4();
813                                 have_ipv4 = ISC_FALSE;
814                         } else
815                                 fatal("can't find IPv6 networking");
816                         break;
817                 case 's':
818                         lookup->servfail_stops = ISC_TRUE;
819                         break;
820                 }
821         }
822
823         lookup->retries = tries;
824
825         if (isc_commandline_index >= argc)
826                 show_usage();
827
828         strlcpy(hostname, argv[isc_commandline_index], sizeof(hostname));
829
830         if (argc > isc_commandline_index + 1) {
831                 set_nameserver(argv[isc_commandline_index+1]);
832                 debug("server is %s", argv[isc_commandline_index+1]);
833                 listed_server = ISC_TRUE;
834         } else
835                 check_ra = ISC_TRUE;
836
837         lookup->pending = ISC_FALSE;
838         if (get_reverse(store, sizeof(store), hostname,
839                         lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) {
840                 strncpy(lookup->textname, store, sizeof(lookup->textname));
841                 lookup->textname[sizeof(lookup->textname)-1] = 0;
842                 lookup->rdtype = dns_rdatatype_ptr;
843                 lookup->rdtypeset = ISC_TRUE;
844                 default_lookups = ISC_FALSE;
845         } else {
846                 strncpy(lookup->textname, hostname, sizeof(lookup->textname));
847                 lookup->textname[sizeof(lookup->textname)-1]=0;
848                 usesearch = ISC_TRUE;
849         }
850         lookup->new_search = ISC_TRUE;
851         ISC_LIST_APPEND(lookup_list, lookup, link);
852 }
853
854 int
855 main(int argc, char **argv) {
856         isc_result_t result;
857
858         tries = 2;
859
860         ISC_LIST_INIT(lookup_list);
861         ISC_LIST_INIT(server_list);
862         ISC_LIST_INIT(search_list);
863
864         fatalexit = 1;
865 #ifdef WITH_IDN
866         idnoptions = IDN_ASCCHECK;
867 #endif
868
869         debug("main()");
870         progname = argv[0];
871         pre_parse_args(argc, argv);
872         result = isc_app_start();
873         check_result(result, "isc_app_start");
874         setup_libs();
875         parse_args(ISC_FALSE, argc, argv);
876         setup_system();
877         result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
878         check_result(result, "isc_app_onrun");
879         isc_app_run();
880         cancel_all();
881         destroy_libs();
882         isc_app_finish();
883         return ((seen_error == 0) ? 0 : 1);
884 }