mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 10:10:06 +00:00
Replace dns_fixedname_init() calls followed by dns_fixedname_name() calls with calls to dns_fixedname_initname() where it is possible without affecting current behavior and/or performance. This patch was mostly prepared using Coccinelle and the following semantic patch: @@ expression fixedname, name; @@ - dns_fixedname_init(&fixedname); ... - name = dns_fixedname_name(&fixedname); + name = dns_fixedname_initname(&fixedname); The resulting set of changes was then manually reviewed to exclude false positives and apply minor tweaks. It is likely that more occurrences of this pattern can be refactored in an identical way. This commit only takes care of the low-hanging fruit.
1021 lines
26 KiB
C
1021 lines
26 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* 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 http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include <isc/app.h>
|
|
#include <isc/buffer.h>
|
|
#include <isc/commandline.h>
|
|
#include <isc/event.h>
|
|
#include <isc/parseint.h>
|
|
#include <isc/print.h>
|
|
#include <isc/string.h>
|
|
#include <isc/util.h>
|
|
#include <isc/task.h>
|
|
#include <isc/netaddr.h>
|
|
|
|
#include <dns/message.h>
|
|
#include <dns/name.h>
|
|
#include <dns/fixedname.h>
|
|
#include <dns/rdata.h>
|
|
#include <dns/rdataclass.h>
|
|
#include <dns/rdataset.h>
|
|
#include <dns/rdatastruct.h>
|
|
#include <dns/rdatatype.h>
|
|
#include <dns/byaddr.h>
|
|
|
|
#include <dig/dig.h>
|
|
|
|
#if defined(HAVE_READLINE)
|
|
#if defined(HAVE_EDIT_READLINE_READLINE_H)
|
|
#include <edit/readline/readline.h>
|
|
#if defined(HAVE_EDIT_READLINE_HISTORY_H)
|
|
#include <edit/readline/history.h>
|
|
#endif
|
|
#elif defined(HAVE_EDITLINE_READLINE_H)
|
|
#include <editline/readline.h>
|
|
#elif defined(HAVE_READLINE_READLINE_H)
|
|
#include <readline/readline.h>
|
|
#if defined (HAVE_READLINE_HISTORY_H)
|
|
#include <readline/history.h>
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
static isc_boolean_t short_form = ISC_TRUE,
|
|
tcpmode = ISC_FALSE, tcpmode_set = ISC_FALSE,
|
|
identify = ISC_FALSE, stats = ISC_TRUE,
|
|
comments = ISC_TRUE, section_question = ISC_TRUE,
|
|
section_answer = ISC_TRUE, section_authority = ISC_TRUE,
|
|
section_additional = ISC_TRUE, recurse = ISC_TRUE,
|
|
aaonly = ISC_FALSE, nofail = ISC_TRUE,
|
|
default_lookups = ISC_TRUE, a_noanswer = ISC_FALSE;
|
|
|
|
static isc_boolean_t interactive;
|
|
|
|
static isc_boolean_t in_use = ISC_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 flush_lookup_list(void);
|
|
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;
|
|
|
|
flush_lookup_list();
|
|
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;
|
|
isc_boolean_t done = ISC_FALSE;
|
|
|
|
if (rdata->type < N_KNOWN_RRTYPES)
|
|
printf("%s", rtypetext[rdata->type]);
|
|
else
|
|
printf("rdata_%d = ", rdata->type);
|
|
|
|
while (!done) {
|
|
result = isc_buffer_allocate(mctx, &b, size);
|
|
if (result != ISC_R_SUCCESS)
|
|
check_result(result, "isc_buffer_allocate");
|
|
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 = ISC_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, isc_boolean_t 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, isc_boolean_t 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, NULL);
|
|
dns_rdata_freestruct(&cname);
|
|
}
|
|
}
|
|
|
|
static isc_result_t
|
|
printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
|
|
char servtext[ISC_SOCKADDR_FORMATSIZE];
|
|
|
|
/* 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, ISC_TRUE, DNS_SECTION_QUESTION);
|
|
detailsection(query, msg, ISC_TRUE, DNS_SECTION_ANSWER);
|
|
detailsection(query, msg, ISC_TRUE, DNS_SECTION_AUTHORITY);
|
|
detailsection(query, msg, ISC_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, NULL);
|
|
chase_cnamechain(msg, name);
|
|
dns_name_format(name, namestr, sizeof(namestr));
|
|
lookup = clone_lookup(query->lookup, ISC_FALSE);
|
|
if (lookup != NULL) {
|
|
strlcpy(lookup->textname, namestr,
|
|
sizeof(lookup->textname));
|
|
lookup->rdtype = dns_rdatatype_aaaa;
|
|
lookup->rdtypeset = ISC_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 = ISC_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(isc_boolean_t full, isc_boolean_t 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 isc_boolean_t
|
|
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 (ISC_TRUE);
|
|
else {
|
|
printf("unknown query type: %s\n", typetext);
|
|
return (ISC_FALSE);
|
|
}
|
|
}
|
|
|
|
static isc_boolean_t
|
|
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 (ISC_TRUE);
|
|
else {
|
|
printf("unknown query class: %s\n", typetext);
|
|
return (ISC_FALSE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_port(const char *value) {
|
|
isc_uint32_t n;
|
|
isc_result_t result = parse_uint(&n, value, 65535, "port");
|
|
if (result == ISC_R_SUCCESS)
|
|
port = (isc_uint16_t) n;
|
|
}
|
|
|
|
static void
|
|
set_timeout(const char *value) {
|
|
isc_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) {
|
|
isc_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) {
|
|
isc_uint32_t n;
|
|
isc_result_t result = parse_uint(&n, value, 128, "ndots");
|
|
if (result == ISC_R_SUCCESS)
|
|
ndots = n;
|
|
}
|
|
|
|
static void
|
|
version(void) {
|
|
fputs("nslookup " VERSION "\n", stderr);
|
|
}
|
|
|
|
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(ISC_TRUE, ISC_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 = ISC_FALSE;
|
|
}
|
|
} else if (strncasecmp(opt, "ty=", 3) == 0) {
|
|
if (testtype(&opt[3])) {
|
|
strlcpy(deftype, &opt[3], sizeof(deftype));
|
|
default_lookups = ISC_FALSE;
|
|
}
|
|
} else if (strncasecmp(opt, "querytype=", 10) == 0) {
|
|
if (testtype(&opt[10])) {
|
|
strlcpy(deftype, &opt[10], sizeof(deftype));
|
|
default_lookups = ISC_FALSE;
|
|
}
|
|
} else if (strncasecmp(opt, "query=", 6) == 0) {
|
|
if (testtype(&opt[6])) {
|
|
strlcpy(deftype, &opt[6], sizeof(deftype));
|
|
default_lookups = ISC_FALSE;
|
|
}
|
|
} else if (strncasecmp(opt, "qu=", 3) == 0) {
|
|
if (testtype(&opt[3])) {
|
|
strlcpy(deftype, &opt[3], sizeof(deftype));
|
|
default_lookups = ISC_FALSE;
|
|
}
|
|
} else if (strncasecmp(opt, "q=", 2) == 0) {
|
|
if (testtype(&opt[2])) {
|
|
strlcpy(deftype, &opt[2], sizeof(deftype));
|
|
default_lookups = ISC_FALSE;
|
|
}
|
|
} else if (strncasecmp(opt, "domain=", 7) == 0) {
|
|
strlcpy(domainopt, &opt[7], sizeof(domainopt));
|
|
set_search_domain(domainopt);
|
|
usesearch = ISC_TRUE;
|
|
} else if (strncasecmp(opt, "do=", 3) == 0) {
|
|
strlcpy(domainopt, &opt[3], sizeof(domainopt));
|
|
set_search_domain(domainopt);
|
|
usesearch = ISC_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 = ISC_TRUE;
|
|
} else if (CHECKOPT("norecurse", 5)) {
|
|
recurse = ISC_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 = ISC_TRUE;
|
|
} else if (CHECKOPT("nodefname", 5)) {
|
|
usesearch = ISC_FALSE;
|
|
} else if (CHECKOPT("vc", 2) == 0) {
|
|
tcpmode = ISC_TRUE;
|
|
tcpmode_set = ISC_TRUE;
|
|
} else if (CHECKOPT("novc", 4) == 0) {
|
|
tcpmode = ISC_FALSE;
|
|
tcpmode_set = ISC_TRUE;
|
|
} else if (CHECKOPT("debug", 3) == 0) {
|
|
short_form = ISC_FALSE;
|
|
showsearch = ISC_TRUE;
|
|
} else if (CHECKOPT("nodebug", 5) == 0) {
|
|
short_form = ISC_TRUE;
|
|
showsearch = ISC_FALSE;
|
|
} else if (CHECKOPT("d2", 2) == 0) {
|
|
debugging = ISC_TRUE;
|
|
} else if (CHECKOPT("nod2", 4) == 0) {
|
|
debugging = ISC_FALSE;
|
|
} else if (CHECKOPT("search", 3) == 0) {
|
|
usesearch = ISC_TRUE;
|
|
} else if (CHECKOPT("nosearch", 5) == 0) {
|
|
usesearch = ISC_FALSE;
|
|
} else if (CHECKOPT("sil", 3) == 0) {
|
|
/* deprecation_msg = ISC_FALSE; */
|
|
} else if (CHECKOPT("fail", 3) == 0) {
|
|
nofail=ISC_FALSE;
|
|
} else if (CHECKOPT("nofail", 5) == 0) {
|
|
nofail=ISC_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 = ISC_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, lookup->ip6_int, ISC_TRUE)
|
|
== ISC_R_SUCCESS) {
|
|
strlcpy(lookup->textname, store, sizeof(lookup->textname));
|
|
lookup->rdtype = dns_rdatatype_ptr;
|
|
lookup->rdtypeset = ISC_TRUE;
|
|
} else {
|
|
strlcpy(lookup->textname, opt, sizeof(lookup->textname));
|
|
lookup->rdtype = rdtype;
|
|
lookup->rdtypeset = ISC_TRUE;
|
|
}
|
|
lookup->rdclass = rdclass;
|
|
lookup->rdclassset = ISC_TRUE;
|
|
lookup->trace = ISC_FALSE;
|
|
lookup->trace_root = lookup->trace;
|
|
lookup->ns_search_only = ISC_FALSE;
|
|
lookup->identify = identify;
|
|
lookup->recurse = recurse;
|
|
lookup->aaonly = aaonly;
|
|
lookup->retries = tries;
|
|
lookup->udpsize = 0;
|
|
lookup->comments = comments;
|
|
if (lookup->rdtype == dns_rdatatype_any && !tcpmode_set)
|
|
lookup->tcp_mode = ISC_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 = ISC_TRUE;
|
|
if (nofail)
|
|
lookup->servfail_stops = ISC_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;
|
|
|
|
ptr = next_token(&input, " \t\r\n");
|
|
if (ptr == NULL)
|
|
return;
|
|
arg = next_token(&input, " \t\r\n");
|
|
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 = ISC_FALSE;
|
|
isc_app_unblock();
|
|
show_settings(ISC_TRUE, ISC_TRUE);
|
|
} else if (strcasecmp(ptr, "exit") == 0) {
|
|
in_use = ISC_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 *buf;
|
|
char *ptr;
|
|
|
|
fflush(stdout);
|
|
buf = isc_mem_allocate(mctx, COMMSIZE);
|
|
if (buf == NULL)
|
|
fatal("memory allocation failure");
|
|
isc_app_block();
|
|
if (interactive) {
|
|
#ifdef HAVE_READLINE
|
|
ptr = readline("> ");
|
|
if (ptr != NULL)
|
|
add_history(ptr);
|
|
#else
|
|
fputs("> ", stderr);
|
|
fflush(stderr);
|
|
ptr = fgets(buf, COMMSIZE, stdin);
|
|
#endif
|
|
} else
|
|
ptr = fgets(buf, COMMSIZE, stdin);
|
|
isc_app_unblock();
|
|
if (ptr == NULL) {
|
|
in_use = ISC_FALSE;
|
|
} else
|
|
do_next_command(ptr);
|
|
#ifdef HAVE_READLINE
|
|
if (interactive)
|
|
free(ptr);
|
|
#endif
|
|
isc_mem_free(mctx, buf);
|
|
}
|
|
|
|
static void
|
|
parse_args(int argc, char **argv) {
|
|
isc_boolean_t have_lookup = ISC_FALSE;
|
|
|
|
usesearch = ISC_TRUE;
|
|
for (argc--, argv++; argc > 0; 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 = ISC_TRUE;
|
|
} else {
|
|
if (!have_lookup) {
|
|
have_lookup = ISC_TRUE;
|
|
in_use = ISC_TRUE;
|
|
addlookup(argv[0]);
|
|
} else {
|
|
set_nameserver(argv[0]);
|
|
check_ra = ISC_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
flush_lookup_list(void) {
|
|
dig_lookup_t *l, *lp;
|
|
dig_query_t *q, *qp;
|
|
dig_server_t *s, *sp;
|
|
|
|
lookup_counter = 0;
|
|
l = ISC_LIST_HEAD(lookup_list);
|
|
while (l != NULL) {
|
|
q = ISC_LIST_HEAD(l->q);
|
|
while (q != NULL) {
|
|
if (q->sock != NULL) {
|
|
isc_socket_cancel(q->sock, NULL,
|
|
ISC_SOCKCANCEL_ALL);
|
|
isc_socket_detach(&q->sock);
|
|
}
|
|
if (ISC_LINK_LINKED(&q->recvbuf, link))
|
|
ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
|
|
link);
|
|
if (ISC_LINK_LINKED(&q->lengthbuf, link))
|
|
ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
|
|
link);
|
|
isc_buffer_invalidate(&q->recvbuf);
|
|
isc_buffer_invalidate(&q->lengthbuf);
|
|
qp = q;
|
|
q = ISC_LIST_NEXT(q, link);
|
|
ISC_LIST_DEQUEUE(l->q, qp, link);
|
|
isc_mem_free(mctx, qp);
|
|
}
|
|
s = ISC_LIST_HEAD(l->my_server_list);
|
|
while (s != NULL) {
|
|
sp = s;
|
|
s = ISC_LIST_NEXT(s, link);
|
|
ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
|
|
isc_mem_free(mctx, sp);
|
|
|
|
}
|
|
if (l->sendmsg != NULL)
|
|
dns_message_destroy(&l->sendmsg);
|
|
lp = l;
|
|
l = ISC_LIST_NEXT(l, link);
|
|
ISC_LIST_DEQUEUE(lookup_list, lp, link);
|
|
isc_mem_free(mctx, lp);
|
|
}
|
|
}
|
|
|
|
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 = ISC_TF(isatty(0));
|
|
|
|
ISC_LIST_INIT(lookup_list);
|
|
ISC_LIST_INIT(server_list);
|
|
ISC_LIST_INIT(search_list);
|
|
|
|
check_ra = ISC_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(ISC_FALSE, ISC_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 = ISC_TF(!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);
|
|
}
|