From 1db056b19c56eb4cdaa3013c67935815c4c4c6bd Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Fri, 12 May 2017 15:10:10 +0000 Subject: [PATCH] - Fix queries for nameservers under a stub leaking to the internet. git-svn-id: file:///svn/unbound/trunk@4154 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 1 + iterator/iterator.c | 31 ++++++++++---- testdata/iter_stub_leak.rpl | 82 ++++++++++++++++++++++++++++++++++++- 3 files changed, 103 insertions(+), 11 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 004e76f77..48700a4c3 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,6 +1,7 @@ 12 May 2017: Wouter - Adjust servfail by iterator to not store in cache when serve-expired is enabled, to avoid overwriting useful information there. + - Fix queries for nameservers under a stub leaking to the internet. 9 May 2017: Ralph - Add 'c' to getopt() in testbound. diff --git a/iterator/iterator.c b/iterator/iterator.c index 55916d726..a57fa3b65 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1576,28 +1576,26 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, /** 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) +can_have_last_resort(struct module_env* env, uint8_t* nm, size_t nmlen, + uint16_t qclass) { struct delegpt* fwddp; struct iter_hints_stub* stub; + int labs = dname_count_labels(nm); /* 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(!dname_is_root(dp->name) && (stub = (struct iter_hints_stub*) - name_tree_find(&env->hints->tree, dp->name, dp->namelen, - dp->namelabs, iq->qchase.qclass)) && + if(!dname_is_root(nm) && (stub = (struct iter_hints_stub*) + name_tree_find(&env->hints->tree, nm, nmlen, labs, 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)) && + if((fwddp = forwards_find(env->fwds, nm, 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; @@ -1624,9 +1622,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)) { + if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, + iq->qchase.qclass)) { /* fail -- no more targets, no more hope of targets, no hope * of a response. */ + verbose(VERB_QUERY, "configured stub or forward servers failed -- returning SERVFAIL"); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) { @@ -1711,6 +1711,19 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, /* see if we can issue queries to get nameserver addresses */ /* this lookup is not randomized, but sequential. */ for(ns = iq->dp->nslist; ns; ns = ns->next) { + /* if this nameserver is at a delegation point, but that + * delegation point is a stub and we cannot go higher, skip*/ + if( ((ie->supports_ipv6 && !ns->done_pside6) || + (ie->supports_ipv4 && !ns->done_pside4)) && + !can_have_last_resort(qstate->env, ns->name, ns->namelen, + iq->qchase.qclass)) { + log_nametypeclass(VERB_ALGO, "cannot pside lookup ns " + "because it is also a stub/forward,", + ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass); + if(ie->supports_ipv6) ns->done_pside6 = 1; + if(ie->supports_ipv4) ns->done_pside4 = 1; + continue; + } /* query for parent-side A and AAAA for nameservers */ if(ie->supports_ipv6 && !ns->done_pside6) { /* Send the AAAA request. */ diff --git a/testdata/iter_stub_leak.rpl b/testdata/iter_stub_leak.rpl index 2f07340ab..e5c620006 100644 --- a/testdata/iter_stub_leak.rpl +++ b/testdata/iter_stub_leak.rpl @@ -8,6 +8,9 @@ stub-zone: stub-zone: name: "example.com" stub-addr: 10.0.1.1 +stub-zone: + name: "example.net" + stub-addr: 10.0.5.1 CONFIG_END SCENARIO_BEGIN Test stub zone leaking to the internet on last resort fallback @@ -18,7 +21,7 @@ RANGE_BEGIN 0 100 ; root prime ENTRY_BEGIN -MATCH +MATCH qname qtype ADJUST copy_id copy_query REPLY QR NOERROR SECTION QUESTION @@ -45,6 +48,7 @@ subzone.example.com. IN A SECTION AUTHORITY subzone.example.com. IN NS sub-ns1.example.com. subzone.example.com. IN NS sub-ns2.example.com. +subzone.example.com. IN NS example.net. SECTION ADDITIONAL sub-ns1.example.com. IN A 10.0.2.3 sub-ns2.example.com. IN A 10.0.2.4 @@ -92,6 +96,44 @@ ENTRY_END RANGE_END +; stub server for example.net +RANGE_BEGIN 0 100 + ADDRESS 10.0.5.1 + +ENTRY_BEGIN +MATCH opcode question +ADJUST copy_id copy_query +REPLY QR AA NOERROR +SECTION QUESTION +example.net. IN NS +SECTION ANSWER +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 10.0.5.1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode question +ADJUST copy_id copy_query +REPLY QR AA NOERROR +SECTION QUESTION +example.net. IN A +SECTION ANSWER +example.net. IN A 10.0.5.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode question +ADJUST copy_id copy_query +REPLY QR AA NOERROR +SECTION QUESTION +example.net. IN AAAA +SECTION AUTHORITY +example.net. 300 SOA master.example.net etc 1 2 3 4 300 +ENTRY_END + +RANGE_END + ; stub server for subzone.example.com RANGE_BEGIN 0 100 ADDRESS 10.0.2.3 @@ -120,16 +162,52 @@ SECTION ANSWER ENTRY_END RANGE_END +; stub server for subzone.example.com +RANGE_BEGIN 0 100 + ADDRESS 10.0.5.4 +; match anything, servfail +ENTRY_BEGIN +MATCH opcode +ADJUST copy_id copy_query +REPLY QR SERVFAIL +SECTION QUESTION +subzone.example.com. IN A +SECTION ANSWER +ENTRY_END +RANGE_END + + +; fetch the delegation point for example.net in cache. STEP 1 QUERY ENTRY_BEGIN REPLY RD SECTION QUESTION +example.net. IN NS +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +example.net. IN NS +SECTION ANSWER +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 10.0.5.1 +ENTRY_END + +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION whatever.subzone.example.com. IN A ENTRY_END ; recursion happens here. ; the query should not leak subzone ns queries to the internet -STEP 10 CHECK_ANSWER +STEP 30 CHECK_ANSWER ENTRY_BEGIN MATCH all REPLY QR RD RA SERVFAIL