summaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2022-08-05 20:02:55 +0000
committerCy Schubert <cy@FreeBSD.org>2022-08-05 20:02:55 +0000
commit9b76d32f2310b735dbeb896cbf2776cad61f23e8 (patch)
treecac9730d14d9c15b0c773429e65bba9e97506c93 /services
parentd57351465531b38689892ec862de2725b52842dd (diff)
Diffstat (limited to 'services')
-rw-r--r--services/authzone.c1
-rw-r--r--services/cache/dns.c111
-rw-r--r--services/cache/dns.h18
-rw-r--r--services/cache/infra.c6
-rw-r--r--services/listen_dnsport.c17
-rw-r--r--services/mesh.c1
6 files changed, 131 insertions, 23 deletions
diff --git a/services/authzone.c b/services/authzone.c
index 5f2b7154a946..b9e0b11ef3bb 100644
--- a/services/authzone.c
+++ b/services/authzone.c
@@ -8189,7 +8189,6 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
keystorage->rk.type = htons(LDNS_RR_TYPE_DNSKEY);
keystorage->rk.rrset_class = htons(z->dclass);
auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS");
- // @TODO add EDE here? we currently just pass NULL
sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg,
why_bogus, NULL, NULL);
regional_free_all(env->scratch);
diff --git a/services/cache/dns.c b/services/cache/dns.c
index f6c11451c93a..6bca8d85fadb 100644
--- a/services/cache/dns.c
+++ b/services/cache/dns.c
@@ -68,11 +68,16 @@
* in a prefetch situation to be updated (without becoming sticky).
* @param qrep: update rrsets here if cache is better
* @param region: for qrep allocs.
+ * @param qstarttime: time when delegations were looked up, this is perhaps
+ * earlier than the time in now. The time is used to determine if RRsets
+ * of type NS have expired, so that they can only be updated using
+ * lookups of delegation points that did not use them, since they had
+ * expired then.
*/
static void
store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
time_t leeway, int pside, struct reply_info* qrep,
- struct regional* region)
+ struct regional* region, time_t qstarttime)
{
size_t i;
/* see if rrset already exists in cache, if not insert it. */
@@ -81,8 +86,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
rep->ref[i].id = rep->rrsets[i]->id;
/* update ref if it was in the cache */
switch(rrset_cache_update(env->rrset_cache, &rep->ref[i],
- env->alloc, now + ((ntohs(rep->ref[i].key->rk.type)==
- LDNS_RR_TYPE_NS && !pside)?0:leeway))) {
+ env->alloc, ((ntohs(rep->ref[i].key->rk.type)==
+ LDNS_RR_TYPE_NS && !pside)?qstarttime:now + leeway))) {
case 0: /* ref unchanged, item inserted */
break;
case 2: /* ref updated, cache is superior */
@@ -155,7 +160,8 @@ msg_del_servfail(struct module_env* env, struct query_info* qinfo,
void
dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside,
- struct reply_info* qrep, uint32_t flags, struct regional* region)
+ struct reply_info* qrep, uint32_t flags, struct regional* region,
+ time_t qstarttime)
{
struct msgreply_entry* e;
time_t ttl = rep->ttl;
@@ -170,7 +176,8 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
/* there was a reply_info_sortref(rep) here but it seems to be
* unnecessary, because the cache gets locked per rrset. */
reply_info_set_ttls(rep, *env->now);
- store_rrsets(env, rep, *env->now, leeway, pside, qrep, region);
+ store_rrsets(env, rep, *env->now, leeway, pside, qrep, region,
+ qstarttime);
if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) {
/* we do not store the message, but we did store the RRs,
* which could be useful for delegation information */
@@ -194,10 +201,51 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc);
}
+/** see if an rrset is expired above the qname, return upper qname. */
+static int
+rrset_expired_above(struct module_env* env, uint8_t** qname, size_t* qnamelen,
+ uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* expiretop,
+ size_t expiretoplen)
+{
+ struct ub_packed_rrset_key *rrset;
+ uint8_t lablen;
+
+ while(*qnamelen > 0) {
+ /* look one label higher */
+ lablen = **qname;
+ *qname += lablen + 1;
+ *qnamelen -= lablen + 1;
+ if(*qnamelen <= 0)
+ break;
+
+ /* looks up with a time of 0, to see expired entries */
+ if((rrset = rrset_cache_lookup(env->rrset_cache, *qname,
+ *qnamelen, searchtype, qclass, 0, 0, 0))) {
+ struct packed_rrset_data* data =
+ (struct packed_rrset_data*)rrset->entry.data;
+ if(now > data->ttl) {
+ /* it is expired, this is not wanted */
+ lock_rw_unlock(&rrset->entry.lock);
+ log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
+ return 1;
+ }
+ /* it is not expired, continue looking */
+ lock_rw_unlock(&rrset->entry.lock);
+ }
+
+ /* do not look above the expiretop. */
+ if(expiretop && *qnamelen == expiretoplen &&
+ query_dname_compare(*qname, expiretop)==0)
+ break;
+ }
+ return 0;
+}
+
/** find closest NS or DNAME and returns the rrset (locked) */
static struct ub_packed_rrset_key*
find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
- uint16_t qclass, time_t now, uint16_t searchtype, int stripfront)
+ uint16_t qclass, time_t now, uint16_t searchtype, int stripfront,
+ int noexpiredabove, uint8_t* expiretop, size_t expiretoplen)
{
struct ub_packed_rrset_key *rrset;
uint8_t lablen;
@@ -212,8 +260,40 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
/* snip off front part of qname until the type is found */
while(qnamelen > 0) {
if((rrset = rrset_cache_lookup(env->rrset_cache, qname,
- qnamelen, searchtype, qclass, 0, now, 0)))
- return rrset;
+ qnamelen, searchtype, qclass, 0, now, 0))) {
+ uint8_t* origqname = qname;
+ size_t origqnamelen = qnamelen;
+ if(!noexpiredabove)
+ return rrset;
+ /* if expiretop set, do not look above it, but
+ * qname is equal, so the just found result is also
+ * the nonexpired above part. */
+ if(expiretop && qnamelen == expiretoplen &&
+ query_dname_compare(qname, expiretop)==0)
+ return rrset;
+ /* check for expiry, but we have to let go of the rrset
+ * for the lock ordering */
+ lock_rw_unlock(&rrset->entry.lock);
+ /* the expired_above function always takes off one
+ * label (if qnamelen>0) and returns the final qname
+ * where it searched, so we can continue from there
+ * turning the O N*N search into O N. */
+ if(!rrset_expired_above(env, &qname, &qnamelen,
+ searchtype, qclass, now, expiretop,
+ expiretoplen)) {
+ /* we want to return rrset, but it may be
+ * gone from cache, if so, just loop like
+ * it was not in the cache in the first place.
+ */
+ if((rrset = rrset_cache_lookup(env->
+ rrset_cache, origqname, origqnamelen,
+ searchtype, qclass, 0, now, 0))) {
+ return rrset;
+ }
+ }
+ log_nametypeclass(VERB_ALGO, "ignoring rrset because expired rrsets exist above it", origqname, searchtype, qclass);
+ continue;
+ }
/* snip off front label */
lablen = *qname;
@@ -462,7 +542,8 @@ dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
struct delegpt*
dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
size_t qnamelen, uint16_t qtype, uint16_t qclass,
- struct regional* region, struct dns_msg** msg, time_t now)
+ struct regional* region, struct dns_msg** msg, time_t now,
+ int noexpiredabove, uint8_t* expiretop, size_t expiretoplen)
{
/* try to find closest NS rrset */
struct ub_packed_rrset_key* nskey;
@@ -470,7 +551,7 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
struct delegpt* dp;
nskey = find_closest_of_type(env, qname, qnamelen, qclass, now,
- LDNS_RR_TYPE_NS, 0);
+ LDNS_RR_TYPE_NS, 0, noexpiredabove, expiretop, expiretoplen);
if(!nskey) /* hope the caller has hints to prime or something */
return NULL;
nsdata = (struct packed_rrset_data*)nskey->entry.data;
@@ -840,7 +921,7 @@ dns_cache_lookup(struct module_env* env,
* consistent with the DNAME */
if(!no_partial &&
(rrset=find_closest_of_type(env, qname, qnamelen, qclass, now,
- LDNS_RR_TYPE_DNAME, 1))) {
+ LDNS_RR_TYPE_DNAME, 1, 0, NULL, 0))) {
/* synthesize a DNAME+CNAME message based on this */
enum sec_status sec_status = sec_status_unchecked;
struct dns_msg* msg = synth_dname_msg(rrset, region, now, &k,
@@ -973,7 +1054,7 @@ dns_cache_lookup(struct module_env* env,
int
dns_cache_store(struct module_env* env, struct query_info* msgqinf,
struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
- struct regional* region, uint32_t flags)
+ struct regional* region, uint32_t flags, time_t qstarttime)
{
struct reply_info* rep = NULL;
/* alloc, malloc properly (not in region, like msg is) */
@@ -996,9 +1077,9 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
/*ignore ret: it was in the cache, ref updated */
/* no leeway for typeNS */
(void)rrset_cache_update(env->rrset_cache, &ref,
- env->alloc, *env->now +
+ env->alloc,
((ntohs(ref.key->rk.type)==LDNS_RR_TYPE_NS
- && !pside) ? 0:leeway));
+ && !pside) ? qstarttime:*env->now + leeway));
}
free(rep);
return 1;
@@ -1020,7 +1101,7 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
rep->flags &= ~(BIT_AA | BIT_CD);
h = query_info_hash(&qinf, (uint16_t)flags);
dns_cache_store_msg(env, &qinf, h, rep, leeway, pside, msgrep,
- flags, region);
+ flags, region, qstarttime);
/* qname is used inside query_info_entrysetup, and set to
* NULL. If it has not been used, free it. free(0) is safe. */
free(qinf.qname);
diff --git a/services/cache/dns.h b/services/cache/dns.h
index bece83702960..147f992cbc74 100644
--- a/services/cache/dns.h
+++ b/services/cache/dns.h
@@ -88,11 +88,13 @@ struct dns_msg {
* @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
* The higher 16 bits are used internally to customize the cache policy.
* (See DNSCACHE_STORE_xxx flags).
+ * @param qstarttime: time when the query was started, and thus when the
+ * delegations were looked up.
* @return 0 on alloc error (out of memory).
*/
int dns_cache_store(struct module_env* env, struct query_info* qinf,
struct reply_info* rep, int is_referral, time_t leeway, int pside,
- struct regional* region, uint32_t flags);
+ struct regional* region, uint32_t flags, time_t qstarttime);
/**
* Store message in the cache. Stores in message cache and rrset cache.
@@ -112,11 +114,14 @@ int dns_cache_store(struct module_env* env, struct query_info* qinf,
* can be updated to full TTL even in prefetch situations.
* @param qrep: message that can be altered with better rrs from cache.
* @param flags: customization flags for the cache policy.
+ * @param qstarttime: time when the query was started, and thus when the
+ * delegations were looked up.
* @param region: to allocate into for qmsg.
*/
void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside,
- struct reply_info* qrep, uint32_t flags, struct regional* region);
+ struct reply_info* qrep, uint32_t flags, struct regional* region,
+ time_t qstarttime);
/**
* Find a delegation from the cache.
@@ -129,11 +134,18 @@ void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
* @param msg: if not NULL, delegation message is returned here, synthesized
* from the cache.
* @param timenow: the time now, for checking if TTL on cache entries is OK.
+ * @param noexpiredabove: if set, no expired NS rrsets above the one found
+ * are tolerated. It only returns delegations where the delegations above
+ * it are valid.
+ * @param expiretop: if not NULL, name where check for expiry ends for
+ * noexpiredabove.
+ * @param expiretoplen: length of expiretop dname.
* @return new delegation or NULL on error or if not found in cache.
*/
struct delegpt* dns_cache_find_delegation(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
- struct regional* region, struct dns_msg** msg, time_t timenow);
+ struct regional* region, struct dns_msg** msg, time_t timenow,
+ int noexpiredabove, uint8_t* expiretop, size_t expiretoplen);
/**
* generate dns_msg from cached message
diff --git a/services/cache/infra.c b/services/cache/infra.c
index 252e1e288b35..0461c815b86b 100644
--- a/services/cache/infra.c
+++ b/services/cache/infra.c
@@ -721,13 +721,13 @@ infra_get_lame_rtt(struct infra_cache* infra,
else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
}
}
+ /* expired entry */
if(timenow > host->ttl) {
- /* expired entry */
+
/* see if this can be a re-probe of an unresponsive server */
/* minus 1000 because that is outside of the RTTBAND, so
* blacklisted servers stay blacklisted if this is chosen */
- if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT ||
- infra->infra_keep_probing) {
+ if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
lock_rw_unlock(&e->lock);
*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
*lame = 0;
diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c
index 03153bd64778..1c7c177a007e 100644
--- a/services/listen_dnsport.c
+++ b/services/listen_dnsport.c
@@ -490,6 +490,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
return -1;
}
# elif defined(IPV6_MTU)
+# ifndef USE_WINSOCK
/*
* On Linux, to send no larger than 1280, the PMTUD is
* disabled by default for datagrams anyway, so we set
@@ -497,13 +498,27 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
*/
if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU,
(void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
- log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
+ log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
sock_strerror(errno));
sock_close(s);
*noproto = 0;
*inuse = 0;
return -1;
}
+# elif defined(IPV6_USER_MTU)
+ /* As later versions of the mingw crosscompiler define
+ * IPV6_MTU, do the same for windows but use IPV6_USER_MTU
+ * instead which is writable; IPV6_MTU is readonly there. */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_USER_MTU,
+ (void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
+ log_err("setsockopt(..., IPV6_USER_MTU, ...) failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ sock_close(s);
+ *noproto = 0;
+ *inuse = 0;
+ return -1;
+ }
+# endif /* USE_WINSOCK */
# endif /* IPv6 MTU */
# if defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
# if defined(IP_PMTUDISC_OMIT)
diff --git a/services/mesh.c b/services/mesh.c
index c40eb50dc55c..30bcf7cda155 100644
--- a/services/mesh.c
+++ b/services/mesh.c
@@ -954,6 +954,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
mstate->s.no_cache_store = 0;
mstate->s.need_refetch = 0;
mstate->s.was_ratelimited = 0;
+ mstate->s.qstarttime = *env->now;
/* init modules */
for(i=0; i<env->mesh->mods.num; i++) {