etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / bin / dig / nslookup.c
blob0f4931e4f303ee57676713808b988cc92672f455
1 /* $NetBSD: nslookup.c,v 1.11 2015/07/08 17:28:54 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 #include <config.h>
22 #include <stdlib.h>
23 #include <unistd.h>
25 #include <isc/app.h>
26 #include <isc/buffer.h>
27 #include <isc/commandline.h>
28 #include <isc/event.h>
29 #include <isc/parseint.h>
30 #include <isc/print.h>
31 #include <isc/string.h>
32 #include <isc/timer.h>
33 #include <isc/util.h>
34 #include <isc/task.h>
35 #include <isc/netaddr.h>
37 #include <dns/message.h>
38 #include <dns/name.h>
39 #include <dns/fixedname.h>
40 #include <dns/rdata.h>
41 #include <dns/rdataclass.h>
42 #include <dns/rdataset.h>
43 #include <dns/rdatastruct.h>
44 #include <dns/rdatatype.h>
45 #include <dns/byaddr.h>
47 #include <dig/dig.h>
49 #if defined(HAVE_READLINE)
50 #include <readline/readline.h>
51 #include <readline/history.h>
52 #endif
54 static isc_boolean_t short_form = ISC_TRUE,
55 tcpmode = ISC_FALSE,
56 identify = ISC_FALSE, stats = ISC_TRUE,
57 comments = ISC_TRUE, section_question = ISC_TRUE,
58 section_answer = ISC_TRUE, section_authority = ISC_TRUE,
59 section_additional = ISC_TRUE, recurse = ISC_TRUE,
60 aaonly = ISC_FALSE, nofail = ISC_TRUE;
62 static isc_boolean_t interactive;
64 static isc_boolean_t in_use = ISC_FALSE;
65 static char defclass[MXRD] = "IN";
66 static char deftype[MXRD] = "A";
67 static isc_event_t *global_event = NULL;
68 static int query_error = 1, print_error = 0;
70 static char domainopt[DNS_NAME_MAXTEXT];
72 static const char *rcodetext[] = {
73 "NOERROR",
74 "FORMERR",
75 "SERVFAIL",
76 "NXDOMAIN",
77 "NOTIMP",
78 "REFUSED",
79 "YXDOMAIN",
80 "YXRRSET",
81 "NXRRSET",
82 "NOTAUTH",
83 "NOTZONE",
84 "RESERVED11",
85 "RESERVED12",
86 "RESERVED13",
87 "RESERVED14",
88 "RESERVED15",
89 "BADVERS"
92 static const char *rtypetext[] = {
93 "rtype_0 = ", /* 0 */
94 "internet address = ", /* 1 */
95 "nameserver = ", /* 2 */
96 "md = ", /* 3 */
97 "mf = ", /* 4 */
98 "canonical name = ", /* 5 */
99 "soa = ", /* 6 */
100 "mb = ", /* 7 */
101 "mg = ", /* 8 */
102 "mr = ", /* 9 */
103 "rtype_10 = ", /* 10 */
104 "protocol = ", /* 11 */
105 "name = ", /* 12 */
106 "hinfo = ", /* 13 */
107 "minfo = ", /* 14 */
108 "mail exchanger = ", /* 15 */
109 "text = ", /* 16 */
110 "rp = ", /* 17 */
111 "afsdb = ", /* 18 */
112 "x25 address = ", /* 19 */
113 "isdn address = ", /* 20 */
114 "rt = ", /* 21 */
115 "nsap = ", /* 22 */
116 "nsap_ptr = ", /* 23 */
117 "signature = ", /* 24 */
118 "key = ", /* 25 */
119 "px = ", /* 26 */
120 "gpos = ", /* 27 */
121 "has AAAA address ", /* 28 */
122 "loc = ", /* 29 */
123 "next = ", /* 30 */
124 "rtype_31 = ", /* 31 */
125 "rtype_32 = ", /* 32 */
126 "service = ", /* 33 */
127 "rtype_34 = ", /* 34 */
128 "naptr = ", /* 35 */
129 "kx = ", /* 36 */
130 "cert = ", /* 37 */
131 "v6 address = ", /* 38 */
132 "dname = ", /* 39 */
133 "rtype_40 = ", /* 40 */
134 "optional = " /* 41 */
137 #define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
139 static void flush_lookup_list(void);
140 static void getinput(isc_task_t *task, isc_event_t *event);
142 static char *
143 rcode_totext(dns_rcode_t rcode)
145 static char buf[sizeof("?65535")];
146 union {
147 const char *consttext;
148 char *deconsttext;
149 } totext;
151 if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
152 snprintf(buf, sizeof(buf), "?%u", rcode);
153 totext.deconsttext = buf;
154 } else
155 totext.consttext = rcodetext[rcode];
156 return totext.deconsttext;
159 void
160 dighost_shutdown(void) {
161 isc_event_t *event = global_event;
163 flush_lookup_list();
164 debug("dighost_shutdown()");
166 if (!in_use) {
167 isc_app_shutdown();
168 return;
171 isc_task_send(global_task, &event);
174 static void
175 printsoa(dns_rdata_t *rdata) {
176 dns_rdata_soa_t soa;
177 isc_result_t result;
178 char namebuf[DNS_NAME_FORMATSIZE];
180 result = dns_rdata_tostruct(rdata, &soa, NULL);
181 check_result(result, "dns_rdata_tostruct");
183 dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
184 printf("\torigin = %s\n", namebuf);
185 dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
186 printf("\tmail addr = %s\n", namebuf);
187 printf("\tserial = %u\n", soa.serial);
188 printf("\trefresh = %u\n", soa.refresh);
189 printf("\tretry = %u\n", soa.retry);
190 printf("\texpire = %u\n", soa.expire);
191 printf("\tminimum = %u\n", soa.minimum);
192 dns_rdata_freestruct(&soa);
195 static void
196 printa(dns_rdata_t *rdata) {
197 isc_result_t result;
198 char text[sizeof("255.255.255.255")];
199 isc_buffer_t b;
201 isc_buffer_init(&b, text, sizeof(text));
202 result = dns_rdata_totext(rdata, NULL, &b);
203 check_result(result, "dns_rdata_totext");
204 printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
205 (char *)isc_buffer_base(&b));
207 #ifdef DIG_SIGCHASE
208 /* Just for compatibility : not use in host program */
209 isc_result_t
210 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
211 isc_buffer_t *target)
213 UNUSED(owner_name);
214 UNUSED(rdataset);
215 UNUSED(target);
216 return(ISC_FALSE);
218 #endif
219 static void
220 printrdata(dns_rdata_t *rdata) {
221 isc_result_t result;
222 isc_buffer_t *b = NULL;
223 unsigned int size = 1024;
224 isc_boolean_t done = ISC_FALSE;
226 if (rdata->type < N_KNOWN_RRTYPES)
227 printf("%s", rtypetext[rdata->type]);
228 else
229 printf("rdata_%d = ", rdata->type);
231 while (!done) {
232 result = isc_buffer_allocate(mctx, &b, size);
233 if (result != ISC_R_SUCCESS)
234 check_result(result, "isc_buffer_allocate");
235 result = dns_rdata_totext(rdata, NULL, b);
236 if (result == ISC_R_SUCCESS) {
237 printf("%.*s\n", (int)isc_buffer_usedlength(b),
238 (char *)isc_buffer_base(b));
239 done = ISC_TRUE;
240 } else if (result != ISC_R_NOSPACE)
241 check_result(result, "dns_rdata_totext");
242 isc_buffer_free(&b);
243 size *= 2;
247 static isc_result_t
248 printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
249 dns_section_t section) {
250 isc_result_t result, loopresult;
251 dns_name_t *name;
252 dns_rdataset_t *rdataset = NULL;
253 dns_rdata_t rdata = DNS_RDATA_INIT;
254 char namebuf[DNS_NAME_FORMATSIZE];
256 UNUSED(query);
257 UNUSED(headers);
259 debug("printsection()");
261 result = dns_message_firstname(msg, section);
262 if (result == ISC_R_NOMORE)
263 return (ISC_R_SUCCESS);
264 else if (result != ISC_R_SUCCESS)
265 return (result);
266 for (;;) {
267 name = NULL;
268 dns_message_currentname(msg, section,
269 &name);
270 for (rdataset = ISC_LIST_HEAD(name->list);
271 rdataset != NULL;
272 rdataset = ISC_LIST_NEXT(rdataset, link)) {
273 loopresult = dns_rdataset_first(rdataset);
274 while (loopresult == ISC_R_SUCCESS) {
275 dns_rdataset_current(rdataset, &rdata);
276 switch (rdata.type) {
277 case dns_rdatatype_a:
278 if (section != DNS_SECTION_ANSWER)
279 goto def_short_section;
280 dns_name_format(name, namebuf,
281 sizeof(namebuf));
282 printf("Name:\t%s\n", namebuf);
283 printa(&rdata);
284 break;
285 case dns_rdatatype_soa:
286 dns_name_format(name, namebuf,
287 sizeof(namebuf));
288 printf("%s\n", namebuf);
289 printsoa(&rdata);
290 break;
291 default:
292 def_short_section:
293 dns_name_format(name, namebuf,
294 sizeof(namebuf));
295 printf("%s\t", namebuf);
296 printrdata(&rdata);
297 break;
299 dns_rdata_reset(&rdata);
300 loopresult = dns_rdataset_next(rdataset);
303 result = dns_message_nextname(msg, section);
304 if (result == ISC_R_NOMORE)
305 break;
306 else if (result != ISC_R_SUCCESS) {
307 return (result);
310 return (ISC_R_SUCCESS);
313 static isc_result_t
314 detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
315 dns_section_t section) {
316 isc_result_t result, loopresult;
317 dns_name_t *name;
318 dns_rdataset_t *rdataset = NULL;
319 dns_rdata_t rdata = DNS_RDATA_INIT;
320 char namebuf[DNS_NAME_FORMATSIZE];
322 UNUSED(query);
324 debug("detailsection()");
326 if (headers) {
327 switch (section) {
328 case DNS_SECTION_QUESTION:
329 puts(" QUESTIONS:");
330 break;
331 case DNS_SECTION_ANSWER:
332 puts(" ANSWERS:");
333 break;
334 case DNS_SECTION_AUTHORITY:
335 puts(" AUTHORITY RECORDS:");
336 break;
337 case DNS_SECTION_ADDITIONAL:
338 puts(" ADDITIONAL RECORDS:");
339 break;
343 result = dns_message_firstname(msg, section);
344 if (result == ISC_R_NOMORE)
345 return (ISC_R_SUCCESS);
346 else if (result != ISC_R_SUCCESS)
347 return (result);
348 for (;;) {
349 name = NULL;
350 dns_message_currentname(msg, section,
351 &name);
352 for (rdataset = ISC_LIST_HEAD(name->list);
353 rdataset != NULL;
354 rdataset = ISC_LIST_NEXT(rdataset, link)) {
355 if (section == DNS_SECTION_QUESTION) {
356 dns_name_format(name, namebuf,
357 sizeof(namebuf));
358 printf("\t%s, ", namebuf);
359 dns_rdatatype_format(rdataset->type,
360 namebuf,
361 sizeof(namebuf));
362 printf("type = %s, ", namebuf);
363 dns_rdataclass_format(rdataset->rdclass,
364 namebuf,
365 sizeof(namebuf));
366 printf("class = %s\n", namebuf);
368 loopresult = dns_rdataset_first(rdataset);
369 while (loopresult == ISC_R_SUCCESS) {
370 dns_rdataset_current(rdataset, &rdata);
372 dns_name_format(name, namebuf,
373 sizeof(namebuf));
374 printf(" -> %s\n", namebuf);
376 switch (rdata.type) {
377 case dns_rdatatype_soa:
378 printsoa(&rdata);
379 break;
380 default:
381 printf("\t");
382 printrdata(&rdata);
384 dns_rdata_reset(&rdata);
385 printf("\tttl = %u\n", rdataset->ttl);
386 loopresult = dns_rdataset_next(rdataset);
389 result = dns_message_nextname(msg, section);
390 if (result == ISC_R_NOMORE)
391 break;
392 else if (result != ISC_R_SUCCESS) {
393 return (result);
396 return (ISC_R_SUCCESS);
399 void
400 received(int bytes, isc_sockaddr_t *from, dig_query_t *query)
402 UNUSED(bytes);
403 UNUSED(from);
404 UNUSED(query);
407 void
408 trying(char *frm, dig_lookup_t *lookup) {
409 UNUSED(frm);
410 UNUSED(lookup);
414 isc_result_t
415 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
416 char servtext[ISC_SOCKADDR_FORMATSIZE];
418 /* I've we've gotten this far, we've reached a server. */
419 query_error = 0;
421 debug("printmessage()");
423 isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
424 printf("Server:\t\t%s\n", query->userarg);
425 printf("Address:\t%s\n", servtext);
427 puts("");
429 if (!short_form) {
430 puts("------------");
431 /* detailheader(query, msg);*/
432 detailsection(query, msg, ISC_TRUE, DNS_SECTION_QUESTION);
433 detailsection(query, msg, ISC_TRUE, DNS_SECTION_ANSWER);
434 detailsection(query, msg, ISC_TRUE, DNS_SECTION_AUTHORITY);
435 detailsection(query, msg, ISC_TRUE, DNS_SECTION_ADDITIONAL);
436 puts("------------");
439 if (msg->rcode != 0) {
440 char nametext[DNS_NAME_FORMATSIZE];
441 dns_name_format(query->lookup->name,
442 nametext, sizeof(nametext));
443 printf("** server can't find %s: %s\n",
444 nametext, rcode_totext(msg->rcode));
445 debug("returning with rcode == 0");
447 /* the lookup failed */
448 print_error |= 1;
449 return (ISC_R_SUCCESS);
452 if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
453 puts("Non-authoritative answer:");
454 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
455 printsection(query, msg, headers, DNS_SECTION_ANSWER);
456 else
457 printf("*** Can't find %s: No answer\n",
458 query->lookup->textname);
460 if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
461 (query->lookup->rdtype != dns_rdatatype_a)) {
462 puts("\nAuthoritative answers can be found from:");
463 printsection(query, msg, headers,
464 DNS_SECTION_AUTHORITY);
465 printsection(query, msg, headers,
466 DNS_SECTION_ADDITIONAL);
468 return (ISC_R_SUCCESS);
471 static void
472 show_settings(isc_boolean_t full, isc_boolean_t serv_only) {
473 dig_server_t *srv;
474 isc_sockaddr_t sockaddr;
475 dig_searchlist_t *listent;
476 isc_result_t result;
478 srv = ISC_LIST_HEAD(server_list);
480 while (srv != NULL) {
481 char sockstr[ISC_SOCKADDR_FORMATSIZE];
483 result = get_address(srv->servername, port, &sockaddr);
484 check_result(result, "get_address");
486 isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
487 printf("Default server: %s\nAddress: %s\n",
488 srv->userarg, sockstr);
489 if (!full)
490 return;
491 srv = ISC_LIST_NEXT(srv, link);
493 if (serv_only)
494 return;
495 printf("\nSet options:\n");
496 printf(" %s\t\t\t%s\t\t%s\n",
497 tcpmode ? "vc" : "novc",
498 short_form ? "nodebug" : "debug",
499 debugging ? "d2" : "nod2");
500 printf(" %s\t\t%s\n",
501 usesearch ? "search" : "nosearch",
502 recurse ? "recurse" : "norecurse");
503 printf(" timeout = %d\t\tretry = %d\tport = %d\tndots = %d\n",
504 timeout, tries, port, ndots);
505 printf(" querytype = %-8s\tclass = %s\n", deftype, defclass);
506 printf(" srchlist = ");
507 for (listent = ISC_LIST_HEAD(search_list);
508 listent != NULL;
509 listent = ISC_LIST_NEXT(listent, link)) {
510 printf("%s", listent->origin);
511 if (ISC_LIST_NEXT(listent, link) != NULL)
512 printf("/");
514 printf("\n");
517 static isc_boolean_t
518 testtype(char *typetext) {
519 isc_result_t result;
520 isc_textregion_t tr;
521 dns_rdatatype_t rdtype;
523 tr.base = typetext;
524 tr.length = strlen(typetext);
525 result = dns_rdatatype_fromtext(&rdtype, &tr);
526 if (result == ISC_R_SUCCESS)
527 return (ISC_TRUE);
528 else {
529 printf("unknown query type: %s\n", typetext);
530 return (ISC_FALSE);
534 static isc_boolean_t
535 testclass(char *typetext) {
536 isc_result_t result;
537 isc_textregion_t tr;
538 dns_rdataclass_t rdclass;
540 tr.base = typetext;
541 tr.length = strlen(typetext);
542 result = dns_rdataclass_fromtext(&rdclass, &tr);
543 if (result == ISC_R_SUCCESS)
544 return (ISC_TRUE);
545 else {
546 printf("unknown query class: %s\n", typetext);
547 return (ISC_FALSE);
551 static void
552 set_port(const char *value) {
553 isc_uint32_t n;
554 isc_result_t result = parse_uint(&n, value, 65535, "port");
555 if (result == ISC_R_SUCCESS)
556 port = (isc_uint16_t) n;
559 static void
560 set_timeout(const char *value) {
561 isc_uint32_t n;
562 isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
563 if (result == ISC_R_SUCCESS)
564 timeout = n;
567 static void
568 set_tries(const char *value) {
569 isc_uint32_t n;
570 isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
571 if (result == ISC_R_SUCCESS)
572 tries = n;
575 static void
576 set_ndots(const char *value) {
577 isc_uint32_t n;
578 isc_result_t result = parse_uint(&n, value, 128, "ndots");
579 if (result == ISC_R_SUCCESS)
580 ndots = n;
583 static void
584 version(void) {
585 fputs("nslookup " VERSION "\n", stderr);
588 static void
589 setoption(char *opt) {
590 if (strncasecmp(opt, "all", 4) == 0) {
591 show_settings(ISC_TRUE, ISC_FALSE);
592 } else if (strncasecmp(opt, "class=", 6) == 0) {
593 if (testclass(&opt[6]))
594 strlcpy(defclass, &opt[6], sizeof(defclass));
595 } else if (strncasecmp(opt, "cl=", 3) == 0) {
596 if (testclass(&opt[3]))
597 strlcpy(defclass, &opt[3], sizeof(defclass));
598 } else if (strncasecmp(opt, "type=", 5) == 0) {
599 if (testtype(&opt[5]))
600 strlcpy(deftype, &opt[5], sizeof(deftype));
601 } else if (strncasecmp(opt, "ty=", 3) == 0) {
602 if (testtype(&opt[3]))
603 strlcpy(deftype, &opt[3], sizeof(deftype));
604 } else if (strncasecmp(opt, "querytype=", 10) == 0) {
605 if (testtype(&opt[10]))
606 strlcpy(deftype, &opt[10], sizeof(deftype));
607 } else if (strncasecmp(opt, "query=", 6) == 0) {
608 if (testtype(&opt[6]))
609 strlcpy(deftype, &opt[6], sizeof(deftype));
610 } else if (strncasecmp(opt, "qu=", 3) == 0) {
611 if (testtype(&opt[3]))
612 strlcpy(deftype, &opt[3], sizeof(deftype));
613 } else if (strncasecmp(opt, "q=", 2) == 0) {
614 if (testtype(&opt[2]))
615 strlcpy(deftype, &opt[2], sizeof(deftype));
616 } else if (strncasecmp(opt, "domain=", 7) == 0) {
617 strlcpy(domainopt, &opt[7], sizeof(domainopt));
618 set_search_domain(domainopt);
619 usesearch = ISC_TRUE;
620 } else if (strncasecmp(opt, "do=", 3) == 0) {
621 strlcpy(domainopt, &opt[3], sizeof(domainopt));
622 set_search_domain(domainopt);
623 usesearch = ISC_TRUE;
624 } else if (strncasecmp(opt, "port=", 5) == 0) {
625 set_port(&opt[5]);
626 } else if (strncasecmp(opt, "po=", 3) == 0) {
627 set_port(&opt[3]);
628 } else if (strncasecmp(opt, "timeout=", 8) == 0) {
629 set_timeout(&opt[8]);
630 } else if (strncasecmp(opt, "t=", 2) == 0) {
631 set_timeout(&opt[2]);
632 } else if (strncasecmp(opt, "rec", 3) == 0) {
633 recurse = ISC_TRUE;
634 } else if (strncasecmp(opt, "norec", 5) == 0) {
635 recurse = ISC_FALSE;
636 } else if (strncasecmp(opt, "retry=", 6) == 0) {
637 set_tries(&opt[6]);
638 } else if (strncasecmp(opt, "ret=", 4) == 0) {
639 set_tries(&opt[4]);
640 } else if (strncasecmp(opt, "def", 3) == 0) {
641 usesearch = ISC_TRUE;
642 } else if (strncasecmp(opt, "nodef", 5) == 0) {
643 usesearch = ISC_FALSE;
644 } else if (strncasecmp(opt, "vc", 3) == 0) {
645 tcpmode = ISC_TRUE;
646 } else if (strncasecmp(opt, "novc", 5) == 0) {
647 tcpmode = ISC_FALSE;
648 } else if (strncasecmp(opt, "deb", 3) == 0) {
649 short_form = ISC_FALSE;
650 showsearch = ISC_TRUE;
651 } else if (strncasecmp(opt, "nodeb", 5) == 0) {
652 short_form = ISC_TRUE;
653 showsearch = ISC_FALSE;
654 } else if (strncasecmp(opt, "d2", 2) == 0) {
655 debugging = ISC_TRUE;
656 } else if (strncasecmp(opt, "nod2", 4) == 0) {
657 debugging = ISC_FALSE;
658 } else if (strncasecmp(opt, "search", 3) == 0) {
659 usesearch = ISC_TRUE;
660 } else if (strncasecmp(opt, "nosearch", 5) == 0) {
661 usesearch = ISC_FALSE;
662 } else if (strncasecmp(opt, "sil", 3) == 0) {
663 /* deprecation_msg = ISC_FALSE; */
664 } else if (strncasecmp(opt, "fail", 3) == 0) {
665 nofail=ISC_FALSE;
666 } else if (strncasecmp(opt, "nofail", 3) == 0) {
667 nofail=ISC_TRUE;
668 } else if (strncasecmp(opt, "ndots=", 6) == 0) {
669 set_ndots(&opt[6]);
670 } else {
671 printf("*** Invalid option: %s\n", opt);
675 static void
676 addlookup(char *opt) {
677 dig_lookup_t *lookup;
678 isc_result_t result;
679 isc_textregion_t tr;
680 dns_rdatatype_t rdtype;
681 dns_rdataclass_t rdclass;
682 char store[MXNAME];
684 debug("addlookup()");
685 tr.base = deftype;
686 tr.length = strlen(deftype);
687 result = dns_rdatatype_fromtext(&rdtype, &tr);
688 if (result != ISC_R_SUCCESS) {
689 printf("unknown query type: %s\n", deftype);
690 rdclass = dns_rdatatype_a;
692 tr.base = defclass;
693 tr.length = strlen(defclass);
694 result = dns_rdataclass_fromtext(&rdclass, &tr);
695 if (result != ISC_R_SUCCESS) {
696 printf("unknown query class: %s\n", defclass);
697 rdclass = dns_rdataclass_in;
699 lookup = make_empty_lookup();
700 if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
701 == ISC_R_SUCCESS) {
702 strlcpy(lookup->textname, store, sizeof(lookup->textname));
703 lookup->rdtype = dns_rdatatype_ptr;
704 lookup->rdtypeset = ISC_TRUE;
705 } else {
706 strlcpy(lookup->textname, opt, sizeof(lookup->textname));
707 lookup->rdtype = rdtype;
708 lookup->rdtypeset = ISC_TRUE;
710 lookup->rdclass = rdclass;
711 lookup->rdclassset = ISC_TRUE;
712 lookup->trace = ISC_FALSE;
713 lookup->trace_root = lookup->trace;
714 lookup->ns_search_only = ISC_FALSE;
715 lookup->identify = identify;
716 lookup->recurse = recurse;
717 lookup->aaonly = aaonly;
718 lookup->retries = tries;
719 lookup->udpsize = 0;
720 lookup->comments = comments;
721 lookup->tcp_mode = tcpmode;
722 lookup->stats = stats;
723 lookup->section_question = section_question;
724 lookup->section_answer = section_answer;
725 lookup->section_authority = section_authority;
726 lookup->section_additional = section_additional;
727 lookup->new_search = ISC_TRUE;
728 if (nofail)
729 lookup->servfail_stops = ISC_FALSE;
730 ISC_LIST_INIT(lookup->q);
731 ISC_LINK_INIT(lookup, link);
732 ISC_LIST_APPEND(lookup_list, lookup, link);
733 lookup->origin = NULL;
734 ISC_LIST_INIT(lookup->my_server_list);
735 debug("looking up %s", lookup->textname);
738 static void
739 do_next_command(char *input) {
740 char *ptr, *arg;
742 ptr = next_token(&input, " \t\r\n");
743 if (ptr == NULL)
744 return;
745 arg = next_token(&input, " \t\r\n");
746 if ((strcasecmp(ptr, "set") == 0) &&
747 (arg != NULL))
748 setoption(arg);
749 else if ((strcasecmp(ptr, "server") == 0) ||
750 (strcasecmp(ptr, "lserver") == 0)) {
751 isc_app_block();
752 set_nameserver(arg);
753 check_ra = ISC_FALSE;
754 isc_app_unblock();
755 show_settings(ISC_TRUE, ISC_TRUE);
756 } else if (strcasecmp(ptr, "exit") == 0) {
757 in_use = ISC_FALSE;
758 } else if (strcasecmp(ptr, "help") == 0 ||
759 strcasecmp(ptr, "?") == 0) {
760 printf("The '%s' command is not yet implemented.\n", ptr);
761 } else if (strcasecmp(ptr, "finger") == 0 ||
762 strcasecmp(ptr, "root") == 0 ||
763 strcasecmp(ptr, "ls") == 0 ||
764 strcasecmp(ptr, "view") == 0) {
765 printf("The '%s' command is not implemented.\n", ptr);
766 } else
767 addlookup(ptr);
770 static void
771 get_next_command(void) {
772 char *buf;
773 char *ptr;
775 fflush(stdout);
776 buf = isc_mem_allocate(mctx, COMMSIZE);
777 if (buf == NULL)
778 fatal("memory allocation failure");
779 isc_app_block();
780 if (interactive) {
781 #ifdef HAVE_READLINE
782 ptr = readline("> ");
783 if (ptr != NULL)
784 add_history(ptr);
785 #else
786 fputs("> ", stderr);
787 fflush(stderr);
788 ptr = fgets(buf, COMMSIZE, stdin);
789 #endif
790 } else
791 ptr = fgets(buf, COMMSIZE, stdin);
792 isc_app_unblock();
793 if (ptr == NULL) {
794 in_use = ISC_FALSE;
795 } else
796 do_next_command(ptr);
797 #ifdef HAVE_READLINE
798 if (interactive)
799 free(ptr);
800 #endif
801 isc_mem_free(mctx, buf);
804 static void
805 parse_args(int argc, char **argv) {
806 isc_boolean_t have_lookup = ISC_FALSE;
808 usesearch = ISC_TRUE;
809 for (argc--, argv++; argc > 0; argc--, argv++) {
810 debug("main parsing %s", argv[0]);
811 if (argv[0][0] == '-') {
812 if (strncasecmp(argv[0], "-ver", 4) == 0) {
813 version();
814 exit(0);
815 } else if (argv[0][1] != 0) {
816 setoption(&argv[0][1]);
817 } else
818 have_lookup = ISC_TRUE;
819 } else {
820 if (!have_lookup) {
821 have_lookup = ISC_TRUE;
822 in_use = ISC_TRUE;
823 addlookup(argv[0]);
824 } else {
825 set_nameserver(argv[0]);
826 check_ra = ISC_FALSE;
832 static void
833 flush_lookup_list(void) {
834 dig_lookup_t *l, *lp;
835 dig_query_t *q, *qp;
836 dig_server_t *s, *sp;
838 lookup_counter = 0;
839 l = ISC_LIST_HEAD(lookup_list);
840 while (l != NULL) {
841 q = ISC_LIST_HEAD(l->q);
842 while (q != NULL) {
843 if (q->sock != NULL) {
844 isc_socket_cancel(q->sock, NULL,
845 ISC_SOCKCANCEL_ALL);
846 isc_socket_detach(&q->sock);
848 if (ISC_LINK_LINKED(&q->recvbuf, link))
849 ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
850 link);
851 if (ISC_LINK_LINKED(&q->lengthbuf, link))
852 ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
853 link);
854 isc_buffer_invalidate(&q->recvbuf);
855 isc_buffer_invalidate(&q->lengthbuf);
856 qp = q;
857 q = ISC_LIST_NEXT(q, link);
858 ISC_LIST_DEQUEUE(l->q, qp, link);
859 isc_mem_free(mctx, qp);
861 s = ISC_LIST_HEAD(l->my_server_list);
862 while (s != NULL) {
863 sp = s;
864 s = ISC_LIST_NEXT(s, link);
865 ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
866 isc_mem_free(mctx, sp);
869 if (l->sendmsg != NULL)
870 dns_message_destroy(&l->sendmsg);
871 if (l->timer != NULL)
872 isc_timer_detach(&l->timer);
873 lp = l;
874 l = ISC_LIST_NEXT(l, link);
875 ISC_LIST_DEQUEUE(lookup_list, lp, link);
876 isc_mem_free(mctx, lp);
880 static void
881 getinput(isc_task_t *task, isc_event_t *event) {
882 UNUSED(task);
883 if (global_event == NULL)
884 global_event = event;
885 while (in_use) {
886 get_next_command();
887 if (ISC_LIST_HEAD(lookup_list) != NULL) {
888 start_lookup();
889 return;
892 isc_app_shutdown();
896 main(int argc, char **argv) {
897 isc_result_t result;
899 interactive = ISC_TF(isatty(0));
901 ISC_LIST_INIT(lookup_list);
902 ISC_LIST_INIT(server_list);
903 ISC_LIST_INIT(search_list);
905 check_ra = ISC_TRUE;
907 result = isc_app_start();
908 check_result(result, "isc_app_start");
910 setup_libs();
911 progname = argv[0];
913 parse_args(argc, argv);
915 setup_system();
916 if (domainopt[0] != '\0')
917 set_search_domain(domainopt);
918 if (in_use)
919 result = isc_app_onrun(mctx, global_task, onrun_callback,
920 NULL);
921 else
922 result = isc_app_onrun(mctx, global_task, getinput, NULL);
923 check_result(result, "isc_app_onrun");
924 in_use = ISC_TF(!in_use);
926 (void)isc_app_run();
928 puts("");
929 debug("done, and starting to shut down");
930 if (global_event != NULL)
931 isc_event_free(&global_event);
932 cancel_all();
933 destroy_libs();
934 isc_app_finish();
936 return (query_error | print_error);