Commit e577837af1 for bind

commit e577837af153430b38fa0c62ecea0492715f5878
Author: Aydın Mercan <aydin@isc.org>
Date:   Thu Aug 27 16:33:14 2026 +0300

    Add functionality to derive the stateless reset from CID in QUIC router

    Use truncated HMAC of the connection ID with a router specific key as a
    mechanism for deriving a stateless reset token.

    This will be needed since random stateless reset tokens fail to be
    tracked when tearing down the connection.

diff --git a/lib/isc/include/isc/quic.h b/lib/isc/include/isc/quic.h
index b189d382cd..c0bb12d3c0 100644
--- a/lib/isc/include/isc/quic.h
+++ b/lib/isc/include/isc/quic.h
@@ -294,6 +294,20 @@ isc_quic_router_del_cid(isc_quic_router_t *router, isc_constregion_t cid);
  * \retval ISC_R_NOTFOUND if no connection exists for the given CID.
  */

+void
+isc_quic_router_stateless_reset_from_cid(
+	const isc_quic_router_t *router, isc_constregion_t cid,
+	uint8_t token[restrict ISC_QUIC_STATELESS_TOKEN_LENGTH]);
+/**<
+ * \brief
+ * Derive the router-specific stateless reset token of the given CID.
+ *
+ * \par Requires:
+ * \li `router` is a valid router
+ * \li `cid.base != NULL` and `cid.length` ∈ [1, 20]
+ * \li `token != NULL`
+ */
+
 isc_result_t
 isc_quic_router_add_stateless_reset(
 	isc_quic_router_t *router,
diff --git a/lib/isc/quic/router.c b/lib/isc/quic/router.c
index e694a91a9b..fdd43ea514 100644
--- a/lib/isc/quic/router.c
+++ b/lib/isc/quic/router.c
@@ -17,9 +17,11 @@

 #include <isc/attributes.h>
 #include <isc/hash.h>
+#include <isc/hmac.h>
 #include <isc/magic.h>
 #include <isc/mem.h>
 #include <isc/quic.h>
+#include <isc/random.h>
 #include <isc/safe.h>
 #include <isc/urcu.h>
 #include <isc/util.h>
@@ -53,6 +55,7 @@ struct isc_quic_router {
 	size_t cidlen;
 	struct cds_lfht *cid_ht;
 	struct cds_lfht *reset_ht;
+	uint8_t hmac_key[ISC_SHA256_DIGESTLENGTH];
 };

 constexpr uint32_t router_magic = ISC_MAGIC('Q', 'U', 'I', 'r');
@@ -128,6 +131,8 @@ destroy(isc_quic_router_t *router) {
 	}
 	RUNTIME_CHECK(!cds_lfht_destroy(router->reset_ht, NULL));

+	isc_safe_memwipe(router->hmac_key, sizeof(router->hmac_key));
+
 	router->magic = 0;

 	isc_mem_putanddetach(&router->mctx, router, sizeof(*router));
@@ -160,6 +165,8 @@ isc_quic_router_create(isc_mem_t *mctx, size_t cidlen,
 	INSIST(router->cid_ht != NULL);
 	INSIST(router->reset_ht != NULL);

+	isc_random_buf(router->hmac_key, sizeof(router->hmac_key));
+
 	*routerp = router;
 }

@@ -271,6 +278,33 @@ isc_quic_router_del_cid(isc_quic_router_t *router, isc_constregion_t cid) {
 	return result;
 }

+void
+isc_quic_router_stateless_reset_from_cid(
+	const isc_quic_router_t *router, isc_constregion_t cid,
+	uint8_t token[restrict ISC_QUIC_STATELESS_TOKEN_LENGTH]) {
+	uint8_t mac[ISC_SHA256_DIGESTLENGTH];
+	unsigned int maclen = sizeof(mac);
+
+	REQUIRE(router != NULL && router->magic == router_magic);
+	REQUIRE(cid.base != NULL && cid.length >= NGTCP2_MIN_CIDLEN &&
+		cid.length <= NGTCP2_MAX_CIDLEN);
+	REQUIRE(token != NULL);
+
+	/*
+	 * HMAC failing here is inactionable and points to an unignorable
+	 * libcrypto issue.
+	 */
+	INSIST(isc_hmac(ISC_MD_SHA256, router->hmac_key,
+			sizeof(router->hmac_key), cid.base, cid.length, mac,
+			&maclen) == ISC_R_SUCCESS);
+
+	STATIC_ASSERT(sizeof(mac) >= ISC_QUIC_STATELESS_TOKEN_LENGTH,
+		      "QUIC stateless token length wrongly reduced to be less "
+		      "than SHA-2-256 output size");
+	memmove(token, mac, ISC_QUIC_STATELESS_TOKEN_LENGTH);
+	isc_safe_memwipe(mac, sizeof(mac));
+}
+
 isc_result_t
 isc_quic_router_add_stateless_reset(
 	isc_quic_router_t *router,