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