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