From: Remi Gacogne Date: Thu, 19 Jul 2018 13:52:40 +0000 (+0200) Subject: Do full packet comparison in the packet caches in addition to the hash X-Git-Tag: dnsdist-1.3.3~6^2~9 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=08b023663b552363133b80b17c959c4052bbe194;p=pdns Do full packet comparison in the packet caches in addition to the hash (cherry picked from commit aab08a02344a66e14572cf63129d157d6e7ba8c9) --- diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 9304dcd61..6f3910597 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -1252,6 +1252,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 \ @@ -1291,6 +1292,7 @@ testrunner_SOURCES = \ test-misc_hh.cc \ test-nameserver_cc.cc \ test-packetcache_cc.cc \ + test-packetcache_hh.cc \ test-rcpgenerator_cc.cc \ test-signers.cc \ test-sha_hh.cc \ diff --git a/pdns/auth-packetcache.cc b/pdns/auth-packetcache.cc index 324a0f12b..7bb0ff32b 100644 --- a/pdns/auth-packetcache.cc +++ b/pdns/auth-packetcache.cc @@ -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::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(); 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; diff --git a/pdns/auth-packetcache.hh b/pdns/auth-packetcache.hh index d817b5d84..934869d2b 100644 --- a/pdns/auth-packetcache.hh +++ b/pdns/auth-packetcache.hh @@ -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::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}; diff --git a/pdns/packetcache.hh b/pdns/packetcache.hh index b0785fd9d..c3589108f 100644 --- a/pdns/packetcache.hh +++ b/pdns/packetcache.hh @@ -28,13 +28,13 @@ 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(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(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(reinterpret_cast(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(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(skipEnd), end-skipEnd, ret); } return ret; } + + static uint32_t canHashPacket(const std::string& packet) + { + uint32_t ret = 0; + ret = burtle(reinterpret_cast(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(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 */ diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 6360a6ba0..fd3feff0e 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -244,11 +244,11 @@ bool g_logRPZChanges{false}; //! used to send information to a newborn mthread struct DNSComboWriter { - DNSComboWriter(const std::string& query, const struct timeval& now): d_mdp(true, query), d_now(now) + DNSComboWriter(const std::string& query, const struct timeval& now): d_mdp(true, query), d_now(now), d_query(query) { } - DNSComboWriter(const std::string& query, const struct timeval& now, std::vector&& policyTags, LuaContext::LuaObject&& data): d_mdp(true, query), d_now(now), d_policyTags(std::move(policyTags)), d_data(std::move(data)) + DNSComboWriter(const std::string& query, const struct timeval& now, std::vector&& policyTags, LuaContext::LuaObject&& data): d_mdp(true, query), d_now(now), d_query(query), d_policyTags(std::move(policyTags)), d_data(std::move(data)) { } @@ -304,6 +304,7 @@ struct DNSComboWriter { string d_requestorId; string d_deviceId; #endif + std::string d_query; std::vector d_policyTags; LuaContext::LuaObject d_data; EDNSSubnetOpts d_ednssubnet; @@ -312,6 +313,8 @@ struct DNSComboWriter { unsigned int d_tag{0}; uint32_t d_qhash{0}; uint32_t d_ttlCap{std::numeric_limits::max()}; + uint16_t d_ecsBegin{0}; + uint16_t d_ecsEnd{0}; bool d_variable{false}; bool d_ecsFound{false}; bool d_ecsParsed{false}; @@ -1506,12 +1509,14 @@ static void startDoResolve(void *p) g_log<getRemote()<<" failed with: "<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), dq.validationState, + dc->d_ecsBegin, + dc->d_ecsEnd, pbMessage); } // else cerr<<"Not putting in packet cache: "<::max(); bool variable = false; try { @@ -2088,10 +2095,10 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr as cacheable we would cache it with a wrong tag, so better safe than sorry. */ vState valState; if (qnameParsed) { - cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &valState, &qhash, pbMessage ? &(*pbMessage) : nullptr)); + cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &valState, &qhash, &ecsBegin, &ecsEnd, pbMessage ? &(*pbMessage) : nullptr)); } else { - cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, &qtype, &qclass, g_now.tv_sec, &response, &age, &valState, &qhash, pbMessage ? &(*pbMessage) : nullptr)); + cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, &qtype, &qclass, g_now.tv_sec, &response, &age, &valState, &qhash, &ecsBegin, &ecsEnd, pbMessage ? &(*pbMessage) : nullptr)); } if (cacheHit) { @@ -2175,6 +2182,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr dc->d_tcp=false; 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; diff --git a/pdns/recpacketcache.cc b/pdns/recpacketcache.cc index 653c1d4fd..9eb753428 100644 --- a/pdns/recpacketcache.cc +++ b/pdns/recpacketcache.cc @@ -39,19 +39,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::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::type::iterator, packetCache_t::index::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, vState* valState, RecProtoBufMessage* protobufMessage) +bool RecursorPacketCache::checkResponseMatches(std::pair::type::iterator, packetCache_t::index::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, vState* valState, 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(now - iter->d_creation); *responsePacket = iter->d_packet; responsePacket->replace(0, 2, queryPacket.c_str(), 2); @@ -97,21 +107,25 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& { DNSName qname; uint16_t qtype, qclass; + uint16_t ecsBegin; + uint16_t ecsEnd; vState valState; - return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, &valState, qhash, nullptr); + return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, &valState, 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) { vState valState; - return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, &valState, qhash, nullptr); + uint16_t ecsBegin; + uint16_t ecsEnd; + return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, &valState, 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, vState* valState, uint32_t* qhash, RecProtoBufMessage* protobufMessage) + std::string* responsePacket, uint32_t* age, vState* valState, 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(); auto range = idx.equal_range(tie(tag,*qhash)); @@ -119,13 +133,14 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& d_misses++; return false; } - return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, valState, protobufMessage); + + return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, valState, protobufMessage, *ecsBegin, *ecsEnd); } 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, vState* valState, uint32_t* qhash, RecProtoBufMessage* protobufMessage) + std::string* responsePacket, uint32_t* age, vState* valState, 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(); auto range = idx.equal_range(tie(tag,*qhash)); @@ -136,29 +151,33 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& qname = DNSName(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, qtype, qclass, 0); - return checkResponseMatches(range, queryPacket, qname, *qtype, *qclass, now, responsePacket, age, valState, protobufMessage); + return checkResponseMatches(range, queryPacket, qname, *qtype, *qclass, now, responsePacket, age, valState, 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) { vState valState; boost::optional pb(boost::none); - insertResponsePacket(tag, qhash, qname, qtype, qclass, responsePacket, now, ttl, valState, pb); + insertResponsePacket(tag, qhash, query, qname, qtype, qclass, responsePacket, now, ttl, valState, ecsBegin, ecsEnd, pb); } -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 vState& valState, const boost::optional& 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, const vState& valState, uint16_t ecsBegin, uint16_t ecsEnd, const boost::optional& protobufMessage) { auto& idx = d_packetCache.get(); 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; iter->d_vstate = valState; @@ -172,8 +191,10 @@ void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, } if(iter == range.second) { // nothing to refresh - struct Entry e(qname, responsePacket); + 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; diff --git a/pdns/recpacketcache.hh b/pdns/recpacketcache.hh index 77d8b419c..b2b236704 100644 --- a/pdns/recpacketcache.hh +++ b/pdns/recpacketcache.hh @@ -54,10 +54,10 @@ public: RecursorPacketCache(); 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, 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, vState* valState, uint32_t* qhash, 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, vState* valState, 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 vState& valState, const boost::optional& 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, vState* valState, 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, vState* valState, 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, const vState& valState, uint16_t ecsBegin, uint16_t ecsEnd, const boost::optional& protobufMessage); void doPruneTo(unsigned int maxSize=250000); uint64_t doDump(int fd); int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false); @@ -72,21 +72,24 @@ private: struct NameTag {}; struct Entry { - Entry(const DNSName& qname, const std::string& packet): d_name(qname), d_packet(packet) + Entry(const DNSName& qname, const std::string& packet, const std::string& query): d_name(qname), d_packet(packet), d_query(query) { } - mutable time_t d_ttd; - mutable time_t d_creation; // so we can 'age' our packets 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 boost::optional 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; mutable vState d_vstate; inline bool operator<(const struct Entry& rhs) const; @@ -107,7 +110,8 @@ private: packetCache_t d_packetCache; - bool checkResponseMatches(std::pair::type::iterator, packetCache_t::index::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, vState* valState, RecProtoBufMessage* protobufMessage); + static bool qrMatch(const packetCache_t::index::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::type::iterator, packetCache_t::index::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, vState* valState, RecProtoBufMessage* protobufMessage, uint16_t ecsBegin, uint16_t ecsEnd); public: void preRemoval(const Entry& entry) diff --git a/pdns/recursordist/Makefile.am b/pdns/recursordist/Makefile.am index 3589ac5eb..f3ae8afe2 100644 --- a/pdns/recursordist/Makefile.am +++ b/pdns/recursordist/Makefile.am @@ -260,6 +260,7 @@ testrunner_SOURCES = \ test-misc_hh.cc \ test-mtasker.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 index 000000000..108a53caf --- /dev/null +++ b/pdns/recursordist/test-packetcache_hh.cc @@ -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 index 000000000..7705a5684 --- /dev/null +++ b/pdns/test-packetcache_hh.cc @@ -0,0 +1,305 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include + +#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 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 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 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 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 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 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 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() diff --git a/pdns/test-recpacketcache_cc.cc b/pdns/test-recpacketcache_cc.cc index 7e57153be..01c898261 100644 --- a/pdns/test-recpacketcache_cc.cc +++ b/pdns/test-recpacketcache_cc.cc @@ -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 */