]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
enforce record count maximums
authorMark Andrews <marka@isc.org>
Thu, 4 Jul 2019 05:24:20 +0000 (15:24 +1000)
committerMark Andrews <marka@isc.org>
Wed, 13 May 2020 05:35:28 +0000 (15:35 +1000)
lib/dns/include/dns/ssu.h
lib/dns/ssu.c
lib/dns/win32/libdns.def.in
lib/ns/update.c

index b3a6e829e007f43f230a7f96549e6a560078bbd9..cc463a9d6bd6dd2b6d55500a395aa717cc806956 100644 (file)
@@ -185,19 +185,32 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
 /*% Accessor functions to extract rule components */
 bool
 dns_ssurule_isgrant(const dns_ssurule_t *rule);
+
 /*% Accessor functions to extract rule components */
 dns_name_t *
 dns_ssurule_identity(const dns_ssurule_t *rule);
+
 /*% Accessor functions to extract rule components */
 unsigned int
 dns_ssurule_matchtype(const dns_ssurule_t *rule);
+
 /*% Accessor functions to extract rule components */
 dns_name_t *
 dns_ssurule_name(const dns_ssurule_t *rule);
+
 /*% Accessor functions to extract rule components */
 unsigned int
 dns_ssurule_types(const dns_ssurule_t *rule, dns_ssuruletype_t **types);
 
+unsigned int
+dns_ssurule_max(const dns_ssurule_t *rule, dns_rdatatype_t type);
+/*%<
+ * Returns the maximum number of records configured for type `type`.
+ * If no maximum has been configured for `type` but one has been
+ * configured for ANY, return that value instead. Otherwise, return
+ * zero, which implies "unlimited".
+ */
+
 isc_result_t
 dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule);
 /*%<
index 39de7057763b22291d2e5932b27af126f52d0c3d..9a601febe8eca19554bb5812adfa91a8dd2bcafa 100644 (file)
@@ -562,6 +562,24 @@ dns_ssurule_types(const dns_ssurule_t *rule, dns_ssuruletype_t **types) {
        return (rule->ntypes);
 }
 
+unsigned int
+dns_ssurule_max(const dns_ssurule_t *rule, dns_rdatatype_t type) {
+       unsigned int i;
+       unsigned int max = 0;
+
+       REQUIRE(VALID_SSURULE(rule));
+
+       for (i = 0; i < rule->ntypes; i++) {
+               if (rule->types[i].type == dns_rdatatype_any) {
+                       max = rule->types[i].max;
+               }
+               if (rule->types[i].type == type) {
+                       return (rule->types[i].max);
+               }
+       }
+       return (max);
+}
+
 isc_result_t
 dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
        REQUIRE(VALID_SSUTABLE(table));
index 629fe5333355c69e173434f57e120d0749dac258..2d1c23b2ed6570266d14835b303a54426323edd4 100644 (file)
@@ -1019,9 +1019,10 @@ dns_soa_setretry
 dns_soa_setserial
 dns_ssu_external_match
 dns_ssu_mtypefromstring
-dns_ssurule_isgrant
 dns_ssurule_identity
+dns_ssurule_isgrant
 dns_ssurule_matchtype
+dns_ssurule_max
 dns_ssurule_name
 dns_ssurule_types
 dns_ssutable_firstrule
index 2a4355a0a3dde92f75ba70b2994a62e4034c7fa3..84e1c7e129eadfec395b10179d5d89f133aa190f 100644 (file)
@@ -753,6 +753,17 @@ cleanup_node:
 typedef bool
 rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
 
+static isc_result_t
+count_action(void *data, rr_t *rr) {
+       unsigned int *ui = (unsigned int *)data;
+
+       UNUSED(rr);
+
+       (*ui)++;
+
+       return (ISC_R_SUCCESS);
+}
+
 /*%
  * Helper function for rrset_exists().
  */
@@ -2878,6 +2889,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
                               &rdata, &covers, &ttl, &update_class);
 
                if (update_class == zoneclass) {
+                       unsigned int max = 0;
+
                        /*
                         * RFC1123 doesn't allow MF and MD in master zones.
                         */
@@ -3003,6 +3016,24 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                }
                        }
 
+                       if (rules != NULL && rules[rule] != NULL) {
+                               max = dns_ssurule_max(rules[rule], rdata.type);
+                       }
+                       if (max != 0) {
+                               unsigned int count = 0;
+                               CHECK(foreach_rr(db, ver, name, rdata.type,
+                                                covers, count_action, &count));
+                               if (count >= max) {
+                                       update_log(client, zone,
+                                                  LOGLEVEL_PROTOCOL,
+                                                  "attempt to add more "
+                                                  "records than permitted by "
+                                                  "policy max=%u",
+                                                  max);
+                                       continue;
+                               }
+                       }
+
                        if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) {
                                char namestr[DNS_NAME_FORMATSIZE];
                                char typestr[DNS_RDATATYPE_FORMATSIZE];