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