summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/dns/resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/dns/resolver.c')
-rw-r--r--contrib/bind9/lib/dns/resolver.c460
1 files changed, 323 insertions, 137 deletions
diff --git a/contrib/bind9/lib/dns/resolver.c b/contrib/bind9/lib/dns/resolver.c
index 503f1d2..e21d97e 100644
--- a/contrib/bind9/lib/dns/resolver.c
+++ b/contrib/bind9/lib/dns/resolver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -21,6 +21,7 @@
#include <config.h>
+#include <isc/log.h>
#include <isc/platform.h>
#include <isc/print.h>
#include <isc/string.h>
@@ -42,6 +43,8 @@
#include <dns/log.h>
#include <dns/message.h>
#include <dns/ncache.h>
+#include <dns/nsec.h>
+#include <dns/nsec3.h>
#include <dns/opcode.h>
#include <dns/peer.h>
#include <dns/rbt.h>
@@ -75,7 +78,7 @@
DNS_LOGCATEGORY_RESOLVER, \
DNS_LOGMODULE_RESOLVER, \
ISC_LOG_DEBUG(3), \
- "fctx %p(%s'): %s", fctx, fctx->info, (m))
+ "fctx %p(%s): %s", fctx, fctx->info, (m))
#define FCTXTRACE2(m1, m2) \
isc_log_write(dns_lctx, \
DNS_LOGCATEGORY_RESOLVER, \
@@ -130,6 +133,7 @@
* Maximum EDNS0 input packet size.
*/
#define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */
+#define EDNSOPTS 2
/*%
* This defines the maximum number of timeouts we will permit before we
@@ -468,12 +472,16 @@ static isc_result_t ncache_adderesult(dns_message_t *message,
dns_rdatatype_t covers,
isc_stdtime_t now, dns_ttl_t maxttl,
isc_boolean_t optout,
+ isc_boolean_t secure,
dns_rdataset_t *ardataset,
isc_result_t *eresultp);
static void validated(isc_task_t *task, isc_event_t *event);
static isc_boolean_t maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked);
static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
isc_result_t reason, badnstype_t badtype);
+static inline isc_result_t findnoqname(fetchctx_t *fctx, dns_name_t *name,
+ dns_rdatatype_t type,
+ dns_name_t **noqname);
/*%
* Increment resolver-related statistics counters.
@@ -1270,67 +1278,15 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
static inline isc_result_t
fctx_addopt(dns_message_t *message, unsigned int version,
- isc_uint16_t udpsize, isc_boolean_t request_nsid)
+ isc_uint16_t udpsize, dns_ednsopt_t *ednsopts, size_t count)
{
- dns_rdataset_t *rdataset;
- dns_rdatalist_t *rdatalist;
- dns_rdata_t *rdata;
+ dns_rdataset_t *rdataset = NULL;
isc_result_t result;
- rdatalist = NULL;
- result = dns_message_gettemprdatalist(message, &rdatalist);
- if (result != ISC_R_SUCCESS)
- return (result);
- rdata = NULL;
- result = dns_message_gettemprdata(message, &rdata);
- if (result != ISC_R_SUCCESS)
- return (result);
- rdataset = NULL;
- result = dns_message_gettemprdataset(message, &rdataset);
+ result = dns_message_buildopt(message, &rdataset, version, udpsize,
+ DNS_MESSAGEEXTFLAG_DO, ednsopts, count);
if (result != ISC_R_SUCCESS)
return (result);
- dns_rdataset_init(rdataset);
-
- rdatalist->type = dns_rdatatype_opt;
- rdatalist->covers = 0;
-
- /*
- * Set Maximum UDP buffer size.
- */
- rdatalist->rdclass = udpsize;
-
- /*
- * Set EXTENDED-RCODE and Z to 0, DO to 1.
- */
- rdatalist->ttl = (version << 16);
- rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO;
-
- /*
- * Set EDNS options if applicable
- */
- if (request_nsid) {
- /* Send empty NSID option (RFC5001) */
- unsigned char data[4];
- isc_buffer_t buf;
-
- isc_buffer_init(&buf, data, sizeof(data));
- isc_buffer_putuint16(&buf, DNS_OPT_NSID);
- isc_buffer_putuint16(&buf, 0);
- rdata->data = data;
- rdata->length = sizeof(data);
- } else {
- rdata->data = NULL;
- rdata->length = 0;
- }
-
- rdata->rdclass = rdatalist->rdclass;
- rdata->type = rdatalist->type;
- rdata->flags = 0;
-
- ISC_LIST_INIT(rdatalist->rdata);
- ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
- RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
-
return (dns_message_setopt(message, rdataset));
}
@@ -1710,6 +1666,8 @@ resquery_send(resquery_t *query) {
isc_boolean_t cleanup_cctx = ISC_FALSE;
isc_boolean_t secure_domain;
isc_boolean_t connecting = ISC_FALSE;
+ dns_ednsopt_t ednsopts[EDNSOPTS];
+ unsigned ednsopt = 0;
fctx = query->fctx;
QTRACE("send");
@@ -1892,8 +1850,15 @@ resquery_send(resquery_t *query) {
/* request NSID for current view or peer? */
if (peer != NULL)
(void) dns_peer_getrequestnsid(peer, &reqnsid);
+ if (reqnsid) {
+ INSIST(ednsopt < EDNSOPTS);
+ ednsopts[ednsopt].code = DNS_OPT_NSID;
+ ednsopts[ednsopt].length = 0;
+ ednsopts[ednsopt].value = NULL;
+ ednsopt++;
+ }
result = fctx_addopt(fctx->qmessage, version,
- udpsize, reqnsid);
+ udpsize, ednsopts, ednsopt);
if (reqnsid && result == ISC_R_SUCCESS) {
query->options |= DNS_FETCHOPT_WANTNSID;
} else if (result != ISC_R_SUCCESS) {
@@ -2478,7 +2443,7 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
isc_result_t result;
res = fctx->res;
- unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0);
+ unshared = ISC_TF((fctx->options & DNS_FETCHOPT_UNSHARED) != 0);
/*
* If this name is a subdomain of the query domain, tell
* the ADB to start looking using zone/hint data. This keeps us
@@ -4227,7 +4192,7 @@ validated(isc_task_t *task, isc_event_t *event) {
result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
covers, now, ttl, vevent->optout,
- ardataset, &eresult);
+ vevent->secure, ardataset, &eresult);
if (result != ISC_R_SUCCESS)
goto noanswer_response;
goto answer_response;
@@ -4237,7 +4202,6 @@ validated(isc_task_t *task, isc_event_t *event) {
FCTXTRACE("validation OK");
if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) {
-
result = dns_rdataset_addnoqname(vevent->rdataset,
vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -4248,6 +4212,18 @@ validated(isc_task_t *task, isc_event_t *event) {
vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER]);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
+ } else if (vevent->rdataset->trust == dns_trust_answer &&
+ vevent->rdataset->type != dns_rdatatype_rrsig)
+ {
+ isc_result_t tresult;
+ dns_name_t *noqname = NULL;
+ tresult = findnoqname(fctx, vevent->name,
+ vevent->rdataset->type, &noqname);
+ if (tresult == ISC_R_SUCCESS && noqname != NULL) {
+ tresult = dns_rdataset_addnoqname(vevent->rdataset,
+ noqname);
+ RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
+ }
}
/*
@@ -4367,6 +4343,14 @@ validated(isc_task_t *task, isc_event_t *event) {
fctx->attributes |= FCTX_ATTR_HAVEANSWER;
if (hevent != NULL) {
+ /*
+ * Negative results must be indicated in event->result.
+ */
+ if (dns_rdataset_isassociated(hevent->rdataset) &&
+ NEGATIVE(hevent->rdataset)) {
+ INSIST(eresult == DNS_R_NCACHENXDOMAIN ||
+ eresult == DNS_R_NCACHENXRRSET);
+ }
hevent->result = eresult;
RUNTIME_CHECK(dns_name_copy(vevent->name,
dns_fixedname_name(&hevent->foundname), NULL)
@@ -4388,6 +4372,149 @@ validated(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
}
+static void
+fctx_log(void *arg, int level, const char *fmt, ...) {
+ char msgbuf[2048];
+ va_list args;
+ fetchctx_t *fctx = arg;
+
+ va_start(args, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+ va_end(args);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, level,
+ "fctx %p(%s): %s", fctx, fctx->info, msgbuf);
+}
+
+static inline isc_result_t
+findnoqname(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
+ dns_name_t **noqnamep)
+{
+ dns_rdataset_t *nrdataset, *next, *sigrdataset;
+ dns_rdata_rrsig_t rrsig;
+ isc_result_t result;
+ unsigned int labels;
+ dns_section_t section;
+ dns_name_t *zonename;
+ dns_fixedname_t fzonename;
+ dns_name_t *closest;
+ dns_fixedname_t fclosest;
+ dns_name_t *nearest;
+ dns_fixedname_t fnearest;
+ dns_rdatatype_t found = dns_rdatatype_none;
+ dns_name_t *noqname = NULL;
+
+ FCTXTRACE("findnoqname");
+
+ REQUIRE(noqnamep != NULL && *noqnamep == NULL);
+
+ /*
+ * Find the SIG for this rdataset, if we have it.
+ */
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == type)
+ break;
+ }
+
+ if (sigrdataset == NULL)
+ return (ISC_R_NOTFOUND);
+
+ labels = dns_name_countlabels(name);
+
+ for (result = dns_rdataset_first(sigrdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(sigrdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(sigrdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ /* Wildcard has rrsig.labels < labels - 1. */
+ if (rrsig.labels + 1U >= labels)
+ continue;
+ break;
+ }
+
+ if (result == ISC_R_NOMORE)
+ return (ISC_R_NOTFOUND);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_fixedname_init(&fzonename);
+ zonename = dns_fixedname_name(&fzonename);
+ dns_fixedname_init(&fclosest);
+ closest = dns_fixedname_name(&fclosest);
+ dns_fixedname_init(&fnearest);
+ nearest = dns_fixedname_name(&fnearest);
+
+#define NXND(x) ((x) == ISC_R_SUCCESS)
+
+ section = DNS_SECTION_AUTHORITY;
+ for (result = dns_message_firstname(fctx->rmessage, section);
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(fctx->rmessage, section)) {
+ dns_name_t *nsec = NULL;
+ dns_message_currentname(fctx->rmessage, section, &nsec);
+ for (nrdataset = ISC_LIST_HEAD(nsec->list);
+ nrdataset != NULL; nrdataset = next) {
+ isc_boolean_t data = ISC_FALSE, exists = ISC_FALSE;
+ isc_boolean_t optout = ISC_FALSE, unknown = ISC_FALSE;
+ isc_boolean_t setclosest = ISC_FALSE;
+ isc_boolean_t setnearest = ISC_FALSE;
+
+ next = ISC_LIST_NEXT(nrdataset, link);
+ if (nrdataset->type != dns_rdatatype_nsec &&
+ nrdataset->type != dns_rdatatype_nsec3)
+ continue;
+
+ if (nrdataset->type == dns_rdatatype_nsec &&
+ NXND(dns_nsec_noexistnodata(type, name, nsec,
+ nrdataset, &exists,
+ &data, NULL, fctx_log,
+ fctx)))
+ {
+ if (!exists) {
+ noqname = nsec;
+ found = dns_rdatatype_nsec;
+ }
+ }
+
+ if (nrdataset->type == dns_rdatatype_nsec3 &&
+ NXND(dns_nsec3_noexistnodata(type, name, nsec,
+ nrdataset, zonename,
+ &exists, &data,
+ &optout, &unknown,
+ &setclosest,
+ &setnearest,
+ closest, nearest,
+ fctx_log, fctx)))
+ {
+ if (!exists && setnearest) {
+ noqname = nsec;
+ found = dns_rdatatype_nsec3;
+ }
+ }
+ }
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ if (noqname != NULL) {
+ for (sigrdataset = ISC_LIST_HEAD(noqname->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == found)
+ break;
+ }
+ if (sigrdataset != NULL)
+ *noqnamep = noqname;
+ }
+ return (result);
+}
+
static inline isc_result_t
cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
isc_stdtime_t now)
@@ -4521,6 +4648,17 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
rdataset->ttl = res->view->maxcachettl;
/*
+ * Find the SIG for this rdataset, if we have it.
+ */
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == rdataset->type)
+ break;
+ }
+
+ /*
* If this RRset is in a secure domain, is in bailiwick,
* and is not glue, attempt DNSSEC validation. (We do not
* attempt to validate glue or out-of-bailiwick data--even
@@ -4540,16 +4678,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
*/
if (rdataset->type == dns_rdatatype_rrsig)
continue;
- /*
- * Find the SIG for this rdataset, if we have it.
- */
- for (sigrdataset = ISC_LIST_HEAD(name->list);
- sigrdataset != NULL;
- sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
- if (sigrdataset->type == dns_rdatatype_rrsig &&
- sigrdataset->covers == rdataset->type)
- break;
- }
+
if (sigrdataset == NULL) {
if (!ANSWER(rdataset) && need_validation) {
/*
@@ -4583,6 +4712,22 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
if (sigrdataset != NULL)
sigrdataset->trust = trust;
if (!need_validation || !ANSWER(rdataset)) {
+ if (ANSWER(rdataset) &&
+ rdataset->type != dns_rdatatype_rrsig) {
+ isc_result_t tresult;
+ dns_name_t *noqname = NULL;
+ tresult = findnoqname(fctx, name,
+ rdataset->type,
+ &noqname);
+ if (tresult == ISC_R_SUCCESS &&
+ noqname != NULL) {
+ tresult =
+ dns_rdataset_addnoqname(
+ rdataset, noqname);
+ RUNTIME_CHECK(tresult ==
+ ISC_R_SUCCESS);
+ }
+ }
addedrdataset = ardataset;
result = dns_db_addrdataset(fctx->cache, node,
NULL, now, rdataset,
@@ -4710,6 +4855,21 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
options = DNS_DBADD_FORCE;
} else
options = 0;
+
+ if (ANSWER(rdataset) &&
+ rdataset->type != dns_rdatatype_rrsig) {
+ isc_result_t tresult;
+ dns_name_t *noqname = NULL;
+ tresult = findnoqname(fctx, name,
+ rdataset->type, &noqname);
+ if (tresult == ISC_R_SUCCESS &&
+ noqname != NULL) {
+ tresult = dns_rdataset_addnoqname(
+ rdataset, noqname);
+ RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
+ }
+ }
+
/*
* Now we can add the rdataset.
*/
@@ -4718,6 +4878,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
rdataset,
options,
addedrdataset);
+
if (result == DNS_R_UNCHANGED) {
if (ANSWER(rdataset) &&
ardataset != NULL &&
@@ -4813,8 +4974,8 @@ cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now)
static isc_result_t
ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
- isc_boolean_t optout, dns_rdataset_t *ardataset,
- isc_result_t *eresultp)
+ isc_boolean_t optout, isc_boolean_t secure,
+ dns_rdataset_t *ardataset, isc_result_t *eresultp)
{
isc_result_t result;
dns_rdataset_t rdataset;
@@ -4823,8 +4984,12 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdataset_init(&rdataset);
ardataset = &rdataset;
}
- result = dns_ncache_addoptout(message, cache, node, covers, now,
- maxttl, optout, ardataset);
+ if (secure)
+ result = dns_ncache_addoptout(message, cache, node, covers,
+ now, maxttl, optout, ardataset);
+ else
+ result = dns_ncache_add(message, cache, node, covers, now,
+ maxttl, ardataset);
if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
/*
* If the cache now contains a negative entry and we
@@ -4991,7 +5156,7 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
covers, now, ttl, ISC_FALSE,
- ardataset, &eresult);
+ ISC_FALSE, ardataset, &eresult);
if (result != ISC_R_SUCCESS)
goto unlock;
@@ -5387,10 +5552,10 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
{
isc_result_t result;
dns_message_t *message;
- dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name;
+ dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name, *save_name;
dns_rdataset_t *rdataset, *ns_rdataset;
isc_boolean_t aa, negative_response;
- dns_rdatatype_t type;
+ dns_rdatatype_t type, save_type;
dns_section_t section;
FCTXTRACE("noanswer_response");
@@ -5457,6 +5622,8 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
ns_rdataset = NULL;
soa_name = NULL;
ds_name = NULL;
+ save_name = NULL;
+ save_type = dns_rdatatype_none;
result = dns_message_firstname(message, section);
while (result == ISC_R_SUCCESS) {
name = NULL;
@@ -5655,6 +5822,9 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
dns_trust_additional;
}
}
+ } else {
+ save_name = name;
+ save_type = ISC_LIST_HEAD(name->list)->type;
}
result = dns_message_nextname(message, section);
if (result == ISC_R_NOMORE)
@@ -5690,7 +5860,27 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
/*
* The responder is insane.
*/
- log_formerr(fctx, "invalid response");
+ if (save_name == NULL) {
+ log_formerr(fctx, "invalid response");
+ return (DNS_R_FORMERR);
+ }
+ if (!dns_name_issubdomain(save_name, &fctx->domain)) {
+ char nbuf[DNS_NAME_FORMATSIZE];
+ char dbuf[DNS_NAME_FORMATSIZE];
+ char tbuf[DNS_RDATATYPE_FORMATSIZE];
+
+ dns_rdatatype_format(save_type, tbuf,
+ sizeof(tbuf));
+ dns_name_format(save_name, nbuf, sizeof(nbuf));
+ dns_name_format(&fctx->domain, dbuf,
+ sizeof(dbuf));
+
+ log_formerr(fctx, "Name %s (%s) not subdomain"
+ " of zone %s -- invalid response",
+ nbuf, tbuf, dbuf);
+ } else {
+ log_formerr(fctx, "invalid response");
+ }
return (DNS_R_FORMERR);
}
}
@@ -5899,12 +6089,12 @@ answer_response(fetchctx_t *fctx) {
* but we found a CNAME.
*
* Getting a CNAME response for some
- * query types is an error.
+ * query types is an error, see
+ * RFC 4035, Section 2.5.
*/
if (type == dns_rdatatype_rrsig ||
- type == dns_rdatatype_dnskey ||
- type == dns_rdatatype_nsec ||
- type == dns_rdatatype_nsec3) {
+ type == dns_rdatatype_key ||
+ type == dns_rdatatype_nsec) {
char buf[DNS_RDATATYPE_FORMATSIZE];
dns_rdatatype_format(fctx->type,
buf, sizeof(buf));
@@ -6449,44 +6639,24 @@ checknames(dns_message_t *message) {
/*
* Log server NSID at log level 'level'
*/
-static isc_result_t
-log_nsid(dns_rdataset_t *opt, resquery_t *query, int level, isc_mem_t *mctx)
+static void
+log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query,
+ int level, isc_mem_t *mctx)
{
static const char hex[17] = "0123456789abcdef";
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
- isc_uint16_t optcode, nsid_len, buflen, i;
- isc_result_t result;
- isc_buffer_t nsidbuf;
- dns_rdata_t rdata;
+ isc_uint16_t buflen, i;
unsigned char *p, *buf, *nsid;
- /* Extract rdata from OPT rdataset */
- result = dns_rdataset_first(opt);
- if (result != ISC_R_SUCCESS)
- return (ISC_R_FAILURE);
-
- dns_rdata_init(&rdata);
- dns_rdataset_current(opt, &rdata);
- if (rdata.length < 4)
- return (ISC_R_FAILURE);
-
- /* Check for NSID */
- isc_buffer_init(&nsidbuf, rdata.data, rdata.length);
- isc_buffer_add(&nsidbuf, rdata.length);
- optcode = isc_buffer_getuint16(&nsidbuf);
- nsid_len = isc_buffer_getuint16(&nsidbuf);
- if (optcode != DNS_OPT_NSID || nsid_len == 0)
- return (ISC_R_FAILURE);
-
/* Allocate buffer for storing hex version of the NSID */
buflen = nsid_len * 2 + 1;
buf = isc_mem_get(mctx, buflen);
if (buf == NULL)
- return (ISC_R_NOSPACE);
+ return;
/* Convert to hex */
p = buf;
- nsid = rdata.data + 4;
+ nsid = isc_buffer_current(opt);
for (i = 0; i < nsid_len; i++) {
*p++ = hex[(nsid[0] >> 4) & 0xf];
*p++ = hex[nsid[0] & 0xf];
@@ -6502,7 +6672,7 @@ log_nsid(dns_rdataset_t *opt, resquery_t *query, int level, isc_mem_t *mctx)
/* Clean up */
isc_mem_put(mctx, buf, buflen);
- return (ISC_R_SUCCESS);
+ return;
}
static void
@@ -6576,6 +6746,41 @@ betterreferral(fetchctx_t *fctx) {
}
static void
+process_opt(resquery_t *query, dns_rdataset_t *opt) {
+ dns_rdata_t rdata;
+ isc_buffer_t optbuf;
+ isc_result_t result;
+ isc_uint16_t optcode;
+ isc_uint16_t optlen;
+
+ result = dns_rdataset_first(opt);
+ if (result == ISC_R_SUCCESS) {
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(opt, &rdata);
+ isc_buffer_init(&optbuf, rdata.data, rdata.length);
+ isc_buffer_add(&optbuf, rdata.length);
+ while (isc_buffer_remaininglength(&optbuf) >= 4) {
+ optcode = isc_buffer_getuint16(&optbuf);
+ optlen = isc_buffer_getuint16(&optbuf);
+ INSIST(optlen <= isc_buffer_remaininglength(&optbuf));
+ switch (optcode) {
+ case DNS_OPT_NSID:
+ if (query->options & DNS_FETCHOPT_WANTNSID)
+ log_nsid(&optbuf, optlen, query,
+ ISC_LOG_INFO,
+ query->fctx->res->mctx);
+ isc_buffer_forward(&optbuf, optlen);
+ break;
+ default:
+ isc_buffer_forward(&optbuf, optlen);
+ break;
+ }
+ }
+ INSIST(isc_buffer_remaininglength(&optbuf) == 0U);
+ }
+}
+
+static void
resquery_response(isc_task_t *task, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS;
resquery_t *query = event->ev_arg;
@@ -6650,13 +6855,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
options |= DNS_FETCHOPT_NOEDNS0;
resend = ISC_TRUE;
- /*
- * Remember that they don't like EDNS0.
- */
- dns_adb_changeflags(fctx->adb,
- query->addrinfo,
- DNS_FETCHOPT_NOEDNS0,
- DNS_FETCHOPT_NOEDNS0);
+ add_bad_edns(fctx, &query->addrinfo->sockaddr);
} else {
/*
* There's no hope for this query.
@@ -6723,14 +6922,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
options |= DNS_FETCHOPT_NOEDNS0;
resend = ISC_TRUE;
- /*
- * Remember that they don't like EDNS0.
- */
- dns_adb_changeflags(
- fctx->adb,
- query->addrinfo,
- DNS_FETCHOPT_NOEDNS0,
- DNS_FETCHOPT_NOEDNS0);
+ add_bad_edns(fctx,
+ &query->addrinfo->sockaddr);
inc_stats(fctx->res,
dns_resstatscounter_edns0fail);
} else {
@@ -6754,13 +6947,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
options |= DNS_FETCHOPT_NOEDNS0;
resend = ISC_TRUE;
- /*
- * Remember that they don't like EDNS0.
- */
- dns_adb_changeflags(fctx->adb,
- query->addrinfo,
- DNS_FETCHOPT_NOEDNS0,
- DNS_FETCHOPT_NOEDNS0);
+ add_bad_edns(fctx, &query->addrinfo->sockaddr);
inc_stats(fctx->res,
dns_resstatscounter_edns0fail);
} else {
@@ -6783,12 +6970,11 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx);
/*
- * Did we request NSID? If so, and if the response contains
- * NSID data, log it at INFO level.
+ * Process receive opt record.
*/
opt = dns_message_getopt(message);
- if (opt != NULL && (query->options & DNS_FETCHOPT_WANTNSID) != 0)
- log_nsid(opt, query, ISC_LOG_INFO, fctx->res->mctx);
+ if (opt != NULL)
+ process_opt(query, opt);
/*
* If the message is signed, check the signature. If not, this
OpenPOWER on IntegriCloud