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;
uint32_t minTTL;
if (rcode == RCode::ServFail || rcode == RCode::Refused) {
- minTTL = d_tempFailureTTL;
+ minTTL = tempFailureTTL == boost::none ? d_tempFailureTTL : *tempFailureTTL;
if (minTTL == 0) {
return;
}
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);
}
};
+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:
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);
});
}
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
}
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) {
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;
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;
size_t size;
uint16_t len;
uint16_t ecsPrefixLength;
+ boost::optional<uint32_t> tempFailureTTL;
const bool tcp;
bool skipCache{false};
bool ecsOverride;
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;
origRemote = orig.origRemote;
origDest = orig.origDest;
delayMsec = orig.delayMsec;
+ tempFailureTTL = orig.tempFailureTTL;
age.store(orig.age.load());
}
uint16_t origID; // 2
uint16_t origFlags; // 2
int delayMsec;
+ boost::optional<uint32_t> tempFailureTTL;
bool ednsAdded{false};
bool ecsAdded{false};
bool skipCache{false};
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) {
}
}
+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)
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) {