From 83561799536ff7792d25e78b41e56f8be48d28e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 14 Nov 2024 11:18:00 +0100 Subject: [PATCH 01/15] Rename the qpzone and qpcache methods that implement DB api All the database implementations share the same names for the methods implementing the database. That has some advantages like knowing what to expect, but it turns out that any time such method shows up in any kind of tracing - be it perf record, backtrace or anything else that uses symbol names, it is very hard to distinguish whether the find() belongs to qpcache, qpzone, builtin or sdlz implementation. Make at least the names for qpzone and qpcache unique. --- lib/dns/qpcache.c | 82 +++++++++++++++++++----------------- lib/dns/qpzone.c | 105 ++++++++++++++++++++++++---------------------- 2 files changed, 99 insertions(+), 88 deletions(-) diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index aadfaf2bb8..5781e6b96f 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -1530,10 +1530,11 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name, } static isc_result_t -find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, - dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, - dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { +qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, + dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset DNS__DB_FLARG) { qpcnode_t *node = NULL; isc_result_t result; qpc_search_t search; @@ -1975,10 +1976,11 @@ tree_exit: } static isc_result_t -findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, - isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, - dns_name_t *dcname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { +qpcache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, + isc_stdtime_t now, dns_dbnode_t **nodep, + dns_name_t *foundname, dns_name_t *dcname, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset DNS__DB_FLARG) { qpcnode_t *node = NULL; isc_rwlock_t *lock = NULL; isc_result_t result; @@ -2150,10 +2152,10 @@ tree_exit: } static isc_result_t -findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now, - dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { +qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdatatype_t type, dns_rdatatype_t covers, + isc_stdtime_t now, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset DNS__DB_FLARG) { qpcache_t *qpdb = (qpcache_t *)db; qpcnode_t *qpnode = (qpcnode_t *)node; dns_slabheader_t *header = NULL, *header_next = NULL; @@ -2552,7 +2554,7 @@ free_qpdb(qpcache_t *qpdb, bool log) { } static void -qpdb_destroy(dns_db_t *arg) { +qpcache_destroy(dns_db_t *arg) { qpcache_t *qpdb = (qpcache_t *)arg; bool want_free = false; unsigned int i; @@ -2680,8 +2682,8 @@ new_qpcnode(qpcache_t *qpdb, const dns_name_t *name) { } static isc_result_t -findnode(dns_db_t *db, const dns_name_t *name, bool create, - dns_dbnode_t **nodep DNS__DB_FLARG) { +qpcache_findnode(dns_db_t *db, const dns_name_t *name, bool create, + dns_dbnode_t **nodep DNS__DB_FLARG) { qpcache_t *qpdb = (qpcache_t *)db; qpcnode_t *node = NULL; isc_result_t result; @@ -2716,8 +2718,8 @@ unlock: } static void -attachnode(dns_db_t *db, dns_dbnode_t *source, - dns_dbnode_t **targetp DNS__DB_FLARG) { +qpcache_attachnode(dns_db_t *db, dns_dbnode_t *source, + dns_dbnode_t **targetp DNS__DB_FLARG) { REQUIRE(VALID_QPDB((qpcache_t *)db)); REQUIRE(targetp != NULL && *targetp == NULL); @@ -2731,7 +2733,7 @@ attachnode(dns_db_t *db, dns_dbnode_t *source, } static void -detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) { +qpcache_detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) { qpcache_t *qpdb = (qpcache_t *)db; qpcnode_t *node = NULL; bool want_free = false; @@ -2786,8 +2788,8 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) { } static isc_result_t -createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED, - dns_dbiterator_t **iteratorp) { +qpcache_createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED, + dns_dbiterator_t **iteratorp) { qpcache_t *qpdb = (qpcache_t *)db; qpc_dbit_t *qpdbiter = NULL; @@ -2809,9 +2811,9 @@ createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED, } static isc_result_t -allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - unsigned int options, isc_stdtime_t now, - dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { +qpcache_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + unsigned int options, isc_stdtime_t now, + dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { qpcache_t *qpdb = (qpcache_t *)db; qpcnode_t *qpnode = (qpcnode_t *)node; qpc_rditer_t *iterator = NULL; @@ -3386,9 +3388,10 @@ expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum, isc_stdtime_t now, bool cache_is_overmem DNS__DB_FLARG); static isc_result_t -addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, - dns_rdataset_t *addedrdataset DNS__DB_FLARG) { +qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + isc_stdtime_t now, dns_rdataset_t *rdataset, + unsigned int options, + dns_rdataset_t *addedrdataset DNS__DB_FLARG) { qpcache_t *qpdb = (qpcache_t *)db; qpcnode_t *qpnode = (qpcnode_t *)node; isc_region_t region; @@ -3569,8 +3572,9 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } static isc_result_t -deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) { +qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, dns_rdatatype_t type, + dns_rdatatype_t covers DNS__DB_FLARG) { qpcache_t *qpdb = (qpcache_t *)db; qpcnode_t *qpnode = (qpcnode_t *)node; isc_result_t result; @@ -4378,17 +4382,17 @@ setmaxtypepername(dns_db_t *db, uint32_t value) { } static dns_dbmethods_t qpdb_cachemethods = { - .destroy = qpdb_destroy, - .findnode = findnode, - .find = find, - .findzonecut = findzonecut, - .attachnode = attachnode, - .detachnode = detachnode, - .createiterator = createiterator, - .findrdataset = findrdataset, - .allrdatasets = allrdatasets, - .addrdataset = addrdataset, - .deleterdataset = deleterdataset, + .destroy = qpcache_destroy, + .findnode = qpcache_findnode, + .find = qpcache_find, + .findzonecut = qpcache_findzonecut, + .attachnode = qpcache_attachnode, + .detachnode = qpcache_detachnode, + .createiterator = qpcache_createiterator, + .findrdataset = qpcache_findrdataset, + .allrdatasets = qpcache_allrdatasets, + .addrdataset = qpcache_addrdataset, + .deleterdataset = qpcache_deleterdataset, .nodecount = nodecount, .getoriginnode = getoriginnode, .getrrsetstats = getrrsetstats, diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 875c39920f..7847d260f1 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -1545,10 +1545,11 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, } static isc_result_t -findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, - dns_rdatatype_t type, dns_rdatatype_t covers, - isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { +qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, + dns_dbversion_t *dbversion, dns_rdatatype_t type, + dns_rdatatype_t covers, isc_stdtime_t now ISC_ATTR_UNUSED, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = (qpznode_t *)dbnode; dns_slabheader_t *header = NULL, *header_next = NULL; @@ -2546,8 +2547,8 @@ findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create, } static isc_result_t -findnode(dns_db_t *db, const dns_name_t *name, bool create, - dns_dbnode_t **nodep DNS__DB_FLARG) { +qpzone_findnode(dns_db_t *db, const dns_name_t *name, bool create, + dns_dbnode_t **nodep DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; REQUIRE(VALID_QPZONE(qpdb)); @@ -2557,8 +2558,8 @@ findnode(dns_db_t *db, const dns_name_t *name, bool create, } static isc_result_t -findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, - dns_dbnode_t **nodep DNS__DB_FLARG) { +qpzone_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, + dns_dbnode_t **nodep DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; REQUIRE(VALID_QPZONE(qpdb)); @@ -2606,9 +2607,9 @@ matchparams(dns_slabheader_t *header, qpz_search_t *search) { } static isc_result_t -setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep, - dns_name_t *foundname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { +qpzone_setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep, + dns_name_t *foundname, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset DNS__DB_FLARG) { dns_name_t *zcname = NULL; dns_typepair_t type; qpznode_t *node = NULL; @@ -3202,7 +3203,7 @@ again: } static isc_result_t -check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { +qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { qpz_search_t *search = arg; dns_slabheader_t *header = NULL, *header_next = NULL; dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL; @@ -3329,11 +3330,11 @@ check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { } static isc_result_t -find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, - dns_rdatatype_t type, unsigned int options, - isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep, - dns_name_t *foundname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset DNS__DB_FLARG) { +qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, + dns_rdatatype_t type, unsigned int options, + isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep, + dns_name_t *foundname, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset DNS__DB_FLARG) { isc_result_t result; qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = NULL; @@ -3403,7 +3404,7 @@ find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, isc_result_t tresult; dns_qpchain_node(&search.chain, i, NULL, (void **)&n, NULL); - tresult = check_zonecut(n, &search DNS__DB_FLARG_PASS); + tresult = qpzone_check_zonecut(n, &search DNS__DB_FLARG_PASS); if (tresult != DNS_R_CONTINUE) { result = tresult; search.chain.len = i - 1; @@ -3415,7 +3416,7 @@ find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, if (result == DNS_R_PARTIALMATCH) { partial_match: if (search.zonecut != NULL) { - result = setup_delegation( + result = qpzone_setup_delegation( &search, nodep, foundname, rdataset, sigrdataset DNS__DB_FLARG_PASS); goto tree_exit; @@ -3705,7 +3706,7 @@ found: * Return the delegation. */ NODE_UNLOCK(lock, &nlocktype); - result = setup_delegation( + result = qpzone_setup_delegation( &search, nodep, foundname, rdataset, sigrdataset DNS__DB_FLARG_PASS); goto tree_exit; @@ -3853,9 +3854,10 @@ tree_exit: } static isc_result_t -allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, - unsigned int options, isc_stdtime_t now ISC_ATTR_UNUSED, - dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { +qpzone_allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode, + dns_dbversion_t *dbversion, unsigned int options, + isc_stdtime_t now ISC_ATTR_UNUSED, + dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = (qpznode_t *)dbnode; qpz_version_t *version = (qpz_version_t *)dbversion; @@ -4589,8 +4591,8 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) { } static isc_result_t -createiterator(dns_db_t *db, unsigned int options, - dns_dbiterator_t **iteratorp) { +qpzone_createiterator(dns_db_t *db, unsigned int options, + dns_dbiterator_t **iteratorp) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpdb_dbiterator_t *iter = NULL; @@ -4628,9 +4630,11 @@ createiterator(dns_db_t *db, unsigned int options, } static isc_result_t -addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, - isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset, - unsigned int options, dns_rdataset_t *addedrdataset DNS__DB_FLARG) { +qpzone_addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, + dns_dbversion_t *dbversion, + isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset, + unsigned int options, + dns_rdataset_t *addedrdataset DNS__DB_FLARG) { isc_result_t result; qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = (qpznode_t *)dbnode; @@ -4757,9 +4761,10 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, } static isc_result_t -subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, - dns_rdataset_t *rdataset, unsigned int options, - dns_rdataset_t *newrdataset DNS__DB_FLARG) { +qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, + dns_dbversion_t *dbversion, dns_rdataset_t *rdataset, + unsigned int options, + dns_rdataset_t *newrdataset DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = (qpznode_t *)dbnode; qpz_version_t *version = (qpz_version_t *)dbversion; @@ -4948,8 +4953,9 @@ unlock: } static isc_result_t -deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion, - dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) { +qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, + dns_dbversion_t *dbversion, dns_rdatatype_t type, + dns_rdatatype_t covers DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = (qpznode_t *)dbnode; qpz_version_t *version = (qpz_version_t *)dbversion; @@ -5061,9 +5067,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, dns_rdataset_init(&rdataset_aaaa); dns_rdataset_init(&sigrdataset_aaaa); - result = find(ctx->db, name, ctx->version, dns_rdatatype_a, - DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, name_a, - &rdataset_a, &sigrdataset_a DNS__DB_FLARG_PASS); + result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_a, + DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, + name_a, &rdataset_a, + &sigrdataset_a DNS__DB_FLARG_PASS); if (result == DNS_R_GLUE) { glue = new_glue(ctx->db->mctx, name_a); @@ -5079,10 +5086,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, } } - result = find(ctx->db, name, ctx->version, dns_rdatatype_aaaa, - DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa, - name_aaaa, &rdataset_aaaa, - &sigrdataset_aaaa DNS__DB_FLARG_PASS); + result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_aaaa, + DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa, + name_aaaa, &rdataset_aaaa, + &sigrdataset_aaaa DNS__DB_FLARG_PASS); if (result == DNS_R_GLUE) { if (glue == NULL) { glue = new_glue(ctx->db->mctx, name_aaaa); @@ -5348,22 +5355,22 @@ static dns_dbmethods_t qpdb_zonemethods = { .newversion = newversion, .attachversion = attachversion, .closeversion = closeversion, - .findnode = findnode, - .find = find, + .findnode = qpzone_findnode, + .find = qpzone_find, .attachnode = attachnode, .detachnode = detachnode, - .createiterator = createiterator, - .findrdataset = findrdataset, - .allrdatasets = allrdatasets, - .addrdataset = addrdataset, - .subtractrdataset = subtractrdataset, - .deleterdataset = deleterdataset, + .createiterator = qpzone_createiterator, + .findrdataset = qpzone_findrdataset, + .allrdatasets = qpzone_allrdatasets, + .addrdataset = qpzone_addrdataset, + .subtractrdataset = qpzone_subtractrdataset, + .deleterdataset = qpzone_deleterdataset, .issecure = issecure, .nodecount = nodecount, .setloop = setloop, .getoriginnode = getoriginnode, .getnsec3parameters = getnsec3parameters, - .findnsec3node = findnsec3node, + .findnsec3node = qpzone_findnsec3node, .setsigningtime = setsigningtime, .getsigningtime = getsigningtime, .getsize = getsize, From e51d4d3b88af00d6667f2055087ebfc47fb3107c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 7 Jan 2025 15:22:40 +0100 Subject: [PATCH 02/15] Isolate using the -T noaa flag only for part of the resolver test Instead of running the whole resolver/ns4 server with -T noaa flag, use it only for the part where it is actually needed. The -T noaa could interfere with other parts of the test because the answers don't have the authoritative-answer bit set, and we could have false positives (or false negatives) in the test because the authoritative server doesn't follow the DNS protocol for all the tests in the resolver system test. --- bin/tests/system/resolver/ns4/named.noaa | 12 ------------ bin/tests/system/resolver/tests.sh | 8 ++++++++ 2 files changed, 8 insertions(+), 12 deletions(-) delete mode 100644 bin/tests/system/resolver/ns4/named.noaa diff --git a/bin/tests/system/resolver/ns4/named.noaa b/bin/tests/system/resolver/ns4/named.noaa deleted file mode 100644 index be78cc2c94..0000000000 --- a/bin/tests/system/resolver/ns4/named.noaa +++ /dev/null @@ -1,12 +0,0 @@ -Copyright (C) Internet Systems Consortium, Inc. ("ISC") - -SPDX-License-Identifier: MPL-2.0 - -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 https://mozilla.org/MPL/2.0/. - -See the COPYRIGHT file distributed with this work for additional -information regarding copyright ownership. - -Add -T noaa. diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh index ab94c17c10..026fd60c9f 100755 --- a/bin/tests/system/resolver/tests.sh +++ b/bin/tests/system/resolver/tests.sh @@ -221,6 +221,10 @@ done if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) +stop_server ns4 +touch ns4/named.noaa +start_server --noclean --restart --port ${PORT} ns4 || ret=1 + n=$((n + 1)) echo_i "RT21594 regression test check setup ($n)" ret=0 @@ -257,6 +261,10 @@ grep "status: NXDOMAIN" dig.ns5.out.${n} >/dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) +stop_server ns4 +rm ns4/named.noaa +start_server --noclean --restart --port ${PORT} ns4 || ret=1 + n=$((n + 1)) echo_i "check that replacement of additional data by a negative cache no data entry clears the additional RRSIGs ($n)" ret=0 From a1982cf1bb95c818aa7b58988b5611dec80f2408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 14 Nov 2024 10:37:29 +0100 Subject: [PATCH 03/15] Limit the additional processing for large RDATA sets Limit the number of records appended to ADDITIONAL section to the names that have less than 14 records in the RDATA. This limits the number of the lookups into the database(s) during single client query. Also don't append any additional data to ANY queries. The answer to ANY is already big enough. --- lib/dns/include/dns/rdataset.h | 10 +++++++++- lib/dns/qpzone.c | 2 +- lib/dns/rdataset.c | 7 ++++++- lib/dns/resolver.c | 17 ++++++++++------- lib/ns/query.c | 5 +++-- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index ae835b961d..89518b0ebf 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -53,6 +53,8 @@ #include #include +#define DNS_RDATASET_MAXADDITIONAL 13 + /* Fixed RRSet helper macros */ #define DNS_RDATASET_LENGTH 2; @@ -503,7 +505,8 @@ dns_rdataset_towirepartial(dns_rdataset_t *rdataset, isc_result_t dns_rdataset_additionaldata(dns_rdataset_t *rdataset, const dns_name_t *owner_name, - dns_additionaldatafunc_t add, void *arg); + dns_additionaldatafunc_t add, void *arg, + size_t limit); /*%< * For each rdata in rdataset, call 'add' for each name and type in the * rdata which is subject to additional section processing. @@ -522,10 +525,15 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset, *\li If a call to dns_rdata_additionaldata() is not successful, the * result returned will be the result of dns_rdataset_additionaldata(). * + *\li If the 'limit' is non-zero and the number of the rdatasets is larger + * than the 'limit', no additional data will be generated. + * * Returns: * *\li #ISC_R_SUCCESS * + *\li #DNS_R_TOOMANYRECORDS in case rdataset count is larger than 'limit' + * *\li Any error that dns_rdata_additionaldata() can return. */ diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 7847d260f1..fadc3bc9c2 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -5261,7 +5261,7 @@ create_gluelist(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node, */ (void)dns_rdataset_additionaldata(rdataset, dns_rootname, - glue_nsdname_cb, &ctx); + glue_nsdname_cb, &ctx, 0); CMM_STORE_SHARED(gluelist->glue, ctx.glue); diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index b09ff3cf29..dc6fc4d867 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -479,7 +479,8 @@ dns_rdataset_towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name, isc_result_t dns_rdataset_additionaldata(dns_rdataset_t *rdataset, const dns_name_t *owner_name, - dns_additionaldatafunc_t add, void *arg) { + dns_additionaldatafunc_t add, void *arg, + size_t limit) { dns_rdata_t rdata = DNS_RDATA_INIT; isc_result_t result; @@ -491,6 +492,10 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset, REQUIRE(DNS_RDATASET_VALID(rdataset)); REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0); + if (limit != 0 && dns_rdataset_count(rdataset) > limit) { + return DNS_R_TOOMANYRECORDS; + } + result = dns_rdataset_first(rdataset); if (result != ISC_R_SUCCESS) { return result; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 70900c4cc0..6497582bea 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -8576,9 +8576,6 @@ rctx_answer_any(respctx_t *rctx) { rdataset->attributes |= DNS_RDATASETATTR_ANSWER; rdataset->attributes |= DNS_RDATASETATTR_CACHE; rdataset->trust = rctx->trust; - - (void)dns_rdataset_additionaldata(rdataset, rctx->aname, - check_related, rctx); } return ISC_R_SUCCESS; @@ -8626,7 +8623,8 @@ rctx_answer_match(respctx_t *rctx) { rctx->ardataset->attributes |= DNS_RDATASETATTR_CACHE; rctx->ardataset->trust = rctx->trust; (void)dns_rdataset_additionaldata(rctx->ardataset, rctx->aname, - check_related, rctx); + check_related, rctx, + DNS_RDATASET_MAXADDITIONAL); for (sigrdataset = ISC_LIST_HEAD(rctx->aname->list); sigrdataset != NULL; @@ -8833,7 +8831,8 @@ rctx_authority_positive(respctx_t *rctx) { */ (void)dns_rdataset_additionaldata( rdataset, name, check_related, - rctx); + rctx, + DNS_RDATASET_MAXADDITIONAL); done = true; } } @@ -9340,8 +9339,11 @@ rctx_referral(respctx_t *rctx) { */ INSIST(rctx->ns_rdataset != NULL); FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING); + /* + * We want to append **all** the GLUE records here. + */ (void)dns_rdataset_additionaldata(rctx->ns_rdataset, rctx->ns_name, - check_related, rctx); + check_related, rctx, 0); #if CHECK_FOR_GLUE_IN_ANSWER /* * Look in the answer section for "glue" that is incorrectly @@ -9456,7 +9458,8 @@ again: if (CHASE(rdataset)) { rdataset->attributes &= ~DNS_RDATASETATTR_CHASE; (void)dns_rdataset_additionaldata( - rdataset, name, check_related, rctx); + rdataset, name, check_related, rctx, + DNS_RDATASET_MAXADDITIONAL); rescan = true; } } diff --git a/lib/ns/query.c b/lib/ns/query.c index 8464e782d9..9757a25622 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -2143,7 +2143,8 @@ addname: if (trdataset != NULL && dns_rdatatype_followadditional(type)) { if (client->additionaldepth++ < client->view->max_restarts) { eresult = dns_rdataset_additionaldata( - trdataset, fname, query_additional_cb, qctx); + trdataset, fname, query_additional_cb, qctx, + DNS_RDATASET_MAXADDITIONAL); } client->additionaldepth--; } @@ -2240,7 +2241,7 @@ regular: * We don't care if dns_rdataset_additionaldata() fails. */ (void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb, - qctx); + qctx, DNS_RDATASET_MAXADDITIONAL); CTRACE(ISC_LOG_DEBUG(3), "query_additional: done"); } From 9846f395ad79bb50a5fa5ca6ab97ef904b3be35a Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Thu, 4 Jul 2024 14:58:10 +0300 Subject: [PATCH 04/15] DoH: process data chunk by chunk instead of all at once Initially, our DNS-over-HTTP(S) implementation would try to process as much incoming data from the network as possible. However, that might be undesirable as we might create too many streams (each effectively backed by a ns_client_t object). That is too forgiving as it might overwhelm the server and trash its memory allocator, causing high CPU and memory usage. Instead of doing that, we resort to processing incoming data using a chunk-by-chunk processing strategy. That is, we split data into small chunks (currently 256 bytes) and process each of them asynchronously. However, we can process more than one chunk at once (up to 4 currently), given that the number of HTTP/2 streams has not increased while processing a chunk. That alone is not enough, though. In addition to the above, we should limit the number of active streams: these streams for which we have received a request and started processing it (the ones for which a read callback was called), as it is perfectly fine to have more opened streams than active ones. In the case we have reached or surpassed the limit of active streams, we stop reading AND processing the data from the remote peer. The number of active streams is effectively decreased only when responses associated with the active streams are sent to the remote peer. Overall, this strategy is very similar to the one used for other stream-based DNS transports like TCP and TLS. --- lib/isc/netmgr/http.c | 325 ++++++++++++++++++++++++++++++++---- lib/isc/netmgr/netmgr-int.h | 1 + 2 files changed, 290 insertions(+), 36 deletions(-) diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 9fd1097f1f..7bf8dbd541 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -85,6 +85,21 @@ #define INITIAL_DNS_MESSAGE_BUFFER_SIZE (512) +/* + * The value should be small enough to not allow a server to open too + * many streams at once. It should not be too small either because + * the incoming data will be split into too many chunks with each of + * them processed asynchronously. + */ +#define INCOMING_DATA_CHUNK_SIZE (256) + +/* + * Often processing a chunk does not change the number of streams. In + * that case we can process more than once, but we still should have a + * hard limit on that. + */ +#define INCOMING_DATA_MAX_CHUNKS_AT_ONCE (4) + typedef struct isc_nm_http_response_status { size_t code; size_t content_length; @@ -155,6 +170,15 @@ struct isc_nm_http_session { isc__nm_http_pending_callbacks_t pending_write_callbacks; isc_buffer_t *pending_write_data; + + /* + * The statistical values below are for usage on server-side + * only. They are meant to detect clients that are taking too many + * resources from the server. + */ + uint64_t received; /* How many requests have been received. */ + uint64_t submitted; /* How many responses were submitted to send */ + uint64_t processed; /* How many responses were processed. */ }; typedef enum isc_http_error_responses { @@ -177,6 +201,7 @@ typedef struct isc_http_send_req { void *cbarg; isc_buffer_t *pending_write_data; isc__nm_http_pending_callbacks_t pending_write_callbacks; + uint64_t submitted; } isc_http_send_req_t; #define HTTP_ENDPOINTS_MAGIC ISC_MAGIC('H', 'T', 'E', 'P') @@ -189,10 +214,20 @@ static bool http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle, isc_nm_cb_t cb, void *cbarg); +static ssize_t +http_process_input_data(isc_nm_http_session_t *session, + isc_buffer_t *input_data); + +static inline bool +http_too_many_active_streams(isc_nm_http_session_t *session); + static void http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, isc_nm_cb_t send_cb, void *send_cbarg); +static void +http_do_bio_async(isc_nm_http_session_t *session); + static void failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result, isc_nm_http_session_t *session); @@ -502,6 +537,15 @@ finish_http_session(isc_nm_http_session_t *session) { isc_nmhandle_close(session->handle); } + /* + * Free any unprocessed incoming data in order to not process + * it during indirect calls to http_do_bio() that might happen + * when calling the failed callbacks. + */ + if (session->buf != NULL) { + isc_buffer_free(&session->buf); + } + if (session->client) { client_call_failed_read_cb(ISC_R_UNEXPECTED, session); } else { @@ -664,6 +708,9 @@ on_server_stream_close_callback(int32_t stream_id, ISC_LIST_UNLINK(session->sstreams, sock->h2, link); session->nsstreams--; + if (sock->h2->request_received) { + session->submitted++; + } /* * By making a call to isc__nmsocket_prep_destroy(), we ensure that @@ -975,6 +1022,103 @@ client_submit_request(isc_nm_http_session_t *session, http_cstream_t *stream) { return ISC_R_SUCCESS; } +static ssize_t +http_process_input_data(isc_nm_http_session_t *session, + isc_buffer_t *input_data) { + ssize_t readlen = 0; + ssize_t processed = 0; + isc_region_t chunk = { 0 }; + size_t before, after; + size_t i; + + REQUIRE(VALID_HTTP2_SESSION(session)); + REQUIRE(input_data != NULL); + + if (!http_session_active(session)) { + return 0; + } + + /* + * For clients that initiate request themselves just process + * everything. + */ + if (session->client) { + isc_buffer_remainingregion(input_data, &chunk); + if (chunk.length == 0) { + return 0; + } + + readlen = nghttp2_session_mem_recv(session->ngsession, + chunk.base, chunk.length); + + if (readlen >= 0) { + isc_buffer_forward(input_data, readlen); + } + + return readlen; + } + + /* + * If no streams are created during processing, we might process + * more than one chunk at a time. Still we should not overdo that + * to avoid processing too much data at once as such behaviour is + * known for trashing the memory allocator at times. + */ + for (before = after = session->nsstreams, i = 0; + after <= before && i < INCOMING_DATA_MAX_CHUNKS_AT_ONCE; + after = session->nsstreams, i++) + { + const uint64_t active_streams = + (session->received - session->processed); + + /* + * If there are non completed send requests in flight -let's + * not process any incoming data, as it could lead to piling + * up too much send data in send buffers. With many clients + * connected it can lead to excessive memory consumption on + * the server instance. + */ + if (session->sending > 0) { + break; + } + + /* + * If we have reached the maximum number of streams used, we + * might stop processing for now, as nghttp2 will happily + * consume as much data as possible. + */ + if (session->nsstreams >= session->max_concurrent_streams && + active_streams > 0) + { + break; + } + + if (http_too_many_active_streams(session)) { + break; + } + + isc_buffer_remainingregion(input_data, &chunk); + if (chunk.length == 0) { + break; + } + + chunk.length = ISC_MIN(chunk.length, INCOMING_DATA_CHUNK_SIZE); + + readlen = nghttp2_session_mem_recv(session->ngsession, + chunk.base, chunk.length); + + if (readlen >= 0) { + isc_buffer_forward(input_data, readlen); + processed += readlen; + } else { + isc_buffer_clear(input_data); + return readlen; + } + } + + return processed; +} + /* * Read callback from TLS socket. */ @@ -984,6 +1128,7 @@ http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result, isc_nm_http_session_t *session = (isc_nm_http_session_t *)data; isc_nm_http_session_t *tmpsess = NULL; ssize_t readlen; + isc_buffer_t input; REQUIRE(VALID_HTTP2_SESSION(session)); @@ -1001,8 +1146,10 @@ http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result, goto done; } - readlen = nghttp2_session_mem_recv(session->ngsession, region->base, - region->length); + isc_buffer_init(&input, region->base, region->length); + isc_buffer_add(&input, region->length); + + readlen = http_process_input_data(session, &input); if (readlen < 0) { failed_read_cb(ISC_R_UNEXPECTED, session); goto done; @@ -1017,11 +1164,12 @@ http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result, isc_buffer_putmem(session->buf, region->base + readlen, unread_size); isc_nm_read_stop(session->handle); + http_do_bio_async(session); + } else { + /* We might have something to receive or send, do IO */ + http_do_bio(session, NULL, NULL, NULL); } - /* We might have something to receive or send, do IO */ - http_do_bio(session, NULL, NULL, NULL); - done: isc__nm_httpsession_detach(&tmpsess); } @@ -1059,14 +1207,18 @@ http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) { } isc_buffer_free(&req->pending_write_data); + session->processed += req->submitted; isc_mem_put(session->mctx, req, sizeof(*req)); session->sending--; - http_do_bio(session, NULL, NULL, NULL); - isc_nmhandle_detach(&transphandle); - if (result != ISC_R_SUCCESS && session->sending == 0) { + + if (result == ISC_R_SUCCESS) { + http_do_bio(session, NULL, NULL, NULL); + } else { finish_http_session(session); } + isc_nmhandle_detach(&transphandle); + isc__nm_httpsession_detach(&session); } @@ -1227,7 +1379,9 @@ http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle, *send = (isc_http_send_req_t){ .pending_write_data = session->pending_write_data, .cb = cb, - .cbarg = cbarg }; + .cbarg = cbarg, + .submitted = session->submitted }; + session->submitted = 0; session->pending_write_data = NULL; move_pending_send_callbacks(session, send); @@ -1249,6 +1403,28 @@ nothing_to_send: return false; } +static inline bool +http_too_many_active_streams(isc_nm_http_session_t *session) { + const uint64_t active_streams = session->received - session->processed; + const uint64_t max_active_streams = + ISC_MIN(ISC_NETMGR_MAX_STREAM_CLIENTS_PER_CONN, + session->max_concurrent_streams); + + if (session->client) { + return false; + } + + /* + * Do not process incoming data if there are too many active DNS + * clients (streams) per connection. + */ + if (active_streams >= max_active_streams) { + return true; + } + + return false; +} + static void http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, isc_nm_cb_t send_cb, void *send_cbarg) { @@ -1264,41 +1440,80 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, finish_http_session(session); } return; - } else if (nghttp2_session_want_read(session->ngsession) == 0 && - nghttp2_session_want_write(session->ngsession) == 0 && - session->pending_write_data == NULL) - { - session->closing = true; + } + + if (send_cb != NULL) { + INSIST(VALID_NMHANDLE(send_httphandle)); + (void)http_send_outgoing(session, send_httphandle, send_cb, + send_cbarg); + return; + } + + INSIST(send_httphandle == NULL); + INSIST(send_cb == NULL); + INSIST(send_cbarg == NULL); + + if (session->pending_write_data != NULL && session->sending == 0) { + (void)http_send_outgoing(session, NULL, NULL, NULL); return; } if (nghttp2_session_want_read(session->ngsession) != 0) { if (!session->reading) { - /* We have not yet started - * reading from this handle */ + /* We have not yet started reading from this handle */ isc_nm_read(session->handle, http_readcb, session); session->reading = true; } else if (session->buf != NULL) { size_t remaining = isc_buffer_remaininglength(session->buf); - /* Leftover data in the - * buffer, use it */ - size_t readlen = nghttp2_session_mem_recv( - session->ngsession, - isc_buffer_current(session->buf), remaining); + /* Leftover data in the buffer, use it */ + size_t remaining_after = 0; + ssize_t readlen = 0; + isc_nm_http_session_t *tmpsess = NULL; - if (readlen == remaining) { + /* + * Let's ensure that HTTP/2 session and its associated + * data will not go "out of scope" too early. + */ + isc__nm_httpsession_attach(session, &tmpsess); + + readlen = http_process_input_data(session, + session->buf); + + remaining_after = + isc_buffer_remaininglength(session->buf); + + if (readlen < 0) { + failed_read_cb(ISC_R_UNEXPECTED, session); + } else if ((size_t)readlen == remaining) { isc_buffer_free(&session->buf); + http_do_bio(session, NULL, NULL, NULL); + } else if (remaining_after > 0 && + remaining_after < remaining) + { + /* + * We have processed a part of the data, now + * let's delay processing of whatever is left + * here. We want it to be an async operation so + * that we will: + * + * a) let other things run; + * b) have finer grained control over how much + * data is processed at once, because nghttp2 + * would happily consume as much data we pass to + * it and that could overwhelm the server. + */ + http_do_bio_async(session); } else { - isc_buffer_forward(session->buf, readlen); + (void)http_send_outgoing(session, NULL, NULL, + NULL); } - http_do_bio(session, send_httphandle, send_cb, - send_cbarg); + isc__nm_httpsession_detach(&tmpsess); return; } else { - /* Resume reading, it's - * idempotent, wait for more + /* + * Resume reading, it's idempotent, wait for more */ isc_nm_read(session->handle, http_readcb, session); } @@ -1307,20 +1522,54 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, isc_nm_read_stop(session->handle); } - if (send_cb != NULL) { - INSIST(VALID_NMHANDLE(send_httphandle)); - (void)http_send_outgoing(session, send_httphandle, send_cb, - send_cbarg); - } else { - INSIST(send_httphandle == NULL); - INSIST(send_cb == NULL); - INSIST(send_cbarg == NULL); - (void)http_send_outgoing(session, NULL, NULL, NULL); + /* we might have some data to send after processing */ + (void)http_send_outgoing(session, NULL, NULL, NULL); + + if (nghttp2_session_want_read(session->ngsession) == 0 && + nghttp2_session_want_write(session->ngsession) == 0 && + session->pending_write_data == NULL) + { + session->closing = true; + isc_nm_read_stop(session->handle); + if (session->sending == 0) { + finish_http_session(session); + } } return; } +static void +http_do_bio_async_cb(void *arg) { + isc_nm_http_session_t *session = arg; + + REQUIRE(VALID_HTTP2_SESSION(session)); + + if (session->handle != NULL && + !isc__nmsocket_closing(session->handle->sock)) + { + http_do_bio(session, NULL, NULL, NULL); + } + + isc__nm_httpsession_detach(&session); +} + +static void +http_do_bio_async(isc_nm_http_session_t *session) { + isc_nm_http_session_t *tmpsess = NULL; + + REQUIRE(VALID_HTTP2_SESSION(session)); + + if (session->handle == NULL || + isc__nmsocket_closing(session->handle->sock)) + { + return; + } + isc__nm_httpsession_attach(session, &tmpsess); + isc_async_run(session->handle->sock->worker->loop, http_do_bio_async_cb, + tmpsess); +} + static isc_result_t get_http_cstream(isc_nmsocket_t *sock, http_cstream_t **streamp) { http_cstream_t *cstream = sock->h2->connect.cstream; @@ -2091,6 +2340,10 @@ server_call_cb(isc_nmsocket_t *socket, const isc_result_t result, if (result != ISC_R_SUCCESS) { data = NULL; } + if (result == ISC_R_SUCCESS) { + socket->h2->request_received = true; + socket->h2->session->received++; + } socket->h2->cb(handle, result, data, socket->h2->cbarg); isc_nmhandle_detach(&handle); } diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index d790590ec4..e6c6e82830 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -474,6 +474,7 @@ typedef struct isc_nmsocket_h2 { isc_nm_http_endpoints_t *peer_endpoints; + bool request_received; bool response_submitted; struct { char *uri; From 3425e4b1d04746520931e93ac7ef5979fd6b54fd Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Mon, 8 Jul 2024 23:27:29 +0300 Subject: [PATCH 05/15] DoH: floodding clients detection This commit adds logic to make code better protected against clients that send valid HTTP/2 data that is useless from a DNS server perspective. Firstly, it adds logic that protects against clients who send too little useful (=DNS) data. We achieve that by adding a check that eventually detects such clients with a nonfavorable useful to processed data ratio after the initial grace period. The grace period is limited to processing 128 KiB of data, which should be enough for sending the largest possible DNS message in a GET request and then some. This is the main safety belt that would detect even flooding clients that initially behave well in order to fool the checks server. Secondly, in addition to the above, we introduce additional checks to detect outright misbehaving clients earlier: The code will treat clients that open too many streams (50) without sending any data for processing as flooding ones; The clients that managed to send 1.5 KiB of data without opening a single stream or submitting at least some DNS data will be treated as flooding ones. Of course, the behaviour described above is nothing else but heuristical checks, so they can never be perfect. At the same time, they should be reasonable enough not to drop any valid clients, realatively easy to implement, and have negligible computational overhead. --- lib/isc/netmgr/http.c | 115 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 7bf8dbd541..77ddfd59a8 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -100,6 +100,22 @@ */ #define INCOMING_DATA_MAX_CHUNKS_AT_ONCE (4) +/* + * These constants define the grace period to help detect flooding clients. + * + * The first one defines how much data can be processed before opening + * a first stream and received at least some useful (=DNS) data. + * + * The second one defines how much data from a client we read before + * trying to drop a clients who sends not enough useful data. + * + * The third constant defines how many streams we agree to process + * before checking if there was at least one DNS request received. + */ +#define INCOMING_DATA_INITIAL_STREAM_SIZE (1536) +#define INCOMING_DATA_GRACE_SIZE (MAX_ALLOWED_DATA_IN_HEADERS) +#define MAX_STREAMS_BEFORE_FIRST_REQUEST (50) + typedef struct isc_nm_http_response_status { size_t code; size_t content_length; @@ -158,6 +174,7 @@ struct isc_nm_http_session { ISC_LIST(http_cstream_t) cstreams; ISC_LIST(isc_nmsocket_h2_t) sstreams; size_t nsstreams; + uint64_t total_opened_sstreams; isc_nmhandle_t *handle; isc_nmhandle_t *client_httphandle; @@ -179,6 +196,9 @@ struct isc_nm_http_session { uint64_t received; /* How many requests have been received. */ uint64_t submitted; /* How many responses were submitted to send */ uint64_t processed; /* How many responses were processed. */ + + uint64_t processed_incoming_data; + uint64_t processed_useful_data; /* DNS data */ }; typedef enum isc_http_error_responses { @@ -214,6 +234,12 @@ static bool http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle, isc_nm_cb_t cb, void *cbarg); +static void +http_log_flooding_peer(isc_nm_http_session_t *session); + +static bool +http_is_flooding_peer(isc_nm_http_session_t *session); + static ssize_t http_process_input_data(isc_nm_http_session_t *session, isc_buffer_t *input_data); @@ -619,6 +645,7 @@ on_server_data_chunk_recv_callback(int32_t stream_id, const uint8_t *data, if (new_bufsize <= MAX_DNS_MESSAGE_SIZE && new_bufsize <= h2->content_length) { + session->processed_useful_data += len; isc_buffer_putmem(&h2->rbuf, data, len); break; } @@ -1053,6 +1080,7 @@ http_process_input_data(isc_nm_http_session_t *session, if (readlen >= 0) { isc_buffer_forward(input_data, readlen); + session->processed_incoming_data += readlen; } return readlen; @@ -1109,6 +1137,7 @@ http_process_input_data(isc_nm_http_session_t *session, if (readlen >= 0) { isc_buffer_forward(input_data, readlen); + session->processed_incoming_data += readlen; processed += readlen; } else { isc_buffer_clear(input_data); @@ -1119,6 +1148,82 @@ http_process_input_data(isc_nm_http_session_t *session, return processed; } +static void +http_log_flooding_peer(isc_nm_http_session_t *session) { + const int log_level = ISC_LOG_DEBUG(1); + if (session->handle != NULL && isc_log_wouldlog(log_level)) { + char client_sabuf[ISC_SOCKADDR_FORMATSIZE]; + char local_sabuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(&session->handle->sock->peer, client_sabuf, + sizeof(client_sabuf)); + isc_sockaddr_format(&session->handle->sock->iface, local_sabuf, + sizeof(local_sabuf)); + isc__nmsocket_log(session->handle->sock, log_level, + "Dropping a flooding HTTP/2 peer " + "%s (on %s) - processed: %" PRIu64 + " bytes, of them useful: %" PRIu64 "", + client_sabuf, local_sabuf, + session->processed_incoming_data, + session->processed_useful_data); + } +} + +static bool +http_is_flooding_peer(isc_nm_http_session_t *session) { + if (session->client) { + return false; + } + + /* + * A flooding client can try to open a lot of streams before + * submitting a request. Let's drop such clients. + */ + if (session->received == 0 && + session->total_opened_sstreams > MAX_STREAMS_BEFORE_FIRST_REQUEST) + { + return true; + } + + /* + * We have processed enough data to open at least one stream and + * get some useful data. + */ + if (session->processed_incoming_data > + INCOMING_DATA_INITIAL_STREAM_SIZE && + (session->total_opened_sstreams == 0 || + session->processed_useful_data == 0)) + { + return true; + } + + if (session->processed_incoming_data < INCOMING_DATA_GRACE_SIZE) { + return false; + } + + /* + * The overhead of DoH per DNS message can be minimum 160-180 + * bytes. We should allow more for extra information that can be + * included in headers, so let's use 256 bytes. Minimum DNS + * message size is 12 bytes. So, (256+12)/12=22. Even that can be + * too restricting for some edge cases, but should be good enough + * for any practical purposes. Not to mention that HTTP/2 may + * include legitimate data that is completely useless for DNS + * purposes... + * + * Anyway, at that point we should have processed enough requests + * for such clients (if any). + */ + if (session->processed_useful_data == 0 || + (session->processed_incoming_data / + session->processed_useful_data) > 22) + { + return true; + } + + return false; +} + /* * Read callback from TLS socket. */ @@ -1153,6 +1258,10 @@ http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result, if (readlen < 0) { failed_read_cb(ISC_R_UNEXPECTED, session); goto done; + } else if (http_is_flooding_peer(session)) { + http_log_flooding_peer(session); + failed_read_cb(ISC_R_RANGE, session); + goto done; } if ((size_t)readlen < region->length) { @@ -1485,6 +1594,9 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, if (readlen < 0) { failed_read_cb(ISC_R_UNEXPECTED, session); + } else if (http_is_flooding_peer(session)) { + http_log_flooding_peer(session); + failed_read_cb(ISC_R_RANGE, session); } else if ((size_t)readlen == remaining) { isc_buffer_free(&session->buf); http_do_bio(session, NULL, NULL, NULL); @@ -1972,6 +2084,7 @@ server_on_begin_headers_callback(nghttp2_session *ngsession, session->nsstreams++; isc__nm_httpsession_attach(session, &socket->h2->session); ISC_LIST_APPEND(session->sstreams, socket->h2, link); + session->total_opened_sstreams++; nghttp2_session_set_stream_user_data(ngsession, frame->hd.stream_id, socket); @@ -2031,6 +2144,8 @@ server_handle_path_header(isc_nmsocket_t *socket, const uint8_t *value, socket->worker->mctx, dns_value, dns_value_len, &socket->h2->query_data_len); + socket->h2->session->processed_useful_data += + dns_value_len; } else { socket->h2->query_too_large = true; return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE; From 609a41517b1631c320876a41c43c68c9a0ee0f9f Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 9 Jul 2024 23:23:11 +0300 Subject: [PATCH 06/15] DoH: introduce manual read timer control This commit introduces manual read timer control as used by StreamDNS and its underlying transports. Before that, DoH code would rely on the timer control provided by TCP, which would reset the timer any time some data arrived. Now, the timer is restarted only when a full DNS message is processed in line with other DNS transports. That change is required because we should not stop the timer when reading from the network is paused due to throttling. We need a way to drop timed-out clients, particularly those who refuse to read the data we send. --- lib/isc/netmgr/http.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 77ddfd59a8..6e2a3bbe46 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -560,6 +560,8 @@ finish_http_session(isc_nm_http_session_t *session) { if (!session->closed) { session->closed = true; session->reading = false; + isc_nm_read_stop(session->handle); + isc__nmsocket_timer_stop(session->handle->sock); isc_nmhandle_close(session->handle); } @@ -694,6 +696,9 @@ call_unlink_cstream_readcb(http_cstream_t *cstream, isc_buffer_usedregion(cstream->rbuf, &read_data); cstream->read_cb(session->client_httphandle, result, &read_data, cstream->read_cbarg); + if (result == ISC_R_SUCCESS) { + isc__nmsocket_timer_restart(session->handle->sock); + } put_http_cstream(session->mctx, cstream); } @@ -1570,6 +1575,7 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, if (nghttp2_session_want_read(session->ngsession) != 0) { if (!session->reading) { /* We have not yet started reading from this handle */ + isc__nmsocket_timer_start(session->handle->sock); isc_nm_read(session->handle, http_readcb, session); session->reading = true; } else if (session->buf != NULL) { @@ -1627,6 +1633,7 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, /* * Resume reading, it's idempotent, wait for more */ + isc__nmsocket_timer_start(session->handle->sock); isc_nm_read(session->handle, http_readcb, session); } } else { @@ -1803,6 +1810,7 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { } http_transpost_tcp_nodelay(handle); + isc__nmhandle_set_manual_timer(session->handle, true); http_call_connect_cb(http_sock, session, result); @@ -2454,6 +2462,8 @@ server_call_cb(isc_nmsocket_t *socket, const isc_result_t result, handle = isc__nmhandle_get(socket, NULL, NULL); if (result != ISC_R_SUCCESS) { data = NULL; + } else if (socket->h2->session->handle != NULL) { + isc__nmsocket_timer_restart(socket->h2->session->handle->sock); } if (result == ISC_R_SUCCESS) { socket->h2->request_received = true; @@ -2860,6 +2870,8 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { isc__nmsocket_attach(httpserver, &session->serversocket); server_send_connection_header(session); + isc__nmhandle_set_manual_timer(session->handle, true); + /* TODO H2 */ http_do_bio(session, NULL, NULL, NULL); return ISC_R_SUCCESS; From 4ae4e255cf0aef16d9b1b462e08ff7237352393e Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 16 Jul 2024 16:38:56 +0300 Subject: [PATCH 07/15] Do not stop timer in isc_nm_read_stop() in manual timer mode A call to isc_nm_read_stop() would always stop reading timer even in manual timer control mode which was added with StreamDNS in mind. That looks like an omission that happened due to how timers are controlled in StreamDNS where we always stop the timer before pausing reading anyway (see streamdns_on_complete_dnsmessage()). That would not work well for HTTP, though, where we might want pause reading without stopping the timer in the case we want to split incoming data into multiple chunks to be processed independently. I suppose that it happened due to NM refactoring in the middle of StreamDNS development (at the time isc_nm_cancelread() and isc_nm_pauseread() were removed), as the StreamDNS code seems to be written as if timers are not stoping during a call to isc_nm_read_stop(). --- lib/isc/netmgr/proxystream.c | 2 ++ lib/isc/netmgr/streamdns.c | 1 + lib/isc/netmgr/tcp.c | 4 +++- lib/isc/netmgr/tlsstream.c | 6 ++++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/isc/netmgr/proxystream.c b/lib/isc/netmgr/proxystream.c index 883e8cf942..8d65ea5444 100644 --- a/lib/isc/netmgr/proxystream.c +++ b/lib/isc/netmgr/proxystream.c @@ -121,6 +121,7 @@ proxystream_on_header_data_cb(const isc_result_t result, * the case of TCP it is disabled by default */ proxystream_read_stop(sock); + isc__nmsocket_timer_stop(sock); isc__nmhandle_set_manual_timer(sock->outerhandle, false); sock->proxy.header_processed = true; @@ -775,6 +776,7 @@ isc__nm_proxystream_close(isc_nmsocket_t *sock) { * external references, we can close everything. */ proxystream_read_stop(sock); + isc__nmsocket_timer_stop(sock); if (sock->outerhandle != NULL) { sock->reading = false; isc_nm_read_stop(sock->outerhandle); diff --git a/lib/isc/netmgr/streamdns.c b/lib/isc/netmgr/streamdns.c index 30b3903986..c80b2285c9 100644 --- a/lib/isc/netmgr/streamdns.c +++ b/lib/isc/netmgr/streamdns.c @@ -1009,6 +1009,7 @@ streamdns_close_direct(isc_nmsocket_t *sock) { if (sock->outerhandle != NULL) { sock->streamdns.reading = false; + isc__nmsocket_timer_stop(sock); isc_nm_read_stop(sock->outerhandle); isc_nmhandle_close(sock->outerhandle); isc_nmhandle_detach(&sock->outerhandle); diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index ca3ed8b7f4..4f98b50862 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -759,7 +759,9 @@ isc__nm_tcp_read_stop(isc_nmhandle_t *handle) { isc_nmsocket_t *sock = handle->sock; - isc__nmsocket_timer_stop(sock); + if (!sock->manual_read_timer) { + isc__nmsocket_timer_stop(sock); + } isc__nm_stop_reading(sock); sock->reading = false; diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index c599600f10..8d5fe1fd37 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -465,6 +465,7 @@ tls_try_handshake(isc_nmsocket_t *sock, isc_result_t *presult) { isc__nmsocket_log_tls_session_reuse(sock, sock->tlsstream.tls); tlshandle = isc__nmhandle_get(sock, &sock->peer, &sock->iface); + isc__nmsocket_timer_stop(sock); tls_read_stop(sock); if (isc__nm_closing(sock->worker)) { @@ -1154,6 +1155,10 @@ isc__nm_tls_read_stop(isc_nmhandle_t *handle) { handle->sock->reading = false; + if (!handle->sock->manual_read_timer) { + isc__nmsocket_timer_stop(handle->sock); + } + tls_read_stop(handle->sock); } @@ -1174,6 +1179,7 @@ isc__nm_tls_close(isc_nmsocket_t *sock) { */ tls_read_stop(sock); if (sock->outerhandle != NULL) { + isc__nmsocket_timer_stop(sock); isc_nm_read_stop(sock->outerhandle); isc_nmhandle_close(sock->outerhandle); isc_nmhandle_detach(&sock->outerhandle); From 937b5f8349a6a5e15af254a53a659e39c7c1d179 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Thu, 18 Jul 2024 20:21:53 +0300 Subject: [PATCH 08/15] DoH: reduce excessive bad request logging We started using isc_nm_bad_request() more actively throughout codebase. In the case of HTTP/2 it can lead to a large count of useless "Bad Request" messages in the BIND log, as often we attempt to send such request over effectively finished HTTP/2 sessions. This commit fixes that. --- lib/isc/netmgr/http.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 6e2a3bbe46..2287035921 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -2484,6 +2484,12 @@ isc__nm_http_bad_request(isc_nmhandle_t *handle) { REQUIRE(!sock->client); REQUIRE(VALID_HTTP2_SESSION(sock->h2->session)); + if (sock->h2->response_submitted || + !http_session_active(sock->h2->session)) + { + return; + } + (void)server_send_error_response(ISC_HTTP_ERROR_BAD_REQUEST, sock->h2->session->ngsession, sock); } From b6ccbcbcf105e106c44793502bed8dfc1223fdfa Mon Sep 17 00:00:00 2001 From: Andoni Duarte Pintado Date: Thu, 16 Jan 2025 10:20:01 +0100 Subject: [PATCH 09/15] Generate changelog for BIND 9.21.4 --- doc/arm/changelog.rst | 1 + doc/changelog/changelog-9.21.4.rst | 304 +++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 doc/changelog/changelog-9.21.4.rst diff --git a/doc/arm/changelog.rst b/doc/arm/changelog.rst index ec3a049e62..eeb76f8592 100644 --- a/doc/arm/changelog.rst +++ b/doc/arm/changelog.rst @@ -18,6 +18,7 @@ Changelog development. Regular users should refer to :ref:`Release Notes ` for changes relevant to them. +.. include:: ../changelog/changelog-9.21.4.rst .. include:: ../changelog/changelog-9.21.3.rst .. include:: ../changelog/changelog-9.21.2.rst .. include:: ../changelog/changelog-9.21.1.rst diff --git a/doc/changelog/changelog-9.21.4.rst b/doc/changelog/changelog-9.21.4.rst new file mode 100644 index 0000000000..d303591912 --- /dev/null +++ b/doc/changelog/changelog-9.21.4.rst @@ -0,0 +1,304 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. 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 https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +BIND 9.21.4 +----------- + +Security Fixes +~~~~~~~~~~~~~~ + +- [CVE-2024-12705] DNS-over-HTTP(s) flooding fixes. ``bddaff32104`` + + Fix DNS-over-HTTP(S) implementation issues that arise under heavy + query load. Optimize resource usage for :iscman:`named` instances that + accept queries over DNS-over-HTTP(S). + + Previously, :iscman:`named` would process all incoming HTTP/2 data at + once, which could overwhelm the server, especially when dealing with + clients that send requests but don't wait for responses. That has been + fixed. Now, :iscman:`named` handles HTTP/2 data in smaller chunks and + throttles reading until the remote side reads the response data. It + also throttles clients that send too many requests at once. + + Additionally, :iscman:`named` now carefully processes data sent by + some clients, which can be considered "flooding." It logs these + clients and drops connections from them. :gl:`#4795` + + In some cases, :iscman:`named` could leave DNS-over-HTTP(S) + connections in the `CLOSE_WAIT` state indefinitely. That also has been + fixed. ISC would like to thank JF Billaud for thoroughly investigating + the issue and verifying the fix. :gl:`#5083` :gl:`#4795` :gl:`#5083` + +- [CVE-2024-11187] Limit the additional processing for large RDATA sets. + ``4d054cca7a0`` + + When answering queries, don't add data to the additional section if + the answer has more than 13 names in the RDATA. This limits the number + of lookups into the database(s) during a single client query, reducing + query processing load. :gl:`#5034` + +New Features +~~~~~~~~~~~~ + +- Add Extended DNS Error Code 22 - No Reachable Authority. + ``3972eacdad2`` + + When the resolver is trying to query an authority server and + eventually timed out, a SERVFAIL answer is given to the client. Add + the Extended DNS Error Code 22 - No Reachable Authority to the + response. :gl:`#2268` :gl:`!9743` + +- Enable extraction of exact local socket addresses. ``44d5dbeab63`` + + Enable extracting the exact address/port that a local wildcard/TCP + socket is bound to, improving the accuracy of dnstap logging and + providing more information in debug logs produced by system tests. + Since this requires issuing an extra system call on some hot paths, + this new feature is only enabled when the ``ISC_SOCKET_DETAILS`` + preprocessor macro is set at compile time. :gl:`#4344` :gl:`!8348` + +- Log both "from" and "to" socket in debug messages. ``6230bc883a5`` + + Debug messages logging network traffic now include information about + both sides of each communication channel rather than just one of them. + :gl:`#4345` :gl:`!8349` + +- Add "Zone has [AAAA/A] records but is not served by IPv[6/4]" + warnings. ``ef6dc36e530`` + + Check that zones with AAAA records are served by IPv6 servers and that + zones with A records are served by IPv4 servers. Sometimes, IPv6 + services are accidentally misconfigured and zones with IPv6 (AAAA) + address records are not served by DNS servers with IPv6 addresses, + which means they need to use translation devices to look up those IPv6 + addresses. The reverse is also sometimes true: zones with A records + are not resolvable over IPv4 when they should be. To prevent this, + BIND now looks for these misconfigured zones and issues a warning if + they are found. :gl:`#4370` :gl:`!8393` + +- Add a new option to configure the maximum number of outgoing queries + per client request. ``80a5745a1f8`` + + The configuration option 'max-query-count' sets how many outgoing + queries per client request is allowed. The existing + 'max-recursion-queries' is the number of permissible queries for a + single name and is reset on every CNAME redirection. This new option + is a global limit on the client request. The default is 200. + + This allows us to send a bit more queries while looking up a single + name. The default for 'max-recursion-queries' is changed from 32 to + 50. :gl:`#4980` :gl:`#4921` :gl:`!9737` + +Removed Features +~~~~~~~~~~~~~~~~ + +- Remove dnssec-must-be-secure feature. ``f5f792f1ed2`` + + :gl:`#4482` :gl:`!9851` + +- Remove 'sortlist' option. ``2bce06e170a`` + + The `sortlist` option, which was deprecated in BIND 9.20, has now been + removed. :gl:`#4665` :gl:`!9839` + +- Remove fixed value for the rrset-order option. ``5bee088dd1f`` + + Remove the "fixed" value from the "rrset-order" option and from the + autoconf script. :gl:`#4666` :gl:`!9852` + +- Remove the log message about incomplete IPv6 API. ``3779a81d501`` + + The log message would not be ever reached, because the IPv6 API is + always considered to be complete. Just remove the dead code. + :gl:`#5068` :gl:`!9798` + +- Remove trusted-keys and managed-keys options. ``9de6b228d41`` + + These options have been deprecated in 9.19 in favor of the + 'trust-anchors' option and are now being removed. :gl:`#5080` + :gl:`!9855` + +- Drop single-use RETERR macro. ``f6ff4fff85e`` + + If the RETERR define is only used once in a file, just drop the macro. + :gl:`!9871` + +- Remove C++ support from the public header. ``8d9bc93e81e`` + + Since BIND 9 headers are not longer public, there's no reason to keep + the ISC_LANG_BEGINDECL and ISC_LANG_ENDDECL macros to support + including them from C++ projects. :gl:`!9925` + +- Remove DLV remnants. ``f4377a3cd69`` + + DLV is long gone, so we can remove design documentation around DLV, + related command line options (that were already a hard failure), and + some DLV related test remnants. :gl:`!9888` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Update picohttpparser.{c,h} with upstream repository. ``9428077f481`` + + :gl:`#4485` :gl:`!9857` + +- The configuration clauses parental-agents and primaries are renamed to + remote-servers. ``858ba71eafc`` + + The top blocks 'primaries' and 'parental-agents' are no longer + preferred and should be renamed to 'remote-servers'. The zone + statements 'parental-agents' and 'primaries' are still used, and may + refer to any 'remote-servers' top block. :gl:`#4544` :gl:`!9822` + +- Add TLS SNI extension to all outgoing TLS connections. ``6eb77ed2b07`` + + This change ensures that SNI extension is used in outgoing connections + over TLS (e.g. for DoT and DoH) when applicable. :gl:`#5099` + :gl:`!9923` + +- Detect and possibly define constexpr using Autoconf. ``1fea227ab8b`` + + Previously, we had an ISC_CONSTEXPR macro that was expanded to either + `constexpr` or `static const`, depending on compiler support. To make + the code cleaner, move `constexpr` support detection to Autoconf; if + `constexpr` support is missing from the compiler, define `constexpr` + as `static const` in config.h. :gl:`!9924` + +- Remove unused maxquerycount. ``43622594f48`` + + Related to #4980 :gl:`!9850` + +- Use query counters in validator code. ``63060314098`` + + Commit af7db8951364a89c468eda1535efb3f53adc2c1f as part of #4141 was + supposed to apply the 'max-recursion-queries' quota to validator + queries, but the counter was never actually passed on to + 'dns_resolver_createfetch()'. This has been fixed, and the global + query counter ('max-query-count', per client request) is now also + added. + + Related to #4980 :gl:`!9856` + +Bug Fixes +~~~~~~~~~ + +- Accept resolv.conf with more than 8 search domains. ``eda02dc3424`` + + :gl:`#1259` :gl:`!2446` + +- Fix nsupdate hang when processing a large update. ``fa56e0d8b10`` + + To mitigate DNS flood attacks over a single TCP connection, we + throttle the connection when the other side does not read the data. + Throttling should only occur on server-side sockets, but erroneously + also happened for nsupdate, which acts as a client. When nsupdate + started throttling the connection, it never attempts to read again. + This has been fixed. :gl:`#4910` :gl:`!9709` + +- Lock and attach when returning zone stats. ``3c720c64250`` + + When returning zone statistics counters, the statistics sets are now + attached while the zone is locked. This addresses Coverity warnings + CID 468720, 468728 and 468729. :gl:`#4934` :gl:`!9488` + +- Fix possible assertion failure when reloading server while processing + updates. ``be5266a7c61`` + + :gl:`#5006` :gl:`!9745` + +- Preserve cache across reconfig when using attach-cache. + ``0b287f3aaf9`` + + When the `attach-cache` option is used in the `options` block with an + arbitrary name, it causes all views to use the same cache. Previously, + this configuration caused the cache to be deleted and a new cache + created every time the server was reconfigured. This has been fixed. + :gl:`#5061` :gl:`!9787` + +- Resolve the spurious drops in performance due GLUE cache. + ``e2c1941efd2`` + + For performance reasons, the returned GLUE records are cached on the + first use. The current implementation could randomly cause a + performance drop and increased memory use. This has been fixed. + :gl:`#5064` :gl:`!9831` + +- Fix dnssec-signzone signing non-DNSKEY RRsets with revoked keys. + ``1435770b1a7`` + + `dnssec-signzone` was using revoked keys for signing RRsets other than + DNSKEY. This has been corrected. :gl:`#5070` :gl:`!9800` + +- Disable deterministic ecdsa for fips builds. ``707dded9798`` + + FIPS 186-5 [1] allows the usage deterministic ECDSA (Section 6.3) + which is compabile with RFC 6979 [2] but OpenSSL seems to follow FIPS + 186-4 (Section 6.3) [3] which only allows for random k values, failing + k value generation for OpenSSL >=3.2. [4] + + Fix signing by not using deterministic ECDSA when FIPS mode is active. + + [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf [2]: + https://datatracker.ietf.org/doc/html/rfc6979 [3]: + https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf [4]: https: + //github.com/openssl/openssl/blob/85f17585b0d8b55b335f561e2862db14a20b + 1e64/crypto/ec/ecdsa_ossl.c#L201-L207 :gl:`#5072` :gl:`!9808` + +- Revert "Lock and attach when returning zone stats" ``de6f199f4d2`` + + :gl:`#5082` :gl:`!9859` + +- Unknown directive in resolv.conf not handled properly. ``48901ef57e7`` + + The line after an unknown directive in resolv.conf could accidentally + be skipped, potentially affecting dig, host, nslookup, nsupdate, or + delv. This has been fixed. :gl:`#5084` :gl:`!9865` + +- Querying an NSEC3-signed zone for an empty record could trigger an + assertion. ``3a94afa03a1`` + + A bug in the qpzone database could trigger a crash when querying for a + deleted name, or a newly-added empty non-terminal name, in an + NSEC3-signed zone. This has been fixed. :gl:`#5108` :gl:`!9928` + +- Fix response policy zones and catalog zones with an $INCLUDE statement + defined. ``19a2aab136a`` + + Response policy zones (RPZ) and catalog zones were not working + correctly if they had an $INCLUDE statement defined. This has been + fixed. :gl:`#5111` :gl:`!9930` + +- Clean up incorrect logging module names. ``3db39ec7ad5`` + + Some files used logmodule names that had been copied in from + elsewhere; these have now been given module names of their own. Also, + the RBT and RBTDB logmodules have been removed, since they are now + unused. :gl:`!9895` + +- Finalize removal of memory debug flags size and mctx. ``667383587b2`` + + Commit 4b3d0c66009d30f5c0bc12ee128fc59f1d853f44 has removed them, but + did not remove few traces in documentation and help. Remove them from + remaining places. :gl:`!9606` + +- Mark loop as shuttingdown earlier in shutdown_cb. ``d71869d6a78`` + + :gl:`!9827` + +- Use CMM_{STORE,LOAD}_SHARED to store/load glue in gluelist. + ``6ce55429f14`` + + ThreadSanitizer has trouble understanding that gluelist->glue is + constant after it is assigned to the slabheader with cmpxchg. Help + ThreadSanitizer to understand the code by using CMM_STORE_SHARED and + CMM_LOAD_SHARED on gluelist->glue. :gl:`!9929` + + From 0937207606deb2dff483e47faa8ce4928b5a7683 Mon Sep 17 00:00:00 2001 From: Andoni Duarte Pintado Date: Thu, 16 Jan 2025 10:39:11 +0100 Subject: [PATCH 10/15] Prepare release notes for BIND 9.21.4 --- doc/arm/notes.rst | 1 + doc/notes/notes-9.21.4.rst | 188 +++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 doc/notes/notes-9.21.4.rst diff --git a/doc/arm/notes.rst b/doc/arm/notes.rst index ac2806e5ec..6446243051 100644 --- a/doc/arm/notes.rst +++ b/doc/arm/notes.rst @@ -47,6 +47,7 @@ The list of known issues affecting the latest version in the 9.21 branch can be found at https://gitlab.isc.org/isc-projects/bind9/-/wikis/Known-Issues-in-BIND-9.21 +.. include:: ../notes/notes-9.21.4.rst .. include:: ../notes/notes-9.21.3.rst .. include:: ../notes/notes-9.21.2.rst .. include:: ../notes/notes-9.21.1.rst diff --git a/doc/notes/notes-9.21.4.rst b/doc/notes/notes-9.21.4.rst new file mode 100644 index 0000000000..18aa894b14 --- /dev/null +++ b/doc/notes/notes-9.21.4.rst @@ -0,0 +1,188 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. 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 https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +Notes for BIND 9.21.4 +--------------------- + +Security Fixes +~~~~~~~~~~~~~~ + +- [CVE-2024-12705] DNS-over-HTTP(s) flooding fixes. + + Fix DNS-over-HTTP(S) implementation issues that arise under heavy + query load. Optimize resource usage for :iscman:`named` instances that + accept queries over DNS-over-HTTP(S). + + Previously, :iscman:`named` would process all incoming HTTP/2 data at + once, which could overwhelm the server, especially when dealing with + clients that send requests but don't wait for responses. That has been + fixed. Now, :iscman:`named` handles HTTP/2 data in smaller chunks and + throttles reading until the remote side reads the response data. It + also throttles clients that send too many requests at once. + + Additionally, :iscman:`named` now carefully processes data sent by + some clients, which can be considered "flooding." It logs these + clients and drops connections from them. :gl:`#4795` + + In some cases, :iscman:`named` could leave DNS-over-HTTP(S) + connections in the `CLOSE_WAIT` state indefinitely. That also has been + fixed. ISC would like to thank JF Billaud for thoroughly investigating + the issue and verifying the fix. :gl:`#5083` :gl:`#4795` :gl:`#5083` + +- [CVE-2024-11187] Limit the additional processing for large RDATA sets. + + When answering queries, don't add data to the additional section if + the answer has more than 13 names in the RDATA. This limits the number + of lookups into the database(s) during a single client query, reducing + query processing load. :gl:`#5034` + +New Features +~~~~~~~~~~~~ + +- Add Extended DNS Error Code 22 - No Reachable Authority. + + When the resolver is trying to query an authority server and + eventually timed out, a SERVFAIL answer is given to the client. Add + the Extended DNS Error Code 22 - No Reachable Authority to the + response. :gl:`#2268` + +- Add "Zone has [AAAA/A] records but is not served by IPv[6/4]" + warnings. + + Check that zones with AAAA records are served by IPv6 servers and that + zones with A records are served by IPv4 servers. Sometimes, IPv6 + services are accidentally misconfigured and zones with IPv6 (AAAA) + address records are not served by DNS servers with IPv6 addresses, + which means they need to use translation devices to look up those IPv6 + addresses. The reverse is also sometimes true: zones with A records + are not resolvable over IPv4 when they should be. To prevent this, + BIND now looks for these misconfigured zones and issues a warning if + they are found. :gl:`#4370` + +- Add a new option to configure the maximum number of outgoing queries + per client request. + + The configuration option 'max-query-count' sets how many outgoing + queries per client request is allowed. The existing + 'max-recursion-queries' is the number of permissible queries for a + single name and is reset on every CNAME redirection. This new option + is a global limit on the client request. The default is 200. + + This allows us to send a bit more queries while looking up a single + name. The default for 'max-recursion-queries' is changed from 32 to + 50. :gl:`#4980` :gl:`#4921` + +Removed Features +~~~~~~~~~~~~~~~~ + +- Remove dnssec-must-be-secure feature. + + :gl:`#4482` + +- Remove 'sortlist' option. + + The `sortlist` option, which was deprecated in BIND 9.20, has now been + removed. :gl:`#4665` + +- Remove fixed value for the rrset-order option. + + Remove the "fixed" value from the "rrset-order" option and from the + autoconf script. :gl:`#4666` + +- Remove trusted-keys and managed-keys options. + + These options have been deprecated in 9.19 in favor of the + 'trust-anchors' option and are now being removed. :gl:`#5080` + +Feature Changes +~~~~~~~~~~~~~~~ + +- The configuration clauses parental-agents and primaries are renamed to + remote-servers. + + The top blocks 'primaries' and 'parental-agents' are no longer + preferred and should be renamed to 'remote-servers'. The zone + statements 'parental-agents' and 'primaries' are still used, and may + refer to any 'remote-servers' top block. :gl:`#4544` + +Bug Fixes +~~~~~~~~~ + +- Fix nsupdate hang when processing a large update. + + To mitigate DNS flood attacks over a single TCP connection, we + throttle the connection when the other side does not read the data. + Throttling should only occur on server-side sockets, but erroneously + also happened for nsupdate, which acts as a client. When nsupdate + started throttling the connection, it never attempts to read again. + This has been fixed. :gl:`#4910` + +- Fix possible assertion failure when reloading server while processing + updates. + + :gl:`#5006` + +- Preserve cache across reconfig when using attach-cache. + + When the `attach-cache` option is used in the `options` block with an + arbitrary name, it causes all views to use the same cache. Previously, + this configuration caused the cache to be deleted and a new cache + created every time the server was reconfigured. This has been fixed. + :gl:`#5061` + +- Resolve the spurious drops in performance due GLUE cache. + + For performance reasons, the returned GLUE records are cached on the + first use. The current implementation could randomly cause a + performance drop and increased memory use. This has been fixed. + :gl:`#5064` + +- Fix dnssec-signzone signing non-DNSKEY RRsets with revoked keys. + + `dnssec-signzone` was using revoked keys for signing RRsets other than + DNSKEY. This has been corrected. :gl:`#5070` + +- Disable deterministic ecdsa for fips builds. + + FIPS 186-5 [1] allows the usage deterministic ECDSA (Section 6.3) + which is compabile with RFC 6979 [2] but OpenSSL seems to follow FIPS + 186-4 (Section 6.3) [3] which only allows for random k values, failing + k value generation for OpenSSL >=3.2. [4] + + Fix signing by not using deterministic ECDSA when FIPS mode is active. + + [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf [2]: + https://datatracker.ietf.org/doc/html/rfc6979 [3]: + https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf [4]: https: + //github.com/openssl/openssl/blob/85f17585b0d8b55b335f561e2862db14a20b + 1e64/crypto/ec/ecdsa_ossl.c#L201-L207 :gl:`#5072` + +- Unknown directive in resolv.conf not handled properly. + + The line after an unknown directive in resolv.conf could accidentally + be skipped, potentially affecting dig, host, nslookup, nsupdate, or + delv. This has been fixed. :gl:`#5084` + +- Querying an NSEC3-signed zone for an empty record could trigger an + assertion. + + A bug in the qpzone database could trigger a crash when querying for a + deleted name, or a newly-added empty non-terminal name, in an + NSEC3-signed zone. This has been fixed. :gl:`#5108` + +- Fix response policy zones and catalog zones with an $INCLUDE statement + defined. + + Response policy zones (RPZ) and catalog zones were not working + correctly if they had an $INCLUDE statement defined. This has been + fixed. :gl:`#5111` + + From 84f36eaa83be35c0047aee67ecc0d1733d87648c Mon Sep 17 00:00:00 2001 From: Andoni Duarte Pintado Date: Thu, 16 Jan 2025 10:41:20 +0100 Subject: [PATCH 11/15] Fix broken option reference in the ARM --- doc/arm/advanced.inc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/arm/advanced.inc.rst b/doc/arm/advanced.inc.rst index 73202eb171..5ebb6a3dc9 100644 --- a/doc/arm/advanced.inc.rst +++ b/doc/arm/advanced.inc.rst @@ -99,7 +99,7 @@ from a primary server, the secondary checks to see that its version of the zone is the current version and, if not, initiates a zone transfer. For more information about DNS NOTIFY, see the description of the -:namedconf:ref:`notify` and :namedconf:ref`also-notify` statements. +:namedconf:ref:`notify` and :namedconf:ref:`also-notify` statements. The NOTIFY protocol is specified in :rfc:`1996`. .. note:: From fa4c45d9e8c04ff5d666685384465802509a121e Mon Sep 17 00:00:00 2001 From: Andoni Duarte Pintado Date: Thu, 16 Jan 2025 10:41:20 +0100 Subject: [PATCH 12/15] Tweak and reword release notes --- doc/notes/notes-9.21.4.rst | 149 +++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 74 deletions(-) diff --git a/doc/notes/notes-9.21.4.rst b/doc/notes/notes-9.21.4.rst index 18aa894b14..b78768a16d 100644 --- a/doc/notes/notes-9.21.4.rst +++ b/doc/notes/notes-9.21.4.rst @@ -15,42 +15,48 @@ Notes for BIND 9.21.4 Security Fixes ~~~~~~~~~~~~~~ -- [CVE-2024-12705] DNS-over-HTTP(s) flooding fixes. +- DNS-over-HTTPS flooding fixes. :cve:`2024-12705` - Fix DNS-over-HTTP(S) implementation issues that arise under heavy + Fix DNS-over-HTTPS implementation issues that arise under heavy query load. Optimize resource usage for :iscman:`named` instances that - accept queries over DNS-over-HTTP(S). + accept queries over DNS-over-HTTPS. - Previously, :iscman:`named` would process all incoming HTTP/2 data at + Previously, :iscman:`named` processed all incoming HTTP/2 data at once, which could overwhelm the server, especially when dealing with - clients that send requests but don't wait for responses. That has been + clients that sent requests but did not wait for responses. That has been fixed. Now, :iscman:`named` handles HTTP/2 data in smaller chunks and throttles reading until the remote side reads the response data. It also throttles clients that send too many requests at once. - Additionally, :iscman:`named` now carefully processes data sent by - some clients, which can be considered "flooding." It logs these - clients and drops connections from them. :gl:`#4795` + In addition, :iscman:`named` now evaluates excessive streams opened by + clients that include no DNS data, which is considered "flooding." It + logs these clients and drops connections from them. :gl:`#4795` - In some cases, :iscman:`named` could leave DNS-over-HTTP(S) - connections in the `CLOSE_WAIT` state indefinitely. That also has been - fixed. ISC would like to thank JF Billaud for thoroughly investigating - the issue and verifying the fix. :gl:`#5083` :gl:`#4795` :gl:`#5083` + In some cases, :iscman:`named` could leave DNS-over-HTTPS + connections in the `CLOSE_WAIT` state indefinitely. That has also been + fixed. :gl:`#5083` -- [CVE-2024-11187] Limit the additional processing for large RDATA sets. + ISC would like to thank Jean-François Billaud for his assistance with + investigating this issue. + +- Limit additional section processing for large RDATA sets. + :cve:`2024-11187` When answering queries, don't add data to the additional section if the answer has more than 13 names in the RDATA. This limits the number of lookups into the database(s) during a single client query, reducing - query processing load. :gl:`#5034` + the query-processing load. :gl:`#5034` + + ISC would like to thank Toshifumi Sakaguchi for bringing this + vulnerability to our attention. New Features ~~~~~~~~~~~~ - Add Extended DNS Error Code 22 - No Reachable Authority. - When the resolver is trying to query an authority server and - eventually timed out, a SERVFAIL answer is given to the client. Add + When the resolver is trying to query an authoritative server and + eventually times out, a SERVFAIL answer is given to the client. Add the Extended DNS Error Code 22 - No Reachable Authority to the response. :gl:`#2268` @@ -70,119 +76,114 @@ New Features - Add a new option to configure the maximum number of outgoing queries per client request. - The configuration option 'max-query-count' sets how many outgoing - queries per client request is allowed. The existing - 'max-recursion-queries' is the number of permissible queries for a + The configuration option :any:`max-query-count` sets how many outgoing + queries per client request are allowed. The existing + :any:`max-recursion-queries` value is the number of permissible queries for a single name and is reset on every CNAME redirection. This new option is a global limit on the client request. The default is 200. - This allows us to send a bit more queries while looking up a single - name. The default for 'max-recursion-queries' is changed from 32 to - 50. :gl:`#4980` :gl:`#4921` + The default for :any:`max-recursion-queries` is changed from 32 to + 50. This allows :any:`named` to send a few more queries + while looking up a single name. :gl:`#4980` :gl:`#4921` Removed Features ~~~~~~~~~~~~~~~~ -- Remove dnssec-must-be-secure feature. +- Remove the ``dnssec-must-be-secure`` feature. :gl:`#4482` - :gl:`#4482` +- Remove ``sortlist`` option. -- Remove 'sortlist' option. - - The `sortlist` option, which was deprecated in BIND 9.20, has now been + The ``sortlist`` option, which was deprecated in BIND 9.20, has now been removed. :gl:`#4665` -- Remove fixed value for the rrset-order option. +- Remove support for fixed RRset ordering. - Remove the "fixed" value from the "rrset-order" option and from the - autoconf script. :gl:`#4666` + Remove the ``fixed`` value from the :any:`rrset-order` option and the + ``--enable-fixed-rrset`` option from the ``./configure`` script. + :gl:`#4666` -- Remove trusted-keys and managed-keys options. +- Remove ``trusted-keys`` and ``managed-keys`` options. These options have been deprecated in 9.19 in favor of the - 'trust-anchors' option and are now being removed. :gl:`#5080` + :any:`trust-anchors` option and are now being removed. :gl:`#5080` Feature Changes ~~~~~~~~~~~~~~~ -- The configuration clauses parental-agents and primaries are renamed to - remote-servers. +- The configuration clauses ``parental-agents`` and ``primaries`` are renamed to + :any:`remote-servers`. - The top blocks 'primaries' and 'parental-agents' are no longer - preferred and should be renamed to 'remote-servers'. The zone - statements 'parental-agents' and 'primaries' are still used, and may - refer to any 'remote-servers' top block. :gl:`#4544` + The top blocks ``primaries`` and ``parental-agents`` are no longer + preferred and should be renamed to :any:`remote-servers`. The zone + statements :any:`parental-agents` and :any:`primaries` are still used, and may + refer to any :any:`remote-servers` top block. :gl:`#4544` Bug Fixes ~~~~~~~~~ -- Fix nsupdate hang when processing a large update. +- Fix :iscman:`nsupdate` hang when processing a large update. - To mitigate DNS flood attacks over a single TCP connection, we - throttle the connection when the other side does not read the data. - Throttling should only occur on server-side sockets, but erroneously - also happened for nsupdate, which acts as a client. When nsupdate - started throttling the connection, it never attempts to read again. - This has been fixed. :gl:`#4910` + To mitigate DNS flood attacks over a single TCP connection, throttle + the connection when the other side does not read the data. Throttling + should only occur on server-side sockets, but erroneously also + happened for :iscman:`nsupdate`, which acts as a client. When + :iscman:`nsupdate` started throttling the connection, it never + attempted to read again. This has been fixed. :gl:`#4910` - Fix possible assertion failure when reloading server while processing - updates. + update policy rules. :gl:`#5006` - :gl:`#5006` +- Preserve cache across reconfig when using :any:`attach-cache`. -- Preserve cache across reconfig when using attach-cache. - - When the `attach-cache` option is used in the `options` block with an + When the :any:`attach-cache` option is used in the ``options`` block with an arbitrary name, it causes all views to use the same cache. Previously, this configuration caused the cache to be deleted and a new cache - created every time the server was reconfigured. This has been fixed. + to be created every time the server was reconfigured. This has been fixed. :gl:`#5061` -- Resolve the spurious drops in performance due GLUE cache. +- Resolve the spurious drops in performance due to glue cache. - For performance reasons, the returned GLUE records are cached on the + For performance reasons, the returned glue records are cached on the first use. The current implementation could randomly cause a performance drop and increased memory use. This has been fixed. :gl:`#5064` -- Fix dnssec-signzone signing non-DNSKEY RRsets with revoked keys. +- Fix :iscman:`dnssec-signzone` signing non-DNSKEY RRsets with revoked keys. - `dnssec-signzone` was using revoked keys for signing RRsets other than + :any:`dnssec-signzone` was using revoked keys for signing RRsets other than DNSKEY. This has been corrected. :gl:`#5070` -- Disable deterministic ecdsa for fips builds. +- Disable deterministic ECDSA for FIPS builds. - FIPS 186-5 [1] allows the usage deterministic ECDSA (Section 6.3) - which is compabile with RFC 6979 [2] but OpenSSL seems to follow FIPS - 186-4 (Section 6.3) [3] which only allows for random k values, failing - k value generation for OpenSSL >=3.2. [4] + `FIPS 186-5 `_ allows use + of deterministic ECDSA (Section 6.3), which is compatible with + :rfc:`6979`, but OpenSSL seems to follow `FIPS 186-4 + `_ + (Section 6.3), which only allows random ``k`` values. This causes ``k`` + value generation to fail for OpenSSL >= 3.2, making BIND unable to + generate ECDSA signatures when in FIPS mode. - Fix signing by not using deterministic ECDSA when FIPS mode is active. + This signing is now fixed by not using deterministic ECDSA when FIPS mode is active. :gl:`#5072` - [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf [2]: - https://datatracker.ietf.org/doc/html/rfc6979 [3]: - https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf [4]: https: - //github.com/openssl/openssl/blob/85f17585b0d8b55b335f561e2862db14a20b - 1e64/crypto/ec/ecdsa_ossl.c#L201-L207 :gl:`#5072` +- Fix improper handling of unknown directives in ``resolv.conf``. -- Unknown directive in resolv.conf not handled properly. - - The line after an unknown directive in resolv.conf could accidentally - be skipped, potentially affecting dig, host, nslookup, nsupdate, or - delv. This has been fixed. :gl:`#5084` + The line after an unknown directive in ``resolv.conf`` could accidentally be + skipped, potentially affecting :iscman:`dig`, :iscman:`host`, + :iscman:`nslookup`, :iscman:`nsupdate`, or :iscman:`delv`. This has been + fixed. :gl:`#5084` - Querying an NSEC3-signed zone for an empty record could trigger an assertion. A bug in the qpzone database could trigger a crash when querying for a - deleted name, or a newly-added empty non-terminal name, in an + deleted name, or a newly added empty non-terminal name, in an NSEC3-signed zone. This has been fixed. :gl:`#5108` -- Fix response policy zones and catalog zones with an $INCLUDE statement +- Fix response policy zones and catalog zones with an ``$INCLUDE`` statement defined. Response policy zones (RPZ) and catalog zones were not working - correctly if they had an $INCLUDE statement defined. This has been + correctly if they had an ``$INCLUDE`` statement defined. This has been fixed. :gl:`#5111` From e9003901a7a5a0de1417d24e75fa2edb0bfd09b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 17 Jan 2025 22:53:57 +0100 Subject: [PATCH 13/15] Add release note for GL #5099 --- doc/notes/notes-9.21.4.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/notes/notes-9.21.4.rst b/doc/notes/notes-9.21.4.rst index b78768a16d..34d08723dc 100644 --- a/doc/notes/notes-9.21.4.rst +++ b/doc/notes/notes-9.21.4.rst @@ -86,6 +86,12 @@ New Features 50. This allows :any:`named` to send a few more queries while looking up a single name. :gl:`#4980` :gl:`#4921` +- Use the Server Name Indication (SNI) extension for all outgoing TLS + connections. + + This improves compatibility with other DNS server software. + :gl:`#5099` + Removed Features ~~~~~~~~~~~~~~~~ From 70187b67aef401a1edbb769cce98b64ecceb9f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 17 Jan 2025 22:53:57 +0100 Subject: [PATCH 14/15] Reorder release notes --- doc/notes/notes-9.21.4.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/notes/notes-9.21.4.rst b/doc/notes/notes-9.21.4.rst index 34d08723dc..cc62e17575 100644 --- a/doc/notes/notes-9.21.4.rst +++ b/doc/notes/notes-9.21.4.rst @@ -127,6 +127,13 @@ Feature Changes Bug Fixes ~~~~~~~~~ +- Querying an NSEC3-signed zone for an empty record could trigger an + assertion. + + A bug in the qpzone database could trigger a crash when querying for a + deleted name, or a newly added empty non-terminal name, in an + NSEC3-signed zone. This has been fixed. :gl:`#5108` + - Fix :iscman:`nsupdate` hang when processing a large update. To mitigate DNS flood attacks over a single TCP connection, throttle @@ -178,13 +185,6 @@ Bug Fixes :iscman:`nslookup`, :iscman:`nsupdate`, or :iscman:`delv`. This has been fixed. :gl:`#5084` -- Querying an NSEC3-signed zone for an empty record could trigger an - assertion. - - A bug in the qpzone database could trigger a crash when querying for a - deleted name, or a newly added empty non-terminal name, in an - NSEC3-signed zone. This has been fixed. :gl:`#5108` - - Fix response policy zones and catalog zones with an ``$INCLUDE`` statement defined. From 0f626b8cc37e8af7e4383c346c7ac9bcb3c955d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Mon, 20 Jan 2025 13:54:00 +0100 Subject: [PATCH 15/15] Update BIND version for release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 71f14127ee..2c4e1a7671 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ m4_define([bind_VERSION_MAJOR], 9)dnl m4_define([bind_VERSION_MINOR], 21)dnl m4_define([bind_VERSION_PATCH], 4)dnl -m4_define([bind_VERSION_EXTRA], -dev)dnl +m4_define([bind_VERSION_EXTRA], )dnl m4_define([bind_DESCRIPTION], [(Development Release)])dnl m4_define([bind_SRCID], [m4_esyscmd_s([git rev-parse --short HEAD | cut -b1-7])])dnl m4_define([bind_PKG_VERSION], [[bind_VERSION_MAJOR.bind_VERSION_MINOR.bind_VERSION_PATCH]bind_VERSION_EXTRA])dnl