diff --git a/dnscrypt/dnscrypt.c b/dnscrypt/dnscrypt.c index 4902447fd..173484cdf 100644 --- a/dnscrypt/dnscrypt.c +++ b/dnscrypt/dnscrypt.c @@ -361,7 +361,7 @@ dnscrypt_server_uncurve(struct dnsc_env* env, len -= DNSCRYPT_QUERY_HEADER_SIZE; - while (*sldns_buffer_at(buffer, --len) == 0) + while (len>0 && *sldns_buffer_at(buffer, --len) == 0) ; if (*sldns_buffer_at(buffer, len) != 0x80) { diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c index 37c4150cd..74a258640 100644 --- a/iterator/iter_scrub.c +++ b/iterator/iter_scrub.c @@ -777,7 +777,13 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, rrset->rrset_all_next = NULL; return 1; } - mark_additional_rrset(pkt, msg, rrset); + /* Only mark glue as allowed for type NS in the authority + * section. Other RR types do not get glue for them, it + * is allowed from the answer section, but not authority + * so that a message can not have address records cached + * as a side effect to the query. */ + if(rrset->type==LDNS_RR_TYPE_NS) + mark_additional_rrset(pkt, msg, rrset); prev = rrset; rrset = rrset->rrset_all_next; } diff --git a/services/cache/dns.c b/services/cache/dns.c index c593dcd72..f6ce272a5 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -712,10 +712,16 @@ struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region) { size_t i; + struct ub_packed_rrset_key** saved_rrsets; struct dns_msg* res = NULL; + size_t rep_alloc_size = sizeof(struct reply_info) + - sizeof(struct rrset_ref); /* this is the size of res->rep + allocated in gen_dns_msg() */ res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count); if(!res) return NULL; - *res->rep = *origin->rep; + saved_rrsets = res->rep->rrsets; /* save rrsets alloc by gen_dns_msg */ + memcpy(res->rep, origin->rep, rep_alloc_size); + res->rep->rrsets = saved_rrsets; if(origin->rep->reason_bogus_str) { res->rep->reason_bogus_str = regional_strdup(region, origin->rep->reason_bogus_str); diff --git a/services/cache/rrset.c b/services/cache/rrset.c index c1716a565..ab4f4c8e0 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -149,6 +149,16 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) && cached->security == sec_status_bogus) return 0; + /* ghost-domain: never let an NS overwrite extend lifetime + * past the entry it replaces, regardless of trust. */ + if(ns && !TTL_IS_EXPIRED(cached->ttl, timenow) && + newd->ttl > cached->ttl) { + size_t i; + newd->ttl = cached->ttl; + for(i=0; i<(newd->count+newd->rrsig_count); i++) + if(newd->rr_ttl[i] > newd->ttl) + newd->rr_ttl[i] = newd->ttl; + } return 1; } /* o item in cache has expired */ diff --git a/services/mesh.c b/services/mesh.c index 433aabc9c..286901047 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -297,12 +297,14 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf) if(mesh->num_reply_states < mesh->max_reply_states) return 1; /* try to kick out a jostle-list item */ - if(m && m->reply_list && m->list_select == mesh_jostle_list) { + if(m && m->list_select == mesh_jostle_list) { /* how old is it? */ struct timeval age; - timeval_subtract(&age, mesh->env->now_tv, - &m->reply_list->start_time); - if(timeval_smaller(&mesh->jostle_max, &age)) { + if(m->has_first_reply_time) + timeval_subtract(&age, mesh->env->now_tv, + &m->first_reply_time); + if(!m->has_first_reply_time || + timeval_smaller(&mesh->jostle_max, &age)) { /* its a goner */ log_nametypeclass(VERB_ALGO, "query jostled out to " "make space for a new one", @@ -1995,6 +1997,10 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, r->qid = qid; r->qflags = qflags; r->start_time = *s->s.env->now_tv; + if(s->reply_list == NULL && !s->has_first_reply_time) { + s->first_reply_time = r->start_time; + s->has_first_reply_time = 1; + } r->next = s->reply_list; r->qname = regional_alloc_init(s->s.region, qinfo->qname, s->s.qinfo.qname_len); diff --git a/services/mesh.h b/services/mesh.h index d2fac9d3c..9ee585156 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -191,6 +191,12 @@ struct mesh_state { struct module_qstate s; /** the list of replies to clients for the results */ struct mesh_reply* reply_list; + /** if it has a first reply time */ + int has_first_reply_time; + /** wall-clock time the first client reply was attached; + * used by mesh_make_new_space() so duplicate retransmits + * cannot reset jostle aging. */ + struct timeval first_reply_time; /** the list of callbacks for the results */ struct mesh_cb* cb_list; /** set of superstates (that want this state's result) diff --git a/services/rpz.c b/services/rpz.c index d83acbfb0..5121e46b5 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -2469,6 +2469,7 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate* { struct auth_zones* az; struct auth_zone* a; + struct dns_msg* ret = NULL; struct clientip_synthesized_rr* raddr = NULL; struct rpz* r = NULL; struct local_zone* z = NULL; @@ -2512,13 +2513,11 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate* z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones, is->qchase.qclass, &match); if(z != NULL) { - lock_rw_unlock(&a->lock); break; } raddr = rpz_delegation_point_ipbased_trigger_lookup(r, is); if(raddr != NULL) { - lock_rw_unlock(&a->lock); break; } lock_rw_unlock(&a->lock); @@ -2533,9 +2532,12 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate* if(z) { lock_rw_unlock(&z->lock); } - return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a); + ret = rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a); + } else { + ret = rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a); } - return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a); + lock_rw_unlock(&a->lock); + return ret; } struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, diff --git a/testcode/unitmain.c b/testcode/unitmain.c index 79ce45f39..4bc756a07 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -1092,7 +1092,7 @@ static void edns_ede_encode_notxt_fit_test( struct query_info* qinfo, { struct edns_data edns; sldns_buffer* pkt; - uint16_t edns_field_size, ede_txt_size; + size_t edns_field_size, ede_txt_size; int found_ede = 0, found_ede_other = 0, found_ede_txt = 0; int found_other_edns = 0; edns_ede_encode_setup(&edns, region); @@ -1123,7 +1123,7 @@ static void edns_ede_encode_no_fit_test( struct query_info* qinfo, { struct edns_data edns; sldns_buffer* pkt; - uint16_t edns_field_size, ede_size, ede_txt_size; + size_t edns_field_size, ede_size, ede_txt_size; int found_ede = 0, found_ede_other = 0, found_ede_txt = 0; int found_other_edns = 0; edns_ede_encode_setup(&edns, region); diff --git a/testdata/val_nsec3_iter_high.rpl b/testdata/val_nsec3_iter_high.rpl index 2b78f0b7f..703092d89 100644 --- a/testdata/val_nsec3_iter_high.rpl +++ b/testdata/val_nsec3_iter_high.rpl @@ -120,12 +120,12 @@ example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 720 example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854} ; closest encloser, H(example.com). -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. NSEC3 1 1 8 - 6md8numosa4q9ugkffdo1bmm82t5j49s SOA NS MX DNSKEY RRSIG -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCz/LkFOFcaQzVnyySW9ZoVUnxh7gIUdxyS9vqVDzo8pGhFU+3YogN2ZRk= ;{id = 2854} +b6fuorg741ufili49mg9j4328ig53sqg.example.com. NSEC3 1 1 123 aabb00123456bbccdd b6fuorg741ufili49mg9j4328ig53sqh SOA NS MX DNSKEY RRSIG +b6fuorg741ufili49mg9j4328ig53sqg.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. AJlV5car66lq5f0ASx7W47A/OADkARAXzKt9ZLojXze+FWK9JjAX+eA= -; wildcard denial, H(*.example.com.) = 4f3cnt8cu22tngec382jj4gde4rb47ub -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. NSEC3 1 1 0 - 4f3cnt8cu22tngec382jj4gde4rb48ub A MX RRSIG -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFHS+i/OB/V/gYmS1eQTXieXIXGjsAhQQ0Ql7TW/hsUklrb0DfoyhVPG95Q== ;{id = 2854} +; wildcard denial, H(*.example.com.) = k1a2vr9c269jummpru5d68qllbfmtdcb. +k1a2vr9c269jummpru5d68qllbfmtacb.example.com. NSEC3 1 1 123 aabb00123456bbccdd k1a2vr9c269jummpru5d68qllbfmtgcb A MX RRSIG +k1a2vr9c269jummpru5d68qllbfmtacb.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. AARB9z4C1WZUI3WP3QAR7RJXFnN0qEBkEt8ocudxXzms4/7/2l6NNWc= ; next closer name, H(www.example.com.) = s1unhcti19bkdr98fegs0v46mbu3t4m3. s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 123 aabb00123456bbccdd s1unhcti19bkdr98fegs0v46mbu3t4m4 A MX RRSIG @@ -152,10 +152,10 @@ SECTION ANSWER SECTION AUTHORITY example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000 example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854} -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. NSEC3 1 1 8 - 6md8numosa4q9ugkffdo1bmm82t5j49s SOA NS MX DNSKEY RRSIG -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCz/LkFOFcaQzVnyySW9ZoVUnxh7gIUdxyS9vqVDzo8pGhFU+3YogN2ZRk= ;{id = 2854} -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. NSEC3 1 1 0 - 4f3cnt8cu22tngec382jj4gde4rb48ub A MX RRSIG -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFHS+i/OB/V/gYmS1eQTXieXIXGjsAhQQ0Ql7TW/hsUklrb0DfoyhVPG95Q== ;{id = 2854} +b6fuorg741ufili49mg9j4328ig53sqg.example.com. NSEC3 1 1 123 aabb00123456bbccdd b6fuorg741ufili49mg9j4328ig53sqh SOA NS MX DNSKEY RRSIG +b6fuorg741ufili49mg9j4328ig53sqg.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. AJlV5car66lq5f0ASx7W47A/OADkARAXzKt9ZLojXze+FWK9JjAX+eA= +k1a2vr9c269jummpru5d68qllbfmtacb.example.com. NSEC3 1 1 123 aabb00123456bbccdd k1a2vr9c269jummpru5d68qllbfmtgcb A MX RRSIG +k1a2vr9c269jummpru5d68qllbfmtacb.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. AARB9z4C1WZUI3WP3QAR7RJXFnN0qEBkEt8ocudxXzms4/7/2l6NNWc= s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 123 aabb00123456bbccdd s1unhcti19bkdr98fegs0v46mbu3t4m4 A MX RRSIG s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFFSH4klZKke48dYyddYDj17gjTS0AhUAltWicpFLWqW98/Af9Qlx70MH8o4= ;{id = 2854} diff --git a/testdata/val_nx_nsec3_collision.rpl b/testdata/val_nx_nsec3_collision.rpl index 87a55f565..1b1f49e80 100644 --- a/testdata/val_nx_nsec3_collision.rpl +++ b/testdata/val_nx_nsec3_collision.rpl @@ -89,6 +89,17 @@ ns.example.com. IN A 1.2.3.4 ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} ENTRY_END +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.com. IN AAAA +SECTION AUTHORITY +example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000 +example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854} +ENTRY_END + ; response to DNSKEY priming query ENTRY_BEGIN MATCH opcode qtype qname @@ -163,29 +174,11 @@ STEP 2 TIME_PASSES ELAPSE 0.05 STEP 10 CHECK_ANSWER ENTRY_BEGIN MATCH all -REPLY QR RD RA DO NXDOMAIN +REPLY QR RD RA DO SERVFAIL SECTION QUESTION www.example.com. IN A SECTION ANSWER SECTION AUTHORITY -example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000 -example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854} -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. NSEC3 1 1 123 aabb00123456bbccdd 6md8numosa4q9ugkffdo1bmm82t5j49s A RRSIG -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. NSEC3 1 1 8 - 6md8numosa4q9ugkffdo1bmm82t5j49s SOA NS MX DNSKEY RRSIG -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFHndWrEEbuzezs/4lxeiMgEuUsUbAhR72gJgd/Zmhf80yoxCauw9k5OkCw== ;{id = 2854} -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. NSEC3 1 1 18 - 4f3cnt8cu22tngec382jj4gde4rb87ub A RRSIG -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. NSEC3 1 1 0 - 4f3cnt8cu22tngec382jj4gde4rb48ub A MX RRSIG -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. NSEC3 1 1 19 - 4f3cnt8cu22tngec382jj4gde4rb87ub A RRSIG -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFDRwji51WCXJg7W/3+Jx586af5qgAhQPxHegtzu1I/QbvCNrOOON05N1rw== ;{id = 2854} -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 18 - s1unhcti19bkdr98fegs0v46mbu3t4m4 A RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 19 - s1unhcti19bkdr98fegs0v46mbu3t4m4 A RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 20 00 s1unhcti19bkdr98fegs0v46mbu3t4m4 A RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 123 aabb00123456bbccdd s1unhcti19bkdr98fegs0v46mbu3t4m4 A MX RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 20 01 s1unhcti19bkdr98fegs0v46mbu3t4m4 A RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 20 02 s1unhcti19bkdr98fegs0v46mbu3t4m4 A RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 20 03 s1unhcti19bkdr98fegs0v46mbu3t4m4 A RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFDLy4GbR8ZaKHATVJGnGxzpsuq60AhQ1/pRbXi1ZbcYohzHgWzNC50fC5A== ;{id = 2854} - SECTION ADDITIONAL ENTRY_END diff --git a/testdata/val_nx_nsec3_params.rpl b/testdata/val_nx_nsec3_params.rpl index dd3ab6b57..59bef2be3 100644 --- a/testdata/val_nx_nsec3_params.rpl +++ b/testdata/val_nx_nsec3_params.rpl @@ -88,6 +88,17 @@ ns.example.com. IN A 1.2.3.4 ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} ENTRY_END +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.com. IN AAAA +SECTION AUTHORITY +example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000 +example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854} +ENTRY_END + ; response to DNSKEY priming query ENTRY_BEGIN MATCH opcode qtype qname @@ -144,20 +155,11 @@ ENTRY_END STEP 10 CHECK_ANSWER ENTRY_BEGIN MATCH all -REPLY QR RD RA DO NXDOMAIN +REPLY QR RD RA DO SERVFAIL SECTION QUESTION www.example.com. IN A SECTION ANSWER SECTION AUTHORITY -example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000 -example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854} -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. NSEC3 1 1 8 - 6md8numosa4q9ugkffdo1bmm82t5j49s SOA NS MX DNSKEY RRSIG -6md8numosa4q9ugkffdo1bmm82t5j39s.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCz/LkFOFcaQzVnyySW9ZoVUnxh7gIUdxyS9vqVDzo8pGhFU+3YogN2ZRk= ;{id = 2854} -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. NSEC3 1 1 0 - 4f3cnt8cu22tngec382jj4gde4rb48ub A MX RRSIG -4f3cnt8cu22tngec382jj4gde4rb46ub.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFHS+i/OB/V/gYmS1eQTXieXIXGjsAhQQ0Ql7TW/hsUklrb0DfoyhVPG95Q== ;{id = 2854} -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. NSEC3 1 1 123 aabb00123456bbccdd s1unhcti19bkdr98fegs0v46mbu3t4m4 A MX RRSIG -s1unhcti19bkdr98fegs0v46mbu3t4m2.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFFSH4klZKke48dYyddYDj17gjTS0AhUAltWicpFLWqW98/Af9Qlx70MH8o4= ;{id = 2854} - SECTION ADDITIONAL ENTRY_END diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 8f4639519..dd56cc6aa 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -352,7 +352,6 @@ compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, (p = compress_tree_lookup(tree, dname, labs, &insertpt))) { if(!write_compressed_dname(pkt, dname, labs, p)) return RETVAL_TRUNC; - (*compress_count)++; } else { if(!dname_buffer_write(pkt, dname)) return RETVAL_TRUNC; @@ -360,6 +359,7 @@ compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && !compress_tree_store(dname, labs, pos, region, p, insertpt)) return RETVAL_OUTMEM; + (*compress_count)++; return RETVAL_OK; } @@ -820,7 +820,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, return 1; } -uint16_t +size_t calc_edns_field_size(struct edns_data* edns) { size_t rdatalen = 0; @@ -856,7 +856,7 @@ calc_edns_option_size(struct edns_data* edns, uint16_t code) } uint16_t -calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size) +calc_ede_option_size(struct edns_data* edns, size_t* txt_size) { size_t rdatalen = 0; struct edns_option* opt; @@ -958,6 +958,10 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns, padding_option = opt; continue; } + if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) + break; /* no space for it */ + if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) + break; sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) @@ -968,12 +972,18 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns, padding_option = opt; continue; } + if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) + break; /* no space for it */ + if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) + break; sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); } - if (padding_option && edns->padding_block_size ) { + if (padding_option && edns->padding_block_size && + sldns_buffer_position(pkt)+4 <= max_msg_sz && + sldns_buffer_available(pkt, 4) /* if there is space for it */) { size_t pad_pos = sldns_buffer_position(pkt); size_t msg_sz = ((pad_pos + 3) / edns->padding_block_size + 1) * edns->padding_block_size; @@ -1017,7 +1027,7 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, { uint16_t flags; unsigned int attach_edns = 0; - uint16_t edns_field_size, ede_size, ede_txt_size; + size_t edns_field_size, ede_size, ede_txt_size; if(!cached || rep->authoritative) { /* original flags, copy RD and CD bits from query. */ @@ -1044,12 +1054,12 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, * calculate sizes once here */ edns_field_size = calc_edns_field_size(edns); ede_size = calc_ede_option_size(edns, &ede_txt_size); - if(sldns_buffer_capacity(pkt) < udpsize) + if(sldns_buffer_capacity(pkt) < (size_t)udpsize) udpsize = sldns_buffer_capacity(pkt); if(!edns || !edns->edns_present) { attach_edns = 0; /* EDEs are optional, try to fit anything else before them */ - } else if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) { + } else if((size_t)udpsize < (size_t)LDNS_HEADER_SIZE + edns_field_size - ede_size) { /* packet too small to contain edns, omit it. */ attach_edns = 0; } else { @@ -1063,13 +1073,13 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, return 0; } if(attach_edns) { - if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size) + if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size) attach_edns_record_max_msg_sz(pkt, edns, udpsize); - else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) { + else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) { ede_trim_text(&edns->opt_list_inplace_cb_out); ede_trim_text(&edns->opt_list_out); attach_edns_record_max_msg_sz(pkt, edns, udpsize); - } else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) { + } else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) { edns_opt_list_remove(&edns->opt_list_inplace_cb_out, LDNS_EDNS_EDE); edns_opt_list_remove(&edns->opt_list_out, LDNS_EDNS_EDE); attach_edns_record_max_msg_sz(pkt, edns, udpsize); @@ -1132,7 +1142,7 @@ extended_error_encode(sldns_buffer* buf, uint16_t rcode, } sldns_buffer_flip(buf); if(edns && edns->edns_present) { - uint16_t edns_field_size, ede_size, ede_txt_size; + size_t edns_field_size, ede_size, ede_txt_size; struct edns_data es = *edns; es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; @@ -1144,13 +1154,13 @@ extended_error_encode(sldns_buffer* buf, uint16_t rcode, * to see if EDNS can fit. */ edns_field_size = calc_edns_field_size(&es); ede_size = calc_ede_option_size(&es, &ede_txt_size); - if(edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size) + if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size) attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); - else if(edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_txt_size) { + else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_txt_size) { ede_trim_text(&es.opt_list_inplace_cb_out); ede_trim_text(&es.opt_list_out); attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); - } else if(edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_size) { + } else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_size) { edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE); edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE); attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); diff --git a/util/data/msgencode.h b/util/data/msgencode.h index 0363a90bf..f561fe1dd 100644 --- a/util/data/msgencode.h +++ b/util/data/msgencode.h @@ -106,7 +106,7 @@ void qinfo_query_encode(struct sldns_buffer* pkt, struct query_info* qinfo); * @param edns: edns data or NULL. * @return octets to reserve for EDNS. */ -uint16_t calc_edns_field_size(struct edns_data* edns); +size_t calc_edns_field_size(struct edns_data* edns); /** * Calculate the size of a specific EDNS option in packet. @@ -127,7 +127,7 @@ uint16_t calc_edns_option_size(struct edns_data* edns, uint16_t code); * extra text. * @return octets the option will take up. */ -uint16_t calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size); +uint16_t calc_ede_option_size(struct edns_data* edns, size_t* txt_size); /** * Attach EDNS record to buffer. Buffer has complete packet. There must diff --git a/util/data/msgparse.c b/util/data/msgparse.c index afbcbca5b..9239f8fe3 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -53,6 +53,8 @@ #include "sldns/parseutil.h" #include "sldns/wire2str.h" +#define MAX_PARSED_EDNS_OPTIONS 100 + /** smart comparison of (compressed, valid) dnames from packet */ static int smart_compare(sldns_buffer* pkt, uint8_t* dnow, @@ -950,6 +952,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, struct comm_reply* repinfo, uint32_t now, struct regional* region, struct cookie_secrets* cookie_secrets) { + int i = 0, nsid_seen = 0, cookie_seen = 0, padding_seen = 0; /* To respond with a Keepalive option, the client connection must have * received one message with a TCP Keepalive EDNS option, and that * option must have 0 length data. Subsequent messages sent on that @@ -969,7 +972,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ - while(rdata_len >= 4) { + while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); uint8_t server_cookie[40]; @@ -984,8 +987,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, /* handle parse time edns options here */ switch(opt_code) { case LDNS_EDNS_NSID: - if (!cfg || !cfg->nsid) + if (!cfg || !cfg->nsid || nsid_seen) break; + nsid_seen = 1; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region)) { @@ -1027,8 +1031,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, case LDNS_EDNS_PADDING: if(!cfg || !cfg->pad_responses || - !c || c->type != comm_tcp ||!c->ssl) + !c || c->type != comm_tcp ||!c->ssl || padding_seen) break; + padding_seen = 1; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_PADDING, 0, NULL, region)) { @@ -1039,8 +1044,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, break; case LDNS_EDNS_COOKIE: - if(!cfg || !cfg->do_answer_cookie || !repinfo) + if(!cfg || !cfg->do_answer_cookie || !repinfo || cookie_seen) break; + cookie_seen = 1; if(opt_len != 8 && (opt_len < 16 || opt_len > 40)) { verbose(VERB_ALGO, "worker request: " "badly formatted cookie"); @@ -1146,6 +1152,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, } rdata_ptr += opt_len; rdata_len -= opt_len; + i++; } return LDNS_RCODE_NOERROR; } @@ -1160,6 +1167,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg, struct rrset_parse* found_prev = 0; size_t rdata_len; uint8_t* rdata_ptr; + int i = 0; /* since the class encodes the UDP size, we cannot use hash table to * find the EDNS OPT record. Scan the packet. */ while(rrset) { @@ -1219,7 +1227,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg, /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ - while(rdata_len >= 4) { + while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); rdata_ptr += 4; @@ -1234,6 +1242,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg, } rdata_ptr += opt_len; rdata_len -= opt_len; + i++; } /* ignore rrsigs */ return LDNS_RCODE_NOERROR; diff --git a/validator/val_neg.c b/validator/val_neg.c index 66fd81899..e82f335b9 100644 --- a/validator/val_neg.c +++ b/validator/val_neg.c @@ -62,6 +62,13 @@ #include "sldns/rrdef.h" #include "sldns/sbuffer.h" +/** + * The maximum salt length that the negative cache is willing to use. + * Larger salt increases the computation time, while recommendations are + * for zero salt length for zones. + */ +#define MAX_SALT_LENGTH 64 + int val_neg_data_compare(const void* a, const void* b) { struct val_neg_data* x = (struct val_neg_data*)a; @@ -826,7 +833,11 @@ void neg_insert_data(struct val_neg_cache* neg, (slen != 0 && zone->nsec3_salt && s && memcmp(zone->nsec3_salt, s, slen) != 0))) { - if(slen > 0) { + if(slen > MAX_SALT_LENGTH) { + /* RFC 9276 s3.1: operators SHOULD NOT use a salt; large + * salts inflate per-hash block count. Decline to cache. */ + return; + } else if(slen > 0) { uint8_t* sa = memdup(s, slen); if(sa) { free(zone->nsec3_salt); @@ -1165,6 +1176,15 @@ neg_find_nsec3_ce(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len, uint8_t hashce[NSEC3_SHA_LEN]; uint8_t b32[257]; size_t celen, b32len; + int hashmax = MAX_NSEC3_CALCULATIONS; + if(qlabs > hashmax) { + /* strip leading labels so the walk costs at most + * MAX_NSEC3_CALCULATIONS hashes, mirroring val_nsec3.c */ + while(qlabs > hashmax) { + dname_remove_label(&qname, &qname_len); + qlabs--; + } + } *nclen = 0; while(qlabs > 0) { @@ -1265,6 +1285,12 @@ neg_nsec3_proof_ds(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len, if(!zone->nsec3_hash) return NULL; /* not nsec3 zone */ + if(!topname && qlabs > zone->labs + 1) + return NULL; /* iterator caller; opt-out proof would be discarded + * at the !topname check below anyway. + * The qlabs check allows the exact-match for + * the one-label-below-zone case. */ + if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf, hashnc, &nclen))) { return NULL; diff --git a/validator/val_nsec3.c b/validator/val_nsec3.c index 998fcc4e3..62effde20 100644 --- a/validator/val_nsec3.c +++ b/validator/val_nsec3.c @@ -59,11 +59,6 @@ #include "sldns/sbuffer.h" #include "util/config_file.h" -/** - * Max number of NSEC3 calculations at once, suspend query for later. - * 8 is low enough and allows for cases where multiple proofs are needed. - */ -#define MAX_NSEC3_CALCULATIONS 8 /** * When all allowed NSEC3 calculations at once resulted in error treat as * bogus. NSEC3 hash errors are not cached and this helps breaks loops with @@ -456,6 +451,67 @@ filter_init(struct nsec3_filter* filter, struct ub_packed_rrset_key** list, } } +/** Check if the NSEC3s have the same parameter set. */ +static int +param_set_same(struct nsec3_filter* flt, char** reason) +{ + size_t rrsetnum; + int rrnum; + struct ub_packed_rrset_key* rrset; + int have_params = 0; + int first_algo = 0; + size_t first_iter = 0; + uint8_t* first_salt = NULL; + size_t first_saltlen = 0; + + /* If the NSEC3 parameter sets have distinct values, then they are + * from different NSEC3 chains, and we do not want that. */ + for(rrset=filter_first(flt, &rrsetnum, &rrnum); rrset; + rrset=filter_next(flt, &rrsetnum, &rrnum)) { + if(!have_params) { + first_algo = nsec3_get_algo(rrset, rrnum); + first_iter = nsec3_get_iter(rrset, rrnum); + if(!nsec3_get_salt(rrset, rrnum, &first_salt, + &first_saltlen)) { + verbose(VERB_ALGO, "NSEC3 salt malformed"); + if(reason) + *reason = "NSEC3 salt malformed"; + return 0; + } + have_params = 1; + } else { + uint8_t* salt = NULL; + size_t saltlen = 0; + if(nsec3_get_algo(rrset, rrnum) != first_algo) { + verbose(VERB_ALGO, "NSEC3 algorithm mismatch"); + if(reason) + *reason = "NSEC3 algorithm mismatch"; + return 0; + } + if(nsec3_get_iter(rrset, rrnum) != first_iter) { + verbose(VERB_ALGO, "NSEC3 iterations mismatch"); + if(reason) + *reason = "NSEC3 iterations mismatch"; + return 0; + } + if(!nsec3_get_salt(rrset, rrnum, &salt, &saltlen)) { + verbose(VERB_ALGO, "NSEC3 salt malformed"); + if(reason) + *reason = "NSEC3 salt malformed"; + return 0; + } + if(saltlen != first_saltlen || + memcmp(salt, first_salt, saltlen) != 0) { + verbose(VERB_ALGO, "NSEC3 salt mismatch"); + if(reason) + *reason = "NSEC3 salt mismatch"; + return 0; + } + } + } + return 1; +} + /** * Find max iteration count using config settings and key size * @param ve: validator environment with iteration count config settings. @@ -1192,6 +1248,8 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone", @@ -1378,6 +1436,8 @@ nsec3_prove_nodata(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ return nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc); @@ -1401,6 +1461,8 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ @@ -1503,6 +1565,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, *reason = "no NSEC3 records"; return sec_status_bogus; /* no RRs */ } + if(!param_set_same(&flt, reason)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ @@ -1596,6 +1660,8 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ diff --git a/validator/val_nsec3.h b/validator/val_nsec3.h index f668a270f..a13e92991 100644 --- a/validator/val_nsec3.h +++ b/validator/val_nsec3.h @@ -98,6 +98,12 @@ struct sldns_buffer; /** The SHA1 hash algorithm for NSEC3 */ #define NSEC3_HASH_SHA1 0x01 +/** + * Max number of NSEC3 calculations at once, suspend query for later. + * 8 is low enough and allows for cases where multiple proofs are needed. + */ +#define MAX_NSEC3_CALCULATIONS 8 + /** * Cache table for NSEC3 hashes. * It keeps a *pointer* to the region its items are allocated. diff --git a/validator/val_utils.c b/validator/val_utils.c index 411a63b25..8e4c91900 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -1066,10 +1066,10 @@ val_fill_reply(struct reply_info* chase, struct reply_info* orig, if(query_dname_compare(name, orig->rrsets[i]->rk.dname) == 0) chase->rrsets[chase->an_numrrsets - +orig->ns_numrrsets+chase->ar_numrrsets++] + +chase->ns_numrrsets+chase->ar_numrrsets++] = orig->rrsets[i]; } else if(rrset_has_signer(orig->rrsets[i], name, len)) { - chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+ + chase->rrsets[chase->an_numrrsets+chase->ns_numrrsets+ chase->ar_numrrsets++] = orig->rrsets[i]; } }