]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Introduce 'cache-min-negative-ttl' option to bound the minimum TTL for 1027/head
authorYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Tue, 12 Mar 2024 10:20:44 +0000 (11:20 +0100)
committerYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Tue, 12 Mar 2024 10:24:59 +0000 (11:24 +0100)
  negative answers overriding 'cache-min-ttl'.

doc/example.conf.in
doc/unbound.conf.5.in
testdata/ttl_max_negative.rpl [new file with mode: 0644]
testdata/ttl_min_negative.rpl [new file with mode: 0644]
util/config_file.c
util/config_file.h
util/configlexer.lex
util/configparser.y
util/data/msgparse.h
util/data/msgreply.c

index 1ac155b7c6eb0cdf13778b3fe47b1f15b37726ba..ed38953f320f6dc6fa6c9356dda4d46e8a6a7303 100644 (file)
@@ -211,6 +211,11 @@ server:
        # the time to live (TTL) value cap for negative responses in the cache
        # cache-max-negative-ttl: 3600
 
+       # the time to live (TTL) value lower bound, in seconds. Default 0.
+       # For negative responses in the cache. If disabled, default,
+       # cache-min-tll applies if configured.
+       # cache-min-negative-ttl: 0
+
        # the time to live (TTL) value for cached roundtrip times, lameness and
        # EDNS version information for hosts. In seconds.
        # infra-host-ttl: 900
index 84eddd941e816fef26924a72a870001f5bb81623..a3097f5c7e20f6a36c207a2d62cceaa3abae7ad0 100644 (file)
@@ -388,6 +388,15 @@ Time to live maximum for negative responses, these have a SOA in the
 authority section that is limited in time.  Default is 3600.
 This applies to nxdomain and nodata answers.
 .TP
+.B cache\-min\-negative\-ttl: \fI<seconds>
+Time to live minimum for negative responses, these have a SOA in the
+authority section that is limited in time.
+Default is 0 (disabled).
+If this is disabled and \fBcache-min-ttl\fR is configured, it will take effect
+instead.
+In that case you can set this to 1 to honor the upstream TTL.
+This applies to nxdomain and nodata answers.
+.TP
 .B infra\-host\-ttl: \fI<seconds>
 Time to live for entries in the host cache. The host cache contains
 roundtrip timing, lameness and EDNS support information. Default is 900.
diff --git a/testdata/ttl_max_negative.rpl b/testdata/ttl_max_negative.rpl
new file mode 100644 (file)
index 0000000..243b66f
--- /dev/null
@@ -0,0 +1,206 @@
+; config options
+server:
+       access-control: 127.0.0.1 allow_snoop
+       cache-max-ttl: 15  # This will be overriden
+       cache-max-negative-ttl: 10
+       qname-minimisation: "no"
+       minimal-responses: no
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test TTL max option for messages in the cache
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.gtld-servers.net.    IN A
+SECTION ANSWER
+a.gtld-servers.net.    IN A    192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+K.ROOT-SERVERS.NET.    IN      A
+SECTION ANSWER
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.gtld-servers.net.    IN AAAA
+SECTION AUTHORITY
+. 86400 IN SOA . . 20070304 28800 7200 604800 86400
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+K.ROOT-SERVERS.NET.    IN      AAAA
+SECTION AUTHORITY
+. 86400 IN SOA . . 20070304 28800 7200 604800 86400
+ENTRY_END
+
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.                IN      A       1.2.3.4
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NXDOMAIN
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com. 3600 IN SOA . . 15 28800 7200 604800 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION AUTHORITY
+example.com. 3600 IN SOA . . 15 28800 7200 604800 3600
+ENTRY_END
+
+RANGE_END
+
+; start by passing time ; so we are not at 0
+STEP 1 TIME_PASSES ELAPSE 10
+
+; query for the record
+STEP 8 QUERY
+ENTRY_BEGIN
+REPLY RD CD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD RA CD NXDOMAIN
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. 10 IN SOA . . 15 28800 7200 604800 3600
+ENTRY_END
+
+; wait
+STEP 20 TIME_PASSES ELAPSE 5
+
+; do a lookup to check TTLs.
+STEP 25 QUERY
+ENTRY_BEGIN
+REPLY
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+STEP 26 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RA NXDOMAIN
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. 5 IN SOA . . 15 28800 7200 604800 3600
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/ttl_min_negative.rpl b/testdata/ttl_min_negative.rpl
new file mode 100644 (file)
index 0000000..ece3366
--- /dev/null
@@ -0,0 +1,204 @@
+; config options
+server:
+       access-control: 127.0.0.1 allow_snoop
+       cache-min-ttl: 5  # This will be overriden
+       cache-min-negative-ttl: 10
+       qname-minimisation: "no"
+       minimal-responses: no
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test TTL min option for messages in the cache
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.gtld-servers.net.    IN A
+SECTION ANSWER
+a.gtld-servers.net.    IN A    192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+K.ROOT-SERVERS.NET.    IN      A
+SECTION ANSWER
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.gtld-servers.net.    IN AAAA
+SECTION AUTHORITY
+. 86400 IN SOA . . 20070304 28800 7200 604800 86400
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+K.ROOT-SERVERS.NET.    IN      AAAA
+SECTION AUTHORITY
+. 86400 IN SOA . . 20070304 28800 7200 604800 86400
+ENTRY_END
+
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.                IN      A       1.2.3.4
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NXDOMAIN
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com. 1 IN SOA . . 15 28800 7200 604800 1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION AUTHORITY
+example.com. 1 IN SOA . . 15 28800 7200 604800 1
+ENTRY_END
+
+RANGE_END
+
+; start by passing time ; so we are not at 0
+STEP 1 TIME_PASSES ELAPSE 10
+
+; query for the record
+STEP 8 QUERY
+ENTRY_BEGIN
+REPLY RD CD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD RA CD NXDOMAIN
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com. 10 IN SOA . . 15 28800 7200 604800 1
+ENTRY_END
+
+; wait for 7 seconds
+STEP 20 TIME_PASSES ELAPSE 7
+
+; do a lookup to check TTLs.
+STEP 25 QUERY
+ENTRY_BEGIN
+REPLY
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+STEP 26 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RA NXDOMAIN
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com. 3 IN SOA . . 15 28800 7200 604800 1
+ENTRY_END
+
+SCENARIO_END
index 26185da0203cef408a9908ac6adf12de57ef6c12..8ad83b90811676c1e6df4d309c774606717c285a 100644 (file)
@@ -174,6 +174,7 @@ config_create(void)
        cfg->min_ttl = 0;
        cfg->max_ttl = 3600 * 24;
        cfg->max_negative_ttl = 3600;
+       cfg->min_negative_ttl = 0;
        cfg->prefetch = 0;
        cfg->prefetch_key = 0;
        cfg->deny_any = 0;
@@ -615,6 +616,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
        { IS_NUMBER_OR_ZERO; cfg->max_ttl = atoi(val); MAX_TTL=(time_t)cfg->max_ttl;}
        else if(strcmp(opt, "cache-max-negative-ttl:") == 0)
        { IS_NUMBER_OR_ZERO; cfg->max_negative_ttl = atoi(val); MAX_NEG_TTL=(time_t)cfg->max_negative_ttl;}
+       else if(strcmp(opt, "cache-min-negative-ttl:") == 0)
+       { IS_NUMBER_OR_ZERO; cfg->min_negative_ttl = atoi(val); MIN_NEG_TTL=(time_t)cfg->min_negative_ttl;}
        else if(strcmp(opt, "cache-min-ttl:") == 0)
        { IS_NUMBER_OR_ZERO; cfg->min_ttl = atoi(val); MIN_TTL=(time_t)cfg->min_ttl;}
        else if(strcmp(opt, "infra-cache-min-rtt:") == 0) {
@@ -1065,6 +1068,7 @@ config_get_option(struct config_file* cfg, const char* opt,
        else O_YNO(opt, "deny-any", deny_any)
        else O_DEC(opt, "cache-max-ttl", max_ttl)
        else O_DEC(opt, "cache-max-negative-ttl", max_negative_ttl)
+       else O_DEC(opt, "cache-min-negative-ttl", min_negative_ttl)
        else O_DEC(opt, "cache-min-ttl", min_ttl)
        else O_DEC(opt, "infra-host-ttl", host_ttl)
        else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
@@ -2310,6 +2314,7 @@ config_apply(struct config_file* config)
        SERVE_EXPIRED_REPLY_TTL = (time_t)config->serve_expired_reply_ttl;
        SERVE_ORIGINAL_TTL = config->serve_original_ttl;
        MAX_NEG_TTL = (time_t)config->max_negative_ttl;
+       MIN_NEG_TTL = (time_t)config->min_negative_ttl;
        RTT_MIN_TIMEOUT = config->infra_cache_min_rtt;
        RTT_MAX_TIMEOUT = config->infra_cache_max_rtt;
        EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
index 491109833e4b3a6e2761d9ca332e32d8184b6a7c..faed1071e55f30ab8944dc465083955353e381c2 100644 (file)
@@ -315,6 +315,8 @@ struct config_file {
        int min_ttl;
        /** the number of seconds maximal negative TTL for SOA in auth */
        int max_negative_ttl;
+       /** the number of seconds minimal negative TTL for SOA in auth */
+       int min_negative_ttl;
        /** if prefetching of messages should be performed. */
        int prefetch;
        /** if prefetching of DNSKEYs should be performed. */
index e1ab76e25560f3b70c2a4c3dce0c0c32332fff71..65abfc5e0b9a495455d0163e39f532ccaa0b2145 100644 (file)
@@ -297,6 +297,7 @@ rrset-cache-size{COLON}             { YDVAR(1, VAR_RRSET_CACHE_SIZE) }
 rrset-cache-slabs{COLON}       { YDVAR(1, VAR_RRSET_CACHE_SLABS) }
 cache-max-ttl{COLON}           { YDVAR(1, VAR_CACHE_MAX_TTL) }
 cache-max-negative-ttl{COLON}   { YDVAR(1, VAR_CACHE_MAX_NEGATIVE_TTL) }
+cache-min-negative-ttl{COLON}   { YDVAR(1, VAR_CACHE_MIN_NEGATIVE_TTL) }
 cache-min-ttl{COLON}           { YDVAR(1, VAR_CACHE_MIN_TTL) }
 infra-host-ttl{COLON}          { YDVAR(1, VAR_INFRA_HOST_TTL) }
 infra-lame-ttl{COLON}          { YDVAR(1, VAR_INFRA_LAME_TTL) }
index 0e4cd5960a299fa49057498f3614a67376c655c0..4ca28d747eb06478f2406ba57612937cd3480156 100644 (file)
@@ -153,6 +153,7 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_MIN_CLIENT_SUBNET_IPV4 VAR_MIN_CLIENT_SUBNET_IPV6
 %token VAR_MAX_ECS_TREE_SIZE_IPV4 VAR_MAX_ECS_TREE_SIZE_IPV6
 %token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN
+%token VAR_CACHE_MIN_NEGATIVE_TTL
 %token VAR_QNAME_MINIMISATION VAR_QNAME_MINIMISATION_STRICT VAR_IP_FREEBIND
 %token VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG VAR_ACCESS_CONTROL_TAG
 %token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION
@@ -298,6 +299,7 @@ content_server: server_num_threads | server_verbosity | server_port |
        server_min_client_subnet_ipv4 | server_min_client_subnet_ipv6 |
        server_max_ecs_tree_size_ipv4 | server_max_ecs_tree_size_ipv6 |
        server_caps_whitelist | server_cache_max_negative_ttl |
+       server_cache_min_negative_ttl |
        server_permit_small_holddown | server_qname_minimisation |
        server_ip_freebind | server_define_tag | server_local_zone_tag |
        server_disable_dnssec_lame_check | server_access_control_tag |
@@ -2014,6 +2016,15 @@ server_cache_max_negative_ttl: VAR_CACHE_MAX_NEGATIVE_TTL STRING_ARG
                free($2);
        }
        ;
+server_cache_min_negative_ttl: VAR_CACHE_MIN_NEGATIVE_TTL STRING_ARG
+       {
+               OUTYY(("P(server_cache_min_negative_ttl:%s)\n", $2));
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               else cfg_parser->cfg->min_negative_ttl = atoi($2);
+               free($2);
+       }
+       ;
 server_cache_min_ttl: VAR_CACHE_MIN_TTL STRING_ARG
        {
                OUTYY(("P(server_cache_min_ttl:%s)\n", $2));
index 8e5c94a28cba7e17d6e279b152fac4c24c55a7be..656e0d285dcdc974cd8015388eae60324fd63ad5 100644 (file)
@@ -82,6 +82,8 @@ extern time_t MAX_TTL;
 extern time_t MIN_TTL;
 /** Maximum Negative TTL that is allowed */
 extern time_t MAX_NEG_TTL;
+/** Minimum Negative TTL that is allowed */
+extern time_t MIN_NEG_TTL;
 /** If we serve expired entries and prefetch them */
 extern int SERVE_EXPIRED;
 /** Time to serve records after expiration */
index 2286d46bc3ff43133aa3e4b2fa9de22b7979cc75..c9d7bbf3ad4730d3de1dd4d038d951445f9e7996 100644 (file)
@@ -61,6 +61,8 @@ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
 time_t MIN_TTL = 0;
 /** MAX Negative TTL, for SOA records in authority section */
 time_t MAX_NEG_TTL = 3600; /* one hour */
+/** MIN Negative TTL, for SOA records in authority section */
+time_t MIN_NEG_TTL = 0;
 /** If we serve expired entries and prefetch them */
 int SERVE_EXPIRED = 0;
 /** Time to serve records after expiration */
@@ -223,18 +225,25 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
        if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
                /* negative response. see if TTL of SOA record larger than the
                 * minimum-ttl in the rdata of the SOA record */
-               if(*rr_ttl > soa_find_minttl(rr))
-                       *rr_ttl = soa_find_minttl(rr);
-       }
-       if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL))
-               *rr_ttl = MIN_TTL;
-       if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL))
-               *rr_ttl = MAX_TTL;
-       if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
-               /* max neg ttl overrides the min and max ttl of everything
-                * else, it is for a more specific record */
-               if(*rr_ttl > MAX_NEG_TTL)
-                       *rr_ttl = MAX_NEG_TTL;
+               if(*rr_ttl > soa_find_minttl(rr)) *rr_ttl = soa_find_minttl(rr);
+               if(!SERVE_ORIGINAL_TTL) {
+                       /* If MIN_NEG_TTL is configured skip setting MIN_TTL */
+                       if(MIN_NEG_TTL <= 0 && *rr_ttl < MIN_TTL) {
+                               *rr_ttl = MIN_TTL;
+                       }
+                       if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL;
+               }
+               /* MAX_NEG_TTL overrides the min and max ttl of everything
+                * else; it is for a more specific record */
+               if(*rr_ttl > MAX_NEG_TTL) *rr_ttl = MAX_NEG_TTL;
+               /* MIN_NEG_TTL overrides the min and max ttl of everything
+                * else if configured; it is for a more specific record */
+               if(MIN_NEG_TTL > 0 && *rr_ttl < MIN_NEG_TTL) {
+                       *rr_ttl = MIN_NEG_TTL;
+               }
+       } else if(!SERVE_ORIGINAL_TTL) {
+               if(*rr_ttl < MIN_TTL) *rr_ttl = MIN_TTL;
+               if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL;
        }
        if(*rr_ttl < data->ttl)
                data->ttl = *rr_ttl;