}
}
-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) {
*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);
}
// 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;
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);
}
}
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);
}
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;
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;
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
}
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();
}
cacheEntry.d_submitted = false;
cacheEntry.d_servedStale = 0;
- cacheEntry.d_tcp = overTCP;
lockedShard->d_map.replace(stored, cacheEntry);
}
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);
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&);
};
// 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});
}
}
* 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});
}
}
}
}
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;
}
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) {
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());
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() << ": ");
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
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);
}
}
}
const ComboAddress nobody;
const ComboAddress somebody("::1");
+ const MemRecursorCache::Extra authAddress{ComboAddress{"::2"}, true};
const time_t ttl_time = 90;
auto checker = [&] {
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);
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());
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);
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);
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++;
}
}