summaryrefslogtreecommitdiff
path: root/iterator
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2024-10-18 13:52:55 +0000
committerCy Schubert <cy@FreeBSD.org>2024-10-18 13:52:55 +0000
commit0a6d797cf6eb751d7eb613900cd19803e05d905f (patch)
treec52b0ffbf8879fbe81816528e0fc7c3dd0f64e1f /iterator
parent9b8db746ac608ff7cdad3c9ac7ac395319e4ea0f (diff)
Diffstat (limited to 'iterator')
-rw-r--r--iterator/iter_scrub.c45
-rw-r--r--iterator/iter_utils.c42
-rw-r--r--iterator/iter_utils.h7
-rw-r--r--iterator/iterator.c57
-rw-r--r--iterator/iterator.h2
5 files changed, 130 insertions, 23 deletions
diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c
index f038ad69af0e..49a5f5da19c2 100644
--- a/iterator/iter_scrub.c
+++ b/iterator/iter_scrub.c
@@ -443,7 +443,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
prev = NULL;
rrset = msg->rrset_first;
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
- if(cname_length > 11 /* env->cfg.iter_scrub_cname */) {
+ if(cname_length > env->cfg->iter_scrub_cname) {
/* Too many CNAMEs, or DNAMEs, from the authority
* server, scrub down the length to something
* shorter. This deletes everything after the limit
@@ -562,8 +562,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
dname_pkt_compare(pkt, oldsname,
rrset->dname) == 0) {
if(rrset->type == LDNS_RR_TYPE_NS &&
- rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
- shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
+ rrset->rr_count > env->cfg->iter_scrub_ns) {
+ shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
}
prev = rrset;
rrset = rrset->rrset_all_next;
@@ -581,8 +581,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
}
if(rrset->type == LDNS_RR_TYPE_NS &&
- rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
- shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
+ rrset->rr_count > env->cfg->iter_scrub_ns) {
+ shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
}
/* Mark the additional names from relevant rrset as OK. */
@@ -641,7 +641,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
}
- if(rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
+ if(rrset->rr_count > env->cfg->iter_scrub_ns) {
/* If this is not a referral, and the NS RRset
* is signed, then remove it entirely, so
* that when it becomes bogus it does not
@@ -657,7 +657,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
} else {
- shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
+ shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
}
}
}
@@ -871,6 +871,7 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
{
int del_addi = 0; /* if additional-holding rrsets are deleted, we
do not trust the normalized additional-A-AAAA any more */
+ uint8_t* ns_rrset_dname = NULL;
int added_rrlen_ede = 0;
struct rrset_parse* rrset, *prev;
prev = NULL;
@@ -976,6 +977,16 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
continue;
}
}
+ if(rrset->type == LDNS_RR_TYPE_NS &&
+ (rrset->section == LDNS_SECTION_AUTHORITY ||
+ rrset->section == LDNS_SECTION_ANSWER)) {
+ /* If the type is NS, and we're in the
+ * answer or authority section, then
+ * store the dname so we can check
+ * against the glue records
+ * further down */
+ ns_rrset_dname = rrset->dname;
+ }
if(del_addi && rrset->section == LDNS_SECTION_ADDITIONAL) {
remove_rrset("sanitize: removing potential "
"poison reference RRset:", pkt, msg, prev, &rrset);
@@ -988,6 +999,26 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
}
+ if(env->cfg->harden_unverified_glue && ns_rrset_dname &&
+ rrset->section == LDNS_SECTION_ADDITIONAL &&
+ (rrset->type == LDNS_RR_TYPE_A || rrset->type == LDNS_RR_TYPE_AAAA) &&
+ !pkt_strict_sub(pkt, rrset->dname, ns_rrset_dname)) {
+ /* We're in the additional section, looking
+ * at an A/AAAA rrset, have a previous
+ * delegation point and we notice that
+ * the glue records are NOT for strict
+ * subdomains of the delegation. So set a
+ * flag, recompute the hash for the rrset
+ * and write the A/AAAA record to cache.
+ * It'll be retrieved if we can't separately
+ * resolve the glue */
+ rrset->flags = PACKED_RRSET_UNVERIFIED_GLUE;
+ rrset->hash = pkt_hash_rrset(pkt, rrset->dname, rrset->type, rrset->rrset_class, rrset->flags);
+ store_rrset(pkt, msg, env, rrset);
+ remove_rrset("sanitize: storing potential "
+ "unverified glue reference RRset:", pkt, msg, prev, &rrset);
+ continue;
+ }
prev = rrset;
rrset = rrset->rrset_all_next;
}
diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c
index 1b4f5f6ebb4f..cacba420e845 100644
--- a/iterator/iter_utils.c
+++ b/iterator/iter_utils.c
@@ -1564,3 +1564,45 @@ void iterator_set_ip46_support(struct module_stack* mods,
if(outnet->num_ip6 == 0)
ie->supports_ipv6 = 0;
}
+
+void
+limit_nsec_ttl(struct dns_msg* msg)
+{
+ /* Limit NSEC and NSEC3 TTL in response, RFC9077 */
+ size_t i;
+ int found = 0;
+ time_t soa_ttl = 0;
+ /* Limit the NSEC and NSEC3 TTL values to the SOA TTL and SOA minimum
+ * TTL. That has already been applied to the SOA record ttl. */
+ for(i=0; i<msg->rep->rrset_count; i++) {
+ struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA) {
+ struct packed_rrset_data* soadata = (struct packed_rrset_data*)s->entry.data;
+ found = 1;
+ soa_ttl = soadata->ttl;
+ break;
+ }
+ }
+ if(!found)
+ return;
+ for(i=0; i<msg->rep->rrset_count; i++) {
+ struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC ||
+ ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
+ struct packed_rrset_data* data = (struct packed_rrset_data*)s->entry.data;
+ /* Limit the negative TTL. */
+ if(data->ttl > soa_ttl) {
+ if(verbosity >= VERB_ALGO) {
+ char buf[256];
+ snprintf(buf, sizeof(buf),
+ "limiting TTL %d of %s record to the SOA TTL of %d for",
+ (int)data->ttl, ((ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC)?"NSEC":"NSEC3"), (int)soa_ttl);
+ log_nametypeclass(VERB_ALGO, buf,
+ s->rk.dname, ntohs(s->rk.type),
+ ntohs(s->rk.rrset_class));
+ }
+ data->ttl = soa_ttl;
+ }
+ }
+ }
+}
diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h
index 4024629e686c..0361e43775e1 100644
--- a/iterator/iter_utils.h
+++ b/iterator/iter_utils.h
@@ -428,4 +428,11 @@ int iter_stub_fwd_no_cache(struct module_qstate *qstate,
void iterator_set_ip46_support(struct module_stack* mods,
struct module_env* env, struct outside_network* outnet);
+/**
+ * Limit NSEC and NSEC3 TTL in response, RFC9077
+ * @param msg: dns message, the SOA record ttl is used to restrict ttls
+ * of NSEC and NSEC3 RRsets. If no SOA record, nothing happens.
+ */
+void limit_nsec_ttl(struct dns_msg* msg);
+
#endif /* ITERATOR_ITER_UTILS_H */
diff --git a/iterator/iterator.c b/iterator/iterator.c
index 228f5dfaef30..59e4b36ce364 100644
--- a/iterator/iterator.c
+++ b/iterator/iterator.c
@@ -70,6 +70,8 @@
#include "sldns/parseutil.h"
#include "sldns/sbuffer.h"
+/* number of packets */
+int MAX_GLOBAL_QUOTA = 128;
/* in msec */
int UNKNOWN_SERVER_NICENESS = 376;
/* in msec */
@@ -252,7 +254,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
} else {
/* see if the failure did get (parent-lame) info */
if(!cache_fill_missing(super->env, super_iq->qchase.qclass,
- super->region, super_iq->dp))
+ super->region, super_iq->dp, 0))
log_err("out of memory adding missing");
}
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
@@ -320,16 +322,21 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
qstate->qinfo.qname, qstate->qinfo.qname_len,
qstate->qinfo.qtype, qstate->qinfo.qclass,
qstate->query_flags, 0,
- qstate->env->cfg->serve_expired_ttl_reset)) != NULL) {
+ qstate->env->cfg->serve_expired)) != NULL) {
struct reply_info* rep = (struct reply_info*)msg->entry.data;
- if(qstate->env->cfg->serve_expired &&
- qstate->env->cfg->serve_expired_ttl_reset && rep &&
- *qstate->env->now + qstate->env->cfg->serve_expired_ttl
- > rep->serve_expired_ttl) {
- verbose(VERB_ALGO, "reset serve-expired-ttl for "
+ if(qstate->env->cfg->serve_expired && rep) {
+ if(qstate->env->cfg->serve_expired_ttl_reset &&
+ *qstate->env->now + qstate->env->cfg->serve_expired_ttl
+ > rep->serve_expired_ttl) {
+ verbose(VERB_ALGO, "reset serve-expired-ttl for "
+ "response in cache");
+ rep->serve_expired_ttl = *qstate->env->now +
+ qstate->env->cfg->serve_expired_ttl;
+ }
+ verbose(VERB_ALGO, "set serve-expired-norec-ttl for "
"response in cache");
- rep->serve_expired_ttl = *qstate->env->now +
- qstate->env->cfg->serve_expired_ttl;
+ rep->serve_expired_norec_ttl = NORR_TTL +
+ *qstate->env->now;
}
if(rep && (FLAGS_GET_RCODE(rep->flags) ==
LDNS_RCODE_NOERROR ||
@@ -407,8 +414,11 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* msg,
num_an = 0;
for(p = iq->an_prepend_list; p; p = p->next) {
sets[num_an++] = p->rrset;
- if(ub_packed_rrset_ttl(p->rrset) < msg->rep->ttl)
+ if(ub_packed_rrset_ttl(p->rrset) < msg->rep->ttl) {
msg->rep->ttl = ub_packed_rrset_ttl(p->rrset);
+ msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
+ }
}
memcpy(sets+num_an, msg->rep->rrsets, msg->rep->an_numrrsets *
sizeof(struct ub_packed_rrset_key*));
@@ -421,8 +431,11 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* msg,
msg->rep->ns_numrrsets, p->rrset))
continue;
sets[msg->rep->an_numrrsets + num_an + num_ns++] = p->rrset;
- if(ub_packed_rrset_ttl(p->rrset) < msg->rep->ttl)
+ if(ub_packed_rrset_ttl(p->rrset) < msg->rep->ttl) {
msg->rep->ttl = ub_packed_rrset_ttl(p->rrset);
+ msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
+ }
}
memcpy(sets + num_an + msg->rep->an_numrrsets + num_ns,
msg->rep->rrsets + msg->rep->an_numrrsets,
@@ -1569,7 +1582,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
- qstate->region, iq->dp)) {
+ qstate->region, iq->dp, 0)) {
errinf(qstate, "malloc failure, copy extra info into delegation point");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
@@ -2150,6 +2163,15 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
verbose(VERB_QUERY, "configured stub or forward servers failed -- returning SERVFAIL");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
+ if(qstate->env->cfg->harden_unverified_glue) {
+ if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
+ qstate->region, iq->dp, PACKED_RRSET_UNVERIFIED_GLUE))
+ log_err("out of memory in cache_fill_missing");
+ if(iq->dp->usable_list) {
+ verbose(VERB_ALGO, "try unverified glue from cache");
+ return next_state(iq, QUERYTARGETS_STATE);
+ }
+ }
if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) {
struct delegpt* dp;
int nolock = 0;
@@ -2192,7 +2214,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
}
/* see if that makes new names available */
if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
- qstate->region, iq->dp))
+ qstate->region, iq->dp, 0))
log_err("out of memory in cache_fill_missing");
if(iq->dp->usable_list) {
verbose(VERB_ALGO, "try parent-side-name, w. glue from cache");
@@ -3424,7 +3446,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
old_dp->name, old_dp->namelen);
}
if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
- qstate->region, iq->dp)) {
+ qstate->region, iq->dp, 0)) {
errinf(qstate, "malloc failure, copy extra info into delegation point");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
@@ -3993,6 +4015,8 @@ processClassResponse(struct module_qstate* qstate, int id,
to->rep->prefetch_ttl = from->rep->prefetch_ttl;
if(from->rep->serve_expired_ttl < to->rep->serve_expired_ttl)
to->rep->serve_expired_ttl = from->rep->serve_expired_ttl;
+ if(from->rep->serve_expired_norec_ttl < to->rep->serve_expired_norec_ttl)
+ to->rep->serve_expired_norec_ttl = from->rep->serve_expired_norec_ttl;
}
/* are we done? */
foriq->num_current_queries --;
@@ -4355,7 +4379,10 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if(verbosity >= VERB_ALGO)
log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
iq->response->rep);
-
+
+ if(qstate->env->cfg->aggressive_nsec) {
+ limit_nsec_ttl(iq->response);
+ }
if(event == module_event_capsfail || iq->caps_fallback) {
if(qstate->env->cfg->qname_minimisation &&
iq->minimisation_state != DONOT_MINIMISE_STATE) {
diff --git a/iterator/iterator.h b/iterator/iterator.h
index 70b11df7ebcf..46701f6eee75 100644
--- a/iterator/iterator.h
+++ b/iterator/iterator.h
@@ -57,7 +57,7 @@ struct rbtree_type;
#define MAX_TARGET_COUNT 64
/** max number of upstream queries for a query and its subqueries, it is
* never reset. */
-#define MAX_GLOBAL_QUOTA 128
+extern int MAX_GLOBAL_QUOTA;
/** max number of target lookups per qstate, per delegation point */
#define MAX_DP_TARGET_COUNT 16
/** max number of nxdomains allowed for target lookups for a query and