From d88911eed518ea3dd8cd77c313ed5022ffadb8e3 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Thu, 11 Apr 2013 10:08:34 +0000 Subject: [PATCH] - Fix queries leaking up for stubs and forwards, if the configured nameservers all fail to answer. git-svn-id: file:///svn/unbound/trunk@2882 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 4 + iterator/iter_fwd.c | 14 ++ iterator/iter_fwd.h | 10 ++ iterator/iterator.c | 33 ++++ testdata/iter_stublastresort.rpl | 259 +++++++++++++++++++++++++++++++ 5 files changed, 320 insertions(+) create mode 100644 testdata/iter_stublastresort.rpl diff --git a/doc/Changelog b/doc/Changelog index 6c639d5e2..922d040ad 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +11 April 2013: Wouter + - Fix queries leaking up for stubs and forwards, if the configured + nameservers all fail to answer. + 10 April 2013: Wouter - code improve for minimal responses, small speed increase. diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c index 0b3b6525c..b84e5eff6 100644 --- a/iterator/iter_fwd.c +++ b/iterator/iter_fwd.c @@ -324,6 +324,20 @@ forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg) return 1; } +struct delegpt* +forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass) +{ + rbnode_t* res = NULL; + struct iter_forward_zone key; + key.node.key = &key; + key.dclass = qclass; + key.name = qname; + key.namelabs = dname_count_size_labels(qname, &key.namelen); + res = rbtree_search(fwd->tree, &key); + if(res) return ((struct iter_forward_zone*)res)->dp; + return NULL; +} + struct delegpt* forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass) { diff --git a/iterator/iter_fwd.h b/iterator/iter_fwd.h index dbb84f226..62408ad52 100644 --- a/iterator/iter_fwd.h +++ b/iterator/iter_fwd.h @@ -104,6 +104,16 @@ void forwards_delete(struct iter_forwards* fwd); */ int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg); +/** + * Find forward zone exactly by name + * @param fwd: forward storage. + * @param qname: The qname of the query. + * @param qclass: The qclass of the query. + * @return: A delegation point or null. + */ +struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname, + uint16_t qclass); + /** * Find forward zone information * For this qname/qclass find forward zone information, returns delegation diff --git a/iterator/iterator.c b/iterator/iterator.c index e3f058fe5..f8a1f8e29 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1409,6 +1409,34 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, return 1; } +/** see if last resort is possible - does config allow queries to parent */ +static int +can_have_last_resort(struct module_env* env, struct delegpt* dp, + struct iter_qstate* iq) +{ + struct delegpt* fwddp; + struct iter_hints_stub* stub; + /* do not process a last resort (the parent side) if a stub + * or forward is configured, because we do not want to go 'above' + * the configured servers */ + if((stub = (struct iter_hints_stub*)name_tree_find(&env->hints->tree, + dp->name, dp->namelen, dp->namelabs, iq->qchase.qclass)) && + /* has_parent side is turned off for stub_first, where we + * are allowed to go to the parent */ + stub->dp->has_parent_side_NS) { + verbose(VERB_QUERY, "configured stub servers failed -- returning SERVFAIL"); + return 0; + } + if((fwddp = forwards_find(env->fwds, dp->name, iq->qchase.qclass)) && + /* has_parent_side is turned off for forward_first, where + * we are allowed to go to the parent */ + fwddp->has_parent_side_NS) { + verbose(VERB_QUERY, "configured forward servers failed -- returning SERVFAIL"); + return 0; + } + return 1; +} + /** * Called by processQueryTargets when it would like extra targets to query * but it seems to be out of options. At last resort some less appealing @@ -1430,6 +1458,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_ALGO, "No more query targets, attempting last resort"); log_assert(iq->dp); + if(!can_have_last_resort(qstate->env, iq->dp, iq)) { + /* fail -- no more targets, no more hope of targets, no hope + * of a response. */ + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); + } if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) { struct delegpt* p = hints_lookup_root(qstate->env->hints, iq->qchase.qclass); diff --git a/testdata/iter_stublastresort.rpl b/testdata/iter_stublastresort.rpl new file mode 100644 index 000000000..b60778910 --- /dev/null +++ b/testdata/iter_stublastresort.rpl @@ -0,0 +1,259 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. + +stub-zone: + name: "example.com" + stub-addr: 1.2.3.6 + stub-prime: yes + +CONFIG_END + +SCENARIO_BEGIN Test stub with stub-prime and last resort fallback +; the last resort fallback should not activate, as the +; configured stub must be used for this data, or its primed data. + +; 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 +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 NOERROR +SECTION QUESTION +ns.example.com. IN A +SECTION ANSWER +ns.example.com. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN AAAA +SECTION ANSWER +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 ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; the stub-prime server. +; local authority (that fails a lot) +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.6 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA +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.7 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA SERVFAIL +SECTION QUESTION +ns.example.com. IN A +SECTION ANSWER +;ns.example.com. IN A 1.2.3.7 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA SERVFAIL +SECTION QUESTION +ns.example.com. IN AAAA +SECTION ANSWER +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA SERVFAIL +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +;www.example.com. IN A 10.20.30.70 +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END +RANGE_END + +; the primed server +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.7 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA +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.8 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA +SECTION QUESTION +ns.example.com. IN A +SECTION ANSWER +ns.example.com. IN A 1.2.3.8 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA +SECTION QUESTION +ns.example.com. IN AAAA +SECTION ANSWER +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA SERVFAIL +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +;www.example.com. IN A 10.20.30.80 +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END +RANGE_END + +; crap server that the primed server refers to. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.8 + +ENTRY_BEGIN +MATCH opcode +ADJUST copy_id copy_query +REPLY QR SERVFAIL +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +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 SERVFAIL +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +;www.example.com. IN A 10.20.30.50 +SECTION AUTHORITY +;example.com. IN NS ns.example.com. +SECTION ADDITIONAL +;ns.example.com. IN A 1.2.3.4 +ENTRY_END + +SCENARIO_END