- delay-close: msec option that delays closing ports for which

the UDP reply has timed out.  Keeps the port open, only accepts
  the correct reply.  This correct reply is not used, but the port
  is open so that no port-denied ICMPs are generated.


git-svn-id: file:///svn/unbound/trunk@3058 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2014-01-28 14:35:55 +00:00
parent 4adaadab61
commit d8e5a83392
16 changed files with 1601 additions and 1490 deletions

View file

@ -1156,7 +1156,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
worker->daemon->env->infra_cache, worker->rndstate, worker->daemon->env->infra_cache, worker->rndstate,
cfg->use_caps_bits_for_id, worker->ports, worker->numports, cfg->use_caps_bits_for_id, worker->ports, worker->numports,
cfg->unwanted_threshold, &worker_alloc_cleanup, worker, cfg->unwanted_threshold, &worker_alloc_cleanup, worker,
cfg->do_udp, worker->daemon->connect_sslctx); cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close);
if(!worker->back) { if(!worker->back) {
log_err("could not create outgoing sockets"); log_err("could not create outgoing sockets");
worker_delete(worker); worker_delete(worker);

View file

@ -2,6 +2,10 @@
- iana portlist updated. - iana portlist updated.
- iana portlist test updated so it does not touch the source - iana portlist test updated so it does not touch the source
if there are no changes. if there are no changes.
- delay-close: msec option that delays closing ports for which
the UDP reply has timed out. Keeps the port open, only accepts
the correct reply. This correct reply is not used, but the port
is open so that no port-denied ICMPs are generated.
27 January 2014: Wouter 27 January 2014: Wouter
- reuseport is attempted, then fallback to without on failure. - reuseport is attempted, then fallback to without on failure.

View file

@ -114,6 +114,9 @@ server:
# if very busy, 50% queries run to completion, 50% get timeout in msec # if very busy, 50% queries run to completion, 50% get timeout in msec
# jostle-timeout: 200 # jostle-timeout: 200
# msec to wait before close of port on timeout UDP. 0 disables.
# delay-close: 0
# the amount of memory to use for the RRset cache. # the amount of memory to use for the RRset cache.
# plain value in bytes or you can append k, m or G. default is "4Mb". # plain value in bytes or you can append k, m or G. default is "4Mb".

View file

@ -228,6 +228,15 @@ The qps for short queries can be about (numqueriesperthread / 2)
/ (jostletimeout in whole seconds) qps per thread, about (1024/2)*5 = 2560 / (jostletimeout in whole seconds) qps per thread, about (1024/2)*5 = 2560
qps by default. qps by default.
.TP .TP
.B delay\-close: \fI<msec>
Extra delay for timeouted UDP ports before they are closed, in msec.
Default is 0, and that disables it. This prevents very delayed answer
packets from the upstream (recursive) servers from bouncing against
closed ports and setting off all sort of close-port counters, with
eg. 1500 msec. When timeouts happen you need extra sockets, it checks
the ID and remote IP of packets, and unwanted packets are added to the
unwanted packet counter.
.TP
.B so\-rcvbuf: \fI<number> .B so\-rcvbuf: \fI<number>
If not 0, then set the SO_RCVBUF socket option to get more buffer If not 0, then set the SO_RCVBUF socket option to get more buffer
space on UDP port 53 incoming queries. So that short spikes on busy space on UDP port 53 incoming queries. So that short spikes on busy

View file

@ -229,7 +229,8 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct event_base* eb)
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->do_tcp?cfg->outgoing_num_tcp:0,
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
ports, numports, cfg->unwanted_threshold, ports, numports, cfg->unwanted_threshold,
&libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx); &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx,
cfg->delay_close);
if(!w->is_bg || w->is_bg_thread) { if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock); lock_basic_unlock(&ctx->cfglock);
} }

View file

@ -381,9 +381,11 @@ outnet_send_wait_udp(struct outside_network* outnet)
if(!randomize_and_send_udp(outnet, pend, outnet->udp_buff, if(!randomize_and_send_udp(outnet, pend, outnet->udp_buff,
pend->timeout)) { pend->timeout)) {
/* callback error on pending */ /* callback error on pending */
fptr_ok(fptr_whitelist_pending_udp(pend->cb)); if(pend->cb) {
(void)(*pend->cb)(outnet->unused_fds->cp, pend->cb_arg, fptr_ok(fptr_whitelist_pending_udp(pend->cb));
NETEVENT_CLOSED, NULL); (void)(*pend->cb)(outnet->unused_fds->cp, pend->cb_arg,
NETEVENT_CLOSED, NULL);
}
pending_delete(outnet, pend); pending_delete(outnet, pend);
} }
} }
@ -460,8 +462,10 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "outnet handle udp reply"); verbose(VERB_ALGO, "outnet handle udp reply");
/* delete from tree first in case callback creates a retry */ /* delete from tree first in case callback creates a retry */
(void)rbtree_delete(outnet->pending, p->node.key); (void)rbtree_delete(outnet->pending, p->node.key);
fptr_ok(fptr_whitelist_pending_udp(p->cb)); if(p->cb) {
(void)(*p->cb)(p->pc->cp, p->cb_arg, NETEVENT_NOERROR, reply_info); fptr_ok(fptr_whitelist_pending_udp(p->cb));
(void)(*p->cb)(p->pc->cp, p->cb_arg, NETEVENT_NOERROR, reply_info);
}
portcomm_loweruse(outnet, p->pc); portcomm_loweruse(outnet, p->pc);
pending_delete(NULL, p); pending_delete(NULL, p);
outnet_send_wait_udp(outnet); outnet_send_wait_udp(outnet);
@ -496,6 +500,17 @@ calc_num46(char** ifs, int num_ifs, int do_ip4, int do_ip6,
} }
void
pending_udp_timer_delay_cb(void* arg)
{
struct pending* p = (struct pending*)arg;
struct outside_network* outnet = p->outnet;
verbose(VERB_ALGO, "timeout udp with delay");
portcomm_loweruse(outnet, p->pc);
pending_delete(outnet, p);
outnet_send_wait_udp(outnet);
}
void void
pending_udp_timer_cb(void *arg) pending_udp_timer_cb(void *arg)
{ {
@ -503,8 +518,16 @@ pending_udp_timer_cb(void *arg)
struct outside_network* outnet = p->outnet; struct outside_network* outnet = p->outnet;
/* it timed out */ /* it timed out */
verbose(VERB_ALGO, "timeout udp"); verbose(VERB_ALGO, "timeout udp");
fptr_ok(fptr_whitelist_pending_udp(p->cb)); if(p->cb) {
(void)(*p->cb)(p->pc->cp, p->cb_arg, NETEVENT_TIMEOUT, NULL); fptr_ok(fptr_whitelist_pending_udp(p->cb));
(void)(*p->cb)(p->pc->cp, p->cb_arg, NETEVENT_TIMEOUT, NULL);
}
if(outnet->delayclose) {
p->cb = NULL;
p->timer->callback = &pending_udp_timer_delay_cb;
comm_timer_set(p->timer, &outnet->delay_tv);
return;
}
portcomm_loweruse(outnet, p->pc); portcomm_loweruse(outnet, p->pc);
pending_delete(outnet, p); pending_delete(outnet, p);
outnet_send_wait_udp(outnet); outnet_send_wait_udp(outnet);
@ -561,7 +584,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
struct ub_randstate* rnd, int use_caps_for_id, int* availports, struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports, size_t unwanted_threshold, int numavailports, size_t unwanted_threshold,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx) void* sslctx, int delayclose)
{ {
struct outside_network* outnet = (struct outside_network*) struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network)); calloc(1, sizeof(struct outside_network));
@ -583,6 +606,13 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->unwanted_param = unwanted_param; outnet->unwanted_param = unwanted_param;
outnet->use_caps_for_id = use_caps_for_id; outnet->use_caps_for_id = use_caps_for_id;
outnet->do_udp = do_udp; outnet->do_udp = do_udp;
#ifndef S_SPLINT_S
if(delayclose) {
outnet->delayclose = 1;
outnet->delay_tv.tv_sec = delayclose/1000;
outnet->delay_tv.tv_usec = (delayclose%1000)*1000;
}
#endif
if(numavailports == 0) { if(numavailports == 0) {
log_err("no outgoing ports available"); log_err("no outgoing ports available");
outside_network_delete(outnet); outside_network_delete(outnet);

View file

@ -95,6 +95,10 @@ struct outside_network {
struct port_comm* unused_fds; struct port_comm* unused_fds;
/** if udp is done */ /** if udp is done */
int do_udp; int do_udp;
/** if udp is delay-closed (delayed answers do not meet closed port)*/
int delayclose;
/** timeout for delayclose */
struct timeval delay_tv;
/** array of outgoing IP4 interfaces */ /** array of outgoing IP4 interfaces */
struct port_if* ip4_ifs; struct port_if* ip4_ifs;
@ -377,6 +381,8 @@ struct serviced_query {
* @param unwanted_param: user parameter to action. * @param unwanted_param: user parameter to action.
* @param do_udp: if udp is done. * @param do_udp: if udp is done.
* @param sslctx: context to create outgoing connections with (if enabled). * @param sslctx: context to create outgoing connections with (if enabled).
* @param delayclose: if not0, udp sockets are delayed before timeout closure.
* msec to wait on timeouted udp sockets.
* @return: the new structure (with no pending answers) or NULL on error. * @return: the new structure (with no pending answers) or NULL on error.
*/ */
struct outside_network* outside_network_create(struct comm_base* base, struct outside_network* outside_network_create(struct comm_base* base,
@ -385,7 +391,7 @@ struct outside_network* outside_network_create(struct comm_base* base,
struct ub_randstate* rnd, int use_caps_for_id, int* availports, struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports, size_t unwanted_threshold, int numavailports, size_t unwanted_threshold,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx); void* sslctx, int delayclose);
/** /**
* Delete outside_network structure. * Delete outside_network structure.
@ -516,6 +522,9 @@ int outnet_tcp_cb(struct comm_point* c, void* arg, int error,
/** callback for udp timeout */ /** callback for udp timeout */
void pending_udp_timer_cb(void *arg); void pending_udp_timer_cb(void *arg);
/** callback for udp delay for timeout */
void pending_udp_timer_delay_cb(void *arg);
/** callback for outgoing TCP timer event */ /** callback for outgoing TCP timer event */
void outnet_tcptimer(void* arg); void outnet_tcptimer(void* arg);

View file

@ -900,7 +900,8 @@ outside_network_create(struct comm_base* base, size_t bufsize,
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold), int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param), void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx)) int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx),
int ATTR_UNUSED(delayclose))
{ {
struct replay_runtime* runtime = (struct replay_runtime*)base; struct replay_runtime* runtime = (struct replay_runtime*)base;
struct outside_network* outnet = calloc(1, struct outside_network* outnet = calloc(1,
@ -1229,6 +1230,11 @@ void pending_udp_timer_cb(void *ATTR_UNUSED(arg))
log_assert(0); log_assert(0);
} }
void pending_udp_timer_delay_cb(void *ATTR_UNUSED(arg))
{
log_assert(0);
}
void outnet_tcptimer(void* ATTR_UNUSED(arg)) void outnet_tcptimer(void* ATTR_UNUSED(arg))
{ {
log_assert(0); log_assert(0);

View file

@ -138,6 +138,7 @@ config_create(void)
cfg->prefetch_key = 0; cfg->prefetch_key = 0;
cfg->infra_cache_slabs = 4; cfg->infra_cache_slabs = 4;
cfg->infra_cache_numhosts = 10000; cfg->infra_cache_numhosts = 10000;
cfg->delay_close = 0;
if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int)))) if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int))))
goto error_exit; goto error_exit;
init_outgoing_availports(cfg->outgoing_avail_ports, 65536); init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
@ -378,6 +379,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_NUMBER_OR_ZERO("infra-host-ttl:", host_ttl) else S_NUMBER_OR_ZERO("infra-host-ttl:", host_ttl)
else S_POW2("infra-cache-slabs:", infra_cache_slabs) else S_POW2("infra-cache-slabs:", infra_cache_slabs)
else S_SIZET_NONZERO("infra-cache-numhosts:", infra_cache_numhosts) else S_SIZET_NONZERO("infra-cache-numhosts:", infra_cache_numhosts)
else S_NUMBER_OR_ZERO("delay-close:", delay_close)
else S_STR("chroot:", chrootdir) else S_STR("chroot:", chrootdir)
else S_STR("username:", username) else S_STR("username:", username)
else S_STR("directory:", directory) else S_STR("directory:", directory)
@ -622,6 +624,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "infra-host-ttl", host_ttl) else O_DEC(opt, "infra-host-ttl", host_ttl)
else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs) else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
else O_MEM(opt, "infra-cache-numhosts", infra_cache_numhosts) else O_MEM(opt, "infra-cache-numhosts", infra_cache_numhosts)
else O_UNS(opt, "delay-close", delay_close)
else O_YNO(opt, "do-ip4", do_ip4) else O_YNO(opt, "do-ip4", do_ip4)
else O_YNO(opt, "do-ip6", do_ip6) else O_YNO(opt, "do-ip6", do_ip6)
else O_YNO(opt, "do-udp", do_udp) else O_YNO(opt, "do-udp", do_udp)

View file

@ -119,6 +119,8 @@ struct config_file {
size_t infra_cache_slabs; size_t infra_cache_slabs;
/** max number of hosts in the infra cache */ /** max number of hosts in the infra cache */
size_t infra_cache_numhosts; size_t infra_cache_numhosts;
/** delay close of udp-timeouted ports, if 0 no delayclose. in msec */
int delay_close;
/** the target fetch policy for the iterator */ /** the target fetch policy for the iterator */
char* target_fetch_policy; char* target_fetch_policy;

File diff suppressed because it is too large Load diff

View file

@ -248,6 +248,7 @@ infra-cache-numhosts{COLON} { YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) }
infra-cache-lame-size{COLON} { YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) } infra-cache-lame-size{COLON} { YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) }
num-queries-per-thread{COLON} { YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) } num-queries-per-thread{COLON} { YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) }
jostle-timeout{COLON} { YDVAR(1, VAR_JOSTLE_TIMEOUT) } jostle-timeout{COLON} { YDVAR(1, VAR_JOSTLE_TIMEOUT) }
delay-close{COLON} { YDVAR(1, VAR_DELAY_CLOSE) }
target-fetch-policy{COLON} { YDVAR(1, VAR_TARGET_FETCH_POLICY) } target-fetch-policy{COLON} { YDVAR(1, VAR_TARGET_FETCH_POLICY) }
harden-short-bufsize{COLON} { YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) } harden-short-bufsize{COLON} { YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) }
harden-large-queries{COLON} { YDVAR(1, VAR_HARDEN_LARGE_QUERIES) } harden-large-queries{COLON} { YDVAR(1, VAR_HARDEN_LARGE_QUERIES) }

File diff suppressed because it is too large Load diff

View file

@ -174,7 +174,8 @@ extern int yydebug;
VAR_STUB_FIRST = 383, VAR_STUB_FIRST = 383,
VAR_MINIMAL_RESPONSES = 384, VAR_MINIMAL_RESPONSES = 384,
VAR_RRSET_ROUNDROBIN = 385, VAR_RRSET_ROUNDROBIN = 385,
VAR_MAX_UDP_SIZE = 386 VAR_MAX_UDP_SIZE = 386,
VAR_DELAY_CLOSE = 387
}; };
#endif #endif
/* Tokens. */ /* Tokens. */
@ -307,6 +308,7 @@ extern int yydebug;
#define VAR_MINIMAL_RESPONSES 384 #define VAR_MINIMAL_RESPONSES 384
#define VAR_RRSET_ROUNDROBIN 385 #define VAR_RRSET_ROUNDROBIN 385
#define VAR_MAX_UDP_SIZE 386 #define VAR_MAX_UDP_SIZE 386
#define VAR_DELAY_CLOSE 387
@ -320,7 +322,7 @@ typedef union YYSTYPE
/* Line 2049 of yacc.c */ /* Line 2049 of yacc.c */
#line 324 "util/configparser.h" #line 326 "util/configparser.h"
} YYSTYPE; } YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */

View file

@ -105,7 +105,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM %token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST %token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
%token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN %token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN
%token VAR_MAX_UDP_SIZE %token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE
%% %%
toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -163,7 +163,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_log_queries | server_tcp_upstream | server_ssl_upstream | server_log_queries | server_tcp_upstream | server_ssl_upstream |
server_ssl_service_key | server_ssl_service_pem | server_ssl_port | server_ssl_service_key | server_ssl_service_pem | server_ssl_port |
server_minimal_responses | server_rrset_roundrobin | server_max_udp_size | server_minimal_responses | server_rrset_roundrobin | server_max_udp_size |
server_so_reuseport server_so_reuseport | server_delay_close
; ;
stubstart: VAR_STUB_ZONE stubstart: VAR_STUB_ZONE
{ {
@ -669,6 +669,15 @@ server_jostle_timeout: VAR_JOSTLE_TIMEOUT STRING_ARG
free($2); free($2);
} }
; ;
server_delay_close: VAR_DELAY_CLOSE STRING_ARG
{
OUTYY(("P(server_delay_close:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->delay_close = atoi($2);
free($2);
}
;
server_rrset_cache_size: VAR_RRSET_CACHE_SIZE STRING_ARG server_rrset_cache_size: VAR_RRSET_CACHE_SIZE STRING_ARG
{ {
OUTYY(("P(server_rrset_cache_size:%s)\n", $2)); OUTYY(("P(server_rrset_cache_size:%s)\n", $2));

View file

@ -104,6 +104,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
{ {
if(fptr == &pending_udp_timer_cb) return 1; if(fptr == &pending_udp_timer_cb) return 1;
else if(fptr == &outnet_tcptimer) return 1; else if(fptr == &outnet_tcptimer) return 1;
else if(fptr == &pending_udp_timer_delay_cb) return 1;
else if(fptr == &worker_stat_timer_cb) return 1; else if(fptr == &worker_stat_timer_cb) return 1;
else if(fptr == &worker_probe_timer_cb) return 1; else if(fptr == &worker_probe_timer_cb) return 1;
#ifdef UB_ON_WINDOWS #ifdef UB_ON_WINDOWS