*flags |= origFlags;
}
+static uint16_t getRDAndCDFlagsFromDNSHeader(const struct dnsheader* dh)
+{
+ return static_cast<uint16_t>((dh->rd << FLAGS_RD_OFFSET) + (dh->cd << FLAGS_CD_OFFSET));
+}
+
static bool fixUpQueryTurnedResponse(DNSQuestion& dq, const uint16_t origFlags)
{
restoreFlags(dq.getHeader(), origFlags);
return false;
}
+ /* We need to get the flags for the packet cache before restoring the original ones, otherwise it might not match later queries */
+ const auto cacheFlags = getRDAndCDFlagsFromDNSHeader(dr.getHeader());
+
bool zeroScope = false;
if (!fixUpResponse(response, *dr.qname, dr.origFlags, dr.ednsAdded, dr.ecsAdded, dr.useZeroScope ? &zeroScope : nullptr)) {
return false;
zeroScope = false;
}
// if zeroScope, pass the pre-ECS hash-key and do not pass the subnet to the cache
- dr.packetCache->insert(zeroScope ? dr.cacheKeyNoECS : dr.cacheKey, zeroScope ? boost::none : dr.subnet, dr.origFlags, dr.dnssecOK, *dr.qname, dr.qtype, dr.qclass, response, receivedOverUDP, dr.getHeader()->rcode, dr.tempFailureTTL);
+ dr.packetCache->insert(zeroScope ? dr.cacheKeyNoECS : dr.cacheKey, zeroScope ? boost::none : dr.subnet, cacheFlags, dr.dnssecOK, *dr.qname, dr.qtype, dr.qclass, response, receivedOverUDP, dr.getHeader()->rcode, dr.tempFailureTTL);
}
#ifdef HAVE_DNSCRYPT
if (dq.packetCache && !dq.skipCache) {
if (dq.packetCache->get(dq, dq.getHeader()->id, &dq.cacheKey, dq.subnet, dq.dnssecOK, !dq.overTCP() || dq.getProtocol() == DNSQuestion::Protocol::DoH, allowExpired)) {
+ restoreFlags(dq.getHeader(), dq.origFlags);
+
if (!prepareOutgoingResponse(holders, cs, dq, true)) {
return ProcessQueryResult::Drop;
}
self.assertTrue(receivedResponse)
self.assertEqual(receivedResponse, response)
-
class TestCachingWithExistingEDNS(DNSDistTest):
_config_template = """
receivedQuery.id = expectedQuery2.id
self.checkMessageEDNSWithECS(expectedQuery2, receivedQuery)
self.checkMessageNoEDNS(receivedResponse, response)
+
+class TestCachingAlteredHeader(DNSDistTest):
+
+ _config_template = """
+ pc = newPacketCache(100)
+ getPool(""):setCache(pc)
+ addAction("cache-set-rd.tests.powerdns.com.", SetNoRecurseAction())
+ newServer{address="127.0.0.1:%d"}
+ """
+
+ def testCachingAlteredHeader(self):
+ """
+ Cache: The header has been altered via a rule
+ """
+ name = 'cache-set-rd.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN')
+ # the query reaching the backend will never have the RD flag set
+ expectedQuery = dns.message.make_query(name, 'A', 'IN')
+ expectedQuery.flags &= ~dns.flags.RD
+ response = dns.message.make_response(query)
+ response.flags &= ~dns.flags.RD
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1')
+ response.answer.append(rrset)
+
+ # first query has RD=1
+ query.flags |= dns.flags.RD
+ expectedResponse = dns.message.make_response(query)
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1')
+ expectedResponse.answer.append(rrset)
+
+ (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+ self.assertTrue(receivedQuery)
+ self.assertTrue(receivedResponse)
+ receivedQuery.id = expectedQuery.id
+ self.assertEqual(expectedQuery, receivedQuery)
+ self.assertEqual(receivedResponse, expectedResponse)
+
+ # next query should hit the cache
+ (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+ self.assertFalse(receivedQuery)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(receivedResponse, expectedResponse)
+
+ # same query with RD=0, should hit the cache as well
+ query.flags &= ~dns.flags.RD
+ expectedResponse = dns.message.make_response(query)
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1')
+ expectedResponse.answer.append(rrset)
+ (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+ self.assertFalse(receivedQuery)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(receivedResponse, expectedResponse)