2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

3956. [func] Notify messages are now rate limited by notify-rate and

startup-notify-rate instead of serial-query-rate.
                        [RT #24454]

3955.   [bug]           Notify messages due to changes are no longer queued
                        behind startup notify messages. [RT #24454]
This commit is contained in:
Mark Andrews 2014-09-29 10:01:08 +10:00
parent 4b92bc0022
commit 10c12aa549
16 changed files with 367 additions and 59 deletions

View File

@ -1,3 +1,10 @@
3956. [func] Notify messages are now rate limited by notify-rate and
startup-notify-rate instead of serial-query-rate.
[RT #24454]
3955. [bug] Notify messages due to changes are no longer queued
behind startup notify messages. [RT #24454]
3954. [bug] Unchecked mutex init in dlz_dlopen_driver.c [RT #37112]
3953. [bug] Don't escape semi-colon in TXT fields. [RT #37159]

2
README
View File

@ -95,6 +95,8 @@ BIND 9.11.0
the specified file by default instead of to the system log.
- dig can now set arbitary EDNS options on requests (+ednsopt).
- dig can now set yet-to-be-defined EDNS flags on requests (+ednsflags).
- serial-query-rate no longer covers NOTIFY messages. These are
seperately controlled by notity-rate and startup-notify-rate.
This release addresses the security flaw described in
CVE-2014-3214 and CVE-2014-3859.

View File

@ -81,6 +81,7 @@ options {\n\
# named-xfer <obsolete>;\n\
nta-lifetime 3600;\n\
nta-recheck 300;\n\
notify-rate 20;\n\
# pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
port 53;\n\
prefetch 2 9;\n\
@ -99,6 +100,7 @@ options {\n\
serial-queries 20;\n\
serial-query-rate 20;\n\
server-id none;\n\
startup-notify-rate 20;\n\
statistics-file \"named.stats\";\n\
statistics-interval 60;\n\
tcp-clients 100;\n\

View File

@ -5701,6 +5701,16 @@ load_configuration(const char *filename, ns_server_t *server,
INSIST(result == ISC_R_SUCCESS);
dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
obj = NULL;
result = ns_config_get(maps, "notify-rate", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
obj = NULL;
result = ns_config_get(maps, "startup-notify-rate", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_zonemgr_setstartupnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
obj = NULL;
result = ns_config_get(maps, "serial-query-rate", &obj);
INSIST(result == ISC_R_SUCCESS);

View File

@ -15,12 +15,11 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: clean.sh,v 1.14 2011/10/17 23:46:33 tbox Exp $
#
# Clean up after zone transfer tests.
#
rm -f ns3/example.bk dig.out.ns2.test* dig.out.ns3.test*
rm -f ns2/example.db
rm -f log.out
rm -f */named.memstats

View File

@ -0,0 +1,28 @@
; Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
;
; Permission to use, copy, modify, and/or distribute this software for any
; purpose with or without fee is hereby granted, provided that the above
; copyright notice and this permission notice appear in all copies.
;
; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
; PERFORMANCE OF THIS SOFTWARE.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
1 ; serial
300 ; refresh (300 seconds)
300 ; retry (300 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
NS ns3
ns2 A 10.53.0.2
ns3 A 10.53.0.3
a A 10.0.0.1

View File

@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named.conf,v 1.23 2011/12/20 00:06:54 marka Exp $ */
controls { /* empty */ };
options {
@ -29,6 +27,7 @@ options {
listen-on-v6 { none; };
recursion no;
notify yes;
startup-notify-rate 5;
};
zone "." {
@ -42,3 +41,24 @@ zone "example" {
// Check that named can handle a empty also-notify.
also-notify { /* empty */ };
};
zone x1 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x2 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x3 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x4 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x5 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x6 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x7 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x8 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x9 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x10 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x11 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x12 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x13 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x14 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x15 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x16 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x17 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x18 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x19 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };
zone x20 { type master; file "generic.db"; also-notify { 10.53.0.3; }; };

View File

@ -15,8 +15,6 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: tests.sh,v 1.36 2011/10/17 01:33:27 marka Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
@ -35,6 +33,8 @@ do
$DIG +tcp example @10.53.0.3 soa -p 5300 > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.* aa[ ;]" dig.out.ns3.test$n > /dev/null || ret=1
nr=`grep 'x[0-9].*sending notify to' ns2/named.run | wc -l`
[ $nr -eq 20 ] || ret=1
[ $ret = 0 ] && break
sleep 1
done
@ -55,6 +55,18 @@ $PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns3.test$n || ret=1
[ $ret = 0 ] || echo "I:failed"
status=`expr $ret + $status`
n=`expr $n + 1`
echo "I:checking startup notify rate limit ($n)"
ret=0
grep 'x[0-9].*sending notify to' ns2/named.run |
sed 's/.*:\([0-9][0-9]\)\..*/\1/' | uniq -c | awk '{print $1}' > log.out
# the notifies should span at least 4 seconds
wc -l log.out | awk '$1 < 4 { exit(1) }' || ret=1
# ... with no more than 5 in any one second
awk '$1 > 5 { exit(1) }' log.out || ret=1
[ $ret = 0 ] || echo "I:failed"
status=`expr $ret + $status`
echo "I:reloading with example2 using HUP and waiting 45 seconds"
sleep 1 # make sure filesystem time stamp is newer for reload.
rm -f ns2/example.db

View File

@ -4835,6 +4835,8 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> tcp-clients <replaceable>number</replaceable>; </optional>
<optional> reserved-sockets <replaceable>number</replaceable>; </optional>
<optional> recursive-clients <replaceable>number</replaceable>; </optional>
<optional> notify-rate <replaceable>number</replaceable>; </optional>
<optional> startup-notify-rate <replaceable>number</replaceable>; </optional>
<optional> serial-query-rate <replaceable>number</replaceable>; </optional>
<optional> serial-queries <replaceable>number</replaceable>; </optional>
<optional> tcp-listen-queue <replaceable>number</replaceable>; </optional>
@ -7783,6 +7785,31 @@ avoid-v6-udp-ports {};
</listitem>
</varlistentry>
<varlistentry>
<term><command>notify-rate</command></term>
<listitem>
<para>
The rate at which NOTIFY requests will be sent
during normal zone maintenance operations. (NOTIFY
requests due to initial zone loading are subject
to a separate rate limit; see below.) The default is
20 per second.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>startup-notify-rate</command></term>
<listitem>
<para>
The rate at which NOTIFY requests will be sent
when the name server is first starting up, or when
zones have been newly added to the nameserver.
The default is 20 per second.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>serial-query-rate</command></term>
<listitem>
@ -7795,14 +7822,7 @@ avoid-v6-udp-ports {};
rate at which queries are sent. The value of the
<command>serial-query-rate</command> option, an
integer, is the maximum number of queries sent
per second. The default is 20.
</para>
<para>
In addition to controlling the rate SOA refresh
queries are issued at
<command>serial-query-rate</command> also controls
the rate at which NOTIFY messages are sent from
both master and slave zones.
per second. The default is 20 per second.
</para>
</listitem>
</varlistentry>

View File

@ -1767,6 +1767,24 @@ dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr);
*\li 'zmgr' to be a valid zone manager.
*/
void
dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value);
/*%<
* Set the number of NOTIFY requests sent per second.
*
* Requires:
*\li 'zmgr' to be a valid zone manager
*/
void
dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value);
/*%<
* Set the number of startup NOTIFY requests sent per second.
*
* Requires:
*\li 'zmgr' to be a valid zone manager
*/
void
dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value);
/*%<
@ -1776,6 +1794,24 @@ dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value);
*\li 'zmgr' to be a valid zone manager
*/
unsigned int
dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr);
/*%<
* Return the number of NOTIFY requests sent per second.
*
* Requires:
*\li 'zmgr' to be a valid zone manager.
*/
unsigned int
dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr);
/*%<
* Return the number of startup NOTIFY requests sent per second.
*
* Requires:
*\li 'zmgr' to be a valid zone manager.
*/
unsigned int
dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr);
/*%<

View File

@ -1064,15 +1064,19 @@ dns_zonemgr_detach
dns_zonemgr_forcemaint
dns_zonemgr_getcount
dns_zonemgr_getiolimit
dns_zonemgr_getnotifyrate
dns_zonemgr_getserialqueryrate
dns_zonemgr_getstartupnotifyrate
dns_zonemgr_getttransfersin
dns_zonemgr_getttransfersperns
dns_zonemgr_managezone
dns_zonemgr_releasezone
dns_zonemgr_resumexfrs
dns_zonemgr_setiolimit
dns_zonemgr_setnotifyrate
dns_zonemgr_setserialqueryrate
dns_zonemgr_setsize
dns_zonemgr_setstartupnotifyrate
dns_zonemgr_settransfersin
dns_zonemgr_settransfersperns
dns_zonemgr_shutdown

View File

@ -476,6 +476,10 @@ typedef struct {
#define DNS_ZONEFLG_LOADPENDING 0x10000000U /*%< Loading scheduled */
#define DNS_ZONEFLG_NODELAY 0x20000000U
#define DNS_ZONEFLG_SENDSECURE 0x40000000U
#define DNS_ZONEFLG_NEEDSTARTUPNOTIFY 0x80000000U /*%< need to send out notify
* due to the zone just
* being loaded for the
* first time. */
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
#define DNS_ZONE_OPTION2(z,o) (((z)->options2 & (o)) != 0)
@ -515,6 +519,8 @@ struct dns_zonemgr {
isc_pool_t * mctxpool;
isc_ratelimiter_t * notifyrl;
isc_ratelimiter_t * refreshrl;
isc_ratelimiter_t * startupnotifyrl;
isc_ratelimiter_t * startuprefreshrl;
isc_rwlock_t rwlock;
isc_mutex_t iolock;
isc_rwlock_t urlock;
@ -527,7 +533,10 @@ struct dns_zonemgr {
/* Configuration data. */
isc_uint32_t transfersin;
isc_uint32_t transfersperns;
unsigned int notifyrate;
unsigned int startupnotifyrate;
unsigned int serialqueryrate;
unsigned int startupserialqueryrate;
/* Locked by iolock */
isc_uint32_t iolimit;
@ -555,9 +564,11 @@ struct dns_notify {
dns_tsigkey_t *key;
isc_dscp_t dscp;
ISC_LINK(dns_notify_t) link;
isc_event_t *event;
};
#define DNS_NOTIFY_NOSOA 0x0001U
#define DNS_NOTIFY_STARTUP 0x0002U
/*%
* dns_stub holds state while performing a 'stub' transfer.
@ -785,6 +796,8 @@ static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver,
dns_diff_t *diff);
static void zone_rekey(dns_zone_t *zone);
static isc_result_t zone_send_securedb(dns_zone_t *zone, dns_db_t *db);
static void setrl(isc_ratelimiter_t *rl, unsigned int *rate,
unsigned int value);
#define ENTER zone_debuglog(zone, me, 1, "enter")
@ -4480,7 +4493,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
zone_attachdb(zone, db);
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
DNS_ZONE_SETFLAG(zone,
DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
DNS_ZONEFLG_LOADED|
DNS_ZONEFLG_NEEDSTARTUPNOTIFY);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SENDSECURE) &&
inline_raw(zone))
{
@ -9330,7 +9344,8 @@ zone_maintenance(dns_zone_t *zone) {
* Slaves send notifies before backing up to disk, masters after.
*/
if (zone->type == dns_zone_slave &&
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
(DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY)) &&
isc_time_compare(&now, &zone->notifytime) >= 0)
zone_notify(zone, &now);
@ -9370,7 +9385,8 @@ zone_maintenance(dns_zone_t *zone) {
switch (zone->type) {
case dns_zone_master:
case dns_zone_redirect:
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
if ((DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY))&&
isc_time_compare(&now, &zone->notifytime) >= 0)
zone_notify(zone, &now);
default:
@ -9999,21 +10015,50 @@ dns_zone_setmaxretrytime(dns_zone_t *zone, isc_uint32_t val) {
}
static isc_boolean_t
notify_isqueued(dns_zone_t *zone, dns_name_t *name, isc_sockaddr_t *addr) {
notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name,
isc_sockaddr_t *addr)
{
dns_notify_t *notify;
dns_zonemgr_t *zmgr;
isc_result_t result;
for (notify = ISC_LIST_HEAD(zone->notifies);
notify != NULL;
notify = ISC_LIST_NEXT(notify, link)) {
if (notify->request != NULL)
continue;
if ((flags & DNS_NOTIFY_STARTUP) == 0)
notify->flags &= ~DNS_NOTIFY_STARTUP;
if (name != NULL && dns_name_dynamic(&notify->ns) &&
dns_name_equal(name, &notify->ns))
return (ISC_TRUE);
goto requeue;
if (addr != NULL && isc_sockaddr_equal(addr, &notify->dst))
return (ISC_TRUE);
goto requeue;
}
return (ISC_FALSE);
requeue:
/*
* If we are enqueued on the startup ratelimiter and this is
* not a startup notify, re-enqueue on the normal notify
* ratelimiter.
*/
if (notify->event != NULL && (flags & DNS_NOTIFY_STARTUP) == 0) {
zmgr = notify->zone->zmgr;
result = isc_ratelimiter_dequeue(zmgr->startupnotifyrl,
notify->event);
if (result != ISC_R_SUCCESS)
return (ISC_TRUE);
result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl,
notify->zone->task,
&notify->event);
if (result != ISC_R_SUCCESS) {
isc_event_free(&notify->event);
return (ISC_FALSE);
}
}
return (ISC_TRUE);
}
static isc_boolean_t
@ -10111,6 +10156,7 @@ notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) {
notify->find = NULL;
notify->request = NULL;
notify->key = NULL;
notify->event = NULL;
isc_sockaddr_any(&notify->dst);
dns_name_init(&notify->ns, NULL);
ISC_LINK_INIT(notify, link);
@ -10186,22 +10232,27 @@ notify_find_address(dns_notify_t *notify) {
static isc_result_t
notify_send_queue(dns_notify_t *notify) {
notify_send_queue(dns_notify_t *notify, isc_boolean_t startup) {
isc_event_t *e;
isc_result_t result;
e = isc_event_allocate(notify->mctx, NULL,
DNS_EVENT_NOTIFYSENDTOADDR,
notify_send_toaddr,
notify, sizeof(isc_event_t));
INSIST(notify->event == NULL);
e = isc_event_allocate(notify->mctx, NULL, DNS_EVENT_NOTIFYSENDTOADDR,
notify_send_toaddr, notify, sizeof(isc_event_t));
if (e == NULL)
return (ISC_R_NOMEMORY);
if (startup)
notify->event = e;
e->ev_arg = notify;
e->ev_sender = NULL;
result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl,
result = isc_ratelimiter_enqueue(startup
? notify->zone->zmgr->startupnotifyrl
: notify->zone->zmgr->notifyrl,
notify->zone->task, &e);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
isc_event_free(&e);
notify->event = NULL;
}
return (result);
}
@ -10226,6 +10277,8 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
LOCK_ZONE(notify->zone);
notify->event = NULL;
if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0) {
result = ISC_R_CANCELED;
goto cleanup;
@ -10342,6 +10395,8 @@ notify_send(dns_notify_t *notify) {
isc_sockaddr_t dst;
isc_result_t result;
dns_notify_t *new = NULL;
unsigned int flags;
isc_boolean_t startup;
/*
* Zone lock held by caller.
@ -10353,20 +10408,20 @@ notify_send(dns_notify_t *notify) {
ai != NULL;
ai = ISC_LIST_NEXT(ai, publink)) {
dst = ai->sockaddr;
if (notify_isqueued(notify->zone, NULL, &dst))
if (notify_isqueued(notify->zone, notify->flags, NULL, &dst))
continue;
if (notify_isself(notify->zone, &dst))
continue;
new = NULL;
result = notify_create(notify->mctx,
(notify->flags & DNS_NOTIFY_NOSOA),
&new);
flags = notify->flags & DNS_NOTIFY_NOSOA;
result = notify_create(notify->mctx, flags, &new);
if (result != ISC_R_SUCCESS)
goto cleanup;
zone_iattach(notify->zone, &new->zone);
ISC_LIST_APPEND(new->zone->notifies, new, link);
new->dst = dst;
result = notify_send_queue(new);
startup = ISC_TF((notify->flags & DNS_NOTIFY_STARTUP) != 0);
result = notify_send_queue(new, startup);
if (result != ISC_R_SUCCESS)
goto cleanup;
new = NULL;
@ -10412,11 +10467,14 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) {
dns_notifytype_t notifytype;
unsigned int flags = 0;
isc_boolean_t loggednotify = ISC_FALSE;
isc_boolean_t startup;
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
startup = !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY);
notifytype = zone->notifytype;
DNS_ZONE_TIME_ADD(now, zone->notifydelay, &zone->notifytime);
UNLOCK_ZONE(zone);
@ -10440,6 +10498,12 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) {
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY))
flags |= DNS_NOTIFY_NOSOA;
/*
* Record that this was a notify due to starting up.
*/
if (startup)
flags |= DNS_NOTIFY_STARTUP;
/*
* Get SOA RRset.
*/
@ -10485,7 +10549,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) {
dns_tsigkey_t *key = NULL;
dst = zone->notify[i];
if (notify_isqueued(zone, NULL, &dst))
if (notify_isqueued(zone, flags, NULL, &dst))
continue;
result = notify_create(zone->mctx, flags, &notify);
@ -10507,7 +10571,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) {
}
ISC_LIST_APPEND(zone->notifies, notify, link);
result = notify_send_queue(notify);
result = notify_send_queue(notify, startup);
if (result != ISC_R_SUCCESS)
notify_destroy(notify, ISC_TRUE);
if (!loggednotify) {
@ -10557,7 +10621,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) {
}
LOCK_ZONE(zone);
isqueued = notify_isqueued(zone, &ns.name, NULL);
isqueued = notify_isqueued(zone, flags, &ns.name, NULL);
UNLOCK_ZONE(zone);
if (isqueued) {
result = dns_rdataset_next(&nsrdset);
@ -12127,7 +12191,8 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) {
/* FALLTHROUGH */
case dns_zone_master:
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY))
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY))
next = zone->notifytime;
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) {
@ -13202,9 +13267,12 @@ notify_done(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
if (message != NULL && message->rcode == dns_rcode_formerr &&
(notify->flags & DNS_NOTIFY_NOSOA) == 0) {
isc_boolean_t startup;
notify->flags |= DNS_NOTIFY_NOSOA;
dns_request_destroy(&notify->request);
result = notify_send_queue(notify);
startup = ISC_TF((notify->flags & DNS_NOTIFY_STARTUP) != 0);
result = notify_send_queue(notify, startup);
if (result != ISC_R_SUCCESS)
notify_destroy(notify, ISC_FALSE);
} else {
@ -15136,7 +15204,6 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
{
dns_zonemgr_t *zmgr;
isc_result_t result;
isc_interval_t interval;
zmgr = isc_mem_get(mctx, sizeof(*zmgr));
if (zmgr == NULL)
@ -15153,6 +15220,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
zmgr->task = NULL;
zmgr->notifyrl = NULL;
zmgr->refreshrl = NULL;
zmgr->startupnotifyrl = NULL;
zmgr->startuprefreshrl = NULL;
ISC_LIST_INIT(zmgr->zones);
ISC_LIST_INIT(zmgr->waiting_for_xfrin);
ISC_LIST_INIT(zmgr->xfrin_in_progress);
@ -15185,15 +15254,21 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
if (result != ISC_R_SUCCESS)
goto free_notifyrl;
/* default to 20 refresh queries / notifies per second. */
isc_interval_set(&interval, 0, 1000000000/2);
result = isc_ratelimiter_setinterval(zmgr->notifyrl, &interval);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_ratelimiter_setpertic(zmgr->notifyrl, 10);
result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
&zmgr->startupnotifyrl);
if (result != ISC_R_SUCCESS)
goto free_refreshrl;
result = isc_ratelimiter_setinterval(zmgr->refreshrl, &interval);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_ratelimiter_setpertic(zmgr->refreshrl, 10);
result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
&zmgr->startuprefreshrl);
if (result != ISC_R_SUCCESS)
goto free_startupnotifyrl;
/* default to 20 refresh queries / notifies per second. */
setrl(zmgr->notifyrl, &zmgr->notifyrate, 20);
setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, 20);
setrl(zmgr->refreshrl, &zmgr->serialqueryrate, 20);
setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, 20);
zmgr->iolimit = 1;
zmgr->ioactive = 0;
@ -15202,7 +15277,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
result = isc_mutex_init(&zmgr->iolock);
if (result != ISC_R_SUCCESS)
goto free_refreshrl;
goto free_startuprefreshrl;
zmgr->magic = ZONEMGR_MAGIC;
@ -15213,6 +15288,10 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
free_iolock:
DESTROYLOCK(&zmgr->iolock);
#endif
free_startuprefreshrl:
isc_ratelimiter_detach(&zmgr->startuprefreshrl);
free_startupnotifyrl:
isc_ratelimiter_detach(&zmgr->startupnotifyrl);
free_refreshrl:
isc_ratelimiter_detach(&zmgr->refreshrl);
free_notifyrl:
@ -15416,6 +15495,8 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
isc_ratelimiter_shutdown(zmgr->notifyrl);
isc_ratelimiter_shutdown(zmgr->refreshrl);
isc_ratelimiter_shutdown(zmgr->startupnotifyrl);
isc_ratelimiter_shutdown(zmgr->startuprefreshrl);
if (zmgr->task != NULL)
isc_task_destroy(&zmgr->task);
@ -15547,6 +15628,8 @@ zonemgr_free(dns_zonemgr_t *zmgr) {
DESTROYLOCK(&zmgr->iolock);
isc_ratelimiter_detach(&zmgr->notifyrl);
isc_ratelimiter_detach(&zmgr->refreshrl);
isc_ratelimiter_detach(&zmgr->startupnotifyrl);
isc_ratelimiter_detach(&zmgr->startuprefreshrl);
isc_rwlock_destroy(&zmgr->urlock);
isc_rwlock_destroy(&zmgr->rwlock);
@ -15909,15 +15992,13 @@ dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event) {
}
#endif
void
dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) {
static void
setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value) {
isc_interval_t interval;
isc_uint32_t s, ns;
isc_uint32_t pertic;
isc_result_t result;
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
if (value == 0)
value = 1;
@ -15937,15 +16018,51 @@ dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) {
isc_interval_set(&interval, s, ns);
result = isc_ratelimiter_setinterval(zmgr->notifyrl, &interval);
result = isc_ratelimiter_setinterval(rl, &interval);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_ratelimiter_setpertic(zmgr->notifyrl, pertic);
isc_ratelimiter_setpertic(rl, pertic);
result = isc_ratelimiter_setinterval(zmgr->refreshrl, &interval);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_ratelimiter_setpertic(zmgr->refreshrl, pertic);
*rate = value;
}
zmgr->serialqueryrate = value;
void
dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) {
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
setrl(zmgr->notifyrl, &zmgr->notifyrate, value);
}
void
dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) {
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, value);
}
void
dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) {
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
setrl(zmgr->refreshrl, &zmgr->serialqueryrate, value);
/* XXXMPA seperate out once we have the code to support this. */
setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, value);
}
unsigned int
dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr) {
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
return (zmgr->notifyrate);
}
unsigned int
dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr) {
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
return (zmgr->startupnotifyrate);
}
unsigned int

View File

@ -89,6 +89,16 @@ isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
*\li '(*eventp)->ev_sender' to be NULL.
*/
isc_result_t
isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event);
/*
* Dequeue a event off the ratelimiter queue.
*
* Returns:
* \li ISC_R_NOTFOUND if the event is no longer linked to the rate limiter.
* \li ISC_R_SUCCESS
*/
void
isc_ratelimiter_shutdown(isc_ratelimiter_t *ratelimiter);
/*%<

View File

@ -79,6 +79,7 @@ isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
result = isc_mutex_init(&rl->lock);
if (result != ISC_R_SUCCESS)
goto free_mem;
result = isc_timer_create(timermgr, isc_timertype_inactive,
NULL, NULL, rl->task, ratelimiter_tick,
rl, &rl->timer);
@ -109,6 +110,10 @@ free_mem:
isc_result_t
isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(rl != NULL);
REQUIRE(interval != NULL);
LOCK(&rl->lock);
rl->interval = *interval;
/*
@ -124,6 +129,9 @@ isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) {
void
isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t pertic) {
REQUIRE(rl != NULL);
if (pertic == 0)
pertic = 1;
rl->pertic = pertic;
@ -136,8 +144,9 @@ isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
isc_result_t result = ISC_R_SUCCESS;
isc_event_t *ev;
REQUIRE(eventp != NULL && *eventp != NULL);
REQUIRE(rl != NULL);
REQUIRE(task != NULL);
REQUIRE(eventp != NULL && *eventp != NULL);
ev = *eventp;
REQUIRE(ev->ev_sender == NULL);
@ -165,6 +174,22 @@ isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
return (result);
}
isc_result_t
isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(rl != NULL);
REQUIRE(event != NULL);
LOCK(&rl->lock);
if (ISC_LINK_LINKED(event, ev_link))
ISC_LIST_UNLINK(rl->pending, event, ev_link);
else
result = ISC_R_NOTFOUND;
UNLOCK(&rl->lock);
return (result);
}
static void
ratelimiter_tick(isc_task_t *task, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS;
@ -211,6 +236,9 @@ void
isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
isc_event_t *ev;
isc_task_t *task;
REQUIRE(rl != NULL);
LOCK(&rl->lock);
rl->state = isc_ratelimiter_shuttingdown;
(void)isc_timer_reset(rl->timer, isc_timertype_inactive,
@ -222,6 +250,7 @@ isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
isc_task_send(task, &ev);
}
isc_timer_detach(&rl->timer);
/*
* Send an event to our task. The delivery of this event
* indicates that no more timer events will be delivered.
@ -249,6 +278,7 @@ ratelimiter_free(isc_ratelimiter_t *rl) {
void
isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target) {
REQUIRE(source != NULL);
REQUIRE(target != NULL && *target == NULL);
@ -262,9 +292,13 @@ isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target) {
void
isc_ratelimiter_detach(isc_ratelimiter_t **rlp) {
isc_ratelimiter_t *rl = *rlp;
isc_ratelimiter_t *rl;
isc_boolean_t free_now = ISC_FALSE;
REQUIRE(rlp != NULL && *rlp != NULL);
rl = *rlp;
LOCK(&rl->lock);
REQUIRE(rl->refs > 0);
rl->refs--;
@ -282,6 +316,8 @@ isc_result_t
isc_ratelimiter_stall(isc_ratelimiter_t *rl) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(rl != NULL);
LOCK(&rl->lock);
switch (rl->state) {
case isc_ratelimiter_shuttingdown:
@ -305,6 +341,8 @@ isc_result_t
isc_ratelimiter_release(isc_ratelimiter_t *rl) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(rl != NULL);
LOCK(&rl->lock);
switch (rl->state) {
case isc_ratelimiter_shuttingdown:

View File

@ -476,6 +476,7 @@ isc_random_jitter
isc_random_seed
isc_ratelimiter_attach
isc_ratelimiter_create
isc_ratelimiter_dequeue
isc_ratelimiter_detach
isc_ratelimiter_enqueue
isc_ratelimiter_setinterval

View File

@ -977,6 +977,7 @@ options_clauses[] = {
{ "memstatistics", &cfg_type_boolean, 0 },
{ "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
{ "notify-rate", &cfg_type_uint32, 0 },
{ "pid-file", &cfg_type_qstringornone, 0 },
{ "port", &cfg_type_uint32, 0 },
{ "querylog", &cfg_type_boolean, 0 },
@ -989,6 +990,7 @@ options_clauses[] = {
{ "serial-query-rate", &cfg_type_uint32, 0 },
{ "server-id", &cfg_type_serverid, 0 },
{ "stacksize", &cfg_type_size, 0 },
{ "startup-notify-rate", &cfg_type_uint32, 0 },
{ "statistics-file", &cfg_type_qstring, 0 },
{ "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
{ "tcp-clients", &cfg_type_uint32, 0 },