From 1e0cf1e86b30c071a537af10940e1cf6f5f130e3 Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Fri, 23 Aug 2024 08:56:48 +0200 Subject: [PATCH] - 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. --- doc/Changelog | 8 + doc/example.conf.in | 3 + doc/unbound.conf.5.in | 5 + iterator/iter_scrub.c | 31 ++++ iterator/iterator.c | 17 +- pythonmod/doc/modules/config.rst | 4 + pythonmod/interface.i | 1 + services/cache/dns.c | 4 +- services/cache/dns.h | 2 +- testdata/iter_unverified_glue.rpl | 188 +++++++++++++++++++++ testdata/iter_unverified_glue_fallback.rpl | 138 +++++++++++++++ util/config_file.c | 3 + util/config_file.h | 2 + util/configlexer.lex | 1 + util/configparser.y | 15 +- util/data/packed_rrset.h | 3 + 16 files changed, 416 insertions(+), 9 deletions(-) create mode 100644 testdata/iter_unverified_glue.rpl create mode 100644 testdata/iter_unverified_glue_fallback.rpl diff --git a/doc/Changelog b/doc/Changelog index a6eb51438..f176de045 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/doc/example.conf.in b/doc/example.conf.in index b7db1e7d9..cce65c0f5 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -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). diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index 15f5a6607..d051e8850 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -1048,6 +1048,11 @@ payload is very large. .B harden\-glue: \fI Will trust glue only if it is within the servers authority. Default is yes. .TP +.B harden\-unverified\-glue: \fI +Will trust only in-zone glue. Will try to resolve all out of zone +(\fI) glue. Will fallback to the original glue if unable to resolve. +Default is no. +.TP .B harden\-dnssec\-stripped: \fI 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 diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c index a043589fd..49a5f5da1 100644 --- a/iterator/iter_scrub.c +++ b/iterator/iter_scrub.c @@ -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; } diff --git a/iterator/iterator.c b/iterator/iterator.c index 1066eb8cd..659af34d9 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -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); } diff --git a/pythonmod/doc/modules/config.rst b/pythonmod/doc/modules/config.rst index ac4db4c94..64480c94d 100644 --- a/pythonmod/doc/modules/config.rst +++ b/pythonmod/doc/modules/config.rst @@ -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. diff --git a/pythonmod/interface.i b/pythonmod/interface.i index c876ab072..810b1449d 100644 --- a/pythonmod/interface.i +++ b/pythonmod/interface.i @@ -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; diff --git a/services/cache/dns.c b/services/cache/dns.c index 5e74c3169..e79002b79 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -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)) { diff --git a/services/cache/dns.h b/services/cache/dns.h index c2bf23c6d..5cb795b07 100644 --- a/services/cache/dns.h +++ b/services/cache/dns.h @@ -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 index 000000000..017f220b6 --- /dev/null +++ b/testdata/iter_unverified_glue.rpl @@ -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 index 000000000..386186d48 --- /dev/null +++ b/testdata/iter_unverified_glue_fallback.rpl @@ -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 diff --git a/util/config_file.c b/util/config_file.c index 12df8e793..d82e4374e 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -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) diff --git a/util/config_file.h b/util/config_file.h index 6b16efa63..ae9c9cb5b 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -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 */ diff --git a/util/configlexer.lex b/util/configlexer.lex index 9a95dc078..8b37131cf 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -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) } diff --git a/util/configparser.y b/util/configparser.y index 0ab15f8eb..8088bcfa9 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -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)); diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index e1feb22bb..776e8d092 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -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 */