Commit 10c12aa5 authored by Mark Andrews's avatar Mark Andrews
Browse files

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]
parent 4b92bc00
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]
......
......@@ -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.
......
......@@ -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\
......
......@@ -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);
......
......@@ -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
; 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
......@@ -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; }; };
......@@ -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
......
......@@ -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>
......
......@@ -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);
/*%<
......
......@@ -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
......
......@@ -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;