diff --git a/bin/named/config.c b/bin/named/config.c index 6a8fc599fb..e93ad273ed 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -177,6 +177,7 @@ options {\n\ query-source address *;\n\ query-source-v6 address *;\n\ recursion true;\n\ + reject-000-label yes;\n\ request-expire true;\n\ request-ixfr true;\n\ require-server-cookie no;\n\ diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst index f02d52d425..6c1ec9b260 100644 --- a/bin/named/named.conf.rst +++ b/bin/named/named.conf.rst @@ -388,6 +388,7 @@ OPTIONS recursing-file quoted_string; recursion boolean; recursive-clients integer; + reject-000-label boolean;// deprecated request-expire boolean; request-ixfr boolean; request-nsid boolean; @@ -793,6 +794,7 @@ VIEW window integer; }; recursion boolean; + reject-000-label boolean;// deprecated request-expire boolean; request-ixfr boolean; request-nsid boolean; diff --git a/bin/named/server.c b/bin/named/server.c index 852d7dbf54..f7db73faf9 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -4456,6 +4456,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, INSIST(result == ISC_R_SUCCESS); view->acceptexpired = cfg_obj_asboolean(obj); + obj = NULL; + result = named_config_get(maps, "reject-000-label", &obj); + INSIST(result == ISC_R_SUCCESS); + view->reject_000_label = cfg_obj_asboolean(obj); + obj = NULL; /* 'optionmaps', not 'maps': don't check named_g_defaults yet */ (void)named_config_get(optionmaps, "dnssec-validation", &obj); diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 279ae583d3..97f4e92594 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -2100,6 +2100,16 @@ Boolean Options default is ``no``. Setting this option to ``yes`` leaves ``named`` vulnerable to replay attacks. +``reject-000-label`` + This can be used to control whether NSEC records which have the + ``next`` field starting with the ``\\000`` label are cached for + ``synth-from-dnssec``. There are a number of DNSSEC implementations + that generate bad NSEC type maps where the ``next`` field starts with + the ``\\000`` label and between BIND 9.18 and BIND 9.20 there will be + a campaign to get these servers corrected. In BIND 9.18 this defaults + to ``yes``. In BIND 9.20 (BIND 9.19) this will default to ``no`` and + in BIND 9.22 (BIND 9.21) this option will be removed. + ``querylog`` Query logging provides a complete log of all incoming queries and all query errors. This provides more insight into the server's activity, but with a @@ -2247,6 +2257,16 @@ Boolean Options named caching broken NSEC records from negative responses from servers that emit broken NSEC records with missing types that actually exist. + ``reject-000-label`` can be used to control whether NSEC records + which have the ``next`` field starting with the ``\\000`` label + are cached for ``synth-from-dnssec``. There are a number of + DNSSEC implementations that generate bad NSEC type maps where + the ``next`` field starts with the ``\\000`` label and between + BIND 9.18 and BIND 9.20 there will be a campaign to get these + servers corrected. In BIND 9.18 this defaults to ``yes``. In + BIND 9.20 (BIND 9.19) this will default to ``no`` and in BIND 9.22 + (BIND 9.21) this option will be removed. + .. note:: DNSSEC validation must be enabled for this option to be effective. This initial implementation only covers synthesis of answers from NSEC records; synthesis from NSEC3 is planned for the future. This diff --git a/doc/man/named.conf.5in b/doc/man/named.conf.5in index 52c1da4f40..ebfc33e975 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -455,6 +455,7 @@ options { recursing\-file quoted_string; recursion boolean; recursive\-clients integer; + reject\-000\-label boolean;// deprecated request\-expire boolean; request\-ixfr boolean; request\-nsid boolean; @@ -896,6 +897,7 @@ view string [ class ] { window integer; }; recursion boolean; + reject\-000\-label boolean;// deprecated request\-expire boolean; request\-ixfr boolean; request\-nsid boolean; diff --git a/doc/misc/options b/doc/misc/options index 52485fd338..f015f926a0 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -313,6 +313,7 @@ options { recursing-file ; recursion ; recursive-clients ; + reject-000-label ; // deprecated request-expire ; request-ixfr ; request-nsid ; @@ -673,6 +674,7 @@ view [ ] { window ; }; recursion ; + reject-000-label ; // deprecated request-expire ; request-ixfr ; request-nsid ; diff --git a/doc/misc/options.active b/doc/misc/options.active index 68aafb9ec9..882c247348 100644 --- a/doc/misc/options.active +++ b/doc/misc/options.active @@ -311,6 +311,7 @@ options { recursing-file ; recursion ; recursive-clients ; + reject-000-label ; // deprecated request-expire ; request-ixfr ; request-nsid ; @@ -669,6 +670,7 @@ view [ ] { window ; }; recursion ; + reject-000-label ; // deprecated request-expire ; request-ixfr ; request-nsid ; diff --git a/doc/misc/options.grammar.rst b/doc/misc/options.grammar.rst index 8e69a09686..862461f690 100644 --- a/doc/misc/options.grammar.rst +++ b/doc/misc/options.grammar.rst @@ -231,6 +231,7 @@ recursing-file ; recursion ; recursive-clients ; + reject-000-label ; // deprecated request-expire ; request-ixfr ; request-nsid ; diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index f1ec93877f..43deee1039 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -130,6 +130,7 @@ struct dns_view { bool synthfromdnssec; bool trust_anchor_telemetry; bool root_key_sentinel; + bool reject_000_label; dns_transfer_format_t transfer_format; dns_acl_t *cacheacl; dns_acl_t *cacheonacl; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index e8b17aae19..64fe5d0b58 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -5210,6 +5210,32 @@ check_soa_and_dnskey(dns_rdataset_t *nsecset) { return (true); } +/* + * Look for NSEC next name that starts with the label '\000'. + */ +static bool +has_000_label(dns_rdataset_t *nsecset) { + dns_rdataset_t rdataset; + isc_result_t result; + + dns_rdataset_init(&rdataset); + dns_rdataset_clone(nsecset, &rdataset); + + for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); + if (rdata.length > 1 && rdata.data[0] == 1 && + rdata.data[1] == 0) { + dns_rdataset_disassociate(&rdataset); + return (true); + } + } + dns_rdataset_disassociate(&rdataset); + return (false); +} + /* * The validator has finished. */ @@ -5645,6 +5671,17 @@ answer_response: !check_soa_and_dnskey(rdataset)) { continue; } + + /* + * Look for \000 label in next name. + */ + if (rdataset->type == dns_rdatatype_nsec && + fctx->res->view->reject_000_label && + has_000_label(rdataset)) + { + continue; + } + result = dns_db_findnode(fctx->cache, name, true, &nsnode); if (result != ISC_R_SUCCESS) { diff --git a/lib/dns/view.c b/lib/dns/view.c index de5464f288..5b6ef54388 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -240,6 +240,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name, view->synthfromdnssec = true; view->trust_anchor_telemetry = true; view->root_key_sentinel = true; + view->reject_000_label = true; view->new_zone_dir = NULL; view->new_zone_file = NULL; view->new_zone_db = NULL; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index ee0f3091f3..bf53b119d6 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -2118,6 +2118,7 @@ static cfg_clausedef_t view_clauses[] = { { "queryport-pool-updateinterval", NULL, CFG_CLAUSEFLAG_ANCIENT }, { "rate-limit", &cfg_type_rrl, 0 }, { "recursion", &cfg_type_boolean, 0 }, + { "reject-000-label", &cfg_type_boolean, CFG_CLAUSEFLAG_DEPRECATED }, { "request-nsid", &cfg_type_boolean, 0 }, { "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT }, { "require-server-cookie", &cfg_type_boolean, 0 },