From: Remi Gacogne Date: Sun, 28 Mar 2021 16:14:08 +0000 (+0100) Subject: dnsdist: Randomized IDs over UDP X-Git-Tag: rec-4.7.0-alpha1~11^2~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ba9585730b9bb3495202ecd02fcc65b34849be98;p=thirdparty%2Fpdns.git dnsdist: Randomized IDs over UDP --- diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 367de3b6dc..8b7bceb1b3 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -2783,6 +2783,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) DownstreamState::s_randomizeSockets = randomized; }); + luaCtx.writeFunction("setRandomizedIdsOverUDP", [](bool randomized) { + DownstreamState::s_randomizeIDs = randomized; + }); + #if defined(HAVE_LIBSSL) luaCtx.writeFunction("loadTLSEngine", [client](const std::string& engineName, boost::optional defaultString) { if (client) { diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index aa8d52d9a5..9695d1619d 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -1524,33 +1524,9 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct return; } - unsigned int idOffset = (ss->idOffset++) % ss->idStates.size(); - IDState* ids = &ss->idStates[idOffset]; - ids->age = 0; - DOHUnitUniquePtr du(nullptr, DOHUnit::release); - - /* that means that the state was in use, possibly with an allocated - DOHUnit that we will need to handle, but we can't touch it before - confirming that we now own this state */ - if (ids->isInUse()) { - du = DOHUnitUniquePtr(ids->du, DOHUnit::release); - } - - /* we atomically replace the value, we now own this state */ - if (!ids->markAsUsed()) { - /* the state was not in use. - we reset 'du' because it might have still been in use when we read it. */ - du.release(); - ++ss->outstanding; - } - else { - /* we are reusing a state, no change in outstanding but if there was an existing DOHUnit we need - to handle it because it's about to be overwritten. */ - ids->du = nullptr; - ++ss->reuseds; - ++g_stats.downstreamTimeouts; - handleDOHTimeout(std::move(du)); - } + unsigned int idOffset = 0; + int64_t generation; + IDState* ids = ss->getIDState(idOffset, generation); ids->cs = &cs; ids->origFD = cs.udpFD; diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 95db2e8550..6205895df2 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -882,6 +882,7 @@ public: bool passCrossProtocolQuery(std::unique_ptr&& cpq); int pickSocketForSending(); void pickSocketsReadyForReceiving(std::vector& ready); + IDState* getIDState(unsigned int& id, int64_t& generation); dnsdist::Protocol getProtocol() const { @@ -898,6 +899,7 @@ public: } static bool s_randomizeSockets; + static bool s_randomizeIDs; }; using servers_t =vector>; diff --git a/pdns/dnsdistdist/dnsdist-backend.cc b/pdns/dnsdistdist/dnsdist-backend.cc index cd8c2be217..e005595aaa 100644 --- a/pdns/dnsdistdist/dnsdist-backend.cc +++ b/pdns/dnsdistdist/dnsdist-backend.cc @@ -244,6 +244,57 @@ void DownstreamState::pickSocketsReadyForReceiving(std::vector& ready) } bool DownstreamState::s_randomizeSockets{false}; +bool DownstreamState::s_randomizeIDs{false}; + +IDState* DownstreamState::getIDState(unsigned int& selectedID, int64_t& generation) +{ + DOHUnitUniquePtr du(nullptr, DOHUnit::release); + IDState* ids = nullptr; + if (s_randomizeIDs) { + /* if the state is already in use we will retry, + up to 5 five times. The last selected one is used + even if it was already in use */ + size_t remainingAttempts = 5; + do { + selectedID = dnsdist::getRandomValue(idStates.size()); + ids = &idStates[selectedID]; + remainingAttempts--; + } + while (ids->isInUse() && remainingAttempts > 0); + } + else { + selectedID = (idOffset++) % idStates.size(); + ids = &idStates[selectedID]; + } + + ids->age = 0; + + /* that means that the state was in use, possibly with an allocated + DOHUnit that we will need to handle, but we can't touch it before + confirming that we now own this state */ + if (ids->isInUse()) { + du = DOHUnitUniquePtr(ids->du, DOHUnit::release); + } + + /* we atomically replace the value, we now own this state */ + generation = ids->generation++; + if (!ids->markAsUsed(generation)) { + /* the state was not in use. + we reset 'du' because it might have still been in use when we read it. */ + du.release(); + ++outstanding; + } + else { + /* we are reusing a state, no change in outstanding but if there was an existing DOHUnit we need + to handle it because it's about to be overwritten. */ + ids->du = nullptr; + ++reuseds; + ++g_stats.downstreamTimeouts; + handleDOHTimeout(std::move(du)); + } + + return ids; +} size_t ServerPool::countServers(bool upOnly) { diff --git a/pdns/dnsdistdist/doh.cc b/pdns/dnsdistdist/doh.cc index e06d64737f..dc8ef14001 100644 --- a/pdns/dnsdistdist/doh.cc +++ b/pdns/dnsdistdist/doh.cc @@ -661,33 +661,9 @@ static void processDOHQuery(DOHUnitUniquePtr&& du) } ComboAddress dest = du->ids.origDest; - unsigned int idOffset = (du->downstream->idOffset++) % du->downstream->idStates.size(); - IDState* ids = &du->downstream->idStates[idOffset]; - ids->age = 0; - DOHUnit* oldDU = nullptr; - if (ids->isInUse()) { - /* that means that the state was in use, possibly with an allocated - DOHUnit that we will need to handle, but we can't touch it before - confirming that we now own this state */ - oldDU = ids->du; - } - - /* we atomically replace the value, we now own this state */ - int64_t generation = ids->generation++; - if (!ids->markAsUsed(generation)) { - /* the state was not in use. - we reset 'oldDU' because it might have still been in use when we read it. */ - oldDU = nullptr; - ++du->downstream->outstanding; - } - else { - ids->du = nullptr; - /* we are reusing a state, no change in outstanding but if there was an existing DOHUnit we need - to handle it because it's about to be overwritten. */ - ++du->downstream->reuseds; - ++g_stats.downstreamTimeouts; - handleDOHTimeout(DOHUnitUniquePtr(oldDU, DOHUnit::release)); - } + unsigned int idOffset = 0; + int64_t generation; + IDState* ids = du->downstream->getIDState(idOffset, generation); ids->origFD = 0; /* increase the ref count since we are about to store the pointer */ diff --git a/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc b/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc index d1f5080836..32d6f2edda 100644 --- a/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc +++ b/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc @@ -64,6 +64,10 @@ void DOHUnit::setHTTPResponse(uint16_t statusCode, PacketBuffer&& body_, const s } #endif /* HAVE_DNS_OVER_HTTPS */ +void handleDOHTimeout(DOHUnitUniquePtr&& oldDU) +{ +} + std::string DNSQuestion::getTrailingData() const { return "";