From: Otto Moerbeek Date: Wed, 5 Feb 2025 13:23:57 +0000 (+0100) Subject: Initial very raw version X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=86e546cd2c2846f065be83158d24ce46005e132d;p=thirdparty%2Fpdns.git Initial very raw version --- diff --git a/pdns/ednscookies.cc b/pdns/ednscookies.cc index 96178998f..dbd599489 100644 --- a/pdns/ednscookies.cc +++ b/pdns/ednscookies.cc @@ -65,6 +65,29 @@ string EDNSCookiesOpt::makeOptString() const return ret; } +string EDNSCookiesOpt::toDisplayString() const +{ + std::string ret = makeHexDump(client, "");; + if (!server.empty()) { + ret += '|'; + if (server.length() != 16) { + // It isn't a rfc9018 one + ret += makeHexDump(server, ""); + } + else { + // It very likely is a rfc9018 one + ret += makeHexDump(server.substr(0, 1), ""); // Version + ret += '|'; + ret += makeHexDump(server.substr(1, 3), ""); // Reserved + ret += '|'; + ret += makeHexDump(server.substr(4, 4), ""); // Timestamp + ret += '|'; + ret += makeHexDump(server.substr(8, 8), ""); // Hash + } + } + return ret; +} + void EDNSCookiesOpt::getEDNSCookiesOptFromString(const char* option, unsigned int len) { client.clear(); diff --git a/pdns/ednscookies.hh b/pdns/ednscookies.hh index 204ef2356..829a234fa 100644 --- a/pdns/ednscookies.hh +++ b/pdns/ednscookies.hh @@ -54,7 +54,9 @@ struct EDNSCookiesOpt [[nodiscard]] bool isValid(const std::string& secret, const ComboAddress& source) const; void makeClientCookie(); bool makeServerCookie(const std::string& secret, const ComboAddress& source); + [[nodiscard]] std::string makeOptString() const; + [[nodiscard]] std::string toDisplayString() const; [[nodiscard]] std::string getServer() const { return server; diff --git a/pdns/recursordist/Makefile.am b/pdns/recursordist/Makefile.am index a2cd2e28d..3e6335735 100644 --- a/pdns/recursordist/Makefile.am +++ b/pdns/recursordist/Makefile.am @@ -185,6 +185,7 @@ pdns_recursor_SOURCES = \ ratelimitedlog.hh \ rcpgenerator.cc rcpgenerator.hh \ rec-carbon.cc \ + rec-cookiestore.cc rec-cookiestore.hh \ rec-eventtrace.cc rec-eventtrace.hh \ rec-lua-conf.hh rec-lua-conf.cc \ rec-main.hh rec-main.cc \ diff --git a/pdns/recursordist/lwres.cc b/pdns/recursordist/lwres.cc index 7f7d74115..36b0fd210 100644 --- a/pdns/recursordist/lwres.cc +++ b/pdns/recursordist/lwres.cc @@ -54,12 +54,33 @@ #include "rec-protozero.hh" #include "uuid-utils.hh" #include "rec-tcpout.hh" +#include "rec-cookiestore.hh" + +static bool g_cookies = true; thread_local TCPOutConnectionManager t_tcp_manager; std::shared_ptr g_slogout; bool g_paddingOutgoing; bool g_ECSHardening; +static LockGuarded s_cookiestore; + +void pruneCookies(time_t cutoff) +{ + auto lock = s_cookiestore.lock(); + lock->prune(cutoff); +} + +uint64_t dumpCookies(int fileDesc) +{ + CookieStore copy; + { + auto lock = s_cookiestore.lock(); + copy = *lock; + } + return CookieStore::dump(copy, fileDesc); +} + void remoteLoggerQueueData(RemoteLoggerInterface& rli, const std::string& data) { auto ret = rli.queueData(data); @@ -416,8 +437,10 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& */ pw.getHeader()->cd = (sendRDQuery && g_dnssecmode != DNSSECMode::Off); - string ping; std::optional subnetOpts = std::nullopt; + std::optional addressToBindTo; + std::optional cookieSentOut; + if (EDNS0Level > 0) { DNSPacketWriter::optvect_t opts; if (srcmask) { @@ -426,6 +449,34 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& opts.emplace_back(EDNSOptionCode::ECS, subnetOpts->makeOptString()); } + if (g_cookies) { + auto lock = s_cookiestore.lock(); + auto found = lock->find(address); + if (found != lock->end()) { + if (found->d_support) { + cookieSentOut = found->d_cookie; + addressToBindTo = found->d_localaddress; + opts.emplace_back(EDNSOptionCode::COOKIE, cookieSentOut->makeOptString()); + found->d_lastupdate = now->tv_sec; + cerr << "Sending stored cookie info to " << address.toString() << ": " << found->d_cookie.toDisplayString() << endl; + } + else { + cerr << "This server does not support cookies" << endl; + } + } + else { + CookieEntry entry; + entry.d_address = address; + entry.d_cookie.makeClientCookie(); + cookieSentOut = entry.d_cookie; + entry.d_lastupdate = now->tv_sec; + entry.d_support = false; + lock->emplace(entry); + opts.emplace_back(EDNSOptionCode::COOKIE, cookieSentOut->makeOptString()); + cerr << "We're sending new client cookie info from to " << address.toString() << ": " << entry.d_cookie.toDisplayString() << endl; + } + } + if (dnsOverTLS && g_paddingOutgoing) { addPadding(pw, bufsize, opts); } @@ -451,12 +502,12 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0 - // We only store the localip if needed for fstrm logging + // We only store the localip if needed for fstrm logging or cookie support ComboAddress localip; -#ifdef HAVE_FSTRM bool fstrmQEnabled = false; bool fstrmREnabled = false; +#ifdef HAVE_FSTRM if (isEnabledForQueries(fstrmLoggers)) { fstrmQEnabled = true; } @@ -467,9 +518,18 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& if (!doTCP) { int queryfd; - - ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, subnetOpts, &queryfd, *now); - + try { + ret = asendto(vpacket.data(), vpacket.size(), 0, address, addressToBindTo, qid, domain, type, subnetOpts, &queryfd, *now); + } + catch (const PDNSException& e) { + if (addressToBindTo) { + // Cookie info already has been added to packet, so we must retry from a higher level + auto lock = s_cookiestore.lock(); + lock->erase(address); + return LWResult::Result::BindError; + } + throw; + } if (ret != LWResult::Result::Success) { return ret; } @@ -478,9 +538,8 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& *chained = true; } -#ifdef HAVE_FSTRM if (!*chained) { - if (fstrmQEnabled || fstrmREnabled) { + if (cookieSentOut || fstrmQEnabled || fstrmREnabled) { localip.sin4.sin_family = address.sin4.sin_family; socklen_t slen = address.getSocklen(); (void)getsockname(queryfd, reinterpret_cast(&localip), &slen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)) @@ -489,7 +548,6 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& logFstreamQuery(fstrmLoggers, queryTime, localip, address, DnstapMessage::ProtocolType::DoUDP, context.d_auth ? context.d_auth : boost::none, vpacket); } } -#endif /* HAVE_FSTRM */ // sleep until we see an answer to this, interface to mtasker ret = arecvfrom(buf, 0, address, len, qid, domain, type, queryfd, subnetOpts, *now); @@ -503,6 +561,7 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& // peer has closed it on error, so we retry. At some point we // *will* get a new connection, so this loop is not endless. isNew = true; // tcpconnect() might throw for new connections. In that case, we want to break the loop, scanbuild complains here, which is a false positive afaik + // XXX cookie case: bind to local address isNew = tcpconnect(address, connection, dnsOverTLS, nsName); ret = tcpsendrecv(address, connection, localip, vpacket, len, buf); #ifdef HAVE_FSTRM @@ -588,6 +647,7 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& lwr->d_records.push_back(answer); } + bool cookieFoundInReply = false; if (EDNSOpts edo; EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) { lwr->d_haveEDNS = true; @@ -623,6 +683,49 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& } } } + if (g_cookies && !*chained) { + for (const auto& opt : edo.d_options) { + if (opt.first == EDNSOptionCode::COOKIE) { + EDNSCookiesOpt received; + if (received.makeFromString(opt.second)) { + cookieFoundInReply = true; + cerr << "Received cookie info back from " << address.toString() << ": " << received.toDisplayString() << endl; + auto lock = s_cookiestore.lock(); + auto found = lock->find(address); + if (found != lock->end()) { + if (received.getClient() == cookieSentOut->getClient()) { + cerr << "Client cookie matched! Storing with localAddress " << localip.toString() << endl; + found->d_localaddress = localip; + found->d_cookie = received; + found->d_lastupdate = now->tv_sec; + found->d_support = true; + uint16_t ercode = (edo.d_extRCode << 4) | lwr->d_rcode; + if (ercode == ERCode::BADCOOKIE) { + lwr->d_validpacket = true; + return LWResult::Result::BadCookie; + } + } + else { + // Server responded with a wrong client cookie, fall back to TCP + lwr->d_validpacket = true; + return LWResult::Result::BadCookie; + } + } + else { + // We sent a cookie out but forgot it? + lwr->d_validpacket = true; + return LWResult::Result::BadCookie; + } + } + } + } + } + } + + // Case: we sent out a cookie but did not get one back + if (cookieSentOut && !cookieFoundInReply && !*chained) { + lwr->d_validpacket = true; + return LWResult::Result::BadCookie; } if (outgoingLoggers) { diff --git a/pdns/recursordist/lwres.hh b/pdns/recursordist/lwres.hh index 0c9ba4507..9f3e1ce91 100644 --- a/pdns/recursordist/lwres.hh +++ b/pdns/recursordist/lwres.hh @@ -73,6 +73,8 @@ public: Spoofed = 4, /* Spoofing attempt (too many near-misses) */ ChainLimitError = 5, ECSMissing = 6, + BadCookie = 7, + BindError = 8, }; [[nodiscard]] static bool isLimitError(Result res) @@ -90,9 +92,12 @@ public: class EDNSSubnetOpts; -LWResult::Result asendto(const void* data, size_t len, int flags, const ComboAddress& toAddress, uint16_t qid, +LWResult::Result asendto(const void* data, size_t len, int flags, const ComboAddress& toAddress, + std::optional& localAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, const std::optional& 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 std::optional& ecs, const struct timeval& now); LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, const ResolveContext& context, const std::shared_ptr>>& outgoingLoggers, const std::shared_ptr>>& fstrmLoggers, const std::set& exportTypes, LWResult* lwr, bool* chained); +uint64_t dumpCookies(int fileDesc); +void pruneCookies(time_t cutoff); diff --git a/pdns/recursordist/pdns_recursor.cc b/pdns/recursordist/pdns_recursor.cc index 0460cdb8c..25ec0cf69 100644 --- a/pdns/recursordist/pdns_recursor.cc +++ b/pdns/recursordist/pdns_recursor.cc @@ -99,9 +99,9 @@ GlobalStateHolder g_dontThrottleNetmasks; GlobalStateHolder g_DoTToAuthNames; uint64_t g_latencyStatSize; -LWResult::Result UDPClientSocks::getSocket(const ComboAddress& toaddr, int* fileDesc) +LWResult::Result UDPClientSocks::getSocket(const ComboAddress& toaddr, const std::optional& localAddress, int* fileDesc) { - *fileDesc = makeClientSocket(toaddr.sin4.sin_family); + *fileDesc = makeClientSocket(toaddr.sin4.sin_family, localAddress); if (*fileDesc < 0) { // temporary error - receive exception otherwise return LWResult::Result::OSLimitError; } @@ -147,7 +147,7 @@ void UDPClientSocks::returnSocket(int fileDesc) } // returns -1 for errors which might go away, throws for ones that won't -int UDPClientSocks::makeClientSocket(int family) +int UDPClientSocks::makeClientSocket(int family, const std::optional& localAddress) { int ret = socket(family, SOCK_DGRAM, 0); // turns out that setting CLO_EXEC and NONBLOCK from here is not a performance win on Linux (oddly enough) @@ -179,7 +179,15 @@ int UDPClientSocks::makeClientSocket(int family) } while (g_avoidUdpSourcePorts.count(port) != 0); } - sin = pdns::getQueryLocalAddress(family, port); // does htons for us + if (localAddress) { + cerr << "Binding to local address associated with cookie: " << localAddress->toString() << endl; + sin = *localAddress; + sin.setPort(port); + } + else { + sin = pdns::getQueryLocalAddress(family, port); // does htons for us + cerr << "Bound to random local address " << sin.toString() << endl; + } if (::bind(ret, reinterpret_cast(&sin), sin.getSocklen()) >= 0) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) break; } @@ -276,7 +284,7 @@ unsigned int authWaitTimeMSec(const std::unique_ptr& mtasker) /* 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, const std::optional& ecs, int* fileDesc, timeval& now) + const ComboAddress& toAddress, std::optional& localAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, const std::optional& ecs, int* fileDesc, timeval& now) { auto pident = std::make_shared(); @@ -316,7 +324,7 @@ LWResult::Result asendto(const void* data, size_t len, int /* flags */, } } - auto ret = t_udpclientsocks->getSocket(toAddress, fileDesc); + auto ret = t_udpclientsocks->getSocket(toAddress, localAddress, fileDesc); if (ret != LWResult::Result::Success) { return ret; } diff --git a/pdns/recursordist/rec-cookiestore.cc b/pdns/recursordist/rec-cookiestore.cc new file mode 100644 index 000000000..321b9c090 --- /dev/null +++ b/pdns/recursordist/rec-cookiestore.cc @@ -0,0 +1,60 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "misc.hh" +#include "rec-cookiestore.hh" + +using timebuf_t = std::array; + +extern const char* timestamp(time_t arg, timebuf_t& buf); // XXX + +void CookieStore::prune(time_t cutoff) +{ + auto& ind = get(); + ind.erase(ind.begin(), ind.upper_bound(cutoff)); +} + +uint64_t CookieStore::dump(const CookieStore& copy, int fileDesc) +{ + int newfd = dup(fileDesc); + if (newfd == -1) { + return 0; + } + auto filePtr = pdns::UniqueFilePtr(fdopen(newfd, "w")); + if (!filePtr) { + close(newfd); + return 0; + } + uint64_t count = 0; + + fprintf(filePtr.get(), "; cookie dump follows\n; server\tlocal\tcookie\tsupport\tts\n"); + for (const auto& entry : copy) { + count++; + timebuf_t tmp; + fprintf(filePtr.get(), "%s\t%s\t%s\t%s\t%s\n", + entry.d_address.toString().c_str(), entry.d_localaddress.toString().c_str(), + entry.d_cookie.toDisplayString().c_str(), + entry.d_support ? "yes" : "no", + timestamp(entry.d_lastupdate, tmp)); + } + return count; +} diff --git a/pdns/recursordist/rec-cookiestore.hh b/pdns/recursordist/rec-cookiestore.hh new file mode 100644 index 000000000..a78810ad5 --- /dev/null +++ b/pdns/recursordist/rec-cookiestore.hh @@ -0,0 +1,69 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +/* + CookieStore is used to keep track of client cookies used for contacting authoritative servers. + According to RFC 7873 and RFC 9018, it has the following design. + + - Cookies are stored with an auth IP address as primary index and are generated randomly. + + - If the the does not support cookies, this is marked as such and no cookies will be sent to it + for a period of time. When a cookie is sent again, it must be a newly generated one. + + - A cookie is stored together with the client IP (as rec can have many). If a server is to be + contacted again, it should use the same bound IP. + + - Although it is perfectly fine for a client cookie to live for a long time, this design will + flush entries older that a certain period of time, to avoid an ever growing CookieStore. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "iputils.hh" +#include "ednscookies.hh" + +using namespace ::boost::multi_index; + +struct CookieEntry +{ + ComboAddress d_address; + mutable ComboAddress d_localaddress; // The address we were bound to, see RFC 9018 + mutable EDNSCookiesOpt d_cookie; // Contains both client and server cookie + mutable time_t d_lastupdate{}; + mutable bool d_support; +}; + +class CookieStore : public multi_index_container < CookieEntry, + indexed_by < ordered_unique, member>, + ordered_non_unique, member>>> +{ +public: + void prune(time_t cutoff); + static uint64_t dump(const CookieStore&, int fileDesc); +}; diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index 9af131491..e8ecd425d 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -2554,6 +2554,11 @@ static void houseKeepingWork(Logr::log_t log) SyncRes::pruneSaveParentsNSSets(now.tv_sec); }); + static PeriodicTask pruneCookiesTask{"pruneCookiesTask", 30}; + pruneCookiesTask.runIfDue(now, [now]() { + pruneCookies(now.tv_sec - 1800); + }); + // By default, refresh at 80% of max-cache-ttl with a minimum period of 10s const unsigned int minRootRefreshInterval = 10; static PeriodicTask rootUpdateTask{"rootUpdateTask", std::max(SyncRes::s_maxcachettl * 8 / 10, minRootRefreshInterval)}; diff --git a/pdns/recursordist/rec-main.hh b/pdns/recursordist/rec-main.hh index 49576ee7b..6b20fc1e0 100644 --- a/pdns/recursordist/rec-main.hh +++ b/pdns/recursordist/rec-main.hh @@ -176,14 +176,14 @@ public: { } - LWResult::Result getSocket(const ComboAddress& toaddr, int* fileDesc); + LWResult::Result getSocket(const ComboAddress& toaddr, const std::optional& localAddress, int* fileDesc); // return a socket to the pool, or simply erase it void returnSocket(int fileDesc); private: // returns -1 for errors which might go away, throws for ones that won't - static int makeClientSocket(int family); + static int makeClientSocket(int family, const std::optional& localAddress); }; enum class PaddingMode diff --git a/pdns/recursordist/rec_channel_rec.cc b/pdns/recursordist/rec_channel_rec.cc index 0289388fa..9e25768b5 100644 --- a/pdns/recursordist/rec_channel_rec.cc +++ b/pdns/recursordist/rec_channel_rec.cc @@ -375,6 +375,11 @@ static uint64_t dumpAggressiveNSECCache(int fileDesc) } // NOLINTBEGIN(cppcoreguidelines-owning-memory) +static uint64_t* pleaseDumpCookiesMap(int fileDesc) +{ + return new uint64_t(dumpCookies(fileDesc)); +} + static uint64_t* pleaseDumpEDNSMap(int fileDesc) { return new uint64_t(SyncRes::doEDNSDump(fileDesc)); @@ -1889,6 +1894,7 @@ static RecursorControlChannel::Answer help() "clear-nta [DOMAIN]... Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n" "clear-ta [DOMAIN]... Clear the Trust Anchor for DOMAINs\n" "dump-cache [type...] dump cache contents to the named file, type is r, n, p or a\n" + "dump-cookies dump the contents of the cookie data to the namewd file\n" "dump-dot-probe-map dump the contents of the DoT probe map to the named file\n" "dump-edns [status] dump EDNS status to the named file\n" "dump-failedservers dump the failed servers to the named file\n" @@ -2100,6 +2106,9 @@ RecursorControlChannel::Answer RecursorControlParser::getAnswer(int socket, cons if (cmd == "dump-cache") { return doDumpCache(socket, begin, end); } + if (cmd == "dump-cookies") { + return doDumpToFile(socket, pleaseDumpCookiesMap, cmd, false); + } if (cmd == "dump-dot-probe-map") { return doDumpToFile(socket, pleaseDumpDoTProbeMap, cmd, false); } diff --git a/pdns/recursordist/rec_control.cc b/pdns/recursordist/rec_control.cc index c8fcf7f77..8a5ff53e2 100644 --- a/pdns/recursordist/rec_control.cc +++ b/pdns/recursordist/rec_control.cc @@ -329,6 +329,7 @@ int main(int argc, char** argv) const set fileCommands = { "dump-cache", + "dump-cookies", "dump-edns", "dump-ednsstatus", "dump-nsspeeds", diff --git a/pdns/recursordist/syncres.cc b/pdns/recursordist/syncres.cc index debd38ead..6769dd61b 100644 --- a/pdns/recursordist/syncres.cc +++ b/pdns/recursordist/syncres.cc @@ -1014,7 +1014,7 @@ const char* isoDateTimeMillis(const struct timeval& tval, timebuf_t& buf) return buf.data(); } -static const char* timestamp(time_t arg, timebuf_t& buf) +const char* timestamp(time_t arg, timebuf_t& buf) { const std::string s_timestampFormat = "%Y-%m-%dT%T"; struct tm tmval{}; @@ -1517,12 +1517,26 @@ LWResult::Result SyncRes::asyncresolveWrapper(const ComboAddress& address, bool auto lock = s_ednsstatus.lock(); // all three branches below need a lock // Determine new mode + if (ret == LWResult::Result::BindError) { + cerr << "BindError, retrying with new client cookie and no specific address to bind to" << endl; + // BindError is only generated when cookies are active and we failed to bind to a local + // address associated with a cookie, see RFC9018 section 3 last paragraph. We assume the + // called code alread erased the cookie info. + // This is the first path that re-iterates the loop + continue; + } + else if (res->d_validpacket && res->d_haveEDNS && ret == LWResult::Result::BadCookie) { + cerr << "Retrying with received server cookie" << endl; + // We assume the received cookie was stored and will be used in the second iteration + // This is the second path that re-iterates the loop + continue; + } if (res->d_validpacket && !res->d_haveEDNS && res->d_rcode == RCode::FormErr) { mode = EDNSStatus::NOEDNS; auto ednsstatus = lock->insert(address).first; auto& ind = lock->get(); lock->setMode(ind, ednsstatus, mode, d_now.tv_sec); - // This is the only path that re-iterates the loop + // This is the third path that re-iterates the loop continue; } if (!res->d_haveEDNS) { @@ -5474,6 +5488,8 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, } } + cerr << "asyncrW: returns " << int(resolveret) << " rcode is " << int(lwr.d_rcode) << endl; + /* preoutquery killed the query by setting dq.rcode to -3 */ if (preOutQueryRet == -3) { throw ImmediateServFailException("Query killed by policy"); @@ -5481,7 +5497,8 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, d_totUsec += lwr.d_usec; - if (resolveret == LWResult::Result::Spoofed) { + if (resolveret == LWResult::Result::Spoofed || resolveret == LWResult::Result::BadCookie) { + cerr << "Acting as we got a spoof" << endl; spoofed = true; return false; } @@ -5986,6 +6003,7 @@ int SyncRes::doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, con } if (forceTCP || (spoofed || (gotAnswer && truncated))) { /* retry, over TCP this time */ + cerr << "Retry over TCP" << endl; gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery, wasForwarded, tns->first, *remoteIP, true, doDoT, truncated, spoofed, context.extendedError); }