]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Do full packet comparison in the packet caches in addition to the hash
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 19 Jul 2018 13:52:40 +0000 (15:52 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 11 Oct 2018 09:48:21 +0000 (11:48 +0200)
(cherry picked from commit aab08a02344a66e14572cf63129d157d6e7ba8c9)
(cherry picked from commit f48315332c4542d09b58a14dafadc90d04f54abd)

pdns/Makefile.am
pdns/auth-packetcache.cc
pdns/auth-packetcache.hh
pdns/packetcache.hh
pdns/pdns_recursor.cc
pdns/recpacketcache.cc
pdns/recpacketcache.hh
pdns/recursordist/Makefile.am
pdns/recursordist/test-packetcache_hh.cc [new symlink]
pdns/test-packetcache_hh.cc [new file with mode: 0644]
pdns/test-recpacketcache_cc.cc

index b570a0ffb265036b4d2a746b02c7e3e17d8048e1..0a99725c29d8b5b5e76052fc168a72ad5252d4c6 100644 (file)
@@ -1149,6 +1149,7 @@ testrunner_SOURCES = \
        dnssecsigner.cc \
        dnswriter.cc \
        ednsoptions.cc ednsoptions.hh \
+       ednscookies.cc \
        ednssubnet.cc \
        gettime.cc gettime.hh \
        gss_context.cc gss_context.hh \
@@ -1185,6 +1186,7 @@ testrunner_SOURCES = \
        test-nameserver_cc.cc \
        test-nmtree.cc \
        test-packetcache_cc.cc \
+       test-packetcache_hh.cc \
        test-rcpgenerator_cc.cc \
        test-signers.cc \
        test-sha_hh.cc \
index f28a6fdc37102bd69dce913e2a463d3942cdae38..f5a251ee09f0df9880584d1de3f2490acadf15c6 100644 (file)
@@ -72,7 +72,7 @@ bool AuthPacketCache::get(DNSPacket *p, DNSPacket *cached)
     return false;
   }
 
-  uint32_t hash = canHashPacket(p->getString(), false);
+  uint32_t hash = canHashPacket(p->getString());
   p->setHash(hash);
 
   string value;
@@ -86,7 +86,7 @@ bool AuthPacketCache::get(DNSPacket *p, DNSPacket *cached)
       return false;
     }
 
-    haveSomething = getEntryLocked(mc.d_map, hash, p->qdomain, p->qtype.getCode(), p->d_tcp, now, value);
+    haveSomething = getEntryLocked(mc.d_map, p->getString(), hash, p->qdomain, p->qtype.getCode(), p->d_tcp, now, value);
   }
 
   if (!haveSomething) {
@@ -106,6 +106,11 @@ bool AuthPacketCache::get(DNSPacket *p, DNSPacket *cached)
   return true;
 }
 
+bool AuthPacketCache::entryMatches(cmap_t::index<HashTag>::type::iterator& iter, const std::string& query, const DNSName& qname, uint16_t qtype, bool tcp)
+{
+  return iter->tcp == tcp && iter->qtype == qtype && iter->qname == qname && queryMatches(iter->query, query, qname);
+}
+
 void AuthPacketCache::insert(DNSPacket *q, DNSPacket *r, unsigned int maxTTL)
 {
   cleanupIfNeeded();
@@ -132,6 +137,7 @@ void AuthPacketCache::insert(DNSPacket *q, DNSPacket *r, unsigned int maxTTL)
   entry.qtype = q->qtype.getCode();
   entry.value = r->getString();
   entry.tcp = r->d_tcp;
+  entry.query = q->getString();
   
   auto& mc = getMap(entry.qname);
   {
@@ -146,8 +152,9 @@ void AuthPacketCache::insert(DNSPacket *q, DNSPacket *r, unsigned int maxTTL)
     auto iter = range.first;
 
     for( ; iter != range.second ; ++iter)  {
-      if (iter->tcp != entry.tcp || iter->qtype != entry.qtype || iter->qname != entry.qname)
+      if (!entryMatches(iter, entry.query, entry.qname, entry.qtype, entry.tcp)) {
         continue;
+      }
 
       iter->value = entry.value;
       iter->ttd = now + ourttl;
@@ -161,17 +168,19 @@ void AuthPacketCache::insert(DNSPacket *q, DNSPacket *r, unsigned int maxTTL)
   }
 }
 
-bool AuthPacketCache::getEntryLocked(cmap_t& map, uint32_t hash, const DNSName &qname, uint16_t qtype, bool tcp, time_t now, string& value)
+bool AuthPacketCache::getEntryLocked(cmap_t& map, const std::string& query, uint32_t hash, const DNSName &qname, uint16_t qtype, bool tcp, time_t now, string& value)
 {
   auto& idx = map.get<HashTag>();
   auto range = idx.equal_range(hash);
 
   for(auto iter = range.first; iter != range.second ; ++iter)  {
-    if (iter->ttd < now)
+    if (iter->ttd < now) {
       continue;
+    }
 
-    if (iter->tcp != tcp || iter->qtype != qtype || iter->qname != qname)
+    if (!entryMatches(iter, query, qname, qtype, tcp)) {
       continue;
+    }
 
     value = iter->value;
     return true;
index d817b5d843e7407b89c06003e147276866a8d4e8..934869d2b194d991397e578576e827dedc2b6f8e 100644 (file)
@@ -75,6 +75,7 @@ private:
 
   struct CacheEntry
   {
+    mutable string query;
     mutable string value;
     DNSName qname;
 
@@ -109,7 +110,8 @@ private:
     return d_maps[name.hash() % d_maps.size()];
   }
 
-  bool getEntryLocked(cmap_t& map, uint32_t hash, const DNSName &qname, uint16_t qtype, bool tcp, time_t now, string& entry);
+  static bool entryMatches(cmap_t::index<HashTag>::type::iterator& iter, const std::string& query, const DNSName& qname, uint16_t qtype, bool tcp);
+  bool getEntryLocked(cmap_t& map, const std::string& query, uint32_t hash, const DNSName &qname, uint16_t qtype, bool tcp, time_t now, string& entry);
   void cleanupIfNeeded();
 
   AtomicCounter d_ops{0};
index b0785fd9d96dfbf8c5b9bd585bb8faef5ffc9a2a..c3589108f43c9bbfa318136862f45d7643b954bf 100644 (file)
 
 class PacketCache : public boost::noncopyable
 {
-protected:
-  static uint32_t canHashPacket(const std::string& packet, bool skipECS=true)
+public:
+  static uint32_t canHashPacket(const std::string& packet, uint16_t* ecsBegin, uint16_t* ecsEnd)
   {
     uint32_t ret = 0;
-    ret=burtle((const unsigned char*)packet.c_str() + 2, 10, ret); // rest of dnsheader, skip id
+    ret = burtle(reinterpret_cast<const unsigned char*>(packet.c_str()) + 2, sizeof(dnsheader) - 2, ret); // rest of dnsheader, skip id
     size_t packetSize = packet.size();
-    size_t pos = 12;
+    size_t pos = sizeof(dnsheader);
     const char* end = packet.c_str() + packetSize;
     const char* p = packet.c_str() + pos;
 
@@ -43,36 +43,110 @@ protected:
       ret=burtle(&l, 1, ret);
     }                           // XXX the embedded 0 in the qname will break the subnet stripping
 
-    struct dnsheader* dh = (struct dnsheader*)packet.c_str();
+    const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.c_str());
     const char* skipBegin = p;
     const char* skipEnd = p;
+    if (ecsBegin != nullptr && ecsEnd != nullptr) {
+      *ecsBegin = 0;
+      *ecsEnd = 0;
+    }
     /* we need at least 1 (final empty label) + 2 (QTYPE) + 2 (QCLASS)
        + OPT root label (1), type (2), class (2) and ttl (4)
        + the OPT RR rdlen (2)
        = 16
     */
-    if(skipECS && ntohs(dh->arcount)==1 && (pos+16) < packetSize) {
+    if(ntohs(dh->arcount)==1 && (pos+16) < packetSize) {
       char* optionBegin = nullptr;
       size_t optionLen = 0;
       /* skip the final empty label (1), the qtype (2), qclass (2) */
       /* root label (1), type (2), class (2) and ttl (4) */
-      int res = getEDNSOption((char*) p + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen);
+      int res = getEDNSOption(const_cast<char*>(reinterpret_cast<const char*>(p)) + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen);
       if (res == 0) {
         skipBegin = optionBegin;
         skipEnd = optionBegin + optionLen;
+        if (ecsBegin != nullptr && ecsEnd != nullptr) {
+          *ecsBegin = optionBegin - packet.c_str();
+          *ecsEnd = *ecsBegin + optionLen;
+        }
       }
     }
     if (skipBegin > p) {
-      // cerr << "Hashing from " << (p-packet.c_str()) << " for " << skipBegin-p << "bytes, end is at "<< end-packet.c_str() << endl;
-      ret = burtle((const unsigned char*)p, skipBegin-p, ret);
+      ret = burtle(reinterpret_cast<const unsigned char*>(p), skipBegin-p, ret);
     }
     if (skipEnd < end) {
-      // cerr << "Hashing from " << (skipEnd-packet.c_str()) << " for " << end-skipEnd << "bytes, end is at " << end-packet.c_str() << endl;
-      ret = burtle((const unsigned char*) skipEnd, end-skipEnd, ret);
+      ret = burtle(reinterpret_cast<const unsigned char*>(skipEnd), end-skipEnd, ret);
     }
 
     return ret;
   }
+
+  static uint32_t canHashPacket(const std::string& packet)
+  {
+    uint32_t ret = 0;
+    ret = burtle(reinterpret_cast<const unsigned char*>(packet.c_str()) + 2, sizeof(dnsheader) - 2, ret); // rest of dnsheader, skip id
+    size_t packetSize = packet.size();
+    size_t pos = sizeof(dnsheader);
+    const char* end = packet.c_str() + packetSize;
+    const char* p = packet.c_str() + pos;
+
+    for(; p < end && *p; ++p) { // XXX if you embed a 0 in your qname we'll stop lowercasing there
+      const unsigned char l = dns_tolower(*p); // label lengths can safely be lower cased
+      ret=burtle(&l, 1, ret);
+    }                           // XXX the embedded 0 in the qname will break the subnet stripping
+
+    if (p < end) {
+      ret = burtle(reinterpret_cast<const unsigned char*>(p), end-p, ret);
+    }
+
+    return ret;
+  }
+
+  static bool queryHeaderMatches(const std::string& cachedQuery, const std::string& query)
+  {
+    if (cachedQuery.size() != query.size()) {
+      return false;
+    }
+
+    return (cachedQuery.compare(/* skip the ID */ 2, sizeof(dnsheader) - 2, query, 2, sizeof(dnsheader) - 2) == 0);
+  }
+
+  static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname)
+  {
+    if (!queryHeaderMatches(cachedQuery, query)) {
+      return false;
+    }
+
+    size_t pos = sizeof(dnsheader) + qname.wirelength();
+
+    return (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) == 0);
+  }
+
+  static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname, uint16_t ecsBegin, uint16_t ecsEnd)
+  {
+    if (!queryHeaderMatches(cachedQuery, query)) {
+      return false;
+    }
+
+    size_t pos = sizeof(dnsheader) + qname.wirelength();
+
+    if (ecsBegin != 0 && ecsBegin >= pos && ecsEnd > ecsBegin) {
+      if (cachedQuery.compare(pos, ecsBegin - pos, query, pos, ecsBegin - pos) != 0) {
+        return false;
+      }
+
+      if (cachedQuery.compare(ecsEnd, cachedQuery.size() - ecsEnd, query, ecsEnd, query.size() - ecsEnd) != 0) {
+        return false;
+      }
+    }
+    else {
+      if (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) != 0) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
 };
 
 #endif /* PACKETCACHE_HH */
index 43601c2f3f30c2394164f1a96429519a371650c2..78b9eb74d9f2b94763e77570994fbecba42f4bdd 100644 (file)
@@ -219,6 +219,7 @@ struct DNSComboWriter {
   string d_requestorId;
   string d_deviceId;
 #endif
+  std::string d_query;
   EDNSSubnetOpts d_ednssubnet;
   bool d_ecsFound{false};
   bool d_ecsParsed{false};
@@ -226,12 +227,13 @@ struct DNSComboWriter {
   int d_socket;
   unsigned int d_tag{0};
   uint32_t d_qhash{0};
-  string d_query;
   shared_ptr<TCPConnection> d_tcpConnection;
   vector<pair<uint16_t, string> > d_ednsOpts;
   std::vector<std::string> d_policyTags;
   LuaContext::LuaObject d_data;
   uint32_t d_ttlCap{std::numeric_limits<uint32_t>::max()};
+  uint16_t d_ecsBegin{0};
+  uint16_t d_ecsEnd{0};
   bool d_variable{false};
 };
 
@@ -1208,11 +1210,13 @@ static void startDoResolve(void *p)
         L<<Logger::Warning<<"Sending UDP reply to client "<<dc->d_remote.toStringWithPort()<<" failed with: "<<strerror(errno)<<endl;
 
       if(!SyncRes::s_nopacketcache && !variableAnswer && !sr.wasVariable() ) {
-        t_packetCache->insertResponsePacket(dc->d_tag, dc->d_qhash, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass,
+        t_packetCache->insertResponsePacket(dc->d_tag, dc->d_qhash, dc->d_query, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass,
                                             string((const char*)&*packet.begin(), packet.size()),
                                             g_now.tv_sec,
                                             pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
                                             min(minTTL,SyncRes::s_packetcachettl),
+                                            dc->d_ecsBegin,
+                                            dc->d_ecsEnd,
                                             &pbMessage);
       }
       //      else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
@@ -1664,6 +1668,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
   EDNSSubnetOpts ednssubnet;
   bool ecsFound = false;
   bool ecsParsed = false;
+  uint16_t ecsBegin = 0;
+  uint16_t ecsEnd = 0;
   uint32_t ttlCap = std::numeric_limits<uint32_t>::max();
   bool variable = false;
   try {
@@ -1727,10 +1733,10 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
        but it means that the hash would not be computed. If some script decides at a later time to mark back the answer
        as cacheable we would cache it with a wrong tag, so better safe than sorry. */
     if (qnameParsed) {
-      cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &qhash, &pbMessage));
+      cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &qhash, &ecsBegin, &ecsEnd, &pbMessage));
     }
     else {
-      cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, g_now.tv_sec, &response, &age, &qhash, &pbMessage));
+      cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, &qtype, &qclass, g_now.tv_sec, &response, &age, &qhash, &ecsBegin, &ecsEnd, &pbMessage));
     }
 
     if (cacheHit) {
@@ -1808,6 +1814,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
   dc->d_data = data;
   dc->d_ecsFound = ecsFound;
   dc->d_ecsParsed = ecsParsed;
+  dc->d_ecsBegin = ecsBegin;
+  dc->d_ecsEnd = ecsEnd;
   dc->d_ednssubnet = ednssubnet;
   dc->d_ttlCap = ttlCap;
   dc->d_variable = variable;
index 9a1104d0687578e0c0e22d28383b47cc1062e595..e6da38d93cc964287614a03d05bb9ba6f14fe123 100644 (file)
@@ -43,19 +43,29 @@ int RecursorPacketCache::doWipePacketCache(const DNSName& name, uint16_t qtype,
   return count;
 }
 
-static bool qrMatch(const DNSName& qname, uint16_t qtype, uint16_t qclass, const DNSName& rname, uint16_t rtype, uint16_t rclass)
+bool RecursorPacketCache::qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t ecsBegin, uint16_t ecsEnd)
 {
   // this ignores checking on the EDNS subnet flags! 
-  return qname==rname && rtype == qtype && rclass == qclass;
+  if (qname != iter->d_name || iter->d_type != qtype || iter->d_class != qclass) {
+    return false;
+  }
+
+  if (iter->d_ecsBegin != ecsBegin || iter->d_ecsEnd != ecsEnd) {
+    return false;
+  }
+
+  return queryMatches(iter->d_query, queryPacket, qname, ecsBegin, ecsEnd);
 }
 
-bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage)
+bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage, uint16_t ecsBegin, uint16_t ecsEnd)
 {
-  for(auto iter = range.first ; iter != range.second ; ++ iter) {
+  for(auto iter = range.first ; iter != range.second ; ++iter) {
     // the possibility is VERY real that we get hits that are not right - birthday paradox
-    if(!qrMatch(qname, qtype, qclass, iter->d_name, iter->d_type, iter->d_class))
+    if (!qrMatch(iter, queryPacket, qname, qtype, qclass, ecsBegin, ecsEnd)) {
       continue;
-    if(now < iter->d_ttd) { // it is right, it is fresh!
+    }
+
+    if (now < iter->d_ttd) { // it is right, it is fresh!
       *age = static_cast<uint32_t>(now - iter->d_creation);
       *responsePacket = iter->d_packet;
       responsePacket->replace(0, 2, queryPacket.c_str(), 2);
@@ -93,19 +103,25 @@ bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<Ha
 bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
                                             std::string* responsePacket, uint32_t* age, uint32_t* qhash)
 {
-  return getResponsePacket(tag, queryPacket, now, responsePacket, age, qhash, nullptr);
+  DNSName qname;
+  uint16_t qtype, qclass;
+  uint16_t ecsBegin;
+  uint16_t ecsEnd;
+  return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, qhash, &ecsBegin, &ecsEnd, nullptr);
 }
 
 bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
                                             std::string* responsePacket, uint32_t* age, uint32_t* qhash)
 {
-  return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, qhash, nullptr);
+  uint16_t ecsBegin;
+  uint16_t ecsEnd;
+  return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, qhash, &ecsBegin, &ecsEnd, nullptr);
 }
 
 bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
-                                            std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage)
+                                            std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage)
 {
-  *qhash = canHashPacket(queryPacket, true);
+  *qhash = canHashPacket(queryPacket, ecsBegin, ecsEnd);
   const auto& idx = d_packetCache.get<HashTag>();
   auto range = idx.equal_range(tie(tag,*qhash));
 
@@ -114,13 +130,13 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string&
     return false;
   }
 
-  return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage);
+  return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage, *ecsBegin, *ecsEnd);
 }
 
-bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
-                                            std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage)
+bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now,
+                                            std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage)
 {
-  *qhash = canHashPacket(queryPacket, true);
+  *qhash = canHashPacket(queryPacket, ecsBegin, ecsEnd);
   const auto& idx = d_packetCache.get<HashTag>();
   auto range = idx.equal_range(tie(tag,*qhash));
 
@@ -129,30 +145,33 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string&
     return false;
   }
 
-  uint16_t qtype, qclass;
-  DNSName qname(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, &qtype, &qclass, 0);
+  qname = DNSName(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, qtype, qclass, 0);
 
-  return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage);
+  return checkResponseMatches(range, queryPacket, qname, *qtype, *qclass, now, responsePacket, age, protobufMessage, *ecsBegin, *ecsEnd);
 }
 
 
-void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl)
+void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd)
 {
-  insertResponsePacket(tag, qhash, qname, qtype, qclass, responsePacket, now, ttl, nullptr);
+  insertResponsePacket(tag, qhash, query, qname, qtype, qclass, responsePacket, now, ttl, ecsBegin, ecsEnd, nullptr);
 }
 
-void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage)
+void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd, const RecProtoBufMessage* protobufMessage)
 {
   auto& idx = d_packetCache.get<HashTag>();
   auto range = idx.equal_range(tie(tag,qhash));
   auto iter = range.first;
 
   for( ; iter != range.second ; ++iter)  {
-    if(iter->d_type != qtype || iter->d_class != qclass || iter->d_name != qname)
+    if (iter->d_type != qtype || iter->d_class != qclass || iter->d_name != qname) {
       continue;
+    }
 
     moveCacheItemToBack(d_packetCache, iter);
     iter->d_packet = responsePacket;
+    iter->d_query = query;
+    iter->d_ecsBegin = ecsBegin;
+    iter->d_ecsEnd = ecsEnd;
     iter->d_ttd = now + ttl;
     iter->d_creation = now;
 #ifdef HAVE_PROTOBUF
@@ -165,10 +184,10 @@ void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash,
   }
   
   if(iter == range.second) { // nothing to refresh
-    struct Entry e;
-    e.d_packet = responsePacket;
-    e.d_name = qname;
+    struct Entry e(qname, responsePacket, query);
     e.d_qhash = qhash;
+    e.d_ecsBegin = ecsBegin;
+    e.d_ecsEnd = ecsEnd;
     e.d_type = qtype;
     e.d_class = qclass;
     e.d_ttd = now+ttl;
index 8263c73f5effa808ec298ed9a7dce6fcf12d1e84..1af69654ccf2eb3b2f90e610ba291412f3bd9e2d 100644 (file)
@@ -57,9 +57,10 @@ public:
   bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash);
   bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage);
   bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash);
-  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage);
-  void insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl);
-  void insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage);
+  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage);
+  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage);
+  void insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd);
+  void insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd, const RecProtoBufMessage* protobufMessage);
   void doPruneTo(unsigned int maxSize=250000);
   uint64_t doDump(int fd);
   int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false);
@@ -74,17 +75,24 @@ private:
   struct NameTag {};
   struct Entry 
   {
-    mutable time_t d_ttd;
-    mutable time_t d_creation; // so we can 'age' our packets
+    Entry(const DNSName& qname, const std::string& packet, const std::string& query): d_name(qname), d_packet(packet), d_query(query)
+    {
+    }
+
     DNSName d_name;
-    uint16_t d_type;
-    uint16_t d_class;
     mutable std::string d_packet; // "I know what I am doing"
+    mutable std::string d_query;
 #ifdef HAVE_PROTOBUF
     mutable RecProtoBufMessage d_protobufMessage;
 #endif
+    mutable time_t d_ttd;
+    mutable time_t d_creation; // so we can 'age' our packets
     uint32_t d_qhash;
     uint32_t d_tag;
+    uint16_t d_type;
+    uint16_t d_class;
+    mutable uint16_t d_ecsBegin;
+    mutable uint16_t d_ecsEnd;
     inline bool operator<(const struct Entry& rhs) const;
     
     time_t getTTD() const
@@ -104,7 +112,8 @@ private:
   
   packetCache_t d_packetCache;
 
-  bool checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage);
+  static bool qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t ecsBegin, uint16_t ecsEnd);
+  bool checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage, uint16_t ecsBegin, uint16_t ecsEnd);
 
 public:
   void preRemoval(const Entry& entry)
index 71bad3d2fdbb6749925757db19dcfcfc11b8502e..e8f9438fdf03c75bef795ff7e3c1e354b51170cd 100644 (file)
@@ -242,6 +242,7 @@ testrunner_SOURCES = \
        test-mtasker.cc \
        test-nmtree.cc \
        test-negcache_cc.cc \
+       test-packetcache_hh.cc \
        test-rcpgenerator_cc.cc \
        test-recpacketcache_cc.cc \
        test-recursorcache_cc.cc \
diff --git a/pdns/recursordist/test-packetcache_hh.cc b/pdns/recursordist/test-packetcache_hh.cc
new file mode 120000 (symlink)
index 0000000..108a53c
--- /dev/null
@@ -0,0 +1 @@
+../test-packetcache_hh.cc
\ No newline at end of file
diff --git a/pdns/test-packetcache_hh.cc b/pdns/test-packetcache_hh.cc
new file mode 100644 (file)
index 0000000..7705a56
--- /dev/null
@@ -0,0 +1,305 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "ednscookies.hh"
+#include "ednssubnet.hh"
+#include "packetcache.hh"
+
+BOOST_AUTO_TEST_SUITE(packetcache_hh)
+
+BOOST_AUTO_TEST_CASE(test_PacketCacheAuthCollision) {
+
+  /* auth version (ECS is not processed, we just hash the whole query except for the ID, while lowercasing the qname) */
+  const DNSName qname("www.powerdns.com.");
+  uint16_t qtype = QType::AAAA;
+  EDNSSubnetOpts opt;
+  DNSPacketWriter::optvect_t ednsOptions;
+
+  {
+    /* same query, different IDs */
+    vector<uint8_t> packet;
+    DNSPacketWriter pw1(packet, qname, qtype);
+    pw1.getHeader()->rd = true;
+    pw1.getHeader()->qr = false;
+    pw1.getHeader()->id = 0x42;
+    string spacket1((const char*)&packet[0], packet.size());
+    auto hash1 = PacketCache::canHashPacket(spacket1);
+
+    packet.clear();
+    DNSPacketWriter pw2(packet, qname, qtype);
+    pw2.getHeader()->rd = true;
+    pw2.getHeader()->qr = false;
+    pw2.getHeader()->id = 0x84;
+    string spacket2((const char*)&packet[0], packet.size());
+    auto hash2 = PacketCache::canHashPacket(spacket2);
+
+    BOOST_CHECK_EQUAL(hash1, hash2);
+    BOOST_CHECK(PacketCache::queryMatches(spacket1, spacket2, qname));
+  }
+
+  {
+    /* same query, different IDs, different ECS, still hashes to the same value */
+    vector<uint8_t> packet;
+    DNSPacketWriter pw1(packet, qname, qtype);
+    pw1.getHeader()->rd = true;
+    pw1.getHeader()->qr = false;
+    pw1.getHeader()->id = 0x42;
+    opt.source = Netmask("10.0.18.199/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    pw1.addOpt(512, 0, 0, ednsOptions);
+    pw1.commit();
+
+    string spacket1((const char*)&packet[0], packet.size());
+    auto hash1 = PacketCache::canHashPacket(spacket1);
+
+    packet.clear();
+    DNSPacketWriter pw2(packet, qname, qtype);
+    pw2.getHeader()->rd = true;
+    pw2.getHeader()->qr = false;
+    pw2.getHeader()->id = 0x84;
+    opt.source = Netmask("10.0.131.66/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    pw2.addOpt(512, 0, 0, ednsOptions);
+    pw2.commit();
+
+    string spacket2((const char*)&packet[0], packet.size());
+    auto hash2 = PacketCache::canHashPacket(spacket2);
+
+    BOOST_CHECK_EQUAL(hash1, hash2);
+    /* the hash is the same but we should _not_ match */
+    BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
+  }
+
+  {
+    /* same query but one has DNSSECOK, not the other, different IDs, different ECS, still hashes to the same value */
+    vector<uint8_t> packet;
+    DNSPacketWriter pw1(packet, qname, qtype);
+    pw1.getHeader()->rd = true;
+    pw1.getHeader()->qr = false;
+    pw1.getHeader()->id = 0x42;
+    opt.source = Netmask("47.8.0.0/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
+    pw1.commit();
+
+    string spacket1((const char*)&packet[0], packet.size());
+    auto hash1 = PacketCache::canHashPacket(spacket1);
+
+    packet.clear();
+    DNSPacketWriter pw2(packet, qname, qtype);
+    pw2.getHeader()->rd = true;
+    pw2.getHeader()->qr = false;
+    pw2.getHeader()->id = 0x84;
+    opt.source = Netmask("18.43.1.0/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    /* no EDNSOpts::DNSSECOK !! */
+    pw2.addOpt(512, 0, 0, ednsOptions);
+    pw2.commit();
+
+    string spacket2((const char*)&packet[0], packet.size());
+    auto hash2 = PacketCache::canHashPacket(spacket2);
+
+    BOOST_CHECK_EQUAL(hash1, hash2);
+    /* the hash is the same but we should _not_ match */
+    BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
+  }
+
+  {
+    /* same query but different cookies, still hashes to the same value */
+    vector<uint8_t> packet;
+    DNSPacketWriter pw1(packet, qname, qtype);
+    pw1.getHeader()->rd = true;
+    pw1.getHeader()->qr = false;
+    pw1.getHeader()->id = 0x42;
+    opt.source = Netmask("192.0.2.1/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    EDNSCookiesOpt cookiesOpt;
+    cookiesOpt.client = string("deadbeef");
+    cookiesOpt.server = string("deadbeef");
+    cookiesOpt.server[4] = -42;
+    cookiesOpt.server[5] = -6;
+    cookiesOpt.server[6] = 1;
+    cookiesOpt.server[7] = 0;
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
+    pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
+    pw1.commit();
+
+    string spacket1((const char*)&packet[0], packet.size());
+    auto hash1 = PacketCache::canHashPacket(spacket1);
+
+    packet.clear();
+    DNSPacketWriter pw2(packet, qname, qtype);
+    pw2.getHeader()->rd = true;
+    pw2.getHeader()->qr = false;
+    pw2.getHeader()->id = 0x84;
+    opt.source = Netmask("192.0.2.1/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    cookiesOpt.client = string("deadbeef");
+    cookiesOpt.server = string("deadbeef");
+    cookiesOpt.server[4] = 29;
+    cookiesOpt.server[5] = -79;
+    cookiesOpt.server[6] = 1;
+    cookiesOpt.server[7] = 0;
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
+    pw2.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
+    pw2.commit();
+
+    string spacket2((const char*)&packet[0], packet.size());
+    auto hash2 = PacketCache::canHashPacket(spacket2);
+
+    BOOST_CHECK_EQUAL(hash1, hash2);
+    /* the hash is the same but we should _not_ match */
+    BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
+  }
+}
+
+BOOST_AUTO_TEST_CASE(test_PacketCacheRecCollision) {
+
+  /* rec version (ECS is processed, we hash the whole query except for the ID and the ECS value, while lowercasing the qname) */
+  const DNSName qname("www.powerdns.com.");
+  uint16_t qtype = QType::AAAA;
+  EDNSSubnetOpts opt;
+  DNSPacketWriter::optvect_t ednsOptions;
+  uint16_t ecsBegin;
+  uint16_t ecsEnd;
+
+  {
+    /* same query, different IDs */
+    vector<uint8_t> packet;
+    DNSPacketWriter pw1(packet, qname, qtype);
+    pw1.getHeader()->rd = true;
+    pw1.getHeader()->qr = false;
+    pw1.getHeader()->id = 0x42;
+    string spacket1((const char*)&packet[0], packet.size());
+    auto hash1 = PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
+    /* no ECS */
+    BOOST_CHECK_EQUAL(ecsBegin, 0);
+    BOOST_CHECK_EQUAL(ecsEnd, 0);
+
+    packet.clear();
+    DNSPacketWriter pw2(packet, qname, qtype);
+    pw2.getHeader()->rd = true;
+    pw2.getHeader()->qr = false;
+    pw2.getHeader()->id = 0x84;
+    string spacket2((const char*)&packet[0], packet.size());
+    auto hash2 = PacketCache::canHashPacket(spacket2, &ecsBegin, &ecsEnd);
+    /* no ECS */
+    BOOST_CHECK_EQUAL(ecsBegin, 0);
+    BOOST_CHECK_EQUAL(ecsEnd, 0);
+
+    BOOST_CHECK_EQUAL(hash1, hash2);
+    BOOST_CHECK(PacketCache::queryMatches(spacket1, spacket2, qname, ecsBegin, ecsEnd));
+  }
+
+  {
+    /* same query, different IDs, different ECS, still hashes to the same value */
+    vector<uint8_t> packet;
+    DNSPacketWriter pw1(packet, qname, qtype);
+    pw1.getHeader()->rd = true;
+    pw1.getHeader()->qr = false;
+    pw1.getHeader()->id = 0x42;
+    opt.source = Netmask("10.0.18.199/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    pw1.addOpt(512, 0, 0, ednsOptions);
+    pw1.commit();
+
+    string spacket1((const char*)&packet[0], packet.size());
+    auto hash1 = PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
+    /* ECS value */
+    BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
+    BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
+
+    packet.clear();
+    DNSPacketWriter pw2(packet, qname, qtype);
+    pw2.getHeader()->rd = true;
+    pw2.getHeader()->qr = false;
+    pw2.getHeader()->id = 0x84;
+    opt.source = Netmask("10.0.131.66/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    pw2.addOpt(512, 0, 0, ednsOptions);
+    pw2.commit();
+
+    string spacket2((const char*)&packet[0], packet.size());
+    auto hash2 = PacketCache::canHashPacket(spacket2, &ecsBegin, &ecsEnd);
+    /* ECS value */
+    BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
+    BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
+
+    BOOST_CHECK_EQUAL(hash1, hash2);
+    /* the hash is the same and we don't hash the ECS so we should match */
+    BOOST_CHECK(PacketCache::queryMatches(spacket1, spacket2, qname, ecsBegin, ecsEnd));
+  }
+
+  {
+    /* same query but different cookies, still hashes to the same value */
+    vector<uint8_t> packet;
+    DNSPacketWriter pw1(packet, qname, qtype);
+    pw1.getHeader()->rd = true;
+    pw1.getHeader()->qr = false;
+    pw1.getHeader()->id = 0x42;
+    opt.source = Netmask("192.0.2.1/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    EDNSCookiesOpt cookiesOpt;
+    cookiesOpt.client = string("deadbeef");
+    cookiesOpt.server = string("deadbeef");
+    cookiesOpt.server[4] = -20;
+    cookiesOpt.server[5] = -114;
+    cookiesOpt.server[6] = 0;
+    cookiesOpt.server[7] = 0;
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
+    pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
+    pw1.commit();
+
+    string spacket1((const char*)&packet[0], packet.size());
+    auto hash1 = PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
+    /* ECS value */
+    BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
+    BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
+
+    packet.clear();
+    DNSPacketWriter pw2(packet, qname, qtype);
+    pw2.getHeader()->rd = true;
+    pw2.getHeader()->qr = false;
+    pw2.getHeader()->id = 0x84;
+    opt.source = Netmask("192.0.2.1/32");
+    ednsOptions.clear();
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
+    cookiesOpt.client = string("deadbeef");
+    cookiesOpt.server = string("deadbeef");
+    cookiesOpt.server[4] = 103;
+    cookiesOpt.server[5] = 68;
+    cookiesOpt.server[6] = 0;
+    cookiesOpt.server[7] = 0;
+    ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
+    pw2.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
+    pw2.commit();
+
+    string spacket2((const char*)&packet[0], packet.size());
+    auto hash2 = PacketCache::canHashPacket(spacket2, &ecsBegin, &ecsEnd);
+    /* ECS value */
+    BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
+    BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
+
+    BOOST_CHECK_EQUAL(hash1, hash2);
+    /* the hash is the same but we should _not_ match, even though we skip the ECS part, because the cookies are different */
+    BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname, ecsBegin, ecsEnd));
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
index f2e68e129791e5657510b0efe6809f4a9e81823c..42022ab972f45decd89dc3c87bf3d51307abc6d2 100644 (file)
@@ -41,16 +41,17 @@ BOOST_AUTO_TEST_CASE(test_recPacketCacheSimple) {
   pw.commit();
   string rpacket((const char*)&packet[0], packet.size());
 
-  rpc.insertResponsePacket(tag, qhash, qname, QType::A, QClass::IN, rpacket, time(0), ttd);
+  rpc.insertResponsePacket(tag, qhash, qpacket, qname, QType::A, QClass::IN, rpacket, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 1);
   rpc.doPruneTo(0);
   BOOST_CHECK_EQUAL(rpc.size(), 0);
-  rpc.insertResponsePacket(tag, qhash, qname, QType::A, QClass::IN, rpacket, time(0), ttd);
+  rpc.insertResponsePacket(tag, qhash, qpacket, qname, QType::A, QClass::IN, rpacket, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 1);
   rpc.doWipePacketCache(qname);
   BOOST_CHECK_EQUAL(rpc.size(), 0);
 
-  rpc.insertResponsePacket(tag, qhash, qname, QType::A, QClass::IN, rpacket, time(0), ttd);
+  rpc.insertResponsePacket(tag, qhash, qpacket, qname, QType::A, QClass::IN, rpacket, time(0), ttd, 0, 0);
+  BOOST_CHECK_EQUAL(rpc.size(), 1);
   uint32_t qhash2 = 0;
   bool found = rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash2);
   BOOST_CHECK_EQUAL(found, true);
@@ -132,11 +133,11 @@ BOOST_AUTO_TEST_CASE(test_recPacketCache_Tags) {
   BOOST_CHECK(r1packet != r2packet);
 
   /* inserting a response for tag1 */
-  rpc.insertResponsePacket(tag1, qhash, qname, QType::A, QClass::IN, r1packet, time(0), ttd);
+  rpc.insertResponsePacket(tag1, qhash, qpacket, qname, QType::A, QClass::IN, r1packet, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 1);
 
   /* inserting a different response for tag2, should not override the first one */
-  rpc.insertResponsePacket(tag2, qhash, qname, QType::A, QClass::IN, r2packet, time(0), ttd);
+  rpc.insertResponsePacket(tag2, qhash, qpacket, qname, QType::A, QClass::IN, r2packet, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 2);
 
   /* remove all responses from the cache */
@@ -144,10 +145,10 @@ BOOST_AUTO_TEST_CASE(test_recPacketCache_Tags) {
   BOOST_CHECK_EQUAL(rpc.size(), 0);
 
   /* reinsert both */
-  rpc.insertResponsePacket(tag1, qhash, qname, QType::A, QClass::IN, r1packet, time(0), ttd);
+  rpc.insertResponsePacket(tag1, qhash, qpacket, qname, QType::A, QClass::IN, r1packet, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 1);
 
-  rpc.insertResponsePacket(tag2, qhash, qname, QType::A, QClass::IN, r2packet, time(0), ttd);
+  rpc.insertResponsePacket(tag2, qhash, qpacket, qname, QType::A, QClass::IN, r2packet, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 2);
 
   /* remove the responses by qname, should remove both */
@@ -155,7 +156,7 @@ BOOST_AUTO_TEST_CASE(test_recPacketCache_Tags) {
   BOOST_CHECK_EQUAL(rpc.size(), 0);
 
   /* insert the response for tag1 */
-  rpc.insertResponsePacket(tag1, qhash, qname, QType::A, QClass::IN, r1packet, time(0), ttd);
+  rpc.insertResponsePacket(tag1, qhash, qpacket, qname, QType::A, QClass::IN, r1packet, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 1);
 
   /* we can retrieve it */
@@ -174,7 +175,7 @@ BOOST_AUTO_TEST_CASE(test_recPacketCache_Tags) {
   BOOST_CHECK_EQUAL(temphash, qhash);
 
   /* adding a response for the second tag */
-  rpc.insertResponsePacket(tag2, qhash, qname, QType::A, QClass::IN, r2packet, time(0), ttd);
+  rpc.insertResponsePacket(tag2, qhash, qpacket, qname, QType::A, QClass::IN, r2packet, time(0), ttd, 0, 0);
   BOOST_CHECK_EQUAL(rpc.size(), 2);
 
   /* We still get the correct response for the first tag */