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