diff options
author | 2016-08-31 07:31:20 +0000 | |
---|---|---|
committer | 2016-08-31 07:31:20 +0000 | |
commit | 6e9bf1eef5ed2e2ddaa89cc4905b1caacf750aff (patch) | |
tree | 305efd4e64a1f833aecf6934a6cdd1e0e9f3f3b8 | |
parent | Delete unused ioctls and associated macros. Move macros that are still (diff) | |
download | wireguard-openbsd-6e9bf1eef5ed2e2ddaa89cc4905b1caacf750aff.tar.xz wireguard-openbsd-6e9bf1eef5ed2e2ddaa89cc4905b1caacf750aff.zip |
update to 4.1.11
"Working fine here." millert@
OK dlg, sthen
-rw-r--r-- | usr.sbin/nsd/buffer.h | 29 | ||||
-rw-r--r-- | usr.sbin/nsd/configlexer.lex | 5 | ||||
-rw-r--r-- | usr.sbin/nsd/configparser.y | 56 | ||||
-rw-r--r-- | usr.sbin/nsd/configure.ac | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/ipc.c | 5 | ||||
-rw-r--r-- | usr.sbin/nsd/namedb.c | 6 | ||||
-rw-r--r-- | usr.sbin/nsd/namedb.h | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-checkconf.c | 34 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.conf.5.in | 20 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.conf.sample.in | 9 | ||||
-rw-r--r-- | usr.sbin/nsd/nsec3.c | 4 | ||||
-rw-r--r-- | usr.sbin/nsd/options.c | 91 | ||||
-rw-r--r-- | usr.sbin/nsd/options.h | 9 | ||||
-rw-r--r-- | usr.sbin/nsd/query.c | 7 | ||||
-rw-r--r-- | usr.sbin/nsd/server.c | 26 | ||||
-rw-r--r-- | usr.sbin/nsd/util.h | 29 | ||||
-rw-r--r-- | usr.sbin/nsd/xfrd-disk.c | 22 | ||||
-rw-r--r-- | usr.sbin/nsd/xfrd-disk.h | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/xfrd.c | 30 | ||||
-rw-r--r-- | usr.sbin/nsd/zonec.c | 11 |
20 files changed, 373 insertions, 26 deletions
diff --git a/usr.sbin/nsd/buffer.h b/usr.sbin/nsd/buffer.h index bee7d8b29eb..9e17bc95844 100644 --- a/usr.sbin/nsd/buffer.h +++ b/usr.sbin/nsd/buffer.h @@ -315,6 +315,20 @@ buffer_write_u32(buffer_type *buffer, uint32_t data) } static inline void +buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) +{ + assert(buffer_available_at(buffer, at, sizeof(data))); + write_uint64(buffer->_data + at, data); +} + +static inline void +buffer_write_u64(buffer_type *buffer, uint64_t data) +{ + buffer_write_u64_at(buffer, buffer->_position, data); + buffer->_position += sizeof(data); +} + +static inline void buffer_read_at(buffer_type *buffer, size_t at, void *data, size_t count) { assert(buffer_available_at(buffer, at, count)); @@ -373,6 +387,21 @@ buffer_read_u32(buffer_type *buffer) return result; } +static inline uint64_t +buffer_read_u64_at(buffer_type *buffer, size_t at) +{ + assert(buffer_available_at(buffer, at, sizeof(uint64_t))); + return read_uint64(buffer->_data + at); +} + +static inline uint64_t +buffer_read_u64(buffer_type *buffer) +{ + uint64_t result = buffer_read_u64_at(buffer, buffer->_position); + buffer->_position += sizeof(uint64_t); + return result; +} + /* * Print to the buffer, increasing the capacity if required using * buffer_reserve(). The buffer's position is set to the terminating diff --git a/usr.sbin/nsd/configlexer.lex b/usr.sbin/nsd/configlexer.lex index 113fa2284c1..d53635298b1 100644 --- a/usr.sbin/nsd/configlexer.lex +++ b/usr.sbin/nsd/configlexer.lex @@ -236,6 +236,7 @@ zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONE;} zonefile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILE;} zonestats{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESTATS;} allow-notify{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_NOTIFY;} +size-limit-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SIZE_LIMIT_XFR;} request-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REQUEST_XFR;} notify{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY;} notify-retry{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY_RETRY;} @@ -268,6 +269,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/usr.sbin/nsd/configparser.y b/usr.sbin/nsd/configparser.y index 1d824d10b05..908966588f6 100644 --- a/usr.sbin/nsd/configparser.y +++ b/usr.sbin/nsd/configparser.y @@ -54,7 +54,7 @@ extern config_parser_state_t* cfg_parser; %token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS VAR_IP_FREEBIND %token VAR_ZONEFILE %token VAR_ZONE -%token VAR_ALLOW_NOTIFY VAR_REQUEST_XFR VAR_NOTIFY VAR_PROVIDE_XFR +%token VAR_ALLOW_NOTIFY VAR_REQUEST_XFR VAR_NOTIFY VAR_PROVIDE_XFR VAR_SIZE_LIMIT_XFR %token VAR_NOTIFY_RETRY VAR_OUTGOING_INTERFACE VAR_ALLOW_AXFR_FALLBACK %token VAR_KEY %token VAR_ALGORITHM VAR_SECRET @@ -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,9 @@ 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 | + zone_size_limit_xfr; pattern_name: VAR_NAME STRING { OUTYY(("P(pattern_name:%s)\n", $2)); @@ -714,6 +718,14 @@ zone_request_xfr: VAR_REQUEST_XFR zone_request_xfr_data { } ; +zone_size_limit_xfr: VAR_SIZE_LIMIT_XFR STRING + { + OUTYY(("P(size_limit_xfr:%s)\n", $2)); + if(atoll($2) < 0) + yyerror("number >= 0 expected"); + else cfg_parser->current_pattern->size_limit_xfr = atoll($2); + } + ; zone_request_xfr_data: STRING STRING { acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $1, $2); @@ -819,6 +831,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/usr.sbin/nsd/configure.ac b/usr.sbin/nsd/configure.ac index 4c451bd01b3..da75edc073c 100644 --- a/usr.sbin/nsd/configure.ac +++ b/usr.sbin/nsd/configure.ac @@ -4,7 +4,7 @@ dnl sinclude(acx_nlnetlabs.m4) -AC_INIT(NSD,4.1.10,nsd-bugs@nlnetlabs.nl) +AC_INIT(NSD,4.1.11,nsd-bugs@nlnetlabs.nl) AC_CONFIG_HEADER([config.h]) CFLAGS="$CFLAGS" diff --git a/usr.sbin/nsd/ipc.c b/usr.sbin/nsd/ipc.c index 1f188e54951..8b5cba4bb88 100644 --- a/usr.sbin/nsd/ipc.c +++ b/usr.sbin/nsd/ipc.c @@ -82,7 +82,10 @@ child_handle_parent_command(int fd, short event, void* arg) server_close_all_sockets(data->nsd->udp, data->nsd->ifs); server_close_all_sockets(data->nsd->tcp, data->nsd->ifs); /* mode == NSD_QUIT_CHILD */ - (void)write(fd, &mode, sizeof(mode)); + if(write(fd, &mode, sizeof(mode)) == -1) { + VERBOSITY(3, (LOG_INFO, "quit child write: %s", + strerror(errno))); + } ipc_child_quit(data->nsd); break; case NSD_QUIT_WITH_STATS: diff --git a/usr.sbin/nsd/namedb.c b/usr.sbin/nsd/namedb.c index db90965c2d3..dbe8efd89ad 100644 --- a/usr.sbin/nsd/namedb.c +++ b/usr.sbin/nsd/namedb.c @@ -533,7 +533,7 @@ domain_find_zone(namedb_type* db, domain_type* domain) } zone_type * -domain_find_parent_zone(zone_type* zone) +domain_find_parent_zone(namedb_type* db, zone_type* zone) { rrset_type* rrset; @@ -544,6 +544,10 @@ domain_find_parent_zone(zone_type* zone) return rrset->zone; } } + /* the NS record in the parent zone above this zone is not present, + * workaround to find that parent zone anyway */ + if(zone->apex->parent) + return domain_find_zone(db, zone->apex->parent); return NULL; } diff --git a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h index ca46477ae20..e5cf36c0159 100644 --- a/usr.sbin/nsd/namedb.h +++ b/usr.sbin/nsd/namedb.h @@ -232,7 +232,7 @@ rrset_type* domain_find_rrset(domain_type* domain, zone_type* zone, uint16_t typ rrset_type* domain_find_any_rrset(domain_type* domain, zone_type* zone); zone_type* domain_find_zone(namedb_type* db, domain_type* domain); -zone_type* domain_find_parent_zone(zone_type* zone); +zone_type* domain_find_parent_zone(namedb_type* db, zone_type* zone); domain_type* domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns); /* find DNAME rrset in domain->parent or higher and return that domain */ diff --git a/usr.sbin/nsd/nsd-checkconf.c b/usr.sbin/nsd/nsd-checkconf.c index e5f669f967b..b7afdd1b916 100644 --- a/usr.sbin/nsd/nsd-checkconf.c +++ b/usr.sbin/nsd/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,11 @@ 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); + ZONE_GET_INT(size_limit_xfr, o, zone->pattern); #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, zone->pattern); #endif @@ -331,6 +342,11 @@ 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); + ZONE_GET_INT(size_limit_xfr, o, p); #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, p); #endif @@ -431,6 +447,17 @@ 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); + if(pat->size_limit_xfr != 0) + printf("\tsize-limit-xfr: %llu\n", + (long long unsigned)pat->size_limit_xfr); } void @@ -559,6 +586,13 @@ additional_checks(nsd_options_t* opt, const char* filename) fprintf(stderr, "%s: cannot parse zone name syntax for zone %s.\n", filename, zone->name); errors ++; } +#ifndef ROOT_SERVER + /* Is it a root zone? Are we a root server then? Idiot proof. */ + if(dname->label_count == 1) { + fprintf(stderr, "%s: not configured as a root server.\n", filename); + errors ++; + } +#endif if(zone->pattern->allow_notify && !zone->pattern->request_xfr) { fprintf(stderr, "%s: zone %s has allow-notify but no request-xfr" " items. Where can it get a zone transfer when a notify " diff --git a/usr.sbin/nsd/nsd.conf.5.in b/usr.sbin/nsd/nsd.conf.5.in index 44493c722cd..bcec054af2c 100644 --- a/usr.sbin/nsd/nsd.conf.5.in +++ b/usr.sbin/nsd/nsd.conf.5.in @@ -583,6 +583,10 @@ transmitted using TCP. This option should be accompanied by request\-xfr. It (dis)allows NSD (as secondary) to fallback to AXFR if the primary name server does not support IXFR. Default is yes. .TP +.B size\-limit\-xfr:\fR <number> +This option should be accompanied by request\-xfr. It specifies XFR temporary file size limit. It can be used to stop very large zone retrieval, that could otherwise use up a lot of memory and disk space. +If this option is 0, unlimited. Default value is 0. +.TP .B notify:\fR <ip\-address> <key\-name | NOKEY> Access control list. The listed address (a secondary) is notified of updates to this zone. A port number can be added using a suffix of @number, @@ -624,6 +628,22 @@ A port number can be added using a suffix of @number, for example 1.2.3.4@5300. .RE .TP +.B max\-refresh\-time:\fR <seconds> +Limit refresh time for secondary zones. This is the timer which checks to see +if the zone has to be refetched when it expires. Normally the value from the +SOA record is used, but this option restricts that value. +.TP +.B min\-refresh\-time:\fR <seconds> +Limit refresh time for secondary zones. +.TP +.B max\-retry\-time:\fR <seconds> +Limit retry time for secondary zones. This is the timeout after a failed +fetch attempt for the zone. Normally the value from the SOA record is used, +but this option restricts that value. +.TP +.B min\-retry\-time:\fR <seconds> +Limit retry time for secondary zones. +.TP .B zonestats:\fR <name> When compiled with \-\-enable\-zone\-stats NSD can collect statistics per zone. This name gives the group where statistics are added to. The groups are diff --git a/usr.sbin/nsd/nsd.conf.sample.in b/usr.sbin/nsd/nsd.conf.sample.in index 48eef14ff9e..cda7dd084ba 100644 --- a/usr.sbin/nsd/nsd.conf.sample.in +++ b/usr.sbin/nsd/nsd.conf.sample.in @@ -258,6 +258,15 @@ 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: 0 + #max-retry-time: 1209600 + #min-retry-time: 0 + + # limit the zone transfer size (in bytes), stops very large transfers + # 0 is no limits enforced. + # size-limit-xfr: 0 # 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/usr.sbin/nsd/nsec3.c b/usr.sbin/nsd/nsec3.c index d4fd1a2d336..bad5af8a1bc 100644 --- a/usr.sbin/nsd/nsec3.c +++ b/usr.sbin/nsd/nsec3.c @@ -893,7 +893,9 @@ nsec3_add_ds_proof(struct query *query, struct answer *answer, /* use NSEC3 record from above the zone cut. */ nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_ds_parent_cover); - } else if (!delegpt && domain->nsec3 && domain->nsec3->nsec3_is_exact) { + } else if (!delegpt && domain->nsec3 && domain->nsec3->nsec3_is_exact + && nsec3_domain_part_of_zone(domain->nsec3->nsec3_cover, + query->zone)) { nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_cover); } else { diff --git a/usr.sbin/nsd/options.c b/usr.sbin/nsd/options.c index 349e271b422..058ceeccab4 100644 --- a/usr.sbin/nsd/options.c +++ b/usr.sbin/nsd/options.c @@ -813,6 +813,7 @@ pattern_options_create(region_type* region) p->zonestats = 0; p->allow_notify = 0; p->request_xfr = 0; + p->size_limit_xfr = 0; p->notify = 0; p->provide_xfr = 0; p->outgoing_interface = 0; @@ -822,6 +823,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 = 0; + 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 = 0; + p->min_retry_time_is_default = 1; #ifdef RATELIMIT p->rrl_whitelist = 0; #endif @@ -944,6 +953,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,9 +1034,22 @@ 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 + if(p->size_limit_xfr != q->size_limit_xfr) return 0; return 1; } @@ -1036,6 +1066,19 @@ unmarshal_u8(struct buffer* b) return buffer_read_u8(b); } +static void +marshal_u64(struct buffer* b, uint64_t v) +{ + buffer_reserve(b, 8); + buffer_write_u64(b, v); +} + +static uint64_t +unmarshal_u64(struct buffer* b) +{ + return buffer_read_u64(b); +} + #ifdef RATELIMIT static void marshal_u16(struct buffer* b, uint16_t v) @@ -1054,6 +1097,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); @@ -1138,11 +1194,20 @@ pattern_options_marshal(struct buffer* b, pattern_options_t* p) marshal_u8(b, p->notify_retry); marshal_u8(b, p->notify_retry_is_default); marshal_u8(b, p->implicit); + marshal_u64(b, p->size_limit_xfr); marshal_acl_list(b, p->allow_notify); marshal_acl_list(b, p->request_xfr); 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* @@ -1160,11 +1225,20 @@ pattern_options_unmarshal(region_type* r, struct buffer* b) p->notify_retry = unmarshal_u8(b); p->notify_retry_is_default = unmarshal_u8(b); p->implicit = unmarshal_u8(b); + p->size_limit_xfr = unmarshal_u64(b); p->allow_notify = unmarshal_acl_list(r, b); p->request_xfr = unmarshal_acl_list(r, 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 +1949,23 @@ 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_retry_time_is_default) { + a->min_retry_time = pat->min_retry_time; + a->min_retry_time_is_default = 0; + } + a->size_limit_xfr = pat->size_limit_xfr; #ifdef RATELIMIT a->rrl_whitelist |= pat->rrl_whitelist; #endif diff --git a/usr.sbin/nsd/options.h b/usr.sbin/nsd/options.h index ceba624fe3f..e0f749cb972 100644 --- a/usr.sbin/nsd/options.h +++ b/usr.sbin/nsd/options.h @@ -154,6 +154,15 @@ 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; + uint64_t size_limit_xfr; }; #define PATTERN_IMPLICIT_MARKER "_implicit_" diff --git a/usr.sbin/nsd/query.c b/usr.sbin/nsd/query.c index f8a429c4a98..7256449d38d 100644 --- a/usr.sbin/nsd/query.c +++ b/usr.sbin/nsd/query.c @@ -704,11 +704,16 @@ add_rrset(struct query *query, result = answer_add_rrset(answer, section, owner, rrset); switch (rrset_rrtype(rrset)) { case TYPE_NS: +#if defined(INET6) /* if query over IPv6, swap A and AAAA; put AAAA first */ add_additional_rrsets(query, answer, rrset, 0, 1, (query->addr.ss_family == AF_INET6)? swap_aaaa_additional_rr_types: default_additional_rr_types); +#else + add_additional_rrsets(query, answer, rrset, 0, 1, + default_additional_rr_types); +#endif break; case TYPE_MB: add_additional_rrsets(query, answer, rrset, 0, 0, @@ -1205,7 +1210,7 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, * parent zone to generate the answer if we are * authoritative for the parent zone. */ - zone_type *zone = domain_find_parent_zone(q->zone); + zone_type *zone = domain_find_parent_zone(nsd->db, q->zone); if (zone) q->zone = zone; } diff --git a/usr.sbin/nsd/server.c b/usr.sbin/nsd/server.c index 530b443de8c..ae27312fbfc 100644 --- a/usr.sbin/nsd/server.c +++ b/usr.sbin/nsd/server.c @@ -160,6 +160,11 @@ struct tcp_handler_data * The number of queries handled by this specific TCP connection. */ int query_count; + + /* + * The timeout in msec for this tcp connection + */ + int tcp_timeout; }; /* @@ -2630,8 +2635,8 @@ handle_tcp_reading(int fd, short event, void* arg) data->query->tcplen = buffer_remaining(data->query->packet); data->bytes_transmitted = 0; - timeout.tv_sec = data->nsd->tcp_timeout; - timeout.tv_usec = 0L; + timeout.tv_sec = data->tcp_timeout / 1000; + timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); @@ -2763,8 +2768,8 @@ handle_tcp_writing(int fd, short event, void* arg) q->tcplen = buffer_remaining(q->packet); data->bytes_transmitted = 0; /* Reset timeout. */ - timeout.tv_sec = data->nsd->tcp_timeout; - timeout.tv_usec = 0L; + timeout.tv_sec = data->tcp_timeout / 1000; + timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT, @@ -2794,8 +2799,8 @@ handle_tcp_writing(int fd, short event, void* arg) data->bytes_transmitted = 0; - timeout.tv_sec = data->nsd->tcp_timeout; - timeout.tv_usec = 0L; + timeout.tv_sec = data->tcp_timeout / 1000; + timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT, @@ -2909,8 +2914,13 @@ handle_tcp_accept(int fd, short event, void* arg) memcpy(&tcp_data->query->addr, &addr, addrlen); tcp_data->query->addrlen = addrlen; - timeout.tv_sec = data->nsd->tcp_timeout; - timeout.tv_usec = 0; + tcp_data->tcp_timeout = data->nsd->tcp_timeout * 1000; + if (data->nsd->current_tcp_count > data->nsd->maximum_tcp_count/2) { + /* very busy, give smaller timeout */ + tcp_data->tcp_timeout = 200; + } + timeout.tv_sec = tcp_data->tcp_timeout / 1000; + timeout.tv_usec = (tcp_data->tcp_timeout % 1000)*1000; event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tcp_reading, tcp_data); diff --git a/usr.sbin/nsd/util.h b/usr.sbin/nsd/util.h index 702674fc411..b59b7b69bd1 100644 --- a/usr.sbin/nsd/util.h +++ b/usr.sbin/nsd/util.h @@ -198,6 +198,20 @@ write_uint32(void *dst, uint32_t data) #endif } +static inline void +write_uint64(void *dst, uint64_t data) +{ + uint8_t *p = (uint8_t *) dst; + p[0] = (uint8_t) ((data >> 56) & 0xff); + p[1] = (uint8_t) ((data >> 48) & 0xff); + p[2] = (uint8_t) ((data >> 40) & 0xff); + p[3] = (uint8_t) ((data >> 32) & 0xff); + p[4] = (uint8_t) ((data >> 24) & 0xff); + p[5] = (uint8_t) ((data >> 16) & 0xff); + p[6] = (uint8_t) ((data >> 8) & 0xff); + p[7] = (uint8_t) (data & 0xff); +} + /* * Copy data allowing for unaligned accesses in network byte order * (big endian). @@ -224,6 +238,21 @@ read_uint32(const void *src) #endif } +static inline uint64_t +read_uint64(const void *src) +{ + uint8_t *p = (uint8_t *) src; + return + ((uint64_t)p[0] << 56) | + ((uint64_t)p[1] << 48) | + ((uint64_t)p[2] << 40) | + ((uint64_t)p[3] << 32) | + ((uint64_t)p[4] << 24) | + ((uint64_t)p[5] << 16) | + ((uint64_t)p[6] << 8) | + (uint64_t)p[7]; +} + /* * Print debugging information using log_msg, * set the logfile as /dev/stdout or /dev/stderr if you like. diff --git a/usr.sbin/nsd/xfrd-disk.c b/usr.sbin/nsd/xfrd-disk.c index 3fa863077ea..654e78edfd4 100644 --- a/usr.sbin/nsd/xfrd-disk.c +++ b/usr.sbin/nsd/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); @@ -564,3 +570,17 @@ xfrd_unlink_xfrfile(struct nsd* nsd, uint64_t number) strerror(errno)); } } + +uint64_t +xfrd_get_xfrfile_size(struct nsd* nsd, uint64_t number ) +{ + char fname[1024]; + struct stat tempxfr_stat; + tempxfrname(fname, sizeof(fname), nsd, number); + if( stat( fname, &tempxfr_stat ) < 0 ) { + log_msg(LOG_WARNING, "could not get file size %s: %s", fname, + strerror(errno)); + return 0; + } + return (uint64_t)tempxfr_stat.st_size; +} diff --git a/usr.sbin/nsd/xfrd-disk.h b/usr.sbin/nsd/xfrd-disk.h index 2c8e23fc752..b7e2d10b237 100644 --- a/usr.sbin/nsd/xfrd-disk.h +++ b/usr.sbin/nsd/xfrd-disk.h @@ -29,5 +29,7 @@ void xfrd_del_tempdir(struct nsd* nsd); FILE* xfrd_open_xfrfile(struct nsd* nsd, uint64_t number, char* mode); /* unlink temp file */ void xfrd_unlink_xfrfile(struct nsd* nsd, uint64_t number); +/* get temp file size */ +uint64_t xfrd_get_xfrfile_size(struct nsd* nsd, uint64_t number ); #endif /* XFRD_DISK_H */ diff --git a/usr.sbin/nsd/xfrd.c b/usr.sbin/nsd/xfrd.c index c2c75eda4df..0eacce799d3 100644 --- a/usr.sbin/nsd/xfrd.c +++ b/usr.sbin/nsd/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); @@ -1918,6 +1928,7 @@ xfrd_handle_received_xfr_packet(xfrd_zone_t* zone, buffer_type* packet) { xfrd_soa_t soa; enum xfrd_packet_result res; + uint64_t xfrfile_size; /* parse and check the packet - see if it ends the xfr */ switch((res=xfrd_parse_received_xfr_packet(zone, packet, &soa))) @@ -1975,6 +1986,15 @@ xfrd_handle_received_xfr_packet(xfrd_zone_t* zone, buffer_type* packet) "disk", zone->apex_str, zone->master->ip_address_spec, (int)zone->msg_new_serial)); zone->msg_seq_nr++; + + xfrfile_size = xfrd_get_xfrfile_size(xfrd->nsd, zone->xfrfilenumber); + if( zone->zone_options->pattern->size_limit_xfr != 0 && + xfrfile_size > zone->zone_options->pattern->size_limit_xfr ) { + /* xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); + xfrd_set_reload_timeout(); */ + log_msg(LOG_INFO, "xfrd : transfered zone data was too large %llu", (long long unsigned)xfrfile_size); + return xfrd_packet_bad; + } if(res == xfrd_packet_more) { /* wait for more */ return xfrd_packet_more; diff --git a/usr.sbin/nsd/zonec.c b/usr.sbin/nsd/zonec.c index 666b0cc3dd7..c186171039c 100644 --- a/usr.sbin/nsd/zonec.c +++ b/usr.sbin/nsd/zonec.c @@ -953,7 +953,10 @@ zparser_conv_loc(region_type *region, char *str) } /* Meters of altitude... */ - (void) strtol(str, &str, 10); + if(strtol(str, &str, 10) == LONG_MAX) { + zc_error_prev_line("altitude too large, number overflow"); + return NULL; + } switch(*str) { case ' ': case '\0': @@ -1576,21 +1579,21 @@ zonec_read(const char* name, const char* zonefile, zone_type* zone) dname = dname_parse(parser->rr_region, name); if (!dname) { zc_error("incorrect zone name '%s'", name); - return 0; + return 1; } #ifndef ROOT_SERVER /* Is it a root zone? Are we a root server then? Idiot proof. */ if (dname->label_count == 1) { zc_error("not configured as a root server"); - return 0; + return 1; } #endif /* Open the zone file */ if (!zone_open(zonefile, 3600, CLASS_IN, dname)) { zc_error("cannot open '%s': %s", zonefile, strerror(errno)); - return 0; + return 1; } parser->current_zone = zone; |