From: Remi Gacogne Date: Tue, 17 Nov 2020 10:51:14 +0000 (+0100) Subject: rec: Switch to TCP in case of spoofing (near-miss) attempts X-Git-Tag: auth-4.5.0-alpha0~15^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a6d9b1334121df131d77cca1a0ab7169253ac8a;p=thirdparty%2Fpdns.git rec: Switch to TCP in case of spoofing (near-miss) attempts Instead of treating this like an unrecoverable network error and trying the next server, let's switch to TCP instead. This might prevent a DoS by making us try every single servers and failing, and will make the spoofing attempt a bit much harder. --- diff --git a/pdns/lwres.hh b/pdns/lwres.hh index 9a2023ce38..c27c57c2d9 100644 --- a/pdns/lwres.hh +++ b/pdns/lwres.hh @@ -55,7 +55,7 @@ class LWResult public: LWResult() : d_usec(0) {} - enum class Result : uint8_t { Timeout=0, Success=1, PermanentError=2 /* not transport related */, OSLimitError=3 }; + enum class Result : uint8_t { Timeout=0, Success=1, PermanentError=2 /* not transport related */, OSLimitError=3, Spoofed=4 /* Spoofing attempt (too many near-misses) */ }; vector d_records; int d_rcode{0}; diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 615681d313..6b5a7bcaed 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -693,9 +693,7 @@ LWResult::Result asendto(const char *data, size_t len, int flags, LWResult::Result arecvfrom(std::string& packet, int flags, const ComboAddress& fromaddr, size_t *d_len, uint16_t id, const DNSName& domain, uint16_t qtype, int fd, const struct timeval* now) { - static boost::optional nearMissLimit; - if(!nearMissLimit) - nearMissLimit=::arg().asNum("spoof-nearmiss-max"); + static const boost::optional nearMissLimit = ::arg().asNum("spoof-nearmiss-max"); PacketID pident; pident.fd=fd; @@ -718,7 +716,7 @@ LWResult::Result arecvfrom(std::string& packet, int flags, const ComboAddress& f if (*nearMissLimit && pident.nearMisses > *nearMissLimit) { g_log< "<<*nearMissLimit<<") bogus answers for '"<mode; - if (ret == LWResult::Result::PermanentError || ret == LWResult::Result::OSLimitError) { + if (ret == LWResult::Result::PermanentError || ret == LWResult::Result::OSLimitError || ret == LWResult::Result::Spoofed) { return ret; // transport error, nothing to learn here } - if(ret == LWResult::Result::Timeout) { // timeout, not doing anything with it now + if (ret == LWResult::Result::Timeout) { // timeout, not doing anything with it now return ret; } else if (*mode == EDNSStatus::UNKNOWN || *mode == EDNSStatus::EDNSOK || *mode == EDNSStatus::EDNSIGNORANT ) { @@ -3523,7 +3523,7 @@ bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, co return done; } -bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool* truncated) +bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool& truncated, bool& spoofed) { bool chained = false; LWResult::Result resolveret = LWResult::Result::Success; @@ -3602,11 +3602,14 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, if(t_timeouts) t_timeouts->push_back(remoteIP); } - else if(resolveret == LWResult::Result::OSLimitError) { + else if (resolveret == LWResult::Result::OSLimitError) { /* OS resource limit reached */ LOG(prefix<first, *remoteIP, false, &truncated); - if (gotAnswer && truncated ) { + tns->first, *remoteIP, false, truncated, spoofed); + if (spoofed || (gotAnswer && truncated) ) { /* retry, over TCP this time */ gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery, wasForwarded, - tns->first, *remoteIP, true, &truncated); + tns->first, *remoteIP, true, truncated, spoofed); } if (!gotAnswer) { diff --git a/pdns/syncres.hh b/pdns/syncres.hh index 36b5cf7a50..bd32049994 100644 --- a/pdns/syncres.hh +++ b/pdns/syncres.hh @@ -808,7 +808,7 @@ private: int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, set&beenthere, vState& state, StopAtDelegation* stopAtDelegation); - bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool* truncated); + bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool& truncated, bool& spoofed); bool processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state); int doResolve(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, set& beenthere, vState& state);