summaryrefslogtreecommitdiffstats
path: root/bin/dig/nslookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/dig/nslookup.c')
-rw-r--r--bin/dig/nslookup.c977
1 files changed, 977 insertions, 0 deletions
diff --git a/bin/dig/nslookup.c b/bin/dig/nslookup.c
new file mode 100644
index 0000000..a0f508d
--- /dev/null
+++ b/bin/dig/nslookup.c
@@ -0,0 +1,977 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <isc/app.h>
+#include <isc/attributes.h>
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/event.h>
+#include <isc/netaddr.h>
+#include <isc/parseint.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <dns/byaddr.h>
+#include <dns/fixedname.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+
+#include "dighost.h"
+#include "readline.h"
+
+static bool short_form = true, tcpmode = false, tcpmode_set = false,
+ identify = false, stats = true, comments = true,
+ section_question = true, section_answer = true,
+ section_authority = true, section_additional = true, recurse = true,
+ aaonly = false, nofail = true, default_lookups = true,
+ a_noanswer = false;
+
+static bool interactive;
+
+static bool in_use = false;
+static char defclass[MXRD] = "IN";
+static char deftype[MXRD] = "A";
+static isc_event_t *global_event = NULL;
+static int query_error = 1, print_error = 0;
+
+static char domainopt[DNS_NAME_MAXTEXT];
+
+static const char *rcodetext[] = { "NOERROR", "FORMERR", "SERVFAIL",
+ "NXDOMAIN", "NOTIMP", "REFUSED",
+ "YXDOMAIN", "YXRRSET", "NXRRSET",
+ "NOTAUTH", "NOTZONE", "RESERVED11",
+ "RESERVED12", "RESERVED13", "RESERVED14",
+ "RESERVED15", "BADVERS" };
+
+static const char *rtypetext[] = {
+ "rtype_0 = ", /* 0 */
+ "internet address = ", /* 1 */
+ "nameserver = ", /* 2 */
+ "md = ", /* 3 */
+ "mf = ", /* 4 */
+ "canonical name = ", /* 5 */
+ "soa = ", /* 6 */
+ "mb = ", /* 7 */
+ "mg = ", /* 8 */
+ "mr = ", /* 9 */
+ "rtype_10 = ", /* 10 */
+ "protocol = ", /* 11 */
+ "name = ", /* 12 */
+ "hinfo = ", /* 13 */
+ "minfo = ", /* 14 */
+ "mail exchanger = ", /* 15 */
+ "text = ", /* 16 */
+ "rp = ", /* 17 */
+ "afsdb = ", /* 18 */
+ "x25 address = ", /* 19 */
+ "isdn address = ", /* 20 */
+ "rt = ", /* 21 */
+ "nsap = ", /* 22 */
+ "nsap_ptr = ", /* 23 */
+ "signature = ", /* 24 */
+ "key = ", /* 25 */
+ "px = ", /* 26 */
+ "gpos = ", /* 27 */
+ "has AAAA address ", /* 28 */
+ "loc = ", /* 29 */
+ "next = ", /* 30 */
+ "rtype_31 = ", /* 31 */
+ "rtype_32 = ", /* 32 */
+ "service = ", /* 33 */
+ "rtype_34 = ", /* 34 */
+ "naptr = ", /* 35 */
+ "kx = ", /* 36 */
+ "cert = ", /* 37 */
+ "v6 address = ", /* 38 */
+ "dname = ", /* 39 */
+ "rtype_40 = ", /* 40 */
+ "optional = " /* 41 */
+};
+
+#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
+
+static void
+getinput(isc_task_t *task, isc_event_t *event);
+
+static char *
+rcode_totext(dns_rcode_t rcode) {
+ static char buf[sizeof("?65535")];
+ union {
+ const char *consttext;
+ char *deconsttext;
+ } totext;
+
+ if (rcode >= (sizeof(rcodetext) / sizeof(rcodetext[0]))) {
+ snprintf(buf, sizeof(buf), "?%u", rcode);
+ totext.deconsttext = buf;
+ } else {
+ totext.consttext = rcodetext[rcode];
+ }
+ return (totext.deconsttext);
+}
+
+static void
+query_finished(void) {
+ isc_event_t *event = global_event;
+
+ debug("dighost_shutdown()");
+
+ if (!in_use) {
+ isc_app_shutdown();
+ return;
+ }
+
+ isc_task_send(global_task, &event);
+}
+
+static void
+printsoa(dns_rdata_t *rdata) {
+ dns_rdata_soa_t soa;
+ isc_result_t result;
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ result = dns_rdata_tostruct(rdata, &soa, NULL);
+ check_result(result, "dns_rdata_tostruct");
+
+ dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
+ printf("\torigin = %s\n", namebuf);
+ dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
+ printf("\tmail addr = %s\n", namebuf);
+ printf("\tserial = %u\n", soa.serial);
+ printf("\trefresh = %u\n", soa.refresh);
+ printf("\tretry = %u\n", soa.retry);
+ printf("\texpire = %u\n", soa.expire);
+ printf("\tminimum = %u\n", soa.minimum);
+ dns_rdata_freestruct(&soa);
+}
+
+static void
+printaddr(dns_rdata_t *rdata) {
+ isc_result_t result;
+ char text[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, text, sizeof(text));
+ result = dns_rdata_totext(rdata, NULL, &b);
+ check_result(result, "dns_rdata_totext");
+ printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
+ (char *)isc_buffer_base(&b));
+}
+
+static void
+printrdata(dns_rdata_t *rdata) {
+ isc_result_t result;
+ isc_buffer_t *b = NULL;
+ unsigned int size = 1024;
+ bool done = false;
+
+ if (rdata->type < N_KNOWN_RRTYPES) {
+ printf("%s", rtypetext[rdata->type]);
+ } else {
+ printf("rdata_%d = ", rdata->type);
+ }
+
+ while (!done) {
+ isc_buffer_allocate(mctx, &b, size);
+ result = dns_rdata_totext(rdata, NULL, b);
+ if (result == ISC_R_SUCCESS) {
+ printf("%.*s\n", (int)isc_buffer_usedlength(b),
+ (char *)isc_buffer_base(b));
+ done = true;
+ } else if (result != ISC_R_NOSPACE) {
+ check_result(result, "dns_rdata_totext");
+ }
+ isc_buffer_free(&b);
+ size *= 2;
+ }
+}
+
+static isc_result_t
+printsection(dig_query_t *query, dns_message_t *msg, bool headers,
+ dns_section_t section) {
+ isc_result_t result, loopresult;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ UNUSED(query);
+ UNUSED(headers);
+
+ debug("printsection()");
+
+ result = dns_message_firstname(msg, section);
+ if (result == ISC_R_NOMORE) {
+ return (ISC_R_SUCCESS);
+ } else if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+ for (;;) {
+ name = NULL;
+ dns_message_currentname(msg, section, &name);
+ for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ loopresult = dns_rdataset_first(rdataset);
+ while (loopresult == ISC_R_SUCCESS) {
+ dns_rdataset_current(rdataset, &rdata);
+ switch (rdata.type) {
+ case dns_rdatatype_a:
+ case dns_rdatatype_aaaa:
+ if (section != DNS_SECTION_ANSWER) {
+ goto def_short_section;
+ }
+ dns_name_format(name, namebuf,
+ sizeof(namebuf));
+ printf("Name:\t%s\n", namebuf);
+ printaddr(&rdata);
+ break;
+ case dns_rdatatype_soa:
+ dns_name_format(name, namebuf,
+ sizeof(namebuf));
+ printf("%s\n", namebuf);
+ printsoa(&rdata);
+ break;
+ default:
+ def_short_section:
+ dns_name_format(name, namebuf,
+ sizeof(namebuf));
+ printf("%s\t", namebuf);
+ printrdata(&rdata);
+ break;
+ }
+ dns_rdata_reset(&rdata);
+ loopresult = dns_rdataset_next(rdataset);
+ }
+ }
+ result = dns_message_nextname(msg, section);
+ if (result == ISC_R_NOMORE) {
+ break;
+ } else if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+detailsection(dig_query_t *query, dns_message_t *msg, bool headers,
+ dns_section_t section) {
+ isc_result_t result, loopresult;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ UNUSED(query);
+
+ debug("detailsection()");
+
+ if (headers) {
+ switch (section) {
+ case DNS_SECTION_QUESTION:
+ puts(" QUESTIONS:");
+ break;
+ case DNS_SECTION_ANSWER:
+ puts(" ANSWERS:");
+ break;
+ case DNS_SECTION_AUTHORITY:
+ puts(" AUTHORITY RECORDS:");
+ break;
+ case DNS_SECTION_ADDITIONAL:
+ puts(" ADDITIONAL RECORDS:");
+ break;
+ }
+ }
+
+ result = dns_message_firstname(msg, section);
+ if (result == ISC_R_NOMORE) {
+ return (ISC_R_SUCCESS);
+ } else if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+ for (;;) {
+ name = NULL;
+ dns_message_currentname(msg, section, &name);
+ for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (section == DNS_SECTION_QUESTION) {
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ printf("\t%s, ", namebuf);
+ dns_rdatatype_format(rdataset->type, namebuf,
+ sizeof(namebuf));
+ printf("type = %s, ", namebuf);
+ dns_rdataclass_format(rdataset->rdclass,
+ namebuf, sizeof(namebuf));
+ printf("class = %s\n", namebuf);
+ }
+ loopresult = dns_rdataset_first(rdataset);
+ while (loopresult == ISC_R_SUCCESS) {
+ dns_rdataset_current(rdataset, &rdata);
+
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ printf(" -> %s\n", namebuf);
+
+ switch (rdata.type) {
+ case dns_rdatatype_soa:
+ printsoa(&rdata);
+ break;
+ default:
+ printf("\t");
+ printrdata(&rdata);
+ }
+ dns_rdata_reset(&rdata);
+ printf("\tttl = %u\n", rdataset->ttl);
+ loopresult = dns_rdataset_next(rdataset);
+ }
+ }
+ result = dns_message_nextname(msg, section);
+ if (result == ISC_R_NOMORE) {
+ break;
+ } else if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static void
+received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
+ UNUSED(bytes);
+ UNUSED(from);
+ UNUSED(query);
+}
+
+static void
+trying(char *frm, dig_lookup_t *lookup) {
+ UNUSED(frm);
+ UNUSED(lookup);
+}
+
+static void
+chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
+ isc_result_t result;
+ dns_rdataset_t *rdataset;
+ dns_rdata_cname_t cname;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned int i = msg->counts[DNS_SECTION_ANSWER];
+
+ while (i-- > 0) {
+ rdataset = NULL;
+ result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
+ dns_rdatatype_cname, 0, NULL,
+ &rdataset);
+ if (result != ISC_R_SUCCESS) {
+ return;
+ }
+ result = dns_rdataset_first(rdataset);
+ check_result(result, "dns_rdataset_first");
+ dns_rdata_reset(&rdata);
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &cname, NULL);
+ check_result(result, "dns_rdata_tostruct");
+ dns_name_copy(&cname.cname, qname);
+ dns_rdata_freestruct(&cname);
+ }
+}
+
+static isc_result_t
+printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg,
+ bool headers) {
+ char servtext[ISC_SOCKADDR_FORMATSIZE];
+
+ UNUSED(msgbuf);
+
+ /* I've we've gotten this far, we've reached a server. */
+ query_error = 0;
+
+ debug("printmessage()");
+
+ if (!default_lookups || query->lookup->rdtype == dns_rdatatype_a) {
+ isc_sockaddr_format(&query->sockaddr, servtext,
+ sizeof(servtext));
+ printf("Server:\t\t%s\n", query->userarg);
+ printf("Address:\t%s\n", servtext);
+
+ puts("");
+ }
+
+ if (!short_form) {
+ puts("------------");
+ /* detailheader(query, msg);*/
+ detailsection(query, msg, true, DNS_SECTION_QUESTION);
+ detailsection(query, msg, true, DNS_SECTION_ANSWER);
+ detailsection(query, msg, true, DNS_SECTION_AUTHORITY);
+ detailsection(query, msg, true, DNS_SECTION_ADDITIONAL);
+ puts("------------");
+ }
+
+ if (msg->rcode != 0) {
+ char nametext[DNS_NAME_FORMATSIZE];
+ dns_name_format(query->lookup->name, nametext,
+ sizeof(nametext));
+ printf("** server can't find %s: %s\n", nametext,
+ rcode_totext(msg->rcode));
+ debug("returning with rcode == 0");
+
+ /* the lookup failed */
+ print_error |= 1;
+ return (ISC_R_SUCCESS);
+ }
+
+ if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
+ char namestr[DNS_NAME_FORMATSIZE];
+ dig_lookup_t *lookup;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+
+ /* Add AAAA lookup. */
+ name = dns_fixedname_initname(&fixed);
+ dns_name_copy(query->lookup->name, name);
+ chase_cnamechain(msg, name);
+ dns_name_format(name, namestr, sizeof(namestr));
+ lookup = clone_lookup(query->lookup, false);
+ if (lookup != NULL) {
+ strlcpy(lookup->textname, namestr,
+ sizeof(lookup->textname));
+ lookup->rdtype = dns_rdatatype_aaaa;
+ lookup->rdtypeset = true;
+ lookup->origin = NULL;
+ lookup->retries = tries;
+ ISC_LIST_APPEND(lookup_list, lookup, link);
+ }
+ }
+
+ if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0 &&
+ (!default_lookups || query->lookup->rdtype == dns_rdatatype_a))
+ {
+ puts("Non-authoritative answer:");
+ }
+ if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
+ printsection(query, msg, headers, DNS_SECTION_ANSWER);
+ } else {
+ if (default_lookups && query->lookup->rdtype == dns_rdatatype_a)
+ {
+ a_noanswer = true;
+ } else if (!default_lookups ||
+ (query->lookup->rdtype == dns_rdatatype_aaaa &&
+ a_noanswer))
+ {
+ printf("*** Can't find %s: No answer\n",
+ query->lookup->textname);
+ }
+ }
+
+ if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
+ (query->lookup->rdtype != dns_rdatatype_a) &&
+ (query->lookup->rdtype != dns_rdatatype_aaaa))
+ {
+ puts("\nAuthoritative answers can be found from:");
+ printsection(query, msg, headers, DNS_SECTION_AUTHORITY);
+ printsection(query, msg, headers, DNS_SECTION_ADDITIONAL);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static void
+show_settings(bool full, bool serv_only) {
+ dig_server_t *srv;
+ isc_sockaddr_t sockaddr;
+ dig_searchlist_t *listent;
+ isc_result_t result;
+
+ srv = ISC_LIST_HEAD(server_list);
+
+ while (srv != NULL) {
+ char sockstr[ISC_SOCKADDR_FORMATSIZE];
+
+ result = get_address(srv->servername, port, &sockaddr);
+ check_result(result, "get_address");
+
+ isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
+ printf("Default server: %s\nAddress: %s\n", srv->userarg,
+ sockstr);
+ if (!full) {
+ return;
+ }
+ srv = ISC_LIST_NEXT(srv, link);
+ }
+ if (serv_only) {
+ return;
+ }
+ printf("\nSet options:\n");
+ printf(" %s\t\t\t%s\t\t%s\n", tcpmode ? "vc" : "novc",
+ short_form ? "nodebug" : "debug", debugging ? "d2" : "nod2");
+ printf(" %s\t\t%s\n", usesearch ? "search" : "nosearch",
+ recurse ? "recurse" : "norecurse");
+ printf(" timeout = %u\t\tretry = %d\tport = %u\tndots = %d\n", timeout,
+ tries, port, ndots);
+ printf(" querytype = %-8s\tclass = %s\n", deftype, defclass);
+ printf(" srchlist = ");
+ for (listent = ISC_LIST_HEAD(search_list); listent != NULL;
+ listent = ISC_LIST_NEXT(listent, link))
+ {
+ printf("%s", listent->origin);
+ if (ISC_LIST_NEXT(listent, link) != NULL) {
+ printf("/");
+ }
+ }
+ printf("\n");
+}
+
+static bool
+testtype(char *typetext) {
+ isc_result_t result;
+ isc_textregion_t tr;
+ dns_rdatatype_t rdtype;
+
+ tr.base = typetext;
+ tr.length = strlen(typetext);
+ result = dns_rdatatype_fromtext(&rdtype, &tr);
+ if (result == ISC_R_SUCCESS) {
+ return (true);
+ } else {
+ printf("unknown query type: %s\n", typetext);
+ return (false);
+ }
+}
+
+static bool
+testclass(char *typetext) {
+ isc_result_t result;
+ isc_textregion_t tr;
+ dns_rdataclass_t rdclass;
+
+ tr.base = typetext;
+ tr.length = strlen(typetext);
+ result = dns_rdataclass_fromtext(&rdclass, &tr);
+ if (result == ISC_R_SUCCESS) {
+ return (true);
+ } else {
+ printf("unknown query class: %s\n", typetext);
+ return (false);
+ }
+}
+
+static void
+set_port(const char *value) {
+ uint32_t n;
+ isc_result_t result = parse_uint(&n, value, 65535, "port");
+ if (result == ISC_R_SUCCESS) {
+ port = (uint16_t)n;
+ port_set = true;
+ }
+}
+
+static void
+set_timeout(const char *value) {
+ uint32_t n;
+ isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
+ if (result == ISC_R_SUCCESS) {
+ timeout = n;
+ }
+}
+
+static void
+set_tries(const char *value) {
+ uint32_t n;
+ isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
+ if (result == ISC_R_SUCCESS) {
+ tries = n;
+ }
+}
+
+static void
+set_ndots(const char *value) {
+ uint32_t n;
+ isc_result_t result = parse_uint(&n, value, 128, "ndots");
+ if (result == ISC_R_SUCCESS) {
+ ndots = n;
+ }
+}
+
+static void
+version(void) {
+ fprintf(stderr, "nslookup %s\n", PACKAGE_VERSION);
+}
+
+static void
+setoption(char *opt) {
+ size_t l = strlen(opt);
+
+#define CHECKOPT(A, N) \
+ ((l >= N) && (l < sizeof(A)) && (strncasecmp(opt, A, l) == 0))
+
+ if (CHECKOPT("all", 3)) {
+ show_settings(true, false);
+ } else if (strncasecmp(opt, "class=", 6) == 0) {
+ if (testclass(&opt[6])) {
+ strlcpy(defclass, &opt[6], sizeof(defclass));
+ }
+ } else if (strncasecmp(opt, "cl=", 3) == 0) {
+ if (testclass(&opt[3])) {
+ strlcpy(defclass, &opt[3], sizeof(defclass));
+ }
+ } else if (strncasecmp(opt, "type=", 5) == 0) {
+ if (testtype(&opt[5])) {
+ strlcpy(deftype, &opt[5], sizeof(deftype));
+ default_lookups = false;
+ }
+ } else if (strncasecmp(opt, "ty=", 3) == 0) {
+ if (testtype(&opt[3])) {
+ strlcpy(deftype, &opt[3], sizeof(deftype));
+ default_lookups = false;
+ }
+ } else if (strncasecmp(opt, "querytype=", 10) == 0) {
+ if (testtype(&opt[10])) {
+ strlcpy(deftype, &opt[10], sizeof(deftype));
+ default_lookups = false;
+ }
+ } else if (strncasecmp(opt, "query=", 6) == 0) {
+ if (testtype(&opt[6])) {
+ strlcpy(deftype, &opt[6], sizeof(deftype));
+ default_lookups = false;
+ }
+ } else if (strncasecmp(opt, "qu=", 3) == 0) {
+ if (testtype(&opt[3])) {
+ strlcpy(deftype, &opt[3], sizeof(deftype));
+ default_lookups = false;
+ }
+ } else if (strncasecmp(opt, "q=", 2) == 0) {
+ if (testtype(&opt[2])) {
+ strlcpy(deftype, &opt[2], sizeof(deftype));
+ default_lookups = false;
+ }
+ } else if (strncasecmp(opt, "domain=", 7) == 0) {
+ strlcpy(domainopt, &opt[7], sizeof(domainopt));
+ set_search_domain(domainopt);
+ usesearch = true;
+ } else if (strncasecmp(opt, "do=", 3) == 0) {
+ strlcpy(domainopt, &opt[3], sizeof(domainopt));
+ set_search_domain(domainopt);
+ usesearch = true;
+ } else if (strncasecmp(opt, "port=", 5) == 0) {
+ set_port(&opt[5]);
+ } else if (strncasecmp(opt, "po=", 3) == 0) {
+ set_port(&opt[3]);
+ } else if (strncasecmp(opt, "timeout=", 8) == 0) {
+ set_timeout(&opt[8]);
+ } else if (strncasecmp(opt, "t=", 2) == 0) {
+ set_timeout(&opt[2]);
+ } else if (CHECKOPT("recurse", 3)) {
+ recurse = true;
+ } else if (CHECKOPT("norecurse", 5)) {
+ recurse = false;
+ } else if (strncasecmp(opt, "retry=", 6) == 0) {
+ set_tries(&opt[6]);
+ } else if (strncasecmp(opt, "ret=", 4) == 0) {
+ set_tries(&opt[4]);
+ } else if (CHECKOPT("defname", 3)) {
+ usesearch = true;
+ } else if (CHECKOPT("nodefname", 5)) {
+ usesearch = false;
+ } else if (CHECKOPT("vc", 2)) {
+ tcpmode = true;
+ tcpmode_set = true;
+ } else if (CHECKOPT("novc", 4)) {
+ tcpmode = false;
+ tcpmode_set = true;
+ } else if (CHECKOPT("debug", 3)) {
+ short_form = false;
+ showsearch = true;
+ } else if (CHECKOPT("nodebug", 5)) {
+ short_form = true;
+ showsearch = false;
+ } else if (CHECKOPT("d2", 2)) {
+ debugging = true;
+ } else if (CHECKOPT("nod2", 4)) {
+ debugging = false;
+ } else if (CHECKOPT("search", 3)) {
+ usesearch = true;
+ } else if (CHECKOPT("nosearch", 5)) {
+ usesearch = false;
+ } else if (CHECKOPT("sil", 3)) {
+ /* deprecation_msg = false; */
+ } else if (CHECKOPT("fail", 3)) {
+ nofail = false;
+ } else if (CHECKOPT("nofail", 5)) {
+ nofail = true;
+ } else if (strncasecmp(opt, "ndots=", 6) == 0) {
+ set_ndots(&opt[6]);
+ } else {
+ printf("*** Invalid option: %s\n", opt);
+ }
+}
+
+static void
+addlookup(char *opt) {
+ dig_lookup_t *lookup;
+ isc_result_t result;
+ isc_textregion_t tr;
+ dns_rdatatype_t rdtype;
+ dns_rdataclass_t rdclass;
+ char store[MXNAME];
+
+ debug("addlookup()");
+
+ a_noanswer = false;
+
+ tr.base = deftype;
+ tr.length = strlen(deftype);
+ result = dns_rdatatype_fromtext(&rdtype, &tr);
+ if (result != ISC_R_SUCCESS) {
+ printf("unknown query type: %s\n", deftype);
+ rdclass = dns_rdatatype_a;
+ }
+ tr.base = defclass;
+ tr.length = strlen(defclass);
+ result = dns_rdataclass_fromtext(&rdclass, &tr);
+ if (result != ISC_R_SUCCESS) {
+ printf("unknown query class: %s\n", defclass);
+ rdclass = dns_rdataclass_in;
+ }
+ lookup = make_empty_lookup();
+ if (get_reverse(store, sizeof(store), opt, true) == ISC_R_SUCCESS) {
+ strlcpy(lookup->textname, store, sizeof(lookup->textname));
+ lookup->rdtype = dns_rdatatype_ptr;
+ lookup->rdtypeset = true;
+ } else {
+ strlcpy(lookup->textname, opt, sizeof(lookup->textname));
+ lookup->rdtype = rdtype;
+ lookup->rdtypeset = true;
+ }
+ lookup->rdclass = rdclass;
+ lookup->rdclassset = true;
+ lookup->trace = false;
+ lookup->trace_root = lookup->trace;
+ lookup->ns_search_only = false;
+ lookup->identify = identify;
+ lookup->recurse = recurse;
+ lookup->aaonly = aaonly;
+ lookup->retries = tries;
+ lookup->setqid = false;
+ lookup->qid = 0;
+ lookup->comments = comments;
+ if (lookup->rdtype == dns_rdatatype_any && !tcpmode_set) {
+ lookup->tcp_mode = true;
+ } else {
+ lookup->tcp_mode = tcpmode;
+ }
+ lookup->stats = stats;
+ lookup->section_question = section_question;
+ lookup->section_answer = section_answer;
+ lookup->section_authority = section_authority;
+ lookup->section_additional = section_additional;
+ lookup->new_search = true;
+ lookup->besteffort = false;
+ if (nofail) {
+ lookup->servfail_stops = false;
+ }
+ ISC_LIST_INIT(lookup->q);
+ ISC_LINK_INIT(lookup, link);
+ ISC_LIST_APPEND(lookup_list, lookup, link);
+ lookup->origin = NULL;
+ ISC_LIST_INIT(lookup->my_server_list);
+ debug("looking up %s", lookup->textname);
+}
+
+static void
+do_next_command(char *input) {
+ char *ptr, *arg, *last;
+
+ if ((ptr = strtok_r(input, " \t\r\n", &last)) == NULL) {
+ return;
+ }
+ arg = strtok_r(NULL, " \t\r\n", &last);
+ if ((strcasecmp(ptr, "set") == 0) && (arg != NULL)) {
+ setoption(arg);
+ } else if ((strcasecmp(ptr, "server") == 0) ||
+ (strcasecmp(ptr, "lserver") == 0))
+ {
+ isc_app_block();
+ set_nameserver(arg);
+ check_ra = false;
+ isc_app_unblock();
+ show_settings(true, true);
+ } else if (strcasecmp(ptr, "exit") == 0) {
+ in_use = false;
+ } else if (strcasecmp(ptr, "help") == 0 || strcasecmp(ptr, "?") == 0) {
+ printf("The '%s' command is not yet implemented.\n", ptr);
+ } else if (strcasecmp(ptr, "finger") == 0 ||
+ strcasecmp(ptr, "root") == 0 || strcasecmp(ptr, "ls") == 0 ||
+ strcasecmp(ptr, "view") == 0)
+ {
+ printf("The '%s' command is not implemented.\n", ptr);
+ } else {
+ addlookup(ptr);
+ }
+}
+
+static void
+get_next_command(void) {
+ char cmdlinebuf[COMMSIZE];
+ char *cmdline, *ptr = NULL;
+
+ isc_app_block();
+ if (interactive) {
+ cmdline = ptr = readline("> ");
+ if (ptr != NULL && *ptr != 0) {
+ add_history(ptr);
+ }
+ } else {
+ cmdline = fgets(cmdlinebuf, COMMSIZE, stdin);
+ }
+ isc_app_unblock();
+ if (cmdline == NULL) {
+ in_use = false;
+ } else {
+ do_next_command(cmdline);
+ }
+ if (ptr != NULL) {
+ free(ptr);
+ }
+}
+
+noreturn static void
+usage(void);
+
+static void
+usage(void) {
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, " nslookup [-opt ...] # interactive mode "
+ "using default server\n");
+ fprintf(stderr, " nslookup [-opt ...] - server # interactive mode "
+ "using 'server'\n");
+ fprintf(stderr, " nslookup [-opt ...] host # just look up "
+ "'host' using default server\n");
+ fprintf(stderr, " nslookup [-opt ...] host server # just look up "
+ "'host' using 'server'\n");
+ exit(1);
+}
+
+static void
+parse_args(int argc, char **argv) {
+ bool have_lookup = false;
+
+ usesearch = true;
+ for (argc--, argv++; argc > 0 && argv[0] != NULL; argc--, argv++) {
+ debug("main parsing %s", argv[0]);
+ if (argv[0][0] == '-') {
+ if (strncasecmp(argv[0], "-ver", 4) == 0) {
+ version();
+ exit(0);
+ } else if (argv[0][1] != 0) {
+ setoption(&argv[0][1]);
+ } else {
+ have_lookup = true;
+ }
+ } else {
+ if (!have_lookup) {
+ have_lookup = true;
+ in_use = true;
+ addlookup(argv[0]);
+ } else {
+ if (argv[1] != NULL) {
+ usage();
+ }
+ set_nameserver(argv[0]);
+ check_ra = false;
+ }
+ }
+ }
+}
+
+static void
+getinput(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+ if (global_event == NULL) {
+ global_event = event;
+ }
+ while (in_use) {
+ get_next_command();
+ if (ISC_LIST_HEAD(lookup_list) != NULL) {
+ start_lookup();
+ return;
+ }
+ }
+ isc_app_shutdown();
+}
+
+int
+main(int argc, char **argv) {
+ isc_result_t result;
+
+ interactive = isatty(0);
+
+ ISC_LIST_INIT(lookup_list);
+ ISC_LIST_INIT(server_list);
+ ISC_LIST_INIT(search_list);
+
+ check_ra = true;
+
+ /* setup dighost callbacks */
+ dighost_printmessage = printmessage;
+ dighost_received = received;
+ dighost_trying = trying;
+ dighost_shutdown = query_finished;
+
+ result = isc_app_start();
+ check_result(result, "isc_app_start");
+
+ setup_libs();
+ progname = argv[0];
+
+ setup_system(false, false);
+ parse_args(argc, argv);
+ if (keyfile[0] != 0) {
+ setup_file_key();
+ } else if (keysecret[0] != 0) {
+ setup_text_key();
+ }
+ if (domainopt[0] != '\0') {
+ set_search_domain(domainopt);
+ }
+ if (in_use) {
+ result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
+ } else {
+ result = isc_app_onrun(mctx, global_task, getinput, NULL);
+ }
+ check_result(result, "isc_app_onrun");
+ in_use = !in_use;
+
+ (void)isc_app_run();
+
+ puts("");
+ debug("done, and starting to shut down");
+ if (global_event != NULL) {
+ isc_event_free(&global_event);
+ }
+ cancel_all();
+ destroy_libs();
+ isc_app_finish();
+
+ return (query_error | print_error);
+}