Coverage Report

Created: 2023-02-27 07:33

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