}
}
-bool DNSDistPacketCache::get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, bool receivedOverUDP, uint32_t allowExpired, bool skipAging)
+bool DNSDistPacketCache::get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, bool receivedOverUDP, uint32_t allowExpired, bool skipAging, bool truncatedOK)
{
const auto& dnsQName = dq.qname->getStorage();
uint32_t key = getKey(dnsQName, dq.qname->wirelength(), dq.getData(), receivedOverUDP);
return false;
}
+ if (!truncatedOK) {
+ dnsheader dh;
+ memcpy(&dh, value.value.data(), sizeof(dh));
+ if (dh.tc != 0) {
+ return false;
+ }
+ }
+
response.resize(value.len);
memcpy(&response.at(0), &queryId, sizeof(queryId));
memcpy(&response.at(sizeof(queryId)), &value.value.at(sizeof(queryId)), sizeof(dnsheader) - sizeof(queryId));
DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t tempFailureTTL=60, uint32_t maxNegativeTTL=3600, uint32_t staleTTL=60, bool dontAge=false, uint32_t shards=1, bool deferrableInsertLock=true, bool parseECS=false);
void insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const PacketBuffer& response, bool receivedOverUDP, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL);
- bool get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, bool receivedOverUDP, uint32_t allowExpired = 0, bool skipAging = false);
+ bool get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, bool receivedOverUDP, uint32_t allowExpired = 0, bool skipAging = false, bool truncatedOK = true);
size_t purgeExpired(size_t upTo, const time_t now);
size_t expunge(size_t upTo=0);
size_t expungeByName(const DNSName& name, uint16_t qtype=QType::ANY, bool suffixMatch=false);
return ProcessQueryResult::SendAnswer;
}
else if (dq.protocol == dnsdist::Protocol::DoH) {
- /* do a second-lookup for UDP responses */
- /* we need to do a copy to be able to restore the query on a TC=1 cached answer */
+ /* do a second-lookup for UDP responses, but we do not want TC=1 answers */
PacketBuffer initialQuery(dq.getData());
- if (dq.packetCache->get(dq, dq.getHeader()->id, &dq.cacheKeyUDP, dq.subnet, dq.dnssecOK, true, allowExpired)) {
- if (dq.getHeader()->tc == 0) {
- if (!prepareOutgoingResponse(holders, cs, dq, true)) {
- return ProcessQueryResult::Drop;
- }
-
- return ProcessQueryResult::SendAnswer;
+ if (dq.packetCache->get(dq, dq.getHeader()->id, &dq.cacheKeyUDP, dq.subnet, dq.dnssecOK, true, allowExpired, false)) {
+ if (!prepareOutgoingResponse(holders, cs, dq, true)) {
+ return ProcessQueryResult::Drop;
}
- dq.getMutableData() = std::move(initialQuery);
+
+ return ProcessQueryResult::SendAnswer;
}
}
pwR.startRecord(a, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
ComboAddress v6("2001:db8::1");
pwR.xfrIP6(std::string(reinterpret_cast<const char*>(v6.sin6.sin6_addr.s6_addr), 16));
- pwR.xfr32BitInt(0x01020304);
pwR.commit();
uint32_t key = 0;
pwR.startRecord(a, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
ComboAddress v6("2001:db8::1");
pwR.xfrIP6(std::string(reinterpret_cast<const char*>(v6.sin6.sin6_addr.s6_addr), 16));
- pwR.xfr32BitInt(0x01020304);
pwR.commit();
{
}
}
+BOOST_AUTO_TEST_CASE(test_PacketCacheTruncated) {
+ const size_t maxEntries = 150000;
+ DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
+
+ struct timespec queryTime;
+ gettime(&queryTime); // does not have to be accurate ("realTime") in tests
+
+ ComboAddress remote;
+ bool dnssecOK = false;
+
+ try {
+ DNSName name("truncated");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 0;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->tc = 1;
+ pwR.getHeader()->rcode = RCode::NoError;
+ pwR.getHeader()->id = pwQ.getHeader()->id;
+ pwR.commit();
+ pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfr32BitInt(0x01020304);
+ pwR.commit();
+
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ DNSQuestion dq(&name, QType::A, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ BOOST_CHECK_EQUAL(found, false);
+ BOOST_CHECK(!subnet);
+
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
+
+ bool allowTruncated = true;
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
+ BOOST_CHECK_EQUAL(found, true);
+ BOOST_CHECK(!subnet);
+
+ allowTruncated = false;
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
+ BOOST_CHECK_EQUAL(found, false);
+}
+ catch(const PDNSException& e) {
+ cerr<<"Had error: "<<e.reason<<endl;
+ throw;
+ }
+}
+
static DNSDistPacketCache g_PC(500000);
static void threadMangler(unsigned int offset)