]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/bin/dig/nslookup.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 / nslookup.c
1 /*
2  * Copyright (C) 2004-2012  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: nslookup.c,v 1.127.38.2 2011/02/28 01:19:58 tbox Exp $ */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23
24 #include <isc/app.h>
25 #include <isc/buffer.h>
26 #include <isc/commandline.h>
27 #include <isc/event.h>
28 #include <isc/parseint.h>
29 #include <isc/print.h>
30 #include <isc/string.h>
31 #include <isc/timer.h>
32 #include <isc/util.h>
33 #include <isc/task.h>
34 #include <isc/netaddr.h>
35
36 #include <dns/message.h>
37 #include <dns/name.h>
38 #include <dns/fixedname.h>
39 #include <dns/rdata.h>
40 #include <dns/rdataclass.h>
41 #include <dns/rdataset.h>
42 #include <dns/rdatastruct.h>
43 #include <dns/rdatatype.h>
44 #include <dns/byaddr.h>
45
46 #include <dig/dig.h>
47
48 static isc_boolean_t short_form = ISC_TRUE,
49         tcpmode = ISC_FALSE,
50         identify = ISC_FALSE, stats = ISC_TRUE,
51         comments = ISC_TRUE, section_question = ISC_TRUE,
52         section_answer = ISC_TRUE, section_authority = ISC_TRUE,
53         section_additional = ISC_TRUE, recurse = ISC_TRUE,
54         aaonly = ISC_FALSE, nofail = ISC_TRUE;
55
56 static isc_boolean_t in_use = ISC_FALSE;
57 static char defclass[MXRD] = "IN";
58 static char deftype[MXRD] = "A";
59 static isc_event_t *global_event = NULL;
60 static int query_error = 1, print_error = 0;
61
62 static char domainopt[DNS_NAME_MAXTEXT];
63
64 static const char *rcodetext[] = {
65         "NOERROR",
66         "FORMERR",
67         "SERVFAIL",
68         "NXDOMAIN",
69         "NOTIMP",
70         "REFUSED",
71         "YXDOMAIN",
72         "YXRRSET",
73         "NXRRSET",
74         "NOTAUTH",
75         "NOTZONE",
76         "RESERVED11",
77         "RESERVED12",
78         "RESERVED13",
79         "RESERVED14",
80         "RESERVED15",
81         "BADVERS"
82 };
83
84 static const char *rtypetext[] = {
85         "rtype_0 = ",                   /* 0 */
86         "internet address = ",          /* 1 */
87         "nameserver = ",                /* 2 */
88         "md = ",                        /* 3 */
89         "mf = ",                        /* 4 */
90         "canonical name = ",            /* 5 */
91         "soa = ",                       /* 6 */
92         "mb = ",                        /* 7 */
93         "mg = ",                        /* 8 */
94         "mr = ",                        /* 9 */
95         "rtype_10 = ",                  /* 10 */
96         "protocol = ",                  /* 11 */
97         "name = ",                      /* 12 */
98         "hinfo = ",                     /* 13 */
99         "minfo = ",                     /* 14 */
100         "mail exchanger = ",            /* 15 */
101         "text = ",                      /* 16 */
102         "rp = ",                        /* 17 */
103         "afsdb = ",                     /* 18 */
104         "x25 address = ",               /* 19 */
105         "isdn address = ",              /* 20 */
106         "rt = ",                        /* 21 */
107         "nsap = ",                      /* 22 */
108         "nsap_ptr = ",                  /* 23 */
109         "signature = ",                 /* 24 */
110         "key = ",                       /* 25 */
111         "px = ",                        /* 26 */
112         "gpos = ",                      /* 27 */
113         "has AAAA address ",            /* 28 */
114         "loc = ",                       /* 29 */
115         "next = ",                      /* 30 */
116         "rtype_31 = ",                  /* 31 */
117         "rtype_32 = ",                  /* 32 */
118         "service = ",                   /* 33 */
119         "rtype_34 = ",                  /* 34 */
120         "naptr = ",                     /* 35 */
121         "kx = ",                        /* 36 */
122         "cert = ",                      /* 37 */
123         "v6 address = ",                /* 38 */
124         "dname = ",                     /* 39 */
125         "rtype_40 = ",                  /* 40 */
126         "optional = "                   /* 41 */
127 };
128
129 #define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
130
131 static void flush_lookup_list(void);
132 static void getinput(isc_task_t *task, isc_event_t *event);
133
134 static char *
135 rcode_totext(dns_rcode_t rcode)
136 {
137         static char buf[sizeof("?65535")];
138         union {
139                 const char *consttext;
140                 char *deconsttext;
141         } totext;
142
143         if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
144                 snprintf(buf, sizeof(buf), "?%u", rcode);
145                 totext.deconsttext = buf;
146         } else
147                 totext.consttext = rcodetext[rcode];
148         return totext.deconsttext;
149 }
150
151 void
152 dighost_shutdown(void) {
153         isc_event_t *event = global_event;
154
155         flush_lookup_list();
156         debug("dighost_shutdown()");
157
158         if (!in_use) {
159                 isc_app_shutdown();
160                 return;
161         }
162
163         isc_task_send(global_task, &event);
164 }
165
166 static void
167 printsoa(dns_rdata_t *rdata) {
168         dns_rdata_soa_t soa;
169         isc_result_t result;
170         char namebuf[DNS_NAME_FORMATSIZE];
171
172         result = dns_rdata_tostruct(rdata, &soa, NULL);
173         check_result(result, "dns_rdata_tostruct");
174
175         dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
176         printf("\torigin = %s\n", namebuf);
177         dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
178         printf("\tmail addr = %s\n", namebuf);
179         printf("\tserial = %u\n", soa.serial);
180         printf("\trefresh = %u\n", soa.refresh);
181         printf("\tretry = %u\n", soa.retry);
182         printf("\texpire = %u\n", soa.expire);
183         printf("\tminimum = %u\n", soa.minimum);
184         dns_rdata_freestruct(&soa);
185 }
186
187 static void
188 printa(dns_rdata_t *rdata) {
189         isc_result_t result;
190         char text[sizeof("255.255.255.255")];
191         isc_buffer_t b;
192
193         isc_buffer_init(&b, text, sizeof(text));
194         result = dns_rdata_totext(rdata, NULL, &b);
195         check_result(result, "dns_rdata_totext");
196         printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
197                (char *)isc_buffer_base(&b));
198 }
199 #ifdef DIG_SIGCHASE
200 /* Just for compatibility : not use in host program */
201 isc_result_t
202 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
203               isc_buffer_t *target)
204 {
205         UNUSED(owner_name);
206         UNUSED(rdataset);
207         UNUSED(target);
208         return(ISC_FALSE);
209 }
210 #endif
211 static void
212 printrdata(dns_rdata_t *rdata) {
213         isc_result_t result;
214         isc_buffer_t *b = NULL;
215         unsigned int size = 1024;
216         isc_boolean_t done = ISC_FALSE;
217
218         if (rdata->type < N_KNOWN_RRTYPES)
219                 printf("%s", rtypetext[rdata->type]);
220         else
221                 printf("rdata_%d = ", rdata->type);
222
223         while (!done) {
224                 result = isc_buffer_allocate(mctx, &b, size);
225                 if (result != ISC_R_SUCCESS)
226                         check_result(result, "isc_buffer_allocate");
227                 result = dns_rdata_totext(rdata, NULL, b);
228                 if (result == ISC_R_SUCCESS) {
229                         printf("%.*s\n", (int)isc_buffer_usedlength(b),
230                                (char *)isc_buffer_base(b));
231                         done = ISC_TRUE;
232                 } else if (result != ISC_R_NOSPACE)
233                         check_result(result, "dns_rdata_totext");
234                 isc_buffer_free(&b);
235                 size *= 2;
236         }
237 }
238
239 static isc_result_t
240 printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
241              dns_section_t section) {
242         isc_result_t result, loopresult;
243         dns_name_t *name;
244         dns_rdataset_t *rdataset = NULL;
245         dns_rdata_t rdata = DNS_RDATA_INIT;
246         char namebuf[DNS_NAME_FORMATSIZE];
247
248         UNUSED(query);
249         UNUSED(headers);
250
251         debug("printsection()");
252
253         result = dns_message_firstname(msg, section);
254         if (result == ISC_R_NOMORE)
255                 return (ISC_R_SUCCESS);
256         else if (result != ISC_R_SUCCESS)
257                 return (result);
258         for (;;) {
259                 name = NULL;
260                 dns_message_currentname(msg, section,
261                                         &name);
262                 for (rdataset = ISC_LIST_HEAD(name->list);
263                      rdataset != NULL;
264                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
265                         loopresult = dns_rdataset_first(rdataset);
266                         while (loopresult == ISC_R_SUCCESS) {
267                                 dns_rdataset_current(rdataset, &rdata);
268                                 switch (rdata.type) {
269                                 case dns_rdatatype_a:
270                                         if (section != DNS_SECTION_ANSWER)
271                                                 goto def_short_section;
272                                         dns_name_format(name, namebuf,
273                                                         sizeof(namebuf));
274                                         printf("Name:\t%s\n", namebuf);
275                                         printa(&rdata);
276                                         break;
277                                 case dns_rdatatype_soa:
278                                         dns_name_format(name, namebuf,
279                                                         sizeof(namebuf));
280                                         printf("%s\n", namebuf);
281                                         printsoa(&rdata);
282                                         break;
283                                 default:
284                                 def_short_section:
285                                         dns_name_format(name, namebuf,
286                                                         sizeof(namebuf));
287                                         printf("%s\t", namebuf);
288                                         printrdata(&rdata);
289                                         break;
290                                 }
291                                 dns_rdata_reset(&rdata);
292                                 loopresult = dns_rdataset_next(rdataset);
293                         }
294                 }
295                 result = dns_message_nextname(msg, section);
296                 if (result == ISC_R_NOMORE)
297                         break;
298                 else if (result != ISC_R_SUCCESS) {
299                         return (result);
300                 }
301         }
302         return (ISC_R_SUCCESS);
303 }
304
305 static isc_result_t
306 detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
307              dns_section_t section) {
308         isc_result_t result, loopresult;
309         dns_name_t *name;
310         dns_rdataset_t *rdataset = NULL;
311         dns_rdata_t rdata = DNS_RDATA_INIT;
312         char namebuf[DNS_NAME_FORMATSIZE];
313
314         UNUSED(query);
315
316         debug("detailsection()");
317
318         if (headers) {
319                 switch (section) {
320                 case DNS_SECTION_QUESTION:
321                         puts("    QUESTIONS:");
322                         break;
323                 case DNS_SECTION_ANSWER:
324                         puts("    ANSWERS:");
325                         break;
326                 case DNS_SECTION_AUTHORITY:
327                         puts("    AUTHORITY RECORDS:");
328                         break;
329                 case DNS_SECTION_ADDITIONAL:
330                         puts("    ADDITIONAL RECORDS:");
331                         break;
332                 }
333         }
334
335         result = dns_message_firstname(msg, section);
336         if (result == ISC_R_NOMORE)
337                 return (ISC_R_SUCCESS);
338         else if (result != ISC_R_SUCCESS)
339                 return (result);
340         for (;;) {
341                 name = NULL;
342                 dns_message_currentname(msg, section,
343                                         &name);
344                 for (rdataset = ISC_LIST_HEAD(name->list);
345                      rdataset != NULL;
346                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
347                         if (section == DNS_SECTION_QUESTION) {
348                                 dns_name_format(name, namebuf,
349                                                 sizeof(namebuf));
350                                 printf("\t%s, ", namebuf);
351                                 dns_rdatatype_format(rdataset->type,
352                                                      namebuf,
353                                                      sizeof(namebuf));
354                                 printf("type = %s, ", namebuf);
355                                 dns_rdataclass_format(rdataset->rdclass,
356                                                       namebuf,
357                                                       sizeof(namebuf));
358                                 printf("class = %s\n", namebuf);
359                         }
360                         loopresult = dns_rdataset_first(rdataset);
361                         while (loopresult == ISC_R_SUCCESS) {
362                                 dns_rdataset_current(rdataset, &rdata);
363
364                                 dns_name_format(name, namebuf,
365                                                 sizeof(namebuf));
366                                 printf("    ->  %s\n", namebuf);
367
368                                 switch (rdata.type) {
369                                 case dns_rdatatype_soa:
370                                         printsoa(&rdata);
371                                         break;
372                                 default:
373                                         printf("\t");
374                                         printrdata(&rdata);
375                                 }
376                                 dns_rdata_reset(&rdata);
377                                 printf("\tttl = %u\n", rdataset->ttl);
378                                 loopresult = dns_rdataset_next(rdataset);
379                         }
380                 }
381                 result = dns_message_nextname(msg, section);
382                 if (result == ISC_R_NOMORE)
383                         break;
384                 else if (result != ISC_R_SUCCESS) {
385                         return (result);
386                 }
387         }
388         return (ISC_R_SUCCESS);
389 }
390
391 void
392 received(int bytes, isc_sockaddr_t *from, dig_query_t *query)
393 {
394         UNUSED(bytes);
395         UNUSED(from);
396         UNUSED(query);
397 }
398
399 void
400 trying(char *frm, dig_lookup_t *lookup) {
401         UNUSED(frm);
402         UNUSED(lookup);
403
404 }
405
406 isc_result_t
407 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
408         char servtext[ISC_SOCKADDR_FORMATSIZE];
409
410         /* I've we've gotten this far, we've reached a server. */
411         query_error = 0;
412
413         debug("printmessage()");
414
415         isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
416         printf("Server:\t\t%s\n", query->userarg);
417         printf("Address:\t%s\n", servtext);
418
419         puts("");
420
421         if (!short_form) {
422                 isc_boolean_t headers = ISC_TRUE;
423                 puts("------------");
424                 /*              detailheader(query, msg);*/
425                 detailsection(query, msg, headers, DNS_SECTION_QUESTION);
426                 detailsection(query, msg, headers, DNS_SECTION_ANSWER);
427                 detailsection(query, msg, headers, DNS_SECTION_AUTHORITY);
428                 detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL);
429                 puts("------------");
430         }
431
432         if (msg->rcode != 0) {
433                 char nametext[DNS_NAME_FORMATSIZE];
434                 dns_name_format(query->lookup->name,
435                                 nametext, sizeof(nametext));
436                 printf("** server can't find %s: %s\n",
437                        (msg->rcode != dns_rcode_nxdomain) ? nametext :
438                        query->lookup->textname, rcode_totext(msg->rcode));
439                 debug("returning with rcode == 0");
440
441                 /* the lookup failed */
442                 print_error |= 1;
443                 return (ISC_R_SUCCESS);
444         }
445
446         if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
447                 puts("Non-authoritative answer:");
448         if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
449                 printsection(query, msg, headers, DNS_SECTION_ANSWER);
450         else
451                 printf("*** Can't find %s: No answer\n",
452                        query->lookup->textname);
453
454         if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
455             (query->lookup->rdtype != dns_rdatatype_a)) {
456                 puts("\nAuthoritative answers can be found from:");
457                 printsection(query, msg, headers,
458                              DNS_SECTION_AUTHORITY);
459                 printsection(query, msg, headers,
460                              DNS_SECTION_ADDITIONAL);
461         }
462         return (ISC_R_SUCCESS);
463 }
464
465 static void
466 show_settings(isc_boolean_t full, isc_boolean_t serv_only) {
467         dig_server_t *srv;
468         isc_sockaddr_t sockaddr;
469         dig_searchlist_t *listent;
470         isc_result_t result;
471
472         srv = ISC_LIST_HEAD(server_list);
473
474         while (srv != NULL) {
475                 char sockstr[ISC_SOCKADDR_FORMATSIZE];
476
477                 result = get_address(srv->servername, port, &sockaddr);
478                 check_result(result, "get_address");
479
480                 isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
481                 printf("Default server: %s\nAddress: %s\n",
482                         srv->userarg, sockstr);
483                 if (!full)
484                         return;
485                 srv = ISC_LIST_NEXT(srv, link);
486         }
487         if (serv_only)
488                 return;
489         printf("\nSet options:\n");
490         printf("  %s\t\t\t%s\t\t%s\n",
491                tcpmode ? "vc" : "novc",
492                short_form ? "nodebug" : "debug",
493                debugging ? "d2" : "nod2");
494         printf("  %s\t\t%s\n",
495                usesearch ? "search" : "nosearch",
496                recurse ? "recurse" : "norecurse");
497         printf("  timeout = %d\t\tretry = %d\tport = %d\n",
498                timeout, tries, port);
499         printf("  querytype = %-8s\tclass = %s\n", deftype, defclass);
500         printf("  srchlist = ");
501         for (listent = ISC_LIST_HEAD(search_list);
502              listent != NULL;
503              listent = ISC_LIST_NEXT(listent, link)) {
504                      printf("%s", listent->origin);
505                      if (ISC_LIST_NEXT(listent, link) != NULL)
506                              printf("/");
507         }
508         printf("\n");
509 }
510
511 static isc_boolean_t
512 testtype(char *typetext) {
513         isc_result_t result;
514         isc_textregion_t tr;
515         dns_rdatatype_t rdtype;
516
517         tr.base = typetext;
518         tr.length = strlen(typetext);
519         result = dns_rdatatype_fromtext(&rdtype, &tr);
520         if (result == ISC_R_SUCCESS)
521                 return (ISC_TRUE);
522         else {
523                 printf("unknown query type: %s\n", typetext);
524                 return (ISC_FALSE);
525         }
526 }
527
528 static isc_boolean_t
529 testclass(char *typetext) {
530         isc_result_t result;
531         isc_textregion_t tr;
532         dns_rdataclass_t rdclass;
533
534         tr.base = typetext;
535         tr.length = strlen(typetext);
536         result = dns_rdataclass_fromtext(&rdclass, &tr);
537         if (result == ISC_R_SUCCESS)
538                 return (ISC_TRUE);
539         else {
540                 printf("unknown query class: %s\n", typetext);
541                 return (ISC_FALSE);
542         }
543 }
544
545 static void
546 set_port(const char *value) {
547         isc_uint32_t n;
548         isc_result_t result = parse_uint(&n, value, 65535, "port");
549         if (result == ISC_R_SUCCESS)
550                 port = (isc_uint16_t) n;
551 }
552
553 static void
554 set_timeout(const char *value) {
555         isc_uint32_t n;
556         isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
557         if (result == ISC_R_SUCCESS)
558                 timeout = n;
559 }
560
561 static void
562 set_tries(const char *value) {
563         isc_uint32_t n;
564         isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
565         if (result == ISC_R_SUCCESS)
566                 tries = n;
567 }
568
569 static void
570 setoption(char *opt) {
571         if (strncasecmp(opt, "all", 4) == 0) {
572                 show_settings(ISC_TRUE, ISC_FALSE);
573         } else if (strncasecmp(opt, "class=", 6) == 0) {
574                 if (testclass(&opt[6]))
575                         strlcpy(defclass, &opt[6], sizeof(defclass));
576         } else if (strncasecmp(opt, "cl=", 3) == 0) {
577                 if (testclass(&opt[3]))
578                         strlcpy(defclass, &opt[3], sizeof(defclass));
579         } else if (strncasecmp(opt, "type=", 5) == 0) {
580                 if (testtype(&opt[5]))
581                         strlcpy(deftype, &opt[5], sizeof(deftype));
582         } else if (strncasecmp(opt, "ty=", 3) == 0) {
583                 if (testtype(&opt[3]))
584                         strlcpy(deftype, &opt[3], sizeof(deftype));
585         } else if (strncasecmp(opt, "querytype=", 10) == 0) {
586                 if (testtype(&opt[10]))
587                         strlcpy(deftype, &opt[10], sizeof(deftype));
588         } else if (strncasecmp(opt, "query=", 6) == 0) {
589                 if (testtype(&opt[6]))
590                         strlcpy(deftype, &opt[6], sizeof(deftype));
591         } else if (strncasecmp(opt, "qu=", 3) == 0) {
592                 if (testtype(&opt[3]))
593                         strlcpy(deftype, &opt[3], sizeof(deftype));
594         } else if (strncasecmp(opt, "q=", 2) == 0) {
595                 if (testtype(&opt[2]))
596                         strlcpy(deftype, &opt[2], sizeof(deftype));
597         } else if (strncasecmp(opt, "domain=", 7) == 0) {
598                 strlcpy(domainopt, &opt[7], sizeof(domainopt));
599                 set_search_domain(domainopt);
600                 usesearch = ISC_TRUE;
601         } else if (strncasecmp(opt, "do=", 3) == 0) {
602                 strlcpy(domainopt, &opt[3], sizeof(domainopt));
603                 set_search_domain(domainopt);
604                 usesearch = ISC_TRUE;
605         } else if (strncasecmp(opt, "port=", 5) == 0) {
606                 set_port(&opt[5]);
607         } else if (strncasecmp(opt, "po=", 3) == 0) {
608                 set_port(&opt[3]);
609         } else if (strncasecmp(opt, "timeout=", 8) == 0) {
610                 set_timeout(&opt[8]);
611         } else if (strncasecmp(opt, "t=", 2) == 0) {
612                 set_timeout(&opt[2]);
613         } else if (strncasecmp(opt, "rec", 3) == 0) {
614                 recurse = ISC_TRUE;
615         } else if (strncasecmp(opt, "norec", 5) == 0) {
616                 recurse = ISC_FALSE;
617         } else if (strncasecmp(opt, "retry=", 6) == 0) {
618                 set_tries(&opt[6]);
619         } else if (strncasecmp(opt, "ret=", 4) == 0) {
620                 set_tries(&opt[4]);
621         } else if (strncasecmp(opt, "def", 3) == 0) {
622                 usesearch = ISC_TRUE;
623         } else if (strncasecmp(opt, "nodef", 5) == 0) {
624                 usesearch = ISC_FALSE;
625         } else if (strncasecmp(opt, "vc", 3) == 0) {
626                 tcpmode = ISC_TRUE;
627         } else if (strncasecmp(opt, "novc", 5) == 0) {
628                 tcpmode = ISC_FALSE;
629         } else if (strncasecmp(opt, "deb", 3) == 0) {
630                 short_form = ISC_FALSE;
631                 showsearch = ISC_TRUE;
632         } else if (strncasecmp(opt, "nodeb", 5) == 0) {
633                 short_form = ISC_TRUE;
634                 showsearch = ISC_FALSE;
635         } else if (strncasecmp(opt, "d2", 2) == 0) {
636                 debugging = ISC_TRUE;
637         } else if (strncasecmp(opt, "nod2", 4) == 0) {
638                 debugging = ISC_FALSE;
639         } else if (strncasecmp(opt, "search", 3) == 0) {
640                 usesearch = ISC_TRUE;
641         } else if (strncasecmp(opt, "nosearch", 5) == 0) {
642                 usesearch = ISC_FALSE;
643         } else if (strncasecmp(opt, "sil", 3) == 0) {
644                 /* deprecation_msg = ISC_FALSE; */
645         } else if (strncasecmp(opt, "fail", 3) == 0) {
646                 nofail=ISC_FALSE;
647         } else if (strncasecmp(opt, "nofail", 3) == 0) {
648                 nofail=ISC_TRUE;
649         } else {
650                 printf("*** Invalid option: %s\n", opt);
651         }
652 }
653
654 static void
655 addlookup(char *opt) {
656         dig_lookup_t *lookup;
657         isc_result_t result;
658         isc_textregion_t tr;
659         dns_rdatatype_t rdtype;
660         dns_rdataclass_t rdclass;
661         char store[MXNAME];
662
663         debug("addlookup()");
664         tr.base = deftype;
665         tr.length = strlen(deftype);
666         result = dns_rdatatype_fromtext(&rdtype, &tr);
667         if (result != ISC_R_SUCCESS) {
668                 printf("unknown query type: %s\n", deftype);
669                 rdclass = dns_rdatatype_a;
670         }
671         tr.base = defclass;
672         tr.length = strlen(defclass);
673         result = dns_rdataclass_fromtext(&rdclass, &tr);
674         if (result != ISC_R_SUCCESS) {
675                 printf("unknown query class: %s\n", defclass);
676                 rdclass = dns_rdataclass_in;
677         }
678         lookup = make_empty_lookup();
679         if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
680             == ISC_R_SUCCESS) {
681                 strlcpy(lookup->textname, store, sizeof(lookup->textname));
682                 lookup->rdtype = dns_rdatatype_ptr;
683                 lookup->rdtypeset = ISC_TRUE;
684         } else {
685                 strlcpy(lookup->textname, opt, sizeof(lookup->textname));
686                 lookup->rdtype = rdtype;
687                 lookup->rdtypeset = ISC_TRUE;
688         }
689         lookup->rdclass = rdclass;
690         lookup->rdclassset = ISC_TRUE;
691         lookup->trace = ISC_FALSE;
692         lookup->trace_root = lookup->trace;
693         lookup->ns_search_only = ISC_FALSE;
694         lookup->identify = identify;
695         lookup->recurse = recurse;
696         lookup->aaonly = aaonly;
697         lookup->retries = tries;
698         lookup->udpsize = 0;
699         lookup->comments = comments;
700         lookup->tcp_mode = tcpmode;
701         lookup->stats = stats;
702         lookup->section_question = section_question;
703         lookup->section_answer = section_answer;
704         lookup->section_authority = section_authority;
705         lookup->section_additional = section_additional;
706         lookup->new_search = ISC_TRUE;
707         if (nofail)
708                 lookup->servfail_stops = ISC_FALSE;
709         ISC_LIST_INIT(lookup->q);
710         ISC_LINK_INIT(lookup, link);
711         ISC_LIST_APPEND(lookup_list, lookup, link);
712         lookup->origin = NULL;
713         ISC_LIST_INIT(lookup->my_server_list);
714         debug("looking up %s", lookup->textname);
715 }
716
717 static void
718 get_next_command(void) {
719         char *buf;
720         char *ptr, *arg;
721         char *input;
722
723         fflush(stdout);
724         buf = isc_mem_allocate(mctx, COMMSIZE);
725         if (buf == NULL)
726                 fatal("memory allocation failure");
727         fputs("> ", stderr);
728         fflush(stderr);
729         isc_app_block();
730         ptr = fgets(buf, COMMSIZE, stdin);
731         isc_app_unblock();
732         if (ptr == NULL) {
733                 in_use = ISC_FALSE;
734                 goto cleanup;
735         }
736         input = buf;
737         ptr = next_token(&input, " \t\r\n");
738         if (ptr == NULL)
739                 goto cleanup;
740         arg = next_token(&input, " \t\r\n");
741         if ((strcasecmp(ptr, "set") == 0) &&
742             (arg != NULL))
743                 setoption(arg);
744         else if ((strcasecmp(ptr, "server") == 0) ||
745                  (strcasecmp(ptr, "lserver") == 0)) {
746                 isc_app_block();
747                 set_nameserver(arg);
748                 check_ra = ISC_FALSE;
749                 isc_app_unblock();
750                 show_settings(ISC_TRUE, ISC_TRUE);
751         } else if (strcasecmp(ptr, "exit") == 0) {
752                 in_use = ISC_FALSE;
753                 goto cleanup;
754         } else if (strcasecmp(ptr, "help") == 0 ||
755                    strcasecmp(ptr, "?") == 0) {
756                 printf("The '%s' command is not yet implemented.\n", ptr);
757                 goto cleanup;
758         } else if (strcasecmp(ptr, "finger") == 0 ||
759                    strcasecmp(ptr, "root") == 0 ||
760                    strcasecmp(ptr, "ls") == 0 ||
761                    strcasecmp(ptr, "view") == 0) {
762                 printf("The '%s' command is not implemented.\n", ptr);
763                 goto cleanup;
764         } else
765                 addlookup(ptr);
766  cleanup:
767         isc_mem_free(mctx, buf);
768 }
769
770 static void
771 parse_args(int argc, char **argv) {
772         isc_boolean_t have_lookup = ISC_FALSE;
773
774         usesearch = ISC_TRUE;
775         for (argc--, argv++; argc > 0; argc--, argv++) {
776                 debug("main parsing %s", argv[0]);
777                 if (argv[0][0] == '-') {
778                         if (argv[0][1] != 0)
779                                 setoption(&argv[0][1]);
780                         else
781                                 have_lookup = ISC_TRUE;
782                 } else {
783                         if (!have_lookup) {
784                                 have_lookup = ISC_TRUE;
785                                 in_use = ISC_TRUE;
786                                 addlookup(argv[0]);
787                         } else {
788                                 set_nameserver(argv[0]);
789                                 check_ra = ISC_FALSE;
790                         }
791                 }
792         }
793 }
794
795 static void
796 flush_lookup_list(void) {
797         dig_lookup_t *l, *lp;
798         dig_query_t *q, *qp;
799         dig_server_t *s, *sp;
800
801         lookup_counter = 0;
802         l = ISC_LIST_HEAD(lookup_list);
803         while (l != NULL) {
804                 q = ISC_LIST_HEAD(l->q);
805                 while (q != NULL) {
806                         if (q->sock != NULL) {
807                                 isc_socket_cancel(q->sock, NULL,
808                                                   ISC_SOCKCANCEL_ALL);
809                                 isc_socket_detach(&q->sock);
810                         }
811                         if (ISC_LINK_LINKED(&q->recvbuf, link))
812                                 ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
813                                                  link);
814                         if (ISC_LINK_LINKED(&q->lengthbuf, link))
815                                 ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
816                                                  link);
817                         isc_buffer_invalidate(&q->recvbuf);
818                         isc_buffer_invalidate(&q->lengthbuf);
819                         qp = q;
820                         q = ISC_LIST_NEXT(q, link);
821                         ISC_LIST_DEQUEUE(l->q, qp, link);
822                         isc_mem_free(mctx, qp);
823                 }
824                 s = ISC_LIST_HEAD(l->my_server_list);
825                 while (s != NULL) {
826                         sp = s;
827                         s = ISC_LIST_NEXT(s, link);
828                         ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
829                         isc_mem_free(mctx, sp);
830
831                 }
832                 if (l->sendmsg != NULL)
833                         dns_message_destroy(&l->sendmsg);
834                 if (l->timer != NULL)
835                         isc_timer_detach(&l->timer);
836                 lp = l;
837                 l = ISC_LIST_NEXT(l, link);
838                 ISC_LIST_DEQUEUE(lookup_list, lp, link);
839                 isc_mem_free(mctx, lp);
840         }
841 }
842
843 static void
844 getinput(isc_task_t *task, isc_event_t *event) {
845         UNUSED(task);
846         if (global_event == NULL)
847                 global_event = event;
848         while (in_use) {
849                 get_next_command();
850                 if (ISC_LIST_HEAD(lookup_list) != NULL) {
851                         start_lookup();
852                         return;
853                 }
854         }
855         isc_app_shutdown();
856 }
857
858 int
859 main(int argc, char **argv) {
860         isc_result_t result;
861
862         ISC_LIST_INIT(lookup_list);
863         ISC_LIST_INIT(server_list);
864         ISC_LIST_INIT(search_list);
865
866         check_ra = ISC_TRUE;
867
868         result = isc_app_start();
869         check_result(result, "isc_app_start");
870
871         setup_libs();
872         progname = argv[0];
873
874         parse_args(argc, argv);
875
876         setup_system();
877         if (domainopt[0] != '\0')
878                 set_search_domain(domainopt);
879         if (in_use)
880                 result = isc_app_onrun(mctx, global_task, onrun_callback,
881                                        NULL);
882         else
883                 result = isc_app_onrun(mctx, global_task, getinput, NULL);
884         check_result(result, "isc_app_onrun");
885         in_use = ISC_TF(!in_use);
886
887         (void)isc_app_run();
888
889         puts("");
890         debug("done, and starting to shut down");
891         if (global_event != NULL)
892                 isc_event_free(&global_event);
893         cancel_all();
894         destroy_libs();
895         isc_app_finish();
896
897         return (query_error | print_error);
898 }