]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Store the zone and remote server IP in the records cache
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 17 Dec 2020 13:45:59 +0000 (14:45 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 17 Dec 2020 13:45:59 +0000 (14:45 +0100)
pdns/recursor_cache.cc
pdns/recursor_cache.hh
pdns/recursordist/test-recursorcache_cc.cc
pdns/recursordist/test-syncres_cc.cc
pdns/recursordist/test-syncres_cc2.cc
pdns/recursordist/test-syncres_cc7.cc
pdns/reczones.cc
pdns/syncres.cc
pdns/syncres.hh

index 497147b97b726a7c43c2faf247ee0ab340d370e8..8a798a60a1ef9fe468e7388428a729d88c0267e9 100644 (file)
@@ -111,7 +111,7 @@ static void updateDNSSECValidationStateFromCache(boost::optional<vState>& state,
   }
 }
 
-int32_t MemRecursorCache::handleHit(MapCombo& map, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, vector<DNSRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth)
+int32_t MemRecursorCache::handleHit(MapCombo& map, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, vector<DNSRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* fromAuthZone)
 {
   // MUTEX SHOULD BE ACQUIRED
   int32_t ttd = entry->d_ttd;
@@ -150,6 +150,10 @@ int32_t MemRecursorCache::handleHit(MapCombo& map, MemRecursorCache::OrderedTagI
     *wasAuth = *wasAuth && entry->d_auth;
   }
 
+  if (fromAuthZone) {
+    *fromAuthZone = entry->d_authZone;
+  }
+
   moveCacheItemToBack<SequencedTag>(map.d_map, entry);
 
   return ttd;
@@ -246,7 +250,7 @@ bool MemRecursorCache::entryMatches(MemRecursorCache::OrderedTagIterator_t& entr
 }
 
 // returns -1 for no hits
-int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth)
+int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone)
 {
   boost::optional<vState> cachedState{boost::none};
   time_t ttd=0;
@@ -272,11 +276,11 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt,
 
       auto entryA = getEntryUsingECSIndex(map, now, qname, QType::A, requireAuth, who);
       if (entryA != map.d_map.end()) {
-        ret = handleHit(map, entryA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth);
+        ret = handleHit(map, entryA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone);
       }
       auto entryAAAA = getEntryUsingECSIndex(map, now, qname, QType::AAAA, requireAuth, who);
       if (entryAAAA != map.d_map.end()) {
-        int32_t ttdAAAA = handleHit(map, entryAAAA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth);
+        int32_t ttdAAAA = handleHit(map, entryAAAA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone);
         if (ret > 0) {
           ret = std::min(ret, ttdAAAA);
         } else {
@@ -293,7 +297,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt,
     else {
       auto entry = getEntryUsingECSIndex(map, now, qname, qtype, requireAuth, who);
       if (entry != map.d_map.end()) {
-        int32_t ret = handleHit(map, entry, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth);
+        int32_t ret = handleHit(map, entry, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone);
         if (state && cachedState) {
           *state = *cachedState;
         }
@@ -319,7 +323,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt,
           continue;
         }
 
-        ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth);
+        ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone);
 
         if (qt.getCode() != QType::ANY && qt.getCode() != QType::ADDR) { // normally if we have a hit, we are done
           break;
@@ -347,7 +351,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt,
         continue;
       }
 
-      ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth);
+      ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone);
 
       if (qt.getCode() != QType::ANY && qt.getCode() != QType::ADDR) { // normally if we have a hit, we are done
         break;
@@ -361,7 +365,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt,
   return -1;
 }
 
-void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask, const OptTag& routingTag, vState state)
+void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask, const OptTag& routingTag, vState state, boost::optional<ComboAddress> from)
 {
   auto& map = getMap(qname);
   const lock l(map);
@@ -403,8 +407,6 @@ void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt
   time_t maxTTD=std::numeric_limits<time_t>::max();
   CacheEntry ce=*stored; // this is a COPY
   ce.d_qtype=qt.getCode();
-  ce.d_signatures=signatures;
-  ce.d_authorityRecs=authorityRecs;
   
   //  cerr<<"asked to store "<< (qname.empty() ? "EMPTY" : qname.toString()) <<"|"+qt.getName()<<" -> '";
   //  cerr<<(content.empty() ? string("EMPTY CONTENT")  : content.begin()->d_content->getZoneRepresentation())<<"', auth="<<auth<<", ce.auth="<<ce.d_auth;
@@ -434,19 +436,25 @@ void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt
   // for an auth to keep a "ghost" zone alive forever, even after the delegation is gone from
   // the parent
   // BUT make sure that we CAN refresh the root
-  if(ce.d_auth && auth && qt.getCode()==QType::NS && !isNew && !qname.isRoot()) {
+  if (ce.d_auth && auth && qt.getCode()==QType::NS && !isNew && !qname.isRoot()) {
     //    cerr<<"\tLimiting TTL of auth->auth NS set replace to "<<ce.d_ttd<<endl;
     maxTTD = ce.d_ttd;
   }
 
-  if(auth) {
+  if (auth) {
     ce.d_auth = true;
   }
 
+  ce.d_signatures = signatures;
+  ce.d_authorityRecs = authorityRecs;
   ce.d_records.clear();
   ce.d_records.reserve(content.size());
+  ce.d_authZone = authZone;
+  if (from) {
+    ce.d_from = *from;
+  }
 
-  for(const auto& i : content) {
+  for (const auto& i : content) {
     /* Yes, we have altered the d_ttl value by adding time(nullptr) to it
        prior to calling this function, so the TTL actually holds a TTD. */
     ce.d_ttd=min(maxTTD, static_cast<time_t>(i.d_ttl));   // XXX this does weird things if TTLs differ in the set
@@ -619,12 +627,12 @@ uint64_t MemRecursorCache::doDump(int fd)
     const lock l(map);
     const auto& sidx = map.d_map.get<SequencedTag>();
 
-    time_t now = time(0);
+    time_t now = time(nullptr);
     for (const auto& i : sidx) {
       for (const auto& j : i.d_records) {
         count++;
         try {
-          fprintf(fp.get(), "%s %" PRId64 " IN %s %s ; (%s) auth=%i %s %s\n", i.d_qname.toString().c_str(), static_cast<int64_t>(i.d_ttd - now), DNSRecordContent::NumberToType(i.d_qtype).c_str(), j->getZoneRepresentation().c_str(), vStateToString(i.d_state).c_str(), i.d_auth, i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str(), !i.d_rtag ? "" : i.d_rtag.get().c_str());
+          fprintf(fp.get(), "%s %" PRId64 " IN %s %s ; (%s) auth=%i zone=%s from=%s %s %s\n", i.d_qname.toString().c_str(), static_cast<int64_t>(i.d_ttd - now), DNSRecordContent::NumberToType(i.d_qtype).c_str(), j->getZoneRepresentation().c_str(), vStateToString(i.d_state).c_str(), i.d_auth, i.d_authZone.toLogString().c_str(), i.d_from.toString().c_str(), i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str(), !i.d_rtag ? "" : i.d_rtag.get().c_str());
         }
         catch(...) {
           fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
index b2cbca1125b044cad6b4a912a4e0f110306495d5..ed81e8cefb4e0d613c0235e940a98c431201858a 100644 (file)
@@ -57,9 +57,9 @@ public:
 
   typedef boost::optional<std::string> OptTag;
 
-  int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag = boost::none, vector<std::shared_ptr<RRSIGRecordContent>>* signatures=nullptr, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr);
+  int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag = boost::none, vector<std::shared_ptr<RRSIGRecordContent>>* signatures=nullptr, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr, DNSName* fromAuthZone=nullptr);
 
-  void replace(time_t, const DNSName &qname, const QType& qt,  const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask=boost::none, const OptTag& routingTag = boost::none, vState state=vState::Indeterminate);
+  void replace(time_t, const DNSName &qname, const QType& qt,  const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask=boost::none, const OptTag& routingTag = boost::none, vState state=vState::Indeterminate, boost::optional<ComboAddress> from=boost::none);
 
   void doPrune(size_t keep);
   uint64_t doDump(int fd);
@@ -89,6 +89,8 @@ private:
     std::vector<std::shared_ptr<RRSIGRecordContent>> d_signatures;
     std::vector<std::shared_ptr<DNSRecord>> d_authorityRecs;
     DNSName d_qname;
+    DNSName d_authZone;
+    ComboAddress d_from;
     Netmask d_netmask;
     OptTag d_rtag;
     mutable vState d_state;
@@ -230,7 +232,7 @@ private:
   bool entryMatches(OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who);
   Entries getEntries(MapCombo& map, const DNSName &qname, const QType& qt, const OptTag& rtag);
   cache_t::const_iterator getEntryUsingECSIndex(MapCombo& map, time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
-  int32_t handleHit(MapCombo& map, OrderedTagIterator_t& entry, const DNSName& qname, vector<DNSRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth);
+  int32_t handleHit(MapCombo& map, OrderedTagIterator_t& entry, const DNSName& qname, vector<DNSRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* authZone);
 
 public:
   struct lock {
index a96edf020d9faf912e9c1f788ff98aa5a0db17ae..799240bd63788fac69a77ef895fac06222602ad2 100644 (file)
@@ -18,6 +18,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
   std::vector<DNSRecord> records;
   std::vector<std::shared_ptr<DNSRecord>> authRecords;
   std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
+  const DNSName authZone(".");
   time_t now = time(nullptr);
 
   time_t ttd = now + 30;
@@ -34,7 +35,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
   records.push_back(dr0);
 
   BOOST_CHECK_EQUAL(MRC.size(), 0U);
-  MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, boost::none);
+  MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, authZone, boost::none);
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_GT(MRC.bytes(), 1U);
   BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1U);
@@ -47,10 +48,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
       DNSName a = DNSName("hello ") + DNSName(std::to_string(counter));
       BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
 
-      MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, boost::none);
+      MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none);
       if (!MRC.doWipeCache(a, false))
         BOOST_FAIL("Could not remove entry we just added to the cache!");
-      MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, boost::none);
+      MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none);
     }
 
     BOOST_CHECK_EQUAL(MRC.size(), counter);
@@ -102,7 +103,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     // insert a subnet specific entry
     records.clear();
     records.push_back(dr1);
-    MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, boost::optional<Netmask>("192.0.2.1/25"));
+    MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, boost::optional<Netmask>("192.0.2.1/25"));
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
 
     // subnet specific should be returned for a matching subnet
@@ -121,7 +122,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     // insert a NON-subnet specific entry
     records.clear();
     records.push_back(dr2);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none);
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none);
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
 
     // NON-subnet specific should always be returned
@@ -132,14 +133,14 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     // insert a subnet specific entry for the same name but a different QType
     records.clear();
     records.push_back(dr1);
-    MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, boost::optional<Netmask>("192.0.2.1/25"));
+    MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, boost::optional<Netmask>("192.0.2.1/25"));
     // we should not have replaced the existing entry
     BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
     // insert a TXT one, we will use that later
     records.clear();
     records.push_back(dr1);
-    MRC.replace(now, power, QType(QType::TXT), records, signatures, authRecords, true, boost::none);
+    MRC.replace(now, power, QType(QType::TXT), records, signatures, authRecords, true, authZone, boost::none);
     // we should not have replaced any existing entry
     BOOST_CHECK_EQUAL(MRC.size(), 3U);
 
@@ -223,7 +224,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
 
     // insert auth record
     records.push_back(dr2);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none);
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none);
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
     BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1")), (ttd - now));
     BOOST_CHECK_EQUAL(retrieved.size(), 1U);
@@ -245,23 +246,23 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     records.push_back(dr3);
 
     // non-auth should not replace valid auth
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::none);
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none);
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
     BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1")), (ttd - now));
     BOOST_REQUIRE_EQUAL(retrieved.size(), 1U);
     BOOST_CHECK_EQUAL(getRR<ARecordContent>(retrieved.at(0))->getCA().toString(), dr2Content.toString());
 
     // but non-auth _should_ replace expired auth
-    MRC.replace(ttd + 1, power, QType(QType::A), records, signatures, authRecords, false, boost::none);
+    MRC.replace(ttd + 1, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none);
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
     BOOST_CHECK_EQUAL(MRC.get(ttd + 1, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1")), (dr3.d_ttl - (ttd + 1)));
     BOOST_REQUIRE_EQUAL(retrieved.size(), 1U);
     BOOST_CHECK_EQUAL(getRR<ARecordContent>(retrieved.at(0))->getCA().toString(), dr3Content.toString());
 
-    // auth should replace non-auth
+    // non-auth should replace non-auth
     records.clear();
     records.push_back(dr2);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::none);
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none);
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
     // let's first check that non-auth is not returned when we need authoritative data
     BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), true, &retrieved, ComboAddress("127.0.0.1")), -now);
@@ -276,7 +277,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
 
     // insert Secure record
     records.push_back(dr2);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none, boost::none, vState::Secure);
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none, boost::none, vState::Secure);
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
     vState retrievedState = vState::Indeterminate;
     bool wasAuth = false;
@@ -285,7 +286,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     BOOST_CHECK_EQUAL(vStateToString(retrievedState), vStateToString(vState::Secure));
     BOOST_CHECK_EQUAL(wasAuth, true);
     // try to replace that with a Bogus record
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none, boost::none, vState::BogusNoRRSIG);
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none, boost::none, vState::BogusNoRRSIG);
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
     retrievedState = vState::Indeterminate;
     wasAuth = false;
@@ -304,7 +305,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     // insert an entry for 192.0.0.1/8
     records.clear();
     records.push_back(dr2);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional<Netmask>("192.0.0.1/8"));
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional<Netmask>("192.0.0.1/8"));
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
 
     /* same as dr2 except for the actual IP */
@@ -320,14 +321,14 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     // insert another entry but for 192.168.0.1/31
     records.clear();
     records.push_back(dr4);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional<Netmask>("192.168.0.1/31"));
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional<Netmask>("192.168.0.1/31"));
     // we should not have replaced any existing entry
     BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
     // insert the same than the first one but for 192.168.0.2/32
     records.clear();
     records.push_back(dr2);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional<Netmask>("192.168.0.2/32"));
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional<Netmask>("192.168.0.2/32"));
     // we should not have replaced any existing entry
     BOOST_CHECK_EQUAL(MRC.size(), 3U);
 
@@ -344,7 +345,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple)
     // insert an entry for 192.0.0.1/8, non auth
     records.clear();
     records.push_back(dr2);
-    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::optional<Netmask>("192.0.0.1/8"));
+    MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::optional<Netmask>("192.0.0.1/8"));
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
 
     // we should not get it when we need authoritative data
@@ -385,7 +386,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheGhost)
   ns1.d_ttl = static_cast<uint32_t>(ttd);
   ns1.d_place = DNSResourceRecord::ANSWER;
   records.push_back(ns1);
-  MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, boost::none);
+  MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("powerdns.com."), boost::none);
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
 
   /* try to raise the TTL, simulating the delegated authoritative server
@@ -393,7 +394,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheGhost)
   records.clear();
   ns1.d_ttl = static_cast<uint32_t>(ttd + 3600);
   records.push_back(ns1);
-  MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, boost::none);
+  MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("ghost.powerdns.com."), boost::none);
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
 
   /* the TTL should not have been raisd */
@@ -410,6 +411,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries)
   std::vector<DNSRecord> records;
   std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
   std::vector<std::shared_ptr<DNSRecord>> authRecs;
+  const DNSName authZone(".");
   BOOST_CHECK_EQUAL(MRC.size(), 0U);
   time_t now = time(nullptr);
   DNSName power1("powerdns.com.");
@@ -440,10 +442,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries)
 
   /* insert both entries */
   records.push_back(dr1);
-  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   records.push_back(dr2);
-  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
@@ -468,10 +470,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries)
 
   /* insert both entries back */
   records.push_back(dr1);
-  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   records.push_back(dr2);
-  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
@@ -500,6 +502,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries)
   std::vector<DNSRecord> records;
   std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
   std::vector<std::shared_ptr<DNSRecord>> authRecs;
+  const DNSName authZone(".");
   BOOST_CHECK_EQUAL(MRC.size(), 0U);
   time_t now = time(nullptr);
   DNSName power1("powerdns.com.");
@@ -530,10 +533,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries)
 
   /* insert both entries */
   records.push_back(dr1);
-  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   records.push_back(dr2);
-  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
@@ -557,16 +560,16 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries)
 
   /* insert both entries back */
   records.push_back(dr1);
-  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   records.push_back(dr2);
-  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
   /* replace the entry for power1 */
   records.push_back(dr1);
-  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
@@ -591,10 +594,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries)
 
   /* insert both entries back */
   records.push_back(dr1);
-  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   records.push_back(dr2);
-  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none);
   records.clear();
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
@@ -633,7 +636,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries)
     r1.d_place = DNSResourceRecord::ANSWER;
     records.push_back(r1);
 
-    MRC.replace(now, power1, QType(QType::A), records, signatures, authRecs, true, Netmask(r1Content, 32));
+    MRC.replace(now, power1, QType(QType::A), records, signatures, authRecs, true, authZone, Netmask(r1Content, 32));
   }
 
   BOOST_CHECK_EQUAL(MRC.size(), 256U);
@@ -675,6 +678,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
   MemRecursorCache MRC(1);
 
   const DNSName power("powerdns.com.");
+  const DNSName authZone(".");
   std::vector<DNSRecord> records;
   std::vector<std::shared_ptr<DNSRecord>> authRecords;
   std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
@@ -710,7 +714,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
 
   /* insert a non-specific entry */
   records.push_back(dr1);
-  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none);
+  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none);
 
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
@@ -726,7 +730,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
 
   /* insert a specific entry */
-  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31"));
+  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
@@ -751,7 +755,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
 
   /* add back the entry while it still exists in the cache but has been removed from the ECS index.
      It should be added back to the ECS index, and we should be able to retrieve it */
-  MRC.replace(now + ttl + 1, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31"));
+  MRC.replace(now + ttl + 1, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31"));
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
   BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.1")), ttd - now);
@@ -764,7 +768,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
 
   /* insert a specific entry */
-  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/24"));
+  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/24"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
@@ -772,7 +776,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
   /* insert a slightly more specific one, but expiring sooner */
   records.clear();
   records.push_back(dr2);
-  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/26"));
+  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/26"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
@@ -801,7 +805,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
   /* insert a non-specific entry */
   records.clear();
   records.push_back(dr1);
-  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none);
+  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none);
 
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
@@ -809,7 +813,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
   /* insert a subnet-specific entry */
   records.clear();
   records.push_back(dr2);
-  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.42/32"));
+  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.42/32"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
@@ -833,6 +837,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe)
   MemRecursorCache MRC;
 
   const DNSName power("powerdns.com.");
+  const DNSName authZone(".");
   std::vector<DNSRecord> records;
   std::vector<std::shared_ptr<DNSRecord>> authRecords;
   std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
@@ -859,7 +864,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe)
 
   /* insert a specific entry */
   records.push_back(dr1);
-  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31"));
+  MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
@@ -869,7 +874,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe)
   dr1.d_name = sub1;
   records.clear();
   records.push_back(dr1);
-  MRC.replace(now, sub1, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31"));
+  MRC.replace(now, sub1, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 2U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 2U);
@@ -878,7 +883,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe)
   dr1.d_name = sub2;
   records.clear();
   records.push_back(dr1);
-  MRC.replace(now, sub2, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31"));
+  MRC.replace(now, sub2, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 3U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 3U);
@@ -888,7 +893,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe)
   dr1.d_name = other1;
   records.clear();
   records.push_back(dr1);
-  MRC.replace(now, other1, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31"));
+  MRC.replace(now, other1, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 4U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 4U);
@@ -897,7 +902,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe)
   dr1.d_name = other2;
   records.clear();
   records.push_back(dr1);
-  MRC.replace(now, other2, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31"));
+  MRC.replace(now, other2, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31"));
 
   BOOST_CHECK_EQUAL(MRC.size(), 5U);
   BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 5U);
@@ -921,6 +926,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
 {
   MemRecursorCache MRC;
 
+  const DNSName authZone(".");
   std::vector<std::shared_ptr<DNSRecord>> authRecords;
   std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
   time_t now = time(nullptr);
@@ -951,8 +957,8 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
 
   BOOST_CHECK_EQUAL(MRC.size(), 0U);
   // An entry without edns subnet gets stored without tag as well
-  MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, boost::none, boost::none);
-  MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, boost::none, string("mytag"));
+  MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, boost::none);
+  MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytag"));
   BOOST_CHECK_EQUAL(MRC.size(), 1U);
   BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1U);
   BOOST_CHECK_EQUAL(MRC.size(), 0U);
@@ -967,8 +973,8 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
       DNSName a = DNSName("hello ") + DNSName(std::to_string(counter));
       BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
 
-      MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, boost::none, string("mytagA"));
-      MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, boost::none, string("mytagB"));
+      MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytagA"));
+      MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytagB"));
       // After this, we have untagged entries, since no address was specified for both replace calls
     }
 
@@ -1010,7 +1016,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
     // Now insert some tagged entries
     for (counter = 0; counter < 50; ++counter) {
       DNSName a = DNSName("hello ") + DNSName(std::to_string(counter));
-      MRC.replace(now, a, QType(QType::A), rset0tagged, signatures, authRecords, true, boost::optional<Netmask>("128.0.0.0/8"), string("mytagA"));
+      MRC.replace(now, a, QType(QType::A), rset0tagged, signatures, authRecords, true, authZone, boost::optional<Netmask>("128.0.0.0/8"), string("mytagA"));
     }
     BOOST_CHECK_EQUAL(MRC.size(), 150U);
 
@@ -1087,7 +1093,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
     rset3.push_back(dr3);
 
     // insert a tagged entry
-    MRC.replace(now, power, QType(QType::A), rset1, signatures, authRecords, true, boost::optional<Netmask>("192.0.2.0/24"), string("mytag"));
+    MRC.replace(now, power, QType(QType::A), rset1, signatures, authRecords, true, authZone, boost::optional<Netmask>("192.0.2.0/24"), string("mytag"));
     BOOST_CHECK_EQUAL(MRC.size(), 1U);
 
     // tagged specific should be returned for a matching tag
@@ -1100,7 +1106,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
     BOOST_CHECK_EQUAL(retrieved.size(), 0U);
 
     // insert a new  entry without tag
-    MRC.replace(now, power, QType(QType::A), rset2, signatures, authRecords, true, boost::optional<Netmask>("192.0.3.0/24"), boost::none);
+    MRC.replace(now, power, QType(QType::A), rset2, signatures, authRecords, true, authZone, boost::optional<Netmask>("192.0.3.0/24"), boost::none);
     BOOST_CHECK_EQUAL(MRC.size(), 2U);
 
     // tagged specific should be returned for a matching tag
@@ -1117,7 +1123,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
     BOOST_REQUIRE_EQUAL(retrieved.size(), 0U);
 
     // Insert untagged entry with no netmask
-    MRC.replace(now, power, QType(QType::A), rset3, signatures, authRecords, true, boost::none, boost::none);
+    MRC.replace(now, power, QType(QType::A), rset3, signatures, authRecords, true, authZone, boost::none, boost::none);
     BOOST_CHECK_EQUAL(MRC.size(), 3U);
 
     // Retrieval with no address and no tag should get that one
index a3845fe1541dbec43017dbef45433840442d68a9..61f55ea7bca6e8c5a38551d62d75a6d3c611c116 100644 (file)
@@ -75,18 +75,18 @@ bool primeHints(void)
     arr.d_content = std::make_shared<ARecordContent>(ComboAddress(rootIps4[c - 'a']));
     vector<DNSRecord> aset;
     aset.push_back(arr);
-    g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
+    g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname); // auth, nuke it all
     if (rootIps6[c - 'a'] != NULL) {
       aaaarr.d_content = std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c - 'a']));
 
       vector<DNSRecord> aaaaset;
       aaaaset.push_back(aaaarr);
-      g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
+      g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname);
     }
 
     nsset.push_back(nsrr);
   }
-  g_recCache->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
+  g_recCache->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, g_rootdnsname); // and stuff in the cache
   return true;
 }
 
index 2c4944dad3f65f9bf18d9214884f12592355ea23..065adc5b800fadfe09bb5ecf70cc240ea0073c01 100644 (file)
@@ -1297,7 +1297,7 @@ BOOST_AUTO_TEST_CASE(test_flawed_nsset)
   std::vector<shared_ptr<RRSIGRecordContent>> sigs;
   addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
 
-  g_recCache->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
+  g_recCache->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::optional<Netmask>());
 
   vector<DNSRecord> ret;
   int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
@@ -1403,7 +1403,7 @@ BOOST_AUTO_TEST_CASE(test_cache_hit)
   std::vector<shared_ptr<RRSIGRecordContent>> sigs;
 
   addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
-  g_recCache->replace(now, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
+  g_recCache->replace(now, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::optional<Netmask>());
 
   vector<DNSRecord> ret;
   int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
@@ -1592,7 +1592,7 @@ BOOST_AUTO_TEST_CASE(test_cache_expired_ttl)
   std::vector<shared_ptr<RRSIGRecordContent>> sigs;
   addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
 
-  g_recCache->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
+  g_recCache->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::optional<Netmask>());
 
   vector<DNSRecord> ret;
   int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
index 235ff0581c41623b8b9f19a198bad33b1ad70a53..8a04eb7f7cf86384b3bc2397848c2dd8a51dfdf8 100644 (file)
@@ -1589,6 +1589,129 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cut_with_cname_at_apex)
   BOOST_CHECK_EQUAL(res, RCode::NoError);
   BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
   BOOST_REQUIRE_EQUAL(ret.size(), 1U);
+  BOOST_CHECK_EQUAL(queriesCount, 13U);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnssec_cname_inside_secure_zone)
+{
+  /* this test makes sure we don't request the DS
+     again and again when there is a CNAME inside a
+     Secure zone */
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+
+  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+  primeHints();
+  const DNSName target("powerdns.com.");
+  const DNSName targetCName("power-dns.com.");
+  const ComboAddress targetCNameAddr("192.0.2.42");
+  testkeysset_t keys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
+  g_luaconfs.setState(luaconfsCopy);
+
+  size_t queriesCount = 0;
+
+  sr->setAsyncCallback([target, targetCName, targetCNameAddr, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
+    queriesCount++;
+
+    if (type == QType::DS) {
+      if (domain.isPartOf(DNSName("powerdns.com.")) || domain.isPartOf(DNSName("power-dns.com."))) {
+        /* no cut */
+        /* technically the zone is com., but we are going to chop off in genericDSAndDNSKEYHandler() */ 
+        return genericDSAndDNSKEYHandler(res, domain, DNSName("powerdns.com."), type, keys, false);
+      }
+      else {
+        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
+      }
+    }
+    else if (type == QType::DNSKEY) {
+      if (domain == g_rootdnsname || domain == DNSName("com.")) {
+        setLWResult(res, 0, true, false, true);
+        addDNSKEY(keys, domain, 300, res->d_records);
+        addRRSIG(keys, res->d_records, domain, 300);
+        return LWResult::Result::Success;
+      }
+      else {
+        setLWResult(res, 0, true, false, true);
+        addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
+        return LWResult::Result::Success;
+      }
+    }
+    else {
+      if (isRootServer(ip)) {
+        setLWResult(res, 0, false, false, true);
+        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
+        addDS(DNSName("com."), 300, res->d_records, keys);
+        addRRSIG(keys, res->d_records, DNSName("."), 300);
+        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+        return LWResult::Result::Success;
+      }
+      else if (ip == ComboAddress("192.0.2.1:53")) {
+        setLWResult(res, 0, true, false, true);
+
+        if (domain == DNSName("com.")) {
+          addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
+          addRRSIG(keys, res->d_records, DNSName("com."), 300);
+          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+          addRRSIG(keys, res->d_records, DNSName("com."), 300);
+        }
+        else {
+          if (domain == DNSName("powerdns.com.")) {
+            addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
+            addRRSIG(keys, res->d_records, DNSName("com."), 300);
+          }
+          else if (domain == DNSName("www.powerdns.com.") || domain == DNSName("www2.powerdns.com.")) {
+            addRecordToLW(res, domain, QType::A, "192.0.2.43");
+            addRRSIG(keys, res->d_records, DNSName("com."), 300);
+          }
+          else if (domain == targetCName) {
+            addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
+            addRRSIG(keys, res->d_records, DNSName("com."), 300);
+          }
+        }
+
+        return LWResult::Result::Success;
+      }
+    }
+
+    return LWResult::Result::Timeout;
+  });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
+  BOOST_CHECK_EQUAL(queriesCount, 8U);
+
+  /* again, to test the cache */
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
+  BOOST_CHECK_EQUAL(queriesCount, 8U);
+
+  /* this time we ask for www.powerdns.com, let's make sure the CNAME does not get in the way */
+  ret.clear();
+  res = sr->beginResolve(DNSName("www.powerdns.com."), QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
+  BOOST_CHECK_EQUAL(queriesCount, 10U);
+
+  /* now we remove the denial of powerdns.com DS from the cache and ask www2 */
+  BOOST_REQUIRE_EQUAL(g_negCache->wipe(target, false), 1);
+  ret.clear();
+  res = sr->beginResolve(DNSName("www2.powerdns.com."), QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
   BOOST_CHECK_EQUAL(queriesCount, 12U);
 }
 
index 5a92d37f6f7ea7983ae4051ecee7dbfb1b70e896..753d87e65b325f36d500edc5dfbf668e254afa04 100644 (file)
@@ -46,6 +46,7 @@ bool primeHints(void)
 {
   // prime root cache
   const vState validationState = vState::Insecure;
+  static const ComboAddress from("255.255.255.255");
   vector<DNSRecord> nsset;
   t_rootNSZones.clear();
 
@@ -68,13 +69,13 @@ bool primeHints(void)
       arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
       vector<DNSRecord> aset;
       aset.push_back(arr);
-      g_recCache->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState); // auth, nuke it all
+      g_recCache->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::none, boost::none, validationState, from); // auth, nuke it all
       if (rootIps6[c-'a'] != NULL) {
         aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
 
         vector<DNSRecord> aaaaset;
         aaaaset.push_back(aaaarr);
-        g_recCache->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState);
+        g_recCache->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::none, boost::none, validationState, from);
       }
       
       nsset.push_back(nsrr);
@@ -94,12 +95,12 @@ bool primeHints(void)
         seenA.insert(rr.qname);
         vector<DNSRecord> aset;
         aset.push_back(DNSRecord(rr));
-        g_recCache->replace(time(0), rr.qname, QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState); // auth, etc see above
+        g_recCache->replace(time(0), rr.qname, QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::none, boost::none, validationState, from); // auth, etc see above
       } else if(rr.qtype.getCode()==QType::AAAA) {
         seenAAAA.insert(rr.qname);
         vector<DNSRecord> aaaaset;
         aaaaset.push_back(DNSRecord(rr));
-        g_recCache->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState);
+        g_recCache->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::none, boost::none, validationState, from);
       } else if(rr.qtype.getCode()==QType::NS) {
         seenNS.insert(DNSName(rr.content));
         rr.content=toLower(rr.content);
@@ -135,7 +136,7 @@ bool primeHints(void)
   }
 
   g_recCache->doWipeCache(g_rootdnsname, false, QType::NS);
-  g_recCache->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, boost::none, boost::none, validationState); // and stuff in the cache
+  g_recCache->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, g_rootdnsname, boost::none, boost::none, validationState, from); // and stuff in the cache
   return true;
 }
 
index 611a07fea66e5af519fc3b90eea7fee30a440f93..d75989d6253dd8294988ec89ecdfc403d42fe89c 100644 (file)
@@ -1390,11 +1390,12 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector
   bool wasAuth;
   uint32_t capTTL = std::numeric_limits<uint32_t>::max();
   DNSName foundName;
+  DNSName authZone;
   QType foundQT = QType(0); // 0 == QTYPE::ENT
 
   LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
   /* we don't require auth data for forward-recurse lookups */
-  if (g_recCache->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
+  if (g_recCache->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth, &authZone) > 0) {
     foundName = qname;
     foundQT = QType(QType::CNAME);
   }
@@ -1411,7 +1412,7 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector
       if (dnameName == qname && qtype != QType::DNAME) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match
         break;
       }
-      if (g_recCache->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
+      if (g_recCache->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth, &authZone) > 0) {
         foundName = dnameName;
         foundQT = QType(QType::DNAME);
         break;
@@ -1423,7 +1424,14 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector
     LOG(prefix<<qname<<": No CNAME or DNAME cache hit of '"<< qname <<"' found"<<endl);
     return false;
   }
-  
+
+  if (qtype == QType::DS && authZone == qname) {
+    /* CNAME at APEX of the child zone, we can't use that to prove that
+       there is no DS */
+    LOG(prefix<<qname<<": Found a "<<foundQT.getName()<<" cache hit of '"<< qname <<"' from "<<authZone<<", but such a record at the apex of the child zone does not prove that there is no DS in the parent zone"<<endl);
+    return false;
+  }
+
   for(auto const &record : cset) {
     if (record.d_class != QClass::IN) {
       continue;
@@ -2922,7 +2930,7 @@ void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DN
   }
 }
 
-RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery)
+RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery, const ComboAddress& remoteIP)
 {
   bool wasForwardRecurse = wasForwarded && rdQuery;
   tcache_t tcache;
@@ -3253,7 +3261,7 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr
         }
       }
       if (doCache) {
-        g_recCache->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, d_routingTag, recordState);
+        g_recCache->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, auth, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, d_routingTag, recordState, remoteIP);
       }
     }
 
@@ -3808,7 +3816,7 @@ void SyncRes::handleNewTarget(const std::string& prefix, const DNSName& qname, c
   updateValidationState(state, cnameState);
 }
 
-bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state)
+bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP)
 {
   string prefix;
   if(doLog()) {
@@ -3835,7 +3843,7 @@ bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qn
   bool needWildcardProof = false;
   bool gatherWildcardProof = false;
   unsigned int wildcardLabelsCount;
-  *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery);
+  *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery, remoteIP);
   if (*rcode != RCode::NoError) {
     return true;
   }
@@ -4002,7 +4010,8 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con
       int rcode = RCode::NoError;
       bool gotNewServers = false;
 
-      if(tns->first.empty() && !wasForwarded) {
+      if (tns->first.empty() && !wasForwarded) {
+        static ComboAddress const s_oobRemote("255.255.255.255");
         LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
         /* setting state to indeterminate since validation is disabled for local auth zone,
            and Insecure would be misleading. */
@@ -4012,7 +4021,7 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con
         lwr.d_aabit=true;
 
         /* we have received an answer, are we done ? */
-        bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
+        bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state, s_oobRemote);
         if (done) {
           return rcode;
         }
@@ -4090,7 +4099,7 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con
           t_sstorage.nsSpeeds[tns->first.empty()? DNSName(remoteIP->toStringWithPort()) : tns->first].submit(*remoteIP, lwr.d_usec, d_now);
 
           /* we have received an answer, are we done ? */
-          bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
+          bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state, *remoteIP);
           if (done) {
             return rcode;
           }
index 8581459b8aa504df30d13c86d8aca6b1c2cf7643..684bfeafca34eb01bba7ce8224d840cffe18e034 100644 (file)
@@ -809,7 +809,7 @@ private:
   int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret,
                   unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state, StopAtDelegation* stopAtDelegation);
   bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool& truncated, bool& spoofed);
-  bool processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state);
+  bool processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP);
 
   int doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state);
   int doResolveNoQNameMinimization(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state, bool* fromCache = NULL, StopAtDelegation* stopAtDelegation = NULL, bool considerforwards = true);
@@ -834,7 +834,7 @@ private:
   vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<std::pair<DNSName, float>>::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<std::pair<DNSName, float>>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly, unsigned int& addressQueriesForNS);
 
   void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
-  RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery);
+  RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery, const ComboAddress& remoteIP);
   bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const bool gatherwildcardProof, const unsigned int wildcardLabelsCount, int& rcode, unsigned int depth);
 
   bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret);