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