Index: configlexer.lex =================================================================== --- configlexer.lex (revision 3903) +++ configlexer.lex (working copy) @@ -140,6 +140,7 @@ UDP { LEXOUT(("v(%s) ", yytext)); return VAR_UDP;} rrl-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;} rrl-ratelimit{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_RATELIMIT;} +rrl-slip{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SLIP;} rrl-whitelist-ratelimit{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST_RATELIMIT;} rrl-whitelist{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST;} {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} Index: configparser.y =================================================================== --- configparser.y (revision 3903) +++ configparser.y (working copy) @@ -59,7 +59,7 @@ %token VAR_ALGORITHM VAR_SECRET %token VAR_AXFR VAR_UDP %token VAR_VERBOSITY VAR_HIDE_VERSION -%token VAR_RRL_SIZE VAR_RRL_RATELIMIT VAR_RRL_WHITELIST_RATELIMIT VAR_RRL_WHITELIST +%token VAR_RRL_SIZE VAR_RRL_RATELIMIT VAR_RRL_SLIP VAR_RRL_WHITELIST_RATELIMIT VAR_RRL_WHITELIST %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -84,7 +84,7 @@ server_difffile | server_xfrdfile | server_xfrd_reload_timeout | server_tcp_query_count | server_tcp_timeout | server_ipv4_edns_size | server_ipv6_edns_size | server_verbosity | server_hide_version | - server_rrl_size | server_rrl_ratelimit | server_rrl_whitelist_ratelimit; + server_rrl_size | server_rrl_ratelimit | server_rrl_slip | server_rrl_whitelist_ratelimit; server_ip_address: VAR_IP_ADDRESS STRING { OUTYY(("P(server_ip_address:%s)\n", $2)); @@ -315,6 +315,18 @@ #endif } ; +server_rrl_slip: VAR_RRL_SLIP STRING + { + OUTYY(("P(server_rrl_slip:%s)\n", $2)); +#ifdef RATELIMIT + if(atoi($2) <= 0) + yyerror("number greater than zero expected"); + if(atoi($2) > 5) + yyerror("number lower than five expected"); + cfg_parser->opt->rrl_slip = atoi($2); +#endif + } + ; server_rrl_whitelist_ratelimit: VAR_RRL_WHITELIST_RATELIMIT STRING { OUTYY(("P(server_rrl_whitelist_ratelimit:%s)\n", $2)); Index: nsd-checkconf.c =================================================================== --- nsd-checkconf.c (revision 3903) +++ nsd-checkconf.c (working copy) @@ -315,6 +315,7 @@ #ifdef RATELIMIT SERV_GET_INT(rrl_size, o); SERV_GET_INT(rrl_ratelimit, o); + SERV_GET_INT(rrl_slip, o); SERV_GET_INT(rrl_whitelist_ratelimit, o); #endif @@ -367,6 +368,7 @@ #ifdef RATELIMIT printf("\trrl-size: %d\n", (int)opt->rrl_size); printf("\trrl-ratelimit: %d\n", (int)opt->rrl_ratelimit); + printf("\trrl-slip: %d\n", (int)opt->rrl_slip); printf("\trrl-whitelist-ratelimit: %d\n", (int)opt->rrl_whitelist_ratelimit); #endif Index: nsd.conf.5.in =================================================================== --- nsd.conf.5.in (revision 3903) +++ nsd.conf.5.in (working copy) @@ -248,6 +248,11 @@ blocked and unblocked subnets are logged. Blocked queries are blocked and some receive TCP fallback replies. .TP +.B rrl\-slip:\fR +This option controls the number of packets discarded before we send back a SLIP response +(a response with "truncated" bit set to one). 0 disables the sending of SLIP packets, +1 means every query will get a SLIP response. +.TP .B rrl\-whitelist\-ratelimit:\fR The max qps for query sorts for a source, which have been whitelisted. Default 2000 qps. With the rrl\-whitelist option you can set Index: nsd.conf.sample.in =================================================================== --- nsd.conf.sample.in (revision 3903) +++ nsd.conf.sample.in (working copy) @@ -108,6 +108,14 @@ # rrl-whitelist-ratelimit to 0 to disable ratelimit processing. # rrl-ratelimit: 200 + # Response Rate Limiting, number of packets to discard before + # sending a SLIP response (a truncated one, allowing an honest + # resolver to retry with TCP). Default is 2 (one half of the + # queries will receive a SLIP response, 0 disables SLIP (all + # packets are discarded), 1 means every request will get a + # SLIP response. + # rrl-slip: 2 + # Response Rate Limiting, maximum QPS allowed (from one query source) # for whitelisted types. Default 2000. # rrl-whitelist-ratelimit: 2000 Index: options.c =================================================================== --- options.c (revision 3903) +++ options.c (working copy) @@ -67,6 +67,7 @@ #ifdef RATELIMIT opt->rrl_size = RRL_BUCKETS; opt->rrl_ratelimit = RRL_LIMIT/2; + opt->rrl_slip = RRL_SLIP; opt->rrl_whitelist_ratelimit = RRL_WLIST_LIMIT/2; #endif nsd_options = opt; Index: options.h =================================================================== --- options.h (revision 3903) +++ options.h (working copy) @@ -69,6 +69,10 @@ size_t rrl_size; /** max qps for queries, 0 is nolimit */ size_t rrl_ratelimit; + /** number of rate-limited packets to ignore, before sending + SLIP (truncated replies), 0 means never reply SLIP, 1 + means always, 2 means one half of queries will receive SLIP, etc. **/ + size_t rrl_slip; /** max qps for whitelisted queries, 0 is nolimit */ size_t rrl_whitelist_ratelimit; #endif Index: rrl.c =================================================================== --- rrl.c (revision 3903) +++ rrl.c (working copy) @@ -46,6 +46,7 @@ static struct rrl_bucket* rrl_array = NULL; static size_t rrl_array_size = RRL_BUCKETS; static uint32_t rrl_ratelimit = RRL_LIMIT; /* 2x qps */ +static uint8_t rrl_slip_ratio = RRL_SLIP; static uint32_t rrl_whitelist_ratelimit = RRL_WLIST_LIMIT; /* 2x qps */ /* the array of mmaps for the children (saved between reloads) */ @@ -83,7 +84,7 @@ return buf; } -void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm) +void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t sm, size_t wlm) { #ifdef HAVE_MMAP size_t i; @@ -91,6 +92,7 @@ if(numbuck != 0) rrl_array_size = numbuck; rrl_ratelimit = lm*2; + rrl_slip_ratio = sm; rrl_whitelist_ratelimit = wlm*2; #ifdef HAVE_MMAP /* allocate the ratelimit hashtable in a memory map so it is @@ -444,8 +446,8 @@ query_state_type rrl_slip(query_type* query) { /* discard half the packets, randomly */ - if((random() & 0x1)) { - /* set TC on the rest */ + if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((random() % rrl_slip_ratio) == 0))) { + /* Set TC on the rest */ TC_SET(query->packet); ANCOUNT_SET(query->packet, 0); NSCOUNT_SET(query->packet, 0); Index: rrl.h =================================================================== --- rrl.h (revision 3903) +++ rrl.h (working copy) @@ -30,6 +30,8 @@ #define RRL_BUCKETS 1000000 /** default rrl limit, in 2x qps , the default is 200 qps */ #define RRL_LIMIT 400 +/** Default SLIP number */ +#define RRL_SLIP 2 /** default whitelist rrl limit, in 2x qps, default is thus 2000 qps */ #define RRL_WLIST_LIMIT 4000 @@ -37,7 +39,7 @@ * Initialize for n children (optional, otherwise no mmaps used) * ratelimits lm and wlm are in qps (this routines x2s them for internal use). */ -void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm); +void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t sm, size_t wlm); /** * Initialize rate limiting (for this child server process) Index: server.c =================================================================== --- server.c (revision 3903) +++ server.c (working copy) @@ -541,8 +541,8 @@ hash_set_raninit(v); else hash_set_raninit(random()); #endif - rrl_mmap_init(nsd->child_count, nsd->options->rrl_size, - nsd->options->rrl_ratelimit, + rrl_mmap_init(nsd->child_count, nsd->options->rrl_size, + nsd->options->rrl_ratelimit, nsd->options->rrl_slip, nsd->options->rrl_whitelist_ratelimit); #endif /* RATELIMIT */