The previous hash_key() was a deterministic, unkeyed (<<1) + add over the
key words. An off-path attacker could invert it offline and submit
queries whose source /24, qname hash, and qtype map to a single bucket;
under chaining this turns every lookup into an O(N) walk under
rrl->lock and starves legitimate query processing on the very feature
deployed to mitigate DoS.
Replace it with isc_hash32(), which is HalfSipHash-2-4 keyed by a
per-process random seed, so collision sets cannot be precomputed.
Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit
a6b7ce29c4cfab2ab1d46f48f21f531d5ffde942)
#include <inttypes.h>
#include <stdbool.h>
+#include <isc/hash.h>
+#include <isc/log.h>
#include <isc/mem.h>
#include <isc/net.h>
#include <isc/netaddr.h>
static uint32_t
hash_key(const dns_rrl_key_t *key) {
- uint32_t hval;
- int i;
-
- hval = key->w[0];
- for (i = sizeof(key->w) / sizeof(key->w[0]) - 1; i >= 0; --i) {
- hval = key->w[i] + (hval << 1);
- }
- return hval;
+ /*
+ * The key includes attacker-controlled bits (client /24, qname
+ * hash, qtype). Use the keyed, per-process-randomised hash so
+ * collisions cannot be engineered to overload one bucket chain.
+ */
+ return isc_hash32(key, sizeof(*key), true);
}
/*