]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/dnssec: rewrite kr_nsec_ref_to_unsigned()
authorVladimír Čunát <vladimir.cunat@nic.cz>
Wed, 27 Apr 2022 14:03:06 +0000 (16:03 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Wed, 18 May 2022 13:49:23 +0000 (13:49 +0000)
- I see no motivation to search for NS records here;
  and I didn't like that loop nesting
- philosophy shift akin to the recent
  replacement of kr_nsec_existence_denial()

lib/dnssec/nsec.c
lib/dnssec/nsec.h
lib/layer/validate.c

index 62ef55beb054c4a68ec4112a8de6bcdec7d2a450..b71fdd36b62abb0c8c9cb3067824b77cef832d72 100644 (file)
@@ -273,60 +273,27 @@ int kr_nsec_negative(const ranked_rr_array_t *rrrs, uint32_t qry_uid,
        return kr_error(ENOENT);
 }
 
-int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt)
+int kr_nsec_ref_to_unsigned(const ranked_rr_array_t *rrrs, uint32_t qry_uid,
+                               const knot_dname_t *sname)
 {
-       int nsec_found = 0;
-       const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY);
-       if (!sec)
-               return kr_error(EINVAL);
-       for (unsigned i = 0; i < sec->count; ++i) {
-               const knot_rrset_t *ns = knot_pkt_rr(sec, i);
-               if (ns->type == KNOT_RRTYPE_DS)
-                       return kr_error(EEXIST);
-               if (ns->type != KNOT_RRTYPE_NS)
-                       continue;
-               nsec_found = 0;
-               for (unsigned j = 0; j < sec->count; ++j) {
-                       const knot_rrset_t *nsec = knot_pkt_rr(sec, j);
-                       if (nsec->type == KNOT_RRTYPE_DS)
-                               return kr_error(EEXIST);
-                       if (nsec->type != KNOT_RRTYPE_NSEC)
-                               continue;
-                       /* nsec found
-                        * check if owner name matches the delegation name
-                        */
-                       if (!knot_dname_is_equal(nsec->owner, ns->owner)) {
-                               /* nsec does not match the delegation */
-                               continue;
-                       }
-                       nsec_found = 1;
-                       const uint8_t *bm = knot_nsec_bitmap(nsec->rrs.rdata);
-                       uint16_t bm_size = knot_nsec_bitmap_len(nsec->rrs.rdata);
-                       if (!bm)
-                               return kr_error(EINVAL);
-                       if (dnssec_nsec_bitmap_contains(bm, bm_size,
-                                                         KNOT_RRTYPE_NS) &&
-                           !dnssec_nsec_bitmap_contains(bm, bm_size,
-                                                         KNOT_RRTYPE_DS) &&
-                           !dnssec_nsec_bitmap_contains(bm, bm_size,
-                                                         KNOT_RRTYPE_SOA)) {
-                               /* rfc4035, 5.2 */
-                               return kr_ok();
-                       }
-               }
-               if (nsec_found) {
-                       /* nsec which owner matches
-                        * the delegation name was found,
-                        * but nsec type bitmap contains wrong types
-                        */
-                       return kr_error(EINVAL);
-               } else {
-                       /* nsec that matches delegation was not found */
-                       return kr_error(DNSSEC_NOT_FOUND);
-               }
-       }
+       for (int i = rrrs->len - 1; i >= 0; --i) { // NSECs near the end typically
+               const knot_rrset_t *nsec = rrrs->at[i]->rr;
+               bool ok = rrrs->at[i]->qry_uid == qry_uid
+                       && nsec->type == KNOT_RRTYPE_NSEC
+                       && kr_rank_test(rrrs->at[i]->rank, KR_RANK_SECURE)
+                       // avoid any possibility of getting tricked in deeper zones
+                       && knot_dname_in_bailiwick(sname, nsec->owner) >= 0;
+               if (!ok) continue;
 
-       return kr_error(EINVAL);
+               kr_assert(nsec->rrs.rdata);
+               const uint8_t *bm = knot_nsec_bitmap(nsec->rrs.rdata);
+               uint16_t bm_size = knot_nsec_bitmap_len(nsec->rrs.rdata);
+               ok = ok &&  dnssec_nsec_bitmap_contains(bm, bm_size, KNOT_RRTYPE_NS)
+                       && !dnssec_nsec_bitmap_contains(bm, bm_size, KNOT_RRTYPE_DS)
+                       && !dnssec_nsec_bitmap_contains(bm, bm_size, KNOT_RRTYPE_SOA);
+               if (ok) return kr_ok();
+       }
+       return kr_error(DNSSEC_NOT_FOUND);
 }
 
 int kr_nsec_matches_name_and_type(const knot_rrset_t *nsec,
index 63c353ffc043f96af786e1912c107d889c526273..1ba9ec8e649f5ea4808e70a2a49143a8a2b20981 100644 (file)
@@ -50,15 +50,13 @@ int kr_nsec_negative(const ranked_rr_array_t *rrrs, uint32_t qry_uid,
 
 /**
  * Referral to unsigned subzone check (RFC4035 5.2).
- * @note            No RRSIGs are validated.
- * @param pkt        Packet structure to be processed.
- * @return           0 or error code:
- *                  DNSSEC_NOT_FOUND - neither ds nor nsec records
- *                  were not found.
- *                  EEXIST - ds record was found.
- *                  EINVAL - bogus.
+ *
+ * @param rrrs       list of RRs to search; typically kr_request::auth_selected
+ * @param qry_uid    only consider NSECs from this packet, for better efficiency
+ * @return           0 or negative error code, in particular DNSSEC_NOT_FOUND
  */
-int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt);
+int kr_nsec_ref_to_unsigned(const ranked_rr_array_t *rrrs, uint32_t qry_uid,
+                               const knot_dname_t *sname);
 
 /**
  * Checks whether supplied NSEC RR matches the supplied name and type.
index 73206a0c6dcd6e7c57ecfe1b4bab63333836135d..ef21e3010851c8c130f507a7fc923de9540b49f7 100644 (file)
@@ -536,7 +536,8 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_
                if (!has_nsec3) {
                        if (referral) {
                                /* Check if it is referral to unsigned, rfc4035 5.2 */
-                               ret = kr_nsec_ref_to_unsigned(answer);
+                               ret = kr_nsec_ref_to_unsigned(&req->auth_selected,
+                                                               qry->uid, proved_name);
                        } else {
                                /* No-data answer */
                                ret = kr_nsec_negative(&req->auth_selected, qry->uid,