mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-05 04:52:05 -04:00
[9.18] fix: usr: Improve the resolver performance under attack
A remote client can force the DNS resolver component to consume the memory faster than cleaning up the resources for the canceled resolver fetches due to `recursive-clients` limit. If the such traffic pattern is sustained for a long period of time, the DNS server might eventually run out of the available memory. This has been fixed. It should be noted that when under such heavy attack for BIND 9 version both with and without the fix, no outgoing DNS queries will be successful as the generated traffic pattern will consume all the available slots for the recursive clients. Merge branch '5110-backport-the-hashtable-use-for-fetchcontexts-9.18' into 'bind-9.18' See merge request isc-projects/bind9!9961
This commit is contained in:
commit
2c667bc9c6
3 changed files with 299 additions and 102 deletions
|
|
@ -155,8 +155,6 @@
|
|||
#define SIZE_AS_PERCENT ((size_t)-2)
|
||||
#endif /* ifndef SIZE_AS_PERCENT */
|
||||
|
||||
#define RESOLVER_NTASKS 523
|
||||
|
||||
/* RFC7828 defines timeout as 16-bit value specified in units of 100
|
||||
* milliseconds, so the maximum and minimum advertised and keepalive
|
||||
* timeouts are capped by the data type (it's ~109 minutes)
|
||||
|
|
@ -503,6 +501,104 @@ static isc_result_t
|
|||
nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
|
||||
#endif /* ifdef HAVE_LMDB */
|
||||
|
||||
static const uint32_t primes[] = {
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
|
||||
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
|
||||
97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
|
||||
157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
|
||||
227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
|
||||
283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
|
||||
367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433,
|
||||
439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
|
||||
509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593,
|
||||
599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
|
||||
661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,
|
||||
751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827,
|
||||
829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
|
||||
919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
|
||||
1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
|
||||
1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
|
||||
1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249,
|
||||
1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321,
|
||||
1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439,
|
||||
1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
|
||||
1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601,
|
||||
1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693,
|
||||
1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783,
|
||||
1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
|
||||
1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
|
||||
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069,
|
||||
2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143,
|
||||
2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267,
|
||||
2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347,
|
||||
2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423,
|
||||
2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543,
|
||||
2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657,
|
||||
2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713,
|
||||
2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801,
|
||||
2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903,
|
||||
2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011,
|
||||
3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119,
|
||||
3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221,
|
||||
3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323,
|
||||
3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413,
|
||||
3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527,
|
||||
3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
|
||||
3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697,
|
||||
3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797,
|
||||
3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907,
|
||||
3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003,
|
||||
4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093,
|
||||
4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211,
|
||||
4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283,
|
||||
4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
|
||||
4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513,
|
||||
4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621,
|
||||
4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721,
|
||||
4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813,
|
||||
4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
|
||||
4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011,
|
||||
5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113,
|
||||
5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233,
|
||||
5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351,
|
||||
5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443,
|
||||
5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531,
|
||||
5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653,
|
||||
5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743,
|
||||
5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849,
|
||||
5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939,
|
||||
5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073,
|
||||
6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173,
|
||||
6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271,
|
||||
6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359,
|
||||
6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473,
|
||||
6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581,
|
||||
6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701,
|
||||
6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803,
|
||||
6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907,
|
||||
6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997,
|
||||
7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121,
|
||||
7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229,
|
||||
7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349,
|
||||
7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487,
|
||||
7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561,
|
||||
7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669,
|
||||
7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757,
|
||||
7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879,
|
||||
7883, 7901, 7907, 7919,
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
closest_prime(uint32_t n) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(primes); i++) {
|
||||
if (primes[i] >= n) {
|
||||
return primes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return primes[ARRAY_SIZE(primes) - 1];
|
||||
}
|
||||
|
||||
/*%
|
||||
* Configure a single view ACL at '*aclp'. Get its configuration from
|
||||
* 'vconfig' (for per-view configuration) and maybe from 'config'
|
||||
|
|
@ -4221,7 +4317,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
named_cache_t *nsc;
|
||||
bool zero_no_soattl;
|
||||
dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
|
||||
unsigned int query_timeout, ndisp;
|
||||
unsigned int query_timeout, ndisp, ntasks;
|
||||
bool old_rpz_ok = false;
|
||||
dns_dyndbctx_t *dctx = NULL;
|
||||
unsigned int resolver_param;
|
||||
|
|
@ -4880,10 +4976,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
}
|
||||
dns_view_setresquerystats(view, resquerystats);
|
||||
|
||||
ntasks = closest_prime(2 * named_g_cpus);
|
||||
ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
|
||||
CHECK(dns_view_createresolver(view, named_g_taskmgr, RESOLVER_NTASKS,
|
||||
ndisp, named_g_netmgr, named_g_timermgr,
|
||||
resopts, named_g_dispatchmgr, dispatch4,
|
||||
CHECK(dns_view_createresolver(view, named_g_taskmgr, ntasks, ndisp,
|
||||
named_g_netmgr, named_g_timermgr, resopts,
|
||||
named_g_dispatchmgr, dispatch4,
|
||||
dispatch6));
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -60,8 +60,6 @@
|
|||
#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
|
||||
#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
|
||||
|
||||
#define RESOLVER_NTASKS 523
|
||||
|
||||
#define CHECK(r) \
|
||||
do { \
|
||||
result = (r); \
|
||||
|
|
@ -328,9 +326,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
|
|||
isc_refcount_init(&client->references, 1);
|
||||
|
||||
/* Create the default view for class IN */
|
||||
result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS,
|
||||
nm, timermgr, client->dispatchmgr, dispatchv4,
|
||||
dispatchv6, &view);
|
||||
result = createview(mctx, dns_rdataclass_in, taskmgr, 1, nm, timermgr,
|
||||
client->dispatchmgr, dispatchv4, dispatchv6, &view);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_references;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/counter.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/ht.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/print.h>
|
||||
#include <isc/random.h>
|
||||
|
|
@ -327,6 +329,7 @@ struct fetchctx {
|
|||
unsigned int options;
|
||||
unsigned int bucketnum;
|
||||
unsigned int dbucketnum;
|
||||
bool hashed;
|
||||
char *info;
|
||||
isc_mem_t *mctx;
|
||||
isc_stdtime_t now;
|
||||
|
|
@ -341,7 +344,6 @@ struct fetchctx {
|
|||
bool cloned;
|
||||
bool spilled;
|
||||
isc_event_t control_event;
|
||||
ISC_LINK(struct fetchctx) link;
|
||||
ISC_LIST(dns_fetchevent_t) events;
|
||||
|
||||
/*% Locked by task event serialization. */
|
||||
|
|
@ -514,10 +516,14 @@ struct dns_fetch {
|
|||
#define DNS_FETCH_MAGIC ISC_MAGIC('F', 't', 'c', 'h')
|
||||
#define DNS_FETCH_VALID(fetch) ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
|
||||
|
||||
#define DNS_FCTX_KEYSIZE \
|
||||
(DNS_NAME_MAXWIRE + sizeof(dns_rdatatype_t) + sizeof(unsigned int))
|
||||
|
||||
typedef struct fctxbucket {
|
||||
isc_task_t *task;
|
||||
isc_mutex_t lock;
|
||||
ISC_LIST(fetchctx_t) fctxs;
|
||||
isc_refcount_t nfctxs;
|
||||
isc_ht_t *fctxs;
|
||||
atomic_bool exiting;
|
||||
} fctxbucket_t;
|
||||
|
||||
|
|
@ -529,12 +535,11 @@ struct fctxcount {
|
|||
uint32_t allowed;
|
||||
uint32_t dropped;
|
||||
isc_stdtime_t logged;
|
||||
ISC_LINK(fctxcount_t) link;
|
||||
};
|
||||
|
||||
typedef struct zonebucket {
|
||||
isc_mutex_t lock;
|
||||
ISC_LIST(fctxcount_t) list;
|
||||
isc_ht_t *counters;
|
||||
} zonebucket_t;
|
||||
|
||||
typedef struct alternate {
|
||||
|
|
@ -603,9 +608,6 @@ struct dns_resolver {
|
|||
|
||||
/* Locked by primelock. */
|
||||
dns_fetch_t *primefetch;
|
||||
|
||||
/* Atomic. */
|
||||
atomic_uint_fast32_t nfctx;
|
||||
};
|
||||
|
||||
#define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!')
|
||||
|
|
@ -1623,6 +1625,25 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter, bool final) {
|
|||
counter->logged = now;
|
||||
}
|
||||
|
||||
static void
|
||||
fcount_makekey(const dns_name_t *name, uint8_t *key, size_t *keysizep) {
|
||||
REQUIRE(*keysizep >= name->length);
|
||||
|
||||
size_t keysize = 0;
|
||||
isc_buffer_t buffer;
|
||||
dns_name_t downname;
|
||||
isc_result_t result;
|
||||
|
||||
DNS_NAME_INIT(&downname, NULL);
|
||||
isc_buffer_init(&buffer, key, *keysizep);
|
||||
|
||||
result = dns_name_downcase(name, &downname, &buffer);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
keysize += isc_buffer_usedlength(&buffer);
|
||||
|
||||
*keysizep = keysize;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
fcount_incr(fetchctx_t *fctx, bool force) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
|
@ -1630,6 +1651,9 @@ fcount_incr(fetchctx_t *fctx, bool force) {
|
|||
fctxcount_t *counter = NULL;
|
||||
uint32_t hashval;
|
||||
uint32_t dbucketnum;
|
||||
uint8_t key[DNS_NAME_MAXWIRE];
|
||||
size_t keysize = sizeof(key);
|
||||
uint_fast32_t spill;
|
||||
|
||||
REQUIRE(fctx != NULL);
|
||||
REQUIRE(fctx->res != NULL);
|
||||
|
|
@ -1641,15 +1665,14 @@ fcount_incr(fetchctx_t *fctx, bool force) {
|
|||
dbucket = &fctx->res->dbuckets[dbucketnum];
|
||||
|
||||
LOCK(&dbucket->lock);
|
||||
for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL;
|
||||
counter = ISC_LIST_NEXT(counter, link))
|
||||
{
|
||||
if (dns_name_equal(counter->domain, fctx->domain)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter == NULL) {
|
||||
fcount_makekey(fctx->domain, key, &keysize);
|
||||
|
||||
result = isc_ht_find(dbucket->counters, key, keysize,
|
||||
(void **)&counter);
|
||||
|
||||
switch (result) {
|
||||
case ISC_R_NOTFOUND:
|
||||
counter = isc_mem_get(fctx->res->mctx, sizeof(*counter));
|
||||
*counter = (fctxcount_t){
|
||||
.count = 1,
|
||||
|
|
@ -1657,11 +1680,11 @@ fcount_incr(fetchctx_t *fctx, bool force) {
|
|||
};
|
||||
|
||||
counter->domain = dns_fixedname_initname(&counter->dfname);
|
||||
ISC_LINK_INIT(counter, link);
|
||||
dns_name_copy(fctx->domain, counter->domain);
|
||||
ISC_LIST_APPEND(dbucket->list, counter, link);
|
||||
} else {
|
||||
uint_fast32_t spill = atomic_load_acquire(&fctx->res->zspill);
|
||||
result = isc_ht_add(dbucket->counters, key, keysize, counter);
|
||||
break;
|
||||
case ISC_R_SUCCESS:
|
||||
spill = atomic_load_acquire(&fctx->res->zspill);
|
||||
if (!force && spill != 0 && counter->count >= spill) {
|
||||
counter->dropped++;
|
||||
fcount_logspill(fctx, counter, false);
|
||||
|
|
@ -1670,6 +1693,9 @@ fcount_incr(fetchctx_t *fctx, bool force) {
|
|||
counter->count++;
|
||||
counter->allowed++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNLOCK(&dbucket->lock);
|
||||
|
||||
|
|
@ -1684,6 +1710,9 @@ static void
|
|||
fcount_decr(fetchctx_t *fctx) {
|
||||
zonebucket_t *dbucket = NULL;
|
||||
fctxcount_t *counter = NULL;
|
||||
uint8_t key[DNS_NAME_MAXWIRE];
|
||||
size_t keysize = sizeof(key);
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(fctx != NULL);
|
||||
|
||||
|
|
@ -1694,24 +1723,22 @@ fcount_decr(fetchctx_t *fctx) {
|
|||
dbucket = &fctx->res->dbuckets[fctx->dbucketnum];
|
||||
|
||||
LOCK(&dbucket->lock);
|
||||
for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL;
|
||||
counter = ISC_LIST_NEXT(counter, link))
|
||||
{
|
||||
if (dns_name_equal(counter->domain, fctx->domain)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter != NULL) {
|
||||
INSIST(counter->count != 0);
|
||||
counter->count--;
|
||||
fctx->dbucketnum = RES_NOBUCKET;
|
||||
fcount_makekey(fctx->domain, key, &keysize);
|
||||
|
||||
if (counter->count == 0) {
|
||||
fcount_logspill(fctx, counter, true);
|
||||
ISC_LIST_UNLINK(dbucket->list, counter, link);
|
||||
isc_mem_put(fctx->res->mctx, counter, sizeof(*counter));
|
||||
}
|
||||
result = isc_ht_find(dbucket->counters, key, keysize,
|
||||
(void **)&counter);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
INSIST(counter->count != 0);
|
||||
counter->count--;
|
||||
fctx->dbucketnum = RES_NOBUCKET;
|
||||
|
||||
if (counter->count == 0) {
|
||||
fcount_logspill(fctx, counter, true);
|
||||
result = isc_ht_delete(dbucket->counters, key, keysize);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
isc_mem_put(fctx->res->mctx, counter, sizeof(*counter));
|
||||
}
|
||||
|
||||
UNLOCK(&dbucket->lock);
|
||||
|
|
@ -1830,6 +1857,73 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) {
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fctx_makekey(const dns_name_t *name, dns_rdatatype_t type, unsigned int options,
|
||||
uint8_t *key, size_t *keysizep) {
|
||||
REQUIRE(*keysizep >= name->length + sizeof(type) + sizeof(options));
|
||||
|
||||
size_t keysize = 0;
|
||||
isc_buffer_t buffer;
|
||||
dns_name_t downname;
|
||||
isc_result_t result;
|
||||
|
||||
DNS_NAME_INIT(&downname, NULL);
|
||||
isc_buffer_init(&buffer, key, *keysizep);
|
||||
|
||||
result = dns_name_downcase(name, &downname, &buffer);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
keysize += isc_buffer_usedlength(&buffer);
|
||||
|
||||
memmove(&key[keysize], &type, sizeof(type));
|
||||
keysize += sizeof(type);
|
||||
|
||||
memmove(&key[keysize], &options, sizeof(options));
|
||||
keysize += sizeof(options);
|
||||
|
||||
*keysizep = keysize;
|
||||
}
|
||||
|
||||
static void
|
||||
fctx_unhash(fetchctx_t *fctx) {
|
||||
dns_resolver_t *res = fctx->res;
|
||||
unsigned int bucketnum = fctx->bucketnum;
|
||||
uint8_t key[DNS_FCTX_KEYSIZE] = { 0 };
|
||||
size_t keysize = sizeof(key);
|
||||
isc_result_t result;
|
||||
|
||||
if (!fctx->hashed) {
|
||||
return;
|
||||
}
|
||||
|
||||
fctx_makekey(fctx->name, fctx->type, fctx->options, key, &keysize);
|
||||
|
||||
result = isc_ht_delete(res->buckets[bucketnum].fctxs, key, keysize);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
fctx->hashed = false;
|
||||
}
|
||||
|
||||
static void
|
||||
fctx_hash(fetchctx_t *fctx) {
|
||||
dns_resolver_t *res = fctx->res;
|
||||
unsigned int bucketnum = fctx->bucketnum;
|
||||
uint8_t key[DNS_FCTX_KEYSIZE] = { 0 };
|
||||
size_t keysize = sizeof(key);
|
||||
isc_result_t result;
|
||||
bool unshared = ((fctx->options & DNS_FETCHOPT_UNSHARED) != 0);
|
||||
|
||||
if (unshared) {
|
||||
return;
|
||||
}
|
||||
|
||||
fctx_makekey(fctx->name, fctx->type, fctx->options, key, &keysize);
|
||||
|
||||
result = isc_ht_add(res->buckets[bucketnum].fctxs, key, keysize, fctx);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
fctx->hashed = true;
|
||||
}
|
||||
|
||||
static void
|
||||
fctx__done_detach(fetchctx_t **fctxp, isc_result_t result, const char *file,
|
||||
unsigned int line, const char *func) {
|
||||
|
|
@ -1857,6 +1951,7 @@ fctx__done_detach(fetchctx_t **fctxp, isc_result_t result, const char *file,
|
|||
LOCK(&res->buckets[fctx->bucketnum].lock);
|
||||
INSIST(fctx->state != fetchstate_done);
|
||||
fctx->state = fetchstate_done;
|
||||
fctx_unhash(fctx);
|
||||
UNLOCK(&res->buckets[fctx->bucketnum].lock);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
|
|
@ -2089,6 +2184,10 @@ resquery_timeout(resquery_t *query) {
|
|||
event->result = ISC_R_TIMEDOUT;
|
||||
isc_task_sendanddetach(&sender, ISC_EVENT_PTR(&event));
|
||||
}
|
||||
|
||||
if (ISC_LIST_EMPTY(fctx->events)) {
|
||||
fctx_unhash(fctx);
|
||||
}
|
||||
UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
|
||||
|
||||
/*
|
||||
|
|
@ -4481,7 +4580,6 @@ fctx_destroy(fetchctx_t *fctx, bool exiting) {
|
|||
struct tried *tried = NULL;
|
||||
unsigned int bucketnum;
|
||||
bool bucket_empty = false;
|
||||
uint_fast32_t nfctx;
|
||||
|
||||
REQUIRE(VALID_FCTX(fctx));
|
||||
REQUIRE(ISC_LIST_EMPTY(fctx->events));
|
||||
|
|
@ -4501,18 +4599,19 @@ fctx_destroy(fetchctx_t *fctx, bool exiting) {
|
|||
LOCK(&res->buckets[bucketnum].lock);
|
||||
REQUIRE(fctx->state != fetchstate_active);
|
||||
|
||||
ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
|
||||
fctx_unhash(fctx);
|
||||
|
||||
nfctx = atomic_fetch_sub_release(&res->nfctx, 1);
|
||||
INSIST(nfctx > 0);
|
||||
|
||||
dec_stats(res, dns_resstatscounter_nfetch);
|
||||
INSIST(res->buckets[bucketnum].nfctxs > 0);
|
||||
res->buckets[bucketnum].nfctxs--;
|
||||
|
||||
if (atomic_load_acquire(&res->buckets[bucketnum].exiting) &&
|
||||
ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
|
||||
res->buckets[bucketnum].nfctxs == 0)
|
||||
{
|
||||
bucket_empty = true;
|
||||
}
|
||||
|
||||
dec_stats(res, dns_resstatscounter_nfetch);
|
||||
|
||||
UNLOCK(&res->buckets[bucketnum].lock);
|
||||
|
||||
if (bucket_empty && exiting &&
|
||||
|
|
@ -4654,6 +4753,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
|
|||
|
||||
if (fctx->state == fetchstate_active) {
|
||||
fctx->state = fetchstate_done;
|
||||
fctx_unhash(fctx);
|
||||
|
||||
fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__);
|
||||
|
||||
|
|
@ -4828,7 +4928,6 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
|
|||
isc_interval_t interval;
|
||||
unsigned int findoptions = 0;
|
||||
char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 1];
|
||||
uint_fast32_t nfctx;
|
||||
size_t p;
|
||||
|
||||
/*
|
||||
|
|
@ -5110,7 +5209,6 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
|
|||
isc_mem_attach(res->mctx, &fctx->mctx);
|
||||
|
||||
ISC_LIST_INIT(fctx->events);
|
||||
ISC_LINK_INIT(fctx, link);
|
||||
fctx->magic = FCTX_MAGIC;
|
||||
|
||||
/*
|
||||
|
|
@ -5124,10 +5222,9 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
|
|||
fctx_minimize_qname(fctx);
|
||||
}
|
||||
|
||||
ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
|
||||
fctx_hash(fctx);
|
||||
|
||||
nfctx = atomic_fetch_add_relaxed(&res->nfctx, 1);
|
||||
INSIST(nfctx < UINT32_MAX);
|
||||
res->buckets[bucketnum].nfctxs++;
|
||||
|
||||
inc_stats(res, dns_resstatscounter_nfetch);
|
||||
|
||||
|
|
@ -5334,6 +5431,7 @@ clone_results(fetchctx_t *fctx) {
|
|||
* Caller must be holding the appropriate lock.
|
||||
*/
|
||||
|
||||
fctx_unhash(fctx);
|
||||
fctx->cloned = true;
|
||||
|
||||
for (event = ISC_LIST_HEAD(fctx->events); event != NULL;
|
||||
|
|
@ -10356,12 +10454,12 @@ destroy(dns_resolver_t *res) {
|
|||
|
||||
RTRACE("destroy");
|
||||
|
||||
REQUIRE(atomic_load_acquire(&res->nfctx) == 0);
|
||||
|
||||
isc_mutex_destroy(&res->primelock);
|
||||
isc_mutex_destroy(&res->lock);
|
||||
for (i = 0; i < res->nbuckets; i++) {
|
||||
INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
|
||||
INSIST(res->buckets[i].nfctxs == 0);
|
||||
INSIST(isc_ht_count(res->buckets[i].fctxs) == 0);
|
||||
isc_ht_destroy(&res->buckets[i].fctxs);
|
||||
isc_task_shutdown(res->buckets[i].task);
|
||||
isc_task_detach(&res->buckets[i].task);
|
||||
isc_mutex_destroy(&res->buckets[i].lock);
|
||||
|
|
@ -10369,7 +10467,8 @@ destroy(dns_resolver_t *res) {
|
|||
isc_mem_put(res->mctx, res->buckets,
|
||||
res->nbuckets * sizeof(fctxbucket_t));
|
||||
for (i = 0; i < HASHSIZE(res->dhashbits); i++) {
|
||||
INSIST(ISC_LIST_EMPTY(res->dbuckets[i].list));
|
||||
INSIST(isc_ht_count(res->dbuckets[i].counters) == 0);
|
||||
isc_ht_destroy(&res->dbuckets[i].counters);
|
||||
isc_mutex_destroy(&res->dbuckets[i].lock);
|
||||
}
|
||||
isc_mem_put(res->mctx, res->dbuckets,
|
||||
|
|
@ -10500,7 +10599,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
|
|||
atomic_init(&res->exiting, false);
|
||||
atomic_init(&res->priming, false);
|
||||
atomic_init(&res->zspill, 0);
|
||||
atomic_init(&res->nfctx, 0);
|
||||
ISC_LIST_INIT(res->whenshutdown);
|
||||
ISC_LIST_INIT(res->alternates);
|
||||
|
||||
|
|
@ -10537,7 +10635,8 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
|
|||
snprintf(name, sizeof(name), "res%" PRIu32, i);
|
||||
isc_task_setname(res->buckets[i].task, name, res);
|
||||
|
||||
ISC_LIST_INIT(res->buckets[i].fctxs);
|
||||
isc_ht_init(&res->buckets[i].fctxs, res->mctx, 8,
|
||||
ISC_HT_CASE_SENSITIVE);
|
||||
atomic_init(&res->buckets[i].exiting, false);
|
||||
}
|
||||
|
||||
|
|
@ -10545,8 +10644,10 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
|
|||
HASHSIZE(res->dhashbits) *
|
||||
sizeof(res->dbuckets[0]));
|
||||
for (size_t i = 0; i < HASHSIZE(res->dhashbits); i++) {
|
||||
res->dbuckets[i] = (zonebucket_t){ .list = { 0 } };
|
||||
ISC_LIST_INIT(res->dbuckets[i].list);
|
||||
res->dbuckets[i] = (zonebucket_t){ 0 };
|
||||
isc_ht_init(&res->dbuckets[i].counters, res->mctx, 8,
|
||||
ISC_HT_CASE_SENSITIVE);
|
||||
|
||||
isc_mutex_init(&res->dbuckets[i].lock);
|
||||
}
|
||||
|
||||
|
|
@ -10774,33 +10875,45 @@ dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
|
|||
void
|
||||
dns_resolver_shutdown(dns_resolver_t *res) {
|
||||
unsigned int i;
|
||||
fetchctx_t *fctx;
|
||||
isc_result_t result;
|
||||
bool is_false = false;
|
||||
bool is_done = false;
|
||||
|
||||
REQUIRE(VALID_RESOLVER(res));
|
||||
|
||||
RTRACE("shutdown");
|
||||
|
||||
if (atomic_compare_exchange_strong(&res->exiting, &is_false, true)) {
|
||||
if (atomic_compare_exchange_strong(&res->exiting, &(bool){ false },
|
||||
true))
|
||||
{
|
||||
RTRACE("exiting");
|
||||
|
||||
for (i = 0; i < res->nbuckets; i++) {
|
||||
LOCK(&res->buckets[i].lock);
|
||||
for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
|
||||
fctx != NULL; fctx = ISC_LIST_NEXT(fctx, link))
|
||||
isc_ht_iter_t *it = NULL;
|
||||
|
||||
isc_ht_iter_create(res->buckets[i].fctxs, &it);
|
||||
|
||||
for (result = isc_ht_iter_first(it);
|
||||
result == ISC_R_SUCCESS;
|
||||
result = isc_ht_iter_next(it))
|
||||
{
|
||||
fetchctx_t *fctx = NULL;
|
||||
isc_ht_iter_current(it, (void **)&fctx);
|
||||
fctx_shutdown(fctx);
|
||||
}
|
||||
|
||||
isc_ht_iter_destroy(&it);
|
||||
|
||||
atomic_store(&res->buckets[i].exiting, true);
|
||||
if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
|
||||
|
||||
if (res->buckets[i].nfctxs == 0) {
|
||||
if (isc_refcount_decrement(
|
||||
&res->activebuckets) == 1)
|
||||
{
|
||||
is_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK(&res->buckets[i].lock);
|
||||
}
|
||||
if (is_done) {
|
||||
|
|
@ -10831,24 +10944,6 @@ dns_resolver_detach(dns_resolver_t **resp) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
fctx_match(fetchctx_t *fctx, const dns_name_t *name, dns_rdatatype_t type,
|
||||
unsigned int options) {
|
||||
/*
|
||||
* Don't match fetch contexts that are shutting down.
|
||||
*/
|
||||
if (fctx->cloned || fctx->state == fetchstate_done ||
|
||||
ISC_LIST_EMPTY(fctx->events))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fctx->type != type || fctx->options != options) {
|
||||
return false;
|
||||
}
|
||||
return dns_name_equal(fctx->name, name);
|
||||
}
|
||||
|
||||
static void
|
||||
log_fetch(const dns_name_t *name, dns_rdatatype_t type) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
|
|
@ -11039,13 +11134,13 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
|
|||
}
|
||||
|
||||
if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
|
||||
for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
|
||||
fctx != NULL; fctx = ISC_LIST_NEXT(fctx, link))
|
||||
{
|
||||
if (fctx_match(fctx, name, type, options)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint8_t key[DNS_FCTX_KEYSIZE];
|
||||
size_t keysize = sizeof(key);
|
||||
|
||||
fctx_makekey(name, type, options, key, &keysize);
|
||||
|
||||
(void)isc_ht_find(res->buckets[bucketnum].fctxs, key, keysize,
|
||||
(void **)&fctx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -11192,6 +11287,7 @@ dns_resolver_cancelfetch(dns_fetch_t *fetch) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The "trystale" event must be sent before the "fetchdone" event,
|
||||
* because the latter clears the "recursing" query attribute, which is
|
||||
|
|
@ -11810,17 +11906,24 @@ dns_resolver_dumpfetches(dns_resolver_t *resolver, isc_statsformat_t format,
|
|||
REQUIRE(format == isc_statsformat_file);
|
||||
|
||||
for (size_t i = 0; i < HASHSIZE(resolver->dhashbits); i++) {
|
||||
fctxcount_t *fc;
|
||||
LOCK(&resolver->dbuckets[i].lock);
|
||||
for (fc = ISC_LIST_HEAD(resolver->dbuckets[i].list); fc != NULL;
|
||||
fc = ISC_LIST_NEXT(fc, link))
|
||||
isc_ht_iter_t *it = NULL;
|
||||
isc_result_t result;
|
||||
|
||||
isc_ht_iter_create(resolver->dbuckets[i].counters, &it);
|
||||
for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
|
||||
result = isc_ht_iter_next(it))
|
||||
{
|
||||
dns_name_print(fc->domain, fp);
|
||||
fctxcount_t *counter = NULL;
|
||||
isc_ht_iter_current(it, (void **)&counter);
|
||||
dns_name_print(counter->domain, fp);
|
||||
fprintf(fp,
|
||||
": %u active (%u spilled, %u "
|
||||
"allowed)\n",
|
||||
fc->count, fc->dropped, fc->allowed);
|
||||
counter->count, counter->dropped,
|
||||
counter->allowed);
|
||||
}
|
||||
isc_ht_iter_destroy(&it);
|
||||
UNLOCK(&resolver->dbuckets[i].lock);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue