{
d_optionsToSkip = optionsToSkip;
}
+
+std::set<DNSName> DNSDistPacketCache::getDomainsContainingRecords(const ComboAddress& addr)
+{
+ std::set<DNSName> domains;
+
+ for (auto& shard : d_shards) {
+ auto map = shard.d_map.read_lock();
+
+ for (const auto& entry : *map) {
+ const CacheValue& value = entry.second;
+
+ try {
+ dnsheader dh;
+ if (value.len >= sizeof(dnsheader)) {
+ memcpy(&dh, value.value.data(), sizeof(dnsheader));
+ }
+ if (dh.rcode != RCode::NoError || (dh.ancount == 0 && dh.nscount == 0 && dh.arcount == 0)) {
+ continue;
+ }
+
+ bool found = false;
+ bool valid = visitDNSPacket(value.value, [addr, &found](uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl, uint16_t rdatalength, const char* rdata) {
+
+ if (qtype == QType::A && qclass == QClass::IN && addr.isIPv4() && rdatalength == 4 && rdata != nullptr) {
+ ComboAddress parsed;
+ parsed.sin4.sin_family = AF_INET;
+ memcpy(&parsed.sin4.sin_addr.s_addr, rdata, rdatalength);
+ if (parsed == addr) {
+ found = true;
+ return true;
+ }
+ }
+ else if (qtype == QType::AAAA && qclass == QClass::IN && addr.isIPv6() && rdatalength == 16 && rdata != nullptr) {
+ ComboAddress parsed;
+ parsed.sin6.sin6_family = AF_INET6;
+ memcpy(&parsed.sin6.sin6_addr.s6_addr, rdata, rdatalength);
+ if (parsed == addr) {
+ found = true;
+ return true;
+ }
+ }
+
+ return false;
+ });
+
+ if (valid && found) {
+ domains.insert(value.qname);
+ }
+ }
+ catch (...) {
+ continue;
+ }
+ }
+ }
+
+ return domains;
+}
+
+std::set<ComboAddress> DNSDistPacketCache::getRecordsForDomain(const DNSName& domain)
+{
+ std::set<ComboAddress> addresses;
+
+ for (auto& shard : d_shards) {
+ auto map = shard.d_map.read_lock();
+
+ for (const auto& entry : *map) {
+ const CacheValue& value = entry.second;
+
+ try {
+ if (value.qname != domain) {
+ continue;
+ }
+
+ dnsheader dh;
+ if (value.len >= sizeof(dnsheader)) {
+ memcpy(&dh, value.value.data(), sizeof(dnsheader));
+ }
+ if (dh.rcode != RCode::NoError || (dh.ancount == 0 && dh.nscount == 0 && dh.arcount == 0)) {
+ continue;
+ }
+
+ visitDNSPacket(value.value, [&addresses](uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl, uint16_t rdatalength, const char* rdata) {
+
+ if (qtype == QType::A && qclass == QClass::IN && rdatalength == 4 && rdata != nullptr) {
+ ComboAddress parsed;
+ parsed.sin4.sin_family = AF_INET;
+ memcpy(&parsed.sin4.sin_addr.s_addr, rdata, rdatalength);
+ addresses.insert(parsed);
+ }
+ else if (qtype == QType::AAAA && qclass == QClass::IN && rdatalength == 16 && rdata != nullptr) {
+ ComboAddress parsed;
+ parsed.sin6.sin6_family = AF_INET6;
+ memcpy(&parsed.sin6.sin6_addr.s6_addr, rdata, rdatalength);
+ addresses.insert(parsed);
+ }
+
+ return false;
+ });
+ }
+ catch (...) {
+ continue;
+ }
+ }
+ }
+
+ return addresses;
+}
}
}
-
BOOST_AUTO_TEST_CASE(test_PacketCacheSharded) {
const size_t maxEntries = 150000;
const size_t numberOfShards = 10;
}
+BOOST_AUTO_TEST_CASE(test_PacketCacheInspection) {
+ const size_t maxEntries = 100;
+ DNSDistPacketCache PC(maxEntries, 86400, 1);
+ BOOST_CHECK_EQUAL(PC.getSize(), 0U);
+ struct timespec queryTime;
+ gettime(&queryTime); // does not have to be accurate ("realTime") in tests
+
+ ComboAddress remote;
+ bool dnssecOK = false;
+
+ uint32_t key = 0;
+
+ /* insert powerdns.com A 192.0.2.1, 192.0.2.2 */
+ {
+ DNSName qname("powerdns.com");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = pwQ.getHeader()->id;
+ {
+ ComboAddress addr("192.0.2.1");
+ pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfrCAWithoutPort(4, addr);
+ pwR.commit();
+ }
+ {
+ ComboAddress addr("192.0.2.2");
+ pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfrCAWithoutPort(4, addr);
+ pwR.commit();
+ }
+
+ PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ BOOST_CHECK_EQUAL(PC.getSize(), key);
+ }
+
+ /* insert powerdns1.com A 192.0.2.3, 192.0.2.4, AAAA 2001:db8::3, 2001:db8::4 */
+ {
+ DNSName qname("powerdns1.com");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = pwQ.getHeader()->id;
+ {
+ ComboAddress addr("192.0.2.3");
+ pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfrCAWithoutPort(4, addr);
+ pwR.commit();
+ }
+ {
+ ComboAddress addr("192.0.2.4");
+ pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfrCAWithoutPort(4, addr);
+ pwR.commit();
+ }
+ {
+ ComboAddress addr("2001:db8::3");
+ pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ pwR.xfrCAWithoutPort(6, addr);
+ pwR.commit();
+ }
+ {
+ ComboAddress addr("2001:db8::4");
+ pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ pwR.xfrCAWithoutPort(6, addr);
+ pwR.commit();
+ }
+
+ PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ BOOST_CHECK_EQUAL(PC.getSize(), key);
+ }
+
+ /* insert powerdns2.com NODATA */
+ {
+ DNSName qname("powerdns2.com");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = pwQ.getHeader()->id;
+ pwR.commit();
+ pwR.startRecord(qname, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
+ pwR.commit();
+ pwR.addOpt(4096, 0, 0);
+ pwR.commit();
+
+ PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ BOOST_CHECK_EQUAL(PC.getSize(), key);
+ }
+
+ /* insert powerdns3.com AAAA 2001:db8::4, 2001:db8::5 */
+ {
+ DNSName qname("powerdns3.com");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = pwQ.getHeader()->id;
+ {
+ ComboAddress addr("2001:db8::4");
+ pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ pwR.xfrCAWithoutPort(6, addr);
+ pwR.commit();
+ }
+ {
+ ComboAddress addr("2001:db8::5");
+ pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ pwR.xfrCAWithoutPort(6, addr);
+ pwR.commit();
+ }
+
+ PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ BOOST_CHECK_EQUAL(PC.getSize(), key);
+ }
+
+ /* insert powerdns4.com A 192.0.2.1 */
+ {
+ DNSName qname("powerdns4.com");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = pwQ.getHeader()->id;
+ {
+ ComboAddress addr("192.0.2.1");
+ pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ pwR.xfrCAWithoutPort(4, addr);
+ pwR.commit();
+ }
+
+ PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ BOOST_CHECK_EQUAL(PC.getSize(), key);
+ }
+
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.1"));
+ BOOST_CHECK_EQUAL(domains.size(), 2U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns.com")), 1U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns4.com")), 1U);
+ }
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.2"));
+ BOOST_CHECK_EQUAL(domains.size(), 1U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns.com")), 1U);
+ }
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.3"));
+ BOOST_CHECK_EQUAL(domains.size(), 1U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
+ }
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.4"));
+ BOOST_CHECK_EQUAL(domains.size(), 1U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
+ }
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.5"));
+ BOOST_CHECK_EQUAL(domains.size(), 0U);
+ }
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::3"));
+ BOOST_CHECK_EQUAL(domains.size(), 1U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
+ }
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::4"));
+ BOOST_CHECK_EQUAL(domains.size(), 2U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns3.com")), 1U);
+ }
+ {
+ auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::5"));
+ BOOST_CHECK_EQUAL(domains.size(), 1U);
+ BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns3.com")), 1U);
+ }
+
+ {
+ auto records = PC.getRecordsForDomain(DNSName("powerdns.com"));
+ BOOST_CHECK_EQUAL(records.size(), 2U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.1")), 1U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.2")), 1U);
+ }
+
+ {
+ auto records = PC.getRecordsForDomain(DNSName("powerdns1.com"));
+ BOOST_CHECK_EQUAL(records.size(), 4U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.3")), 1U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.4")), 1U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::3")), 1U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U);
+ }
+
+ {
+ auto records = PC.getRecordsForDomain(DNSName("powerdns2.com"));
+ BOOST_CHECK_EQUAL(records.size(), 0U);
+ }
+
+ {
+ auto records = PC.getRecordsForDomain(DNSName("powerdns3.com"));
+ BOOST_CHECK_EQUAL(records.size(), 2U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U);
+ }
+
+ {
+ auto records = PC.getRecordsForDomain(DNSName("powerdns4.com"));
+ BOOST_CHECK_EQUAL(records.size(), 1U);
+ BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.1")), 1U);
+ }
+
+ {
+ auto records = PC.getRecordsForDomain(DNSName("powerdns5.com"));
+ BOOST_CHECK_EQUAL(records.size(), 0U);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()