]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Combine a few args to get() and replace() into struct 16384/head
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Mon, 27 Oct 2025 11:21:16 +0000 (12:21 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 29 Oct 2025 08:23:30 +0000 (09:23 +0100)
Signed-off-by: Otto Moerbeek <otto.moerbeek@open-xchange.com>
pdns/recursordist/recursor_cache.cc
pdns/recursordist/recursor_cache.hh
pdns/recursordist/reczones-helpers.cc
pdns/recursordist/reczones.cc
pdns/recursordist/syncres.cc
pdns/recursordist/test-recursorcache_cc.cc

index 517cbba56bf1f5870635f250869d02f8e550bc6b..5e2f5d7466733dfe3581d7d6ea53b013fa527976 100644 (file)
@@ -207,7 +207,7 @@ static void ptrAssign(T* ptr, const T& value)
   }
 }
 
-time_t MemRecursorCache::handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP, bool* tcp)
+time_t MemRecursorCache::handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* fromAuthZone, Extra* extra)
 {
   // MUTEX SHOULD BE ACQUIRED (as indicated by the reference to the content which is protected by a lock)
   if (entry->d_tooBig) {
@@ -269,8 +269,10 @@ time_t MemRecursorCache::handleHit(time_t now, MapCombo::LockedContent& content,
     *wasAuth = *wasAuth && entry->d_auth;
   }
   ptrAssign(fromAuthZone, entry->d_authZone);
-  ptrAssign(fromAuthIP, entry->d_from);
-  ptrAssign(tcp, entry->d_tcp);
+  if (extra != nullptr) {
+    extra->d_address = entry->d_from;
+    extra->d_tcp = entry->d_tcp;
+  }
 
   moveCacheItemToBack<SequencedTag>(content.d_map, entry);
 
@@ -428,7 +430,7 @@ time_t MemRecursorCache::fakeTTD(MemRecursorCache::OrderedTagIterator_t& entry,
 }
 
 // returns -1 for no hits
-time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP, bool* tcp) // NOLINT(readability-function-cognitive-complexity)
+time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone, Extra* extra) // NOLINT(readability-function-cognitive-complexity)
 {
   bool requireAuth = (flags & RequireAuth) != 0;
   bool refresh = (flags & Refresh) != 0;
@@ -456,11 +458,11 @@ time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype
 
       auto entryA = getEntryUsingECSIndex(*lockedShard, now, qname, QType::A, requireAuth, who, serveStale);
       if (entryA != lockedShard->d_map.end()) {
-        ret = handleHit(now, *lockedShard, entryA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP, tcp);
+        ret = handleHit(now, *lockedShard, entryA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra);
       }
       auto entryAAAA = getEntryUsingECSIndex(*lockedShard, now, qname, QType::AAAA, requireAuth, who, serveStale);
       if (entryAAAA != lockedShard->d_map.end()) {
-        time_t ttdAAAA = handleHit(now, *lockedShard, entryAAAA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP, tcp);
+        time_t ttdAAAA = handleHit(now, *lockedShard, entryAAAA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra);
         if (ret > 0) {
           ret = std::min(ret, ttdAAAA);
         }
@@ -477,7 +479,7 @@ time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype
     }
     auto entry = getEntryUsingECSIndex(*lockedShard, now, qname, qtype, requireAuth, who, serveStale);
     if (entry != lockedShard->d_map.end()) {
-      time_t ret = handleHit(now, *lockedShard, entry, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP, tcp);
+      time_t ret = handleHit(now, *lockedShard, entry, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra);
       if (cachedState && ret > now) {
         ptrAssign(state, *cachedState);
       }
@@ -509,7 +511,7 @@ time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype
 
         handleServeStaleBookkeeping(now, serveStale, firstIndexIterator);
 
-        ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP, tcp);
+        ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra);
 
         if (qtype == QType::ADDR && found == 2) {
           break;
@@ -551,7 +553,7 @@ time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype
 
       handleServeStaleBookkeeping(now, serveStale, firstIndexIterator);
 
-      ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP, tcp);
+      ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra);
 
       if (qtype == QType::ADDR && found == 2) {
         break;
@@ -631,14 +633,16 @@ bool MemRecursorCache::replace(CacheEntry&& entry)
   return false;
 }
 
-void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qtype, const vector<DNSRecord>& content, const SigRecsVec& signatures, const AuthRecsVec& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask, const OptTag& routingTag, vState state, boost::optional<ComboAddress> from, bool overTCP, bool refresh, time_t ttl_time)
+void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qtype, const vector<DNSRecord>& content, const SigRecsVec& signatures, const AuthRecsVec& authorityRecs, bool auth, const DNSName& authZone, const boost::optional<Netmask>& ednsmaskArg, const OptTag& routingTag, vState state, const boost::optional<Extra>& extra, bool refresh, time_t ttl_time)
 {
   auto& shard = getMap(qname);
   auto lockedShard = shard.lock();
 
   lockedShard->d_cachecachevalid = false;
-  if (ednsmask) {
-    ednsmask = ednsmask->getNormalized();
+
+  boost::optional<Netmask> ednsmask;
+  if (ednsmaskArg) {
+    ednsmask = ednsmaskArg->getNormalized();
   }
 
   // We only store with a tag if we have an ednsmask and the tag is available
@@ -705,11 +709,13 @@ void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qty
   }
   cacheEntry.d_records.clear();
   cacheEntry.d_authZone = authZone;
-  if (from) {
-    cacheEntry.d_from = *from;
+  if (extra) {
+    cacheEntry.d_from = extra->d_address;
+    cacheEntry.d_tcp = extra->d_tcp;
   }
   else {
     cacheEntry.d_from = ComboAddress();
+    cacheEntry.d_tcp = false;
   }
 
   size_t toStore = content.size();
@@ -745,7 +751,6 @@ void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qty
   }
   cacheEntry.d_submitted = false;
   cacheEntry.d_servedStale = 0;
-  cacheEntry.d_tcp = overTCP;
   lockedShard->d_map.replace(stored, cacheEntry);
 }
 
index cd3a3f0621b281c6f09153615d46e65106156a65..595b8cde10f8dd3bea113ab49149cadaca58d27c 100644 (file)
@@ -96,9 +96,15 @@ public:
   using SigRecs = std::shared_ptr<const SigRecsVec>; // Also const as it is shared
   const static SigRecs s_emptySigRecs;
 
-  [[nodiscard]] time_t get(time_t, const DNSName& qname, QType qtype, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag = boost::none, SigRecs* signatures = nullptr, AuthRecs* authorityRecs = nullptr, bool* variable = nullptr, vState* state = nullptr, bool* wasAuth = nullptr, DNSName* fromAuthZone = nullptr, ComboAddress* fromAuthIP = nullptr, bool *tcp = nullptr);
+  struct Extra
+  {
+    ComboAddress d_address;
+    bool d_tcp{false};
+  };
+
+  [[nodiscard]] time_t get(time_t, const DNSName& qname, QType qtype, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag = boost::none, SigRecs* signatures = nullptr, AuthRecs* authorityRecs = nullptr, bool* variable = nullptr, vState* state = nullptr, bool* wasAuth = nullptr, DNSName* fromAuthZone = nullptr, Extra* extra = nullptr);
 
-  void replace(time_t, const DNSName& qname, QType qtype, const vector<DNSRecord>& content, const SigRecsVec& signatures, const AuthRecsVec& 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, bool overTCP = false, bool refresh = false, time_t ttl_time = time(nullptr));
+  void replace(time_t, const DNSName& qname, QType qtype, const vector<DNSRecord>& content, const SigRecsVec& signatures, const AuthRecsVec& authorityRecs, bool auth, const DNSName& authZone, const boost::optional<Netmask>& ednsmask = boost::none, const OptTag& routingTag = boost::none, vState state = vState::Indeterminate, const boost::optional<Extra>& extra = boost::none, bool refresh = false, time_t ttl_time = time(nullptr));
 
   void doPrune(time_t now, size_t keep);
   uint64_t doDump(int fileDesc, size_t maxCacheEntries);
@@ -379,7 +385,7 @@ private:
   static Entries getEntries(MapCombo::LockedContent& map, const DNSName& qname, QType qtype, const OptTag& rtag);
   static cache_t::const_iterator getEntryUsingECSIndex(MapCombo::LockedContent& map, time_t now, const DNSName& qname, QType qtype, bool requireAuth, const ComboAddress& who, bool serveStale);
 
-  static time_t handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* authZone, ComboAddress* fromAuthIP, bool* tcp);
+  static time_t handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* authZone, Extra* extra);
   static void updateStaleEntry(time_t now, OrderedTagIterator_t& entry);
   static void handleServeStaleBookkeeping(time_t, bool, OrderedTagIterator_t&);
 };
index a0d61d8b7b8263faf477efdf982de97ab031c80f..147d32f55fba313608ed03b5c2d3a329f3b116d9 100644 (file)
@@ -41,7 +41,7 @@ static void putIntoCache(time_t now, QType qtype, vState state, const ComboAddre
     // Put non-default root hints into cache as authoritative.  As argued below in
     // putDefaultHintsIntoCache, this is actually wrong, but people might depend on it by having
     // root-hints that refer to servers that aren't actually capable or willing to serve root data.
-    g_recCache->replace(now, name, qtype, aset, {}, {}, true, g_rootdnsname, boost::none, boost::none, state, from);
+    g_recCache->replace(now, name, qtype, aset, {}, {}, true, g_rootdnsname, boost::none, boost::none, state, MemRecursorCache::Extra{from, false});
   }
 }
 
@@ -158,11 +158,11 @@ void putDefaultHintsIntoCache(time_t now, std::vector<DNSRecord>& nsvec)
        * auth and will expire at the same time. A re-prime is then triggered, as before, when the
        * records were inserted with the auth bit set and the TTD comes.
        */
-      g_recCache->replace(now, DNSName(templ), QType::A, {arr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, from);
+      g_recCache->replace(now, DNSName(templ), QType::A, {arr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, MemRecursorCache::Extra{from, false});
     }
     if (!rootIps6.at(letter).empty()) {
       aaaarr.setContent(std::make_shared<AAAARecordContent>(ComboAddress(rootIps6.at(letter))));
-      g_recCache->replace(now, DNSName(templ), QType::AAAA, {aaaarr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, from);
+      g_recCache->replace(now, DNSName(templ), QType::AAAA, {aaaarr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, MemRecursorCache::Extra{from, false});
     }
   }
 }
index dba5c5dcdd694e966da21201b21838e4a70c2e09..745cad67b589416290099054940d210998c1b5ef 100644 (file)
@@ -56,7 +56,7 @@ bool primeHints(time_t now)
   }
 
   g_recCache->doWipeCache(g_rootdnsname, false, QType::NS);
-  g_recCache->replace(now, g_rootdnsname, QType::NS, nsvec, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, ComboAddress("255.255.255.255")); // and stuff in the cache
+  g_recCache->replace(now, g_rootdnsname, QType::NS, nsvec, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, MemRecursorCache::Extra{ComboAddress("255.255.255.255"), false}); // and stuff in the cache
   return ret;
 }
 
index a16317bb85cf0bae7e63ed82e4c0f779a8e58511..377ca68bee24ae1cd3fb6b9311cd578b8c1d29b5 100644 (file)
@@ -2498,9 +2498,11 @@ bool SyncRes::doCNAMECacheCheck(const DNSName& qname, const QType qtype, vector<
   if (d_serveStale) {
     flags |= MemRecursorCache::ServeStale;
   }
-  if (g_recCache->get(d_now.tv_sec, qname, QType::CNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &d_fromAuthIP) > 0) {
+  MemRecursorCache::Extra extra;
+  if (g_recCache->get(d_now.tv_sec, qname, QType::CNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &extra) > 0) {
     foundName = qname;
     foundQT = QType::CNAME;
+    d_fromAuthIP = extra.d_address;
   }
 
   if (foundName.empty() && qname != g_rootdnsname) {
@@ -2514,9 +2516,10 @@ 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::DNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &d_fromAuthIP) > 0) {
+      if (g_recCache->get(d_now.tv_sec, dnameName, QType::DNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &extra) > 0) {
         foundName = std::move(dnameName);
         foundQT = QType::DNAME;
+        d_fromAuthIP = extra.d_address;
         break;
       }
     } while (!labels.empty());
@@ -2938,7 +2941,10 @@ bool SyncRes::doCacheCheck(const DNSName& qname, const DNSName& authname, bool w
   if (d_refresh) {
     flags |= MemRecursorCache::Refresh;
   }
-  if (g_recCache->get(d_now.tv_sec, sqname, sqt, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth, nullptr, &d_fromAuthIP) > 0) {
+
+  MemRecursorCache::Extra extra;
+  if (g_recCache->get(d_now.tv_sec, sqname, sqt, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth, nullptr, &extra) > 0) {
+    d_fromAuthIP = extra.d_address;
 
     LOG(prefix << sqname << ": Found cache hit for " << sqt.toString() << ": ");
 
@@ -4821,7 +4827,7 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, const string&
             thisRRNeedsWildcardProof = true;
           }
         }
-        g_recCache->replace(d_now.tv_sec, tCacheEntry->first.name, tCacheEntry->first.type, tCacheEntry->second.records, tCacheEntry->second.signatures, thisRRNeedsWildcardProof ? authorityRecs : *MemRecursorCache::s_emptyAuthRecs, tCacheEntry->first.type == QType::DS ? true : isAA, auth, tCacheEntry->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, d_routingTag, recordState, remoteIP, overTCP, d_refresh, tCacheEntry->second.d_ttl_time);
+        g_recCache->replace(d_now.tv_sec, tCacheEntry->first.name, tCacheEntry->first.type, tCacheEntry->second.records, tCacheEntry->second.signatures, thisRRNeedsWildcardProof ? authorityRecs : *MemRecursorCache::s_emptyAuthRecs, tCacheEntry->first.type == QType::DS ? true : isAA, auth, tCacheEntry->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, d_routingTag, recordState, MemRecursorCache::Extra{remoteIP, overTCP}, d_refresh, tCacheEntry->second.d_ttl_time);
 
         // Delete potential negcache entry. When a record recovers with serve-stale the negcache entry can cause the wrong entry to
         // be served, as negcache entries are checked before record cache entries
@@ -4846,7 +4852,7 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, const string&
               content.push_back(std::move(nonExpandedRecord));
             }
 
-            g_recCache->replace(d_now.tv_sec, realOwner, QType(tCacheEntry->first.type), content, tCacheEntry->second.signatures, /* no additional records in that case */ {}, tCacheEntry->first.type == QType::DS ? true : isAA, auth, boost::none, boost::none, recordState, remoteIP, overTCP, d_refresh, tCacheEntry->second.d_ttl_time);
+            g_recCache->replace(d_now.tv_sec, realOwner, QType(tCacheEntry->first.type), content, tCacheEntry->second.signatures, /* no additional records in that case */ {}, tCacheEntry->first.type == QType::DS ? true : isAA, auth, boost::none, boost::none, recordState, MemRecursorCache::Extra{remoteIP, overTCP}, d_refresh, tCacheEntry->second.d_ttl_time);
           }
         }
       }
index 3c4ebf0fad9eb2b158454f12765e9cf3297ffaa2..073beac6134f8093685ce9a6812080c6725a17cb 100644 (file)
@@ -1323,6 +1323,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheDumpAndRestore)
 
   const ComboAddress nobody;
   const ComboAddress somebody("::1");
+  const MemRecursorCache::Extra authAddress{ComboAddress{"::2"}, true};
   const time_t ttl_time = 90;
 
   auto checker = [&] {
@@ -1332,7 +1333,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheDumpAndRestore)
       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, authZone, boost::none, boost::none, vState::Insecure, somebody, false, ttl_time);
+      MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, boost::none, vState::Insecure, authAddress, false, ttl_time);
     }
 
     BOOST_CHECK_EQUAL(MRC.size(), expected);
@@ -1347,8 +1348,8 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheDumpAndRestore)
       vState state = vState::Indeterminate;
       bool wasAuth = false;
       DNSName fromZone;
-      ComboAddress from;
-      if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, somebody, boost::none, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &from) > 0) {
+      MemRecursorCache::Extra extra;
+      if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, somebody, boost::none, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &extra) > 0) {
         matches++;
         BOOST_CHECK_EQUAL(retrieved.size(), rset0.size());
         BOOST_CHECK_EQUAL(getRR<ARecordContent>(retrieved.at(0))->getCA().toString(), dr0Content.toString());
@@ -1360,7 +1361,8 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheDumpAndRestore)
         BOOST_CHECK_EQUAL(state, vState::Insecure);
         BOOST_CHECK_EQUAL(wasAuth, true);
         BOOST_CHECK_EQUAL(fromZone, authZone);
-        BOOST_CHECK_EQUAL(from.toString(), somebody.toString());
+        BOOST_CHECK_EQUAL(extra.d_address.toString(), authAddress.d_address.toString());
+        BOOST_CHECK(extra.d_tcp);
       }
     }
     BOOST_CHECK_EQUAL(matches, expected);
@@ -1480,7 +1482,7 @@ struct RecordsSpeedTest
       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, authZone, boost::none, boost::none, vState::Insecure, somebody, false, ttl_time);
+      MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, boost::none, vState::Insecure, MemRecursorCache::Extra{somebody, false}, false, ttl_time);
     }
 
     BOOST_CHECK_EQUAL(MRC.size(), expected);
@@ -1497,8 +1499,10 @@ struct RecordsSpeedTest
         vState state = vState::Indeterminate;
         bool wasAuth = false;
         DNSName fromZone;
-        ComboAddress from;
-        if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, somebody, boost::none, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &from) > 0) {
+        MemRecursorCache::Extra extra;
+        if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, somebody, boost::none, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &extra) > 0) {
+          BOOST_CHECK_EQUAL(somebody.toString(), extra.d_address.toString());
+          BOOST_CHECK(!extra.d_tcp);
           matches++;
         }
       }