From b247774236ea684214730055fd643bda7698986b Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 22 Oct 2007 12:05:46 +0000 Subject: [PATCH] Detect recursion-lameness. git-svn-id: file:///svn/unbound/trunk@713 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 1 + iterator/iter_resptype.c | 23 +++- iterator/iter_resptype.h | 5 +- iterator/iterator.c | 5 +- testdata/iter_ranoaa_lame.rpl | 218 ++++++++++++++++++++++++++++++++++ 5 files changed, 245 insertions(+), 7 deletions(-) create mode 100644 testdata/iter_ranoaa_lame.rpl diff --git a/doc/Changelog b/doc/Changelog index 88afbfb3b..4d1cd7369 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,7 @@ - added donotquerylocalhost config option. Can be turned off for out test cases. - ISO C compat changes. + - detect RA-no-AA lameness, as LAME. 19 October 2007: Wouter - added configure (and its files) to svn, so that the trunk is easier diff --git a/iterator/iter_resptype.c b/iterator/iter_resptype.c index 94e98a5a3..bad8e393a 100644 --- a/iterator/iter_resptype.c +++ b/iterator/iter_resptype.c @@ -100,8 +100,8 @@ response_type_from_cache(struct dns_msg* msg, } enum response_type -response_type_from_server(struct dns_msg* msg, struct query_info* request, - struct delegpt* dp) +response_type_from_server(int rdset, + struct dns_msg* msg, struct query_info* request, struct delegpt* dp) { uint8_t* origzone = (uint8_t*)"\000"; /* the default */ size_t origzonelen = 1; @@ -111,8 +111,13 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request, return RESPONSE_TYPE_THROWAWAY; /* If the message is NXDOMAIN, then it answers the question. */ - if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) + if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) { + /* make sure its not recursive when we don't want it to */ + if( (msg->rep->flags&BIT_RA) && + !(msg->rep->flags&BIT_AA) && !rdset) + return RESPONSE_TYPE_LAME; return RESPONSE_TYPE_ANSWER; + } /* Other response codes mean (so far) to throw the response away as * meaningless and move on to the next nameserver. */ @@ -193,6 +198,10 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request, /* The normal way of detecting NOERROR/NODATA. */ if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA && dname_subdomain_c(request->qname, s->rk.dname)) { + /* we do our own recursion, thank you */ + if( (msg->rep->flags&BIT_RA) && + !(msg->rep->flags&BIT_AA) && !rdset) + return RESPONSE_TYPE_LAME; return RESPONSE_TYPE_ANSWER; } @@ -203,6 +212,11 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request, * thought we were contacting, then it is an answer.*/ /* FIXME: is this correct? */ if(query_dname_compare(s->rk.dname, origzone) == 0) { + /* see if mistakenly a recursive server was + * deployed and is responding nonAA */ + if( (msg->rep->flags&BIT_RA) && + !(msg->rep->flags&BIT_AA) && !rdset) + return RESPONSE_TYPE_LAME; return RESPONSE_TYPE_ANSWER; } /* If we are getting a referral upwards (or to @@ -231,5 +245,8 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request, /* If we've gotten this far, this is NOERROR/NODATA (which could * be an entirely empty message) */ + /* check if recursive answer; saying it has empty cache */ + if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset) + return RESPONSE_TYPE_LAME; return RESPONSE_TYPE_ANSWER; } diff --git a/iterator/iter_resptype.h b/iterator/iter_resptype.h index c50f07e1c..bfacd6148 100644 --- a/iterator/iter_resptype.h +++ b/iterator/iter_resptype.h @@ -107,13 +107,14 @@ enum response_type response_type_from_cache(struct dns_msg* msg, * relies somewhat on the originating zone to be accurate (for lameness * detection, mostly). * + * @param rdset: if RD bit was sent in query sent by unbound. * @param msg: the message from the cache. * @param request: the request that generated the response. * @param dp: The delegation point that was being queried * when the response was returned. * @return the response type (CNAME or ANSWER). */ -enum response_type response_type_from_server(struct dns_msg* msg, - struct query_info* request, struct delegpt* dp); +enum response_type response_type_from_server(int rdset, + struct dns_msg* msg, struct query_info* request, struct delegpt* dp); #endif /* ITERATOR_ITER_RESPTYPE_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index eb0e9269e..c6f2d2f14 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1179,7 +1179,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_ALGO, "query response was timeout"); return next_state(iq, QUERYTARGETS_STATE); } - type = response_type_from_server(iq->response, &iq->qchase, iq->dp); + type = response_type_from_server((int)(iq->chase_flags&BIT_RD), + iq->response, &iq->qchase, iq->dp); if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD)) { /* When forwarding (RD bit is set), we handle referrals * differently. No queries should be sent elsewhere */ @@ -1373,7 +1374,7 @@ static int processPrimeResponse(struct module_qstate* qstate, int id) { struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id]; - enum response_type type = response_type_from_server(iq->response, + enum response_type type = response_type_from_server(0, iq->response, &iq->qchase, iq->dp); if(type == RESPONSE_TYPE_ANSWER) { qstate->return_rcode = LDNS_RCODE_NOERROR; diff --git a/testdata/iter_ranoaa_lame.rpl b/testdata/iter_ranoaa_lame.rpl new file mode 100644 index 000000000..48a0e7bca --- /dev/null +++ b/testdata/iter_ranoaa_lame.rpl @@ -0,0 +1,218 @@ +; config options +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test detection of RA but no AA lameness +; in this scenario mistakenly, a recursive server is deployed, instead +; of an authoritative server. It gives answers from cache. +; However, unbound is doing recursion on behalf of its client, and does +; not trust the server to do so. + +; 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 qtype qname +ADJUST copy_id +REPLY QR 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 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN A +SECTION AUTHORITY +net. IN NS e.gtld-servers.net. +SECTION ADDITIONAL +e.gtld-servers.net. IN A 192.12.94.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +SECTION AUTHORITY +net. IN NS e.gtld-servers.net. +SECTION ADDITIONAL +e.gtld-servers.net. IN A 192.12.94.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 +www.example.com. IN A +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. IN NS ns.example.net. +SECTION ADDITIONAL +; this entry; glue will make unbound take this reference first. +; it is however, the lame server. +ns.example.com. IN A 1.2.3.55 +ENTRY_END +RANGE_END + +; e.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.12.94.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN A +SECTION AUTHORITY +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +SECTION AUTHORITY +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 1.2.3.44 +ENTRY_END +RANGE_END + +; ns.example.net. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.44 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN A +SECTION ANSWER +ns.example.net. IN A 1.2.3.44 +SECTION AUTHORITY +example.net. IN NS ns.example.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +SECTION AUTHORITY +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +www.example.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA 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. +example.com. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net IN A 1.2.3.44 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.55 +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.55 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +ENTRY_END + +; the lame response. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +; the wrong answer. +www.example.com. IN A 10.20.30.50 +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.55 +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 20 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 +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. IN NS ns.example.net. +; scrubbed off +;SECTION ADDITIONAL +;ns.example.net IN A 1.2.3.44 +ENTRY_END + +SCENARIO_END -- 2.47.2