From: Pieter Lexis Date: Fri, 15 Jan 2016 17:00:26 +0000 (+0100) Subject: Fix the forward zones in the recursor X-Git-Tag: dnsdist-1.0.0-alpha2~54^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=88490c0365375978afea38bf352079b4fef28e17;p=pdns Fix the forward zones in the recursor In the pre-DNSName era, when dns-native names were passed as strings, we overloaded the NS-name for a forward or auth zone. e.g. an empty string meant 'this is an auth zone' and '+203.0.113.1' meant 'forward to 203.0.113.1 with the RD bit set'. With DNSNames, this is impossible (yay!). In this commit, the set of strings (and later DNSNames), is replaced by a map where a DNSName is the key and the value is a pair of a ComboAddress and a boolean. A non-empty DNSName: This is a normal NS, recurse as usual (the pair is ignored). An empty DNSName and empty ComboAddress: We are auth for this zone, check the auth store for an answer. An empty DNSName and non-empty ComboAddress: The query must be forwarded to the ComboAddress specified and the boolean in the pair tells us the value of the RD bit in the query we need to send. --- diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 5b3321bda..8993f9d33 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -432,7 +432,7 @@ int SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector nsset; + map< DNSName, pair< ComboAddress, bool > > nsset; bool flawedNSSet=false; // the two retries allow getBestNSNamesFromCache&co to reprime the root @@ -618,7 +618,7 @@ SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(DNSName* qname) } /** doesn't actually do the work, leaves that to getBestNSFromCache */ -DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, set& nsset, bool* flawedNSSet, int depth, set&beenthere) +DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, map >& nsset, bool* flawedNSSet, int depth, set&beenthere) { DNSName subdomain(qname); DNSName authdomain(qname); @@ -626,14 +626,11 @@ DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtyp domainmap_t::const_iterator iter=getBestAuthZone(&authdomain); if(iter!=t_sstorage->domainmap->end()) { if( iter->second.d_servers.empty() ) - nsset.insert(DNSName()); // this gets picked up in doResolveAt, if empty it means "we are auth", otherwise it denotes a forward + nsset.insert({DNSName(), {ComboAddress(), false}}); // this gets picked up in doResolveAt, the empty DNSName, combined with the empty ComboAddress means 'we are auth' else { - for(vector::const_iterator server=iter->second.d_servers.begin(); server != iter->second.d_servers.end(); ++server) - // nsset.insert((iter->second.d_rdForward ? "+" : "-") + server->toStringWithPort()); // add a '+' if the rd bit should be set - // XXX this doesn't work, nsset can't contain a port number, or a plus etc! DNSNAME PAIN - abort(); + for(auto const &server : iter->second.d_servers) + nsset.insert({DNSName(), {server, iter->second.d_rdForward}}); // An empty DNSName, combined with a non-empty ComboAddress means 'this is a forwarded domain' } - return authdomain; } @@ -641,7 +638,7 @@ DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtyp getBestNSFromCache(subdomain, qtype, bestns, flawedNSSet, depth, beenthere); for(auto k=bestns.cbegin() ; k != bestns.cend(); ++k) { - nsset.insert(std::dynamic_pointer_cast(k->d_content)->getNS()); + nsset.insert({std::dynamic_pointer_cast(k->d_content)->getNS(), {ComboAddress(), false}}); // The actual resolver code will not even look at the ComboAddress or bool if(k==bestns.cbegin()) subdomain=k->d_name; } @@ -840,12 +837,12 @@ struct speedOrder map& d_speeds; }; -inline vector SyncRes::shuffleInSpeedOrder(set &tnameservers, const string &prefix) +inline vector SyncRes::shuffleInSpeedOrder(map > &tnameservers, const string &prefix) { vector rnameservers; rnameservers.reserve(tnameservers.size()); for(const auto& tns:tnameservers) { - rnameservers.push_back(tns); + rnameservers.push_back(tns.first); } map speeds; @@ -913,7 +910,7 @@ static void addNXNSECS(vector&ret, const vector& records) } /** returns -1 in case of no results, rcode otherwise */ -int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, +int SyncRes::doResolveAt(map > &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector&ret, int depth, set&beenthere) { @@ -928,12 +925,12 @@ int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSe for(;;) { // we may get more specific nameservers vector rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() ); - for(vector::const_iterator tns=rnameservers.begin();;++tns) { + for(vector::const_iterator tns=rnameservers.begin();;++tns) { if(tns==rnameservers.end()) { LOG(prefix<doAgeCache(d_now.tv_sec, auth, QType::NS, 10)) g_stats.nsSetInvalidations++; } @@ -954,14 +951,14 @@ int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSe bool sendRDQuery=false; boost::optional ednsmask; LWResult lwr; - if(tns->empty()) { + if(tns->empty() && nameservers[*tns].first == ComboAddress() ) { LOG(prefix<toString()<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<empty() ? nameservers[*tns].first.toString() : tns->toString())<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"< nameservers, DNSName auth, bool flawedNSSe if(!isCanonical(*tns)) { LOG(prefix<toString(); - if(!tns->empty()) { - sendRDQuery = txtAddr[0] == '+'; - txtAddr=txtAddr.c_str()+1; - } - ComboAddress addr=parseIPAndPort(txtAddr, 53); - - remoteIPs.push_back(addr); + remoteIPs.push_back(nameservers[*tns].first); + sendRDQuery = nameservers[*tns].second; pierceDontQuery=true; } else { @@ -993,7 +984,7 @@ int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSe } else { - LOG(prefix<toString()<<" to: "); + LOG(prefix<empty() ? nameservers[*tns].first.toString() : tns->toString())<<" to: "); for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) { if(remoteIP != remoteIPs.begin()) { LOG(", "); @@ -1085,7 +1076,7 @@ int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSe // if(d_timeouts + 0.5*d_throttledqueries > 6.0 && d_timeouts > 2) throw ImmediateServFailException("Too much work resolving "+qname+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries)); if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) { - LOG(prefix<toString()<<" returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<empty() ? nameservers[*tns].first.toString() : tns->toString())<<" returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<throttle.throttle(d_now.tv_sec,boost::make_tuple(*remoteIP, qname, qtype.getCode()),60,3); // servfail or refused continue; } @@ -1112,7 +1103,7 @@ int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSe LOG(prefix<toString()<<" ("<< remoteIP->toString() <<"), rcode="<empty() ? nameservers[*tns].first.toString() : tns->toString())<<" ("<< remoteIP->toString() <<"), rcode="<sin4.sin_family==AF_INET6) @@ -1176,7 +1167,7 @@ int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSe continue; } else { // ugly... - LOG("YES! - This answer was retrieved from the local auth store"< nameservers, DNSName auth, bool flawedNSSe cout< nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector&ret, + int doResolveAt(map > &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector&ret, int depth, set&beenthere); int doResolve(const DNSName &qname, const QType &qtype, vector&ret, int depth, set& beenthere); bool doOOBResolve(const DNSName &qname, const QType &qtype, vector&ret, int depth, int &res); @@ -468,9 +468,9 @@ private: bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector&ret, int depth, int &res); bool doCacheCheck(const DNSName &qname, const QType &qtype, vector&ret, int depth, int &res); void getBestNSFromCache(const DNSName &qname, const QType &qtype, vector&bestns, bool* flawedNSSet, int depth, set& beenthere); - DNSName getBestNSNamesFromCache(const DNSName &qname, const QType &qtype, set& nsset, bool* flawedNSSet, int depth, set&beenthere); + DNSName getBestNSNamesFromCache(const DNSName &qname, const QType &qtype, map >& nsset, bool* flawedNSSet, int depth, set&beenthere); - inline vector shuffleInSpeedOrder(set &nameservers, const string &prefix); + inline vector shuffleInSpeedOrder(map > &nameservers, const string &prefix); bool moreSpecificThan(const DNSName& a, const DNSName &b); vector getAddrs(const DNSName &qname, int depth, set& beenthere); private: