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