Commit 6ace801d authored by Mark Andrews's avatar Mark Andrews

Merge branch 'marka-update-per-type-record-limits' into 'master'

allow per type record counts to be specified in update-policy

Closes #1657

See merge request !2124
parents 61b53955 8f9dc72e
Pipeline #41568 passed with stages
in 8 minutes and 49 seconds
5410. [func] Add the ability to specify per-type record count
limits in an "update-policy" statement, which
are enforced when adding records via UPDATE.
[GL #1657]
5409. [performance] When looking up NSEC3 data in a zone database, skip
the check for empty non-terminal nodes; the NSEC3
tree doesn't have any. [GL #1834]
......
......@@ -237,7 +237,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
dns_ssumatchtype_t mtype = dns_ssumatchtype_name;
dns_fixedname_t fname, fident;
isc_buffer_t b;
dns_rdatatype_t *types;
dns_ssuruletype_t *types;
unsigned int i, n;
str = cfg_obj_asstring(mode);
......@@ -290,7 +290,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
if (n == 0) {
types = NULL;
} else {
types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
types = isc_mem_get(mctx, n * sizeof(*types));
}
i = 0;
......@@ -298,22 +298,43 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
element2 = cfg_list_next(element2))
{
const cfg_obj_t *typeobj;
const char *bracket;
isc_textregion_t r;
unsigned long max = 0;
INSIST(i < n);
typeobj = cfg_listelt_value(element2);
str = cfg_obj_asstring(typeobj);
DE_CONST(str, r.base);
r.length = strlen(str);
result = dns_rdatatype_fromtext(&types[i++], &r);
bracket = strchr(str, '(' /*)*/);
if (bracket != NULL) {
char *end = NULL;
r.length = bracket - str;
max = strtoul(bracket + 1, &end, 10);
if (max > 0xffff || end[0] != /*(*/ ')' ||
end[1] != 0) {
cfg_obj_log(identity, named_g_lctx,
ISC_LOG_ERROR,
"'%s' is not a valid count",
bracket);
isc_mem_put(mctx, types,
n * sizeof(*types));
goto cleanup;
}
} else {
r.length = strlen(str);
}
types[i].max = max;
result = dns_rdatatype_fromtext(&types[i++].type, &r);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(identity, named_g_lctx,
ISC_LOG_ERROR,
"'%s' is not a valid type", str);
isc_mem_put(mctx, types,
n * sizeof(dns_rdatatype_t));
"'%.*s' is not a valid type",
(int)r.length, str);
isc_mem_put(mctx, types, n * sizeof(types));
goto cleanup;
}
}
......@@ -323,7 +344,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
table, grant, dns_fixedname_name(&fident), mtype,
dns_fixedname_name(&fname), n, types);
if (types != NULL) {
isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
isc_mem_put(mctx, types, n * sizeof(*types));
}
if (result != ISC_R_SUCCESS) {
goto cleanup;
......@@ -336,7 +357,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
* update-policy { grant <session-keyname> zonesub any; };
*/
if (autoddns) {
dns_rdatatype_t any = dns_rdatatype_any;
dns_ssuruletype_t any = { dns_rdatatype_any, 0 };
if (named_g_server->session_keyname == NULL) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
......
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone "example.com" {
type master;
file "example.com.db";
update-policy {
grant * tcp-self . "ptr(10 )";
};
};
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone "example.com" {
type master;
file "example.com.db";
update-policy {
grant * tcp-self . ptr(1);
};
};
......@@ -60,3 +60,5 @@ rm -f update.out.*
rm -f check.out.*
rm -f update.out.*
rm -f ns*/managed-keys.bind* ns*/*.mkeys*
rm -f nextpart.out.*
rm -f */named.run.prev
......@@ -34,5 +34,5 @@ controls {
zone "in-addr.arpa" {
type master;
file "in-addr.db";
update-policy { grant * tcp-self . PTR; };
update-policy { grant * tcp-self . PTR(1) ANY(2) A; };
};
......@@ -1031,6 +1031,65 @@ grep "UPDATE, status: NOERROR" nsupdate.out-$n > /dev/null 2>&1 || ret=1
grep "UPDATE, status: FORMERR" nsupdate.out-$n > /dev/null 2>&1 || ret=1
[ $ret = 0 ] || { echo_i "failed"; status=1; }
n=`expr $n + 1`
ret=0
echo_i "check that max records is enforced ($n)"
nextpart ns6/named.run > /dev/null
$NSUPDATE -v > nsupdate.out.$n 2>&1 << END
server 10.53.0.6 ${PORT}
local 10.53.0.5
update del 5.0.53.10.in-addr.arpa.
update add 5.0.53.10.in-addr.arpa. 600 PTR localhost.
update add 5.0.53.10.in-addr.arpa. 600 PTR other.
send
END
$DIG $DIGOPTS @10.53.0.6 \
+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd \
-x 10.53.0.5 > dig.out.ns6.$n
# the policy is 'grant * tcp-self . PTR(1) ANY(2) A;' so only the
# first PTR record should be added.
grep localhost. dig.out.ns6.$n > /dev/null 2>&1 || ret=1
grep other. dig.out.ns6.$n > /dev/null 2>&1 && ret=1
nextpart ns6/named.run > nextpart.out.$n
grep "attempt to add more records than permitted by policy" nextpart.out.$n > /dev/null || ret=1
if test $ret -ne 0
then
echo_i "failed"; status=1
fi
n=`expr $n + 1`
ret=0
echo_i "check that max records for ANY is enforced ($n)"
nextpart ns6/named.run > /dev/null
$NSUPDATE -v > nsupdate.out.$n 2>&1 << END
server 10.53.0.6 ${PORT}
local 10.53.0.5
update del 5.0.53.10.in-addr.arpa.
update add 5.0.53.10.in-addr.arpa. 600 A 1.2.3.4
update add 5.0.53.10.in-addr.arpa. 600 A 1.2.3.3
update add 5.0.53.10.in-addr.arpa. 600 A 1.2.3.2
update add 5.0.53.10.in-addr.arpa. 600 AAAA ::ffff:1.2.3.4
update add 5.0.53.10.in-addr.arpa. 600 AAAA ::ffff:1.2.3.3
update add 5.0.53.10.in-addr.arpa. 600 AAAA ::ffff:1.2.3.2
send
END
$DIG $DIGOPTS @10.53.0.6 \
+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd \
ANY -x 10.53.0.5 > dig.out.ns6.test$n
nextpart ns6/named.run > nextpart.out.test$n
grep "attempt to add more records than permitted by policy" nextpart.out.test$n > /dev/null || ret=1
# the policy is 'grant * tcp-self . PTR(1) ANY(2) A;' so all the A
# records should have been added as there is no limit and the first 2
# of the AAAA records added as they match ANY(2).
c1=$(awk '$4 == "A" { print }' dig.out.ns6.test$n | wc -l)
c2=$(awk '$4 == "AAAA" { print }' dig.out.ns6.test$n | wc -l)
test "$c1" -eq 3 -a "$c2" -eq 2 || ret=1
grep "::ffff:1.2.3.2" dig.out.ns6.test$n && ret=1
if test $ret -ne 0
then
echo_i "failed"; status=1
fi
if $FEATURETEST --gssapi ; then
n=`expr $n + 1`
ret=0
......
......@@ -8,16 +8,6 @@
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
..
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
.. Reference:
BIND 9 Configuration Reference
......@@ -5708,6 +5698,29 @@ never be updated). Note that when an attempt is made to delete all
records associated with a name, the rules are checked for each existing
record type.
If the type is immediately followed by a number in parentheses,
that number is the maximum number of records of that type permitted
to exist in the RRset after an update has been applied. For example,
``PTR(1)`` indicates that only one PTR record is allowed. If an
attempt is made to add two PTR records in an update, the second one
will be silently discarded. If a PTR record already exists, both
new records will be silently discarded.
If type ANY is specified with a limit, then that limit applies to
all types that are not otherwise specified. For example, ``A PTR(1)
ANY(2)`` indicates that an unlimited number of A records can exist,
but only one PTR record, and no more than two of any other type.
Typical use with rule ``grant * tcp-self . PTR(1);`` in the zone
2.0.192.IN-ADDR.ARPA::
nsupdate -v <<EOF
local 192.0.2.1
del 1.2.0.192.IN-ADDR.ARPA PTR
add 1.2.0.192.IN-ADDR.ARPA 0 PTR EXAMPLE.COM
send
EOF
The ruletype field has 16 values: ``name``, ``subdomain``, ``wildcard``,
``self``, ``selfsub``, ``selfwild``, ``krb5-self``, ``ms-self``,
``krb5-selfsub``, ``ms-selfsub``, ``krb5-subdomain``, ``ms-subdomain``,
......
......@@ -58,6 +58,10 @@ New Features
- ``dig`` and other tools can now print the Extended DNS Error (EDE)
option when it appears in a request or response. [GL #1834]
- Per-type record count limits can now be specified in ``update-policy``
statements, to limit the number of records of a particular type
that can be added to a domain name via dynamic update. [GL #1657]
Feature Changes
~~~~~~~~~~~~~~~
......
......@@ -45,6 +45,7 @@
#include <dns/rbt.h>
#include <dns/rdataclass.h>
#include <dns/rdatatype.h>
#include <dns/result.h>
#include <dns/rrl.h>
#include <dns/secalg.h>
#include <dns/ssu.h>
......@@ -1850,15 +1851,35 @@ check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
element2 = cfg_list_next(element2))
{
const cfg_obj_t *typeobj;
const char *bracket;
typeobj = cfg_listelt_value(element2);
DE_CONST(cfg_obj_asstring(typeobj), r.base);
r.length = strlen(r.base);
bracket = strchr(r.base, '(' /*)*/);
if (bracket != NULL) {
char *end = NULL;
unsigned long max;
r.length = bracket - r.base;
max = strtoul(bracket + 1, &end, 10);
if (max > 0xffff || end[0] != /*(*/ ')' ||
end[1] != 0) {
cfg_obj_log(typeobj, logctx,
ISC_LOG_ERROR,
"'%s' is not a valid count",
bracket);
result = DNS_R_SYNTAX;
}
} else {
r.length = strlen(r.base);
}
tresult = dns_rdatatype_fromtext(&type, &r);
if (tresult != ISC_R_SUCCESS) {
cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
"'%s' is not a valid type", r.base);
"'%.*s' is not a valid type",
(int)r.length, r.base);
result = tresult;
}
}
......
......@@ -47,6 +47,11 @@ typedef enum {
dns_ssumatchtype_dlz = 16 /* intentionally higher than _max */
} dns_ssumatchtype_t;
typedef struct dns_ssuruletype {
dns_rdatatype_t type; /* type allowed */
unsigned int max; /* maximum number of records allowed. */
} dns_ssuruletype_t;
isc_result_t
dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table);
/*%<
......@@ -103,7 +108,7 @@ isc_result_t
dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
const dns_name_t *identity, dns_ssumatchtype_t matchtype,
const dns_name_t *name, unsigned int ntypes,
dns_rdatatype_t *types);
dns_ssuruletype_t *types);
/*%<
* Adds a new rule to a simple-secure-update rule table. The rule
* either grants or denies update privileges of an identity (or set of
......@@ -136,7 +141,7 @@ bool
dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
const dns_name_t *name, const isc_netaddr_t *addr,
bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type,
const dst_key_t *key);
const dst_key_t *key, const dns_ssurule_t **rulep);
/*%<
* Checks that the attempted update of (name, type) is allowed according
* to the rules specified in the simple-secure-update rule table. If
......@@ -180,18 +185,31 @@ 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_rdatatype_t **types);
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);
......
......@@ -39,12 +39,11 @@
struct dns_ssurule {
unsigned int magic;
bool grant; /*%< is this a grant or a deny? */
dns_ssumatchtype_t matchtype; /*%< which type of pattern match?
* */
dns_ssumatchtype_t matchtype; /*%< which type of pattern match? */
dns_name_t *identity; /*%< the identity to match */
dns_name_t *name; /*%< the name being updated */
unsigned int ntypes; /*%< number of data types covered */
dns_rdatatype_t *types; /*%< the data types. Can include */
dns_ssuruletype_t *types; /*%< the data types. Can include */
/* ANY. if NULL, defaults to all */
/* types except SIG, SOA, and NS */
ISC_LINK(dns_ssurule_t) link;
......@@ -86,15 +85,16 @@ destroy(dns_ssutable_t *table) {
dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules);
if (rule->identity != NULL) {
dns_name_free(rule->identity, mctx);
isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
isc_mem_put(mctx, rule->identity,
sizeof(*rule->identity));
}
if (rule->name != NULL) {
dns_name_free(rule->name, mctx);
isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
isc_mem_put(mctx, rule->name, sizeof(*rule->name));
}
if (rule->types != NULL) {
isc_mem_put(mctx, rule->types,
rule->ntypes * sizeof(dns_rdatatype_t));
rule->ntypes * sizeof(*rule->types));
}
ISC_LIST_UNLINK(table->rules, rule, link);
rule->magic = 0;
......@@ -133,7 +133,7 @@ isc_result_t
dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
const dns_name_t *identity, dns_ssumatchtype_t matchtype,
const dns_name_t *name, unsigned int ntypes,
dns_rdatatype_t *types) {
dns_ssuruletype_t *types) {
dns_ssurule_t *rule;
isc_mem_t *mctx;
......@@ -149,7 +149,7 @@ dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
}
mctx = table->mctx;
rule = isc_mem_get(mctx, sizeof(dns_ssurule_t));
rule = isc_mem_get(mctx, sizeof(*rule));
rule->identity = NULL;
rule->name = NULL;
......@@ -157,11 +157,11 @@ dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
rule->grant = grant;
rule->identity = isc_mem_get(mctx, sizeof(dns_name_t));
rule->identity = isc_mem_get(mctx, sizeof(*rule->identity));
dns_name_init(rule->identity, NULL);
dns_name_dup(identity, mctx, rule->identity);
rule->name = isc_mem_get(mctx, sizeof(dns_name_t));
rule->name = isc_mem_get(mctx, sizeof(*rule->name));
dns_name_init(rule->name, NULL);
dns_name_dup(name, mctx, rule->name);
......@@ -169,9 +169,8 @@ dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
rule->ntypes = ntypes;
if (ntypes > 0) {
rule->types = isc_mem_get(mctx,
ntypes * sizeof(dns_rdatatype_t));
memmove(rule->types, types, ntypes * sizeof(dns_rdatatype_t));
rule->types = isc_mem_get(mctx, ntypes * sizeof(*rule->types));
memmove(rule->types, types, ntypes * sizeof(*rule->types));
} else {
rule->types = NULL;
}
......@@ -284,15 +283,15 @@ bool
dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
const dns_name_t *name, const isc_netaddr_t *addr,
bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type,
const dst_key_t *key) {
dns_ssurule_t *rule;
unsigned int i;
const dst_key_t *key, const dns_ssurule_t **rulep) {
dns_fixedname_t fixed;
dns_name_t *wildcard;
dns_name_t *tcpself;
dns_name_t *stfself;
isc_result_t result;
dns_name_t *tcpself;
dns_name_t *wildcard;
dns_ssurule_t *rule;
int match;
isc_result_t result;
unsigned int i;
REQUIRE(VALID_SSUTABLE(table));
REQUIRE(signer == NULL || dns_name_isabsolute(signer));
......@@ -513,8 +512,8 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
}
} else {
for (i = 0; i < rule->ntypes; i++) {
if (rule->types[i] == dns_rdatatype_any ||
rule->types[i] == type) {
if (rule->types[i].type == dns_rdatatype_any ||
rule->types[i].type == type) {
break;
}
}
......@@ -522,6 +521,9 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
continue;
}
}
if (rule->grant && rulep != NULL) {
*rulep = rule;
}
return (rule->grant);
}
......@@ -553,13 +555,31 @@ dns_ssurule_name(const dns_ssurule_t *rule) {
}
unsigned int
dns_ssurule_types(const dns_ssurule_t *rule, dns_rdatatype_t **types) {
dns_ssurule_types(const dns_ssurule_t *rule, dns_ssuruletype_t **types) {
REQUIRE(VALID_SSURULE(rule));
REQUIRE(types != NULL && *types != NULL);
*types = rule->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));
......@@ -599,7 +619,6 @@ dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
rule->identity = NULL;
rule->name = NULL;
rule->types = NULL;
rule->grant = true;
rule->matchtype = dns_ssumatchtype_dlz;
rule->ntypes = 0;
......
......@@ -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
......
......@@ -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().
*/
......@@ -899,8 +910,9 @@ typedef struct {
static isc_result_t
ssu_checkrule(void *data, dns_rdataset_t *rrset) {
ssu_check_t *ssuinfo = data;
bool result;
const dns_ssurule_t *rule = NULL;
ssu_check_t *ssuinfo = data;
/*
* If we're deleting all records, it's ok to delete RRSIG and NSEC even
......@@ -910,9 +922,10 @@ ssu_checkrule(void *data, dns_rdataset_t *rrset) {
rrset->type == dns_rdatatype_nsec) {
return (ISC_R_SUCCESS);
}
result = dns_ssutable_checkrules(
ssuinfo->table, ssuinfo->signer, ssuinfo->name, ssuinfo->addr,
ssuinfo->tcp, ssuinfo->aclenv, rrset->type, ssuinfo->key);
result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
ssuinfo->name, ssuinfo->addr,
ssuinfo->tcp, ssuinfo->aclenv,
rrset->type, ssuinfo->key, &rule);
return (result == true ? ISC_R_SUCCESS : ISC_R_FAILURE);
}
......@@ -2565,6 +2578,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
uint64_t records;
dns_aclenv_t *env =
ns_interfacemgr_getaclenv(client->manager->interface->mgr);
size_t ruleslen = 0;
size_t rule;
const dns_ssurule_t **rules = NULL;
INSIST(event->ev_type == DNS_EVENT_UPDATE);
......@@ -2739,15 +2755,24 @@ update_action(isc_task_t *task, isc_event_t *event) {
/*
* Perform the Update Section Prescan.
*/
if (ssutable != NULL) {
ruleslen = request->counts[DNS_SECTION_UPDATE];
rules = isc_mem_get(mctx, sizeof(*rules) * ruleslen);
memset(rules, 0, sizeof(*rules) * ruleslen);
}
for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
for (rule = 0,
result = dns_message_firstname(request, DNS_SECTION_UPDATE);
result == ISC_R_SUCCESS;
result = dns_message_nextname(request, DNS_SECTION_UPDATE))
rule++, result = dns_message_nextname(request, DNS_SECTION_UPDATE))
{
dns_name_t *name = NULL;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_ttl_t ttl;
dns_rdataclass_t update_class;
INSIST(ssutable == NULL || rule < ruleslen);
get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
&rdata, &covers, &ttl, &update_class);
......@@ -2820,7 +2845,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
if (!dns_ssutable_checkrules(
ssutable, client->signer, name,
&netaddr, TCPCLIENT(client), env,
rdata.type, tsigkey))
rdata.type, tsigkey, &rules[rule]))
{
FAILC(DNS_R_REFUSED, "rejected by "
"secure update");
......@@ -2847,9 +2872,10 @@ update_action(isc_task_t *task, isc_event_t *event) {
*/