#include "dnsdist-cache.hh"
#include "gettime.hh"
-BOOST_AUTO_TEST_SUITE(dnsdistpacketcache_cc)
+BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc)
BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
const size_t maxEntries = 150000;
size_t counter=0;
size_t skipped=0;
ComboAddress remote;
+ bool dnssecOK = false;
try {
for(counter = 0; counter < 100000; ++counter) {
DNSName a=DNSName(std::to_string(counter))+DNSName(" hello");
pwR.getHeader()->ra = 1;
pwR.getHeader()->qr = 1;
pwR.getHeader()->id = pwQ.getHeader()->id;
- pwR.startRecord(a, QType::A, 100, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
pwR.xfr32BitInt(0x01020304);
pwR.commit();
uint16_t responseLen = response.size();
boost::optional<Netmask> subnet;
auto dh = reinterpret_cast<dnsheader*>(query.data());
DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet);
+ bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, 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, subnet, 0, true);
+ found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
if (found == true) {
BOOST_CHECK_EQUAL(responseBufSize, responseLen);
int match = memcmp(responseBuf, response.data(), responseLen);
uint32_t key = 0;
boost::optional<Netmask> subnet;
DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet);
+ bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
if (found == true) {
- PC.expungeByName(a);
- deleted++;
+ auto removed = PC.expungeByName(a);
+ BOOST_CHECK_EQUAL(removed, 1);
+ deleted += removed;
}
}
BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted);
-
size_t matches=0;
vector<DNSResourceRecord> entry;
size_t expected=counter-skipped-deleted;
char response[4096];
uint16_t responseSize = sizeof(response);
DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), len, query.size(), false, &queryTime);
- if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key, subnet)) {
+ if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key, subnet, dnssecOK)) {
matches++;
}
}
- BOOST_CHECK_EQUAL(matches, expected);
- PC.expungeByName(DNSName(" hello"), QType::ANY, true);
+ /* in the unlikely event that the test took so long that the entries did expire.. */
+ auto expired = PC.purgeExpired();
+ BOOST_CHECK_EQUAL(matches + expired, expected);
+
+ auto remaining = PC.getSize();
+ auto removed = PC.expungeByName(DNSName(" hello"), QType::ANY, true);
BOOST_CHECK_EQUAL(PC.getSize(), 0);
+ BOOST_CHECK_EQUAL(removed, remaining);
}
catch(PDNSException& e) {
cerr<<"Had error: "<<e.reason<<endl;
gettime(&queryTime); // does not have to be accurate ("realTime") in tests
ComboAddress remote;
+ bool dnssecOK = false;
try {
DNSName a = DNSName("servfail");
BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
boost::optional<Netmask> subnet;
auto dh = reinterpret_cast<dnsheader*>(query.data());
DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet);
+ bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
// Insert with failure-TTL of 0 (-> should not enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), 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, subnet, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, 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, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
// Insert with failure-TTL non-zero (-> should enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), 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, subnet, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, 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, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
}
gettime(&queryTime); // does not have to be accurate ("realTime") in tests
ComboAddress remote;
+ bool dnssecOK = false;
try {
DNSName name("nodata");
vector<uint8_t> query;
boost::optional<Netmask> subnet;
auto dh = reinterpret_cast<dnsheader*>(query.data());
DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet);
+ bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NoError, boost::none);
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NoError, boost::none);
+ found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
sleep(2);
/* it should have expired by now */
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, 0, true);
+ found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
}
gettime(&queryTime); // does not have to be accurate ("realTime") in tests
ComboAddress remote;
+ bool dnssecOK = false;
try {
DNSName name("nxdomain");
vector<uint8_t> query;
boost::optional<Netmask> subnet;
auto dh = reinterpret_cast<dnsheader*>(query.data());
DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet);
+ bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NXDomain, boost::none);
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NXDomain, boost::none);
+ found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
sleep(2);
/* it should have expired by now */
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, 0, true);
+ found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
}
gettime(&queryTime); // does not have to be accurate ("realTime") in tests
try {
ComboAddress remote;
+ bool dnssecOK = false;
unsigned int offset=(unsigned int)(unsigned long)off;
for(unsigned int counter=0; counter < 100000; ++counter) {
DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
boost::optional<Netmask> subnet;
auto dh = reinterpret_cast<dnsheader*>(query.data());
DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet);
+ PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
}
}
catch(PDNSException& e) {
static void *threadReader(void* off)
{
+ bool dnssecOK = false;
struct timespec queryTime;
gettime(&queryTime); // does not have to be accurate ("realTime") in tests
try
uint32_t key = 0;
boost::optional<Netmask> subnet;
DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet);
+ bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
if (!found) {
g_missing++;
}
uint32_t key;
uint32_t secondKey;
boost::optional<Netmask> subnetOut;
+ bool dnssecOK = false;
/* lookup for a query with an ECS value of 10.0.118.46/32,
insert a corresponding response */
struct timespec queryTime;
gettime(&queryTime);
DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut);
+ bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_REQUIRE(subnetOut);
BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
pwR.addOpt(512, 0, 0, ednsOptions);
pwR.commit();
- PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none);
+ PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none);
BOOST_CHECK_EQUAL(PC.getSize(), 1);
- found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut);
+ found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
BOOST_CHECK_EQUAL(found, true);
BOOST_REQUIRE(subnetOut);
BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
struct timespec queryTime;
gettime(&queryTime);
DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &secondKey, subnetOut);
+ bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &secondKey, subnetOut, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK_EQUAL(secondKey, key);
BOOST_REQUIRE(subnetOut);
}
}
+BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
+ const size_t maxEntries = 150000;
+ DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true);
+ BOOST_CHECK_EQUAL(PC.getSize(), 0);
+
+ DNSName qname("www.powerdns.com.");
+ uint16_t qtype = QType::AAAA;
+ uint16_t qid = 0x42;
+ uint32_t key;
+ boost::optional<Netmask> subnetOut;
+
+ /* lookup for a query with DNSSEC OK,
+ insert a corresponding response with DO set,
+ check that it doesn't match without DO, but does with it */
+ {
+ vector<uint8_t> query;
+ DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+ pwQ.getHeader()->id = qid;
+ pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
+ pwQ.commit();
+
+ char responseBuf[4096];
+ uint16_t responseBufSize = sizeof(responseBuf);
+ ComboAddress remote("192.0.2.1");
+ struct timespec queryTime;
+ gettime(&queryTime);
+ DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
+ bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
+ BOOST_CHECK_EQUAL(found, false);
+
+ vector<uint8_t> response;
+ DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->id = qid;
+ pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
+ ComboAddress v6("::1");
+ pwR.xfrCAWithoutPort(6, v6);
+ pwR.commit();
+ pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
+ pwR.commit();
+
+ PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none);
+ BOOST_CHECK_EQUAL(PC.getSize(), 1);
+
+ found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, false);
+ BOOST_CHECK_EQUAL(found, false);
+
+ found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
+ BOOST_CHECK_EQUAL(found, true);
+ }
+
+}
+
BOOST_AUTO_TEST_SUITE_END()