diff options
| author | Cy Schubert <cy@FreeBSD.org> | 2024-10-18 13:52:55 +0000 |
|---|---|---|
| committer | Cy Schubert <cy@FreeBSD.org> | 2024-10-18 13:52:55 +0000 |
| commit | 0a6d797cf6eb751d7eb613900cd19803e05d905f (patch) | |
| tree | c52b0ffbf8879fbe81816528e0fc7c3dd0f64e1f /iterator | |
| parent | 9b8db746ac608ff7cdad3c9ac7ac395319e4ea0f (diff) | |
Diffstat (limited to 'iterator')
| -rw-r--r-- | iterator/iter_scrub.c | 45 | ||||
| -rw-r--r-- | iterator/iter_utils.c | 42 | ||||
| -rw-r--r-- | iterator/iter_utils.h | 7 | ||||
| -rw-r--r-- | iterator/iterator.c | 57 | ||||
| -rw-r--r-- | iterator/iterator.h | 2 |
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 |
