]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Be smarter about refusing to add many RR types to the database
authorOndřej Surý <ondrej@isc.org>
Mon, 17 Jun 2024 09:40:40 +0000 (11:40 +0200)
committerNicki Křížek <nicki@isc.org>
Wed, 24 Jul 2024 09:06:03 +0000 (11:06 +0200)
Instead of outright refusing to add new RR types to the cache, be a bit
smarter:

1. If the new header type is in our priority list, we always add either
   positive or negative entry at the beginning of the list.

2. If the new header type is negative entry, and we are over the limit,
   we mark it as ancient immediately, so it gets evicted from the cache
   as soon as possible.

3. Otherwise add the new header after the priority headers (or at the
   head of the list).

4. If we are over the limit, evict the last entry on the normal header
   list.

(cherry picked from commit 57cd34441a1b4ecc9874a4a106c2c95b8d7a3120)

lib/dns/rbtdb.c

index c1fdf31c8073d41a98dd525a05e68271b6622d15..8e352ae4e93801a68b6688a4b05900806ed2b7ec 100644 (file)
@@ -1187,10 +1187,6 @@ prio_type(rbtdb_rdatatype_t type) {
        case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname):
        case dns_rdatatype_dname:
        case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname):
-       case dns_rdatatype_svcb:
-       case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_svcb):
-       case dns_rdatatype_https:
-       case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_https):
        case dns_rdatatype_dnskey:
        case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dnskey):
        case dns_rdatatype_srv:
@@ -6222,6 +6218,26 @@ update_recordsandbytes(bool add, rbtdb_version_t *rbtversion,
 #define DNS_RBTDB_MAX_RTYPES 100
 #endif /* DNS_RBTDB_MAX_RTYPES */
 
+static bool
+overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) {
+       UNUSED(rbtdb);
+
+       if (DNS_RBTDB_MAX_RTYPES == 0) {
+               return (false);
+       }
+
+       return (ntypes >= DNS_RBTDB_MAX_RTYPES);
+}
+
+static bool
+prio_header(rdatasetheader_t *header) {
+       if (NEGATIVE(header) && prio_type(RBTDB_RDATATYPE_EXT(header->type))) {
+               return (true);
+       }
+
+       return (prio_type(header->type));
+}
+
 /*
  * write lock on rbtnode must be held.
  */
@@ -6232,7 +6248,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
 {
        rbtdb_changed_t *changed = NULL;
        rdatasetheader_t *topheader, *topheader_prev, *header, *sigheader;
-       rdatasetheader_t *prioheader = NULL;
+       rdatasetheader_t *prioheader = NULL, *expireheader = NULL;
        unsigned char *merged;
        isc_result_t result;
        bool header_nx;
@@ -6242,7 +6258,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
        rbtdb_rdatatype_t negtype, sigtype;
        dns_trust_t trust;
        int idx;
-       uint32_t ntypes;
+       uint32_t ntypes = 0;
 
        /*
         * Add an rdatasetheader_t to a node.
@@ -6305,7 +6321,6 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                                        set_ttl(rbtdb, topheader, 0);
                                        mark_stale_header(rbtdb, topheader);
                                }
-                               ntypes = 0;
                                goto find_header;
                        }
                        /*
@@ -6327,11 +6342,9 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                         * check for an extant non-stale NODATA ncache
                         * entry which covers the same type as the RRSIG.
                         */
-                       ntypes = 0;
                        for (topheader = rbtnode->data;
                             topheader != NULL;
                             topheader = topheader->next) {
-                               ntypes++;
                                if ((topheader->type ==
                                        RBTDB_RDATATYPE_NCACHEANY) ||
                                        (newheader->type == sigtype &&
@@ -6375,12 +6388,16 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                }
        }
 
-       ntypes = 0;
        for (topheader = rbtnode->data;
             topheader != NULL;
             topheader = topheader->next) {
-               ntypes++;
-               if (prio_type(topheader->type)) {
+               if (IS_CACHE(rbtdb) && ACTIVE(topheader, now)) {
+                       ++ntypes;
+                       expireheader = topheader;
+               } else if (!IS_CACHE(rbtdb)) {
+                       ++ntypes;
+               }
+               if (prio_header(topheader)) {
                        prioheader = topheader;
                }
                if (topheader->type == newheader->type ||
@@ -6738,8 +6755,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                        /*
                         * No rdatasets of the given type exist at the node.
                         */
-
-                       if (ntypes > DNS_RBTDB_MAX_RTYPES) {
+                       if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
                                free_rdataset(rbtdb, rbtdb->common.mctx,
                                              newheader);
                                return (ISC_R_QUOTA);
@@ -6747,7 +6763,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
 
                        newheader->down = NULL;
 
-                       if (prio_type(newheader->type)) {
+                       if (prio_header(newheader)) {
                                /* This is a priority type, prepend it */
                                newheader->next = rbtnode->data;
                                rbtnode->data = newheader;
@@ -6760,6 +6776,25 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                                newheader->next = rbtnode->data;
                                rbtnode->data = newheader;
                        }
+
+                       if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
+                               if (expireheader == NULL) {
+                                       expireheader = newheader;
+                               }
+                               if (NEGATIVE(newheader) &&
+                                   !prio_header(newheader))
+                               {
+                                       /*
+                                        * Add the new non-priority negative
+                                        * header to the database only
+                                        * temporarily.
+                                        */
+                                       expireheader = newheader;
+                               }
+
+                               set_ttl(rbtdb, expireheader, 0);
+                               mark_stale_header(rbtdb, expireheader);
+                       }
                }
        }