Blame SOURCES/unbound-1.4.20-cache-max-negative-ttl.patch

0f4e4e
From e1132a3a41d2ff5a9479bbb629d73db4856a5f34 Mon Sep 17 00:00:00 2001
0f4e4e
From: Tomas Hozza <thozza@redhat.com>
0f4e4e
Date: Tue, 11 Oct 2016 15:38:58 +0200
0f4e4e
Subject: [PATCH] Add cache-max-negative-ttl option
0f4e4e
0f4e4e
https://github.com/thozza/unbound/commit/0ef133ea5819fbf7518de9c8492c5e05c95ac8ce
0f4e4e
0f4e4e
git-svn-id: http://unbound.nlnetlabs.nl/svn/trunk@3431 be551aaa-1e26-0410-a405-d3ace91eadb9
0f4e4e
Signed-off-by: Tomas Hozza <thozza@redhat.com>
0f4e4e
---
0f4e4e
 doc/example.conf.in                    |  3 +++
0f4e4e
 doc/unbound-control.8.in               |  2 +-
0f4e4e
 doc/unbound.conf.5.in                  |  4 ++++
0f4e4e
 testcode/unitmsgparse.c                |  3 +++
0f4e4e
 testdata/iter_domain_sale.rpl          |  3 ++-
0f4e4e
 testdata/iter_domain_sale_nschange.rpl |  6 ++++--
0f4e4e
 util/config_file.c                     |  5 +++++
0f4e4e
 util/config_file.h                     |  2 ++
0f4e4e
 util/configlexer.lex                   |  1 +
0f4e4e
 util/configparser.y                    | 12 +++++++++++-
0f4e4e
 util/data/msgparse.h                   |  2 ++
0f4e4e
 util/data/msgreply.c                   | 29 ++++++++++++++++++++++++++---
0f4e4e
 12 files changed, 64 insertions(+), 8 deletions(-)
0f4e4e
0f4e4e
diff --git a/doc/example.conf.in b/doc/example.conf.in
0f4e4e
index aa9a7f7..52cad67 100644
0f4e4e
--- a/doc/example.conf.in
0f4e4e
+++ b/doc/example.conf.in
0f4e4e
@@ -125,6 +125,9 @@ server:
0f4e4e
 	# cache. Items are not cached for longer. In seconds.
0f4e4e
 	# cache-max-ttl: 86400
0f4e4e
 
0f4e4e
+	# the time to live (TTL) value cap for negative responses in the cache
0f4e4e
+	# cache-max-negative-ttl: 3600
0f4e4e
+
0f4e4e
 	# the time to live (TTL) value for cached roundtrip times, lameness and
0f4e4e
 	# EDNS version information for hosts. In seconds.
0f4e4e
 	# infra-host-ttl: 900
0f4e4e
diff --git a/doc/unbound-control.8.in b/doc/unbound-control.8.in
0f4e4e
index 669e81d..f2c76eb 100644
0f4e4e
--- a/doc/unbound-control.8.in
0f4e4e
+++ b/doc/unbound-control.8.in
0f4e4e
@@ -170,7 +170,7 @@ harden\-glue, harden\-dnssec\-stripped, harden\-below\-nxdomain,
0f4e4e
 harden\-referral\-path, prefetch, prefetch\-key, log\-queries,
0f4e4e
 hide\-identity, hide\-version, identity, version, val\-log\-level,
0f4e4e
 val\-log\-squelch, ignore\-cd\-flag, add\-holddown, del\-holddown,
0f4e4e
-keep\-missing, tcp\-upstream, ssl\-upstream.
0f4e4e
+keep\-missing, tcp\-upstream, ssl\-upstream, cache\-max\-negative\-ttl.
0f4e4e
 .TP
0f4e4e
 .B get_option \fIopt
0f4e4e
 Get the value of the option.  Give the option name without a trailing ':'.
0f4e4e
diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in
0f4e4e
index 6dd0216..7485345 100644
0f4e4e
--- a/doc/unbound.conf.5.in
0f4e4e
+++ b/doc/unbound.conf.5.in
0f4e4e
@@ -267,6 +267,10 @@ Zero makes sure the data in the cache is as the domain owner intended,
0f4e4e
 higher values, especially more than an hour or so, can lead to trouble as 
0f4e4e
 the data in the cache does not match up with the actual data any more.
0f4e4e
 .TP
0f4e4e
+.B cache\-max\-negative\-ttl: \fI<seconds>
0f4e4e
+Time to live maximum for negative responses, these have a SOA in the
0f4e4e
+authority section that is limited in time.  Default is 3600.
0f4e4e
+.TP
0f4e4e
 .B infra\-host\-ttl: \fI<seconds>
0f4e4e
 Time to live for entries in the host cache. The host cache contains 
0f4e4e
 roundtrip timing, lameness and EDNS support information. Default is 900.
0f4e4e
diff --git a/testcode/unitmsgparse.c b/testcode/unitmsgparse.c
0f4e4e
index 4342395..08f3b50 100644
0f4e4e
--- a/testcode/unitmsgparse.c
0f4e4e
+++ b/testcode/unitmsgparse.c
0f4e4e
@@ -582,9 +582,11 @@ testfromdrillfile(ldns_buffer* pkt, struct alloc_cache* alloc,
0f4e4e
 
0f4e4e
 void msgparse_test(void)
0f4e4e
 {
0f4e4e
+	uint32_t origttl = MAX_NEG_TTL;
0f4e4e
 	ldns_buffer* pkt = ldns_buffer_new(65553);
0f4e4e
 	ldns_buffer* out = ldns_buffer_new(65553);
0f4e4e
 	struct alloc_cache super_a, alloc;
0f4e4e
+	MAX_NEG_TTL = 86400;
0f4e4e
 	/* init */
0f4e4e
 	alloc_init(&super_a, NULL, 0);
0f4e4e
 	alloc_init(&alloc, &super_a, 2);
0f4e4e
@@ -621,4 +623,5 @@ void msgparse_test(void)
0f4e4e
 	alloc_clear(&super_a);
0f4e4e
 	ldns_buffer_free(pkt);
0f4e4e
 	ldns_buffer_free(out);
0f4e4e
+	MAX_NEG_TTL = origttl;
0f4e4e
 }
0f4e4e
diff --git a/testdata/iter_domain_sale.rpl b/testdata/iter_domain_sale.rpl
0f4e4e
index 724b51d..ff61278 100644
0f4e4e
--- a/testdata/iter_domain_sale.rpl
0f4e4e
+++ b/testdata/iter_domain_sale.rpl
0f4e4e
@@ -238,7 +238,8 @@ SECTION QUESTION
0f4e4e
 nx1.example.com. IN A
0f4e4e
 SECTION ANSWER
0f4e4e
 SECTION AUTHORITY
0f4e4e
-example.com.	3600 IN SOA	a. b. 1 2 3 4 5
0f4e4e
+; at TTL 5 because TTL is capped at min-ttl of 5 in rdata of SOA
0f4e4e
+example.com.	5 IN SOA	a. b. 1 2 3 4 5
0f4e4e
 example.com.	1800 IN NS	ns.example.com.
0f4e4e
 SECTION ADDITIONAL
0f4e4e
 ns.example.com.	1800 	IN 	A	1.2.3.4
0f4e4e
diff --git a/testdata/iter_domain_sale_nschange.rpl b/testdata/iter_domain_sale_nschange.rpl
0f4e4e
index a7d9f11..bc396f6 100644
0f4e4e
--- a/testdata/iter_domain_sale_nschange.rpl
0f4e4e
+++ b/testdata/iter_domain_sale_nschange.rpl
0f4e4e
@@ -285,7 +285,8 @@ SECTION QUESTION
0f4e4e
 nx1.example.com. IN A
0f4e4e
 SECTION ANSWER
0f4e4e
 SECTION AUTHORITY
0f4e4e
-example.com.	3600 IN SOA	a. b. 1 2 3 4 5
0f4e4e
+; at TTL 5 because TTL capped at ttl of minttl in rdata of SOA.
0f4e4e
+example.com.	5 IN SOA	a. b. 1 2 3 4 5
0f4e4e
 example.com.	3600 IN NS	nsb.example.com.
0f4e4e
 SECTION ADDITIONAL
0f4e4e
 nsb.example.com.	3600 	IN 	A	1.2.3.4
0f4e4e
@@ -306,7 +307,8 @@ SECTION QUESTION
0f4e4e
 nx1.example.com. IN A
0f4e4e
 SECTION ANSWER
0f4e4e
 SECTION AUTHORITY
0f4e4e
-example.com.	3600 IN SOA	a. b. 1 2 3 4 5
0f4e4e
+; at TTL 5 because TTL capped at ttl of minttl in rdata of SOA.
0f4e4e
+example.com.	5 IN SOA	a. b. 1 2 3 4 5
0f4e4e
 example.com.	1800 IN NS	nsb.example.com.
0f4e4e
 SECTION ADDITIONAL
0f4e4e
 nsb.example.com.	3600 	IN 	A	1.2.3.4
0f4e4e
diff --git a/util/config_file.c b/util/config_file.c
0f4e4e
index b946f0d..4e0fbe7 100644
0f4e4e
--- a/util/config_file.c
0f4e4e
+++ b/util/config_file.c
0f4e4e
@@ -128,6 +128,7 @@ config_create(void)
0f4e4e
 	cfg->bogus_ttl = 60;
0f4e4e
 	cfg->min_ttl = 0;
0f4e4e
 	cfg->max_ttl = 3600 * 24;
0f4e4e
+	cfg->max_negative_ttl = 3600;
0f4e4e
 	cfg->prefetch = 0;
0f4e4e
 	cfg->prefetch_key = 0;
0f4e4e
 	cfg->infra_cache_slabs = 4;
0f4e4e
@@ -359,6 +360,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
0f4e4e
 	else S_YNO("prefetch:", prefetch)
0f4e4e
 	else S_YNO("prefetch-key:", prefetch_key)
0f4e4e
 	else S_NUMBER_OR_ZERO("cache-max-ttl:", max_ttl)
0f4e4e
+	else if(strcmp(opt, "cache-max-negative-ttl:") == 0)
0f4e4e
+	{ IS_NUMBER_OR_ZERO; cfg->max_negative_ttl = atoi(val); MAX_NEG_TTL=cfg->max_negative_ttl;}
0f4e4e
 	else S_NUMBER_OR_ZERO("infra-host-ttl:", host_ttl)
0f4e4e
 	else S_POW2("infra-cache-slabs:", infra_cache_slabs)
0f4e4e
 	else S_SIZET_NONZERO("infra-cache-numhosts:", infra_cache_numhosts)
0f4e4e
@@ -593,6 +596,7 @@ config_get_option(struct config_file* cfg, const char* opt,
0f4e4e
 	else O_YNO(opt, "prefetch-key", prefetch_key)
0f4e4e
 	else O_YNO(opt, "prefetch", prefetch)
0f4e4e
 	else O_DEC(opt, "cache-max-ttl", max_ttl)
0f4e4e
+	else O_DEC(opt, "cache-max-negative-ttl", max_negative_ttl)
0f4e4e
 	else O_DEC(opt, "infra-host-ttl", host_ttl)
0f4e4e
 	else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
0f4e4e
 	else O_MEM(opt, "infra-cache-numhosts", infra_cache_numhosts)
0f4e4e
@@ -1149,6 +1153,7 @@ config_apply(struct config_file* config)
0f4e4e
 {
0f4e4e
 	MAX_TTL = (uint32_t)config->max_ttl;
0f4e4e
 	MIN_TTL = (uint32_t)config->min_ttl;
0f4e4e
+	MAX_NEG_TTL = (uint32_t)config->max_negative_ttl;
0f4e4e
 	EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
0f4e4e
 	MINIMAL_RESPONSES = config->minimal_responses;
0f4e4e
 	RRSET_ROUNDROBIN = config->rrset_roundrobin;
0f4e4e
diff --git a/util/config_file.h b/util/config_file.h
0f4e4e
index 69595cb..4d493b8 100644
0f4e4e
--- a/util/config_file.h
0f4e4e
+++ b/util/config_file.h
0f4e4e
@@ -179,6 +179,8 @@ struct config_file {
0f4e4e
 	int max_ttl;
0f4e4e
 	/** the number of seconds minimum TTL used for RRsets and messages */
0f4e4e
 	int min_ttl;
0f4e4e
+	/** the number of seconds maximal negative TTL for SOA in auth */
0f4e4e
+	int max_negative_ttl;
0f4e4e
 	/** if prefetching of messages should be performed. */
0f4e4e
 	int prefetch;
0f4e4e
 	/** if prefetching of DNSKEYs should be performed. */
0f4e4e
diff --git a/util/configlexer.lex b/util/configlexer.lex
0f4e4e
index 4694cdd..079f195 100644
0f4e4e
--- a/util/configlexer.lex
0f4e4e
+++ b/util/configlexer.lex
0f4e4e
@@ -208,6 +208,7 @@ msg-cache-slabs{COLON}		{ YDVAR(1, VAR_MSG_CACHE_SLABS) }
0f4e4e
 rrset-cache-size{COLON}		{ YDVAR(1, VAR_RRSET_CACHE_SIZE) }
0f4e4e
 rrset-cache-slabs{COLON}	{ YDVAR(1, VAR_RRSET_CACHE_SLABS) }
0f4e4e
 cache-max-ttl{COLON}     	{ YDVAR(1, VAR_CACHE_MAX_TTL) }
0f4e4e
+cache-max-negative-ttl{COLON}   { YDVAR(1, VAR_CACHE_MAX_NEGATIVE_TTL) }
0f4e4e
 cache-min-ttl{COLON}     	{ YDVAR(1, VAR_CACHE_MIN_TTL) }
0f4e4e
 infra-host-ttl{COLON}		{ YDVAR(1, VAR_INFRA_HOST_TTL) }
0f4e4e
 infra-lame-ttl{COLON}		{ YDVAR(1, VAR_INFRA_LAME_TTL) }
0f4e4e
diff --git a/util/configparser.y b/util/configparser.y
0f4e4e
index 0dbee2b..7d7147d 100644
0f4e4e
--- a/util/configparser.y
0f4e4e
+++ b/util/configparser.y
0f4e4e
@@ -105,6 +105,7 @@ extern struct config_parser_state* cfg_parser;
0f4e4e
 %token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
0f4e4e
 %token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
0f4e4e
 %token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN
0f4e4e
+%token VAR_CACHE_MAX_NEGATIVE_TTL
0f4e4e
 
0f4e4e
 %%
0f4e4e
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
0f4e4e
@@ -161,7 +162,7 @@ content_server: server_num_threads | server_verbosity | server_port |
0f4e4e
 	server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag |
0f4e4e
 	server_log_queries | server_tcp_upstream | server_ssl_upstream |
0f4e4e
 	server_ssl_service_key | server_ssl_service_pem | server_ssl_port |
0f4e4e
-	server_minimal_responses | server_rrset_roundrobin
0f4e4e
+	server_minimal_responses | server_rrset_roundrobin | server_cache_max_negative_ttl
0f4e4e
 	;
0f4e4e
 stubstart: VAR_STUB_ZONE
0f4e4e
 	{
0f4e4e
@@ -934,6 +935,15 @@ server_cache_max_ttl: VAR_CACHE_MAX_TTL STRING_ARG
0f4e4e
 		free($2);
0f4e4e
 	}
0f4e4e
 	;
0f4e4e
+server_cache_max_negative_ttl: VAR_CACHE_MAX_NEGATIVE_TTL STRING_ARG
0f4e4e
+	{
0f4e4e
+		OUTYY(("P(server_cache_max_negative_ttl:%s)\n", $2));
0f4e4e
+		if(atoi($2) == 0 && strcmp($2, "0") != 0)
0f4e4e
+			yyerror("number expected");
0f4e4e
+		else cfg_parser->cfg->max_negative_ttl = atoi($2);
0f4e4e
+		free($2);
0f4e4e
+	}
0f4e4e
+	;
0f4e4e
 server_cache_min_ttl: VAR_CACHE_MIN_TTL STRING_ARG
0f4e4e
 	{
0f4e4e
 		OUTYY(("P(server_cache_min_ttl:%s)\n", $2));
0f4e4e
diff --git a/util/data/msgparse.h b/util/data/msgparse.h
0f4e4e
index 830d68e..825d368 100644
0f4e4e
--- a/util/data/msgparse.h
0f4e4e
+++ b/util/data/msgparse.h
0f4e4e
@@ -74,6 +74,8 @@ struct regional;
0f4e4e
 extern uint32_t MAX_TTL;
0f4e4e
 /** Minimum TTL that is allowed. */
0f4e4e
 extern uint32_t MIN_TTL;
0f4e4e
+/** Maximum Negative TTL that is allowed */
0f4e4e
+extern uint32_t MAX_NEG_TTL;
0f4e4e
 /** Negative cache time (for entries without any RRs.) */
0f4e4e
 #define NORR_TTL 5 /* seconds */
0f4e4e
 
0f4e4e
diff --git a/util/data/msgreply.c b/util/data/msgreply.c
0f4e4e
index 6d711ff..dce724d 100644
0f4e4e
--- a/util/data/msgreply.c
0f4e4e
+++ b/util/data/msgreply.c
0f4e4e
@@ -56,6 +56,8 @@
0f4e4e
 uint32_t MAX_TTL = 3600 * 24 * 10; /* ten days */
0f4e4e
 /** MIN TTL default for messages and rrsets */
0f4e4e
 uint32_t MIN_TTL = 0;
0f4e4e
+/** MAX Negative TTL, for SOA records in authority section */
0f4e4e
+uint32_t MAX_NEG_TTL = 3600; /* one hour */
0f4e4e
 
0f4e4e
 /** allocate qinfo, return 0 on error */
0f4e4e
 static int
0f4e4e
@@ -151,10 +153,23 @@ repinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
0f4e4e
 	return 1;
0f4e4e
 }
0f4e4e
 
0f4e4e
+/** find the minimumttl in the rdata of SOA record */
0f4e4e
+static uint32_t
0f4e4e
+soa_find_minttl(struct rr_parse* rr)
0f4e4e
+{
0f4e4e
+	uint16_t rlen = ldns_read_uint16(rr->ttl_data+4);
0f4e4e
+	if(rlen < 20)
0f4e4e
+		return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */
0f4e4e
+	/* minimum TTL is the last 32bit value in the rdata of the record */
0f4e4e
+	/* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/
0f4e4e
+	return ldns_read_uint32(rr->ttl_data+6+rlen-4);
0f4e4e
+}
0f4e4e
+
0f4e4e
 /** do the rdata copy */
0f4e4e
 static int
0f4e4e
 rdata_copy(ldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 
0f4e4e
-	struct rr_parse* rr, uint32_t* rr_ttl, uint16_t type)
0f4e4e
+	struct rr_parse* rr, uint32_t* rr_ttl, uint16_t type,
0f4e4e
+	ldns_pkt_section section)
0f4e4e
 {
0f4e4e
 	uint16_t pkt_len;
0f4e4e
 	const ldns_rr_descriptor* desc;
0f4e4e
@@ -163,6 +178,14 @@ rdata_copy(ldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
0f4e4e
 	/* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
0f4e4e
 	if(*rr_ttl & 0x80000000U)
0f4e4e
 		*rr_ttl = 0;
0f4e4e
+	if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
0f4e4e
+		/* negative response. see if TTL of SOA record larger than the
0f4e4e
+		 * minimum-ttl in the rdata of the SOA record */
0f4e4e
+		if(*rr_ttl > soa_find_minttl(rr))
0f4e4e
+			*rr_ttl = soa_find_minttl(rr);
0f4e4e
+		if(*rr_ttl > MAX_NEG_TTL)
0f4e4e
+			*rr_ttl = MAX_NEG_TTL;
0f4e4e
+	}
0f4e4e
 	if(*rr_ttl < MIN_TTL)
0f4e4e
 		*rr_ttl = MIN_TTL;
0f4e4e
 	if(*rr_ttl < data->ttl)
0f4e4e
@@ -252,7 +275,7 @@ parse_rr_copy(ldns_buffer* pkt, struct rrset_parse* pset,
0f4e4e
 		data->rr_data[i] = nextrdata;
0f4e4e
 		nextrdata += rr->size;
0f4e4e
 		if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
0f4e4e
-			&data->rr_ttl[i], pset->type))
0f4e4e
+			&data->rr_ttl[i], pset->type, pset->section))
0f4e4e
 			return 0;
0f4e4e
 		rr = rr->next;
0f4e4e
 	}
0f4e4e
@@ -263,7 +286,7 @@ parse_rr_copy(ldns_buffer* pkt, struct rrset_parse* pset,
0f4e4e
 		data->rr_data[i] = nextrdata;
0f4e4e
 		nextrdata += rr->size;
0f4e4e
 		if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
0f4e4e
-			&data->rr_ttl[i], LDNS_RR_TYPE_RRSIG))
0f4e4e
+			&data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section))
0f4e4e
 			return 0;
0f4e4e
 		rr = rr->next;
0f4e4e
 	}
0f4e4e
-- 
0f4e4e
2.7.4
0f4e4e