xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rrl.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: rrl.c,v 1.11 2025/01/26 16:25:25 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 /*
19  * Rate limit DNS responses.
20  */
21 
22 /* #define ISC_LIST_CHECKINIT */
23 
24 #include <inttypes.h>
25 #include <stdbool.h>
26 
27 #include <isc/mem.h>
28 #include <isc/net.h>
29 #include <isc/netaddr.h>
30 #include <isc/overflow.h>
31 #include <isc/result.h>
32 #include <isc/util.h>
33 
34 #include <dns/log.h>
35 #include <dns/name.h>
36 #include <dns/rcode.h>
37 #include <dns/rdataclass.h>
38 #include <dns/rdatatype.h>
39 #include <dns/rrl.h>
40 #include <dns/view.h>
41 #include <dns/zone.h>
42 
43 static void
44 log_end(dns_rrl_t *rrl, dns_rrl_entry_t *e, bool early, char *log_buf,
45 	unsigned int log_buf_len);
46 
47 /*
48  * Get a modulus for a hash function that is tolerably likely to be
49  * relatively prime to most inputs.  Of course, we get a prime for for initial
50  * values not larger than the square of the last prime.  We often get a prime
51  * after that.
52  * This works well in practice for hash tables up to at least 100
53  * times the square of the last prime and better than a multiplicative hash.
54  */
55 static int
56 hash_divisor(unsigned int initial) {
57 	static uint16_t primes[] = {
58 		3,  5,	7,  11, 13, 17, 19, 23, 29, 31, 37, 41,
59 		43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
60 #if 0
61 		101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157,
62 		163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
63 		229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
64 		293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367,
65 		373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
66 		443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
67 		521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599,
68 		601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661,
69 		673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751,
70 		757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
71 		839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919,
72 		929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009,
73 #endif /* if 0 */
74 	};
75 	int divisions, tries;
76 	unsigned int result;
77 	uint16_t *pp, p;
78 
79 	result = initial;
80 
81 	if (primes[sizeof(primes) / sizeof(primes[0]) - 1] >= result) {
82 		pp = primes;
83 		while (*pp < result) {
84 			++pp;
85 		}
86 		return *pp;
87 	}
88 
89 	if ((result & 1) == 0) {
90 		++result;
91 	}
92 
93 	divisions = 0;
94 	tries = 1;
95 	pp = primes;
96 	do {
97 		p = *pp++;
98 		++divisions;
99 		if ((result % p) == 0) {
100 			++tries;
101 			result += 2;
102 			pp = primes;
103 		}
104 	} while (pp < &primes[sizeof(primes) / sizeof(primes[0])]);
105 
106 	if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) {
107 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
108 			      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG3,
109 			      "%d hash_divisor() divisions in %d tries"
110 			      " to get %d from %d",
111 			      divisions, tries, result, initial);
112 	}
113 
114 	return result;
115 }
116 
117 /*
118  * Convert a timestamp to a number of seconds in the past.
119  */
120 static int
121 delta_rrl_time(isc_stdtime_t ts, isc_stdtime_t now) {
122 	int delta;
123 
124 	delta = now - ts;
125 	if (delta >= 0) {
126 		return delta;
127 	}
128 
129 	/*
130 	 * The timestamp is in the future.  That future might result from
131 	 * re-ordered requests, because we use timestamps on requests
132 	 * instead of consulting a clock.  Timestamps in the distant future are
133 	 * assumed to result from clock changes.  When the clock changes to
134 	 * the past, make existing timestamps appear to be in the past.
135 	 */
136 	if (delta < -DNS_RRL_MAX_TIME_TRAVEL) {
137 		return DNS_RRL_FOREVER;
138 	}
139 	return 0;
140 }
141 
142 static int
143 get_age(const dns_rrl_t *rrl, const dns_rrl_entry_t *e, isc_stdtime_t now) {
144 	if (!e->ts_valid) {
145 		return DNS_RRL_FOREVER;
146 	}
147 	return delta_rrl_time(e->ts + rrl->ts_bases[e->ts_gen], now);
148 }
149 
150 static void
151 set_age(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_stdtime_t now) {
152 	dns_rrl_entry_t *e_old;
153 	unsigned int ts_gen;
154 	int i, ts;
155 
156 	ts_gen = rrl->ts_gen;
157 	ts = now - rrl->ts_bases[ts_gen];
158 	if (ts < 0) {
159 		if (ts < -DNS_RRL_MAX_TIME_TRAVEL) {
160 			ts = DNS_RRL_FOREVER;
161 		} else {
162 			ts = 0;
163 		}
164 	}
165 
166 	/*
167 	 * Make a new timestamp base if the current base is too old.
168 	 * All entries older than DNS_RRL_MAX_WINDOW seconds are ancient,
169 	 * useless history.  Their timestamps can be treated as if they are
170 	 * all the same.
171 	 * We only do arithmetic on more recent timestamps, so bases for
172 	 * older timestamps can be recycled provided the old timestamps are
173 	 * marked as ancient history.
174 	 * This loop is almost always very short because most entries are
175 	 * recycled after one second and any entries that need to be marked
176 	 * are older than (DNS_RRL_TS_BASES)*DNS_RRL_MAX_TS seconds.
177 	 */
178 	if (ts >= DNS_RRL_MAX_TS) {
179 		ts_gen = (ts_gen + 1) % DNS_RRL_TS_BASES;
180 		for (e_old = ISC_LIST_TAIL(rrl->lru), i = 0;
181 		     e_old != NULL && (e_old->ts_gen == ts_gen ||
182 				       !ISC_LINK_LINKED(e_old, hlink));
183 		     e_old = ISC_LIST_PREV(e_old, lru), ++i)
184 		{
185 			e_old->ts_valid = false;
186 		}
187 		if (i != 0) {
188 			isc_log_write(
189 				dns_lctx, DNS_LOGCATEGORY_RRL,
190 				DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1,
191 				"rrl new time base scanned %d entries"
192 				" at %d for %d %d %d %d",
193 				i, now, rrl->ts_bases[ts_gen],
194 				rrl->ts_bases[(ts_gen + 1) % DNS_RRL_TS_BASES],
195 				rrl->ts_bases[(ts_gen + 2) % DNS_RRL_TS_BASES],
196 				rrl->ts_bases[(ts_gen + 3) % DNS_RRL_TS_BASES]);
197 		}
198 		rrl->ts_gen = ts_gen;
199 		rrl->ts_bases[ts_gen] = now;
200 		ts = 0;
201 	}
202 
203 	e->ts_gen = ts_gen;
204 	e->ts = ts;
205 	e->ts_valid = true;
206 }
207 
208 static isc_result_t
209 expand_entries(dns_rrl_t *rrl, int newsize) {
210 	unsigned int bsize;
211 	dns_rrl_block_t *b;
212 	dns_rrl_entry_t *e;
213 	double rate;
214 	int i;
215 
216 	if (rrl->num_entries + newsize >= rrl->max_entries &&
217 	    rrl->max_entries != 0)
218 	{
219 		newsize = rrl->max_entries - rrl->num_entries;
220 		if (newsize <= 0) {
221 			return ISC_R_SUCCESS;
222 		}
223 	}
224 
225 	/*
226 	 * Log expansions so that the user can tune max-table-size
227 	 * and min-table-size.
228 	 */
229 	if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP) && rrl->hash != NULL) {
230 		rate = rrl->probes;
231 		if (rrl->searches != 0) {
232 			rate /= rrl->searches;
233 		}
234 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
235 			      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP,
236 			      "increase from %d to %d RRL entries with"
237 			      " %d bins; average search length %.1f",
238 			      rrl->num_entries, rrl->num_entries + newsize,
239 			      rrl->hash->length, rate);
240 	}
241 
242 	bsize = sizeof(dns_rrl_block_t) +
243 		ISC_CHECKED_MUL((newsize - 1), sizeof(dns_rrl_entry_t));
244 	b = isc_mem_cget(rrl->mctx, 1, bsize);
245 	b->size = bsize;
246 
247 	e = b->entries;
248 	for (i = 0; i < newsize; ++i, ++e) {
249 		ISC_LINK_INIT(e, hlink);
250 		ISC_LIST_INITANDAPPEND(rrl->lru, e, lru);
251 	}
252 	rrl->num_entries += newsize;
253 	ISC_LIST_INITANDAPPEND(rrl->blocks, b, link);
254 
255 	return ISC_R_SUCCESS;
256 }
257 
258 static dns_rrl_bin_t *
259 get_bin(dns_rrl_hash_t *hash, unsigned int hval) {
260 	INSIST(hash != NULL);
261 	return &hash->bins[hval % hash->length];
262 }
263 
264 static void
265 free_old_hash(dns_rrl_t *rrl) {
266 	dns_rrl_hash_t *old_hash;
267 	dns_rrl_bin_t *old_bin;
268 	dns_rrl_entry_t *e, *e_next;
269 
270 	old_hash = rrl->old_hash;
271 	for (old_bin = &old_hash->bins[0];
272 	     old_bin < &old_hash->bins[old_hash->length]; ++old_bin)
273 	{
274 		for (e = ISC_LIST_HEAD(*old_bin); e != NULL; e = e_next) {
275 			e_next = ISC_LIST_NEXT(e, hlink);
276 			ISC_LINK_INIT(e, hlink);
277 		}
278 	}
279 
280 	isc_mem_put(rrl->mctx, old_hash,
281 		    sizeof(*old_hash) +
282 			    ISC_CHECKED_MUL((old_hash->length - 1),
283 					    sizeof(old_hash->bins[0])));
284 	rrl->old_hash = NULL;
285 }
286 
287 static isc_result_t
288 expand_rrl_hash(dns_rrl_t *rrl, isc_stdtime_t now) {
289 	dns_rrl_hash_t *hash;
290 	int old_bins, new_bins, hsize;
291 	double rate;
292 
293 	if (rrl->old_hash != NULL) {
294 		free_old_hash(rrl);
295 	}
296 
297 	/*
298 	 * Most searches fail and so go to the end of the chain.
299 	 * Use a small hash table load factor.
300 	 */
301 	old_bins = (rrl->hash == NULL) ? 0 : rrl->hash->length;
302 	new_bins = old_bins / 8 + old_bins;
303 	if (new_bins < rrl->num_entries) {
304 		new_bins = rrl->num_entries;
305 	}
306 	new_bins = hash_divisor(new_bins);
307 
308 	hsize = sizeof(dns_rrl_hash_t) +
309 		ISC_CHECKED_MUL((new_bins - 1), sizeof(hash->bins[0]));
310 	hash = isc_mem_cget(rrl->mctx, 1, hsize);
311 	hash->length = new_bins;
312 	rrl->hash_gen ^= 1;
313 	hash->gen = rrl->hash_gen;
314 
315 	if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP) && old_bins != 0) {
316 		rate = rrl->probes;
317 		if (rrl->searches != 0) {
318 			rate /= rrl->searches;
319 		}
320 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
321 			      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP,
322 			      "increase from %d to %d RRL bins for"
323 			      " %d entries; average search length %.1f",
324 			      old_bins, new_bins, rrl->num_entries, rate);
325 	}
326 
327 	rrl->old_hash = rrl->hash;
328 	if (rrl->old_hash != NULL) {
329 		rrl->old_hash->check_time = now;
330 	}
331 	rrl->hash = hash;
332 
333 	return ISC_R_SUCCESS;
334 }
335 
336 static void
337 ref_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, int probes, isc_stdtime_t now) {
338 	/*
339 	 * Make the entry most recently used.
340 	 */
341 	if (ISC_LIST_HEAD(rrl->lru) != e) {
342 		if (e == rrl->last_logged) {
343 			rrl->last_logged = ISC_LIST_PREV(e, lru);
344 		}
345 		ISC_LIST_UNLINK(rrl->lru, e, lru);
346 		ISC_LIST_PREPEND(rrl->lru, e, lru);
347 	}
348 
349 	/*
350 	 * Expand the hash table if it is time and necessary.
351 	 * This will leave the newly referenced entry in a chain in the
352 	 * old hash table.  It will migrate to the new hash table the next
353 	 * time it is used or be cut loose when the old hash table is destroyed.
354 	 */
355 	rrl->probes += probes;
356 	++rrl->searches;
357 	if (rrl->searches > 100 &&
358 	    delta_rrl_time(rrl->hash->check_time, now) > 1)
359 	{
360 		if (rrl->probes / rrl->searches > 2) {
361 			expand_rrl_hash(rrl, now);
362 		}
363 		rrl->hash->check_time = now;
364 		rrl->probes = 0;
365 		rrl->searches = 0;
366 	}
367 }
368 
369 static bool
370 key_cmp(const dns_rrl_key_t *a, const dns_rrl_key_t *b) {
371 	if (memcmp(a, b, sizeof(dns_rrl_key_t)) == 0) {
372 		return true;
373 	}
374 	return false;
375 }
376 
377 static uint32_t
378 hash_key(const dns_rrl_key_t *key) {
379 	uint32_t hval;
380 	int i;
381 
382 	hval = key->w[0];
383 	for (i = sizeof(key->w) / sizeof(key->w[0]) - 1; i >= 0; --i) {
384 		hval = key->w[i] + (hval << 1);
385 	}
386 	return hval;
387 }
388 
389 /*
390  * Construct the hash table key.
391  * Use a hash of the DNS query name to save space in the database.
392  * Collisions result in legitimate rate limiting responses for one
393  * query name also limiting responses for other names to the
394  * same client.  This is rare and benign enough given the large
395  * space costs compared to keeping the entire name in the database
396  * entry or the time costs of dynamic allocation.
397  */
398 static void
399 make_key(const dns_rrl_t *rrl, dns_rrl_key_t *key,
400 	 const isc_sockaddr_t *client_addr, dns_zone_t *zone,
401 	 dns_rdatatype_t qtype, const dns_name_t *qname,
402 	 dns_rdataclass_t qclass, dns_rrl_rtype_t rtype) {
403 	int i;
404 
405 	memset(key, 0, sizeof(*key));
406 
407 	key->s.rtype = rtype;
408 	if (rtype == DNS_RRL_RTYPE_QUERY) {
409 		key->s.qtype = qtype;
410 		key->s.qclass = qclass & 0xff;
411 	} else if (rtype == DNS_RRL_RTYPE_REFERRAL ||
412 		   rtype == DNS_RRL_RTYPE_NODATA)
413 	{
414 		/*
415 		 * Because there is no qtype in the empty answer sections of
416 		 * referral and NODATA responses, count them as the same.
417 		 */
418 		key->s.qclass = qclass & 0xff;
419 	}
420 
421 	if (qname != NULL && qname->labels != 0) {
422 		dns_name_t *origin = NULL;
423 
424 		if (qname->attributes.wildcard && zone != NULL &&
425 		    (origin = dns_zone_getorigin(zone)) != NULL)
426 		{
427 			dns_fixedname_t fixed;
428 			dns_name_t *wild;
429 			isc_result_t result;
430 
431 			/*
432 			 * Put all wildcard names in one bucket using the zone's
433 			 * origin name concatenated to the "*" name.
434 			 */
435 			wild = dns_fixedname_initname(&fixed);
436 			result = dns_name_concatenate(dns_wildcardname, origin,
437 						      wild, NULL);
438 			if (result != ISC_R_SUCCESS) {
439 				/*
440 				 * Fallback to use the zone's origin name
441 				 * instead of the concatenated name.
442 				 */
443 				wild = origin;
444 			}
445 			key->s.qname_hash = dns_name_hash(wild);
446 		} else {
447 			key->s.qname_hash = dns_name_hash(qname);
448 		}
449 	}
450 
451 	switch (client_addr->type.sa.sa_family) {
452 	case AF_INET:
453 		key->s.ip[0] = (client_addr->type.sin.sin_addr.s_addr &
454 				rrl->ipv4_mask);
455 		break;
456 	case AF_INET6:
457 		key->s.ipv6 = true;
458 		memmove(key->s.ip, &client_addr->type.sin6.sin6_addr,
459 			sizeof(key->s.ip));
460 		for (i = 0; i < DNS_RRL_MAX_PREFIX / 32; ++i) {
461 			key->s.ip[i] &= rrl->ipv6_mask[i];
462 		}
463 		break;
464 	}
465 }
466 
467 static dns_rrl_rate_t *
468 get_rate(dns_rrl_t *rrl, dns_rrl_rtype_t rtype) {
469 	switch (rtype) {
470 	case DNS_RRL_RTYPE_QUERY:
471 		return &rrl->responses_per_second;
472 	case DNS_RRL_RTYPE_REFERRAL:
473 		return &rrl->referrals_per_second;
474 	case DNS_RRL_RTYPE_NODATA:
475 		return &rrl->nodata_per_second;
476 	case DNS_RRL_RTYPE_NXDOMAIN:
477 		return &rrl->nxdomains_per_second;
478 	case DNS_RRL_RTYPE_ERROR:
479 		return &rrl->errors_per_second;
480 	case DNS_RRL_RTYPE_ALL:
481 		return &rrl->all_per_second;
482 	default:
483 		UNREACHABLE();
484 	}
485 }
486 
487 static int
488 response_balance(dns_rrl_t *rrl, const dns_rrl_entry_t *e, int age) {
489 	dns_rrl_rate_t *ratep;
490 	int balance, rate;
491 
492 	if (e->key.s.rtype == DNS_RRL_RTYPE_TCP) {
493 		rate = 1;
494 	} else {
495 		ratep = get_rate(rrl, e->key.s.rtype);
496 		rate = ratep->scaled;
497 	}
498 
499 	balance = e->responses + age * rate;
500 	if (balance > rate) {
501 		balance = rate;
502 	}
503 	return balance;
504 }
505 
506 /*
507  * Search for an entry for a response and optionally create it.
508  */
509 static dns_rrl_entry_t *
510 get_entry(dns_rrl_t *rrl, const isc_sockaddr_t *client_addr, dns_zone_t *zone,
511 	  dns_rdataclass_t qclass, dns_rdatatype_t qtype,
512 	  const dns_name_t *qname, dns_rrl_rtype_t rtype, isc_stdtime_t now,
513 	  bool create, char *log_buf, unsigned int log_buf_len) {
514 	dns_rrl_key_t key;
515 	uint32_t hval;
516 	dns_rrl_entry_t *e;
517 	dns_rrl_hash_t *hash;
518 	dns_rrl_bin_t *new_bin, *old_bin;
519 	int probes, age;
520 
521 	make_key(rrl, &key, client_addr, zone, qtype, qname, qclass, rtype);
522 	hval = hash_key(&key);
523 
524 	/*
525 	 * Look for the entry in the current hash table.
526 	 */
527 	new_bin = get_bin(rrl->hash, hval);
528 	probes = 1;
529 	e = ISC_LIST_HEAD(*new_bin);
530 	while (e != NULL) {
531 		if (key_cmp(&e->key, &key)) {
532 			ref_entry(rrl, e, probes, now);
533 			return e;
534 		}
535 		++probes;
536 		e = ISC_LIST_NEXT(e, hlink);
537 	}
538 
539 	/*
540 	 * Look in the old hash table.
541 	 */
542 	if (rrl->old_hash != NULL) {
543 		old_bin = get_bin(rrl->old_hash, hval);
544 		e = ISC_LIST_HEAD(*old_bin);
545 		while (e != NULL) {
546 			if (key_cmp(&e->key, &key)) {
547 				ISC_LIST_UNLINK(*old_bin, e, hlink);
548 				ISC_LIST_PREPEND(*new_bin, e, hlink);
549 				e->hash_gen = rrl->hash_gen;
550 				ref_entry(rrl, e, probes, now);
551 				return e;
552 			}
553 			e = ISC_LIST_NEXT(e, hlink);
554 		}
555 
556 		/*
557 		 * Discard previous hash table when all of its entries are old.
558 		 */
559 		age = delta_rrl_time(rrl->old_hash->check_time, now);
560 		if (age > rrl->window) {
561 			free_old_hash(rrl);
562 		}
563 	}
564 
565 	if (!create) {
566 		return NULL;
567 	}
568 
569 	/*
570 	 * The entry does not exist, so create it by finding a free entry.
571 	 * Keep currently penalized and logged entries.
572 	 * Try to make more entries if none are idle.
573 	 * Steal the oldest entry if we cannot create more.
574 	 */
575 	for (e = ISC_LIST_TAIL(rrl->lru); e != NULL; e = ISC_LIST_PREV(e, lru))
576 	{
577 		if (!ISC_LINK_LINKED(e, hlink)) {
578 			break;
579 		}
580 		age = get_age(rrl, e, now);
581 		if (age <= 1) {
582 			e = NULL;
583 			break;
584 		}
585 		if (!e->logged && response_balance(rrl, e, age) > 0) {
586 			break;
587 		}
588 	}
589 	if (e == NULL) {
590 		expand_entries(rrl, ISC_MIN((rrl->num_entries + 1) / 2, 1000));
591 		e = ISC_LIST_TAIL(rrl->lru);
592 	}
593 	if (e->logged) {
594 		log_end(rrl, e, true, log_buf, log_buf_len);
595 	}
596 	if (ISC_LINK_LINKED(e, hlink)) {
597 		if (e->hash_gen == rrl->hash_gen) {
598 			hash = rrl->hash;
599 		} else {
600 			hash = rrl->old_hash;
601 		}
602 		old_bin = get_bin(hash, hash_key(&e->key));
603 		ISC_LIST_UNLINK(*old_bin, e, hlink);
604 	}
605 	ISC_LIST_PREPEND(*new_bin, e, hlink);
606 	e->hash_gen = rrl->hash_gen;
607 	e->key = key;
608 	e->ts_valid = false;
609 	ref_entry(rrl, e, probes, now);
610 	return e;
611 }
612 
613 static void
614 debit_log(const dns_rrl_entry_t *e, int age, const char *action) {
615 	char buf[sizeof("age=2147483647")];
616 	const char *age_str;
617 
618 	if (age == DNS_RRL_FOREVER) {
619 		age_str = "";
620 	} else {
621 		snprintf(buf, sizeof(buf), "age=%d", age);
622 		age_str = buf;
623 	}
624 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, DNS_LOGMODULE_REQUEST,
625 		      DNS_RRL_LOG_DEBUG3, "rrl %08x %6s  responses=%-3d %s",
626 		      hash_key(&e->key), age_str, e->responses, action);
627 }
628 
629 static dns_rrl_result_t
630 debit_rrl_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, double qps, double scale,
631 		const isc_sockaddr_t *client_addr, isc_stdtime_t now,
632 		char *log_buf, unsigned int log_buf_len) {
633 	int rate, new_rate, slip, new_slip, age, log_secs, min;
634 	dns_rrl_rate_t *ratep;
635 	dns_rrl_entry_t const *credit_e;
636 
637 	/*
638 	 * Pick the rate counter.
639 	 * Optionally adjust the rate by the estimated query/second rate.
640 	 */
641 	ratep = get_rate(rrl, e->key.s.rtype);
642 	rate = ratep->r;
643 	if (rate == 0) {
644 		return DNS_RRL_RESULT_OK;
645 	}
646 
647 	if (scale < 1.0) {
648 		/*
649 		 * The limit for clients that have used TCP is not scaled.
650 		 */
651 		credit_e = get_entry(
652 			rrl, client_addr, NULL, 0, dns_rdatatype_none, NULL,
653 			DNS_RRL_RTYPE_TCP, now, false, log_buf, log_buf_len);
654 		if (credit_e != NULL) {
655 			age = get_age(rrl, e, now);
656 			if (age < rrl->window) {
657 				scale = 1.0;
658 			}
659 		}
660 	}
661 	if (scale < 1.0) {
662 		new_rate = (int)(rate * scale);
663 		if (new_rate < 1) {
664 			new_rate = 1;
665 		}
666 		if (ratep->scaled != new_rate) {
667 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
668 				      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1,
669 				      "%d qps scaled %s by %.2f"
670 				      " from %d to %d",
671 				      (int)qps, ratep->str, scale, rate,
672 				      new_rate);
673 			rate = new_rate;
674 			ratep->scaled = rate;
675 		}
676 	}
677 
678 	min = -rrl->window * rate;
679 
680 	/*
681 	 * Treat time jumps into the recent past as no time.
682 	 * Treat entries older than the window as if they were just created
683 	 * Credit other entries.
684 	 */
685 	age = get_age(rrl, e, now);
686 	if (age > 0) {
687 		/*
688 		 * Credit tokens earned during elapsed time.
689 		 */
690 		if (age > rrl->window) {
691 			e->responses = rate;
692 			e->slip_cnt = 0;
693 		} else {
694 			e->responses += rate * age;
695 			if (e->responses > rate) {
696 				e->responses = rate;
697 				e->slip_cnt = 0;
698 			}
699 		}
700 		/*
701 		 * Find the seconds since last log message without overflowing
702 		 * small counter.  This counter is reset when an entry is
703 		 * created.  It is not necessarily reset when some requests
704 		 * are answered provided other requests continue to be dropped
705 		 * or slipped.  This can happen when the request rate is just
706 		 * at the limit.
707 		 */
708 		if (e->logged) {
709 			log_secs = e->log_secs;
710 			log_secs += age;
711 			if (log_secs > DNS_RRL_MAX_LOG_SECS || log_secs < 0) {
712 				log_secs = DNS_RRL_MAX_LOG_SECS;
713 			}
714 			e->log_secs = log_secs;
715 		}
716 	}
717 	set_age(rrl, e, now);
718 
719 	/*
720 	 * Debit the entry for this response.
721 	 */
722 	if (--e->responses >= 0) {
723 		if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) {
724 			debit_log(e, age, "");
725 		}
726 		return DNS_RRL_RESULT_OK;
727 	}
728 
729 	if (e->responses < min) {
730 		e->responses = min;
731 	}
732 
733 	/*
734 	 * Drop this response unless it should slip or leak.
735 	 */
736 	slip = rrl->slip.r;
737 	if (slip > 2 && scale < 1.0) {
738 		new_slip = (int)(slip * scale);
739 		if (new_slip < 2) {
740 			new_slip = 2;
741 		}
742 		if (rrl->slip.scaled != new_slip) {
743 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
744 				      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1,
745 				      "%d qps scaled slip"
746 				      " by %.2f from %d to %d",
747 				      (int)qps, scale, slip, new_slip);
748 			slip = new_slip;
749 			rrl->slip.scaled = slip;
750 		}
751 	}
752 	if (slip != 0 && e->key.s.rtype != DNS_RRL_RTYPE_ALL) {
753 		if (e->slip_cnt++ == 0) {
754 			if ((int)e->slip_cnt >= slip) {
755 				e->slip_cnt = 0;
756 			}
757 			if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) {
758 				debit_log(e, age, "slip");
759 			}
760 			return DNS_RRL_RESULT_SLIP;
761 		} else if ((int)e->slip_cnt >= slip) {
762 			e->slip_cnt = 0;
763 		}
764 	}
765 
766 	if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) {
767 		debit_log(e, age, "drop");
768 	}
769 	return DNS_RRL_RESULT_DROP;
770 }
771 
772 static dns_rrl_qname_buf_t *
773 get_qname(dns_rrl_t *rrl, const dns_rrl_entry_t *e) {
774 	dns_rrl_qname_buf_t *qbuf;
775 
776 	qbuf = rrl->qnames[e->log_qname];
777 	if (qbuf == NULL || qbuf->e != e) {
778 		return NULL;
779 	}
780 	return qbuf;
781 }
782 
783 static void
784 free_qname(dns_rrl_t *rrl, dns_rrl_entry_t *e) {
785 	dns_rrl_qname_buf_t *qbuf;
786 
787 	qbuf = get_qname(rrl, e);
788 	if (qbuf != NULL) {
789 		qbuf->e = NULL;
790 		ISC_LIST_APPEND(rrl->qname_free, qbuf, link);
791 	}
792 }
793 
794 static void
795 add_log_str(isc_buffer_t *lb, const char *str, unsigned int str_len) {
796 	isc_region_t region;
797 
798 	isc_buffer_availableregion(lb, &region);
799 	if (str_len >= region.length) {
800 		if (region.length == 0U) {
801 			return;
802 		}
803 		str_len = region.length;
804 	}
805 	memmove(region.base, str, str_len);
806 	isc_buffer_add(lb, str_len);
807 }
808 
809 #define ADD_LOG_CSTR(eb, s) add_log_str(eb, s, sizeof(s) - 1)
810 
811 /*
812  * Build strings for the logs
813  */
814 static void
815 make_log_buf(dns_rrl_t *rrl, dns_rrl_entry_t *e, const char *str1,
816 	     const char *str2, bool plural, const dns_name_t *qname,
817 	     bool save_qname, dns_rrl_result_t rrl_result,
818 	     isc_result_t resp_result, char *log_buf,
819 	     unsigned int log_buf_len) {
820 	isc_buffer_t lb;
821 	dns_rrl_qname_buf_t *qbuf;
822 	isc_netaddr_t cidr;
823 	char strbuf[ISC_MAX(sizeof("/123"), sizeof("  (12345678)"))];
824 	const char *rstr;
825 	isc_result_t msg_result;
826 
827 	if (log_buf_len <= 1) {
828 		if (log_buf_len == 1) {
829 			log_buf[0] = '\0';
830 		}
831 		return;
832 	}
833 	isc_buffer_init(&lb, log_buf, log_buf_len - 1);
834 
835 	if (str1 != NULL) {
836 		add_log_str(&lb, str1, strlen(str1));
837 	}
838 	if (str2 != NULL) {
839 		add_log_str(&lb, str2, strlen(str2));
840 	}
841 
842 	switch (rrl_result) {
843 	case DNS_RRL_RESULT_OK:
844 		break;
845 	case DNS_RRL_RESULT_DROP:
846 		ADD_LOG_CSTR(&lb, "drop ");
847 		break;
848 	case DNS_RRL_RESULT_SLIP:
849 		ADD_LOG_CSTR(&lb, "slip ");
850 		break;
851 	default:
852 		UNREACHABLE();
853 	}
854 
855 	switch (e->key.s.rtype) {
856 	case DNS_RRL_RTYPE_QUERY:
857 		break;
858 	case DNS_RRL_RTYPE_REFERRAL:
859 		ADD_LOG_CSTR(&lb, "referral ");
860 		break;
861 	case DNS_RRL_RTYPE_NODATA:
862 		ADD_LOG_CSTR(&lb, "NODATA ");
863 		break;
864 	case DNS_RRL_RTYPE_NXDOMAIN:
865 		ADD_LOG_CSTR(&lb, "NXDOMAIN ");
866 		break;
867 	case DNS_RRL_RTYPE_ERROR:
868 		if (resp_result == ISC_R_SUCCESS) {
869 			ADD_LOG_CSTR(&lb, "error ");
870 		} else {
871 			rstr = isc_result_totext(resp_result);
872 			add_log_str(&lb, rstr, strlen(rstr));
873 			ADD_LOG_CSTR(&lb, " error ");
874 		}
875 		break;
876 	case DNS_RRL_RTYPE_ALL:
877 		ADD_LOG_CSTR(&lb, "all ");
878 		break;
879 	default:
880 		UNREACHABLE();
881 	}
882 
883 	if (plural) {
884 		ADD_LOG_CSTR(&lb, "responses to ");
885 	} else {
886 		ADD_LOG_CSTR(&lb, "response to ");
887 	}
888 
889 	memset(&cidr, 0, sizeof(cidr));
890 	if (e->key.s.ipv6) {
891 		snprintf(strbuf, sizeof(strbuf), "/%d", rrl->ipv6_prefixlen);
892 		cidr.family = AF_INET6;
893 		memset(&cidr.type.in6, 0, sizeof(cidr.type.in6));
894 		memmove(&cidr.type.in6, e->key.s.ip, sizeof(e->key.s.ip));
895 	} else {
896 		snprintf(strbuf, sizeof(strbuf), "/%d", rrl->ipv4_prefixlen);
897 		cidr.family = AF_INET;
898 		cidr.type.in.s_addr = e->key.s.ip[0];
899 	}
900 	msg_result = isc_netaddr_totext(&cidr, &lb);
901 	if (msg_result != ISC_R_SUCCESS) {
902 		ADD_LOG_CSTR(&lb, "?");
903 	}
904 	add_log_str(&lb, strbuf, strlen(strbuf));
905 
906 	if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY ||
907 	    e->key.s.rtype == DNS_RRL_RTYPE_REFERRAL ||
908 	    e->key.s.rtype == DNS_RRL_RTYPE_NODATA ||
909 	    e->key.s.rtype == DNS_RRL_RTYPE_NXDOMAIN)
910 	{
911 		qbuf = get_qname(rrl, e);
912 		if (save_qname && qbuf == NULL && qname != NULL &&
913 		    dns_name_isabsolute(qname))
914 		{
915 			/*
916 			 * Capture the qname for the "stop limiting" message.
917 			 */
918 			qbuf = ISC_LIST_TAIL(rrl->qname_free);
919 			if (qbuf != NULL) {
920 				ISC_LIST_UNLINK(rrl->qname_free, qbuf, link);
921 			} else if (rrl->num_qnames < DNS_RRL_QNAMES) {
922 				qbuf = isc_mem_get(rrl->mctx, sizeof(*qbuf));
923 				*qbuf = (dns_rrl_qname_buf_t){
924 					.index = rrl->num_qnames,
925 				};
926 				ISC_LINK_INIT(qbuf, link);
927 				rrl->qnames[rrl->num_qnames++] = qbuf;
928 			}
929 			if (qbuf != NULL) {
930 				e->log_qname = qbuf->index;
931 				qbuf->e = e;
932 				dns_fixedname_init(&qbuf->qname);
933 				dns_name_copy(qname,
934 					      dns_fixedname_name(&qbuf->qname));
935 			}
936 		}
937 		if (qbuf != NULL) {
938 			qname = dns_fixedname_name(&qbuf->qname);
939 		}
940 		if (qname != NULL) {
941 			ADD_LOG_CSTR(&lb, " for ");
942 			(void)dns_name_totext(qname, DNS_NAME_OMITFINALDOT,
943 					      &lb);
944 		} else {
945 			ADD_LOG_CSTR(&lb, " for (?)");
946 		}
947 		if (e->key.s.rtype != DNS_RRL_RTYPE_NXDOMAIN) {
948 			ADD_LOG_CSTR(&lb, " ");
949 			(void)dns_rdataclass_totext(e->key.s.qclass, &lb);
950 			if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY) {
951 				ADD_LOG_CSTR(&lb, " ");
952 				(void)dns_rdatatype_totext(e->key.s.qtype, &lb);
953 			}
954 		}
955 		snprintf(strbuf, sizeof(strbuf), "  (%08" PRIx32 ")",
956 			 e->key.s.qname_hash);
957 		add_log_str(&lb, strbuf, strlen(strbuf));
958 	}
959 
960 	/*
961 	 * We saved room for '\0'.
962 	 */
963 	log_buf[isc_buffer_usedlength(&lb)] = '\0';
964 }
965 
966 static void
967 log_end(dns_rrl_t *rrl, dns_rrl_entry_t *e, bool early, char *log_buf,
968 	unsigned int log_buf_len) {
969 	if (e->logged) {
970 		make_log_buf(rrl, e, early ? "*" : NULL,
971 			     rrl->log_only ? "would stop limiting "
972 					   : "stop limiting ",
973 			     true, NULL, false, DNS_RRL_RESULT_OK,
974 			     ISC_R_SUCCESS, log_buf, log_buf_len);
975 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
976 			      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, "%s",
977 			      log_buf);
978 		free_qname(rrl, e);
979 		e->logged = false;
980 		--rrl->num_logged;
981 	}
982 }
983 
984 /*
985  * Log messages for streams that have stopped being rate limited.
986  */
987 static void
988 log_stops(dns_rrl_t *rrl, isc_stdtime_t now, int limit, char *log_buf,
989 	  unsigned int log_buf_len) {
990 	dns_rrl_entry_t *e;
991 	int age;
992 
993 	for (e = rrl->last_logged; e != NULL; e = ISC_LIST_PREV(e, lru)) {
994 		if (!e->logged) {
995 			continue;
996 		}
997 		if (now != 0) {
998 			age = get_age(rrl, e, now);
999 			if (age < DNS_RRL_STOP_LOG_SECS ||
1000 			    response_balance(rrl, e, age) < 0)
1001 			{
1002 				break;
1003 			}
1004 		}
1005 
1006 		log_end(rrl, e, now == 0, log_buf, log_buf_len);
1007 		if (rrl->num_logged <= 0) {
1008 			break;
1009 		}
1010 
1011 		/*
1012 		 * Too many messages could stall real work.
1013 		 */
1014 		if (--limit < 0) {
1015 			rrl->last_logged = ISC_LIST_PREV(e, lru);
1016 			return;
1017 		}
1018 	}
1019 	if (e == NULL) {
1020 		INSIST(rrl->num_logged == 0);
1021 		rrl->log_stops_time = now;
1022 	}
1023 	rrl->last_logged = e;
1024 }
1025 
1026 /*
1027  * Main rate limit interface.
1028  */
1029 dns_rrl_result_t
1030 dns_rrl(dns_view_t *view, dns_zone_t *zone, const isc_sockaddr_t *client_addr,
1031 	bool is_tcp, dns_rdataclass_t qclass, dns_rdatatype_t qtype,
1032 	const dns_name_t *qname, isc_result_t resp_result, isc_stdtime_t now,
1033 	bool wouldlog, char *log_buf, unsigned int log_buf_len) {
1034 	dns_rrl_t *rrl;
1035 	dns_rrl_rtype_t rtype;
1036 	dns_rrl_entry_t *e;
1037 	isc_netaddr_t netclient;
1038 	int secs;
1039 	double qps, scale;
1040 	int exempt_match;
1041 	isc_result_t result;
1042 	dns_rrl_result_t rrl_result;
1043 
1044 	INSIST(log_buf != NULL && log_buf_len > 0);
1045 
1046 	rrl = view->rrl;
1047 	if (rrl->exempt != NULL) {
1048 		isc_netaddr_fromsockaddr(&netclient, client_addr);
1049 		result = dns_acl_match(&netclient, NULL, rrl->exempt,
1050 				       view->aclenv, &exempt_match, NULL);
1051 		if (result == ISC_R_SUCCESS && exempt_match > 0) {
1052 			return DNS_RRL_RESULT_OK;
1053 		}
1054 	}
1055 
1056 	LOCK(&rrl->lock);
1057 
1058 	/*
1059 	 * Estimate total query per second rate when scaling by qps.
1060 	 */
1061 	if (rrl->qps_scale == 0) {
1062 		qps = 0.0;
1063 		scale = 1.0;
1064 	} else {
1065 		++rrl->qps_responses;
1066 		secs = delta_rrl_time(rrl->qps_time, now);
1067 		if (secs <= 0) {
1068 			qps = rrl->qps;
1069 		} else {
1070 			qps = (1.0 * rrl->qps_responses) / secs;
1071 			if (secs >= rrl->window) {
1072 				if (isc_log_wouldlog(dns_lctx,
1073 						     DNS_RRL_LOG_DEBUG3))
1074 				{
1075 					isc_log_write(dns_lctx,
1076 						      DNS_LOGCATEGORY_RRL,
1077 						      DNS_LOGMODULE_REQUEST,
1078 						      DNS_RRL_LOG_DEBUG3,
1079 						      "%d responses/%d seconds"
1080 						      " = %d qps",
1081 						      rrl->qps_responses, secs,
1082 						      (int)qps);
1083 				}
1084 				rrl->qps = qps;
1085 				rrl->qps_responses = 0;
1086 				rrl->qps_time = now;
1087 			} else if (qps < rrl->qps) {
1088 				qps = rrl->qps;
1089 			}
1090 		}
1091 		scale = rrl->qps_scale / qps;
1092 	}
1093 
1094 	/*
1095 	 * Do maintenance once per second.
1096 	 */
1097 	if (rrl->num_logged > 0 && rrl->log_stops_time != now) {
1098 		log_stops(rrl, now, 8, log_buf, log_buf_len);
1099 	}
1100 
1101 	/*
1102 	 * Notice TCP responses when scaling limits by qps.
1103 	 * Do not try to rate limit TCP responses.
1104 	 */
1105 	if (is_tcp) {
1106 		if (scale < 1.0) {
1107 			e = get_entry(rrl, client_addr, NULL, 0,
1108 				      dns_rdatatype_none, NULL,
1109 				      DNS_RRL_RTYPE_TCP, now, true, log_buf,
1110 				      log_buf_len);
1111 			if (e != NULL) {
1112 				e->responses = -(rrl->window + 1);
1113 				set_age(rrl, e, now);
1114 			}
1115 		}
1116 		UNLOCK(&rrl->lock);
1117 		return DNS_RRL_RESULT_OK;
1118 	}
1119 
1120 	/*
1121 	 * Find the right kind of entry, creating it if necessary.
1122 	 * If that is impossible, then nothing more can be done
1123 	 */
1124 	switch (resp_result) {
1125 	case ISC_R_SUCCESS:
1126 		rtype = DNS_RRL_RTYPE_QUERY;
1127 		break;
1128 	case DNS_R_DELEGATION:
1129 		rtype = DNS_RRL_RTYPE_REFERRAL;
1130 		break;
1131 	case DNS_R_NXRRSET:
1132 		rtype = DNS_RRL_RTYPE_NODATA;
1133 		break;
1134 	case DNS_R_NXDOMAIN:
1135 		rtype = DNS_RRL_RTYPE_NXDOMAIN;
1136 		break;
1137 	default:
1138 		rtype = DNS_RRL_RTYPE_ERROR;
1139 		break;
1140 	}
1141 	e = get_entry(rrl, client_addr, zone, qclass, qtype, qname, rtype, now,
1142 		      true, log_buf, log_buf_len);
1143 	if (e == NULL) {
1144 		UNLOCK(&rrl->lock);
1145 		return DNS_RRL_RESULT_OK;
1146 	}
1147 
1148 	if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG1)) {
1149 		/*
1150 		 * Do not worry about speed or releasing the lock.
1151 		 * This message appears before messages from debit_rrl_entry().
1152 		 */
1153 		make_log_buf(rrl, e, "consider limiting ", NULL, false, qname,
1154 			     false, DNS_RRL_RESULT_OK, resp_result, log_buf,
1155 			     log_buf_len);
1156 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
1157 			      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1, "%s",
1158 			      log_buf);
1159 	}
1160 
1161 	rrl_result = debit_rrl_entry(rrl, e, qps, scale, client_addr, now,
1162 				     log_buf, log_buf_len);
1163 
1164 	if (rrl->all_per_second.r != 0) {
1165 		/*
1166 		 * We must debit the all-per-second token bucket if we have
1167 		 * an all-per-second limit for the IP address.
1168 		 * The all-per-second limit determines the log message
1169 		 * when both limits are hit.
1170 		 * The response limiting must continue if the
1171 		 * all-per-second limiting lapses.
1172 		 */
1173 		dns_rrl_entry_t *e_all;
1174 		dns_rrl_result_t rrl_all_result;
1175 
1176 		e_all = get_entry(rrl, client_addr, zone, 0, dns_rdatatype_none,
1177 				  NULL, DNS_RRL_RTYPE_ALL, now, true, log_buf,
1178 				  log_buf_len);
1179 		if (e_all == NULL) {
1180 			UNLOCK(&rrl->lock);
1181 			return DNS_RRL_RESULT_OK;
1182 		}
1183 		rrl_all_result = debit_rrl_entry(rrl, e_all, qps, scale,
1184 						 client_addr, now, log_buf,
1185 						 log_buf_len);
1186 		if (rrl_all_result != DNS_RRL_RESULT_OK) {
1187 			e = e_all;
1188 			rrl_result = rrl_all_result;
1189 			if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG1)) {
1190 				make_log_buf(rrl, e,
1191 					     "prefer all-per-second limiting ",
1192 					     NULL, true, qname, false,
1193 					     DNS_RRL_RESULT_OK, resp_result,
1194 					     log_buf, log_buf_len);
1195 				isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
1196 					      DNS_LOGMODULE_REQUEST,
1197 					      DNS_RRL_LOG_DEBUG1, "%s",
1198 					      log_buf);
1199 			}
1200 		}
1201 	}
1202 
1203 	if (rrl_result == DNS_RRL_RESULT_OK) {
1204 		UNLOCK(&rrl->lock);
1205 		return DNS_RRL_RESULT_OK;
1206 	}
1207 
1208 	/*
1209 	 * Log occasionally in the rate-limit category.
1210 	 */
1211 	if ((!e->logged || e->log_secs >= DNS_RRL_MAX_LOG_SECS) &&
1212 	    isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP))
1213 	{
1214 		make_log_buf(rrl, e, rrl->log_only ? "would " : NULL,
1215 			     e->logged ? "continue limiting " : "limit ", true,
1216 			     qname, true, DNS_RRL_RESULT_OK, resp_result,
1217 			     log_buf, log_buf_len);
1218 		if (!e->logged) {
1219 			e->logged = true;
1220 			if (++rrl->num_logged <= 1) {
1221 				rrl->last_logged = e;
1222 			}
1223 		}
1224 		e->log_secs = 0;
1225 
1226 		/*
1227 		 * Avoid holding the lock.
1228 		 */
1229 		if (!wouldlog) {
1230 			UNLOCK(&rrl->lock);
1231 			e = NULL;
1232 		}
1233 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
1234 			      DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, "%s",
1235 			      log_buf);
1236 	}
1237 
1238 	/*
1239 	 * Make a log message for the caller.
1240 	 */
1241 	if (wouldlog) {
1242 		make_log_buf(rrl, e,
1243 			     rrl->log_only ? "would rate limit "
1244 					   : "rate limit ",
1245 			     NULL, false, qname, false, rrl_result, resp_result,
1246 			     log_buf, log_buf_len);
1247 	}
1248 
1249 	if (e != NULL) {
1250 		/*
1251 		 * Do not save the qname unless we might need it for
1252 		 * the ending log message.
1253 		 */
1254 		if (!e->logged) {
1255 			free_qname(rrl, e);
1256 		}
1257 		UNLOCK(&rrl->lock);
1258 	}
1259 
1260 	return rrl_result;
1261 }
1262 
1263 void
1264 dns_rrl_view_destroy(dns_view_t *view) {
1265 	dns_rrl_t *rrl;
1266 	dns_rrl_block_t *b;
1267 	dns_rrl_hash_t *h;
1268 	char log_buf[DNS_RRL_LOG_BUF_LEN];
1269 	int i;
1270 
1271 	rrl = view->rrl;
1272 	if (rrl == NULL) {
1273 		return;
1274 	}
1275 	view->rrl = NULL;
1276 
1277 	/*
1278 	 * Assume the caller takes care of locking the view and anything else.
1279 	 */
1280 
1281 	if (rrl->num_logged > 0) {
1282 		log_stops(rrl, 0, INT32_MAX, log_buf, sizeof(log_buf));
1283 	}
1284 
1285 	for (i = 0; i < DNS_RRL_QNAMES; ++i) {
1286 		if (rrl->qnames[i] == NULL) {
1287 			break;
1288 		}
1289 		isc_mem_put(rrl->mctx, rrl->qnames[i], sizeof(*rrl->qnames[i]));
1290 	}
1291 
1292 	if (rrl->exempt != NULL) {
1293 		dns_acl_detach(&rrl->exempt);
1294 	}
1295 
1296 	isc_mutex_destroy(&rrl->lock);
1297 
1298 	while (!ISC_LIST_EMPTY(rrl->blocks)) {
1299 		b = ISC_LIST_HEAD(rrl->blocks);
1300 		ISC_LIST_UNLINK(rrl->blocks, b, link);
1301 		isc_mem_put(rrl->mctx, b, b->size);
1302 	}
1303 
1304 	h = rrl->hash;
1305 	if (h != NULL) {
1306 		isc_mem_put(rrl->mctx, h,
1307 			    sizeof(*h) + ISC_CHECKED_MUL((h->length - 1),
1308 							 sizeof(h->bins[0])));
1309 	}
1310 
1311 	h = rrl->old_hash;
1312 	if (h != NULL) {
1313 		isc_mem_put(rrl->mctx, h,
1314 			    sizeof(*h) + ISC_CHECKED_MUL((h->length - 1),
1315 							 sizeof(h->bins[0])));
1316 	}
1317 
1318 	isc_mem_putanddetach(&rrl->mctx, rrl, sizeof(*rrl));
1319 }
1320 
1321 isc_result_t
1322 dns_rrl_init(dns_rrl_t **rrlp, dns_view_t *view, int min_entries) {
1323 	dns_rrl_t *rrl;
1324 	isc_result_t result;
1325 
1326 	*rrlp = NULL;
1327 
1328 	rrl = isc_mem_get(view->mctx, sizeof(*rrl));
1329 	*rrl = (dns_rrl_t){
1330 		.ts_bases[0] = isc_stdtime_now(),
1331 	};
1332 	isc_mem_attach(view->mctx, &rrl->mctx);
1333 	isc_mutex_init(&rrl->lock);
1334 
1335 	view->rrl = rrl;
1336 
1337 	result = expand_entries(rrl, min_entries);
1338 	if (result != ISC_R_SUCCESS) {
1339 		dns_rrl_view_destroy(view);
1340 		return result;
1341 	}
1342 	result = expand_rrl_hash(rrl, 0);
1343 	if (result != ISC_R_SUCCESS) {
1344 		dns_rrl_view_destroy(view);
1345 		return result;
1346 	}
1347 
1348 	*rrlp = rrl;
1349 	return ISC_R_SUCCESS;
1350 }
1351