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, ®ion); 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