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