[ratelimits] Extending RRL to refused recursive queries

shawmplayer at yahoo.com shawmplayer at yahoo.com
Wed Apr 17 04:08:08 UTC 2013


I installed the Bind 2013/04/04 RRL-only patch (rl-9.9.2-P1.patch) to 
see how well it performs against the DNS reflection attempts my domains 
are experiencing. It had some impact, but overall it only marginally 
reduced the DNS spam traffic, which can be as much as 50X my ham.

I've not dug into the bowels of bind before, but after a quick look it 
appears most of this is coming from external recursion requests being 
refused by my DNS. Recursion is only enabled for internal clients and 
my immediate WAN subnet. My external zone is only authoritative. While 
the outbound traffic from the reflection attempts isn't staggering, I 
see no point subjecting the victims to any of this, and furthermore I 
would like to disincentivize the rabble by absorbing their recursion 
request noise while delivering nothing in return to their victims.

However that didn't seem to be possible with the RRL patch, and when I 
read the code it was apparent that refused recursion queries never pass 
through through it. Hence I slapped together the attached patch (to be 
applied on top of rl-9.9.2-P1.patch), which adds a 
"cantdelegates-per-second" option to "rate-limit". Because my external 
zone always refuses recursion requests, I don't mind telling this to a 
client that occasionally asks. However I don't care what name they're 
trying to query, so the hash key only applies to the client address.

Being a neophyte this patch is probably a mess, and might be useless to 
the general DNS public. But it works great for me and drops recursive 
refusals to virtually all the remaining reflection attempts I am 
seeing. Sorry for the trouble if I am turning up dust that was put to 
rest before.
-------------- next part --------------
--- ../../ref/bind-9.9.2-P1/bin/named/query.c	Tue Apr 16 21:00:42 2013
+++ bin/named/query.c	Tue Apr 16 20:12:47 2013
@@ -5433,6 +5433,51 @@
 	return (ISC_TRUE);
 }
 
+static isc_boolean_t
+rrl_log_n_drop(ns_client_t *client, dns_rrl_result_t rrl_result, isc_result_t *query_error,
+	isc_boolean_t wouldlog, char *log_buf)
+{
+	/*
+	 * Log dropped or slipped responses in the query
+	 * category so that requests are not silently lost.
+	 * Starts of rate-limited bursts are logged in
+	 * DNS_LOGCATEGORY_RRL.
+	 *
+	 * Dropped responses are counted with dropped queries
+	 * in QryDropped while slipped responses are counted
+	 * with other truncated responses in RespTruncated.
+	 */
+	*query_error = 0;
+	if (wouldlog && ns_g_server->log_queries) {
+		ns_client_log(client, NS_LOGCATEGORY_QUERIES,
+			      NS_LOGMODULE_CLIENT,
+			      DNS_RRL_LOG_DROP,
+			      "%s", log_buf);
+	}
+	if (!client->view->rrl->log_only) {
+		if (rrl_result == DNS_RRL_RESULT_DROP) {
+			/*
+			 * These will also be counted in
+			 * dns_nsstatscounter_dropped
+			 */
+			inc_stats(client,
+				dns_nsstatscounter_ratedropped);
+			*query_error = DNS_R_DROP;
+		} else {
+			/*
+			 * These will also be counted in
+			 * dns_nsstatscounter_truncatedresp
+			 */
+			inc_stats(client,
+				dns_nsstatscounter_rateslipped);
+			client->message->flags |=
+				DNS_MESSAGEFLAG_TC;
+		}
+		return (ISC_TRUE);
+	}  
+	return (ISC_FALSE);
+}
+
 /*
  * Do the bulk of query processing for the current query of 'client'.
  * If 'event' is non-NULL, we are returning from recursion and 'qtype'
@@ -5683,6 +5728,33 @@
 			if (WANTRECURSION(client)) {
 				inc_stats(client,
 					  dns_nsstatscounter_recurserej);
+
+				if (client->view->rrl != NULL &&
+				    (client->query.attributes & NS_QUERYATTR_RRL_CHECKED) == 0) {
+					isc_boolean_t wouldlog;
+					char log_buf[DNS_RRL_LOG_BUF_LEN];
+					dns_rrl_result_t rrl_result;
+
+					client->query.attributes |= NS_QUERYATTR_RRL_CHECKED;
+					wouldlog = isc_log_wouldlog(ns_g_lctx, DNS_RRL_LOG_DROP);
+
+					rrl_result = DNS_R_CANTDELEGATE;
+					rrl_result = dns_rrl(client->view, &client->peeraddr,
+							     ISC_TF((client->attributes
+								     & NS_CLIENTATTR_TCP) != 0),
+							     client->message->rdclass, qtype, NULL,
+							     rrl_result, client->now,
+							     wouldlog, log_buf, sizeof(log_buf));
+					if (rrl_result != DNS_RRL_RESULT_OK) {
+						isc_result_t query_error;
+
+						rrl_log_n_drop(client, rrl_result, &query_error, wouldlog, log_buf);
+						if (query_error) {
+							QUERY_ERROR(query_error);
+						}
+						goto cleanup;
+					}
+				}
 			} else
 				inc_stats(client, dns_nsstatscounter_authrej);
 			if (!PARTIALANSWER(client))
@@ -5807,41 +5879,14 @@
 				     rrl_result, client->now,
 				     wouldlog, log_buf, sizeof(log_buf));
 		if (rrl_result != DNS_RRL_RESULT_OK) {
-			/*
-			 * Log dropped or slipped responses in the query
-			 * category so that requests are not silently lost.
-			 * Starts of rate-limited bursts are logged in
-			 * DNS_LOGCATEGORY_RRL.
-			 *
-			 * Dropped responses are counted with dropped queries
-			 * in QryDropped while slipped responses are counted
-			 * with other truncated responses in RespTruncated.
-			 */
-			if (wouldlog && ns_g_server->log_queries) {
-				ns_client_log(client, NS_LOGCATEGORY_QUERIES,
-					      NS_LOGMODULE_CLIENT,
-					      DNS_RRL_LOG_DROP,
-					      "%s", log_buf);
-			}
-			if (!client->view->rrl->log_only) {
-				if (rrl_result == DNS_RRL_RESULT_DROP) {
-					/*
-					 * These will also be counted in
-					 * dns_nsstatscounter_dropped
-					 */
-					inc_stats(client,
-						dns_nsstatscounter_ratedropped);
-					QUERY_ERROR(DNS_R_DROP);
-				} else {
-					/*
-					 * These will also be counted in
-					 * dns_nsstatscounter_truncatedresp
-					 */
-					inc_stats(client,
-						dns_nsstatscounter_rateslipped);
-					client->message->flags |=
-						DNS_MESSAGEFLAG_TC;
+			isc_result_t query_error;
+			isc_boolean_t goto_cleanup;
+
+			goto_cleanup = rrl_log_n_drop(client, rrl_result, &query_error, wouldlog, log_buf);
+			if (query_error) {
+				QUERY_ERROR(query_error);
 				}
+			if (goto_cleanup) {
 				goto cleanup;
 			}
 		}
--- ../../ref/bind-9.9.2-P1/bin/named/server.c	Tue Apr 16 21:00:42 2013
+++ bin/named/server.c	Tue Apr 16 15:40:37 2013
@@ -1619,6 +1619,17 @@
 	rrl->responses_per_second = i;
 	rrl->scaled_responses_per_second = rrl->responses_per_second;
 
+	i = 0;
+	obj = NULL;
+	result = cfg_map_get(map, "cantdelegates-per-second", &obj);
+	if (result == ISC_R_SUCCESS) {
+		i = cfg_obj_asuint32(obj);
+		CHECK_RRL(obj, i <= DNS_RRL_MAX_RATE,
+			  "cantdelegates-per-second %d > %d",
+			  i, DNS_RRL_MAX_RATE);
+	}
+	rrl->cantdelegates_per_second = i;
+	rrl->scaled_cantdelegates_per_second = rrl->cantdelegates_per_second;
 	/*
 	 * The default error rate is the response rate,
 	 * and so off by default.
--- ../../ref/bind-9.9.2-P1/lib/dns/include/dns/result.h	Thu Oct 25 22:50:34 2012
+++ lib/dns/include/dns/result.h	Tue Apr 16 15:44:42 2013
@@ -152,8 +152,9 @@
 #define DNS_R_BROKENCHAIN		(ISC_RESULTCLASS_DNS + 106)
 #define DNS_R_EXPIRED			(ISC_RESULTCLASS_DNS + 107)
 #define DNS_R_NOTDYNAMIC 		(ISC_RESULTCLASS_DNS + 108)
+#define DNS_R_CANTDELEGATE 		(ISC_RESULTCLASS_DNS + 109)
 
-#define DNS_R_NRESULTS			109	/*%< Number of results */
+#define DNS_R_NRESULTS			110	/*%< Number of results */
 
 /*
  * DNS wire format rcodes.
--- ../../ref/bind-9.9.2-P1/lib/dns/include/dns/rrl.h	Tue Apr 16 21:00:42 2013
+++ lib/dns/include/dns/rrl.h	Tue Apr 16 15:45:22 2013
@@ -76,6 +76,7 @@
 	DNS_RRL_RTYPE_ERROR,
 	DNS_RRL_RTYPE_ALL,
 	DNS_RRL_RTYPE_TCP,
+	DNS_RRL_RTYPE_CANTDELEGATE,
 } dns_rrl_rtype_t;
 
 /*
@@ -200,6 +201,7 @@
 
 	isc_boolean_t	log_only;
 	int		responses_per_second;
+	int		cantdelegates_per_second;
 	int		errors_per_second;
 	int		nxdomains_per_second;
 	int		all_per_second;
@@ -216,6 +218,7 @@
 	isc_stdtime_t	qps_time;
 	double		qps;
 	int		scaled_responses_per_second;
+	int		scaled_cantdelegates_per_second;
 	int		scaled_errors_per_second;
 	int		scaled_nxdomains_per_second;
 	int		scaled_all_per_second;
--- ../../ref/bind-9.9.2-P1/lib/dns/rrl.c	Tue Apr 16 21:00:42 2013
+++ lib/dns/rrl.c	Tue Apr 16 19:44:32 2013
@@ -451,6 +451,9 @@
 		case DNS_RRL_RTYPE_DELEGATION:
 			rate = rrl->scaled_responses_per_second;
 			break;
+		case DNS_RRL_RTYPE_CANTDELEGATE:
+			rate = rrl->scaled_cantdelegates_per_second;
+			break;
 		case DNS_RRL_RTYPE_NXDOMAIN:
 			rate = rrl->scaled_nxdomains_per_second;
 			break;
@@ -612,6 +615,10 @@
 		rate = rrl->responses_per_second;
 		ratep = &rrl->scaled_responses_per_second;
 		break;
+	case DNS_RRL_RTYPE_CANTDELEGATE:
+		rate = rrl->cantdelegates_per_second;
+		ratep = &rrl->scaled_cantdelegates_per_second;
+		break;
 	case DNS_RRL_RTYPE_NXDOMAIN:
 		rate = rrl->nxdomains_per_second;
 		ratep = &rrl->scaled_nxdomains_per_second;
@@ -655,6 +662,9 @@
 				case DNS_RRL_RTYPE_DELEGATION:
 					rate_str = "responses-per-second";
 					break;
+				case DNS_RRL_RTYPE_CANTDELEGATE:
+					rate_str = "cantdelegates-per-second";
+					break;
 				case DNS_RRL_RTYPE_NXDOMAIN:
 					rate_str = "nxdomains-per-second";
 					break;
@@ -858,6 +868,9 @@
 	case DNS_RRL_RTYPE_DELEGATION:
 		ADD_LOG_CSTR(&lb, "referral");
 		break;
+	case DNS_RRL_RTYPE_CANTDELEGATE:
+		ADD_LOG_CSTR(&lb, "cannot refer response");
+		break;
 	case DNS_RRL_RTYPE_NXDOMAIN:
 		ADD_LOG_CSTR(&lb, "NXDOMAIN response");
 		break;
@@ -1121,6 +1134,8 @@
 		rtype = DNS_RRL_RTYPE_QUERY;
 	else if (resp_result == DNS_R_DELEGATION)
 		rtype = DNS_RRL_RTYPE_DELEGATION;
+	else if (resp_result == DNS_R_CANTDELEGATE)
+		rtype = DNS_RRL_RTYPE_CANTDELEGATE;
 	else if (resp_result == DNS_R_NXDOMAIN)
 		rtype = DNS_RRL_RTYPE_NXDOMAIN;
 	else
--- ../../ref/bind-9.9.2-P1/lib/isccfg/namedconf.c	Tue Apr 16 21:00:43 2013
+++ lib/isccfg/namedconf.c	Tue Apr 16 15:59:56 2013
@@ -1251,7 +1251,7 @@
 	{ "responses-per-second", &cfg_type_uint32, 0 },
 	{ "errors-per-second", &cfg_type_uint32, 0 },
 	{ "nxdomains-per-second", &cfg_type_uint32, 0 },
-	{ "responses-per-second", &cfg_type_uint32, 0 },
+	{ "cantdelegates-per-second", &cfg_type_uint32, 0 },
 	{ "all-per-second", &cfg_type_uint32, 0 },
 	{ "slip", &cfg_type_uint32, 0 },
 	{ "window", &cfg_type_uint32, 0 },


More information about the ratelimits mailing list