#define BOOST_TEST_DYN_LINK #define BOOST_TEST_NO_MAIN #include #include "ednscookies.hh" #include "ednsoptions.hh" #include "ednssubnet.hh" #include "dnsdist.hh" #include "iputils.hh" #include "dnswriter.hh" #include "dnsdist-cache.hh" #include "gettime.hh" #include "packetcache.hh" BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc) static bool receivedOverUDP = true; BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) { const size_t maxEntries = 150000; 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 size_t counter=0; size_t skipped=0; ComboAddress remote; bool dnssecOK = false; const time_t now = time(nullptr); try { for (counter = 0; counter < 100000; ++counter) { DNSName a=DNSName(std::to_string(counter))+DNSName(" hello"); BOOST_CHECK_EQUAL(DNSName(a.toString()), a); PacketBuffer query; GenericDNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; PacketBuffer response; GenericDNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); pwR.getHeader()->rd = 1; pwR.getHeader()->ra = 1; pwR.getHeader()->qr = 1; pwR.getHeader()->id = pwQ.getHeader()->id; pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); pwR.xfr32BitInt(0x01020304); pwR.commit(); uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, 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, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); if (found == true) { BOOST_CHECK_EQUAL(dq.getData().size(), response.size()); int match = memcmp(dq.getData().data(), response.data(), dq.getData().size()); BOOST_CHECK_EQUAL(match, 0); BOOST_CHECK(!subnet); } else { skipped++; } } BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions()); BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped); size_t deleted=0; size_t delcounter=0; for (delcounter=0; delcounter < counter/1000; ++delcounter) { DNSName a=DNSName(std::to_string(delcounter))+DNSName(" hello"); PacketBuffer query; GenericDNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP); if (found == true) { auto removed = PC.expungeByName(a); BOOST_CHECK_EQUAL(removed, 1U); deleted += removed; } } BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted); size_t matches=0; size_t expected=counter-skipped-deleted; for (; delcounter < counter; ++delcounter) { DNSName a(DNSName(std::to_string(delcounter))+DNSName(" hello")); PacketBuffer query; GenericDNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); if (PC.get(dq, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) { matches++; } } /* in the unlikely event that the test took so long that the entries did expire.. */ auto expired = PC.purgeExpired(0, now); BOOST_CHECK_EQUAL(matches + expired, expected); auto remaining = PC.getSize(); auto removed = PC.expungeByName(DNSName(" hello"), QType::ANY, true); BOOST_CHECK_EQUAL(PC.getSize(), 0U); BOOST_CHECK_EQUAL(removed, remaining); /* nothing to remove */ BOOST_CHECK_EQUAL(PC.purgeExpired(0, now), 0U); } catch (const PDNSException& e) { cerr<<"Had error: "< pwQ(query, a, QType::AAAA, QClass::IN, 0); pwQ.getHeader()->rd = 1; PacketBuffer response; GenericDNSPacketWriter pwR(response, a, QType::AAAA, QClass::IN, 0); pwR.getHeader()->rd = 1; pwR.getHeader()->ra = 1; pwR.getHeader()->qr = 1; pwR.getHeader()->id = pwQ.getHeader()->id; pwR.startRecord(a, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER); ComboAddress v6("2001:db8::1"); pwR.xfrIP6(std::string(reinterpret_cast(v6.sin6.sin6_addr.s6_addr), 16)); pwR.xfr32BitInt(0x01020304); pwR.commit(); uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, QType::AAAA, 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, a, QType::AAAA, QClass::IN, response, receivedOverUDP, 0, boost::none); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); if (found == true) { BOOST_CHECK_EQUAL(dq.getData().size(), response.size()); int match = memcmp(dq.getData().data(), response.data(), dq.getData().size()); BOOST_CHECK_EQUAL(match, 0); BOOST_CHECK(!subnet); } else { skipped++; } } BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions()); BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped); size_t matches = 0; for (counter = 0; counter < 100000; ++counter) { DNSName a(std::to_string(counter) + ".powerdns.com."); PacketBuffer query; GenericDNSPacketWriter pwQ(query, a, QType::AAAA, QClass::IN, 0); pwQ.getHeader()->rd = 1; uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, QType::AAAA, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); if (PC.get(dq, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) { matches++; } } BOOST_CHECK_EQUAL(matches, counter - skipped); auto remaining = PC.getSize(); /* no entry should have expired */ auto expired = PC.purgeExpired(0, now); BOOST_CHECK_EQUAL(expired, 0U); /* but after the TTL .. let's ask for at most 1k entries */ auto removed = PC.purgeExpired(1000, now + 7200 + 3600); BOOST_CHECK_EQUAL(removed, remaining - 1000U); BOOST_CHECK_EQUAL(PC.getSize(), 1000U); /* now remove everything */ removed = PC.purgeExpired(0, now + 7200 + 3600); BOOST_CHECK_EQUAL(removed, 1000U); BOOST_CHECK_EQUAL(PC.getSize(), 0U); /* nothing to remove */ BOOST_CHECK_EQUAL(PC.purgeExpired(0, now), 0U); } catch (const PDNSException& e) { cerr<<"Had error: "< pwQ(query, a, QType::AAAA, QClass::IN, 0); pwQ.getHeader()->rd = 1; PacketBuffer response; GenericDNSPacketWriter pwR(response, a, QType::AAAA, QClass::IN, 0); pwR.getHeader()->rd = 1; pwR.getHeader()->ra = 1; pwR.getHeader()->qr = 1; pwR.getHeader()->id = pwQ.getHeader()->id; pwR.startRecord(a, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER); ComboAddress v6("2001:db8::1"); pwR.xfrIP6(std::string(reinterpret_cast(v6.sin6.sin6_addr.s6_addr), 16)); pwR.xfr32BitInt(0x01020304); pwR.commit(); { /* UDP */ uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, 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, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, true); BOOST_CHECK(!subnet); } { /* same but over TCP */ uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoTCP, &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, a, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, true); BOOST_CHECK(!subnet); } } catch(PDNSException& e) { cerr<<"Had error: "< pwQ(query, a, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; PacketBuffer response; GenericDNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); pwR.getHeader()->rd = 1; pwR.getHeader()->ra = 0; pwR.getHeader()->qr = 1; pwR.getHeader()->rcode = RCode::ServFail; pwR.getHeader()->id = pwQ.getHeader()->id; pwR.commit(); uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, 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); // Insert with failure-TTL of 0 (-> should not enter cache). PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional(0)); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, false); BOOST_CHECK(!subnet); // Insert with failure-TTL non-zero (-> should enter cache). PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional(300)); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, true); BOOST_CHECK(!subnet); } catch(PDNSException& e) { cerr<<"Had error: "< pwQ(query, name, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; PacketBuffer response; GenericDNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0); pwR.getHeader()->rd = 1; pwR.getHeader()->ra = 0; pwR.getHeader()->qr = 1; pwR.getHeader()->rcode = RCode::NoError; pwR.getHeader()->id = pwQ.getHeader()->id; pwR.commit(); pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY); pwR.commit(); pwR.addOpt(4096, 0, 0); pwR.commit(); uint32_t key = 0; boost::optional 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::NoError, boost::none); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, true); BOOST_CHECK(!subnet); sleep(2); /* it should have expired by now */ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, false); BOOST_CHECK(!subnet); } catch(const PDNSException& e) { cerr<<"Had error: "< pwQ(query, name, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; PacketBuffer response; GenericDNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0); pwR.getHeader()->rd = 1; pwR.getHeader()->ra = 0; pwR.getHeader()->qr = 1; pwR.getHeader()->rcode = RCode::NXDomain; pwR.getHeader()->id = pwQ.getHeader()->id; pwR.commit(); pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY); pwR.commit(); pwR.addOpt(4096, 0, 0); pwR.commit(); uint32_t key = 0; boost::optional 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); found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, true); BOOST_CHECK(!subnet); sleep(2); /* it should have expired by now */ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); BOOST_CHECK_EQUAL(found, false); BOOST_CHECK(!subnet); } catch(const PDNSException& e) { cerr<<"Had error: "< pwQ(query, a, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; PacketBuffer response; GenericDNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); pwR.getHeader()->rd = 1; pwR.getHeader()->ra = 1; pwR.getHeader()->qr = 1; pwR.getHeader()->id = pwQ.getHeader()->id; pwR.startRecord(a, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER); pwR.xfr32BitInt(0x01020304); pwR.commit(); uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); g_PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP); g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); } } catch(PDNSException& e) { cerr<<"Had error: "< pwQ(query, a, QType::A, QClass::IN, 0); pwQ.getHeader()->rd = 1; uint32_t key = 0; boost::optional subnet; DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); bool found = g_PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP); if (!found) { g_missing++; } } } catch(PDNSException& e) { cerr<<"Had error in threadReader: "< threads; for (int i = 0; i < 4; ++i) { threads.push_back(std::thread(threadMangler, i*1000000UL)); } for (auto& t : threads) { t.join(); } threads.clear(); BOOST_CHECK_EQUAL(g_PC.getSize() + g_PC.getDeferredInserts() + g_PC.getInsertCollisions(), 400000U); BOOST_CHECK_SMALL(1.0*g_PC.getInsertCollisions(), 10000.0); for (int i = 0; i < 4; ++i) { threads.push_back(std::thread(threadReader, i*1000000UL)); } for (auto& t : threads) { t.join(); } BOOST_CHECK((g_PC.getDeferredInserts() + g_PC.getDeferredLookups() + g_PC.getInsertCollisions()) >= g_missing); } catch(PDNSException& e) { cerr<<"Had error: "< subnetOut; bool dnssecOK = false; /* lookup for a query with a first ECS value, insert a corresponding response */ { PacketBuffer query; GenericDNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0); pwQ.getHeader()->rd = 1; pwQ.getHeader()->id = qid; GenericDNSPacketWriter::optvect_t ednsOptions; EDNSSubnetOpts opt; opt.source = Netmask("10.0.59.220/32"); ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); pwQ.addOpt(512, 0, 0, ednsOptions); pwQ.commit(); ComboAddress remote("192.0.2.1"); struct timespec queryTime; gettime(&queryTime); DNSQuestion dq(&qname, QType::AAAA, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); bool found = PC.get(dq, 0, &key, subnetOut, dnssecOK, receivedOverUDP); BOOST_CHECK_EQUAL(found, false); BOOST_REQUIRE(subnetOut); BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); PacketBuffer response; GenericDNSPacketWriter 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, 0, ednsOptions); pwR.commit(); PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, qname, qtype, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); BOOST_CHECK_EQUAL(PC.getSize(), 1U); found = PC.get(dq, 0, &key, subnetOut, dnssecOK, receivedOverUDP); BOOST_CHECK_EQUAL(found, true); BOOST_REQUIRE(subnetOut); BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); } /* now lookup for the same query with a different ECS value, we should get the same key (collision) but no match */ { PacketBuffer query; GenericDNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0); pwQ.getHeader()->rd = 1; pwQ.getHeader()->id = qid; GenericDNSPacketWriter::optvect_t ednsOptions; EDNSSubnetOpts opt; opt.source = Netmask("10.0.167.48/32"); ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); pwQ.addOpt(512, 0, 0, ednsOptions); pwQ.commit(); ComboAddress remote("192.0.2.1"); struct timespec queryTime; gettime(&queryTime); DNSQuestion dq(&qname, QType::AAAA, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); bool found = PC.get(dq, 0, &secondKey, subnetOut, dnssecOK, receivedOverUDP); BOOST_CHECK_EQUAL(found, false); BOOST_CHECK_EQUAL(secondKey, key); BOOST_REQUIRE(subnetOut); BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); BOOST_CHECK_EQUAL(PC.getLookupCollisions(), 1U); } #if 0 /* to be able to compute a new collision if the packet cache hashing code is updated */ { DNSDistPacketCache pc(10000); GenericDNSPacketWriter::optvect_t ednsOptions; EDNSSubnetOpts opt; std::map colMap; size_t collisions = 0; size_t total = 0; //qname = DNSName("collision-with-ecs-parsing.cache.tests.powerdns.com."); for (size_t idxA = 0; idxA < 256; idxA++) { for (size_t idxB = 0; idxB < 256; idxB++) { for (size_t idxC = 0; idxC < 256; idxC++) { PacketBuffer secondQuery; GenericDNSPacketWriter pwFQ(secondQuery, qname, QType::AAAA, QClass::IN, 0); pwFQ.getHeader()->rd = 1; pwFQ.getHeader()->qr = false; pwFQ.getHeader()->id = 0x42; opt.source = Netmask("10." + std::to_string(idxA) + "." + std::to_string(idxB) + "." + std::to_string(idxC) + "/32"); ednsOptions.clear(); ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); pwFQ.addOpt(512, 0, 0, ednsOptions); pwFQ.commit(); secondKey = pc.getKey(qname.toDNSString(), qname.wirelength(), secondQuery, false); auto pair = colMap.emplace(secondKey, opt.source); total++; if (!pair.second) { collisions++; cerr<<"Collision between "< 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 */ { PacketBuffer query; GenericDNSPacketWriter 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(); ComboAddress remote("192.0.2.1"); struct timespec queryTime; gettime(&queryTime); DNSQuestion dq(&qname, QType::AAAA, QClass::IN, &remote, &remote, query, dnsdist::Protocol::DoUDP, &queryTime); bool found = PC.get(dq, 0, &key, subnetOut, true, receivedOverUDP); BOOST_CHECK_EQUAL(found, false); PacketBuffer response; GenericDNSPacketWriter 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, response, receivedOverUDP, RCode::NoError, boost::none); BOOST_CHECK_EQUAL(PC.getSize(), 1U); found = PC.get(dq, 0, &key, subnetOut, false, receivedOverUDP); BOOST_CHECK_EQUAL(found, false); found = PC.get(dq, 0, &key, subnetOut, true, receivedOverUDP); BOOST_CHECK_EQUAL(found, true); } } BOOST_AUTO_TEST_SUITE_END()