]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Merge patch to fix for glue that is outside of zone, with
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 23 Aug 2024 06:56:48 +0000 (08:56 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 23 Aug 2024 06:56:48 +0000 (08:56 +0200)
  `harden-unverified-glue`, from Karthik Umashankar (Microsoft).
  Enabling this option protects the Unbound resolver against bad
  glue, that is unverified out of zone glue, by resolving them.
  It uses the records as last resort if there is no other working
  glue.

16 files changed:
doc/Changelog
doc/example.conf.in
doc/unbound.conf.5.in
iterator/iter_scrub.c
iterator/iterator.c
pythonmod/doc/modules/config.rst
pythonmod/interface.i
services/cache/dns.c
services/cache/dns.h
testdata/iter_unverified_glue.rpl [new file with mode: 0644]
testdata/iter_unverified_glue_fallback.rpl [new file with mode: 0644]
util/config_file.c
util/config_file.h
util/configlexer.lex
util/configparser.y
util/data/packed_rrset.h

index a6eb51438f8d76ba2d12d4d98e25081c32f5cad3..f176de045312e41538aeb8a567637e8c3ff7ca7e 100644 (file)
@@ -1,3 +1,11 @@
+23 August 2024: Wouter
+       - Merge patch to fix for glue that is outside of zone, with
+         `harden-unverified-glue`, from Karthik Umashankar (Microsoft).
+         Enabling this option protects the Unbound resolver against bad
+         glue, that is unverified out of zone glue, by resolving them.
+         It uses the records as last resort if there is no other working
+         glue.
+
 21 August 2024: Wouter
        - Add cross platform freebsd, openbsd and netbsd to github ci.
        - Fix for char signedness warnings on NetBSD.
index b7db1e7d9bcd9388c6aa79091a38fa350e790849..cce65c0f54b96be9c65137c85b0f4f48da81613e 100644 (file)
@@ -533,6 +533,9 @@ server:
        # Harden against out of zone rrsets, to avoid spoofing attempts.
        # harden-glue: yes
 
+       # Harden against unverified (outside-zone, including sibling zone) glue rrsets
+       # harden-unverified-glue: no
+
        # Harden against receiving dnssec-stripped data. If you turn it
        # off, failing to validate dnskey data for a trustanchor will
        # trigger insecure mode for that zone (like without a trustanchor).
index 15f5a6607abbc15083945ae58cd2f5adc6658b20..d051e8850cd806af58065e48e9ae5993466d211f 100644 (file)
@@ -1048,6 +1048,11 @@ payload is very large.
 .B harden\-glue: \fI<yes or no>
 Will trust glue only if it is within the servers authority. Default is yes.
 .TP
+.B harden\-unverified\-glue: \fI<yes or no>
+Will trust only in-zone glue. Will try to resolve all out of zone
+(\fI<unverfied>) glue. Will fallback to the original glue if unable to resolve.
+Default is no.
+.TP
 .B harden\-dnssec\-stripped: \fI<yes or no>
 Require DNSSEC data for trust\-anchored zones, if such data is absent,
 the zone becomes bogus. If turned off, and no DNSSEC data is received
index a043589fdabec9b136023e19c6aa15c7aba36c22..49a5f5da19c22271ff1f958c3f67e1b665467cb1 100644 (file)
@@ -871,6 +871,7 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
 {
        int del_addi = 0; /* if additional-holding rrsets are deleted, we
                do not trust the normalized additional-A-AAAA any more */
+       uint8_t* ns_rrset_dname = NULL;
        int added_rrlen_ede = 0;
        struct rrset_parse* rrset, *prev;
        prev = NULL;
@@ -976,6 +977,16 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
                                continue;
                        }
                }
+               if(rrset->type == LDNS_RR_TYPE_NS &&
+                       (rrset->section == LDNS_SECTION_AUTHORITY ||
+                       rrset->section == LDNS_SECTION_ANSWER)) {
+                       /* If the type is NS, and we're in the
+                        * answer or authority section, then
+                        * store the dname so we can check
+                        * against the glue records
+                        * further down */
+                       ns_rrset_dname = rrset->dname;
+               }
                if(del_addi && rrset->section == LDNS_SECTION_ADDITIONAL) {
                        remove_rrset("sanitize: removing potential "
                        "poison reference RRset:", pkt, msg, prev, &rrset);
@@ -988,6 +999,26 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
                                "RRset:", pkt, msg, prev, &rrset);
                        continue;
                }
+               if(env->cfg->harden_unverified_glue && ns_rrset_dname &&
+                       rrset->section == LDNS_SECTION_ADDITIONAL &&
+                       (rrset->type == LDNS_RR_TYPE_A || rrset->type == LDNS_RR_TYPE_AAAA) &&
+                       !pkt_strict_sub(pkt, rrset->dname, ns_rrset_dname)) {
+                       /* We're in the additional section, looking
+                        * at an A/AAAA rrset, have a previous
+                        * delegation point and we notice that
+                        * the glue records are NOT for strict
+                        * subdomains of the delegation. So set a
+                        * flag, recompute the hash for the rrset
+                        * and write the A/AAAA record to cache.
+                        * It'll be retrieved if we can't separately
+                        * resolve the glue     */
+                       rrset->flags = PACKED_RRSET_UNVERIFIED_GLUE;
+                       rrset->hash = pkt_hash_rrset(pkt, rrset->dname, rrset->type, rrset->rrset_class, rrset->flags);
+                       store_rrset(pkt, msg, env, rrset);
+                       remove_rrset("sanitize: storing potential "
+                       "unverified glue reference RRset:", pkt, msg, prev, &rrset);
+                       continue;
+               }
                prev = rrset;
                rrset = rrset->rrset_all_next;
        }
index 1066eb8cd6f189838b3107ec0ea0574c832f1b1e..659af34d9b69961efd4a8ea836fbc3cb96269ad0 100644 (file)
@@ -254,7 +254,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
                } else {
                        /* see if the failure did get (parent-lame) info */
                        if(!cache_fill_missing(super->env, super_iq->qchase.qclass,
-                               super->region, super_iq->dp))
+                               super->region, super_iq->dp, 0))
                                log_err("out of memory adding missing");
                }
                delegpt_mark_neg(dpns, qstate->qinfo.qtype);
@@ -1571,7 +1571,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
                        return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
                }
                if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
-                       qstate->region, iq->dp)) {
+                       qstate->region, iq->dp, 0)) {
                        errinf(qstate, "malloc failure, copy extra info into delegation point");
                        return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
                }
@@ -2152,6 +2152,15 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
                verbose(VERB_QUERY, "configured stub or forward servers failed -- returning SERVFAIL");
                return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
        }
+       if(qstate->env->cfg->harden_unverified_glue) {
+               if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
+                       qstate->region, iq->dp, PACKED_RRSET_UNVERIFIED_GLUE))
+                       log_err("out of memory in cache_fill_missing");
+               if(iq->dp->usable_list) {
+                       verbose(VERB_ALGO, "try unverified glue from cache");
+                       return next_state(iq, QUERYTARGETS_STATE);
+               }
+       }
        if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) {
                struct delegpt* dp;
                int nolock = 0;
@@ -2194,7 +2203,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
        }
        /* see if that makes new names available */
        if(!cache_fill_missing(qstate->env, iq->qchase.qclass, 
-               qstate->region, iq->dp))
+               qstate->region, iq->dp, 0))
                log_err("out of memory in cache_fill_missing");
        if(iq->dp->usable_list) {
                verbose(VERB_ALGO, "try parent-side-name, w. glue from cache");
@@ -3426,7 +3435,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                                old_dp->name, old_dp->namelen);
                }
                if(!cache_fill_missing(qstate->env, iq->qchase.qclass, 
-                       qstate->region, iq->dp)) {
+                       qstate->region, iq->dp, 0)) {
                        errinf(qstate, "malloc failure, copy extra info into delegation point");
                        return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
                }
index ac4db4c94af275c120fea24f9296643c537205ab..64480c94d66f14d5ad05bef89ae8378c38bb8878 100644 (file)
@@ -176,6 +176,10 @@ config_file
    
       Harden against spoofed glue (out of zone data).
    
+   .. attribute:: harden_unverified_glue
+
+      Harden against unverified glue.
+
    .. attribute:: harden_dnssec_stripped
    
       Harden against receiving no DNSSEC data for trust anchor.
index c876ab0729d25877d2aaef3502a7a93110584b89..810b1449d34e603dfaee6a87a74ca58fb60d3b50 100644 (file)
@@ -1009,6 +1009,7 @@ struct config_file {
    int harden_short_bufsize;
    int harden_large_queries;
    int harden_glue;
+   int harden_unverified_glue;
    int harden_dnssec_stripped;
    int harden_referral_path;
    int use_caps_bits_for_id;
index 5e74c31693b3ea8522b0714c88ba3804f5a0e2b2..e79002b7910809fbe9bcb0447db76ecd1cca546c 100644 (file)
@@ -365,7 +365,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass,
 /** find and add A and AAAA records for missing nameservers in delegpt */
 int
 cache_fill_missing(struct module_env* env, uint16_t qclass, 
-       struct regional* region, struct delegpt* dp)
+       struct regional* region, struct delegpt* dp, uint32_t flags)
 {
        struct delegpt_ns* ns;
        struct msgreply_entry* neg;
@@ -376,7 +376,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
                        continue;
                ns->cache_lookup_count++;
                akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
-                       ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0);
+                       ns->namelen, LDNS_RR_TYPE_A, qclass, flags, now, 0);
                if(akey) {
                        if(!delegpt_add_rrset_A(dp, region, akey, ns->lame,
                                NULL)) {
index c2bf23c6de54f7e16ccca32f9dd217a523f62472..5cb795b07305d144eb9b5344a339440b13d03705 100644 (file)
@@ -205,7 +205,7 @@ struct dns_msg* dns_cache_lookup(struct module_env* env,
  * @return false on alloc failure.
  */
 int cache_fill_missing(struct module_env* env, uint16_t qclass, 
-       struct regional* region, struct delegpt* dp);
+       struct regional* region, struct delegpt* dp, uint32_t flags);
 
 /**
  * Utility, create new, unpacked data structure for cache response.
diff --git a/testdata/iter_unverified_glue.rpl b/testdata/iter_unverified_glue.rpl
new file mode 100644 (file)
index 0000000..017f220
--- /dev/null
@@ -0,0 +1,188 @@
+; config options
+server:
+       target-fetch-policy: "0 0 0 0 0"
+       qname-minimisation: no
+       minimal-responses: no
+       do-ip6: no
+       harden-unverified-glue: yes
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test iterative resolve with lame hints.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR RA 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 qtype qname
+ADJUST copy_id
+REPLY QR RA NOERROR
+SECTION QUESTION
+a.gtld-servers.net. IN A
+SECTION AUTHORITY
+net.   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 RA NOERROR
+SECTION QUESTION
+www.example.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
+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
+a.gtld-servers.net. IN A
+SECTION ANSWER
+a.gtld-servers.net.    IN A    192.5.6.30
+SECTION AUTHORITY
+net.   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 NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns1.examplesibling.com.
+SECTION ADDITIONAL
+ns1.examplesibling.com.                IN      A       1.2.3.4
+ENTRY_END
+
+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 qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns1.examplesibling.com. IN A
+SECTION ANSWER
+ns1.examplesibling.com. IN A 1.2.3.5
+ENTRY_END
+RANGE_END
+
+; stale ns1.examplesibling.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   ns1.examplesibling.com.
+SECTION ADDITIONAL
+ns1.examplesibling.com.                IN      A       1.2.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+SECTION AUTHORITY
+example.com.   IN NS   ns1.examplesibling.com.
+SECTION ADDITIONAL
+ns1.examplesibling.com.                IN      A       1.2.3.5
+ENTRY_END
+RANGE_END
+
+; actual ns1.examplesibling.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.   IN NS   ns1.examplesibling.com.
+SECTION ADDITIONAL
+ns1.examplesibling.com.                IN      A       1.2.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.50
+SECTION AUTHORITY
+example.com.   IN NS   ns1.examplesibling.com.
+SECTION ADDITIONAL
+ns1.examplesibling.com.                IN      A       1.2.3.5
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.50
+SECTION AUTHORITY
+example.com.   IN NS   ns1.examplesibling.com.
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/iter_unverified_glue_fallback.rpl b/testdata/iter_unverified_glue_fallback.rpl
new file mode 100644 (file)
index 0000000..386186d
--- /dev/null
@@ -0,0 +1,138 @@
+; config options
+server:
+       target-fetch-policy: "0 0 0 0 0"
+       qname-minimisation: no
+       minimal-responses: no
+       do-ip6: no
+       harden-unverified-glue: yes
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test iterative resolve with lame hints.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR RA 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 qtype qname
+ADJUST copy_id
+REPLY QR RA NOERROR
+SECTION QUESTION
+a.gtld-servers.net. IN A
+SECTION AUTHORITY
+net.   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 RA NOERROR
+SECTION QUESTION
+www.example.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
+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
+a.gtld-servers.net. IN A
+SECTION ANSWER
+a.gtld-servers.net.    IN A    192.5.6.30
+SECTION AUTHORITY
+net.   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 NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns1.examplesibling.com.
+SECTION ADDITIONAL
+ns1.examplesibling.com.                IN      A       1.2.3.4
+ENTRY_END
+
+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 qtype qname
+ADJUST copy_id
+REPLY QR NXDOMAIN
+SECTION QUESTION
+ns1.examplesibling.com. IN A
+ENTRY_END
+RANGE_END
+
+; stale ns1.examplesibling.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ENTRY_END
+
+SCENARIO_END
index 12df8e79348460ef03d1c4ab1d97d2bd5dd17f53..d82e4374e760c38e45c608709cbe6390356c8e3f 100644 (file)
@@ -237,6 +237,7 @@ config_create(void)
        cfg->harden_short_bufsize = 1;
        cfg->harden_large_queries = 0;
        cfg->harden_glue = 1;
+       cfg->harden_unverified_glue = 0;
        cfg->harden_dnssec_stripped = 1;
        cfg->harden_below_nxdomain = 1;
        cfg->harden_referral_path = 0;
@@ -675,6 +676,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
        else S_STRLIST("root-hints:", root_hints)
        else S_STR("target-fetch-policy:", target_fetch_policy)
        else S_YNO("harden-glue:", harden_glue)
+       else S_YNO("harden-unverified-glue:", harden_unverified_glue)
        else S_YNO("harden-short-bufsize:", harden_short_bufsize)
        else S_YNO("harden-large-queries:", harden_large_queries)
        else S_YNO("harden-dnssec-stripped:", harden_dnssec_stripped)
@@ -1168,6 +1170,7 @@ config_get_option(struct config_file* cfg, const char* opt,
        else O_YNO(opt, "harden-short-bufsize", harden_short_bufsize)
        else O_YNO(opt, "harden-large-queries", harden_large_queries)
        else O_YNO(opt, "harden-glue", harden_glue)
+       else O_YNO(opt, "harden-unverified-glue", harden_unverified_glue)
        else O_YNO(opt, "harden-dnssec-stripped", harden_dnssec_stripped)
        else O_YNO(opt, "harden-below-nxdomain", harden_below_nxdomain)
        else O_YNO(opt, "harden-referral-path", harden_referral_path)
index 6b16efa63fc167f2fcf72b9e0634457a5c590ba2..ae9c9cb5b82dcee7737b0807d5dbdebe2d085468 100644 (file)
@@ -288,6 +288,8 @@ struct config_file {
        int harden_large_queries;
        /** harden against spoofed glue (out of zone data) */
        int harden_glue;
+       /** harden against unverified glue */
+       int harden_unverified_glue;
        /** harden against receiving no DNSSEC data for trust anchor */
        int harden_dnssec_stripped;
        /** harden against queries that fall under known nxdomain names */
index 9a95dc078e8880c19a1330e14fcad0377c2bcf8f..8b37131cfe97985040aefde461046a55434b635b 100644 (file)
@@ -315,6 +315,7 @@ target-fetch-policy{COLON}  { YDVAR(1, VAR_TARGET_FETCH_POLICY) }
 harden-short-bufsize{COLON}    { YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) }
 harden-large-queries{COLON}    { YDVAR(1, VAR_HARDEN_LARGE_QUERIES) }
 harden-glue{COLON}             { YDVAR(1, VAR_HARDEN_GLUE) }
+harden-unverified-glue{COLON}  { YDVAR(1, VAR_HARDEN_UNVERIFIED_GLUE) }
 harden-dnssec-stripped{COLON}  { YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) }
 harden-below-nxdomain{COLON}   { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) }
 harden-referral-path{COLON}    { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
index 0ab15f8ebad23a0323cdf7160e8420b2896f27b4..8088bcfa96aa84245011a14bf749fd657d1f59df 100644 (file)
@@ -206,7 +206,7 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE
 %token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED
 %token VAR_COOKIE_SECRET_FILE VAR_ITER_SCRUB_NS VAR_ITER_SCRUB_CNAME
-%token VAR_MAX_GLOBAL_QUOTA
+%token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -345,7 +345,8 @@ content_server: server_num_threads | server_verbosity | server_port |
        server_proxy_protocol_port | server_statistics_inhibit_zero |
        server_harden_unknown_additional | server_disable_edns_do |
        server_log_destaddr | server_cookie_secret_file |
-       server_iter_scrub_ns | server_iter_scrub_cname | server_max_global_quota
+       server_iter_scrub_ns | server_iter_scrub_cname | server_max_global_quota |
+       server_harden_unverified_glue
        ;
 stubstart: VAR_STUB_ZONE
        {
@@ -1807,6 +1808,16 @@ server_harden_glue: VAR_HARDEN_GLUE STRING_ARG
                free($2);
        }
        ;
+server_harden_unverified_glue: VAR_HARDEN_UNVERIFIED_GLUE STRING_ARG
+       {
+               OUTYY(("P(server_harden_unverified_glue:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->harden_unverified_glue =
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_harden_dnssec_stripped: VAR_HARDEN_DNSSEC_STRIPPED STRING_ARG
        {
                OUTYY(("P(server_harden_dnssec_stripped:%s)\n", $2));
index e1feb22bb7f6046fa5ec8deed98acaa29017401b..776e8d0923cc5aadbe78e6ec33edd0bf1d429ed8 100644 (file)
@@ -68,6 +68,8 @@ typedef uint64_t rrset_id_type;
  * actual network. But messages with these records in it can be stored in
  * the cache and retrieved for a reply. */
 #define PACKED_RRSET_RPZ 0x8
+/** this rrset is A/AAAA and is an unverified glue record */
+#define PACKED_RRSET_UNVERIFIED_GLUE 0x10
 
 /** number of rrs and rrsets for integer overflow protection.  More than
  * this is not really possible (64K packet has much less RRs and RRsets) in
@@ -96,6 +98,7 @@ struct packed_rrset_key {
         *      o PACKED_RRSET_SOA_NEG
         *      o PACKED_RRSET_FIXEDTTL (not supposed to be cached)
         *      o PACKED_RRSET_RPZ
+        *      o PACKED_RRSET_UNVERIFIED_GLUE
         */
        uint32_t flags;
        /** the rrset type in network format */