BIND 9.19.9

-----BEGIN PGP SIGNATURE-----
 
 iQJDBAABCgAtFiEENKwGS3ftSQfs1TU17QVz/8hFYQUFAmPAfwYPHG1pY2hhbEBp
 c2Mub3JnAAoJEO0Fc//IRWEFpmAP/23tasuol54W1dxnjGoQ7NYDV89ywQiWplyn
 syPs+iESFb3I9SlAHHhRGM0IREuDxjuexFdrIJOfZqokg36qPj+z81LRlRuRuetc
 HigGzpt2CDP41rVMsxzW3vyh2a3fTrjBKYT4tnDlsdnbwJOfFG4N/hdB7jqDPWut
 u1Itf/lD8iHhsISgFqvtKiQqc6XFwwzVAeSPH6pHnmngt16imVoQiddnw1RYn0vB
 EPcqhVvSeYS1AGWprnHpaWt8bru460iZwet+QKlxNxW6p4mOXGr6jQWqhZ+6ORDr
 Vo/a3+5Di+tNn89GJSbehLi5UQbvrcMR8WiQ54WP/k0PPTgoqMRC4PerLsNU8Vzq
 y1k18n8DMsuro92cNAdJk3gXuXYgGNF2sk9JtqwmiDo1/6G3afKfDiVKjiK1CxK0
 1CMKD+mPHCWB/H5U50oL1z89OCZDVUBUDT0YIrCBBrTIitzyXyAFkh+sjbRbdzww
 kg1GdZ4ODaydcWYH7r3RCHWDX6nkwADqGRk0SYvrJTFL2Hu150mwuxZj/5UZcmsz
 of6qh5b9yZrDrnBHgoqknnepuxiORFF7l3kk63fA13WG6S1m6h2ZONoVLw0J67dx
 mnAo0nlnWKi+TEl/CHiHcMZbeVhE/jrHAMPIcQQphKbCeQT1NPFSU2FQxa+dpix+
 V+y8x6Qb
 =TTpT
 -----END PGP SIGNATURE-----

Merge tag 'v9_19_9'

BIND 9.19.9
This commit is contained in:
Michał Kępień 2023-01-25 21:16:00 +01:00
commit 4e934bae0b
28 changed files with 679 additions and 279 deletions

21
CHANGES
View file

@ -41,13 +41,24 @@
not negotiate "dot" ALPN token could crash BIND
on shutdown. That has been fixed. [GL #3767]
6067. [placeholder]
--- 9.19.9 released ---
6066. [placeholder]
6067. [security] Fix serve-stale crash when recursive clients soft quota
is reached. (CVE-2022-3924) [GL #3619]
6066. [security] Handle RRSIG lookups when serve-stale is active.
(CVE-2022-3736) [GL #3622]
6065. [placeholder]
6064. [placeholder]
6064. [security] An UPDATE message flood could cause named to exhaust all
available memory. This flaw was addressed by adding a
new "update-quota" statement that controls the number of
simultaneous UPDATE messages that can be processed or
forwarded. The default is 100. A stats counter has been
added to record events when the update quota is
exceeded, and the XML and JSON statistics version
numbers have been updated. (CVE-2022-3094) [GL #3523]
6063. [cleanup] The RSA and ECDSA parts of the DNSSEC has been
refactored for a better OpenSSL 3.x integration and
@ -986,7 +997,9 @@
when the resent query's result was SERVFAIL. [GL #3020]
5830. [func] Implement incremental resizing of isc_ht hash tables to
perform the rehashing gradually. [GL #3212]
perform the rehashing gradually. The catalog zone
implementation has been optimized to work with hundreds
of thousands of member zones. [GL #3212] [GL #3744]
5829. [func] Refactor and simplify isc_timer API in preparation
for further refactoring on top of network manager

View file

@ -15,7 +15,7 @@
<xsl:output method="html" indent="yes" version="4.0"/>
<!-- the version number **below** must match version in bin/named/statschannel.c -->
<!-- don't forget to update "/xml/v<STATS_XML_VERSION_MAJOR>" in the HTTP endpoints listed below -->
<xsl:template match="statistics[@version=&quot;3.12&quot;]">
<xsl:template match="statistics[@version=&quot;3.13&quot;]">
<html>
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

View file

@ -131,6 +131,7 @@ options {\n\
trust-anchor-telemetry yes;\n\
udp-receive-buffer 0;\n\
udp-send-buffer 0;\n\
update-quota 100;\n\
\n\
/* view */\n\
allow-new-zones no;\n\

View file

@ -8590,6 +8590,7 @@ load_configuration(const char *filename, named_server_t *server,
configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
configure_server_quota(maps, "recursive-clients",
&server->sctx->recursionquota);
configure_server_quota(maps, "update-quota", &server->sctx->updquota);
max = isc_quota_getmax(&server->sctx->recursionquota);
if (max > 1000) {

View file

@ -56,11 +56,11 @@
#include "xsl_p.h"
#define STATS_XML_VERSION_MAJOR "3"
#define STATS_XML_VERSION_MINOR "12"
#define STATS_XML_VERSION_MINOR "13"
#define STATS_XML_VERSION STATS_XML_VERSION_MAJOR "." STATS_XML_VERSION_MINOR
#define STATS_JSON_VERSION_MAJOR "1"
#define STATS_JSON_VERSION_MINOR "6"
#define STATS_JSON_VERSION_MINOR "7"
#define STATS_JSON_VERSION STATS_JSON_VERSION_MAJOR "." STATS_JSON_VERSION_MINOR
#define CHECK(m) \
@ -352,6 +352,7 @@ init_desc(void) {
SET_NSSTATDESC(reclimitdropped,
"queries dropped due to recursive client limit",
"RecLimitDropped");
SET_NSSTATDESC(updatequota, "Update quota exceeded", "UpdateQuota");
INSIST(i == ns_statscounter_max);

View file

@ -68,6 +68,7 @@ options {
recursive-clients 3000;
serial-query-rate 100;
server-id none;
update-quota 200;
check-names primary warn;
check-names secondary ignore;
max-cache-size 20000000000000;

View file

@ -57,6 +57,7 @@ options {
recursion no;
notify yes;
minimal-responses no;
update-quota 1;
};
acl named-acl {
@ -117,6 +118,7 @@ zone "other.nil" {
check-integrity no;
check-mx warn;
update-policy local;
allow-query { !10.53.0.2; any; };
allow-query-on { 10.53.0.1; 127.0.0.1; };
allow-transfer { any; };
};

View file

@ -1558,6 +1558,34 @@ $DIG $DIGOPTS +tcp @10.53.0.3 _dns.ns.relaxed SVCB > dig.out.ns3.test$n
grep '1 ns.relaxed. alpn="h2"' dig.out.ns3.test$n || ret=1
[ $ret = 0 ] || { echo_i "failed"; status=1; }
n=$((n + 1))
ret=0
echo_i "check that update is rejected if query is not allowed ($n)"
{
$NSUPDATE -d <<END
local 10.53.0.2
server 10.53.0.1 ${PORT}
update add reject.other.nil 3600 IN TXT Whatever
send
END
} > nsupdate.out.test$n 2>&1
grep 'failed: REFUSED' nsupdate.out.test$n > /dev/null || ret=1
[ $ret = 0 ] || { echo_i "failed"; status=1; }
n=$((n + 1))
ret=0
echo_i "check that update is rejected if quota is exceeded ($n)"
for loop in 1 2 3 4 5 6 7 8 9 10; do
{
$NSUPDATE -4 -l -p ${PORT} -k ns1/session.key > /dev/null 2>&1 <<END
update add txt-$loop.other.nil 3600 IN TXT Whatever
send
END
} &
done
wait_for_log 10 "too many DNS UPDATEs queued" ns1/named.run || ret=1
[ $ret = 0 ] || { echo_i "failed"; status=1; }
if ! $FEATURETEST --gssapi ; then
echo_i "SKIPPED: GSSAPI tests"
else

View file

@ -31,3 +31,5 @@ rm -f keyname keyname.err
rm -f ns*/named.lock
rm -f ns1/example2.db
rm -f ns*/managed-keys.bind*
rm -f nsupdate.out.*
rm -f ns*/named.run.prev

View file

@ -27,12 +27,12 @@ options {
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
tls tls-example-primary {
@ -43,21 +43,21 @@ tls tls-example-primary {
zone "example" {
type secondary;
file "example.bk";
allow-update-forwarding { any; };
allow-update-forwarding { 10.53.0.1; };
primaries { 10.53.0.1 tls ephemeral; };
};
zone "example2" {
type secondary;
file "example2.bk";
allow-update-forwarding { any; };
allow-update-forwarding { 10.53.0.1; };
primaries { 10.53.0.1; };
};
zone "example3" {
type secondary;
file "example3.bk";
allow-update-forwarding { any; };
allow-update-forwarding { 10.53.0.1; };
primaries {
10.53.0.1 tls tls-example-primary; // bad
10.53.0.1; // good

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
tls-port @TLSPORT@;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on tls ephemeral { 10.53.0.3; };
listen-on-v6 { none; };
recursion no;
notify yes;
update-quota 1;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "example" {
type secondary;
file "example.bk";
allow-update-forwarding { any; };
primaries { 10.53.0.1; };
};

View file

@ -18,7 +18,7 @@ cp -f ns3/noprimary.db ns3/noprimary1.db
copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns3/named1.conf.in ns3/named.conf
if $FEATURETEST --enable-dnstap
then

View file

@ -81,6 +81,7 @@ if [ $ret != 0 ] ; then echo_i "failed"; status=`expr $status + $ret`; fi
echo_i "checking update forwarding of a zone (signed) (Do53 -> DoT) ($n)"
ret=0
$NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -- - <<EOF || ret=1
local 10.53.0.1
server 10.53.0.3 ${PORT}
update add updated.example. 600 A 10.10.10.1
update add updated.example. 600 TXT Foo
@ -122,6 +123,7 @@ if [ $ret != 0 ] ; then echo_i "failed"; status=`expr $status + $ret`; fi
echo_i "checking update forwarding of a zone (signed) (DoT -> DoT) ($n)"
ret=0
$NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -S -O -- - <<EOF || ret=1
local 10.53.0.1
server 10.53.0.3 ${TLSPORT}
update add updated-dot.example. 600 A 10.10.10.1
update add updated-dot.example. 600 TXT Foo
@ -181,6 +183,7 @@ fi
echo_i "updating zone (unsigned) ($n)"
ret=0
$NSUPDATE -- - <<EOF || ret=1
local 10.53.0.1
server 10.53.0.3 ${PORT}
update add unsigned.example. 600 A 10.10.10.1
update add unsigned.example. 600 TXT Foo
@ -248,6 +251,7 @@ if [ $ret != 0 ] ; then echo_i "failed"; status=`expr $status + $ret`; fi
echo_i "checking update forwarding of a zone (signed) (Do53 -> DoT) ($n)"
ret=0
$NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -- - <<EOF || ret=1
local 10.53.0.1
server 10.53.0.3 ${PORT}
update add updated.example3. 600 A 10.10.10.1
update add updated.example3. 600 TXT Foo
@ -305,6 +309,7 @@ while [ $count -lt 5 -a $ret -eq 0 ]
do
(
$NSUPDATE -- - <<EOF
local 10.53.0.1
server 10.53.0.3 ${PORT}
zone noprimary
update add unsigned.noprimary. 600 A 10.10.10.1
@ -332,10 +337,11 @@ fi
if test -f keyname
then
echo_i "checking update forwarding to with sig0 (Do53 -> Do53) ($n)"
echo_i "checking update forwarding with sig0 (Do53 -> Do53) ($n)"
ret=0
keyname=`cat keyname`
$NSUPDATE -k $keyname.private -- - <<EOF
local 10.53.0.1
server 10.53.0.3 ${PORT}
zone example2
update add unsigned.example2. 600 A 10.10.10.1
@ -359,10 +365,11 @@ EOF
n=`expr $n + 1`
fi
echo_i "checking update forwarding to with sig0 (DoT -> Do53) ($n)"
echo_i "checking update forwarding with sig0 (DoT -> Do53) ($n)"
ret=0
keyname=`cat keyname`
$NSUPDATE -k $keyname.private -S -O -- - <<EOF
local 10.53.0.1
server 10.53.0.3 ${TLSPORT}
zone example2
update add unsigned-dot.example2. 600 A 10.10.10.1
@ -387,5 +394,40 @@ EOF
fi
fi
echo_i "attempting an update that should be rejected by ACL ($n)"
ret=0
{
$NSUPDATE -- - << EOF
local 10.53.0.2
server 10.53.0.3 ${PORT}
update add another.unsigned.example. 600 A 10.10.10.2
update add another.unsigned.example. 600 TXT Bar
send
EOF
} > nsupdate.out.$n 2>&1
grep REFUSED nsupdate.out.$n > /dev/null || ret=1
if [ $ret != 0 ] ; then echo_i "failed"; status=`expr $status + $ret`; fi
n=`expr $n + 1`
n=$((n + 1))
ret=0
echo_i "attempting updates that should exceed quota ($n)"
# lower the update quota to 1.
copy_setports ns3/named2.conf.in ns3/named.conf
rndc_reconfig ns3 10.53.0.3
nextpart ns3/named.run > /dev/null
for loop in 1 2 3 4 5 6 7 8 9 10; do
{
$NSUPDATE -- - > /dev/null 2>&1 <<END
local 10.53.0.1
server 10.53.0.3 ${PORT}
update add txt-$loop.unsigned.example 300 IN TXT Whatever
send
END
} &
done
wait_for_log 10 "too many DNS UPDATEs queued" ns3/named.run || ret=1
[ $ret = 0 ] || { echo_i "failed"; status=1; }
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View file

@ -39,6 +39,7 @@ information about each release, and source code.
.. include:: ../notes/notes-known-issues.rst
.. include:: ../notes/notes-current.rst
.. include:: ../notes/notes-9.19.9.rst
.. include:: ../notes/notes-9.19.8.rst
.. include:: ../notes/notes-9.19.7.rst
.. include:: ../notes/notes-9.19.6.rst

View file

@ -3903,6 +3903,14 @@ system.
value as :any:`tcp-keepalive-timeout`. This value can be updated at
runtime by using :option:`rndc tcp-timeouts`.
.. namedconf:statement:: update-quota
:tags: server
:short: Specifies the maximum number of concurrent DNS UPDATE messages that can be processed by the server.
This is the maximum number of simultaneous DNS UPDATE messages that
the server will accept for updating local authoritiative zones or
forwarding to a primary server. The default is ``100``.
.. _intervals:
Periodic Task Intervals
@ -7848,6 +7856,11 @@ Name Server Statistics Counters
``UpdateBadPrereq``
This indicates the number of dynamic updates rejected due to a prerequisite failure.
``UpdateQuota``
This indicates the number of times a dynamic update or update
forwarding request was rejected because the number of pending
requests exceeded :any:`update-quota`.
``RateDropped``
This indicates the number of responses dropped due to rate limits.

View file

@ -250,7 +250,7 @@ at a very high level, looking up the name ``www.isc.org`` :
Let's take a quick break here and look at what we've got so far...
how can our server trust this answer? If a clever attacker had taken over
the ``isc.org`` name server(s), or course she would send matching
the ``isc.org`` name server(s), of course she would send matching
keys and signatures. We need to ask someone else to have confidence
that we are really talking to the real ``isc.org`` name server. This
is a critical part of DNSSEC: at some point, the DNS administrators

View file

@ -359,6 +359,7 @@ options {
udp\-receive\-buffer <integer>;
udp\-send\-buffer <integer>;
update\-check\-ksk <boolean>;
update\-quota <integer>;
use\-v4\-udp\-ports { <portrange>; ... }; // deprecated
use\-v6\-udp\-ports { <portrange>; ... }; // deprecated
v6\-bias <integer>;

View file

@ -302,6 +302,7 @@ options {
udp-receive-buffer <integer>;
udp-send-buffer <integer>;
update-check-ksk <boolean>;
update-quota <integer>;
use-v4-udp-ports { <portrange>; ... }; // deprecated
use-v6-udp-ports { <portrange>; ... }; // deprecated
v6-bias <integer>;

View file

@ -56,3 +56,6 @@ Feature Changes
threads. This should increase the responsiveness of :iscman:`named`
when RPZ updates are being applied after an RPZ zone has been
successfully transferred. :gl:`#3190`
- The catalog zone implementation has been optimized to work with
hundreds of thousands of member zones. :gl:`#3212` :gl:`#3744`

View file

@ -44,8 +44,8 @@ Feature Changes
- Setting alternate local addresses for inbound zone transfers has been
deprecated. The relevant options (``alt-transfer-source``,
``alt-transfer-source-v6``, and ``use-alt-transfer-source``)
will be removed in a future BIND 9.19.x release. :gl:`#3694`
``alt-transfer-source-v6``, and ``use-alt-transfer-source``) will be
removed in a future BIND 9.19.x release. :gl:`#3694`
- On startup, :iscman:`named` now sets the limit on the number of open
files to the maximum allowed by the operating system, instead of

120
doc/notes/notes-9.19.9.rst Normal file
View file

@ -0,0 +1,120 @@
.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
..
.. SPDX-License-Identifier: MPL-2.0
..
.. 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 https://mozilla.org/MPL/2.0/.
..
.. See the COPYRIGHT file distributed with this work for additional
.. information regarding copyright ownership.
Notes for BIND 9.19.9
---------------------
Security Fixes
~~~~~~~~~~~~~~
- An UPDATE message flood could cause :iscman:`named` to exhaust all
available memory. This flaw was addressed by adding a new
:any:`update-quota` option that controls the maximum number of
outstanding DNS UPDATE messages that :iscman:`named` can hold in a
queue at any given time (default: 100). (CVE-2022-3094)
ISC would like to thank Rob Schulhof from Infoblox for bringing this
vulnerability to our attention. :gl:`#3523`
- :iscman:`named` could crash with an assertion failure when an RRSIG
query was received and :any:`stale-answer-client-timeout` was set to a
non-zero value. This has been fixed. (CVE-2022-3736)
ISC would like to thank Borja Marcos from Sarenet (with assistance by
Iratxe Niño from Fundación Sarenet) for bringing this vulnerability to
our attention. :gl:`#3622`
- :iscman:`named` running as a resolver with the
:any:`stale-answer-client-timeout` option set to any value greater
than ``0`` could crash with an assertion failure, when the
:any:`recursive-clients` soft quota was reached. This has been fixed.
(CVE-2022-3924)
ISC would like to thank Maksym Odinintsev from AWS for bringing this
vulnerability to our attention. :gl:`#3619`
New Features
~~~~~~~~~~~~
- The new :any:`update-quota` option can be used to control the number
of simultaneous DNS UPDATE messages that can be processed to update an
authoritative zone on a primary server, or forwarded to the primary
server by a secondary server. The default is 100. A new statistics
counter has also been added to record events when this quota is
exceeded, and the version numbers for the XML and JSON statistics
schemas have been updated. :gl:`#3523`
Removed Features
~~~~~~~~~~~~~~~~
- The statements setting alternate local addresses for inbound zone
transfers (``alt-transfer-source``, ``alt-transfer-source-v6``, and
``use-alt-transfer-source``) have been removed. :gl:`#3714`
- The Differentiated Services Code Point (DSCP) feature in BIND has been
non-operational since the new Network Manager was introduced in BIND
9.16. It is now marked as obsolete, and vestigial code implementing it
has been removed. Configuring DSCP values in ``named.conf`` now causes
a warning to be logged. :gl:`#3773`
Feature Changes
~~~~~~~~~~~~~~~
- A new way of configuring the preferred source address when talking to
remote servers, such as :any:`primaries` and :any:`parental-agents`,
has been added: setting the ``source`` and/or ``source-v6`` arguments
for a given statement is now possible. This new approach is intended
to eventually replace statements such as :any:`parental-source`,
:any:`parental-source-v6`, :any:`transfer-source`, etc. :gl:`#3762`
- The code for DNS over TCP and DNS over TLS transports has been
replaced with a new, unified transport implementation. :gl:`#3374`
Bug Fixes
~~~~~~~~~
- A rare assertion failure was fixed in outgoing TCP DNS connection
handling. :gl:`#3178` :gl:`#3636`
- In addition to a previously fixed bug, another similar issue was
discovered where quotas could be erroneously reached for servers,
including any configured forwarders, resulting in SERVFAIL answers
being sent to clients. This has been fixed. :gl:`#3752`
- In certain query resolution scenarios (e.g. when following CNAME
records), :iscman:`named` configured to answer from stale cache could
return a SERVFAIL response despite a usable, non-stale answer being
present in the cache. This has been fixed. :gl:`#3678`
- When an outgoing request timed out, :iscman:`named` would retry up to
three times with the same server instead of trying the next available
name server. This has been fixed. :gl:`#3637`
- Recently used ADB names and ADB entries (IP addresses) could get
cleaned when ADB was under memory pressure. To mitigate this, only
actual ADB names and ADB entries are now counted (excluding internal
memory structures used for "housekeeping") and recently used (<= 10
seconds) ADB names and entries are excluded from the overmem memory
cleaner. :gl:`#3739`
- The "Prohibited" Extended DNS Error was inadvertently set in some
NOERROR responses. This has been fixed. :gl:`#3743`
- Previously, TLS session resumption could have led to handshake
failures when client certificates were used for authentication (Mutual
TLS). This has been fixed. :gl:`#3725`
Known Issues
~~~~~~~~~~~~
- There are no new known issues with this release. See :ref:`above
<relnotes_known_issues>` for a list of all known issues affecting this
BIND 9 branch.

View file

@ -10730,6 +10730,8 @@ fail:
void
dns_resolver_cancelfetch(dns_fetch_t *fetch) {
fetchctx_t *fctx = NULL;
dns_fetchevent_t *event_trystale = NULL;
dns_fetchevent_t *event_fetchdone = NULL;
REQUIRE(DNS_FETCH_VALID(fetch));
fctx = fetch->private;
@ -10740,24 +10742,69 @@ dns_resolver_cancelfetch(dns_fetch_t *fetch) {
LOCK(&fctx->lock);
/*
* Find the completion event for this fetch (as opposed
* to those for other fetches that have joined the same
* fctx) and send it with result = ISC_R_CANCELED.
* Find all the events associated with the provided 'fetch' (as opposed
* to those for other fetches that have joined the same fctx). The
* event(s) found are only sent and removed from the fctx->events list
* after this loop is finished (i.e. the fctx->events list is not
* modified during iteration).
*/
for (dns_fetchevent_t *event = ISC_LIST_HEAD(fctx->events);
event != NULL; event = ISC_LIST_NEXT(event, ev_link))
{
if (event->fetch == fetch) {
isc_task_t *task = event->ev_sender;
ISC_LIST_UNLINK(fctx->events, event, ev_link);
event->ev_sender = fctx;
event->result = ISC_R_CANCELED;
/*
* Only process events associated with the provided 'fetch'.
*/
if (event->fetch != fetch) {
continue;
}
isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
/*
* Track various events associated with the provided 'fetch' in
* separate variables as they will need to be sent in a
* specific order.
*/
switch (event->ev_type) {
case DNS_EVENT_TRYSTALE:
INSIST(event_trystale == NULL);
event_trystale = event;
break;
case DNS_EVENT_FETCHDONE:
INSIST(event_fetchdone == NULL);
event_fetchdone = event;
break;
default:
UNREACHABLE();
}
/*
* Break out of the loop once all possible types of events
* associated with the provided 'fetch' are found.
*/
if (event_trystale != NULL && event_fetchdone != NULL) {
break;
}
}
/*
* The "trystale" event must be sent before the "fetchdone" event,
* because the latter clears the "recursing" query attribute, which is
* required by both events (handled by the same callback function).
*/
if (event_trystale != NULL) {
isc_task_t *etask = event_trystale->ev_sender;
ISC_LIST_UNLINK(fctx->events, event_trystale, ev_link);
event_trystale->ev_sender = fctx;
event_trystale->result = ISC_R_CANCELED;
isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event_trystale));
}
if (event_fetchdone != NULL) {
isc_task_t *etask = event_fetchdone->ev_sender;
ISC_LIST_UNLINK(fctx->events, event_fetchdone, ev_link);
event_fetchdone->ev_sender = fctx;
event_fetchdone->result = ISC_R_CANCELED;
isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event_fetchdone));
}
/*
* The fctx continues running even if no fetches remain;
* the answer is still cached.

View file

@ -1339,6 +1339,7 @@ static cfg_clausedef_t options_clauses[] = {
{ "treat-cr-as-space", NULL, CFG_CLAUSEFLAG_ANCIENT },
{ "udp-receive-buffer", &cfg_type_uint32, 0 },
{ "udp-send-buffer", &cfg_type_uint32, 0 },
{ "update-quota", &cfg_type_uint32, 0 },
{ "use-id-pool", NULL, CFG_CLAUSEFLAG_ANCIENT },
{ "use-ixfr", NULL, CFG_CLAUSEFLAG_ANCIENT },
{ "use-v4-udp-ports", &cfg_type_bracketed_portlist,

View file

@ -84,6 +84,7 @@ struct ns_server {
isc_quota_t recursionquota;
isc_quota_t tcpquota;
isc_quota_t xfroutquota;
isc_quota_t updquota;
ISC_LIST(isc_quota_t) http_quotas;
isc_mutex_t http_quotas_lock;

View file

@ -107,7 +107,9 @@ enum {
ns_statscounter_reclimitdropped = 66,
ns_statscounter_max = 67,
ns_statscounter_updatequota = 67,
ns_statscounter_max = 68,
};
void

View file

@ -5356,6 +5356,15 @@ qctx_init(ns_client_t *client, dns_fetchevent_t **eventp, dns_rdatatype_t qtype,
qctx->result = ISC_R_SUCCESS;
qctx->findcoveringnsec = qctx->view->synthfromdnssec;
/*
* If it's an RRSIG or SIG query, we'll iterate the node.
*/
if (qctx->qtype == dns_rdatatype_rrsig ||
qctx->qtype == dns_rdatatype_sig)
{
qctx->type = dns_rdatatype_any;
}
CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx);
}
@ -5523,15 +5532,6 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
CALL_HOOK(NS_QUERY_SETUP, &qctx);
/*
* If it's a SIG query, we'll iterate the node.
*/
if (qctx.qtype == dns_rdatatype_rrsig ||
qctx.qtype == dns_rdatatype_sig)
{
qctx.type = dns_rdatatype_any;
}
/*
* Check SERVFAIL cache
*/
@ -6257,7 +6257,9 @@ fetch_callback(isc_task_t *task, isc_event_t *event) {
CTRACE(ISC_LOG_DEBUG(3), "fetch_callback");
if (event->ev_type == DNS_EVENT_TRYSTALE) {
query_lookup_stale(client);
if (devent->result != ISC_R_CANCELED) {
query_lookup_stale(client);
}
isc_event_free(ISC_EVENT_PTR(&event));
return;
}

View file

@ -61,6 +61,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
isc_quota_init(&sctx->xfroutquota, 10);
isc_quota_init(&sctx->tcpquota, 10);
isc_quota_init(&sctx->recursionquota, 100);
isc_quota_init(&sctx->updquota, 100);
ISC_LIST_INIT(sctx->http_quotas);
isc_mutex_init(&sctx->http_quotas_lock);
@ -133,6 +134,7 @@ ns_server_detach(ns_server_t **sctxp) {
isc_mem_put(sctx->mctx, altsecret, sizeof(*altsecret));
}
isc_quota_destroy(&sctx->updquota);
isc_quota_destroy(&sctx->recursionquota);
isc_quota_destroy(&sctx->tcpquota);
isc_quota_destroy(&sctx->xfroutquota);

View file

@ -230,6 +230,8 @@ struct update_event {
dns_zone_t *zone;
isc_result_t result;
dns_message_t *answer;
const dns_ssurule_t **rules;
size_t ruleslen;
};
/*%
@ -269,6 +271,9 @@ static void
forward_done(isc_task_t *task, isc_event_t *event);
static isc_result_t
add_rr_prepare_action(void *data, rr_t *rr);
static isc_result_t
rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
const dns_rdata_t *rdata, bool *flag);
/**************************************************************************/
@ -341,25 +346,26 @@ inc_stats(ns_client_t *client, dns_zone_t *zone, isc_statscounter_t counter) {
static isc_result_t
checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename,
dns_acl_t *updateacl, dns_ssutable_t *ssutable) {
isc_result_t result;
char namebuf[DNS_NAME_FORMATSIZE];
char classbuf[DNS_RDATACLASS_FORMATSIZE];
int level;
isc_result_t result;
bool update_possible =
((updateacl != NULL && !dns_acl_isnone(updateacl)) ||
ssutable != NULL);
result = ns_client_checkaclsilent(client, NULL, queryacl, true);
if (result != ISC_R_SUCCESS) {
int level = update_possible ? ISC_LOG_ERROR : ISC_LOG_INFO;
dns_name_format(zonename, namebuf, sizeof(namebuf));
dns_rdataclass_format(client->view->rdclass, classbuf,
sizeof(classbuf));
level = (updateacl == NULL && ssutable == NULL) ? ISC_LOG_INFO
: ISC_LOG_ERROR;
ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
NS_LOGMODULE_UPDATE, level,
"update '%s/%s' denied due to allow-query",
namebuf, classbuf);
} else if (updateacl == NULL && ssutable == NULL) {
} else if (!update_possible) {
dns_name_format(zonename, namebuf, sizeof(namebuf));
dns_rdataclass_format(client->view->rdclass, classbuf,
sizeof(classbuf));
@ -1643,19 +1649,279 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) {
isc_result_t result = ISC_R_SUCCESS;
update_event_t *event = NULL;
isc_task_t *zonetask = NULL;
dns_ssutable_t *ssutable = NULL;
dns_message_t *request = client->message;
isc_mem_t *mctx = client->manager->mctx;
dns_aclenv_t *env = client->manager->aclenv;
dns_rdataclass_t zoneclass;
dns_rdatatype_t covers;
dns_name_t *zonename = NULL;
const dns_ssurule_t **rules = NULL;
size_t rule = 0, ruleslen = 0;
dns_zoneopt_t options;
dns_db_t *db = NULL;
dns_dbversion_t *ver = NULL;
CHECK(dns_zone_getdb(zone, &db));
zonename = dns_db_origin(db);
zoneclass = dns_db_class(db);
dns_zone_getssutable(zone, &ssutable);
options = dns_zone_getoptions(zone);
dns_db_currentversion(db, &ver);
/*
* Update message processing can leak record existence information
* so check that we are allowed to query this zone. Additionally,
* if we would refuse all updates for this zone, we bail out here.
*/
CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone),
dns_zone_getorigin(zone),
dns_zone_getupdateacl(zone), ssutable));
/*
* Check requestor's permissions.
*/
if (ssutable == NULL) {
CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
"update", dns_zone_getorigin(zone), false,
false));
} else if (client->signer == NULL && !TCPCLIENT(client)) {
CHECK(checkupdateacl(client, NULL, "update",
dns_zone_getorigin(zone), false, true));
}
if (dns_zone_getupdatedisabled(zone)) {
FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
"because the zone is frozen. Use "
"'rndc thaw' to re-enable updates.");
}
/*
* Prescan the update section, checking for updates that
* are illegal or violate policy.
*/
if (ssutable != NULL) {
ruleslen = request->counts[DNS_SECTION_UPDATE];
rules = isc_mem_getx(mctx, sizeof(*rules) * ruleslen,
ISC_MEM_ZERO);
}
for (rule = 0,
result = dns_message_firstname(request, DNS_SECTION_UPDATE);
result == ISC_R_SUCCESS;
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);
if (!dns_name_issubdomain(name, zonename)) {
FAILC(DNS_R_NOTZONE, "update RR is outside zone");
}
if (update_class == zoneclass) {
/*
* Check for meta-RRs. The RFC2136 pseudocode says
* check for ANY|AXFR|MAILA|MAILB, but the text adds
* "or any other QUERY metatype"
*/
if (dns_rdatatype_ismeta(rdata.type)) {
FAILC(DNS_R_FORMERR, "meta-RR in update");
}
result = dns_zone_checknames(zone, name, &rdata);
if (result != ISC_R_SUCCESS) {
FAIL(DNS_R_REFUSED);
}
if ((options & DNS_ZONEOPT_CHECKSVCB) != 0 &&
rdata.type == dns_rdatatype_svcb)
{
result = dns_rdata_checksvcb(name, &rdata);
if (result != ISC_R_SUCCESS) {
const char *reason =
isc_result_totext(result);
FAILNT(DNS_R_REFUSED, name, rdata.type,
reason);
}
}
} else if (update_class == dns_rdataclass_any) {
if (ttl != 0 || rdata.length != 0 ||
(dns_rdatatype_ismeta(rdata.type) &&
rdata.type != dns_rdatatype_any))
{
FAILC(DNS_R_FORMERR, "meta-RR in update");
}
} else if (update_class == dns_rdataclass_none) {
if (ttl != 0 || dns_rdatatype_ismeta(rdata.type)) {
FAILC(DNS_R_FORMERR, "meta-RR in update");
}
} else {
update_log(client, zone, ISC_LOG_WARNING,
"update RR has incorrect class %d",
update_class);
FAIL(DNS_R_FORMERR);
}
/*
* draft-ietf-dnsind-simple-secure-update-01 says
* "Unlike traditional dynamic update, the client
* is forbidden from updating NSEC records."
*/
if (rdata.type == dns_rdatatype_nsec3) {
FAILC(DNS_R_REFUSED, "explicit NSEC3 updates are not "
"allowed "
"in secure zones");
} else if (rdata.type == dns_rdatatype_nsec) {
FAILC(DNS_R_REFUSED, "explicit NSEC updates are not "
"allowed "
"in secure zones");
} else if (rdata.type == dns_rdatatype_rrsig &&
!dns_name_equal(name, zonename))
{
FAILC(DNS_R_REFUSED, "explicit RRSIG updates are "
"currently "
"not supported in secure zones "
"except "
"at the apex");
}
if (ssutable != NULL) {
isc_netaddr_t netaddr;
dns_name_t *target = NULL;
dst_key_t *tsigkey = NULL;
dns_rdata_ptr_t ptr;
dns_rdata_in_srv_t srv;
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
if (client->message->tsigkey != NULL) {
tsigkey = client->message->tsigkey->key;
}
if ((update_class == dns_rdataclass_in ||
update_class == dns_rdataclass_none) &&
rdata.type == dns_rdatatype_ptr)
{
result = dns_rdata_tostruct(&rdata, &ptr, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
target = &ptr.ptr;
}
if ((update_class == dns_rdataclass_in ||
update_class == dns_rdataclass_none) &&
rdata.type == dns_rdatatype_srv)
{
result = dns_rdata_tostruct(&rdata, &srv, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
target = &srv.target;
}
if (update_class == dns_rdataclass_any &&
zoneclass == dns_rdataclass_in &&
(rdata.type == dns_rdatatype_ptr ||
rdata.type == dns_rdatatype_srv))
{
ssu_check_t ssuinfo;
ssuinfo.name = name;
ssuinfo.table = ssutable;
ssuinfo.signer = client->signer;
ssuinfo.addr = &netaddr;
ssuinfo.aclenv = env;
ssuinfo.tcp = TCPCLIENT(client);
ssuinfo.key = tsigkey;
result = foreach_rr(db, ver, name, rdata.type,
dns_rdatatype_none,
ssu_checkrr, &ssuinfo);
if (result != ISC_R_SUCCESS) {
FAILC(DNS_R_REFUSED,
"rejected by secure update");
}
} else if (target != NULL &&
update_class == dns_rdataclass_none)
{
bool flag;
CHECK(rr_exists(db, ver, name, &rdata, &flag));
if (flag &&
!dns_ssutable_checkrules(
ssutable, client->signer, name,
&netaddr, TCPCLIENT(client), env,
rdata.type, target, tsigkey,
&rules[rule]))
{
FAILC(DNS_R_REFUSED,
"rejected by secure update");
}
} else if (rdata.type != dns_rdatatype_any) {
if (!dns_ssutable_checkrules(
ssutable, client->signer, name,
&netaddr, TCPCLIENT(client), env,
rdata.type, target, tsigkey,
&rules[rule]))
{
FAILC(DNS_R_REFUSED, "rejected by "
"secure update");
}
} else {
if (!ssu_checkall(db, ver, name, ssutable,
client->signer, &netaddr, env,
TCPCLIENT(client), tsigkey))
{
FAILC(DNS_R_REFUSED, "rejected by "
"secure update");
}
}
}
}
if (result != ISC_R_NOMORE) {
FAIL(result);
}
update_log(client, zone, LOGLEVEL_DEBUG, "update section prescan OK");
result = isc_quota_attach(&client->manager->sctx->updquota,
&(isc_quota_t *){ NULL });
if (result != ISC_R_SUCCESS) {
update_log(client, zone, LOGLEVEL_PROTOCOL,
"update failed: too many DNS UPDATEs queued (%s)",
isc_result_totext(result));
ns_stats_increment(client->manager->sctx->nsstats,
ns_statscounter_updatequota);
CHECK(DNS_R_DROP);
}
event = (update_event_t *)isc_event_allocate(
client->manager->mctx, client, DNS_EVENT_UPDATE, update_action,
NULL, sizeof(*event));
client, sizeof(*event));
event->zone = zone;
event->result = ISC_R_SUCCESS;
event->ev_arg = client;
event->rules = rules;
event->ruleslen = ruleslen;
rules = NULL;
isc_nmhandle_attach(client->handle, &client->updatehandle);
dns_zone_gettask(zone, &zonetask);
isc_task_send(zonetask, ISC_EVENT_PTR(&event));
failure:
if (db != NULL) {
dns_db_closeversion(db, &ver, false);
dns_db_detach(&db);
}
if (rules != NULL) {
isc_mem_put(mctx, rules, sizeof(*rules) * ruleslen);
}
if (ssutable != NULL) {
dns_ssutable_detach(&ssutable);
}
return (result);
}
@ -1763,9 +2029,6 @@ ns_update_start(ns_client_t *client, isc_nmhandle_t *handle,
break;
case dns_zone_secondary:
case dns_zone_mirror:
CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
"update forwarding", zonename, true,
false));
dns_message_clonebuffer(client->message);
CHECK(send_forward_event(client, zone));
break;
@ -1776,16 +2039,21 @@ ns_update_start(ns_client_t *client, isc_nmhandle_t *handle,
failure:
if (result == DNS_R_REFUSED) {
INSIST(dns_zone_gettype(zone) == dns_zone_secondary ||
dns_zone_gettype(zone) == dns_zone_mirror);
inc_stats(client, zone, ns_statscounter_updaterej);
}
/*
* We failed without having sent an update event to the zone.
* We are still in the client task context, so we can
* simply give an error response without switching tasks.
*/
respond(client, result);
if (result == DNS_R_DROP) {
ns_client_drop(client, result);
isc_nmhandle_detach(&client->reqhandle);
} else {
respond(client, result);
}
if (zone != NULL) {
dns_zone_detach(&zone);
}
@ -2619,6 +2887,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
update_event_t *uev = (update_event_t *)event;
dns_zone_t *zone = uev->zone;
ns_client_t *client = (ns_client_t *)event->ev_arg;
const dns_ssurule_t **rules = uev->rules;
size_t rule = 0, ruleslen = uev->ruleslen;
isc_result_t result;
dns_db_t *db = NULL;
dns_dbversion_t *oldver = NULL;
@ -2630,7 +2900,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
dns_rdatatype_t covers;
dns_message_t *request = client->message;
dns_rdataclass_t zoneclass;
dns_name_t *zonename;
dns_name_t *zonename = NULL;
dns_ssutable_t *ssutable = NULL;
dns_fixedname_t tmpnamefixed;
dns_name_t *tmpname = NULL;
@ -2640,10 +2910,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
dns_ttl_t maxttl = 0;
uint32_t maxrecords;
uint64_t records;
dns_aclenv_t *env = client->manager->aclenv;
size_t ruleslen = 0;
size_t rule;
const dns_ssurule_t **rules = NULL;
INSIST(event->ev_type == DNS_EVENT_UPDATE);
@ -2654,14 +2920,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
zonename = dns_db_origin(db);
zoneclass = dns_db_class(db);
dns_zone_getssutable(zone, &ssutable);
/*
* Update message processing can leak record existence information
* so check that we are allowed to query this zone. Additionally
* if we would refuse all updates for this zone we bail out here.
*/
CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename,
dns_zone_getupdateacl(zone), ssutable));
options = dns_zone_getoptions(zone);
/*
* Get old and new versions now that queryacl has been checked.
@ -2796,217 +3055,10 @@ update_action(isc_task_t *task, isc_event_t *event) {
update_log(client, zone, LOGLEVEL_DEBUG, "prerequisites are OK");
/*
* Check Requestor's Permissions. It seems a bit silly to do this
* only after prerequisite testing, but that is what RFC2136 says.
*/
if (ssutable == NULL) {
CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
"update", zonename, false, false));
} else if (client->signer == NULL && !TCPCLIENT(client)) {
CHECK(checkupdateacl(client, NULL, "update", zonename, false,
true));
}
if (dns_zone_getupdatedisabled(zone)) {
FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
"because the zone is frozen. Use "
"'rndc thaw' to re-enable updates.");
}
/*
* Perform the Update Section Prescan.
*/
if (ssutable != NULL) {
ruleslen = request->counts[DNS_SECTION_UPDATE];
rules = isc_mem_getx(mctx, sizeof(*rules) * ruleslen,
ISC_MEM_ZERO);
}
options = dns_zone_getoptions(zone);
for (rule = 0,
result = dns_message_firstname(request, DNS_SECTION_UPDATE);
result == ISC_R_SUCCESS;
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);
if (!dns_name_issubdomain(name, zonename)) {
FAILC(DNS_R_NOTZONE, "update RR is outside zone");
}
if (update_class == zoneclass) {
/*
* Check for meta-RRs. The RFC2136 pseudocode says
* check for ANY|AXFR|MAILA|MAILB, but the text adds
* "or any other QUERY metatype"
*/
if (dns_rdatatype_ismeta(rdata.type)) {
FAILC(DNS_R_FORMERR, "meta-RR in update");
}
result = dns_zone_checknames(zone, name, &rdata);
if (result != ISC_R_SUCCESS) {
FAIL(DNS_R_REFUSED);
}
if ((options & DNS_ZONEOPT_CHECKSVCB) != 0 &&
rdata.type == dns_rdatatype_svcb)
{
result = dns_rdata_checksvcb(name, &rdata);
if (result != ISC_R_SUCCESS) {
const char *reason =
isc_result_totext(result);
FAILNT(DNS_R_REFUSED, name, rdata.type,
reason);
}
}
} else if (update_class == dns_rdataclass_any) {
if (ttl != 0 || rdata.length != 0 ||
(dns_rdatatype_ismeta(rdata.type) &&
rdata.type != dns_rdatatype_any))
{
FAILC(DNS_R_FORMERR, "meta-RR in update");
}
} else if (update_class == dns_rdataclass_none) {
if (ttl != 0 || dns_rdatatype_ismeta(rdata.type)) {
FAILC(DNS_R_FORMERR, "meta-RR in update");
}
} else {
update_log(client, zone, ISC_LOG_WARNING,
"update RR has incorrect class %d",
update_class);
FAIL(DNS_R_FORMERR);
}
/*
* draft-ietf-dnsind-simple-secure-update-01 says
* "Unlike traditional dynamic update, the client
* is forbidden from updating NSEC records."
*/
if (rdata.type == dns_rdatatype_nsec3) {
FAILC(DNS_R_REFUSED, "explicit NSEC3 updates are not "
"allowed "
"in secure zones");
} else if (rdata.type == dns_rdatatype_nsec) {
FAILC(DNS_R_REFUSED, "explicit NSEC updates are not "
"allowed "
"in secure zones");
} else if (rdata.type == dns_rdatatype_rrsig &&
!dns_name_equal(name, zonename))
{
FAILC(DNS_R_REFUSED, "explicit RRSIG updates are "
"currently "
"not supported in secure zones "
"except "
"at the apex");
}
if (ssutable != NULL) {
isc_netaddr_t netaddr;
dns_name_t *target = NULL;
dst_key_t *tsigkey = NULL;
dns_rdata_ptr_t ptr;
dns_rdata_in_srv_t srv;
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
if (client->message->tsigkey != NULL) {
tsigkey = client->message->tsigkey->key;
}
if ((update_class == dns_rdataclass_in ||
update_class == dns_rdataclass_none) &&
rdata.type == dns_rdatatype_ptr)
{
result = dns_rdata_tostruct(&rdata, &ptr, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
target = &ptr.ptr;
}
if ((update_class == dns_rdataclass_in ||
update_class == dns_rdataclass_none) &&
rdata.type == dns_rdatatype_srv)
{
result = dns_rdata_tostruct(&rdata, &srv, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
target = &srv.target;
}
if (update_class == dns_rdataclass_any &&
zoneclass == dns_rdataclass_in &&
(rdata.type == dns_rdatatype_ptr ||
rdata.type == dns_rdatatype_srv))
{
ssu_check_t ssuinfo;
ssuinfo.name = name;
ssuinfo.table = ssutable;
ssuinfo.signer = client->signer;
ssuinfo.addr = &netaddr;
ssuinfo.aclenv = env;
ssuinfo.tcp = TCPCLIENT(client);
ssuinfo.key = tsigkey;
result = foreach_rr(db, ver, name, rdata.type,
dns_rdatatype_none,
ssu_checkrr, &ssuinfo);
if (result != ISC_R_SUCCESS) {
FAILC(DNS_R_REFUSED,
"rejected by secure update");
}
} else if (target != NULL &&
update_class == dns_rdataclass_none)
{
bool flag;
CHECK(rr_exists(db, ver, name, &rdata, &flag));
if (flag &&
!dns_ssutable_checkrules(
ssutable, client->signer, name,
&netaddr, TCPCLIENT(client), env,
rdata.type, target, tsigkey,
&rules[rule]))
{
FAILC(DNS_R_REFUSED,
"rejected by secure update");
}
} else if (rdata.type != dns_rdatatype_any) {
if (!dns_ssutable_checkrules(
ssutable, client->signer, name,
&netaddr, TCPCLIENT(client), env,
rdata.type, target, tsigkey,
&rules[rule]))
{
FAILC(DNS_R_REFUSED, "rejected by "
"secure update");
}
} else {
if (!ssu_checkall(db, ver, name, ssutable,
client->signer, &netaddr, env,
TCPCLIENT(client), tsigkey))
{
FAILC(DNS_R_REFUSED, "rejected by "
"secure update");
}
}
}
}
if (result != ISC_R_NOMORE) {
FAIL(result);
}
update_log(client, zone, LOGLEVEL_DEBUG, "update section prescan OK");
/*
* Process the Update Section.
*/
INSIST(ssutable == NULL || rules != NULL);
for (rule = 0,
result = dns_message_firstname(request, DNS_SECTION_UPDATE);
result == ISC_R_SUCCESS;
@ -3454,10 +3506,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
if (result == ISC_R_SUCCESS && records > maxrecords) {
update_log(client, zone, ISC_LOG_ERROR,
"records in zone (%" PRIu64 ") "
"exceeds"
" max-"
"records"
" (%u)",
"exceeds max-records (%u)",
records, maxrecords);
result = DNS_R_TOOMANYRECORDS;
goto failure;
@ -3582,6 +3631,7 @@ updatedone_action(isc_task_t *task, isc_event_t *event) {
respond(client, uev->result);
isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota });
isc_event_free(&event);
isc_nmhandle_detach(&client->updatehandle);
}
@ -3596,6 +3646,8 @@ forward_fail(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
respond(client, DNS_R_SERVFAIL);
isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota });
isc_event_free(&event);
isc_nmhandle_detach(&client->updatehandle);
}
@ -3631,6 +3683,8 @@ forward_done(isc_task_t *task, isc_event_t *event) {
ns_client_sendraw(client, uev->answer);
dns_message_detach(&uev->answer);
isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota });
isc_event_free(&event);
isc_nmhandle_detach(&client->reqhandle);
isc_nmhandle_detach(&client->updatehandle);
@ -3666,6 +3720,24 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) {
update_event_t *event = NULL;
isc_task_t *zonetask = NULL;
result = checkupdateacl(client, dns_zone_getforwardacl(zone),
"update forwarding", dns_zone_getorigin(zone),
true, false);
if (result != ISC_R_SUCCESS) {
return (result);
}
result = isc_quota_attach(&client->manager->sctx->updquota,
&(isc_quota_t *){ NULL });
if (result != ISC_R_SUCCESS) {
update_log(client, zone, LOGLEVEL_PROTOCOL,
"update failed: too many DNS UPDATEs queued (%s)",
isc_result_totext(result));
ns_stats_increment(client->manager->sctx->nsstats,
ns_statscounter_updatequota);
return (DNS_R_DROP);
}
event = (update_event_t *)isc_event_allocate(
client->manager->mctx, client, DNS_EVENT_UPDATE, forward_action,
NULL, sizeof(*event));