summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bind/lib/dns/resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bind/lib/dns/resolver.c')
-rw-r--r--usr.sbin/bind/lib/dns/resolver.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/usr.sbin/bind/lib/dns/resolver.c b/usr.sbin/bind/lib/dns/resolver.c
index b5950dd726e..76f6f85c748 100644
--- a/usr.sbin/bind/lib/dns/resolver.c
+++ b/usr.sbin/bind/lib/dns/resolver.c
@@ -35,6 +35,7 @@
#include <dns/ncache.h>
#include <dns/peer.h>
#include <dns/rdata.h>
+#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
@@ -291,6 +292,80 @@ static isc_result_t ncache_adderesult(dns_message_t *message,
dns_rdataset_t *ardataset,
isc_result_t *eresultp);
+static isc_boolean_t
+fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
+ dns_name_t *name;
+ dns_name_t *domain = &fctx->domain;
+ dns_rdataset_t *rdataset;
+ dns_rdatatype_t type;
+ isc_result_t result;
+ isc_boolean_t keep_auth = ISC_FALSE;
+
+ if (message->rcode == dns_rcode_nxdomain)
+ return (ISC_FALSE);
+
+ /*
+ * Look for BIND 8 style delegations.
+ * Also look for answers to ANY queries where the duplicate NS RRset
+ * may have been stripped from the authority section.
+ */
+ if (message->counts[DNS_SECTION_ANSWER] != 0 &&
+ (fctx->type == dns_rdatatype_ns ||
+ fctx->type == dns_rdatatype_any)) {
+ result = dns_message_firstname(message, DNS_SECTION_ANSWER);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_ANSWER,
+ &name);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ type = rdataset->type;
+ if (type != dns_rdatatype_ns)
+ continue;
+ if (dns_name_issubdomain(name, domain))
+ return (ISC_FALSE);
+ }
+ result = dns_message_nextname(message,
+ DNS_SECTION_ANSWER);
+ }
+ }
+
+ /* Look for referral. */
+ if (message->counts[DNS_SECTION_AUTHORITY] == 0)
+ goto munge;
+
+ result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ type = rdataset->type;
+ if (type == dns_rdatatype_soa &&
+ dns_name_equal(name, domain))
+ keep_auth = ISC_TRUE;
+ if (type != dns_rdatatype_ns &&
+ type != dns_rdatatype_soa)
+ continue;
+ if (dns_name_equal(name, domain))
+ goto munge;
+ if (dns_name_issubdomain(name, domain))
+ return (ISC_FALSE);
+ }
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+ }
+
+ munge:
+ message->rcode = dns_rcode_nxdomain;
+ message->counts[DNS_SECTION_ANSWER] = 0;
+ if (!keep_auth)
+ message->counts[DNS_SECTION_AUTHORITY] = 0;
+ message->counts[DNS_SECTION_ADDITIONAL] = 0;
+ return (ISC_TRUE);
+}
+
static inline isc_result_t
fctx_starttimer(fetchctx_t *fctx) {
/*
@@ -4376,6 +4451,34 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
}
/*
+ * Enforce delegations only zones like NET and COM.
+ */
+ if (!ISFORWARDER(query->addrinfo) &&
+ dns_view_isdelegationonly(fctx->res->view, &fctx->domain) &&
+ !dns_name_equal(&fctx->domain, &fctx->name) &&
+ fix_mustbedelegationornxdomain(message, fctx)) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char domainbuf[DNS_NAME_FORMATSIZE];
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ char classbuf[64];
+ char typebuf[64];
+
+ dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+ dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+ dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
+ dns_rdataclass_format(fctx->res->rdclass, classbuf,
+ sizeof(classbuf));
+ isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
+ sizeof(addrbuf));
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "enforced delegation-only for '%s' (%s/%s/%s) "
+ "from %s",
+ domainbuf, namebuf, typebuf, classbuf, addrbuf);
+ }
+
+ /*
* Did we get any answers?
*/
if (message->counts[DNS_SECTION_ANSWER] > 0 &&