mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 18:19:42 +00:00
new: usr: Redesign the unreachable primaries cache
Previously, the cache for the unreachable primary servers was limited to 10 entries (LRU) and a fixed 10 minutes delay for each entry, unless removed forcibly by a new entry. The cache is now redesigned to remove the 10 entry limitation and to introduce delay values with exponential backoff time - initially an unreachable primary server is cached as being unreachable for 10 seconds, but each time the cache entry is expired and the same server is added again during the eligibility period of the next 120 seconds, the delay time is doubled up until to the maximum of 640 seconds. Closes #3992 Merge branch '3992-unreachable-cache-redesign' into 'main' See merge request isc-projects/bind9!10393
This commit is contained in:
commit
b814434836
@ -87,6 +87,13 @@ The numbers in parentheses in the following text refer to the numbered items in
|
|||||||
from the primary (as described in section 2 a. above). If the zone file has
|
from the primary (as described in section 2 a. above). If the zone file has
|
||||||
changed, propagation is practically immediate.
|
changed, propagation is practically immediate.
|
||||||
|
|
||||||
|
.. Note:: When a primary server is unreachable, :iscman:`named` initially caches
|
||||||
|
that information for 10 seconds. After that initial period, :iscman:`named`
|
||||||
|
may try that server again; if the server remains unresponsive,
|
||||||
|
:iscman:`named` caches its unreachable status for up to 640 seconds using an
|
||||||
|
exponential backoff. During that time :iscman:`named` does not try to contact
|
||||||
|
the affected server. The cache can be cleared using :option:`rndc flush`.
|
||||||
|
|
||||||
The authoritative samples all use NOTIFY but identify the statements used, so
|
The authoritative samples all use NOTIFY but identify the statements used, so
|
||||||
that they can be removed if not required.
|
that they can be removed if not required.
|
||||||
|
|
||||||
|
@ -131,6 +131,7 @@ libdns_la_HEADERS = \
|
|||||||
include/dns/tsig.h \
|
include/dns/tsig.h \
|
||||||
include/dns/ttl.h \
|
include/dns/ttl.h \
|
||||||
include/dns/types.h \
|
include/dns/types.h \
|
||||||
|
include/dns/unreachcache.h \
|
||||||
include/dns/update.h \
|
include/dns/update.h \
|
||||||
include/dns/validator.h \
|
include/dns/validator.h \
|
||||||
include/dns/view.h \
|
include/dns/view.h \
|
||||||
@ -247,6 +248,7 @@ libdns_la_SOURCES = \
|
|||||||
tsig.c \
|
tsig.c \
|
||||||
tsig_p.h \
|
tsig_p.h \
|
||||||
ttl.c \
|
ttl.c \
|
||||||
|
unreachcache.c \
|
||||||
update.c \
|
update.c \
|
||||||
validator.c \
|
validator.c \
|
||||||
view.c \
|
view.c \
|
||||||
|
@ -167,6 +167,7 @@ typedef struct dns_tsigkeyring dns_tsigkeyring_t;
|
|||||||
typedef struct dns_tsigkey dns_tsigkey_t;
|
typedef struct dns_tsigkey dns_tsigkey_t;
|
||||||
typedef uint32_t dns_ttl_t;
|
typedef uint32_t dns_ttl_t;
|
||||||
typedef uint32_t dns_typepair_t;
|
typedef uint32_t dns_typepair_t;
|
||||||
|
typedef struct dns_unreachcache dns_unreachcache_t;
|
||||||
typedef struct dns_update_state dns_update_state_t;
|
typedef struct dns_update_state dns_update_state_t;
|
||||||
typedef struct dns_validator dns_validator_t;
|
typedef struct dns_validator dns_validator_t;
|
||||||
typedef struct dns_view dns_view_t;
|
typedef struct dns_view dns_view_t;
|
||||||
|
132
lib/dns/include/dns/unreachcache.h
Normal file
132
lib/dns/include/dns/unreachcache.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* See the COPYRIGHT file distributed with this work for additional
|
||||||
|
* information regarding copyright ownership.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*****
|
||||||
|
***** Module Info
|
||||||
|
*****/
|
||||||
|
|
||||||
|
/*! \file dns/unreachcache.h
|
||||||
|
* \brief
|
||||||
|
* Defines dns_unreachcache_t, the "unreachable cache" object.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
*\li An unreachable cache object is a hash table of
|
||||||
|
* isc_sockaddr_t/isc_sockaddr_t tuples, indicating whether a given tuple
|
||||||
|
* is known to be "unreachable" in some sense (e.g. an unresponsive primary
|
||||||
|
* server). This is currently used by the secondary servers for the
|
||||||
|
* "unreachable cache".
|
||||||
|
*
|
||||||
|
* Reliability:
|
||||||
|
*
|
||||||
|
* Resources:
|
||||||
|
*
|
||||||
|
* Security:
|
||||||
|
*
|
||||||
|
* Standards:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
*** Imports
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <isc/loop.h>
|
||||||
|
#include <isc/mem.h>
|
||||||
|
#include <isc/stdtime.h>
|
||||||
|
|
||||||
|
#include <dns/types.h>
|
||||||
|
|
||||||
|
/***
|
||||||
|
*** Functions
|
||||||
|
***/
|
||||||
|
|
||||||
|
dns_unreachcache_t *
|
||||||
|
dns_unreachcache_new(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
|
||||||
|
const uint16_t expire_min_s, const uint16_t expire_max_s,
|
||||||
|
const uint16_t backoff_eligible_s);
|
||||||
|
/*%
|
||||||
|
* Allocate and initialize an unreachable cache. A newly entered entry expires
|
||||||
|
* in 'expire_min_s' seconds, a duplicate entry refreshes the expire timer.
|
||||||
|
* However, after expiring, if the same entry is added again in less that the
|
||||||
|
* 'backoff_eligible_s' time, then the next expire happens in a double amount of
|
||||||
|
* time of the previous expiration, but no more than in 'expire_max_s' seconds.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li mctx != NULL
|
||||||
|
* \li expire_min_s > 0
|
||||||
|
* \li expire_min_s <= expire_max_s
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_destroy(dns_unreachcache_t **ucp);
|
||||||
|
/*%
|
||||||
|
* Flush and then free unreachcache in 'ucp'. '*ucp' is set to NULL on return.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li '*ucp' to be a valid unreachcache
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_add(dns_unreachcache_t *uc, const isc_sockaddr_t *remote,
|
||||||
|
const isc_sockaddr_t *local);
|
||||||
|
/*%
|
||||||
|
* Adds an unreachcache entry to the unreachcache 'uc' for addresses 'remote'
|
||||||
|
* and 'local'. If an entry already exists, then it is refreshed. See also
|
||||||
|
* the documentation of the dns_unreachcache_new() function.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li uc to be a valid unreachcache.
|
||||||
|
* \li remote != NULL
|
||||||
|
* \li local != NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
isc_result_t
|
||||||
|
dns_unreachcache_find(dns_unreachcache_t *uc, const isc_sockaddr_t *remote,
|
||||||
|
const isc_sockaddr_t *local);
|
||||||
|
/*%
|
||||||
|
* Returns ISC_R_SUCCESS if a record is found in the unreachcache 'uc' matching
|
||||||
|
* 'remote' and 'local', with an expiration date later than 'now'. Returns
|
||||||
|
* ISC_R_NOTFOUND otherwise.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li uc to be a valid unreachcache.
|
||||||
|
* \li remote != NULL
|
||||||
|
* \li local != NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_remove(dns_unreachcache_t *uc, const isc_sockaddr_t *remote,
|
||||||
|
const isc_sockaddr_t *local);
|
||||||
|
/*%
|
||||||
|
* Removes a record that is found in the unreachcache 'uc' matching 'remote' and
|
||||||
|
* 'local', if it exists.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li uc to be a valid unreachcache.
|
||||||
|
* \li remote != NULL
|
||||||
|
* \li local != NULL
|
||||||
|
* \li now != NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_flush(dns_unreachcache_t *uc);
|
||||||
|
/*%
|
||||||
|
* Flush the entire unreachable cache.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li uc to be a valid unreachcache
|
||||||
|
*/
|
@ -178,6 +178,7 @@ struct dns_view {
|
|||||||
dns_dlzdblist_t dlz_unsearched;
|
dns_dlzdblist_t dlz_unsearched;
|
||||||
uint32_t fail_ttl;
|
uint32_t fail_ttl;
|
||||||
dns_badcache_t *failcache;
|
dns_badcache_t *failcache;
|
||||||
|
dns_unreachcache_t *unreachcache;
|
||||||
unsigned int udpsize;
|
unsigned int udpsize;
|
||||||
uint32_t sig0key_checks_limit;
|
uint32_t sig0key_checks_limit;
|
||||||
uint32_t sig0message_checks_limit;
|
uint32_t sig0message_checks_limit;
|
||||||
|
@ -1953,44 +1953,6 @@ dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_firstrefresh,
|
|||||||
* ISC_R_FAILURE error while trying to get the transfer information
|
* ISC_R_FAILURE error while trying to get the transfer information
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
|
||||||
dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
|
|
||||||
isc_sockaddr_t *local, isc_time_t *now);
|
|
||||||
/*%<
|
|
||||||
* Add the pair of addresses to the unreachable cache.
|
|
||||||
*
|
|
||||||
* Requires:
|
|
||||||
*\li 'zmgr' to be a valid zone manager.
|
|
||||||
*\li 'remote' to be a valid sockaddr.
|
|
||||||
*\li 'local' to be a valid sockaddr.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool
|
|
||||||
dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
|
|
||||||
isc_sockaddr_t *local, isc_time_t *now);
|
|
||||||
/*%<
|
|
||||||
* Returns true if the given local/remote address pair
|
|
||||||
* is found in the zone maanger's unreachable cache.
|
|
||||||
*
|
|
||||||
* Requires:
|
|
||||||
*\li 'zmgr' to be a valid zone manager.
|
|
||||||
*\li 'remote' to be a valid sockaddr.
|
|
||||||
*\li 'local' to be a valid sockaddr.
|
|
||||||
*\li 'now' != NULL
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
|
|
||||||
isc_sockaddr_t *local);
|
|
||||||
/*%<
|
|
||||||
* Remove the pair of addresses from the unreachable cache.
|
|
||||||
*
|
|
||||||
* Requires:
|
|
||||||
*\li 'zmgr' to be a valid zone manager.
|
|
||||||
*\li 'remote' to be a valid sockaddr.
|
|
||||||
*\li 'local' to be a valid sockaddr.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_zonemgr_set_tlsctx_cache(dns_zonemgr_t *zmgr,
|
dns_zonemgr_set_tlsctx_cache(dns_zonemgr_t *zmgr,
|
||||||
isc_tlsctx_cache_t *tlsctx_cache);
|
isc_tlsctx_cache_t *tlsctx_cache);
|
||||||
|
436
lib/dns/unreachcache.c
Normal file
436
lib/dns/unreachcache.c
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* See the COPYRIGHT file distributed with this work for additional
|
||||||
|
* information regarding copyright ownership.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \file */
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <isc/async.h>
|
||||||
|
#include <isc/buffer.h>
|
||||||
|
#include <isc/hash.h>
|
||||||
|
#include <isc/log.h>
|
||||||
|
#include <isc/loop.h>
|
||||||
|
#include <isc/mem.h>
|
||||||
|
#include <isc/mutex.h>
|
||||||
|
#include <isc/rwlock.h>
|
||||||
|
#include <isc/sockaddr.h>
|
||||||
|
#include <isc/spinlock.h>
|
||||||
|
#include <isc/stdtime.h>
|
||||||
|
#include <isc/string.h>
|
||||||
|
#include <isc/thread.h>
|
||||||
|
#include <isc/time.h>
|
||||||
|
#include <isc/urcu.h>
|
||||||
|
#include <isc/util.h>
|
||||||
|
|
||||||
|
#include <dns/fixedname.h>
|
||||||
|
#include <dns/name.h>
|
||||||
|
#include <dns/rdatatype.h>
|
||||||
|
#include <dns/types.h>
|
||||||
|
#include <dns/unreachcache.h>
|
||||||
|
|
||||||
|
typedef struct dns_ucentry dns_ucentry_t;
|
||||||
|
|
||||||
|
typedef struct dns_uckey {
|
||||||
|
const isc_sockaddr_t *remote;
|
||||||
|
const isc_sockaddr_t *local;
|
||||||
|
} dns__uckey_t;
|
||||||
|
|
||||||
|
struct dns_unreachcache {
|
||||||
|
unsigned int magic;
|
||||||
|
isc_mem_t *mctx;
|
||||||
|
uint16_t expire_min_s;
|
||||||
|
uint16_t expire_max_s;
|
||||||
|
uint16_t backoff_eligible_s;
|
||||||
|
struct cds_lfht *ht;
|
||||||
|
struct cds_list_head *lru;
|
||||||
|
uint32_t nloops;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UNREACHCACHE_MAGIC ISC_MAGIC('U', 'R', 'C', 'a')
|
||||||
|
#define VALID_UNREACHCACHE(m) ISC_MAGIC_VALID(m, UNREACHCACHE_MAGIC)
|
||||||
|
|
||||||
|
#define UNREACHCACHE_INIT_SIZE (1 << 4) /* Must be power of 2 */
|
||||||
|
#define UNREACHCACHE_MIN_SIZE (1 << 5) /* Must be power of 2 */
|
||||||
|
|
||||||
|
struct dns_ucentry {
|
||||||
|
isc_loop_t *loop;
|
||||||
|
isc_stdtime_t expire;
|
||||||
|
unsigned int exp_backoff_n;
|
||||||
|
uint16_t wait_time;
|
||||||
|
bool confirmed;
|
||||||
|
|
||||||
|
struct cds_lfht_node ht_node;
|
||||||
|
struct rcu_head rcu_head;
|
||||||
|
struct cds_list_head lru_head;
|
||||||
|
|
||||||
|
isc_sockaddr_t remote;
|
||||||
|
isc_sockaddr_t local;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucentry_destroy(struct rcu_head *rcu_head);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ucentry_alive(struct cds_lfht *ht, dns_ucentry_t *unreach, isc_stdtime_t now,
|
||||||
|
bool alive_or_waiting);
|
||||||
|
|
||||||
|
dns_unreachcache_t *
|
||||||
|
dns_unreachcache_new(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
|
||||||
|
const uint16_t expire_min_s, const uint16_t expire_max_s,
|
||||||
|
const uint16_t backoff_eligible_s) {
|
||||||
|
REQUIRE(loopmgr != NULL);
|
||||||
|
REQUIRE(expire_min_s > 0);
|
||||||
|
REQUIRE(expire_min_s <= expire_max_s);
|
||||||
|
|
||||||
|
uint32_t nloops = isc_loopmgr_nloops(loopmgr);
|
||||||
|
dns_unreachcache_t *uc = isc_mem_get(mctx, sizeof(*uc));
|
||||||
|
*uc = (dns_unreachcache_t){
|
||||||
|
.magic = UNREACHCACHE_MAGIC,
|
||||||
|
.expire_min_s = expire_min_s,
|
||||||
|
.expire_max_s = expire_max_s,
|
||||||
|
.backoff_eligible_s = backoff_eligible_s,
|
||||||
|
.nloops = nloops,
|
||||||
|
};
|
||||||
|
|
||||||
|
uc->ht = cds_lfht_new(UNREACHCACHE_INIT_SIZE, UNREACHCACHE_MIN_SIZE, 0,
|
||||||
|
CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
|
||||||
|
INSIST(uc->ht != NULL);
|
||||||
|
|
||||||
|
uc->lru = isc_mem_cget(mctx, uc->nloops, sizeof(uc->lru[0]));
|
||||||
|
for (size_t i = 0; i < uc->nloops; i++) {
|
||||||
|
CDS_INIT_LIST_HEAD(&uc->lru[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
isc_mem_attach(mctx, &uc->mctx);
|
||||||
|
|
||||||
|
return uc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_destroy(dns_unreachcache_t **ucp) {
|
||||||
|
REQUIRE(ucp != NULL && *ucp != NULL);
|
||||||
|
REQUIRE(VALID_UNREACHCACHE(*ucp));
|
||||||
|
dns_unreachcache_t *uc = *ucp;
|
||||||
|
*ucp = NULL;
|
||||||
|
uc->magic = 0;
|
||||||
|
|
||||||
|
dns_ucentry_t *unreach = NULL;
|
||||||
|
struct cds_lfht_iter iter;
|
||||||
|
cds_lfht_for_each_entry(uc->ht, &iter, unreach, ht_node) {
|
||||||
|
INSIST(!cds_lfht_del(uc->ht, &unreach->ht_node));
|
||||||
|
ucentry_destroy(&unreach->rcu_head);
|
||||||
|
}
|
||||||
|
RUNTIME_CHECK(!cds_lfht_destroy(uc->ht, NULL));
|
||||||
|
|
||||||
|
isc_mem_cput(uc->mctx, uc->lru, uc->nloops, sizeof(uc->lru[0]));
|
||||||
|
|
||||||
|
isc_mem_putanddetach(&uc->mctx, uc, sizeof(dns_unreachcache_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ucentry_match(struct cds_lfht_node *ht_node, const void *key0) {
|
||||||
|
const dns__uckey_t *key = key0;
|
||||||
|
dns_ucentry_t *unreach = caa_container_of(ht_node, dns_ucentry_t,
|
||||||
|
ht_node);
|
||||||
|
|
||||||
|
return isc_sockaddr_equal(&unreach->remote, key->remote) &&
|
||||||
|
isc_sockaddr_equal(&unreach->local, key->local);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
ucentry_hash(const dns__uckey_t *key) {
|
||||||
|
return isc_sockaddr_hash(key->remote, false) ^
|
||||||
|
isc_sockaddr_hash(key->local, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dns_ucentry_t *
|
||||||
|
ucentry_lookup(struct cds_lfht *ht, uint32_t hashval, dns__uckey_t *key) {
|
||||||
|
struct cds_lfht_iter iter;
|
||||||
|
|
||||||
|
cds_lfht_lookup(ht, hashval, ucentry_match, key, &iter);
|
||||||
|
|
||||||
|
return cds_lfht_entry(cds_lfht_iter_get_node(&iter), dns_ucentry_t,
|
||||||
|
ht_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dns_ucentry_t *
|
||||||
|
ucentry_new(isc_loop_t *loop, const isc_sockaddr_t *remote,
|
||||||
|
const isc_sockaddr_t *local, const isc_stdtime_t expire,
|
||||||
|
const isc_stdtime_t wait_time) {
|
||||||
|
isc_mem_t *mctx = isc_loop_getmctx(loop);
|
||||||
|
dns_ucentry_t *unreach = isc_mem_get(mctx, sizeof(*unreach));
|
||||||
|
*unreach = (dns_ucentry_t){
|
||||||
|
.remote = *remote,
|
||||||
|
.local = *local,
|
||||||
|
.expire = expire,
|
||||||
|
.wait_time = wait_time,
|
||||||
|
.loop = isc_loop_ref(loop),
|
||||||
|
.lru_head = CDS_LIST_HEAD_INIT(unreach->lru_head),
|
||||||
|
};
|
||||||
|
|
||||||
|
return unreach;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucentry_destroy(struct rcu_head *rcu_head) {
|
||||||
|
dns_ucentry_t *unreach = caa_container_of(rcu_head, dns_ucentry_t,
|
||||||
|
rcu_head);
|
||||||
|
isc_loop_t *loop = unreach->loop;
|
||||||
|
isc_mem_t *mctx = isc_loop_getmctx(loop);
|
||||||
|
|
||||||
|
isc_mem_put(mctx, unreach, sizeof(*unreach));
|
||||||
|
isc_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucentry_evict_async(void *arg) {
|
||||||
|
dns_ucentry_t *unreach = arg;
|
||||||
|
|
||||||
|
RUNTIME_CHECK(unreach->loop == isc_loop());
|
||||||
|
|
||||||
|
cds_list_del(&unreach->lru_head);
|
||||||
|
call_rcu(&unreach->rcu_head, ucentry_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucentry_evict(struct cds_lfht *ht, dns_ucentry_t *unreach) {
|
||||||
|
if (!cds_lfht_del(ht, &unreach->ht_node)) {
|
||||||
|
if (unreach->loop == isc_loop()) {
|
||||||
|
ucentry_evict_async(unreach);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isc_async_run(unreach->loop, ucentry_evict_async, unreach);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ucentry_alive(struct cds_lfht *ht, dns_ucentry_t *unreach, isc_stdtime_t now,
|
||||||
|
bool alive_or_waiting) {
|
||||||
|
if (cds_lfht_is_node_deleted(&unreach->ht_node)) {
|
||||||
|
return false;
|
||||||
|
} else if (unreach->expire < now) {
|
||||||
|
bool is_waiting = unreach->expire + unreach->wait_time >= now;
|
||||||
|
|
||||||
|
if (is_waiting) {
|
||||||
|
/*
|
||||||
|
* Wait some minimum time before evicting an expired
|
||||||
|
* entry so we can support exponential backoff for
|
||||||
|
* nodes which enter again shortly after expiring.
|
||||||
|
*
|
||||||
|
* The return value depends on whether the caller is
|
||||||
|
* interested to know if the node is in either active or
|
||||||
|
* waiting state (i.e. not eviceted), or is interested
|
||||||
|
* only if it's still alive (i.e. not expired).
|
||||||
|
*/
|
||||||
|
return alive_or_waiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The entry is already expired, evict it before returning. */
|
||||||
|
ucentry_evict(ht, unreach);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucentry_purge(struct cds_lfht *ht, struct cds_list_head *lru,
|
||||||
|
isc_stdtime_t now) {
|
||||||
|
size_t count = 10;
|
||||||
|
dns_ucentry_t *unreach;
|
||||||
|
cds_list_for_each_entry_rcu(unreach, lru, lru_head) {
|
||||||
|
if (ucentry_alive(ht, unreach, now, true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (--count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucentry_backoff(const dns_unreachcache_t *uc, const isc_stdtime_t now,
|
||||||
|
dns_ucentry_t *new, const dns_ucentry_t *old) {
|
||||||
|
/*
|
||||||
|
* Perform exponential backoff if this is an expired entry wating to be
|
||||||
|
* evicted. Otherwise it's a duplicate entry and no backoff is required
|
||||||
|
* as we will just update the cache with a new entry that has the same
|
||||||
|
* expiration time as the old one, but calculated freshly, based on the
|
||||||
|
* current time.
|
||||||
|
*/
|
||||||
|
if (old->expire < now) {
|
||||||
|
new->exp_backoff_n = old->exp_backoff_n + 1;
|
||||||
|
} else {
|
||||||
|
new->exp_backoff_n = old->exp_backoff_n;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < new->exp_backoff_n; i++) {
|
||||||
|
new->expire += uc->expire_min_s;
|
||||||
|
if (new->expire > now + uc->expire_max_s) {
|
||||||
|
new->expire = now + uc->expire_max_s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_add(dns_unreachcache_t *uc, const isc_sockaddr_t *remote,
|
||||||
|
const isc_sockaddr_t *local) {
|
||||||
|
REQUIRE(VALID_UNREACHCACHE(uc));
|
||||||
|
REQUIRE(remote != NULL);
|
||||||
|
REQUIRE(local != NULL);
|
||||||
|
|
||||||
|
isc_loop_t *loop = isc_loop();
|
||||||
|
uint32_t tid = isc_tid();
|
||||||
|
struct cds_list_head *lru = &uc->lru[tid];
|
||||||
|
isc_stdtime_t now = isc_stdtime_now();
|
||||||
|
isc_stdtime_t expire = now + uc->expire_min_s;
|
||||||
|
bool exp_backoff_activated = false;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
struct cds_lfht *ht = rcu_dereference(uc->ht);
|
||||||
|
INSIST(ht != NULL);
|
||||||
|
|
||||||
|
dns__uckey_t key = {
|
||||||
|
.remote = remote,
|
||||||
|
.local = local,
|
||||||
|
};
|
||||||
|
uint32_t hashval = ucentry_hash(&key);
|
||||||
|
|
||||||
|
dns_ucentry_t *unreach = ucentry_new(loop, remote, local, expire,
|
||||||
|
uc->backoff_eligible_s);
|
||||||
|
struct cds_lfht_node *ht_node;
|
||||||
|
do {
|
||||||
|
ht_node = cds_lfht_add_unique(ht, hashval, ucentry_match, &key,
|
||||||
|
&unreach->ht_node);
|
||||||
|
if (ht_node != &unreach->ht_node) {
|
||||||
|
/* The entry already exists, get it. */
|
||||||
|
dns_ucentry_t *found = caa_container_of(
|
||||||
|
ht_node, dns_ucentry_t, ht_node);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Consider unreachability as confirmed only if
|
||||||
|
* an entry is submitted at least twice, i.e. there
|
||||||
|
* was an older entry (which is exactly this case).
|
||||||
|
*/
|
||||||
|
unreach->confirmed = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recalculate the expire time of the new entry based
|
||||||
|
* on the old entry's exponential backoff value.
|
||||||
|
*/
|
||||||
|
if (!exp_backoff_activated) {
|
||||||
|
exp_backoff_activated = true;
|
||||||
|
ucentry_backoff(uc, now, unreach, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evict the old entry, so we can try to insert the new
|
||||||
|
* one again.
|
||||||
|
*/
|
||||||
|
ucentry_evict(ht, found);
|
||||||
|
}
|
||||||
|
} while (ht_node != &unreach->ht_node);
|
||||||
|
|
||||||
|
/* No locking, instead we are using per-thread lists */
|
||||||
|
cds_list_add_tail_rcu(&unreach->lru_head, lru);
|
||||||
|
|
||||||
|
ucentry_purge(ht, lru, now);
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
isc_result_t
|
||||||
|
dns_unreachcache_find(dns_unreachcache_t *uc, const isc_sockaddr_t *remote,
|
||||||
|
const isc_sockaddr_t *local) {
|
||||||
|
REQUIRE(VALID_UNREACHCACHE(uc));
|
||||||
|
REQUIRE(remote != NULL);
|
||||||
|
REQUIRE(local != NULL);
|
||||||
|
|
||||||
|
isc_result_t result = ISC_R_NOTFOUND;
|
||||||
|
isc_stdtime_t now = isc_stdtime_now();
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
struct cds_lfht *ht = rcu_dereference(uc->ht);
|
||||||
|
INSIST(ht != NULL);
|
||||||
|
|
||||||
|
dns__uckey_t key = {
|
||||||
|
.remote = remote,
|
||||||
|
.local = local,
|
||||||
|
};
|
||||||
|
uint32_t hashval = ucentry_hash(&key);
|
||||||
|
|
||||||
|
dns_ucentry_t *found = ucentry_lookup(ht, hashval, &key);
|
||||||
|
if (found != NULL && found->confirmed &&
|
||||||
|
ucentry_alive(ht, found, now, false))
|
||||||
|
{
|
||||||
|
result = ISC_R_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tid = isc_tid();
|
||||||
|
struct cds_list_head *lru = &uc->lru[tid];
|
||||||
|
ucentry_purge(ht, lru, now);
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_remove(dns_unreachcache_t *uc, const isc_sockaddr_t *remote,
|
||||||
|
const isc_sockaddr_t *local) {
|
||||||
|
REQUIRE(VALID_UNREACHCACHE(uc));
|
||||||
|
REQUIRE(remote != NULL);
|
||||||
|
REQUIRE(local != NULL);
|
||||||
|
|
||||||
|
isc_stdtime_t now = isc_stdtime_now();
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
struct cds_lfht *ht = rcu_dereference(uc->ht);
|
||||||
|
INSIST(ht != NULL);
|
||||||
|
|
||||||
|
dns__uckey_t key = {
|
||||||
|
.remote = remote,
|
||||||
|
.local = local,
|
||||||
|
};
|
||||||
|
uint32_t hashval = ucentry_hash(&key);
|
||||||
|
|
||||||
|
dns_ucentry_t *found = ucentry_lookup(ht, hashval, &key);
|
||||||
|
if (found != NULL) {
|
||||||
|
ucentry_evict(ht, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tid = isc_tid();
|
||||||
|
struct cds_list_head *lru = &uc->lru[tid];
|
||||||
|
ucentry_purge(ht, lru, now);
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_unreachcache_flush(dns_unreachcache_t *uc) {
|
||||||
|
REQUIRE(VALID_UNREACHCACHE(uc));
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
struct cds_lfht *ht = rcu_dereference(uc->ht);
|
||||||
|
INSIST(ht != NULL);
|
||||||
|
|
||||||
|
/* Flush the hash table */
|
||||||
|
dns_ucentry_t *unreach;
|
||||||
|
struct cds_lfht_iter iter;
|
||||||
|
cds_lfht_for_each_entry(ht, &iter, unreach, ht_node) {
|
||||||
|
ucentry_evict(ht, unreach);
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
@ -60,6 +60,7 @@
|
|||||||
#include <dns/time.h>
|
#include <dns/time.h>
|
||||||
#include <dns/transport.h>
|
#include <dns/transport.h>
|
||||||
#include <dns/tsig.h>
|
#include <dns/tsig.h>
|
||||||
|
#include <dns/unreachcache.h>
|
||||||
#include <dns/view.h>
|
#include <dns/view.h>
|
||||||
#include <dns/zone.h>
|
#include <dns/zone.h>
|
||||||
#include <dns/zt.h>
|
#include <dns/zt.h>
|
||||||
@ -84,6 +85,11 @@
|
|||||||
*/
|
*/
|
||||||
#define DEFAULT_EDNS_BUFSIZE 1232
|
#define DEFAULT_EDNS_BUFSIZE 1232
|
||||||
|
|
||||||
|
/* Exponental backoff from 10 seconds to 640 seconds */
|
||||||
|
#define UNREACH_HOLD_TIME_INITIAL_SEC ((uint16_t)10)
|
||||||
|
#define UNREACH_HOLD_TIME_MAX_SEC (UNREACH_HOLD_TIME_INITIAL_SEC << 6)
|
||||||
|
#define UNREACH_BACKOFF_ELIGIBLE_SEC ((uint16_t)120)
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
|
dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
|
||||||
dns_dispatchmgr_t *dispatchmgr, dns_rdataclass_t rdclass,
|
dns_dispatchmgr_t *dispatchmgr, dns_rdataclass_t rdclass,
|
||||||
@ -149,6 +155,10 @@ dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
|
|||||||
|
|
||||||
view->failcache = dns_badcache_new(view->mctx, loopmgr);
|
view->failcache = dns_badcache_new(view->mctx, loopmgr);
|
||||||
|
|
||||||
|
view->unreachcache = dns_unreachcache_new(
|
||||||
|
view->mctx, loopmgr, UNREACH_HOLD_TIME_INITIAL_SEC,
|
||||||
|
UNREACH_HOLD_TIME_MAX_SEC, UNREACH_BACKOFF_ELIGIBLE_SEC);
|
||||||
|
|
||||||
isc_mutex_init(&view->new_zone_lock);
|
isc_mutex_init(&view->new_zone_lock);
|
||||||
|
|
||||||
dns_order_create(view->mctx, &view->order);
|
dns_order_create(view->mctx, &view->order);
|
||||||
@ -355,6 +365,9 @@ destroy(dns_view_t *view) {
|
|||||||
if (view->failcache != NULL) {
|
if (view->failcache != NULL) {
|
||||||
dns_badcache_destroy(&view->failcache);
|
dns_badcache_destroy(&view->failcache);
|
||||||
}
|
}
|
||||||
|
if (view->unreachcache != NULL) {
|
||||||
|
dns_unreachcache_destroy(&view->unreachcache);
|
||||||
|
}
|
||||||
isc_mutex_destroy(&view->new_zone_lock);
|
isc_mutex_destroy(&view->new_zone_lock);
|
||||||
isc_mutex_destroy(&view->lock);
|
isc_mutex_destroy(&view->lock);
|
||||||
isc_refcount_destroy(&view->references);
|
isc_refcount_destroy(&view->references);
|
||||||
@ -1391,6 +1404,9 @@ dns_view_flushcache(dns_view_t *view, bool fixuponly) {
|
|||||||
if (view->failcache != NULL) {
|
if (view->failcache != NULL) {
|
||||||
dns_badcache_flush(view->failcache);
|
dns_badcache_flush(view->failcache);
|
||||||
}
|
}
|
||||||
|
if (view->unreachcache != NULL) {
|
||||||
|
dns_unreachcache_flush(view->unreachcache);
|
||||||
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
adb = rcu_dereference(view->adb);
|
adb = rcu_dereference(view->adb);
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <dns/trace.h>
|
#include <dns/trace.h>
|
||||||
#include <dns/transport.h>
|
#include <dns/transport.h>
|
||||||
#include <dns/tsig.h>
|
#include <dns/tsig.h>
|
||||||
|
#include <dns/unreachcache.h>
|
||||||
#include <dns/view.h>
|
#include <dns/view.h>
|
||||||
#include <dns/xfrin.h>
|
#include <dns/xfrin.h>
|
||||||
#include <dns/zone.h>
|
#include <dns/zone.h>
|
||||||
@ -1448,7 +1449,8 @@ xfrin_connect_done(isc_result_t result, isc_region_t *region ISC_ATTR_UNUSED,
|
|||||||
|
|
||||||
zmgr = dns_zone_getmgr(xfr->zone);
|
zmgr = dns_zone_getmgr(xfr->zone);
|
||||||
if (zmgr != NULL) {
|
if (zmgr != NULL) {
|
||||||
dns_zonemgr_unreachabledel(zmgr, &xfr->primaryaddr,
|
dns_view_t *view = dns_zone_getview(xfr->zone);
|
||||||
|
dns_unreachcache_remove(view->unreachcache, &xfr->primaryaddr,
|
||||||
&xfr->sourceaddr);
|
&xfr->sourceaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1480,16 +1482,16 @@ failure:
|
|||||||
case ISC_R_CONNREFUSED:
|
case ISC_R_CONNREFUSED:
|
||||||
case ISC_R_TIMEDOUT:
|
case ISC_R_TIMEDOUT:
|
||||||
/*
|
/*
|
||||||
* Add the server to unreachable primaries table if
|
* Add the server to unreachable primaries cache if
|
||||||
* the server has a permanent networking error or
|
* the server has a permanent networking error or
|
||||||
* the connection attempt as timed out.
|
* the connection attempt as timed out.
|
||||||
*/
|
*/
|
||||||
zmgr = dns_zone_getmgr(xfr->zone);
|
zmgr = dns_zone_getmgr(xfr->zone);
|
||||||
if (zmgr != NULL) {
|
if (zmgr != NULL) {
|
||||||
isc_time_t now = isc_time_now();
|
dns_view_t *view = dns_zone_getview(xfr->zone);
|
||||||
|
dns_unreachcache_add(view->unreachcache,
|
||||||
dns_zonemgr_unreachableadd(zmgr, &xfr->primaryaddr,
|
&xfr->primaryaddr,
|
||||||
&xfr->sourceaddr, &now);
|
&xfr->sourceaddr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
157
lib/dns/zone.c
157
lib/dns/zone.c
@ -87,6 +87,7 @@
|
|||||||
#include <dns/time.h>
|
#include <dns/time.h>
|
||||||
#include <dns/tsig.h>
|
#include <dns/tsig.h>
|
||||||
#include <dns/ttl.h>
|
#include <dns/ttl.h>
|
||||||
|
#include <dns/unreachcache.h>
|
||||||
#include <dns/update.h>
|
#include <dns/update.h>
|
||||||
#include <dns/xfrin.h>
|
#include <dns/xfrin.h>
|
||||||
#include <dns/zone.h>
|
#include <dns/zone.h>
|
||||||
@ -600,9 +601,6 @@ typedef enum {
|
|||||||
* load. */
|
* load. */
|
||||||
} dns_zoneloadflag_t;
|
} dns_zoneloadflag_t;
|
||||||
|
|
||||||
#define UNREACH_CACHE_SIZE 10U
|
|
||||||
#define UNREACH_HOLD_TIME 600 /* 10 minutes */
|
|
||||||
|
|
||||||
#define CHECK(op) \
|
#define CHECK(op) \
|
||||||
do { \
|
do { \
|
||||||
result = (op); \
|
result = (op); \
|
||||||
@ -610,14 +608,6 @@ typedef enum {
|
|||||||
goto failure; \
|
goto failure; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
struct dns_unreachable {
|
|
||||||
isc_sockaddr_t remote;
|
|
||||||
isc_sockaddr_t local;
|
|
||||||
atomic_uint_fast32_t expire;
|
|
||||||
atomic_uint_fast32_t last;
|
|
||||||
uint32_t count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dns_zonemgr {
|
struct dns_zonemgr {
|
||||||
unsigned int magic;
|
unsigned int magic;
|
||||||
isc_mem_t *mctx;
|
isc_mem_t *mctx;
|
||||||
@ -632,7 +622,6 @@ struct dns_zonemgr {
|
|||||||
isc_ratelimiter_t *startupnotifyrl;
|
isc_ratelimiter_t *startupnotifyrl;
|
||||||
isc_ratelimiter_t *startuprefreshrl;
|
isc_ratelimiter_t *startuprefreshrl;
|
||||||
isc_rwlock_t rwlock;
|
isc_rwlock_t rwlock;
|
||||||
isc_rwlock_t urlock;
|
|
||||||
|
|
||||||
/* Locked by rwlock. */
|
/* Locked by rwlock. */
|
||||||
dns_zonelist_t zones;
|
dns_zonelist_t zones;
|
||||||
@ -648,10 +637,6 @@ struct dns_zonemgr {
|
|||||||
unsigned int serialqueryrate;
|
unsigned int serialqueryrate;
|
||||||
unsigned int startupserialqueryrate;
|
unsigned int startupserialqueryrate;
|
||||||
|
|
||||||
/* Locked by urlock. */
|
|
||||||
/* LRU cache */
|
|
||||||
struct dns_unreachable unreachable[UNREACH_CACHE_SIZE];
|
|
||||||
|
|
||||||
dns_keymgmt_t *keymgmt;
|
dns_keymgmt_t *keymgmt;
|
||||||
|
|
||||||
isc_tlsctx_cache_t *tlsctx_cache;
|
isc_tlsctx_cache_t *tlsctx_cache;
|
||||||
@ -13309,7 +13294,6 @@ stub_glue_response(void *arg) {
|
|||||||
uint32_t addr_count, cnamecnt;
|
uint32_t addr_count, cnamecnt;
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
isc_sockaddr_t curraddr;
|
isc_sockaddr_t curraddr;
|
||||||
isc_time_t now;
|
|
||||||
dns_rdataset_t *addr_rdataset = NULL;
|
dns_rdataset_t *addr_rdataset = NULL;
|
||||||
dns_dbnode_t *node = NULL;
|
dns_dbnode_t *node = NULL;
|
||||||
|
|
||||||
@ -13319,8 +13303,6 @@ stub_glue_response(void *arg) {
|
|||||||
|
|
||||||
ENTER;
|
ENTER;
|
||||||
|
|
||||||
now = isc_time_now();
|
|
||||||
|
|
||||||
LOCK_ZONE(zone);
|
LOCK_ZONE(zone);
|
||||||
|
|
||||||
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
|
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
|
||||||
@ -13333,8 +13315,8 @@ stub_glue_response(void *arg) {
|
|||||||
isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source));
|
isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source));
|
||||||
|
|
||||||
if (dns_request_getresult(request) != ISC_R_SUCCESS) {
|
if (dns_request_getresult(request) != ISC_R_SUCCESS) {
|
||||||
dns_zonemgr_unreachableadd(zone->zmgr, &curraddr,
|
dns_unreachcache_add(zone->view->unreachcache, &curraddr,
|
||||||
&zone->sourceaddr, &now);
|
&zone->sourceaddr);
|
||||||
dns_zone_log(zone, ISC_LOG_INFO,
|
dns_zone_log(zone, ISC_LOG_INFO,
|
||||||
"could not refresh stub from primary %s"
|
"could not refresh stub from primary %s"
|
||||||
" (source %s): %s",
|
" (source %s): %s",
|
||||||
@ -13487,7 +13469,7 @@ cleanup:
|
|||||||
/* If last request, release all related resources */
|
/* If last request, release all related resources */
|
||||||
if (atomic_fetch_sub_release(&stub->pending_requests, 1) == 1) {
|
if (atomic_fetch_sub_release(&stub->pending_requests, 1) == 1) {
|
||||||
isc_mem_put(zone->mctx, cb_args, sizeof(*cb_args));
|
isc_mem_put(zone->mctx, cb_args, sizeof(*cb_args));
|
||||||
stub_finish_zone_update(stub, now);
|
stub_finish_zone_update(stub, isc_time_now());
|
||||||
UNLOCK_ZONE(zone);
|
UNLOCK_ZONE(zone);
|
||||||
stub->magic = 0;
|
stub->magic = 0;
|
||||||
dns_zone_idetach(&stub->zone);
|
dns_zone_idetach(&stub->zone);
|
||||||
@ -13762,8 +13744,8 @@ stub_callback(void *arg) {
|
|||||||
}
|
}
|
||||||
FALLTHROUGH;
|
FALLTHROUGH;
|
||||||
default:
|
default:
|
||||||
dns_zonemgr_unreachableadd(zone->zmgr, &curraddr,
|
dns_unreachcache_add(zone->view->unreachcache, &curraddr,
|
||||||
&zone->sourceaddr, &now);
|
&zone->sourceaddr);
|
||||||
dns_zone_log(zone, ISC_LOG_INFO,
|
dns_zone_log(zone, ISC_LOG_INFO,
|
||||||
"could not refresh stub from primary "
|
"could not refresh stub from primary "
|
||||||
"%s (source %s): %s",
|
"%s (source %s): %s",
|
||||||
@ -14117,9 +14099,9 @@ refresh_callback(void *arg) {
|
|||||||
zone->type == dns_zone_redirect) &&
|
zone->type == dns_zone_redirect) &&
|
||||||
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH))
|
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH))
|
||||||
{
|
{
|
||||||
if (!dns_zonemgr_unreachable(
|
if (dns_unreachcache_find(
|
||||||
zone->zmgr, &curraddr,
|
zone->view->unreachcache, &curraddr,
|
||||||
&zone->sourceaddr, &now))
|
&zone->sourceaddr) != ISC_R_SUCCESS)
|
||||||
{
|
{
|
||||||
DNS_ZONE_SETFLAG(
|
DNS_ZONE_SETFLAG(
|
||||||
zone,
|
zone,
|
||||||
@ -14361,8 +14343,8 @@ refresh_callback(void *arg) {
|
|||||||
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) ||
|
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) ||
|
||||||
isc_serial_gt(serial, oldserial))
|
isc_serial_gt(serial, oldserial))
|
||||||
{
|
{
|
||||||
if (dns_zonemgr_unreachable(zone->zmgr, &curraddr,
|
if (dns_unreachcache_find(zone->view->unreachcache, &curraddr,
|
||||||
&zone->sourceaddr, &now))
|
&zone->sourceaddr) == ISC_R_SUCCESS)
|
||||||
{
|
{
|
||||||
dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN,
|
dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN,
|
||||||
ISC_LOG_INFO,
|
ISC_LOG_INFO,
|
||||||
@ -15727,7 +15709,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
|
|||||||
UNLOCK_ZONE(zone);
|
UNLOCK_ZONE(zone);
|
||||||
|
|
||||||
if (to != NULL) {
|
if (to != NULL) {
|
||||||
dns_zonemgr_unreachabledel(zone->zmgr, from, to);
|
dns_unreachcache_remove(zone->view->unreachcache, from, to);
|
||||||
}
|
}
|
||||||
dns_zone_refresh(zone);
|
dns_zone_refresh(zone);
|
||||||
return ISC_R_SUCCESS;
|
return ISC_R_SUCCESS;
|
||||||
@ -18521,7 +18503,6 @@ got_transfer_quota(void *arg) {
|
|||||||
isc_netaddr_t primaryip;
|
isc_netaddr_t primaryip;
|
||||||
isc_sockaddr_t primaryaddr;
|
isc_sockaddr_t primaryaddr;
|
||||||
isc_sockaddr_t sourceaddr;
|
isc_sockaddr_t sourceaddr;
|
||||||
isc_time_t now;
|
|
||||||
dns_transport_type_t soa_transport_type = DNS_TRANSPORT_NONE;
|
dns_transport_type_t soa_transport_type = DNS_TRANSPORT_NONE;
|
||||||
const char *soa_before = "";
|
const char *soa_before = "";
|
||||||
bool loaded;
|
bool loaded;
|
||||||
@ -18533,12 +18514,10 @@ got_transfer_quota(void *arg) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
now = isc_time_now();
|
|
||||||
|
|
||||||
primaryaddr = dns_remote_curraddr(&zone->primaries);
|
primaryaddr = dns_remote_curraddr(&zone->primaries);
|
||||||
isc_sockaddr_format(&primaryaddr, primary, sizeof(primary));
|
isc_sockaddr_format(&primaryaddr, primary, sizeof(primary));
|
||||||
if (dns_zonemgr_unreachable(zone->zmgr, &primaryaddr, &zone->sourceaddr,
|
if (dns_unreachcache_find(zone->view->unreachcache, &primaryaddr,
|
||||||
&now))
|
&zone->sourceaddr) == ISC_R_SUCCESS)
|
||||||
{
|
{
|
||||||
isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source));
|
isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source));
|
||||||
dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO,
|
dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO,
|
||||||
@ -19194,15 +19173,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_nm_t *netmgr, dns_zonemgr_t **zmgrp) {
|
|||||||
ISC_LIST_INIT(zmgr->zones);
|
ISC_LIST_INIT(zmgr->zones);
|
||||||
ISC_LIST_INIT(zmgr->waiting_for_xfrin);
|
ISC_LIST_INIT(zmgr->waiting_for_xfrin);
|
||||||
ISC_LIST_INIT(zmgr->xfrin_in_progress);
|
ISC_LIST_INIT(zmgr->xfrin_in_progress);
|
||||||
memset(zmgr->unreachable, 0, sizeof(zmgr->unreachable));
|
|
||||||
for (size_t i = 0; i < UNREACH_CACHE_SIZE; i++) {
|
|
||||||
atomic_init(&zmgr->unreachable[i].expire, 0);
|
|
||||||
}
|
|
||||||
isc_rwlock_init(&zmgr->rwlock);
|
isc_rwlock_init(&zmgr->rwlock);
|
||||||
|
|
||||||
/* Unreachable lock. */
|
|
||||||
isc_rwlock_init(&zmgr->urlock);
|
|
||||||
|
|
||||||
isc_ratelimiter_create(loop, &zmgr->checkdsrl);
|
isc_ratelimiter_create(loop, &zmgr->checkdsrl);
|
||||||
isc_ratelimiter_create(loop, &zmgr->notifyrl);
|
isc_ratelimiter_create(loop, &zmgr->notifyrl);
|
||||||
isc_ratelimiter_create(loop, &zmgr->refreshrl);
|
isc_ratelimiter_create(loop, &zmgr->refreshrl);
|
||||||
@ -19410,7 +19382,6 @@ zonemgr_free(dns_zonemgr_t *zmgr) {
|
|||||||
isc_mem_cput(zmgr->mctx, zmgr->mctxpool, zmgr->workers,
|
isc_mem_cput(zmgr->mctx, zmgr->mctxpool, zmgr->workers,
|
||||||
sizeof(zmgr->mctxpool[0]));
|
sizeof(zmgr->mctxpool[0]));
|
||||||
|
|
||||||
isc_rwlock_destroy(&zmgr->urlock);
|
|
||||||
isc_rwlock_destroy(&zmgr->rwlock);
|
isc_rwlock_destroy(&zmgr->rwlock);
|
||||||
isc_rwlock_destroy(&zmgr->tlsctx_cache_rwlock);
|
isc_rwlock_destroy(&zmgr->tlsctx_cache_rwlock);
|
||||||
|
|
||||||
@ -19701,106 +19672,6 @@ dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) {
|
|||||||
return zmgr->serialqueryrate;
|
return zmgr->serialqueryrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
|
|
||||||
isc_sockaddr_t *local, isc_time_t *now) {
|
|
||||||
unsigned int i;
|
|
||||||
uint32_t seconds = isc_time_seconds(now);
|
|
||||||
uint32_t count = 0;
|
|
||||||
|
|
||||||
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
|
|
||||||
|
|
||||||
RWLOCK(&zmgr->urlock, isc_rwlocktype_read);
|
|
||||||
for (i = 0; i < UNREACH_CACHE_SIZE; i++) {
|
|
||||||
if (atomic_load(&zmgr->unreachable[i].expire) >= seconds &&
|
|
||||||
isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) &&
|
|
||||||
isc_sockaddr_equal(&zmgr->unreachable[i].local, local))
|
|
||||||
{
|
|
||||||
atomic_store_relaxed(&zmgr->unreachable[i].last,
|
|
||||||
seconds);
|
|
||||||
count = zmgr->unreachable[i].count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RWUNLOCK(&zmgr->urlock, isc_rwlocktype_read);
|
|
||||||
return i < UNREACH_CACHE_SIZE && count > 1U;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
|
|
||||||
isc_sockaddr_t *local) {
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
|
|
||||||
|
|
||||||
RWLOCK(&zmgr->urlock, isc_rwlocktype_read);
|
|
||||||
for (i = 0; i < UNREACH_CACHE_SIZE; i++) {
|
|
||||||
if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) &&
|
|
||||||
isc_sockaddr_equal(&zmgr->unreachable[i].local, local))
|
|
||||||
{
|
|
||||||
atomic_store_relaxed(&zmgr->unreachable[i].expire, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RWUNLOCK(&zmgr->urlock, isc_rwlocktype_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
|
|
||||||
isc_sockaddr_t *local, isc_time_t *now) {
|
|
||||||
uint32_t seconds = isc_time_seconds(now);
|
|
||||||
uint32_t expire = 0, last = seconds;
|
|
||||||
unsigned int slot = UNREACH_CACHE_SIZE, oldest = 0;
|
|
||||||
bool update_entry = true;
|
|
||||||
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
|
|
||||||
|
|
||||||
RWLOCK(&zmgr->urlock, isc_rwlocktype_write);
|
|
||||||
for (unsigned int i = 0; i < UNREACH_CACHE_SIZE; i++) {
|
|
||||||
/* Existing entry? */
|
|
||||||
if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) &&
|
|
||||||
isc_sockaddr_equal(&zmgr->unreachable[i].local, local))
|
|
||||||
{
|
|
||||||
update_entry = false;
|
|
||||||
slot = i;
|
|
||||||
expire = atomic_load_relaxed(
|
|
||||||
&zmgr->unreachable[i].expire);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Pick first empty slot? */
|
|
||||||
if (atomic_load_relaxed(&zmgr->unreachable[i].expire) < seconds)
|
|
||||||
{
|
|
||||||
slot = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* The worst case, least recently used slot? */
|
|
||||||
if (atomic_load_relaxed(&zmgr->unreachable[i].last) < last) {
|
|
||||||
last = atomic_load_relaxed(&zmgr->unreachable[i].last);
|
|
||||||
oldest = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We haven't found any existing or free slots, use the oldest */
|
|
||||||
if (slot == UNREACH_CACHE_SIZE) {
|
|
||||||
slot = oldest;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expire < seconds) {
|
|
||||||
/* Expired or new entry, reset count to 1 */
|
|
||||||
zmgr->unreachable[slot].count = 1;
|
|
||||||
} else {
|
|
||||||
zmgr->unreachable[slot].count++;
|
|
||||||
}
|
|
||||||
atomic_store_relaxed(&zmgr->unreachable[slot].expire,
|
|
||||||
seconds + UNREACH_HOLD_TIME);
|
|
||||||
atomic_store_relaxed(&zmgr->unreachable[slot].last, seconds);
|
|
||||||
if (update_entry) {
|
|
||||||
zmgr->unreachable[slot].remote = *remote;
|
|
||||||
zmgr->unreachable[slot].local = *local;
|
|
||||||
}
|
|
||||||
|
|
||||||
RWUNLOCK(&zmgr->urlock, isc_rwlocktype_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_zone_stopxfr(dns_zone_t *zone) {
|
dns_zone_stopxfr(dns_zone_t *zone) {
|
||||||
dns_xfrin_t *xfr = NULL;
|
dns_xfrin_t *xfr = NULL;
|
||||||
|
@ -50,6 +50,7 @@ check_PROGRAMS = \
|
|||||||
time_test \
|
time_test \
|
||||||
transport_test \
|
transport_test \
|
||||||
tsig_test \
|
tsig_test \
|
||||||
|
unreachcache_test \
|
||||||
update_test \
|
update_test \
|
||||||
zonefile_test \
|
zonefile_test \
|
||||||
zonemgr_test \
|
zonemgr_test \
|
||||||
|
189
tests/dns/unreachcache_test.c
Normal file
189
tests/dns/unreachcache_test.c
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* See the COPYRIGHT file distributed with this work for additional
|
||||||
|
* information regarding copyright ownership.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <sched.h> /* IWYU pragma: keep */
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define UNIT_TESTING
|
||||||
|
#include <cmocka.h>
|
||||||
|
|
||||||
|
#include <isc/buffer.h>
|
||||||
|
#include <isc/commandline.h>
|
||||||
|
#include <isc/lib.h>
|
||||||
|
#include <isc/md.h>
|
||||||
|
#include <isc/mem.h>
|
||||||
|
#include <isc/os.h>
|
||||||
|
#include <isc/sockaddr.h>
|
||||||
|
#include <isc/thread.h>
|
||||||
|
#include <isc/urcu.h>
|
||||||
|
#include <isc/util.h>
|
||||||
|
#include <isc/uv.h>
|
||||||
|
|
||||||
|
#include <dns/compress.h>
|
||||||
|
#include <dns/fixedname.h>
|
||||||
|
#include <dns/lib.h>
|
||||||
|
#include <dns/name.h>
|
||||||
|
#include <dns/rdatatype.h>
|
||||||
|
#include <dns/unreachcache.h>
|
||||||
|
|
||||||
|
#include <tests/dns.h>
|
||||||
|
|
||||||
|
#define EXPIRE_MIN_S 5
|
||||||
|
#define EXPIRE_MAX_S 10
|
||||||
|
#define BACKOFF_ELGIBLE_S 5
|
||||||
|
|
||||||
|
ISC_LOOP_TEST_IMPL(basic) {
|
||||||
|
dns_unreachcache_t *uc = NULL;
|
||||||
|
struct in_addr localhost4 = { 0 };
|
||||||
|
isc_sockaddr_t src_addrv4 = { 0 }, dst_addrv4 = { 0 },
|
||||||
|
src_addrv6 = { 0 }, dst_addrv6 = { 0 };
|
||||||
|
const uint16_t src_port = 1234;
|
||||||
|
const uint16_t dst_port = 5678;
|
||||||
|
isc_result_t result;
|
||||||
|
|
||||||
|
isc_sockaddr_fromin(&src_addrv4, &localhost4, src_port);
|
||||||
|
isc_sockaddr_fromin(&dst_addrv4, &localhost4, dst_port);
|
||||||
|
isc_sockaddr_fromin6(&src_addrv6, &in6addr_loopback, src_port);
|
||||||
|
isc_sockaddr_fromin6(&dst_addrv6, &in6addr_loopback, dst_port);
|
||||||
|
|
||||||
|
uc = dns_unreachcache_new(mctx, loopmgr, EXPIRE_MIN_S, EXPIRE_MAX_S,
|
||||||
|
BACKOFF_ELGIBLE_S);
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv6, &src_addrv6);
|
||||||
|
|
||||||
|
/* Added but unconfirmed (at least another add required to confirm). */
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv6, &src_addrv6);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
|
||||||
|
/* Confirmed. */
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv6, &src_addrv6);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv6, &src_addrv6);
|
||||||
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
/* Removal. */
|
||||||
|
dns_unreachcache_remove(uc, &dst_addrv6, &src_addrv6);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv6, &src_addrv6);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
|
||||||
|
/* Swapped addresses, should be not found. */
|
||||||
|
result = dns_unreachcache_find(uc, &src_addrv4, &dst_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
result = dns_unreachcache_find(uc, &src_addrv6, &dst_addrv6);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
|
||||||
|
dns_unreachcache_destroy(&uc);
|
||||||
|
|
||||||
|
isc_loopmgr_shutdown(loopmgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISC_LOOP_TEST_IMPL(expire) {
|
||||||
|
dns_unreachcache_t *uc = NULL;
|
||||||
|
struct in_addr localhost4 = { 0 };
|
||||||
|
isc_sockaddr_t src_addrv4 = { 0 }, dst_addrv4 = { 0 };
|
||||||
|
const uint16_t src_port = 1234;
|
||||||
|
const uint16_t dst_port = 5678;
|
||||||
|
isc_result_t result;
|
||||||
|
|
||||||
|
isc_sockaddr_fromin(&src_addrv4, &localhost4, src_port);
|
||||||
|
isc_sockaddr_fromin(&dst_addrv4, &localhost4, dst_port);
|
||||||
|
|
||||||
|
uc = dns_unreachcache_new(mctx, loopmgr, EXPIRE_MIN_S, EXPIRE_MAX_S,
|
||||||
|
BACKOFF_ELGIBLE_S);
|
||||||
|
/* Two adds to "confirm" the addition. */
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
sleep(EXPIRE_MIN_S);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because of the exponentatl backoff, the new quick addition after the
|
||||||
|
* previous expiration should expire in 2 x EXPIRE_MIN_S seconds.
|
||||||
|
*/
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
sleep(EXPIRE_MIN_S);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
sleep(EXPIRE_MIN_S);
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
|
||||||
|
dns_unreachcache_destroy(&uc);
|
||||||
|
|
||||||
|
isc_loopmgr_shutdown(loopmgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISC_LOOP_TEST_IMPL(flush) {
|
||||||
|
dns_unreachcache_t *uc = NULL;
|
||||||
|
struct in_addr localhost4 = { 0 };
|
||||||
|
isc_sockaddr_t src_addrv4 = { 0 }, dst_addrv4 = { 0 };
|
||||||
|
const uint16_t src_port = 1234;
|
||||||
|
const uint16_t dst_port = 5678;
|
||||||
|
isc_result_t result;
|
||||||
|
|
||||||
|
isc_sockaddr_fromin(&src_addrv4, &localhost4, src_port);
|
||||||
|
isc_sockaddr_fromin(&dst_addrv4, &localhost4, dst_port);
|
||||||
|
|
||||||
|
uc = dns_unreachcache_new(mctx, loopmgr, EXPIRE_MIN_S, EXPIRE_MAX_S,
|
||||||
|
BACKOFF_ELGIBLE_S);
|
||||||
|
/* Two adds to "confirm" the addition. */
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
dns_unreachcache_add(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
dns_unreachcache_flush(uc);
|
||||||
|
|
||||||
|
result = dns_unreachcache_find(uc, &dst_addrv4, &src_addrv4);
|
||||||
|
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||||
|
|
||||||
|
dns_unreachcache_destroy(&uc);
|
||||||
|
|
||||||
|
isc_loopmgr_shutdown(loopmgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISC_TEST_LIST_START
|
||||||
|
ISC_TEST_ENTRY_CUSTOM(basic, setup_managers, teardown_managers)
|
||||||
|
ISC_TEST_ENTRY_CUSTOM(expire, setup_managers, teardown_managers)
|
||||||
|
ISC_TEST_ENTRY_CUSTOM(flush, setup_managers, teardown_managers)
|
||||||
|
ISC_TEST_LIST_END
|
||||||
|
|
||||||
|
ISC_TEST_MAIN
|
@ -125,75 +125,10 @@ ISC_LOOP_TEST_IMPL(zonemgr_createzone) {
|
|||||||
isc_loopmgr_shutdown(loopmgr);
|
isc_loopmgr_shutdown(loopmgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* manage and release a zone */
|
|
||||||
ISC_LOOP_TEST_IMPL(zonemgr_unreachable) {
|
|
||||||
dns_zonemgr_t *myzonemgr = NULL;
|
|
||||||
dns_zone_t *zone = NULL;
|
|
||||||
isc_sockaddr_t addr1, addr2;
|
|
||||||
struct in_addr in;
|
|
||||||
isc_result_t result;
|
|
||||||
isc_time_t now;
|
|
||||||
|
|
||||||
UNUSED(arg);
|
|
||||||
|
|
||||||
now = isc_time_now();
|
|
||||||
|
|
||||||
dns_zonemgr_create(mctx, netmgr, &myzonemgr);
|
|
||||||
|
|
||||||
result = dns_test_makezone("foo", &zone, NULL, false);
|
|
||||||
assert_int_equal(result, ISC_R_SUCCESS);
|
|
||||||
|
|
||||||
result = dns_zonemgr_managezone(myzonemgr, zone);
|
|
||||||
assert_int_equal(result, ISC_R_SUCCESS);
|
|
||||||
|
|
||||||
in.s_addr = inet_addr("10.53.0.1");
|
|
||||||
isc_sockaddr_fromin(&addr1, &in, 2112);
|
|
||||||
in.s_addr = inet_addr("10.53.0.2");
|
|
||||||
isc_sockaddr_fromin(&addr2, &in, 5150);
|
|
||||||
assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
/*
|
|
||||||
* We require multiple unreachableadd calls to mark a server as
|
|
||||||
* unreachable.
|
|
||||||
*/
|
|
||||||
dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
|
|
||||||
assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
|
|
||||||
assert_true(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
|
|
||||||
in.s_addr = inet_addr("10.53.0.3");
|
|
||||||
isc_sockaddr_fromin(&addr2, &in, 5150);
|
|
||||||
assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
/*
|
|
||||||
* We require multiple unreachableadd calls to mark a server as
|
|
||||||
* unreachable.
|
|
||||||
*/
|
|
||||||
dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
|
|
||||||
dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
|
|
||||||
assert_true(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
|
|
||||||
dns_zonemgr_unreachabledel(myzonemgr, &addr1, &addr2);
|
|
||||||
assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
|
|
||||||
in.s_addr = inet_addr("10.53.0.2");
|
|
||||||
isc_sockaddr_fromin(&addr2, &in, 5150);
|
|
||||||
assert_true(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
dns_zonemgr_unreachabledel(myzonemgr, &addr1, &addr2);
|
|
||||||
assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
|
|
||||||
|
|
||||||
dns_zonemgr_releasezone(myzonemgr, zone);
|
|
||||||
dns_zone_detach(&zone);
|
|
||||||
dns_zonemgr_shutdown(myzonemgr);
|
|
||||||
dns_zonemgr_detach(&myzonemgr);
|
|
||||||
assert_null(myzonemgr);
|
|
||||||
|
|
||||||
isc_loopmgr_shutdown(loopmgr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISC_TEST_LIST_START
|
ISC_TEST_LIST_START
|
||||||
ISC_TEST_ENTRY_CUSTOM(zonemgr_create, setup_test, teardown_test)
|
ISC_TEST_ENTRY_CUSTOM(zonemgr_create, setup_test, teardown_test)
|
||||||
ISC_TEST_ENTRY_CUSTOM(zonemgr_managezone, setup_test, teardown_test)
|
ISC_TEST_ENTRY_CUSTOM(zonemgr_managezone, setup_test, teardown_test)
|
||||||
ISC_TEST_ENTRY_CUSTOM(zonemgr_createzone, setup_test, teardown_test)
|
ISC_TEST_ENTRY_CUSTOM(zonemgr_createzone, setup_test, teardown_test)
|
||||||
ISC_TEST_ENTRY_CUSTOM(zonemgr_unreachable, setup_test, teardown_test)
|
|
||||||
ISC_TEST_LIST_END
|
ISC_TEST_LIST_END
|
||||||
|
|
||||||
ISC_TEST_MAIN
|
ISC_TEST_MAIN
|
||||||
|
Loading…
x
Reference in New Issue
Block a user