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 <numpackets>
+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 <qps>
 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 */
 
