]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix TTL of SOA record for negative answers (localzone data and
authorGeorge Thessalonikefs <george@nlnetlabs.nl>
Tue, 19 Jan 2021 11:15:18 +0000 (12:15 +0100)
committerGeorge Thessalonikefs <george@nlnetlabs.nl>
Tue, 19 Jan 2021 14:55:55 +0000 (15:55 +0100)
  authzone) to be the minimum of the SOA TTL and the SOA.MINIMUM.

services/authzone.c
services/localzone.c
services/localzone.h
testdata/auth_zonefile_down.rpl
testdata/localdata.rpl

index 3ad38865e35d13d53aba30c791024e6dcc59f815..3d7f49388cd94af795b71eddd952590e50695140 100644 (file)
@@ -2331,7 +2331,8 @@ static int
 az_add_negative_soa(struct auth_zone* z, struct regional* region,
        struct dns_msg* msg)
 {
-       uint32_t minimum;
+       time_t minimum;
+       size_t i;
        struct packed_rrset_data* d;
        struct auth_rrset* soa;
        struct auth_data* apex = az_find_name(z, z->name, z->namelen);
@@ -2348,9 +2349,11 @@ az_add_negative_soa(struct auth_zone* z, struct regional* region,
        /* last 4 bytes are minimum ttl in network format */
        if(d->count == 0) return 0;
        if(d->rr_len[0] < 2+4) return 0;
-       minimum = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-4));
-       d->ttl = (time_t)minimum;
-       d->rr_ttl[0] = (time_t)minimum;
+       minimum = (time_t)sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-4));
+       minimum = d->ttl<minimum?d->ttl:minimum;
+       d->ttl = minimum;
+       for(i=0; i < d->count + d->rrsig_count; i++)
+               d->rr_ttl[i] = minimum;
        msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[0]);
        msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
        msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
index ed0d2c56558790206ef372e9bbeab66fd9612af5..00067705edbf5c853d1ed2d01b703d75df8aec2b 100644 (file)
@@ -463,6 +463,48 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
        return 1;
 }
 
+/* Mark the SOA record for the zone. This only marks the SOA rrset; the data
+ * for the RR is entered later on local_zone_enter_rr() as with the other
+ * records. An artifical soa_negative record with a modified TTL (minimum of
+ * the TTL and the SOA.MINIMUM) is also created and marked for usage with
+ * negative answers and to avoid allocations during those answers. */
+static int
+lz_mark_soa_for_zone(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset,
+       uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr)
+{
+       struct packed_rrset_data* pd = (struct packed_rrset_data*)
+               regional_alloc_zero(z->region, sizeof(*pd));
+       struct ub_packed_rrset_key* rrset_negative = (struct ub_packed_rrset_key*)
+               regional_alloc_zero(z->region, sizeof(*rrset_negative));
+       time_t minimum;
+       if(!rrset_negative||!pd) {
+               log_err("out of memory");
+               return 0;
+       }
+       /* Mark the original SOA record and then continue with the negative one. */
+       z->soa = soa_rrset;
+       rrset_negative->entry.key = rrset_negative;
+       pd->trust = rrset_trust_prim_noglue;
+       pd->security = sec_status_insecure;
+       rrset_negative->entry.data = pd;
+       rrset_negative->rk.dname = soa_rrset->rk.dname;
+       rrset_negative->rk.dname_len = soa_rrset->rk.dname_len;
+       rrset_negative->rk.type = soa_rrset->rk.type;
+       rrset_negative->rk.rrset_class = soa_rrset->rk.rrset_class;
+       if(!rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr))
+               return 0;
+       /* last 4 bytes are minimum ttl in network format */
+       if(pd->count == 0 || pd->rr_len[0] < 2+4) {
+               return 0;
+       }
+       minimum = (time_t)sldns_read_uint32(pd->rr_data[0]+(pd->rr_len[0]-4));
+       pd->ttl = ttl<minimum?ttl:minimum;
+       pd->rr_ttl[0] = pd->ttl;
+
+       z->soa_negative = rrset_negative;
+       return 1;
+}
+
 int
 local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
        int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
@@ -502,8 +544,10 @@ local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
                if(query_dname_compare(node->name, z->name) == 0) {
                        if(rrtype == LDNS_RR_TYPE_NSEC)
                          rrset->rrset->rk.flags = PACKED_RRSET_NSEC_AT_APEX;
-                       if(rrtype == LDNS_RR_TYPE_SOA)
-                               z->soa = rrset->rrset;
+                       if(rrtype == LDNS_RR_TYPE_SOA &&
+                               !lz_mark_soa_for_zone(z, rrset->rrset, rdata, rdata_len, ttl,
+                                       rrstr))
+                               return 0;
                }
        } 
        pd = (struct packed_rrset_data*)rrset->rrset->entry.data;
@@ -1548,9 +1592,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                        lz_type == local_zone_inform_redirect ||
                        lz_type == local_zone_always_nodata)?
                        LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
-               if(z->soa)
+               if(z->soa && z->soa_negative)
                        return local_encode(qinfo, env, edns, repinfo, buf, temp,
-                               z->soa, 0, rcode);
+                               z->soa_negative, 0, rcode);
                local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
                        (rcode|BIT_AA));
                return 1;
@@ -1605,9 +1649,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
         * does not, then we should make this noerror/nodata */
        if(ld && ld->rrsets) {
                int rcode = LDNS_RCODE_NOERROR;
-               if(z->soa)
+               if(z->soa && z->soa_negative)
                        return local_encode(qinfo, env, edns, repinfo, buf, temp,
-                               z->soa, 0, rcode);
+                               z->soa_negative, 0, rcode);
                local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
                        (rcode|BIT_AA));
                return 1;
@@ -2045,6 +2089,7 @@ void local_zones_del_data(struct local_zones* zones,
                /* did we delete the soa record ? */
                if(query_dname_compare(d->name, z->name) == 0)
                        z->soa = NULL;
+                       z->soa_negative = NULL;
 
                /* cleanup the empty nonterminals for this name */
                del_empty_term(z, d, name, len, labs);
index 492629936dad04152b0e39c26fde3c37851f365d..3da5c8754bf3fab5eff23c25131dcfc1f4e49c37 100644 (file)
@@ -158,6 +158,10 @@ struct local_zone {
        rbtree_type data;
        /** if data contains zone apex SOA data, this is a ptr to it. */
        struct ub_packed_rrset_key* soa;
+       /** if data contains zone apex SOA data, this is a prt to an
+        * artificial negative SOA rrset (TTL is the minimum of the TTL and the
+        * SOA.MINIMUM). */
+       struct ub_packed_rrset_key* soa_negative;
 };
 
 /**
index 09e7fd061407b97560947e489d3504b129939d17..2b17c8433581db4a8faced140b8ee81ff2508542 100644 (file)
@@ -1,6 +1,12 @@
 ; config options
 server:
        target-fetch-policy: "0 0 0 0 0"
+       ; Options for singed zone. The zone is partially copied from val_negcache_nxdomain.rpl
+       trust-anchor: "testzone.nlnetlabs.nl.   IN      DS      2926 8 2 6f8512d1e82eecbd684fc4a76f39f8c5b411af385494873bdead663ddb78a88b"
+       val-override-date: "20180213111425"
+       qname-minimisation: "no"
+       trust-anchor-signaling: no
+       aggressive-nsec: yes
 
 auth-zone:
        name: "example.com."
@@ -41,6 +47,50 @@ ns1  3600    IN      A       1.2.3.4
 ns2    3600    IN      AAAA    ::2
 TEMPFILE_END
 
+auth-zone:
+       name: "soa.high.com."
+       for-downstream: yes
+       for-upstream: no
+       zonefile:
+TEMPFILE_NAME soa.high.com
+TEMPFILE_CONTENTS soa.high.com
+$ORIGIN high.com.
+soa    500     IN      SOA     dns.example.de. hostmaster.dns.example.de. (
+               1379078166 28800 7200 604800 200 )
+       3600    IN      NS      ns1.example.com.
+       3600    IN      NS      ns2.example.com.
+TEMPFILE_END
+
+auth-zone:
+       name: "soa.low.com."
+       for-downstream: yes
+       for-upstream: no
+       zonefile:
+TEMPFILE_NAME soa.low.com
+TEMPFILE_CONTENTS soa.low.com
+$ORIGIN low.com.
+soa    200     IN      SOA     dns.example.de. hostmaster.dns.example.de. (
+               1379078166 28800 7200 604800 500 )
+       3600    IN      NS      ns1.example.com.
+       3600    IN      NS      ns2.example.com.
+TEMPFILE_END
+
+auth-zone:
+       name: "testzone.nlnetlabs.nl."
+       for-downstream: yes
+       for-upstream: no
+       zonefile:
+TEMPFILE_NAME testzone.nlnetlabs.nl
+TEMPFILE_CONTENTS testzone.nlnetlabs.nl
+$ORIGIN testzone.nlnetlabs.nl.
+testzone.nlnetlabs.nl.  3600    IN      NSEC    alligator.testzone.nlnetlabs.nl. NS SOA RRSIG NSEC DNSKEY
+testzone.nlnetlabs.nl.  3600    IN      RRSIG   NSEC 8 3 3600 20180313102201 20180213102201 44940 testzone.nlnetlabs.nl. gTKn6U1nal9oA79IRxLa/7zexl6A0yJZzeEGBbZ5rh5feyAr2X4LTR9bPCgcHeMVggf4FP+kD1L/sxzj/YLwB1ZKGKlwnzsHtPFTlmvDClaqQ76DRZq5Vejr2ZfnclBUb2vtxaXywTRW8oueaaq9flcShEQ/cQ+KRU8sc344qd0=
+alligator.testzone.nlnetlabs.nl.        3600    IN      NSEC    cheetah.testzone.nlnetlabs.nl. TXT RRSIG NSEC
+alligator.testzone.nlnetlabs.nl.        3600    IN      RRSIG   NSEC 8 4 3600 20180313102201 20180213102201 44940 testzone.nlnetlabs.nl. QAgQ0AsMoYG02+VPfoOctSPlTHdQOkQt5fFkSkzIbVhUzNOqa+dB/Qkc81AwFeJosA+PvYjt6utcVkIWmK2Djy9eXC49gILtVF79vUe4G7ZrybO5NXjqNa5ANoUGM+yew4wkjeNOMVAsvs+1kvFY7S8RAa/0AIYlZHQ8vNBPNaI=
+testzone.nlnetlabs.nl.  4600    IN      SOA     ns.nlnetlabs.nl. ralph.nlnetlabs.nl. 1 14400 3600 604800 3600
+testzone.nlnetlabs.nl.  4600    IN      RRSIG   SOA 8 3 3600 20180313102201 20180213102201 44940 testzone.nlnetlabs.nl. GhmXNFQktZIgaBpGKwj9Q2mfq5+jcbRPK+PPgtRVicUPZga/d/iGEL8PV/8DzGwkaZbM14pamSUMgdJibW4zNhLz/ukjPilbjoj6giH1jtbdZLAQ6iK9pZ/4jKUEq4txviTczZNnDeolgPEEl4xo4NclQmi7zj1XBlQRbjvG0/0=
+TEMPFILE_END
+
 stub-zone:
        name: "."
        stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
@@ -50,7 +100,7 @@ SCENARIO_BEGIN Test authority zone with zonefile for downstream responses
 
 ; K.ROOT-SERVERS.NET.
 RANGE_BEGIN 0 100
-       ADDRESS 193.0.14.129 
+       ADDRESS 193.0.14.129
 ENTRY_BEGIN
 MATCH opcode qtype qname
 ADJUST copy_id
@@ -182,4 +232,109 @@ SECTION ANSWER
 www.example.com. IN A  1.2.3.4
 ENTRY_END
 
+; check SOA TTL to be the minimum of the SOA.minimum and the SOA TTL
+STEP 30 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+nonexistent.soa.high.com. IN A
+ENTRY_END
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD RA AA NXDOMAIN
+SECTION QUESTION
+nonexistent.soa.high.com IN A
+SECTION AUTHORITY
+soa.high.com. 200 IN SOA dns.example.de. hostmaster.dns.example.de. 1379078166 28800 7200 604800 200
+ENTRY_END
+; check that the original SOA is also returned
+STEP 32 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+soa.high.com. IN SOA
+ENTRY_END
+STEP 33 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+soa.high.com. IN SOA
+SECTION ANSWER
+soa.high.com. 500 IN SOA dns.example.de. hostmaster.dns.example.de. 1379078166 28800 7200 604800 200
+ENTRY_END
+
+; check SOA TTL to be the minimum of the SOA.minimum and the SOA TTL
+STEP 40 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+nonexistent.soa.low.com. IN A
+ENTRY_END
+STEP 41 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD RA AA NXDOMAIN
+SECTION QUESTION
+nonexistent.soa.low.com. IN A
+SECTION AUTHORITY
+soa.low.com. 200 IN SOA dns.example.de. hostmaster.dns.example.de. 1379078166 28800 7200 604800 500
+ENTRY_END
+; check that the original SOA is also returned
+STEP 42 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+soa.low.com. IN SOA
+ENTRY_END
+STEP 43 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+soa.low.com. IN SOA
+SECTION ANSWER
+soa.low.com. 200 IN SOA dns.example.de. hostmaster.dns.example.de. 1379078166 28800 7200 604800 500
+ENTRY_END
+
+; check SOA TTL to be minimum of the SOA.minimum and the SOA TTL for DNSSEC
+STEP 50 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+ant.testzone.nlnetlabs.nl. IN A
+ENTRY_END
+STEP 51 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD DO RA AA NXDOMAIN
+SECTION QUESTION
+ant.testzone.nlnetlabs.nl. IN A
+SECTION AUTHORITY
+testzone.nlnetlabs.nl.  3600    IN      SOA     ns.nlnetlabs.nl. ralph.nlnetlabs.nl. 1 14400 3600 604800 3600
+testzone.nlnetlabs.nl.  3600    IN      RRSIG   SOA 8 3 3600 20180313102201 20180213102201 44940 testzone.nlnetlabs.nl. GhmXNFQktZIgaBpGKwj9Q2mfq5+jcbRPK+PPgtRVicUPZga/d/iGEL8PV/8DzGwkaZbM14pamSUMgdJibW4zNhLz/ukjPilbjoj6giH1jtbdZLAQ6iK9pZ/4jKUEq4txviTczZNnDeolgPEEl4xo4NclQmi7zj1XBlQRbjvG0/0=
+alligator.testzone.nlnetlabs.nl.        3600    IN      NSEC    cheetah.testzone.nlnetlabs.nl. TXT RRSIG NSEC
+alligator.testzone.nlnetlabs.nl.        3600    IN      RRSIG   NSEC 8 4 3600 20180313102201 20180213102201 44940 testzone.nlnetlabs.nl. QAgQ0AsMoYG02+VPfoOctSPlTHdQOkQt5fFkSkzIbVhUzNOqa+dB/Qkc81AwFeJosA+PvYjt6utcVkIWmK2Djy9eXC49gILtVF79vUe4G7ZrybO5NXjqNa5ANoUGM+yew4wkjeNOMVAsvs+1kvFY7S8RAa/0AIYlZHQ8vNBPNaI=
+testzone.nlnetlabs.nl.  3600    IN      NSEC    alligator.testzone.nlnetlabs.nl. NS SOA RRSIG NSEC DNSKEY
+testzone.nlnetlabs.nl.  3600    IN      RRSIG   NSEC 8 3 3600 20180313102201 20180213102201 44940 testzone.nlnetlabs.nl. gTKn6U1nal9oA79IRxLa/7zexl6A0yJZzeEGBbZ5rh5feyAr2X4LTR9bPCgcHeMVggf4FP+kD1L/sxzj/YLwB1ZKGKlwnzsHtPFTlmvDClaqQ76DRZq5Vejr2ZfnclBUb2vtxaXywTRW8oueaaq9flcShEQ/cQ+KRU8sc344qd0=
+ENTRY_END
+; check that the original SOA is also returned
+STEP 52 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+testzone.nlnetlabs.nl. IN SOA
+ENTRY_END
+STEP 53 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD DO RA AA NOERROR
+SECTION QUESTION
+testzone.nlnetlabs.nl. IN SOA
+SECTION ANSWER
+testzone.nlnetlabs.nl.  4600    IN      SOA     ns.nlnetlabs.nl. ralph.nlnetlabs.nl. 1 14400 3600 604800 3600
+testzone.nlnetlabs.nl.  4600    IN      RRSIG   SOA 8 3 3600 20180313102201 20180213102201 44940 testzone.nlnetlabs.nl. GhmXNFQktZIgaBpGKwj9Q2mfq5+jcbRPK+PPgtRVicUPZga/d/iGEL8PV/8DzGwkaZbM14pamSUMgdJibW4zNhLz/ukjPilbjoj6giH1jtbdZLAQ6iK9pZ/4jKUEq4txviTczZNnDeolgPEEl4xo4NclQmi7zj1XBlQRbjvG0/0=
+ENTRY_END
+
 SCENARIO_END
index eb25ef573d74c61ead5850234346d68cd8267942..047fbeebadd41c9c88f1b7d58932ec92b3da3dd6 100644 (file)
@@ -88,12 +88,12 @@ local. IN A
 ENTRY_END
 STEP 6 CHECK_ANSWER
 ENTRY_BEGIN
-MATCH all
+MATCH all ttl
 REPLY QR RA AA
 SECTION QUESTION
 local. IN A
 SECTION AUTHORITY
-local. 3600 IN SOA nobody nobody 1 2 3 4 5
+local. 5 IN SOA nobody nobody 1 2 3 4 5
 ENTRY_END
 
 ; positive SOA
@@ -104,7 +104,7 @@ local. IN SOA
 ENTRY_END
 STEP 8 CHECK_ANSWER
 ENTRY_BEGIN
-MATCH all
+MATCH all ttl
 REPLY QR RA AA
 SECTION QUESTION
 local. IN SOA
@@ -136,12 +136,12 @@ serv.local. IN MX
 ENTRY_END
 STEP 12 CHECK_ANSWER
 ENTRY_BEGIN
-MATCH all
+MATCH all ttl
 REPLY QR RA AA
 SECTION QUESTION
 serv.local. IN MX
 SECTION AUTHORITY
-local. 3600 IN SOA nobody nobody 1 2 3 4 5
+local. 5 IN SOA nobody nobody 1 2 3 4 5
 ENTRY_END
 
 ; no such type, empty nonterminal
@@ -152,12 +152,12 @@ bla.local. IN MX
 ENTRY_END
 STEP 14 CHECK_ANSWER
 ENTRY_BEGIN
-MATCH all
+MATCH all ttl
 REPLY QR RA AA
 SECTION QUESTION
 bla.local. IN MX
 SECTION AUTHORITY
-local. 3600 IN SOA nobody nobody 1 2 3 4 5
+local. 5 IN SOA nobody nobody 1 2 3 4 5
 ENTRY_END
 
 ; nxdomain with SOA
@@ -168,12 +168,12 @@ doing.local. IN MX
 ENTRY_END
 STEP 16 CHECK_ANSWER
 ENTRY_BEGIN
-MATCH all
+MATCH all ttl
 REPLY QR RA AA NXDOMAIN
 SECTION QUESTION
 doing.local. IN MX
 SECTION AUTHORITY
-local. 3600 IN SOA nobody nobody 1 2 3 4 5
+local. 5 IN SOA nobody nobody 1 2 3 4 5
 ENTRY_END
 
 ; nxdomain without SOA