if (response.size() < sizeof(dnsheader)) {
return;
}
+ if (qtype == QType::AXFR || qtype == QType::IXFR) {
+ return;
+ }
uint32_t minTTL;
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, bool recordMiss)
{
+ if (dq.ids.qtype == QType::AXFR || dq.ids.qtype == QType::IXFR) {
+ d_misses++;
+ return false;
+ }
+
const auto& dnsQName = dq.ids.qname.getStorage();
uint32_t key = getKey(dnsQName, dq.ids.qname.wirelength(), dq.getData(), receivedOverUDP);
-- this rule will route SOA, AXFR and IXFR queries to a specific pool of servers
addAction(OrRule({QTypeRule(DNSQType.SOA), QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)}), PoolAction("primary"))
+.. versionchanged:: 1.8.0
+ Since 1.8.0, dnsdist will no longer cache responses to AXFR and IXFR queries.
+
In front of secondaries
-----------------------
1.7.x to 1.8.0
--------------
+Responses to AXFR and IXFR queries are no longer cached.
+
Cache-hits are now counted as responses in our metrics.
1.7.0 to 1.7.1
}
}
+BOOST_AUTO_TEST_CASE(test_PacketCacheXFR) {
+ const size_t maxEntries = 150000;
+ DNSDistPacketCache PC(maxEntries, 86400, 1);
+ BOOST_CHECK_EQUAL(PC.getSize(), 0U);
+
+ const std::set<QType> xfrTypes = { QType::AXFR, QType::IXFR };
+ for (const auto& type : xfrTypes) {
+ bool dnssecOK = false;
+ const time_t now = time(nullptr);
+ InternalQueryState ids;
+ ids.qtype = type;
+ ids.qclass = QClass::IN;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.qname = DNSName("powerdns.com.");
+
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, ids.qclass, 0);
+ pwQ.getHeader()->rd = 1;
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, ids.qtype, ids.qclass, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = pwQ.getHeader()->id;
+ pwR.startRecord(ids.qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfr32BitInt(0x01020304);
+ pwR.commit();
+
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ DNSQuestion dq(ids, query);
+ 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, ids.qname, ids.qtype, ids.qclass, response, receivedOverUDP, 0, boost::none);
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ BOOST_CHECK_EQUAL(found, false);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
value = self._responsesCounter[key]
self.assertEqual(value, numberOfQueries)
+ def testAXFRResponse(self):
+ """
+ Cache: AXFR should not be cached
+
+ dnsdist should not cache responses to AXFR queries.
+ """
+ name = 'axfr.cache.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'AXFR', 'IN')
+ response = dns.message.make_response(query)
+ soa = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.SOA,
+ 'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+ response.answer.append(soa)
+ response.answer.append(dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1'))
+ response.answer.append(soa)
+ numberOfQueries = 5
+
+ for _ in range(numberOfQueries):
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (receivedQuery, receivedResponse) = sender(query, response)
+ self.assertTrue(receivedQuery)
+ self.assertTrue(receivedResponse)
+ receivedQuery.id = query.id
+ self.assertEqual(query, receivedQuery)
+ self.assertEqual(receivedResponse, response)
+
+ for key in self._responsesCounter:
+ value = self._responsesCounter[key]
+ self.assertEqual(value, numberOfQueries)
+
+ def testIXFRResponse(self):
+ """
+ Cache: IXFR should not be cached
+
+ dnsdist should not cache responses to IXFR queries.
+ """
+ name = 'ixfr.cache.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'IXFR', 'IN')
+ response = dns.message.make_response(query)
+ soa = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.SOA,
+ 'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+ response.answer.append(soa)
+ response.answer.append(dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1'))
+ response.answer.append(soa)
+ numberOfQueries = 5
+
+ for _ in range(numberOfQueries):
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (receivedQuery, receivedResponse) = sender(query, response)
+ self.assertTrue(receivedQuery)
+ self.assertTrue(receivedResponse)
+ receivedQuery.id = query.id
+ self.assertEqual(query, receivedQuery)
+ self.assertEqual(receivedResponse, response)
+
+ for key in self._responsesCounter:
+ value = self._responsesCounter[key]
+ self.assertEqual(value, numberOfQueries)
+
def testCacheExpiration(self):
"""
Cache: Cache expiration