Annotation of src/usr.bin/dig/nslookup.c, Revision 1.13
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:
1.12 florian 38: static int short_form = 1,
39: tcpmode = 0,
40: identify = 0, stats = 1,
41: comments = 1, section_question = 1,
42: section_answer = 1, section_authority = 1,
43: section_additional = 1, recurse = 1,
44: aaonly = 0, nofail = 1;
1.1 florian 45:
1.12 florian 46: static int interactive;
1.1 florian 47:
1.12 florian 48: static int in_use = 0;
1.1 florian 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;
1.12 florian 196: int done = 0;
1.1 florian 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));
1.12 florian 211: done = 1;
1.1 florian 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
1.12 florian 220: printsection(dig_query_t *query, dns_message_t *msg, int headers,
1.1 florian 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
1.12 florian 286: detailsection(dig_query_t *query, dns_message_t *msg, int headers,
1.1 florian 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
1.13 ! florian 372: received(unsigned int bytes, struct sockaddr_storage *from, dig_query_t *query)
1.1 florian 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
1.12 florian 386: printmessage(dig_query_t *query, dns_message_t *msg, int headers) {
1.1 florian 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);*/
1.12 florian 403: detailsection(query, msg, 1, DNS_SECTION_QUESTION);
404: detailsection(query, msg, 1, DNS_SECTION_ANSWER);
405: detailsection(query, msg, 1, DNS_SECTION_AUTHORITY);
406: detailsection(query, msg, 1, DNS_SECTION_ADDITIONAL);
1.1 florian 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
1.12 florian 443: show_settings(int full, int serv_only) {
1.1 florian 444: dig_server_t *srv;
1.13 ! florian 445: struct sockaddr_storage sockaddr;
1.1 florian 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:
1.12 florian 488: static int
1.1 florian 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)
1.12 florian 498: return (1);
1.1 florian 499: else {
500: printf("unknown query type: %s\n", typetext);
1.12 florian 501: return (0);
1.1 florian 502: }
503: }
504:
1.12 florian 505: static int
1.1 florian 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)
1.12 florian 515: return (1);
1.1 florian 516: else {
517: printf("unknown query class: %s\n", typetext);
1.12 florian 518: return (0);
1.1 florian 519: }
520: }
521:
522: static void
523: set_port(const char *value) {
524: uint32_t n;
1.11 florian 525: const char *errstr;
526:
527: n = strtonum(value, 0, 65535, &errstr);
528: if (errstr == NULL)
1.1 florian 529: port = (uint16_t) n;
1.11 florian 530: else
531: printf("port is %s: '%s'\n", errstr, value);
1.1 florian 532: }
533:
534: static void
535: set_timeout(const char *value) {
536: uint32_t n;
1.11 florian 537: const char *errstr;
538:
539: n = strtonum(value, 0, UINT_MAX, &errstr);
540: if (errstr == NULL)
1.1 florian 541: timeout = n;
1.11 florian 542: else
543: printf("timeout is %s: '%s'\n", errstr, value);
1.1 florian 544: }
545:
546: static void
547: set_tries(const char *value) {
548: uint32_t n;
1.11 florian 549: const char *errstr;
550:
551: n = strtonum(value, 0, INT_MAX, &errstr);
552: if (errstr == NULL)
1.1 florian 553: tries = n;
1.11 florian 554: else
555: printf("tries is %s: '%s'\n", errstr, value);
1.1 florian 556: }
557:
558: static void
559: set_ndots(const char *value) {
560: uint32_t n;
1.11 florian 561: const char *errstr;
562:
563: n = strtonum(value, 0, 128, &errstr);
564: if (errstr == NULL)
1.1 florian 565: ndots = n;
1.11 florian 566: else
567: printf("ndots is %s: '%s'\n", errstr, value);
1.1 florian 568: }
569:
570: static void
571: version(void) {
572: fputs("nslookup " VERSION "\n", stderr);
573: }
574:
575: static void
576: setoption(char *opt) {
577: size_t l = strlen(opt);
578:
579: #define CHECKOPT(A, N) \
580: ((l >= N) && (l < sizeof(A)) && (strncasecmp(opt, A, l) == 0))
581:
582: if (CHECKOPT("all", 3)) {
1.12 florian 583: show_settings(1, 0);
1.1 florian 584: } else if (strncasecmp(opt, "class=", 6) == 0) {
585: if (testclass(&opt[6]))
586: strlcpy(defclass, &opt[6], sizeof(defclass));
587: } else if (strncasecmp(opt, "cl=", 3) == 0) {
588: if (testclass(&opt[3]))
589: strlcpy(defclass, &opt[3], sizeof(defclass));
590: } else if (strncasecmp(opt, "type=", 5) == 0) {
591: if (testtype(&opt[5]))
592: strlcpy(deftype, &opt[5], sizeof(deftype));
593: } else if (strncasecmp(opt, "ty=", 3) == 0) {
594: if (testtype(&opt[3]))
595: strlcpy(deftype, &opt[3], sizeof(deftype));
596: } else if (strncasecmp(opt, "querytype=", 10) == 0) {
597: if (testtype(&opt[10]))
598: strlcpy(deftype, &opt[10], sizeof(deftype));
599: } else if (strncasecmp(opt, "query=", 6) == 0) {
600: if (testtype(&opt[6]))
601: strlcpy(deftype, &opt[6], sizeof(deftype));
602: } else if (strncasecmp(opt, "qu=", 3) == 0) {
603: if (testtype(&opt[3]))
604: strlcpy(deftype, &opt[3], sizeof(deftype));
605: } else if (strncasecmp(opt, "q=", 2) == 0) {
606: if (testtype(&opt[2]))
607: strlcpy(deftype, &opt[2], sizeof(deftype));
608: } else if (strncasecmp(opt, "domain=", 7) == 0) {
609: strlcpy(domainopt, &opt[7], sizeof(domainopt));
610: set_search_domain(domainopt);
1.12 florian 611: usesearch = 1;
1.1 florian 612: } else if (strncasecmp(opt, "do=", 3) == 0) {
613: strlcpy(domainopt, &opt[3], sizeof(domainopt));
614: set_search_domain(domainopt);
1.12 florian 615: usesearch = 1;
1.1 florian 616: } else if (strncasecmp(opt, "port=", 5) == 0) {
617: set_port(&opt[5]);
618: } else if (strncasecmp(opt, "po=", 3) == 0) {
619: set_port(&opt[3]);
620: } else if (strncasecmp(opt, "timeout=", 8) == 0) {
621: set_timeout(&opt[8]);
622: } else if (strncasecmp(opt, "t=", 2) == 0) {
623: set_timeout(&opt[2]);
624: } else if (CHECKOPT("recurse", 3)) {
1.12 florian 625: recurse = 1;
1.1 florian 626: } else if (CHECKOPT("norecurse", 5)) {
1.12 florian 627: recurse = 0;
1.1 florian 628: } else if (strncasecmp(opt, "retry=", 6) == 0) {
629: set_tries(&opt[6]);
630: } else if (strncasecmp(opt, "ret=", 4) == 0) {
631: set_tries(&opt[4]);
632: } else if (CHECKOPT("defname", 3)) {
1.12 florian 633: usesearch = 1;
1.1 florian 634: } else if (CHECKOPT("nodefname", 5)) {
1.12 florian 635: usesearch = 0;
1.1 florian 636: } else if (CHECKOPT("vc", 2) == 0) {
1.12 florian 637: tcpmode = 1;
1.1 florian 638: } else if (CHECKOPT("novc", 4) == 0) {
1.12 florian 639: tcpmode = 0;
1.1 florian 640: } else if (CHECKOPT("debug", 3) == 0) {
1.12 florian 641: short_form = 0;
642: showsearch = 1;
1.1 florian 643: } else if (CHECKOPT("nodebug", 5) == 0) {
1.12 florian 644: short_form = 1;
645: showsearch = 0;
1.1 florian 646: } else if (CHECKOPT("d2", 2) == 0) {
1.12 florian 647: debugging = 1;
1.1 florian 648: } else if (CHECKOPT("nod2", 4) == 0) {
1.12 florian 649: debugging = 0;
1.1 florian 650: } else if (CHECKOPT("search", 3) == 0) {
1.12 florian 651: usesearch = 1;
1.1 florian 652: } else if (CHECKOPT("nosearch", 5) == 0) {
1.12 florian 653: usesearch = 0;
1.1 florian 654: } else if (CHECKOPT("sil", 3) == 0) {
1.12 florian 655: /* deprecation_msg = 0; */
1.1 florian 656: } else if (CHECKOPT("fail", 3) == 0) {
1.12 florian 657: nofail=0;
1.1 florian 658: } else if (CHECKOPT("nofail", 5) == 0) {
1.12 florian 659: nofail=1;
1.1 florian 660: } else if (strncasecmp(opt, "ndots=", 6) == 0) {
661: set_ndots(&opt[6]);
662: } else {
663: printf("*** Invalid option: %s\n", opt);
664: }
665: }
666:
667: static void
668: addlookup(char *opt) {
669: dig_lookup_t *lookup;
670: isc_result_t result;
671: isc_textregion_t tr;
672: dns_rdatatype_t rdtype;
673: dns_rdataclass_t rdclass;
674: char store[MXNAME];
675:
676: debug("addlookup()");
677: tr.base = deftype;
678: tr.length = strlen(deftype);
679: result = dns_rdatatype_fromtext(&rdtype, &tr);
680: if (result != ISC_R_SUCCESS) {
681: printf("unknown query type: %s\n", deftype);
682: rdclass = dns_rdatatype_a;
683: }
684: tr.base = defclass;
685: tr.length = strlen(defclass);
686: result = dns_rdataclass_fromtext(&rdclass, &tr);
687: if (result != ISC_R_SUCCESS) {
688: printf("unknown query class: %s\n", defclass);
689: rdclass = dns_rdataclass_in;
690: }
691: lookup = make_empty_lookup();
1.12 florian 692: if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, 1)
1.1 florian 693: == ISC_R_SUCCESS) {
694: strlcpy(lookup->textname, store, sizeof(lookup->textname));
695: lookup->rdtype = dns_rdatatype_ptr;
1.12 florian 696: lookup->rdtypeset = 1;
1.1 florian 697: } else {
698: strlcpy(lookup->textname, opt, sizeof(lookup->textname));
699: lookup->rdtype = rdtype;
1.12 florian 700: lookup->rdtypeset = 1;
1.1 florian 701: }
702: lookup->rdclass = rdclass;
1.12 florian 703: lookup->rdclassset = 1;
704: lookup->trace = 0;
1.1 florian 705: lookup->trace_root = lookup->trace;
1.12 florian 706: lookup->ns_search_only = 0;
1.1 florian 707: lookup->identify = identify;
708: lookup->recurse = recurse;
709: lookup->aaonly = aaonly;
710: lookup->retries = tries;
711: lookup->udpsize = 0;
712: lookup->comments = comments;
713: lookup->tcp_mode = tcpmode;
714: lookup->stats = stats;
715: lookup->section_question = section_question;
716: lookup->section_answer = section_answer;
717: lookup->section_authority = section_authority;
718: lookup->section_additional = section_additional;
1.12 florian 719: lookup->new_search = 1;
1.1 florian 720: if (nofail)
1.12 florian 721: lookup->servfail_stops = 0;
1.1 florian 722: ISC_LIST_INIT(lookup->q);
723: ISC_LINK_INIT(lookup, link);
724: ISC_LIST_APPEND(lookup_list, lookup, link);
725: lookup->origin = NULL;
726: ISC_LIST_INIT(lookup->my_server_list);
727: debug("looking up %s", lookup->textname);
728: }
729:
730: static void
731: do_next_command(char *input) {
732: char *ptr, *arg;
733:
734: ptr = next_token(&input, " \t\r\n");
735: if (ptr == NULL)
736: return;
737: arg = next_token(&input, " \t\r\n");
1.10 deraadt 738: if (strcasecmp(ptr, "set") == 0) {
739: if (arg == NULL)
740: printf("Usage: set keyword=value, or set all\n");
741: else
742: setoption(arg);
743: } else if ((strcasecmp(ptr, "server") == 0) ||
1.1 florian 744: (strcasecmp(ptr, "lserver") == 0)) {
1.9 deraadt 745: isc_result_t res;
746:
747: if (arg == NULL)
748: printf("usage: server hostname\n");
749: else if ((res = set_nameserver(arg))) {
750: printf("couldn't get address for '%s': %s\n",
751: arg, isc_result_totext(res));
752: } else {
1.12 florian 753: check_ra = 0;
754: show_settings(1, 1);
1.9 deraadt 755: }
1.1 florian 756: } else if (strcasecmp(ptr, "exit") == 0) {
1.12 florian 757: in_use = 0;
1.1 florian 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);
768: }
769:
770: static void
771: get_next_command(void) {
772: char *buf;
773: char *ptr;
774:
775: fflush(stdout);
776: buf = malloc(COMMSIZE);
777: if (buf == NULL)
778: fatal("memory allocation failure");
779: if (interactive) {
780: fputs("> ", stderr);
781: fflush(stderr);
782: ptr = fgets(buf, COMMSIZE, stdin);
783: } else
784: ptr = fgets(buf, COMMSIZE, stdin);
785: if (ptr == NULL) {
1.12 florian 786: in_use = 0;
1.1 florian 787: } else
788: do_next_command(ptr);
789: free(buf);
790: }
791:
792: static void
793: parse_args(int argc, char **argv) {
1.12 florian 794: int have_lookup = 0;
1.1 florian 795:
1.12 florian 796: usesearch = 1;
1.1 florian 797: for (argc--, argv++; argc > 0; argc--, argv++) {
798: debug("main parsing %s", argv[0]);
799: if (argv[0][0] == '-') {
800: if (strncasecmp(argv[0], "-ver", 4) == 0) {
801: version();
802: exit(0);
803: } else if (argv[0][1] != 0) {
804: setoption(&argv[0][1]);
805: } else
1.12 florian 806: have_lookup = 1;
1.1 florian 807: } else {
808: if (!have_lookup) {
1.12 florian 809: have_lookup = 1;
810: in_use = 1;
1.1 florian 811: addlookup(argv[0]);
812: } else {
1.9 deraadt 813: isc_result_t res;
814:
815: if ((res = set_nameserver(argv[0])))
816: fatal("couldn't get address for '%s': %s",
817: argv[0], isc_result_totext(res));
1.12 florian 818: check_ra = 0;
1.1 florian 819: }
820: }
821: }
822: }
823:
824: static void
825: flush_lookup_list(void) {
826: dig_lookup_t *l, *lp;
827: dig_query_t *q, *qp;
828: dig_server_t *s, *sp;
829:
830: lookup_counter = 0;
831: l = ISC_LIST_HEAD(lookup_list);
832: while (l != NULL) {
833: q = ISC_LIST_HEAD(l->q);
834: while (q != NULL) {
835: if (q->sock != NULL) {
836: isc_socket_cancel(q->sock, NULL,
837: ISC_SOCKCANCEL_ALL);
838: isc_socket_detach(&q->sock);
839: }
840: if (ISC_LINK_LINKED(&q->recvbuf, link))
841: ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
842: link);
843: if (ISC_LINK_LINKED(&q->lengthbuf, link))
844: ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
845: link);
846: isc_buffer_invalidate(&q->recvbuf);
847: isc_buffer_invalidate(&q->lengthbuf);
848: qp = q;
849: q = ISC_LIST_NEXT(q, link);
850: ISC_LIST_DEQUEUE(l->q, qp, link);
851: free(qp);
852: }
853: s = ISC_LIST_HEAD(l->my_server_list);
854: while (s != NULL) {
855: sp = s;
856: s = ISC_LIST_NEXT(s, link);
857: ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
858: free(sp);
859:
860: }
861: if (l->sendmsg != NULL)
862: dns_message_destroy(&l->sendmsg);
863: lp = l;
864: l = ISC_LIST_NEXT(l, link);
865: ISC_LIST_DEQUEUE(lookup_list, lp, link);
866: free(lp);
867: }
868: }
869:
870: static void
871: getinput(isc_task_t *task, isc_event_t *event) {
872: UNUSED(task);
873: if (global_event == NULL)
874: global_event = event;
875: while (in_use) {
876: get_next_command();
877: if (ISC_LIST_HEAD(lookup_list) != NULL) {
878: start_lookup();
879: return;
880: }
881: }
882: isc_app_shutdown();
883: }
884:
885: int
886: nslookup_main(int argc, char **argv) {
887: isc_result_t result;
888:
1.12 florian 889: interactive = isatty(0);
1.1 florian 890:
891: ISC_LIST_INIT(lookup_list);
892: ISC_LIST_INIT(server_list);
1.3 florian 893: ISC_LIST_INIT(root_hints_server_list);
1.1 florian 894: ISC_LIST_INIT(search_list);
895:
1.12 florian 896: check_ra = 1;
1.1 florian 897:
898: /* setup dighost callbacks */
899: dighost_printmessage = printmessage;
900: dighost_received = received;
901: dighost_trying = trying;
902: dighost_shutdown = query_finished;
903:
904: result = isc_app_start();
905: check_result(result, "isc_app_start");
906:
907: if (pledge("stdio rpath inet dns", NULL) == -1) {
908: perror("pledge");
909: exit(1);
910: }
911:
912: setup_libs();
913: progname = argv[0];
914:
915: if (pledge("stdio inet dns", NULL) == -1) {
916: perror("pledge");
917: exit(1);
918: }
919:
920: parse_args(argc, argv);
921:
1.12 florian 922: setup_system(0, 0);
1.1 florian 923: if (domainopt[0] != '\0')
924: set_search_domain(domainopt);
925: if (in_use)
926: result = isc_app_onrun(global_task, onrun_callback,
927: NULL);
928: else
929: result = isc_app_onrun(global_task, getinput, NULL);
930: check_result(result, "isc_app_onrun");
1.12 florian 931: in_use = !in_use;
1.1 florian 932:
933: (void)isc_app_run();
934:
935: puts("");
936: debug("done, and starting to shut down");
937: if (global_event != NULL)
938: isc_event_free(&global_event);
939: cancel_all();
940: destroy_libs();
941:
942: return (query_error | print_error);
943: }