diff --git a/lib/dnssec/nsec.c b/lib/dnssec/nsec.c index 572755cd6f27b04bb73d89c22be60d805f017cf9..c5a974477227277be47624c81453c271b6f42474 100644 --- a/lib/dnssec/nsec.c +++ b/lib/dnssec/nsec.c @@ -355,6 +355,51 @@ int kr_nsec_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_t return kr_error(ENOENT); } +/** + * Check whether the NSEC RR proves that there is a empty non-terminal. + * @param nsec NSEC RRSet. + * @param sname Searched name. + * @return 0 or error code. + */ +static int nsec_empty_nonterminal(const knot_rrset_t *nsec, const knot_dname_t *sname) +{ + assert(nsec && sname); + + int ret = nsec_nonamematch(nsec, sname); + if (ret != 0) { + return ret; + } + + const knot_dname_t *next = knot_nsec_next(&nsec->rrs); + + if (knot_dname_in(sname, next)) { + return kr_ok(); + } else { + return kr_error(EINVAL); + } +} + +int kr_nsec_empty_nonterminal_response_check(const knot_pkt_t *pkt, knot_section_t section_id, + const knot_dname_t *sname) +{ + const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id); + if (!sec || !sname) { + return kr_error(EINVAL); + } + + for (unsigned i = 0; i < sec->count; ++i) { + const knot_rrset_t *rrset = knot_pkt_rr(sec, i); + if (rrset->type != KNOT_RRTYPE_NSEC) { + continue; + } + if (nsec_empty_nonterminal(rrset, sname) == 0) { + return kr_ok(); + } + } + + return kr_error(ENOENT); +} + int kr_nsec_existence_denial(const knot_pkt_t *pkt, knot_section_t section_id, const knot_dname_t *sname, uint16_t stype, mm_ctx_t *pool) { diff --git a/lib/dnssec/nsec.h b/lib/dnssec/nsec.h index 73ab99454056ff481be461d831c61a717c2b04c2..1f9d258c185567317d7f4b09904298398979244b 100644 --- a/lib/dnssec/nsec.h +++ b/lib/dnssec/nsec.h @@ -73,6 +73,18 @@ int kr_nsec_wildcard_no_data_response_check(const knot_pkt_t *pkt, knot_section_ int kr_nsec_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_t section_id, const knot_dname_t *sname); +/** + * Empty non-terminal response. + * @note There are no NSEC records for empty non-terminals. The existence of + * the domain is inferred from the covering NSEC record. + * @param pkt Packet structure to be processed. + * @param section_id Packet section to be processed. + * @param sname Name to be checked. + * @return 0 or error code. + */ +int kr_nsec_empty_nonterminal_response_check(const knot_pkt_t *pkt, knot_section_t section_id, + const knot_dname_t *sname); + /** * Authenticated denial of existence according to RFC4035 5.4. * @note No RRSIGs are validated.