Coverage Report

Created: 2025-12-12 06:31

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