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