"Fossies" - the Fresh Open Source Software Archive

Member "pdns-auth-4.2.0/pdns/test-dnsdistpacketcache_cc.cc" (27 Aug 2019, 20877 Bytes) of package /linux/misc/dns/pdns-auth-4.2.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "test-dnsdistpacketcache_cc.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.1.13_vs_4.2.0.

    1 #define BOOST_TEST_DYN_LINK
    2 #define BOOST_TEST_NO_MAIN
    3 
    4 #include <boost/test/unit_test.hpp>
    5 
    6 #include "ednscookies.hh"
    7 #include "ednsoptions.hh"
    8 #include "ednssubnet.hh"
    9 #include "dnsdist.hh"
   10 #include "iputils.hh"
   11 #include "dnswriter.hh"
   12 #include "dnsdist-cache.hh"
   13 #include "gettime.hh"
   14 
   15 BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc)
   16 
   17 BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
   18   const size_t maxEntries = 150000;
   19   DNSDistPacketCache PC(maxEntries, 86400, 1);
   20   BOOST_CHECK_EQUAL(PC.getSize(), 0);
   21   struct timespec queryTime;
   22   gettime(&queryTime);  // does not have to be accurate ("realTime") in tests
   23 
   24   size_t counter=0;
   25   size_t skipped=0;
   26   ComboAddress remote;
   27   bool dnssecOK = false;
   28   try {
   29     for(counter = 0; counter < 100000; ++counter) {
   30       DNSName a=DNSName(std::to_string(counter))+DNSName(" hello");
   31       BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
   32 
   33       vector<uint8_t> query;
   34       DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
   35       pwQ.getHeader()->rd = 1;
   36 
   37       vector<uint8_t> response;
   38       DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
   39       pwR.getHeader()->rd = 1;
   40       pwR.getHeader()->ra = 1;
   41       pwR.getHeader()->qr = 1;
   42       pwR.getHeader()->id = pwQ.getHeader()->id;
   43       pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
   44       pwR.xfr32BitInt(0x01020304);
   45       pwR.commit();
   46       uint16_t responseLen = response.size();
   47 
   48       char responseBuf[4096];
   49       uint16_t responseBufSize = sizeof(responseBuf);
   50       uint32_t key = 0;
   51       boost::optional<Netmask> subnet;
   52       auto dh = reinterpret_cast<dnsheader*>(query.data());
   53       DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
   54       bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
   55       BOOST_CHECK_EQUAL(found, false);
   56       BOOST_CHECK(!subnet);
   57 
   58       PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
   59 
   60       found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
   61       if (found == true) {
   62         BOOST_CHECK_EQUAL(responseBufSize, responseLen);
   63         int match = memcmp(responseBuf, response.data(), responseLen);
   64         BOOST_CHECK_EQUAL(match, 0);
   65         BOOST_CHECK(!subnet);
   66       }
   67       else {
   68         skipped++;
   69       }
   70     }
   71 
   72     BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions());
   73     BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped);
   74 
   75     size_t deleted=0;
   76     size_t delcounter=0;
   77     for(delcounter=0; delcounter < counter/1000; ++delcounter) {
   78       DNSName a=DNSName(std::to_string(delcounter))+DNSName(" hello");
   79       vector<uint8_t> query;
   80       DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
   81       pwQ.getHeader()->rd = 1;
   82       char responseBuf[4096];
   83       uint16_t responseBufSize = sizeof(responseBuf);
   84       uint32_t key = 0;
   85       boost::optional<Netmask> subnet;
   86       DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
   87       bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
   88       if (found == true) {
   89         auto removed = PC.expungeByName(a);
   90         BOOST_CHECK_EQUAL(removed, 1);
   91         deleted += removed;
   92       }
   93     }
   94     BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted);
   95 
   96     size_t matches=0;
   97     vector<DNSResourceRecord> entry;
   98     size_t expected=counter-skipped-deleted;
   99     for(; delcounter < counter; ++delcounter) {
  100       DNSName a(DNSName(std::to_string(delcounter))+DNSName(" hello"));
  101       vector<uint8_t> query;
  102       DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
  103       pwQ.getHeader()->rd = 1;
  104       uint16_t len = query.size();
  105       uint32_t key = 0;
  106       boost::optional<Netmask> subnet;
  107       char response[4096];
  108       uint16_t responseSize = sizeof(response);
  109       DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), len, query.size(), false, &queryTime);
  110       if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key, subnet, dnssecOK)) {
  111         matches++;
  112       }
  113     }
  114 
  115     /* in the unlikely event that the test took so long that the entries did expire.. */
  116     auto expired = PC.purgeExpired();
  117     BOOST_CHECK_EQUAL(matches + expired, expected);
  118 
  119     auto remaining = PC.getSize();
  120     auto removed = PC.expungeByName(DNSName(" hello"), QType::ANY, true);
  121     BOOST_CHECK_EQUAL(PC.getSize(), 0);
  122     BOOST_CHECK_EQUAL(removed, remaining);
  123   }
  124   catch(PDNSException& e) {
  125     cerr<<"Had error: "<<e.reason<<endl;
  126     throw;
  127   }
  128 }
  129 
  130 BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) {
  131   const size_t maxEntries = 150000;
  132   DNSDistPacketCache PC(maxEntries, 86400, 1);
  133   struct timespec queryTime;
  134   gettime(&queryTime);  // does not have to be accurate ("realTime") in tests
  135 
  136   ComboAddress remote;
  137   bool dnssecOK = false;
  138   try {
  139     DNSName a = DNSName("servfail");
  140     BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
  141 
  142     vector<uint8_t> query;
  143     DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
  144     pwQ.getHeader()->rd = 1;
  145 
  146     vector<uint8_t> response;
  147     DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
  148     pwR.getHeader()->rd = 1;
  149     pwR.getHeader()->ra = 0;
  150     pwR.getHeader()->qr = 1;
  151     pwR.getHeader()->rcode = RCode::ServFail;
  152     pwR.getHeader()->id = pwQ.getHeader()->id;
  153     pwR.commit();
  154     uint16_t responseLen = response.size();
  155 
  156     char responseBuf[4096];
  157     uint16_t responseBufSize = sizeof(responseBuf);
  158     uint32_t key = 0;
  159     boost::optional<Netmask> subnet;
  160     auto dh = reinterpret_cast<dnsheader*>(query.data());
  161     DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
  162     bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
  163     BOOST_CHECK_EQUAL(found, false);
  164     BOOST_CHECK(!subnet);
  165 
  166     // Insert with failure-TTL of 0 (-> should not enter cache).
  167     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));
  168     found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
  169     BOOST_CHECK_EQUAL(found, false);
  170     BOOST_CHECK(!subnet);
  171 
  172     // Insert with failure-TTL non-zero (-> should enter cache).
  173     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));
  174     found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
  175     BOOST_CHECK_EQUAL(found, true);
  176     BOOST_CHECK(!subnet);
  177   }
  178   catch(PDNSException& e) {
  179     cerr<<"Had error: "<<e.reason<<endl;
  180     throw;
  181   }
  182 }
  183 
  184 BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) {
  185   const size_t maxEntries = 150000;
  186   DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
  187 
  188   struct timespec queryTime;
  189   gettime(&queryTime);  // does not have to be accurate ("realTime") in tests
  190 
  191   ComboAddress remote;
  192   bool dnssecOK = false;
  193   try {
  194     DNSName name("nodata");
  195     vector<uint8_t> query;
  196     DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0);
  197     pwQ.getHeader()->rd = 1;
  198 
  199     vector<uint8_t> response;
  200     DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0);
  201     pwR.getHeader()->rd = 1;
  202     pwR.getHeader()->ra = 0;
  203     pwR.getHeader()->qr = 1;
  204     pwR.getHeader()->rcode = RCode::NoError;
  205     pwR.getHeader()->id = pwQ.getHeader()->id;
  206     pwR.commit();
  207     pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
  208     pwR.commit();
  209     pwR.addOpt(4096, 0, 0);
  210     pwR.commit();
  211 
  212     uint16_t responseLen = response.size();
  213 
  214     char responseBuf[4096];
  215     uint16_t responseBufSize = sizeof(responseBuf);
  216     uint32_t key = 0;
  217     boost::optional<Netmask> subnet;
  218     auto dh = reinterpret_cast<dnsheader*>(query.data());
  219     DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
  220     bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
  221     BOOST_CHECK_EQUAL(found, false);
  222     BOOST_CHECK(!subnet);
  223 
  224     PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NoError, boost::none);
  225     found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
  226     BOOST_CHECK_EQUAL(found, true);
  227     BOOST_CHECK(!subnet);
  228 
  229     sleep(2);
  230     /* it should have expired by now */
  231     found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
  232     BOOST_CHECK_EQUAL(found, false);
  233     BOOST_CHECK(!subnet);
  234   }
  235   catch(const PDNSException& e) {
  236     cerr<<"Had error: "<<e.reason<<endl;
  237     throw;
  238   }
  239 }
  240 
  241 BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) {
  242   const size_t maxEntries = 150000;
  243   DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
  244 
  245   struct timespec queryTime;
  246   gettime(&queryTime);  // does not have to be accurate ("realTime") in tests
  247 
  248   ComboAddress remote;
  249   bool dnssecOK = false;
  250   try {
  251     DNSName name("nxdomain");
  252     vector<uint8_t> query;
  253     DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0);
  254     pwQ.getHeader()->rd = 1;
  255 
  256     vector<uint8_t> response;
  257     DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0);
  258     pwR.getHeader()->rd = 1;
  259     pwR.getHeader()->ra = 0;
  260     pwR.getHeader()->qr = 1;
  261     pwR.getHeader()->rcode = RCode::NXDomain;
  262     pwR.getHeader()->id = pwQ.getHeader()->id;
  263     pwR.commit();
  264     pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
  265     pwR.commit();
  266     pwR.addOpt(4096, 0, 0);
  267     pwR.commit();
  268 
  269     uint16_t responseLen = response.size();
  270 
  271     char responseBuf[4096];
  272     uint16_t responseBufSize = sizeof(responseBuf);
  273     uint32_t key = 0;
  274     boost::optional<Netmask> subnet;
  275     auto dh = reinterpret_cast<dnsheader*>(query.data());
  276     DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
  277     bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
  278     BOOST_CHECK_EQUAL(found, false);
  279     BOOST_CHECK(!subnet);
  280 
  281     PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NXDomain, boost::none);
  282     found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
  283     BOOST_CHECK_EQUAL(found, true);
  284     BOOST_CHECK(!subnet);
  285 
  286     sleep(2);
  287     /* it should have expired by now */
  288     found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
  289     BOOST_CHECK_EQUAL(found, false);
  290     BOOST_CHECK(!subnet);
  291   }
  292   catch(const PDNSException& e) {
  293     cerr<<"Had error: "<<e.reason<<endl;
  294     throw;
  295   }
  296 }
  297 
  298 static DNSDistPacketCache PC(500000);
  299 
  300 static void *threadMangler(void* off)
  301 {
  302   struct timespec queryTime;
  303   gettime(&queryTime);  // does not have to be accurate ("realTime") in tests
  304   try {
  305     ComboAddress remote;
  306     bool dnssecOK = false;
  307     unsigned int offset=(unsigned int)(unsigned long)off;
  308     for(unsigned int counter=0; counter < 100000; ++counter) {
  309       DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
  310       vector<uint8_t> query;
  311       DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
  312       pwQ.getHeader()->rd = 1;
  313 
  314       vector<uint8_t> response;
  315       DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
  316       pwR.getHeader()->rd = 1;
  317       pwR.getHeader()->ra = 1;
  318       pwR.getHeader()->qr = 1;
  319       pwR.getHeader()->id = pwQ.getHeader()->id;
  320       pwR.startRecord(a, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER);
  321       pwR.xfr32BitInt(0x01020304);
  322       pwR.commit();
  323       uint16_t responseLen = response.size();
  324 
  325       char responseBuf[4096];
  326       uint16_t responseBufSize = sizeof(responseBuf);
  327       uint32_t key = 0;
  328       boost::optional<Netmask> subnet;
  329       auto dh = reinterpret_cast<dnsheader*>(query.data());
  330       DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
  331       PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
  332 
  333       PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
  334     }
  335   }
  336   catch(PDNSException& e) {
  337     cerr<<"Had error: "<<e.reason<<endl;
  338     throw;
  339   }
  340   return 0;
  341 }
  342 
  343 AtomicCounter g_missing;
  344 
  345 static void *threadReader(void* off)
  346 {
  347   bool dnssecOK = false;
  348   struct timespec queryTime;
  349   gettime(&queryTime);  // does not have to be accurate ("realTime") in tests
  350   try
  351   {
  352     unsigned int offset=(unsigned int)(unsigned long)off;
  353     vector<DNSResourceRecord> entry;
  354     ComboAddress remote;
  355     for(unsigned int counter=0; counter < 100000; ++counter) {
  356       DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
  357       vector<uint8_t> query;
  358       DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
  359       pwQ.getHeader()->rd = 1;
  360 
  361       char responseBuf[4096];
  362       uint16_t responseBufSize = sizeof(responseBuf);
  363       uint32_t key = 0;
  364       boost::optional<Netmask> subnet;
  365       DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
  366       bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
  367       if (!found) {
  368     g_missing++;
  369       }
  370     }
  371   }
  372   catch(PDNSException& e) {
  373     cerr<<"Had error in threadReader: "<<e.reason<<endl;
  374     throw;
  375   }
  376   return 0;
  377 }
  378 
  379 BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) {
  380   try {
  381     pthread_t tid[4];
  382     for(int i=0; i < 4; ++i)
  383       pthread_create(&tid[i], 0, threadMangler, (void*)(i*1000000UL));
  384     void* res;
  385     for(int i=0; i < 4 ; ++i)
  386       pthread_join(tid[i], &res);
  387 
  388     BOOST_CHECK_EQUAL(PC.getSize() + PC.getDeferredInserts() + PC.getInsertCollisions(), 400000);
  389     BOOST_CHECK_SMALL(1.0*PC.getInsertCollisions(), 10000.0);
  390 
  391     for(int i=0; i < 4; ++i)
  392       pthread_create(&tid[i], 0, threadReader, (void*)(i*1000000UL));
  393     for(int i=0; i < 4 ; ++i)
  394       pthread_join(tid[i], &res);
  395 
  396     BOOST_CHECK((PC.getDeferredInserts() + PC.getDeferredLookups() + PC.getInsertCollisions()) >= g_missing);
  397   }
  398   catch(PDNSException& e) {
  399     cerr<<"Had error: "<<e.reason<<endl;
  400     throw;
  401   }
  402 
  403 }
  404 
  405 BOOST_AUTO_TEST_CASE(test_PCCollision) {
  406   const size_t maxEntries = 150000;
  407   DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true);
  408   BOOST_CHECK_EQUAL(PC.getSize(), 0);
  409 
  410   DNSName qname("www.powerdns.com.");
  411   uint16_t qtype = QType::AAAA;
  412   uint16_t qid = 0x42;
  413   uint32_t key;
  414   uint32_t secondKey;
  415   boost::optional<Netmask> subnetOut;
  416   bool dnssecOK = false;
  417 
  418   /* lookup for a query with an ECS value of 10.0.118.46/32,
  419      insert a corresponding response */
  420   {
  421     vector<uint8_t> query;
  422     DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
  423     pwQ.getHeader()->rd = 1;
  424     pwQ.getHeader()->id = qid;
  425     DNSPacketWriter::optvect_t ednsOptions;
  426     EDNSSubnetOpts opt;
  427     opt.source = Netmask("10.0.118.46/32");
  428     ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
  429     pwQ.addOpt(512, 0, 0, ednsOptions);
  430     pwQ.commit();
  431 
  432     char responseBuf[4096];
  433     uint16_t responseBufSize = sizeof(responseBuf);
  434     ComboAddress remote("192.0.2.1");
  435     struct timespec queryTime;
  436     gettime(&queryTime);
  437     DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
  438     bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
  439     BOOST_CHECK_EQUAL(found, false);
  440     BOOST_REQUIRE(subnetOut);
  441     BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
  442 
  443     vector<uint8_t> response;
  444     DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0);
  445     pwR.getHeader()->rd = 1;
  446     pwR.getHeader()->id = qid;
  447     pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
  448     ComboAddress v6("::1");
  449     pwR.xfrCAWithoutPort(6, v6);
  450     pwR.commit();
  451     pwR.addOpt(512, 0, 0, ednsOptions);
  452     pwR.commit();
  453 
  454     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);
  455     BOOST_CHECK_EQUAL(PC.getSize(), 1);
  456 
  457     found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
  458     BOOST_CHECK_EQUAL(found, true);
  459     BOOST_REQUIRE(subnetOut);
  460     BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
  461   }
  462 
  463   /* now lookup for the same query with an ECS value of 10.0.123.193/32
  464      we should get the same key (collision) but no match */
  465   {
  466     vector<uint8_t> query;
  467     DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
  468     pwQ.getHeader()->rd = 1;
  469     pwQ.getHeader()->id = qid;
  470     DNSPacketWriter::optvect_t ednsOptions;
  471     EDNSSubnetOpts opt;
  472     opt.source = Netmask("10.0.123.193/32");
  473     ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
  474     pwQ.addOpt(512, 0, 0, ednsOptions);
  475     pwQ.commit();
  476 
  477     char responseBuf[4096];
  478     uint16_t responseBufSize = sizeof(responseBuf);
  479     ComboAddress remote("192.0.2.1");
  480     struct timespec queryTime;
  481     gettime(&queryTime);
  482     DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
  483     bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &secondKey, subnetOut, dnssecOK);
  484     BOOST_CHECK_EQUAL(found, false);
  485     BOOST_CHECK_EQUAL(secondKey, key);
  486     BOOST_REQUIRE(subnetOut);
  487     BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
  488     BOOST_CHECK_EQUAL(PC.getLookupCollisions(), 1);
  489   }
  490 }
  491 
  492 BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
  493   const size_t maxEntries = 150000;
  494   DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true);
  495   BOOST_CHECK_EQUAL(PC.getSize(), 0);
  496 
  497   DNSName qname("www.powerdns.com.");
  498   uint16_t qtype = QType::AAAA;
  499   uint16_t qid = 0x42;
  500   uint32_t key;
  501   boost::optional<Netmask> subnetOut;
  502 
  503   /* lookup for a query with DNSSEC OK,
  504      insert a corresponding response with DO set,
  505      check that it doesn't match without DO, but does with it */
  506   {
  507     vector<uint8_t> query;
  508     DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
  509     pwQ.getHeader()->rd = 1;
  510     pwQ.getHeader()->id = qid;
  511     pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
  512     pwQ.commit();
  513 
  514     char responseBuf[4096];
  515     uint16_t responseBufSize = sizeof(responseBuf);
  516     ComboAddress remote("192.0.2.1");
  517     struct timespec queryTime;
  518     gettime(&queryTime);
  519     DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
  520     bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
  521     BOOST_CHECK_EQUAL(found, false);
  522 
  523     vector<uint8_t> response;
  524     DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0);
  525     pwR.getHeader()->rd = 1;
  526     pwR.getHeader()->id = qid;
  527     pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
  528     ComboAddress v6("::1");
  529     pwR.xfrCAWithoutPort(6, v6);
  530     pwR.commit();
  531     pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
  532     pwR.commit();
  533 
  534     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);
  535     BOOST_CHECK_EQUAL(PC.getSize(), 1);
  536 
  537     found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, false);
  538     BOOST_CHECK_EQUAL(found, false);
  539 
  540     found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
  541     BOOST_CHECK_EQUAL(found, true);
  542   }
  543 
  544 }
  545 
  546 BOOST_AUTO_TEST_SUITE_END()