[BACK]Return to rrl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / mpl / bind / dist / lib / dns

Annotation of src/external/mpl/bind/dist/lib/dns/rrl.c, Revision 1.3

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

CVSweb <webmaster@jp.NetBSD.org>