From: Chris Hofstaedtler Date: Mon, 27 Nov 2017 18:31:20 +0000 (+0100) Subject: Add TempFailureCacheTTLAction X-Git-Tag: dnsdist-1.3.0~162^2~4 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=acb8f5d5f187c70c9b211c7cee379039ee30b3dc;p=pdns Add TempFailureCacheTTLAction --- diff --git a/pdns/dnsdist-cache.cc b/pdns/dnsdist-cache.cc index 7ecb8c2dd..50703e28c 100644 --- a/pdns/dnsdist-cache.cc +++ b/pdns/dnsdist-cache.cc @@ -89,7 +89,7 @@ void DNSDistPacketCache::insertLocked(CacheShard& shard, uint32_t key, const DNS value = newValue; } -void DNSDistPacketCache::insert(uint32_t key, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode) +void DNSDistPacketCache::insert(uint32_t key, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional tempFailureTTL) { if (responseLen < sizeof(dnsheader)) return; @@ -97,7 +97,7 @@ void DNSDistPacketCache::insert(uint32_t key, const DNSName& qname, uint16_t qty uint32_t minTTL; if (rcode == RCode::ServFail || rcode == RCode::Refused) { - minTTL = d_tempFailureTTL; + minTTL = tempFailureTTL == boost::none ? d_tempFailureTTL : *tempFailureTTL; if (minTTL == 0) { return; } diff --git a/pdns/dnsdist-cache.hh b/pdns/dnsdist-cache.hh index 7283f96ac..daeabc6f6 100644 --- a/pdns/dnsdist-cache.hh +++ b/pdns/dnsdist-cache.hh @@ -33,7 +33,7 @@ public: DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t tempFailureTTL=60, uint32_t staleTTL=60, bool dontAge=false, uint32_t shards=1, bool deferrableInsertLock=true); ~DNSDistPacketCache(); - void insert(uint32_t key, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode); + void insert(uint32_t key, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional tempFailureTTL); bool get(const DNSQuestion& dq, uint16_t consumed, uint16_t queryId, char* response, uint16_t* responseLen, uint32_t* keyOut, uint32_t allowExpired=0, bool skipAging=false); void purgeExpired(size_t upTo=0); void expunge(size_t upTo=0); diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index 2c6e13752..1c2874663 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -527,6 +527,24 @@ public: } }; +class TempFailureCacheTTLAction : public DNSAction +{ +public: + TempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl) + {} + TempFailureCacheTTLAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override + { + dq->tempFailureTTL = d_ttl; + return Action::None; + } + string toString() const override + { + return "set tempfailure cache ttl to "+std::to_string(d_ttl); + } +private: + uint32_t d_ttl; +}; + class ECSPrefixLengthAction : public DNSAction { public: @@ -949,6 +967,10 @@ void setupLuaActions() return std::shared_ptr(new SkipCacheAction); }); + g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) { + return std::shared_ptr(new TempFailureCacheTTLAction(maxTTL)); + }); + g_lua.writeFunction("DropResponseAction", []() { return std::shared_ptr(new DropResponseAction); }); diff --git a/pdns/dnsdist-tcp.cc b/pdns/dnsdist-tcp.cc index 61630b533..63cc4ce31 100644 --- a/pdns/dnsdist-tcp.cc +++ b/pdns/dnsdist-tcp.cc @@ -553,7 +553,7 @@ void* tcpClientThread(int pipefd) } if (packetCache && !dq.skipCache) { - packetCache->insert(cacheKey, qname, qtype, qclass, response, responseLen, true, dh->rcode); + packetCache->insert(cacheKey, qname, qtype, qclass, response, responseLen, true, dh->rcode, dq.tempFailureTTL); } #ifdef HAVE_DNSCRYPT diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index c3018e0bd..9d9dbe295 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -467,7 +467,7 @@ try { } if (ids->packetCache && !ids->skipCache) { - ids->packetCache->insert(ids->cacheKey, ids->qname, ids->qtype, ids->qclass, response, responseLen, false, dh->rcode); + ids->packetCache->insert(ids->cacheKey, ids->qname, ids->qtype, ids->qclass, response, responseLen, false, dh->rcode, ids->tempFailureTTL); } if (ids->cs && !ids->cs->muted) { @@ -1371,6 +1371,7 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct ids->qtype = dq.qtype; ids->qclass = dq.qclass; ids->delayMsec = delayMsec; + ids->tempFailureTTL = dq.tempFailureTTL; ids->origFlags = origFlags; ids->cacheKey = cacheKey; ids->skipCache = dq.skipCache; diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index b8a05d523..d726271fe 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -129,7 +129,7 @@ extern thread_local boost::uuids::random_generator t_uuidGenerator; struct DNSQuestion { - DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp): qname(name), qtype(type), qclass(class_), local(lc), remote(rem), dh(header), size(bufferSize), len(queryLen), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tcp(isTcp), ecsOverride(g_ECSOverride) { } + DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp): qname(name), qtype(type), qclass(class_), local(lc), remote(rem), dh(header), size(bufferSize), len(queryLen), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tempFailureTTL(boost::none), tcp(isTcp), ecsOverride(g_ECSOverride) { } #ifdef HAVE_PROTOBUF boost::optional uniqueId; @@ -144,6 +144,7 @@ struct DNSQuestion size_t size; uint16_t len; uint16_t ecsPrefixLength; + boost::optional tempFailureTTL; const bool tcp; bool skipCache{false}; bool ecsOverride; @@ -386,7 +387,7 @@ struct ClientState; struct IDState { - IDState() : origFD(-1), sentTime(true), delayMsec(0) { origDest.sin4.sin_family = 0;} + IDState() : origFD(-1), sentTime(true), delayMsec(0), tempFailureTTL(boost::none) { origDest.sin4.sin_family = 0;} IDState(const IDState& orig) { origFD = orig.origFD; @@ -394,6 +395,7 @@ struct IDState origRemote = orig.origRemote; origDest = orig.origDest; delayMsec = orig.delayMsec; + tempFailureTTL = orig.tempFailureTTL; age.store(orig.age.load()); } @@ -419,6 +421,7 @@ struct IDState uint16_t origID; // 2 uint16_t origFlags; // 2 int delayMsec; + boost::optional tempFailureTTL; bool ednsAdded{false}; bool ecsAdded{false}; bool skipCache{false}; diff --git a/pdns/test-dnsdistpacketcache_cc.cc b/pdns/test-dnsdistpacketcache_cc.cc index a8b022361..fd6ba398e 100644 --- a/pdns/test-dnsdistpacketcache_cc.cc +++ b/pdns/test-dnsdistpacketcache_cc.cc @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) { bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key); BOOST_CHECK_EQUAL(found, false); - PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0); + PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none); found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true); if (found == true) { @@ -109,6 +109,52 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) { } } +BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) { + const size_t maxEntries = 150000; + DNSDistPacketCache PC(maxEntries, 86400, 1); + + ComboAddress remote; + try { + DNSName a = DNSName("servfail"); + BOOST_CHECK_EQUAL(DNSName(a.toString()), a); + + vector query; + DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); + pwQ.getHeader()->rd = 1; + + vector response; + DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); + pwR.getHeader()->rd = 1; + pwR.getHeader()->ra = 0; + pwR.getHeader()->qr = 1; + pwR.getHeader()->rcode = RCode::ServFail; + pwR.getHeader()->id = pwQ.getHeader()->id; + pwR.commit(); + uint16_t responseLen = response.size(); + + char responseBuf[4096]; + uint16_t responseBufSize = sizeof(responseBuf); + uint32_t key = 0; + DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false); + bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key); + BOOST_CHECK_EQUAL(found, false); + + // Insert with failure-TTL of 0 (-> should not enter cache). + PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional(0)); + found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true); + BOOST_CHECK_EQUAL(found, false); + + // Insert with failure-TTL non-zero (-> should not enter cache). + PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional(300)); + found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true); + BOOST_CHECK_EQUAL(found, true); + } + catch(PDNSException& e) { + cerr<<"Had error: "<