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