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