Annotation of src/usr.bin/dig/nslookup.c, Revision 1.3
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 "rdatastruct.h"
35: #include <dns/rdatatype.h>
36:
37: #include "dig.h"
38:
39: static isc_boolean_t short_form = ISC_TRUE,
40: tcpmode = ISC_FALSE,
41: identify = ISC_FALSE, stats = ISC_TRUE,
42: comments = ISC_TRUE, section_question = ISC_TRUE,
43: section_answer = ISC_TRUE, section_authority = ISC_TRUE,
44: section_additional = ISC_TRUE, recurse = ISC_TRUE,
45: aaonly = ISC_FALSE, nofail = ISC_TRUE;
46:
47: static isc_boolean_t interactive;
48:
49: static isc_boolean_t in_use = ISC_FALSE;
50: static char defclass[MXRD] = "IN";
51: static char deftype[MXRD] = "A";
52: static isc_event_t *global_event = NULL;
53: static int query_error = 1, print_error = 0;
54:
55: static char domainopt[DNS_NAME_MAXTEXT];
56:
57: static const char *rcodetext[] = {
58: "NOERROR",
59: "FORMERR",
60: "SERVFAIL",
61: "NXDOMAIN",
62: "NOTIMP",
63: "REFUSED",
64: "YXDOMAIN",
65: "YXRRSET",
66: "NXRRSET",
67: "NOTAUTH",
68: "NOTZONE",
69: "RESERVED11",
70: "RESERVED12",
71: "RESERVED13",
72: "RESERVED14",
73: "RESERVED15",
74: "BADVERS"
75: };
76:
77: static const char *rtypetext[] = {
78: "rtype_0 = ", /* 0 */
79: "internet address = ", /* 1 */
80: "nameserver = ", /* 2 */
81: "md = ", /* 3 */
82: "mf = ", /* 4 */
83: "canonical name = ", /* 5 */
84: "soa = ", /* 6 */
85: "mb = ", /* 7 */
86: "mg = ", /* 8 */
87: "mr = ", /* 9 */
88: "rtype_10 = ", /* 10 */
89: "protocol = ", /* 11 */
90: "name = ", /* 12 */
91: "hinfo = ", /* 13 */
92: "minfo = ", /* 14 */
93: "mail exchanger = ", /* 15 */
94: "text = ", /* 16 */
95: "rp = ", /* 17 */
96: "afsdb = ", /* 18 */
97: "x25 address = ", /* 19 */
98: "isdn address = ", /* 20 */
99: "rt = ", /* 21 */
100: "nsap = ", /* 22 */
101: "nsap_ptr = ", /* 23 */
102: "signature = ", /* 24 */
103: "key = ", /* 25 */
104: "px = ", /* 26 */
105: "gpos = ", /* 27 */
106: "has AAAA address ", /* 28 */
107: "loc = ", /* 29 */
108: "next = ", /* 30 */
109: "rtype_31 = ", /* 31 */
110: "rtype_32 = ", /* 32 */
111: "service = ", /* 33 */
112: "rtype_34 = ", /* 34 */
113: "naptr = ", /* 35 */
114: "kx = ", /* 36 */
115: "cert = ", /* 37 */
116: "v6 address = ", /* 38 */
117: "dname = ", /* 39 */
118: "rtype_40 = ", /* 40 */
119: "optional = " /* 41 */
120: };
121:
122: #define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
123:
124: static void flush_lookup_list(void);
125: static void getinput(isc_task_t *task, isc_event_t *event);
126:
127: static char *
128: rcode_totext(dns_rcode_t rcode)
129: {
130: static char buf[sizeof("?65535")];
131: union {
132: const char *consttext;
133: char *deconsttext;
134: } totext;
135:
136: if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
137: snprintf(buf, sizeof(buf), "?%u", rcode);
138: totext.deconsttext = buf;
139: } else
140: totext.consttext = rcodetext[rcode];
141: return totext.deconsttext;
142: }
143:
144: static void
145: query_finished(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);
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: 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(&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: printf("\tttl = %u\n", rdataset->ttl);
359: loopresult = dns_rdataset_next(rdataset);
360: }
361: }
362: result = dns_message_nextname(msg, section);
363: if (result == ISC_R_NOMORE)
364: break;
365: else if (result != ISC_R_SUCCESS) {
366: return (result);
367: }
368: }
369: return (ISC_R_SUCCESS);
370: }
371:
372: static void
373: received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query)
374: {
375: UNUSED(bytes);
376: UNUSED(from);
377: UNUSED(query);
378: }
379:
380: static void
381: trying(char *frm, dig_lookup_t *lookup) {
382: UNUSED(frm);
383: UNUSED(lookup);
384: }
385:
386: static 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: /* I've we've gotten this far, we've reached a server. */
391: query_error = 0;
392:
393: debug("printmessage()");
394:
395: isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
396: printf("Server:\t\t%s\n", query->userarg);
397: printf("Address:\t%s\n", servtext);
398:
399: puts("");
400:
401: if (!short_form) {
402: puts("------------");
403: /* detailheader(query, msg);*/
404: detailsection(query, msg, ISC_TRUE, DNS_SECTION_QUESTION);
405: detailsection(query, msg, ISC_TRUE, DNS_SECTION_ANSWER);
406: detailsection(query, msg, ISC_TRUE, DNS_SECTION_AUTHORITY);
407: detailsection(query, msg, ISC_TRUE, DNS_SECTION_ADDITIONAL);
408: puts("------------");
409: }
410:
411: if (msg->rcode != 0) {
412: char nametext[DNS_NAME_FORMATSIZE];
413: dns_name_format(query->lookup->name,
414: nametext, sizeof(nametext));
415: printf("** server can't find %s: %s\n",
416: nametext, rcode_totext(msg->rcode));
417: debug("returning with rcode == 0");
418:
419: /* the lookup failed */
420: print_error |= 1;
421: return (ISC_R_SUCCESS);
422: }
423:
424: if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
425: puts("Non-authoritative answer:");
426: if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
427: printsection(query, msg, headers, DNS_SECTION_ANSWER);
428: else
429: printf("*** Can't find %s: No answer\n",
430: query->lookup->textname);
431:
432: if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
433: (query->lookup->rdtype != dns_rdatatype_a)) {
434: puts("\nAuthoritative answers can be found from:");
435: printsection(query, msg, headers,
436: DNS_SECTION_AUTHORITY);
437: printsection(query, msg, headers,
438: DNS_SECTION_ADDITIONAL);
439: }
440: return (ISC_R_SUCCESS);
441: }
442:
443: static void
444: show_settings(isc_boolean_t full, isc_boolean_t serv_only) {
445: dig_server_t *srv;
446: isc_sockaddr_t sockaddr;
447: dig_searchlist_t *listent;
448: isc_result_t result;
449:
450: srv = ISC_LIST_HEAD(server_list);
451:
452: while (srv != NULL) {
453: char sockstr[ISC_SOCKADDR_FORMATSIZE];
454:
455: result = get_address(srv->servername, port, &sockaddr);
456: check_result(result, "get_address");
457:
458: isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
459: printf("Default server: %s\nAddress: %s\n",
460: srv->userarg, sockstr);
461: if (!full)
462: return;
463: srv = ISC_LIST_NEXT(srv, link);
464: }
465: if (serv_only)
466: return;
467: printf("\nSet options:\n");
468: printf(" %s\t\t\t%s\t\t%s\n",
469: tcpmode ? "vc" : "novc",
470: short_form ? "nodebug" : "debug",
471: debugging ? "d2" : "nod2");
472: printf(" %s\t\t%s\n",
473: usesearch ? "search" : "nosearch",
474: recurse ? "recurse" : "norecurse");
475: printf(" timeout = %u\t\tretry = %d\tport = %u\tndots = %d\n",
476: timeout, tries, port, ndots);
477: printf(" querytype = %-8s\tclass = %s\n", deftype, defclass);
478: printf(" srchlist = ");
479: for (listent = ISC_LIST_HEAD(search_list);
480: listent != NULL;
481: listent = ISC_LIST_NEXT(listent, link)) {
482: printf("%s", listent->origin);
483: if (ISC_LIST_NEXT(listent, link) != NULL)
484: printf("/");
485: }
486: printf("\n");
487: }
488:
489: static isc_boolean_t
490: testtype(char *typetext) {
491: isc_result_t result;
492: isc_textregion_t tr;
493: dns_rdatatype_t rdtype;
494:
495: tr.base = typetext;
496: tr.length = strlen(typetext);
497: result = dns_rdatatype_fromtext(&rdtype, &tr);
498: if (result == ISC_R_SUCCESS)
499: return (ISC_TRUE);
500: else {
501: printf("unknown query type: %s\n", typetext);
502: return (ISC_FALSE);
503: }
504: }
505:
506: static isc_boolean_t
507: testclass(char *typetext) {
508: isc_result_t result;
509: isc_textregion_t tr;
510: dns_rdataclass_t rdclass;
511:
512: tr.base = typetext;
513: tr.length = strlen(typetext);
514: result = dns_rdataclass_fromtext(&rdclass, &tr);
515: if (result == ISC_R_SUCCESS)
516: return (ISC_TRUE);
517: else {
518: printf("unknown query class: %s\n", typetext);
519: return (ISC_FALSE);
520: }
521: }
522:
523: static void
524: set_port(const char *value) {
525: uint32_t n;
526: isc_result_t result = parse_uint(&n, value, 65535, "port");
527: if (result == ISC_R_SUCCESS)
528: port = (uint16_t) n;
529: }
530:
531: static void
532: set_timeout(const char *value) {
533: uint32_t n;
534: isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
535: if (result == ISC_R_SUCCESS)
536: timeout = n;
537: }
538:
539: static void
540: set_tries(const char *value) {
541: uint32_t n;
542: isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
543: if (result == ISC_R_SUCCESS)
544: tries = n;
545: }
546:
547: static void
548: set_ndots(const char *value) {
549: uint32_t n;
550: isc_result_t result = parse_uint(&n, value, 128, "ndots");
551: if (result == ISC_R_SUCCESS)
552: ndots = n;
553: }
554:
555: static void
556: version(void) {
557: fputs("nslookup " VERSION "\n", stderr);
558: }
559:
560: static void
561: setoption(char *opt) {
562: size_t l = strlen(opt);
563:
564: #define CHECKOPT(A, N) \
565: ((l >= N) && (l < sizeof(A)) && (strncasecmp(opt, A, l) == 0))
566:
567: if (CHECKOPT("all", 3)) {
568: show_settings(ISC_TRUE, ISC_FALSE);
569: } else if (strncasecmp(opt, "class=", 6) == 0) {
570: if (testclass(&opt[6]))
571: strlcpy(defclass, &opt[6], sizeof(defclass));
572: } else if (strncasecmp(opt, "cl=", 3) == 0) {
573: if (testclass(&opt[3]))
574: strlcpy(defclass, &opt[3], sizeof(defclass));
575: } else if (strncasecmp(opt, "type=", 5) == 0) {
576: if (testtype(&opt[5]))
577: strlcpy(deftype, &opt[5], sizeof(deftype));
578: } else if (strncasecmp(opt, "ty=", 3) == 0) {
579: if (testtype(&opt[3]))
580: strlcpy(deftype, &opt[3], sizeof(deftype));
581: } else if (strncasecmp(opt, "querytype=", 10) == 0) {
582: if (testtype(&opt[10]))
583: strlcpy(deftype, &opt[10], sizeof(deftype));
584: } else if (strncasecmp(opt, "query=", 6) == 0) {
585: if (testtype(&opt[6]))
586: strlcpy(deftype, &opt[6], sizeof(deftype));
587: } else if (strncasecmp(opt, "qu=", 3) == 0) {
588: if (testtype(&opt[3]))
589: strlcpy(deftype, &opt[3], sizeof(deftype));
590: } else if (strncasecmp(opt, "q=", 2) == 0) {
591: if (testtype(&opt[2]))
592: strlcpy(deftype, &opt[2], sizeof(deftype));
593: } else if (strncasecmp(opt, "domain=", 7) == 0) {
594: strlcpy(domainopt, &opt[7], sizeof(domainopt));
595: set_search_domain(domainopt);
596: usesearch = ISC_TRUE;
597: } else if (strncasecmp(opt, "do=", 3) == 0) {
598: strlcpy(domainopt, &opt[3], sizeof(domainopt));
599: set_search_domain(domainopt);
600: usesearch = ISC_TRUE;
601: } else if (strncasecmp(opt, "port=", 5) == 0) {
602: set_port(&opt[5]);
603: } else if (strncasecmp(opt, "po=", 3) == 0) {
604: set_port(&opt[3]);
605: } else if (strncasecmp(opt, "timeout=", 8) == 0) {
606: set_timeout(&opt[8]);
607: } else if (strncasecmp(opt, "t=", 2) == 0) {
608: set_timeout(&opt[2]);
609: } else if (CHECKOPT("recurse", 3)) {
610: recurse = ISC_TRUE;
611: } else if (CHECKOPT("norecurse", 5)) {
612: recurse = ISC_FALSE;
613: } else if (strncasecmp(opt, "retry=", 6) == 0) {
614: set_tries(&opt[6]);
615: } else if (strncasecmp(opt, "ret=", 4) == 0) {
616: set_tries(&opt[4]);
617: } else if (CHECKOPT("defname", 3)) {
618: usesearch = ISC_TRUE;
619: } else if (CHECKOPT("nodefname", 5)) {
620: usesearch = ISC_FALSE;
621: } else if (CHECKOPT("vc", 2) == 0) {
622: tcpmode = ISC_TRUE;
623: } else if (CHECKOPT("novc", 4) == 0) {
624: tcpmode = ISC_FALSE;
625: } else if (CHECKOPT("debug", 3) == 0) {
626: short_form = ISC_FALSE;
627: showsearch = ISC_TRUE;
628: } else if (CHECKOPT("nodebug", 5) == 0) {
629: short_form = ISC_TRUE;
630: showsearch = ISC_FALSE;
631: } else if (CHECKOPT("d2", 2) == 0) {
632: debugging = ISC_TRUE;
633: } else if (CHECKOPT("nod2", 4) == 0) {
634: debugging = ISC_FALSE;
635: } else if (CHECKOPT("search", 3) == 0) {
636: usesearch = ISC_TRUE;
637: } else if (CHECKOPT("nosearch", 5) == 0) {
638: usesearch = ISC_FALSE;
639: } else if (CHECKOPT("sil", 3) == 0) {
640: /* deprecation_msg = ISC_FALSE; */
641: } else if (CHECKOPT("fail", 3) == 0) {
642: nofail=ISC_FALSE;
643: } else if (CHECKOPT("nofail", 5) == 0) {
644: nofail=ISC_TRUE;
645: } else if (strncasecmp(opt, "ndots=", 6) == 0) {
646: set_ndots(&opt[6]);
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: strlcpy(lookup->textname, store, sizeof(lookup->textname));
680: lookup->rdtype = dns_rdatatype_ptr;
681: lookup->rdtypeset = ISC_TRUE;
682: } else {
683: strlcpy(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: if (nofail)
706: lookup->servfail_stops = ISC_FALSE;
707: ISC_LIST_INIT(lookup->q);
708: ISC_LINK_INIT(lookup, link);
709: ISC_LIST_APPEND(lookup_list, lookup, link);
710: lookup->origin = NULL;
711: ISC_LIST_INIT(lookup->my_server_list);
712: debug("looking up %s", lookup->textname);
713: }
714:
715: static void
716: do_next_command(char *input) {
717: char *ptr, *arg;
718:
719: ptr = next_token(&input, " \t\r\n");
720: if (ptr == NULL)
721: return;
722: arg = next_token(&input, " \t\r\n");
723: if ((strcasecmp(ptr, "set") == 0) &&
724: (arg != NULL))
725: setoption(arg);
726: else if ((strcasecmp(ptr, "server") == 0) ||
727: (strcasecmp(ptr, "lserver") == 0)) {
728: isc_app_block();
729: set_nameserver(arg);
730: check_ra = ISC_FALSE;
731: isc_app_unblock();
732: show_settings(ISC_TRUE, ISC_TRUE);
733: } else if (strcasecmp(ptr, "exit") == 0) {
734: in_use = ISC_FALSE;
735: } else if (strcasecmp(ptr, "help") == 0 ||
736: strcasecmp(ptr, "?") == 0) {
737: printf("The '%s' command is not yet implemented.\n", ptr);
738: } else if (strcasecmp(ptr, "finger") == 0 ||
739: strcasecmp(ptr, "root") == 0 ||
740: strcasecmp(ptr, "ls") == 0 ||
741: strcasecmp(ptr, "view") == 0) {
742: printf("The '%s' command is not implemented.\n", ptr);
743: } else
744: addlookup(ptr);
745: }
746:
747: static void
748: get_next_command(void) {
749: char *buf;
750: char *ptr;
751:
752: fflush(stdout);
753: buf = malloc(COMMSIZE);
754: if (buf == NULL)
755: fatal("memory allocation failure");
756: isc_app_block();
757: if (interactive) {
758: fputs("> ", stderr);
759: fflush(stderr);
760: ptr = fgets(buf, COMMSIZE, stdin);
761: } else
762: ptr = fgets(buf, COMMSIZE, stdin);
763: isc_app_unblock();
764: if (ptr == NULL) {
765: in_use = ISC_FALSE;
766: } else
767: do_next_command(ptr);
768: free(buf);
769: }
770:
771: static void
772: parse_args(int argc, char **argv) {
773: isc_boolean_t have_lookup = ISC_FALSE;
774:
775: usesearch = ISC_TRUE;
776: for (argc--, argv++; argc > 0; argc--, argv++) {
777: debug("main parsing %s", argv[0]);
778: if (argv[0][0] == '-') {
779: if (strncasecmp(argv[0], "-ver", 4) == 0) {
780: version();
781: exit(0);
782: } else if (argv[0][1] != 0) {
783: setoption(&argv[0][1]);
784: } else
785: have_lookup = ISC_TRUE;
786: } else {
787: if (!have_lookup) {
788: have_lookup = ISC_TRUE;
789: in_use = ISC_TRUE;
790: addlookup(argv[0]);
791: } else {
792: set_nameserver(argv[0]);
793: check_ra = ISC_FALSE;
794: }
795: }
796: }
797: }
798:
799: static void
800: flush_lookup_list(void) {
801: dig_lookup_t *l, *lp;
802: dig_query_t *q, *qp;
803: dig_server_t *s, *sp;
804:
805: lookup_counter = 0;
806: l = ISC_LIST_HEAD(lookup_list);
807: while (l != NULL) {
808: q = ISC_LIST_HEAD(l->q);
809: while (q != NULL) {
810: if (q->sock != NULL) {
811: isc_socket_cancel(q->sock, NULL,
812: ISC_SOCKCANCEL_ALL);
813: isc_socket_detach(&q->sock);
814: }
815: if (ISC_LINK_LINKED(&q->recvbuf, link))
816: ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
817: link);
818: if (ISC_LINK_LINKED(&q->lengthbuf, link))
819: ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
820: link);
821: isc_buffer_invalidate(&q->recvbuf);
822: isc_buffer_invalidate(&q->lengthbuf);
823: qp = q;
824: q = ISC_LIST_NEXT(q, link);
825: ISC_LIST_DEQUEUE(l->q, qp, link);
826: free(qp);
827: }
828: s = ISC_LIST_HEAD(l->my_server_list);
829: while (s != NULL) {
830: sp = s;
831: s = ISC_LIST_NEXT(s, link);
832: ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
833: free(sp);
834:
835: }
836: if (l->sendmsg != NULL)
837: dns_message_destroy(&l->sendmsg);
838: lp = l;
839: l = ISC_LIST_NEXT(l, link);
840: ISC_LIST_DEQUEUE(lookup_list, lp, link);
841: free(lp);
842: }
843: }
844:
845: static void
846: getinput(isc_task_t *task, isc_event_t *event) {
847: UNUSED(task);
848: if (global_event == NULL)
849: global_event = event;
850: while (in_use) {
851: get_next_command();
852: if (ISC_LIST_HEAD(lookup_list) != NULL) {
853: start_lookup();
854: return;
855: }
856: }
857: isc_app_shutdown();
858: }
859:
860: int
861: nslookup_main(int argc, char **argv) {
862: isc_result_t result;
863:
864: interactive = ISC_TF(isatty(0));
865:
866: ISC_LIST_INIT(lookup_list);
867: ISC_LIST_INIT(server_list);
1.3 ! florian 868: ISC_LIST_INIT(root_hints_server_list);
1.1 florian 869: ISC_LIST_INIT(search_list);
870:
871: check_ra = ISC_TRUE;
872:
873: /* setup dighost callbacks */
874: dighost_printmessage = printmessage;
875: dighost_received = received;
876: dighost_trying = trying;
877: dighost_shutdown = query_finished;
878:
879: result = isc_app_start();
880: check_result(result, "isc_app_start");
881:
882: if (pledge("stdio rpath inet dns", NULL) == -1) {
883: perror("pledge");
884: exit(1);
885: }
886:
887: setup_libs();
888: progname = argv[0];
889:
890: if (pledge("stdio inet dns", NULL) == -1) {
891: perror("pledge");
892: exit(1);
893: }
894:
895: parse_args(argc, argv);
896:
897: setup_system(ISC_FALSE, ISC_FALSE);
898: if (domainopt[0] != '\0')
899: set_search_domain(domainopt);
900: if (in_use)
901: result = isc_app_onrun(global_task, onrun_callback,
902: NULL);
903: else
904: result = isc_app_onrun(global_task, getinput, NULL);
905: check_result(result, "isc_app_onrun");
906: in_use = ISC_TF(!in_use);
907:
908: (void)isc_app_run();
909:
910: puts("");
911: debug("done, and starting to shut down");
912: if (global_event != NULL)
913: isc_event_free(&global_event);
914: cancel_all();
915: destroy_libs();
916: isc_app_finish();
917:
918: return (query_error | print_error);
919: }