]> granicus.if.org Git - pdns/commitdiff
Add TempFailureCacheTTLAction
authorChris Hofstaedtler <chris.hofstaedtler@deduktiva.com>
Mon, 27 Nov 2017 18:31:20 +0000 (19:31 +0100)
committerChris Hofstaedtler <chris.hofstaedtler@deduktiva.com>
Mon, 18 Dec 2017 17:02:12 +0000 (18:02 +0100)
pdns/dnsdist-cache.cc
pdns/dnsdist-cache.hh
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-tcp.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/test-dnsdistpacketcache_cc.cc

index 7ecb8c2ddc858302ff9dcbeff893fdce3086c66b..50703e28c8f3984063cc571196345db55ca1bdde 100644 (file)
@@ -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<uint32_t> 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;
     }
index 7283f96ace150c4c50f85d4bdedc5b72707fa97f..daeabc6f61fd0e2547050b907603b565979d647d 100644 (file)
@@ -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<uint32_t> 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);
index 2c6e137521658f538a11ebdac8cba43eae9b922a..1c287466357a9ab64eb951e906ec8e92c90bb76d 100644 (file)
@@ -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<DNSAction>(new SkipCacheAction);
     });
 
+  g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
+      return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
+    });
+
   g_lua.writeFunction("DropResponseAction", []() {
       return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
     });
index 61630b5333e79c10bee7f1d681a2e388ff25c489..63cc4ce314139d1504b3458c177c67412b7e4f9f 100644 (file)
@@ -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
index c3018e0bd018c460386a524b5e73ff47378761ff..9d9dbe2954ae2388b49030471ec6d661a84da15c 100644 (file)
@@ -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;
index b8a05d5235b14a51e5d51f12c8624e1e73534c9a..d726271fed55c1a650de9d358b80b79069b1375f 100644 (file)
@@ -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<boost::uuids::uuid> uniqueId;
@@ -144,6 +144,7 @@ struct DNSQuestion
   size_t size;
   uint16_t len;
   uint16_t ecsPrefixLength;
+  boost::optional<uint32_t> 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<uint32_t> tempFailureTTL;
   bool ednsAdded{false};
   bool ecsAdded{false};
   bool skipCache{false};
index a8b022361592bcaf8cce3b77b4bf8359767b152e..fd6ba398eb7217d5ddbb97222d96fdaa837a02ee 100644 (file)
@@ -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<uint8_t> query;
+    DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
+    pwQ.getHeader()->rd = 1;
+
+    vector<uint8_t> 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<uint32_t>(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<uint32_t>(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: "<<e.reason<<endl;
+    throw;
+  }
+}
+
 static DNSDistPacketCache PC(500000);
 
 static void *threadMangler(void* off)
@@ -139,7 +185,7 @@ static void *threadMangler(void* off)
       DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false);
       PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key);
 
-      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);
     }
   }
   catch(PDNSException& e) {