Annotation of src/usr.bin/dig/nslookup.c, Revision 1.6
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);
1.6 ! florian 177: dns_rdata_freestruct_soa(&soa);
1.1 florian 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: set_nameserver(arg);
729: check_ra = ISC_FALSE;
730: show_settings(ISC_TRUE, ISC_TRUE);
731: } else if (strcasecmp(ptr, "exit") == 0) {
732: in_use = ISC_FALSE;
733: } else if (strcasecmp(ptr, "help") == 0 ||
734: strcasecmp(ptr, "?") == 0) {
735: printf("The '%s' command is not yet implemented.\n", ptr);
736: } else if (strcasecmp(ptr, "finger") == 0 ||
737: strcasecmp(ptr, "root") == 0 ||
738: strcasecmp(ptr, "ls") == 0 ||
739: strcasecmp(ptr, "view") == 0) {
740: printf("The '%s' command is not implemented.\n", ptr);
741: } else
742: addlookup(ptr);
743: }
744:
745: static void
746: get_next_command(void) {
747: char *buf;
748: char *ptr;
749:
750: fflush(stdout);
751: buf = malloc(COMMSIZE);
752: if (buf == NULL)
753: fatal("memory allocation failure");
754: if (interactive) {
755: fputs("> ", stderr);
756: fflush(stderr);
757: ptr = fgets(buf, COMMSIZE, stdin);
758: } else
759: ptr = fgets(buf, COMMSIZE, stdin);
760: if (ptr == NULL) {
761: in_use = ISC_FALSE;
762: } else
763: do_next_command(ptr);
764: free(buf);
765: }
766:
767: static void
768: parse_args(int argc, char **argv) {
769: isc_boolean_t have_lookup = ISC_FALSE;
770:
771: usesearch = ISC_TRUE;
772: for (argc--, argv++; argc > 0; argc--, argv++) {
773: debug("main parsing %s", argv[0]);
774: if (argv[0][0] == '-') {
775: if (strncasecmp(argv[0], "-ver", 4) == 0) {
776: version();
777: exit(0);
778: } else if (argv[0][1] != 0) {
779: setoption(&argv[0][1]);
780: } else
781: have_lookup = ISC_TRUE;
782: } else {
783: if (!have_lookup) {
784: have_lookup = ISC_TRUE;
785: in_use = ISC_TRUE;
786: addlookup(argv[0]);
787: } else {
788: set_nameserver(argv[0]);
789: check_ra = ISC_FALSE;
790: }
791: }
792: }
793: }
794:
795: static void
796: flush_lookup_list(void) {
797: dig_lookup_t *l, *lp;
798: dig_query_t *q, *qp;
799: dig_server_t *s, *sp;
800:
801: lookup_counter = 0;
802: l = ISC_LIST_HEAD(lookup_list);
803: while (l != NULL) {
804: q = ISC_LIST_HEAD(l->q);
805: while (q != NULL) {
806: if (q->sock != NULL) {
807: isc_socket_cancel(q->sock, NULL,
808: ISC_SOCKCANCEL_ALL);
809: isc_socket_detach(&q->sock);
810: }
811: if (ISC_LINK_LINKED(&q->recvbuf, link))
812: ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
813: link);
814: if (ISC_LINK_LINKED(&q->lengthbuf, link))
815: ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
816: link);
817: isc_buffer_invalidate(&q->recvbuf);
818: isc_buffer_invalidate(&q->lengthbuf);
819: qp = q;
820: q = ISC_LIST_NEXT(q, link);
821: ISC_LIST_DEQUEUE(l->q, qp, link);
822: free(qp);
823: }
824: s = ISC_LIST_HEAD(l->my_server_list);
825: while (s != NULL) {
826: sp = s;
827: s = ISC_LIST_NEXT(s, link);
828: ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
829: free(sp);
830:
831: }
832: if (l->sendmsg != NULL)
833: dns_message_destroy(&l->sendmsg);
834: lp = l;
835: l = ISC_LIST_NEXT(l, link);
836: ISC_LIST_DEQUEUE(lookup_list, lp, link);
837: free(lp);
838: }
839: }
840:
841: static void
842: getinput(isc_task_t *task, isc_event_t *event) {
843: UNUSED(task);
844: if (global_event == NULL)
845: global_event = event;
846: while (in_use) {
847: get_next_command();
848: if (ISC_LIST_HEAD(lookup_list) != NULL) {
849: start_lookup();
850: return;
851: }
852: }
853: isc_app_shutdown();
854: }
855:
856: int
857: nslookup_main(int argc, char **argv) {
858: isc_result_t result;
859:
860: interactive = ISC_TF(isatty(0));
861:
862: ISC_LIST_INIT(lookup_list);
863: ISC_LIST_INIT(server_list);
1.3 florian 864: ISC_LIST_INIT(root_hints_server_list);
1.1 florian 865: ISC_LIST_INIT(search_list);
866:
867: check_ra = ISC_TRUE;
868:
869: /* setup dighost callbacks */
870: dighost_printmessage = printmessage;
871: dighost_received = received;
872: dighost_trying = trying;
873: dighost_shutdown = query_finished;
874:
875: result = isc_app_start();
876: check_result(result, "isc_app_start");
877:
878: if (pledge("stdio rpath inet dns", NULL) == -1) {
879: perror("pledge");
880: exit(1);
881: }
882:
883: setup_libs();
884: progname = argv[0];
885:
886: if (pledge("stdio inet dns", NULL) == -1) {
887: perror("pledge");
888: exit(1);
889: }
890:
891: parse_args(argc, argv);
892:
893: setup_system(ISC_FALSE, ISC_FALSE);
894: if (domainopt[0] != '\0')
895: set_search_domain(domainopt);
896: if (in_use)
897: result = isc_app_onrun(global_task, onrun_callback,
898: NULL);
899: else
900: result = isc_app_onrun(global_task, getinput, NULL);
901: check_result(result, "isc_app_onrun");
902: in_use = ISC_TF(!in_use);
903:
904: (void)isc_app_run();
905:
906: puts("");
907: debug("done, and starting to shut down");
908: if (global_event != NULL)
909: isc_event_free(&global_event);
910: cancel_all();
911: destroy_libs();
912:
913: return (query_error | print_error);
914: }