From: Otto Moerbeek Date: Wed, 22 Nov 2023 08:33:32 +0000 (+0100) Subject: If the chain is old, refuse to add more entries to it X-Git-Tag: rec-5.1.0-beta1~22^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e3c3a4db449386f4bd65760d79b8d95229385bcd;p=thirdparty%2Fpdns.git If the chain is old, refuse to add more entries to it --- diff --git a/pdns/recursordist/lwres.cc b/pdns/recursordist/lwres.cc index 28e142ed85..7061b97f49 100644 --- a/pdns/recursordist/lwres.cc +++ b/pdns/recursordist/lwres.cc @@ -468,7 +468,7 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& if (!doTCP) { int queryfd; - ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, weWantEDNSSubnet, &queryfd); + ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, weWantEDNSSubnet, &queryfd, *now); if (ret != LWResult::Result::Success) { return ret; diff --git a/pdns/recursordist/lwres.hh b/pdns/recursordist/lwres.hh index 8fca61fe15..216d44c90c 100644 --- a/pdns/recursordist/lwres.hh +++ b/pdns/recursordist/lwres.hh @@ -81,7 +81,7 @@ public: }; LWResult::Result asendto(const void* data, size_t len, int flags, const ComboAddress& toAddress, uint16_t qid, - const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc); + const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc, timeval& now); LWResult::Result arecvfrom(PacketBuffer& packet, int flags, const ComboAddress& fromAddr, size_t& len, uint16_t qid, const DNSName& domain, uint16_t qtype, int fileDesc, const struct timeval& now); diff --git a/pdns/recursordist/pdns_recursor.cc b/pdns/recursordist/pdns_recursor.cc index 7713869ce6..921d429a31 100644 --- a/pdns/recursordist/pdns_recursor.cc +++ b/pdns/recursordist/pdns_recursor.cc @@ -273,18 +273,17 @@ unsigned int authWaitTime(const std::unique_ptr& mtasker) { const auto max = g_maxMThreads; const auto current = mtasker->numProcesses(); - const unsigned int cutoff = max / 10; /// if we have less than 10% used, do not reduce auth timeout + const unsigned int cutoff = max / 10; // if we have less than 10% used, do not reduce auth timeout if (current < cutoff) { return g_networkTimeoutMsec; } - // current is between cutoff and max const auto avail = max - current; return std::max(g_networkTimeoutMsec / 10, g_networkTimeoutMsec * avail / (max - cutoff)); } /* these two functions are used by LWRes */ LWResult::Result asendto(const void* data, size_t len, int /* flags */, - const ComboAddress& toAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc) + const ComboAddress& toAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc, timeval& now) { auto pident = std::make_shared(); @@ -307,13 +306,19 @@ LWResult::Result asendto(const void* data, size_t len, int /* flags */, // don't chain onto existing chained waiter or a chain already processed if (chain.first->key->fd > -1 && !chain.first->key->closed) { *fileDesc = -1; // gets used in waitEvent / sendEvent later on - if (g_maxChainLength > 0 && chain.first->key->authReqChain.size() >= g_maxChainLength) { + auto currentChainSize = chain.first->key->authReqChain.size(); + if (g_maxChainLength > 0 && currentChainSize >= g_maxChainLength) { + return LWResult::Result::OSLimitError; + } + assert(uSec(chain.first->key->creationTime) != 0); + auto age = now - chain.first->key->creationTime; + if (uSec(age) > static_cast(1000) * authWaitTime(g_multiTasker) * 2 / 3) { return LWResult::Result::OSLimitError; } chain.first->key->authReqChain.insert(qid); // we can chain auto maxLength = t_Counters.at(rec::Counter::maxChainLength); - if (chain.first->key->authReqChain.size() > maxLength) { - t_Counters.at(rec::Counter::maxChainLength) = chain.first->key->authReqChain.size(); + if (currentChainSize > maxLength) { + t_Counters.at(rec::Counter::maxChainLength) = currentChainSize; } return LWResult::Result::Success; } @@ -353,6 +358,7 @@ LWResult::Result arecvfrom(PacketBuffer& packet, int /* flags */, const ComboAdd pident->domain = domain; pident->type = qtype; pident->remote = fromAddr; + pident->creationTime = now; int ret = g_multiTasker->waitEvent(pident, &packet, authWaitTime(g_multiTasker), &now); len = 0; diff --git a/pdns/recursordist/settings/table.py b/pdns/recursordist/settings/table.py index 0525094dfe..2ac1fe069d 100644 --- a/pdns/recursordist/settings/table.py +++ b/pdns/recursordist/settings/table.py @@ -1499,7 +1499,7 @@ means unlimited. 'default' : '2048', 'help' : 'Maximum number of simultaneous Mtasker threads', 'doc' : ''' -Maximum number of simultaneous MTasker threads. +Maximum number of simultaneous MTasker threads, per worker thread. ''', }, { @@ -1816,6 +1816,7 @@ a new domain is observed. 'help' : 'Wait this number of milliseconds for network i/o', 'doc' : ''' Number of milliseconds to wait for a remote authoritative server to respond. +If the number of concurrent requests is high, the :program:Recursor uses a lower value. ''', }, { diff --git a/pdns/recursordist/syncres.cc b/pdns/recursordist/syncres.cc index 01ee4cdc4e..268a55d850 100644 --- a/pdns/recursordist/syncres.cc +++ b/pdns/recursordist/syncres.cc @@ -5400,7 +5400,6 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, // don't account for resource limits, they are our own fault // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames if (resolveret != LWResult::Result::OSLimitError && !chained && !dontThrottle) { - cerr << "THROTTLING !!!!" << remoteIP.toString() << ' ' << int(resolveret) << endl; s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, 1000000, d_now); // 1 sec // make sure we don't throttle the root diff --git a/pdns/recursordist/syncres.hh b/pdns/recursordist/syncres.hh index 50626a37a1..bf9fab1b38 100644 --- a/pdns/recursordist/syncres.hh +++ b/pdns/recursordist/syncres.hh @@ -764,6 +764,7 @@ struct PacketID using chain_t = set; mutable chain_t authReqChain; shared_ptr tcphandler{nullptr}; + timeval creationTime{}; string::size_type inPos{0}; // how far are we along in the inMSG size_t inWanted{0}; // if this is set, we'll read until inWanted bytes are read string::size_type outPos{0}; // how far we are along in the outMSG