[nsd-users] Patch: {max,min}-{refresh,retry}-time
YAMAGUCHI Takanori
t-yama at iij.ad.jp
Thu Jun 16 08:29:27 UTC 2016
Hi,
I wrote a patch to limit too long or too short SOA refresh and retry parameters.
This allows the slave server to override the definition of SOA RR.
Changes are welcome.
Regards.
-------------- next part --------------
diff --git a/configlexer.lex b/configlexer.lex
index 113fa22..03903de 100644
--- a/configlexer.lex
+++ b/configlexer.lex
@@ -268,6 +268,10 @@ zonefiles-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_CHECK;
zonefiles-write{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_WRITE;}
log-time-ascii{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ASCII;}
round-robin{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ROUND_ROBIN;}
+max-refresh-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_REFRESH_TIME;}
+min-refresh-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_REFRESH_TIME;}
+max-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;}
+min-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;}
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
/* Quoted strings. Strip leading and ending quotes */
diff --git a/configparser.y b/configparser.y
index 7ebf782..e0f9c15 100644
--- a/configparser.y
+++ b/configparser.y
@@ -69,6 +69,8 @@ extern config_parser_state_t* cfg_parser;
%token VAR_RRL_WHITELIST_RATELIMIT VAR_RRL_WHITELIST
%token VAR_ZONEFILES_CHECK VAR_ZONEFILES_WRITE VAR_LOG_TIME_ASCII
%token VAR_ROUND_ROBIN VAR_ZONESTATS VAR_REUSEPORT VAR_VERSION
+%token VAR_MAX_REFRESH_TIME VAR_MIN_REFRESH_TIME
+%token VAR_MAX_RETRY_TIME VAR_MIN_RETRY_TIME
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -598,7 +600,8 @@ content_pattern: pattern_name | zone_config_item;
zone_config_item: zone_zonefile | zone_allow_notify | zone_request_xfr |
zone_notify | zone_notify_retry | zone_provide_xfr |
zone_outgoing_interface | zone_allow_axfr_fallback | include_pattern |
- zone_rrl_whitelist | zone_zonestats;
+ zone_rrl_whitelist | zone_zonestats | zone_max_refresh_time |
+ zone_min_refresh_time | zone_max_retry_time | zone_min_retry_time;
pattern_name: VAR_NAME STRING
{
OUTYY(("P(pattern_name:%s)\n", $2));
@@ -819,6 +822,46 @@ zone_rrl_whitelist: VAR_RRL_WHITELIST STRING
#endif
}
;
+zone_max_refresh_time: VAR_MAX_REFRESH_TIME STRING
+{
+ OUTYY(("P(zone_max_refresh_time:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->current_pattern->max_refresh_time = atoi($2);
+ cfg_parser->current_pattern->max_refresh_time_is_default = 0;
+ }
+};
+zone_min_refresh_time: VAR_MIN_REFRESH_TIME STRING
+{
+ OUTYY(("P(zone_min_refresh_time:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->current_pattern->min_refresh_time = atoi($2);
+ cfg_parser->current_pattern->min_refresh_time_is_default = 0;
+ }
+};
+zone_max_retry_time: VAR_MAX_RETRY_TIME STRING
+{
+ OUTYY(("P(zone_max_retry_time:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->current_pattern->max_retry_time = atoi($2);
+ cfg_parser->current_pattern->max_retry_time_is_default = 0;
+ }
+};
+zone_min_retry_time: VAR_MIN_RETRY_TIME STRING
+{
+ OUTYY(("P(zone_min_retry_time:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->current_pattern->min_retry_time = atoi($2);
+ cfg_parser->current_pattern->min_retry_time_is_default = 0;
+ }
+};
/* key: declaration */
keystart: VAR_KEY
diff --git a/nsd-checkconf.c b/nsd-checkconf.c
index e5f669f..9525c56 100644
--- a/nsd-checkconf.c
+++ b/nsd-checkconf.c
@@ -59,6 +59,12 @@ extern int optind;
return; \
}
+#define ZONE_GET_INT(NAME, VAR, PATTERN) \
+ if (strcasecmp(#NAME, (VAR)) == 0) { \
+ printf("%d\n", (int) PATTERN->NAME); \
+ return; \
+ }
+
#define SERV_GET_BIN(NAME, VAR) \
if (strcasecmp(#NAME, (VAR)) == 0) { \
printf("%s\n", opt->NAME?"yes":"no"); \
@@ -306,6 +312,10 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, const char *o,
ZONE_GET_STR(zonestats, o, zone->pattern);
ZONE_GET_OUTGOING(outgoing_interface, o, zone->pattern);
ZONE_GET_BIN(allow_axfr_fallback, o, zone->pattern);
+ ZONE_GET_INT(max_refresh_time, o, zone->pattern);
+ ZONE_GET_INT(min_refresh_time, o, zone->pattern);
+ ZONE_GET_INT(max_retry_time, o, zone->pattern);
+ ZONE_GET_INT(min_retry_time, o, zone->pattern);
#ifdef RATELIMIT
ZONE_GET_RRL(rrl_whitelist, o, zone->pattern);
#endif
@@ -331,6 +341,10 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, const char *o,
ZONE_GET_STR(zonestats, o, p);
ZONE_GET_OUTGOING(outgoing_interface, o, p);
ZONE_GET_BIN(allow_axfr_fallback, o, p);
+ ZONE_GET_INT(max_refresh_time, o, p);
+ ZONE_GET_INT(min_refresh_time, o, p);
+ ZONE_GET_INT(max_retry_time, o, p);
+ ZONE_GET_INT(min_retry_time, o, p);
#ifdef RATELIMIT
ZONE_GET_RRL(rrl_whitelist, o, p);
#endif
@@ -431,6 +445,14 @@ static void print_zone_content_elems(pattern_options_t* pat)
if(!pat->allow_axfr_fallback_is_default)
printf("\tallow-axfr-fallback: %s\n",
pat->allow_axfr_fallback?"yes":"no");
+ if(!pat->max_refresh_time_is_default)
+ printf("\tmax-refresh-time: %d\n", pat->max_refresh_time);
+ if(!pat->min_refresh_time_is_default)
+ printf("\tmin-refresh-time: %d\n", pat->min_refresh_time);
+ if(!pat->max_retry_time_is_default)
+ printf("\tmax-retry-time: %d\n", pat->max_retry_time);
+ if(!pat->min_retry_time_is_default)
+ printf("\tmin-retry-time: %d\n", pat->min_retry_time);
}
void
diff --git a/nsd.conf.sample.in b/nsd.conf.sample.in
index 48eef14..a55816e 100644
--- a/nsd.conf.sample.in
+++ b/nsd.conf.sample.in
@@ -258,6 +258,11 @@ remote-control:
# set local interface for sending zone transfer requests.
# default is let the OS choose.
#outgoing-interface: 10.0.0.10
+ # limit the refresh and retry interval in seconds.
+ #max-refresh-time: 2419200
+ #min-refresh-time: 300
+ #max-retry-time: 1209600
+ #min-retry-time: 500
# if compiled with --enable-zone-stats, give name of stat block for
# this zone (or group of zones). Output from nsd-control stats.
diff --git a/options.c b/options.c
index eabc8bf..e211af9 100644
--- a/options.c
+++ b/options.c
@@ -822,6 +822,14 @@ pattern_options_create(region_type* region)
p->allow_axfr_fallback_is_default = 1;
p->implicit = 0;
p->xfrd_flags = 0;
+ p->max_refresh_time = 2419200; /* 4 weeks */
+ p->max_refresh_time_is_default = 1;
+ p->min_refresh_time = 300;
+ p->min_refresh_time_is_default = 1;
+ p->max_retry_time = 1209600; /* 2 weeks */
+ p->max_retry_time_is_default = 1;
+ p->min_retry_time = 500;
+ p->min_retry_time_is_default = 1;
#ifdef RATELIMIT
p->rrl_whitelist = 0;
#endif
@@ -944,6 +952,14 @@ copy_pat_fixed(region_type* region, pattern_options_t* orig,
if(p->zonestats)
orig->zonestats = region_strdup(region, p->zonestats);
else orig->zonestats = NULL;
+ orig->max_refresh_time = p->max_refresh_time;
+ orig->max_refresh_time_is_default = p->max_refresh_time_is_default;
+ orig->min_refresh_time = p->min_refresh_time;
+ orig->min_refresh_time_is_default = p->min_refresh_time_is_default;
+ orig->max_retry_time = p->max_retry_time;
+ orig->max_retry_time_is_default = p->max_retry_time_is_default;
+ orig->min_retry_time = p->min_retry_time;
+ orig->min_retry_time_is_default = p->min_retry_time_is_default;
#ifdef RATELIMIT
orig->rrl_whitelist = p->rrl_whitelist;
#endif
@@ -1017,6 +1033,18 @@ pattern_options_equal(pattern_options_t* p, pattern_options_t* q)
if(!acl_list_equal(p->provide_xfr, q->provide_xfr)) return 0;
if(!acl_list_equal(p->outgoing_interface, q->outgoing_interface))
return 0;
+ if(p->max_refresh_time != q->max_refresh_time) return 0;
+ if(!booleq(p->max_refresh_time_is_default,
+ q->max_refresh_time_is_default)) return 0;
+ if(p->min_refresh_time != q->min_refresh_time) return 0;
+ if(!booleq(p->min_refresh_time_is_default,
+ q->min_refresh_time_is_default)) return 0;
+ if(p->max_retry_time != q->max_retry_time) return 0;
+ if(!booleq(p->max_retry_time_is_default,
+ q->max_retry_time_is_default)) return 0;
+ if(p->min_retry_time != q->min_retry_time) return 0;
+ if(!booleq(p->min_retry_time_is_default,
+ q->min_retry_time_is_default)) return 0;
#ifdef RATELIMIT
if(p->rrl_whitelist != q->rrl_whitelist) return 0;
#endif
@@ -1054,6 +1082,19 @@ unmarshal_u16(struct buffer* b)
#endif
static void
+marshal_u32(struct buffer* b, uint32_t v)
+{
+ buffer_reserve(b, 4);
+ buffer_write_u32(b, v);
+}
+
+static uint32_t
+unmarshal_u32(struct buffer* b)
+{
+ return buffer_read_u32(b);
+}
+
+static void
marshal_str(struct buffer* b, const char* s)
{
if(!s) marshal_u8(b, 0);
@@ -1143,6 +1184,14 @@ pattern_options_marshal(struct buffer* b, pattern_options_t* p)
marshal_acl_list(b, p->notify);
marshal_acl_list(b, p->provide_xfr);
marshal_acl_list(b, p->outgoing_interface);
+ marshal_u32(b, p->max_refresh_time);
+ marshal_u8(b, p->max_refresh_time_is_default);
+ marshal_u32(b, p->min_refresh_time);
+ marshal_u8(b, p->min_refresh_time_is_default);
+ marshal_u32(b, p->max_retry_time);
+ marshal_u8(b, p->max_retry_time_is_default);
+ marshal_u32(b, p->min_retry_time);
+ marshal_u8(b, p->min_retry_time_is_default);
}
pattern_options_t*
@@ -1165,6 +1214,14 @@ pattern_options_unmarshal(region_type* r, struct buffer* b)
p->notify = unmarshal_acl_list(r, b);
p->provide_xfr = unmarshal_acl_list(r, b);
p->outgoing_interface = unmarshal_acl_list(r, b);
+ p->max_refresh_time = unmarshal_u32(b);
+ p->max_refresh_time_is_default = unmarshal_u8(b);
+ p->min_refresh_time = unmarshal_u32(b);
+ p->min_refresh_time_is_default = unmarshal_u8(b);
+ p->max_retry_time = unmarshal_u32(b);
+ p->max_retry_time_is_default = unmarshal_u8(b);
+ p->min_retry_time = unmarshal_u32(b);
+ p->min_retry_time_is_default = unmarshal_u8(b);
return p;
}
@@ -1875,6 +1932,22 @@ config_apply_pattern(const char* name)
a->notify_retry = pat->notify_retry;
a->notify_retry_is_default = 0;
}
+ if(!pat->max_refresh_time_is_default) {
+ a->max_refresh_time = pat->max_refresh_time;
+ a->max_refresh_time_is_default = 0;
+ }
+ if(!pat->min_refresh_time_is_default) {
+ a->min_refresh_time = pat->min_refresh_time;
+ a->min_refresh_time_is_default = 0;
+ }
+ if(!pat->max_retry_time_is_default) {
+ a->max_retry_time = pat->max_retry_time;
+ a->max_retry_time_is_default = 0;
+ }
+ if(!pat->min_refresh_time_is_default) {
+ a->min_retry_time = pat->min_retry_time;
+ a->min_retry_time_is_default = 0;
+ }
#ifdef RATELIMIT
a->rrl_whitelist |= pat->rrl_whitelist;
#endif
diff --git a/options.h b/options.h
index ceba624..3f500ed 100644
--- a/options.h
+++ b/options.h
@@ -154,6 +154,14 @@ struct pattern_options {
uint8_t notify_retry_is_default;
uint8_t implicit; /* pattern is implicit, part_of_config zone used */
uint8_t xfrd_flags;
+ uint32_t max_refresh_time;
+ uint8_t max_refresh_time_is_default;
+ uint32_t min_refresh_time;
+ uint8_t min_refresh_time_is_default;
+ uint32_t max_retry_time;
+ uint8_t max_retry_time_is_default;
+ uint32_t min_retry_time;
+ uint8_t min_retry_time_is_default;
};
#define PATTERN_IMPLICIT_MARKER "_implicit_"
diff --git a/xfrd-disk.c b/xfrd-disk.c
index 3fa8630..b23a619 100644
--- a/xfrd-disk.c
+++ b/xfrd-disk.c
@@ -147,6 +147,7 @@ xfrd_read_state(struct xfrd_state* xfrd)
uint32_t filetime = 0;
uint32_t numzones, i;
region_type *tempregion;
+ time_t soa_refresh;
tempregion = region_create(xalloc, free);
if(!tempregion)
@@ -265,10 +266,15 @@ xfrd_read_state(struct xfrd_state* xfrd)
* or there is a notification,
* or there is a soa && current time is past refresh point
*/
+ soa_refresh = ntohl(soa_disk_read.refresh);
+ if (soa_refresh > zone->zone_options->pattern->max_refresh_time)
+ soa_refresh = zone->zone_options->pattern->max_refresh_time;
+ else if (soa_refresh < zone->zone_options->pattern->min_refresh_time)
+ soa_refresh = zone->zone_options->pattern->min_refresh_time;
if(timeout == 0 || soa_notified_acquired_read != 0 ||
(soa_disk_acquired_read != 0 &&
(uint32_t)xfrd_time() - soa_disk_acquired_read
- > ntohl(soa_disk_read.refresh)))
+ > soa_refresh))
{
zone->state = xfrd_zone_refreshing;
xfrd_set_refresh_now(zone);
diff --git a/xfrd.c b/xfrd.c
index c2c75ed..2a55421 100644
--- a/xfrd.c
+++ b/xfrd.c
@@ -702,7 +702,12 @@ xfrd_set_timer_refresh(xfrd_zone_t* zone)
return;
}
/* refresh or expire timeout, whichever is earlier */
- set_refresh = zone->soa_disk_acquired + ntohl(zone->soa_disk.refresh);
+ set_refresh = ntohl(zone->soa_disk.refresh);
+ if (set_refresh > zone->zone_options->pattern->max_refresh_time)
+ set_refresh = zone->zone_options->pattern->max_refresh_time;
+ else if (set_refresh < zone->zone_options->pattern->min_refresh_time)
+ set_refresh = zone->zone_options->pattern->min_refresh_time;
+ set_refresh += zone->soa_disk_acquired;
set_expire = zone->soa_disk_acquired + ntohl(zone->soa_disk.expire);
if(set_refresh < set_expire)
set = set_refresh;
@@ -719,6 +724,7 @@ xfrd_set_timer_refresh(xfrd_zone_t* zone)
static void
xfrd_set_timer_retry(xfrd_zone_t* zone)
{
+ time_t set_retry;
/* set timer for next retry or expire timeout if earlier. */
if(zone->soa_disk_acquired == 0) {
/* if no information, use reasonable timeout */
@@ -743,10 +749,14 @@ xfrd_set_timer_retry(xfrd_zone_t* zone)
xfrd_time() + (time_t)ntohl(zone->soa_disk.retry) <
zone->soa_disk_acquired + (time_t)ntohl(zone->soa_disk.expire))
{
- if(ntohl(zone->soa_disk.retry) < XFRD_LOWERBOUND_RETRY)
- xfrd_set_timer(zone, XFRD_LOWERBOUND_RETRY);
- else
- xfrd_set_timer(zone, ntohl(zone->soa_disk.retry));
+ set_retry = ntohl(zone->soa_disk.retry);
+ if(set_retry > zone->zone_options->pattern->max_retry_time)
+ set_retry = zone->zone_options->pattern->max_retry_time;
+ else if(set_retry < zone->zone_options->pattern->min_retry_time)
+ set_retry = zone->zone_options->pattern->min_retry_time;
+ if(set_retry < XFRD_LOWERBOUND_RETRY)
+ set_retry = XFRD_LOWERBOUND_RETRY;
+ xfrd_set_timer(zone, set_retry);
} else {
if(ntohl(zone->soa_disk.expire) < XFRD_LOWERBOUND_RETRY)
xfrd_set_timer(zone, XFRD_LOWERBOUND_RETRY);
More information about the nsd-users
mailing list