diff options
Diffstat (limited to 'usr.sbin/bind/lib/dns/resolver.c')
| -rw-r--r-- | usr.sbin/bind/lib/dns/resolver.c | 103 |
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 && |
