diff --git a/doc/Changelog b/doc/Changelog index 34fcb1fba..befbfcaab 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,6 +1,8 @@ 3 July 2023: George - Merge #739: Add SVCB dohpath support. - Code cleanup for sldns_str2wire_svcparam_key_lookup. + - Merge #802: add validation EDEs to queries where the CD bit is set. + - For #802: Cleanup comments and add RCODE check for CD bit test case. 3 July 2023: Wouter - Fix #906: warning: ‘Py_SetProgramName’ is deprecated. diff --git a/services/mesh.c b/services/mesh.c index 0c920a16a..2bc042596 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -1238,6 +1238,34 @@ mesh_is_udp(struct mesh_reply const* r) { return r->query_reply.c->type == comm_udp; } +static inline void +mesh_find_and_attach_ede_and_reason(struct mesh_state* m, + struct reply_info* rep, struct mesh_reply* r) { + char *reason = m->s.env->cfg->val_log_level >= 2 + ? errinf_to_str_bogus(&m->s) : NULL; + + /* During validation the EDE code can be received via two + * code paths. One code path fills the reply_info EDE, and + * the other fills it in the errinf_strlist. These paths + * intersect at some points, but where is opaque due to + * the complexity of the validator. At the time of writing + * we make the choice to prefer the EDE from errinf_strlist + * but a compelling reason to do otherwise is just as valid + */ + sldns_ede_code reason_bogus = errinf_to_reason_bogus(&m->s); + if ((reason_bogus == LDNS_EDE_DNSSEC_BOGUS && + rep->reason_bogus != LDNS_EDE_NONE) || + reason_bogus == LDNS_EDE_NONE) { + reason_bogus = rep->reason_bogus; + } + + if(reason_bogus != LDNS_EDE_NONE) { + edns_opt_list_append_ede(&r->edns.opt_list_out, + m->s.region, reason_bogus, reason); + } + free(reason); +} + /** * Send reply to mesh reply entry * @param m: mesh state to send it for. @@ -1329,35 +1357,14 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, &r->edns, &r->query_reply, m->s.region, &r->start_time)) r->edns.opt_list_inplace_cb_out = NULL; } - /* Send along EDE BOGUS EDNS0 option when answer is bogus */ + /* Send along EDE BOGUS EDNS0 option when validation is bogus */ if(m->s.env->cfg->ede && rcode == LDNS_RCODE_SERVFAIL && m->s.env->need_to_validate && (!(r->qflags&BIT_CD) || m->s.env->cfg->ignore_cd) && rep && (rep->security <= sec_status_bogus || rep->security == sec_status_secure_sentinel_fail)) { - char *reason = m->s.env->cfg->val_log_level >= 2 - ? errinf_to_str_bogus(&m->s) : NULL; - - /* During validation the EDE code can be received via two - * code paths. One code path fills the reply_info EDE, and - * the other fills it in the errinf_strlist. These paths - * intersect at some points, but where is opaque due to - * the complexity of the validator. At the time of writing - * we make the choice to prefer the EDE from errinf_strlist - * but a compelling reason to do otherwise is just as valid - */ - sldns_ede_code reason_bogus = errinf_to_reason_bogus(&m->s); - if ((reason_bogus == LDNS_EDE_DNSSEC_BOGUS && - rep->reason_bogus != LDNS_EDE_NONE) || - reason_bogus == LDNS_EDE_NONE) { - reason_bogus = rep->reason_bogus; - } - - if(reason_bogus != LDNS_EDE_NONE) { - edns_opt_list_append_ede(&r->edns.opt_list_out, - m->s.region, reason_bogus, reason); - } - free(reason); + + mesh_find_and_attach_ede_and_reason(m, rep, r); } error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); @@ -1372,6 +1379,14 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, r->edns.bits &= EDNS_DO; m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; + + /* Attach EDE without servfail if the validation failed */ + if (m->s.env->cfg->ede && rep && + (rep->security <= sec_status_bogus || + rep->security == sec_status_secure_sentinel_fail)) { + mesh_find_and_attach_ede_and_reason(m, rep, r); + } + if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region, &r->start_time) || !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, diff --git a/testdata/ede.tdir/ede.test b/testdata/ede.tdir/ede.test index 5d478bd49..7ce05faf9 100644 --- a/testdata/ede.tdir/ede.test +++ b/testdata/ede.tdir/ede.test @@ -68,5 +68,21 @@ then exit 1 fi +# EDE with CD bit set (EDE but no SERVFAIL) +dig @127.0.0.1 -p $UNBOUND_PORT cd.dnskey-failures.test +cd > cd_bit_ede.txt -# @TODO DNSSEC indeterminate when implemented +if ! grep -q -e "NXDOMAIN" cd_bit_ede.txt +then + echo "No NXDOMAIN reply with CD bit set" + cat cd_bit_ede.txt + exit 1 +fi +if ! grep -q -e "OPT=15: 00 09" -e "EDE: 9" cd_bit_ede.txt +then + echo "No EDE attached with CD bit set" + cat cd_bit_ede.txt + exit 1 +fi + +# TODO EDE with CD bit set (EDE but no SERVFAIL) for a cached answer +# TODO DNSSEC indeterminate when implemented