auto log = g_slog->withName("taskq")->withValues("name", Logging::Loggable(task.d_qname), "qtype", Logging::Loggable(QType(task.d_qtype).toString()), "netmask", Logging::Loggable(task.d_netmask.empty() ? "" : task.d_netmask.toString()));
const string msg = "Exception while running a background ResolveTask";
SyncRes resolver(now);
- resolver.setRefreshAlmostExpired(task.d_refreshMode);
+ resolver.setRefreshAlmostExpired(task.d_refreshMode != pdns::ResolveTask::RefreshMode::None);
+ resolver.setForcedRefresh(task.d_refreshMode == pdns::ResolveTask::RefreshMode::Forced);
resolver.setQuerySource(task.d_netmask);
if (forceNoQM) {
resolver.setQNameMinimization(false);
return true;
}
-void pushAlmostExpiredTask(const DNSName& qname, uint16_t qtype, time_t deadline, const Netmask& netmask)
+void pushAlmostExpiredTask(const DNSName& qname, uint16_t qtype, time_t deadline, const Netmask& netmask, bool force)
{
if (SyncRes::isUnsupported(qtype)) {
auto log = g_slog->withName("taskq")->withValues("name", Logging::Loggable(qname), "qtype", Logging::Loggable(QType(qtype).toString()), "netmask", Logging::Loggable(netmask.empty() ? "" : netmask.toString()));
log->error(Logr::Error, "Cannot push task", "qtype unsupported");
return;
}
- pdns::ResolveTask task{qname, qtype, deadline, true, resolve, {}, {}, netmask};
+ pdns::ResolveTask task{qname, qtype, deadline, force ? pdns::ResolveTask::ResolveTask::Forced : pdns::ResolveTask::RefreshMode::Refresh, resolve, {}, {}, netmask};
if (s_taskQueue.lock()->queue.push(std::move(task))) {
++s_almost_expired_tasks.pushed;
}
return;
}
auto func = forceQMOff ? resolveForceNoQM : resolve;
- pdns::ResolveTask task{qname, qtype, deadline, false, func, {}, {}, {}};
+ pdns::ResolveTask task{qname, qtype, deadline, pdns::ResolveTask::RefreshMode::None, func, {}, {}, {}};
auto lock = s_taskQueue.lock();
bool inserted = lock->rateLimitSet.insert(now, task);
if (inserted) {
return false;
}
- pdns::ResolveTask task{qname, qtype, deadline, false, tryDoT, ipAddress, nsname, {}};
+ pdns::ResolveTask task{qname, qtype, deadline, pdns::ResolveTask::RefreshMode::None, tryDoT, ipAddress, nsname, {}};
bool pushed = s_taskQueue.lock()->queue.push(std::move(task));
if (pushed) {
++s_almost_expired_tasks.pushed;
if (d_serveStale) {
LOG(prefix << qname << ": Restart, with serve-stale enabled" << endl);
}
- // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
- if (!d_updatingRootNS || qtype.getCode() != QType::NS || !qname.isRoot()) {
- DNSName authname(qname);
- const auto iter = getBestAuthZone(&authname);
-
- if (d_cacheonly) {
- if (iter != t_sstorage.domainmap->end()) {
- if (iter->second.isAuth()) {
- LOG(prefix << qname << ": Cache only lookup for '" << qname << "|" << qtype << "', in auth zone" << endl);
- ret.clear();
- d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, prefix, res);
- if (fromCache != nullptr) {
- *fromCache = d_wasOutOfBand;
- }
- return res;
+
+ // Originally this was all skipped for root refresh cases, but we now have a generic solution
+ // for that via forcedRefresh
+ DNSName authname(qname);
+ const auto iter = getBestAuthZone(&authname);
+
+ if (d_cacheonly) {
+ if (iter != t_sstorage.domainmap->end()) {
+ if (iter->second.isAuth()) {
+ LOG(prefix << qname << ": Cache only lookup for '" << qname << "|" << qtype << "', in auth zone" << endl);
+ ret.clear();
+ d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, prefix, res);
+ if (fromCache != nullptr) {
+ *fromCache = d_wasOutOfBand;
}
+ return res;
}
}
+ }
- bool wasForwardedOrAuthZone = false;
- bool wasAuthZone = false;
- bool wasForwardRecurse = false;
+ bool wasForwardedOrAuthZone = false;
+ bool wasAuthZone = false;
+ bool wasForwardRecurse = false;
- if (iter != t_sstorage.domainmap->end()) {
- wasForwardedOrAuthZone = true;
+ if (iter != t_sstorage.domainmap->end()) {
+ wasForwardedOrAuthZone = true;
- if (iter->second.isAuth()) {
- wasAuthZone = true;
- }
- else if (iter->second.shouldRecurse()) {
- wasForwardRecurse = true;
- }
+ if (iter->second.isAuth()) {
+ wasAuthZone = true;
+ }
+ else if (iter->second.shouldRecurse()) {
+ wasForwardRecurse = true;
}
+ }
- /* When we are looking for a DS, we want to the non-CNAME cache check first
- because we can actually have a DS (from the parent zone) AND a CNAME (from
- the child zone), and what we really want is the DS */
- if (qtype != QType::DS && doCNAMECacheCheck(qname, qtype, ret, depth, prefix, res, context, wasAuthZone, wasForwardRecurse, loop == 1)) { // will reroute us if needed
- d_wasOutOfBand = wasAuthZone;
- // Here we have an issue. If we were prevented from going out to the network (cache-only was set, possibly because we
- // are in QM Step0) we might have a CNAME but not the corresponding target.
- // It means that we will sometimes go to the next steps when we are in fact done, but that's fine since
- // we will get the records from the cache, resulting in a small overhead.
- // This might be a real problem if we had a RPZ hit, though, because we do not want the processing to continue, since
- // RPZ rules will not be evaluated anymore (we already matched).
- bool stoppedByPolicyHit = d_appliedPolicy.wasHit();
- if (stoppedByPolicyHit && d_appliedPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom && d_appliedPolicy.d_custom) {
- // if the custom RPZ record was a CNAME we still need a full chase
- // tested by unit test test_following_cname_chain_with_rpz
- if (!d_appliedPolicy.d_custom->empty() && d_appliedPolicy.d_custom->at(0)->getType() == QType::CNAME) {
- stoppedByPolicyHit = false;
- }
- }
- if (fromCache != nullptr && (!d_cacheonly || stoppedByPolicyHit)) {
- *fromCache = true;
+ /* When we are looking for a DS, we want to the non-CNAME cache check first
+ because we can actually have a DS (from the parent zone) AND a CNAME (from
+ the child zone), and what we really want is the DS */
+ if (qtype != QType::DS && doCNAMECacheCheck(qname, qtype, ret, depth, prefix, res, context, wasAuthZone, wasForwardRecurse, loop == 1)) { // will reroute us if needed
+ d_wasOutOfBand = wasAuthZone;
+ // Here we have an issue. If we were prevented from going out to the network (cache-only was set, possibly because we
+ // are in QM Step0) we might have a CNAME but not the corresponding target.
+ // It means that we will sometimes go to the next steps when we are in fact done, but that's fine since
+ // we will get the records from the cache, resulting in a small overhead.
+ // This might be a real problem if we had a RPZ hit, though, because we do not want the processing to continue, since
+ // RPZ rules will not be evaluated anymore (we already matched).
+ bool stoppedByPolicyHit = d_appliedPolicy.wasHit();
+ if (stoppedByPolicyHit && d_appliedPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom && d_appliedPolicy.d_custom) {
+ // if the custom RPZ record was a CNAME we still need a full chase
+ // tested by unit test test_following_cname_chain_with_rpz
+ if (!d_appliedPolicy.d_custom->empty() && d_appliedPolicy.d_custom->at(0)->getType() == QType::CNAME) {
+ stoppedByPolicyHit = false;
}
- /* Apply Post filtering policies */
-
- if (d_wantsRPZ && !d_appliedPolicy.wasHit()) {
- auto luaLocal = g_luaconfs.getLocal();
- if (luaLocal->dfe.getPostPolicy(ret, d_discardedPolicies, d_appliedPolicy)) {
- mergePolicyTags(d_policyTags, d_appliedPolicy.getTags());
- bool done = false;
- handlePolicyHit(prefix, qname, qtype, ret, done, res, depth);
- if (done && fromCache != nullptr) {
- *fromCache = true;
- }
+ }
+ if (fromCache != nullptr && (!d_cacheonly || stoppedByPolicyHit)) {
+ *fromCache = true;
+ }
+ /* Apply Post filtering policies */
+
+ if (d_wantsRPZ && !d_appliedPolicy.wasHit()) {
+ auto luaLocal = g_luaconfs.getLocal();
+ if (luaLocal->dfe.getPostPolicy(ret, d_discardedPolicies, d_appliedPolicy)) {
+ mergePolicyTags(d_policyTags, d_appliedPolicy.getTags());
+ bool done = false;
+ handlePolicyHit(prefix, qname, qtype, ret, done, res, depth);
+ if (done && fromCache != nullptr) {
+ *fromCache = true;
}
}
- // This handles the case mentioned above: if the full CNAME chain leading to the answer was
- // constructed from the cache, indicate that.
- if (fromCache != nullptr && !*fromCache && haveFinalAnswer(qname, qtype, res, ret)) {
- *fromCache = true;
- }
- return res;
}
+ // This handles the case mentioned above: if the full CNAME chain leading to the answer was
+ // constructed from the cache, indicate that.
+ if (fromCache != nullptr && !*fromCache && haveFinalAnswer(qname, qtype, res, ret)) {
+ *fromCache = true;
+ }
+ return res;
+ }
- if (doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, wasForwardRecurse, qtype, ret, depth, prefix, res, context)) {
- // we done
- d_wasOutOfBand = wasAuthZone;
- if (fromCache != nullptr) {
- *fromCache = true;
- }
+ if (doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, wasForwardRecurse, qtype, ret, depth, prefix, res, context)) {
+ // we done
+ d_wasOutOfBand = wasAuthZone;
+ if (fromCache != nullptr) {
+ *fromCache = true;
+ }
- if (d_wantsRPZ && !d_appliedPolicy.wasHit()) {
- auto luaLocal = g_luaconfs.getLocal();
- if (luaLocal->dfe.getPostPolicy(ret, d_discardedPolicies, d_appliedPolicy)) {
- mergePolicyTags(d_policyTags, d_appliedPolicy.getTags());
- bool done = false;
- handlePolicyHit(prefix, qname, qtype, ret, done, res, depth);
- }
+ if (d_wantsRPZ && !d_appliedPolicy.wasHit()) {
+ auto luaLocal = g_luaconfs.getLocal();
+ if (luaLocal->dfe.getPostPolicy(ret, d_discardedPolicies, d_appliedPolicy)) {
+ mergePolicyTags(d_policyTags, d_appliedPolicy.getTags());
+ bool done = false;
+ handlePolicyHit(prefix, qname, qtype, ret, done, res, depth);
}
-
- return res;
}
- /* if we have not found a cached DS (or denial of), now is the time to look for a CNAME */
- if (qtype == QType::DS && doCNAMECacheCheck(qname, qtype, ret, depth, prefix, res, context, wasAuthZone, wasForwardRecurse, loop == 1)) { // will reroute us if needed
- d_wasOutOfBand = wasAuthZone;
- // Here we have an issue. If we were prevented from going out to the network (cache-only was set, possibly because we
- // are in QM Step0) we might have a CNAME but not the corresponding target.
- // It means that we will sometimes go to the next steps when we are in fact done, but that's fine since
- // we will get the records from the cache, resulting in a small overhead.
- // This might be a real problem if we had a RPZ hit, though, because we do not want the processing to continue, since
- // RPZ rules will not be evaluated anymore (we already matched).
- const bool stoppedByPolicyHit = d_appliedPolicy.wasHit();
+ return res;
+ }
- if (fromCache != nullptr && (!d_cacheonly || stoppedByPolicyHit)) {
- *fromCache = true;
- }
- /* Apply Post filtering policies */
-
- if (d_wantsRPZ && !stoppedByPolicyHit) {
- auto luaLocal = g_luaconfs.getLocal();
- if (luaLocal->dfe.getPostPolicy(ret, d_discardedPolicies, d_appliedPolicy)) {
- mergePolicyTags(d_policyTags, d_appliedPolicy.getTags());
- bool done = false;
- handlePolicyHit(prefix, qname, qtype, ret, done, res, depth);
- if (done && fromCache != nullptr) {
- *fromCache = true;
- }
+ /* if we have not found a cached DS (or denial of), now is the time to look for a CNAME */
+ if (qtype == QType::DS && doCNAMECacheCheck(qname, qtype, ret, depth, prefix, res, context, wasAuthZone, wasForwardRecurse, loop == 1)) { // will reroute us if needed
+ d_wasOutOfBand = wasAuthZone;
+ // Here we have an issue. If we were prevented from going out to the network (cache-only was set, possibly because we
+ // are in QM Step0) we might have a CNAME but not the corresponding target.
+ // It means that we will sometimes go to the next steps when we are in fact done, but that's fine since
+ // we will get the records from the cache, resulting in a small overhead.
+ // This might be a real problem if we had a RPZ hit, though, because we do not want the processing to continue, since
+ // RPZ rules will not be evaluated anymore (we already matched).
+ const bool stoppedByPolicyHit = d_appliedPolicy.wasHit();
+
+ if (fromCache != nullptr && (!d_cacheonly || stoppedByPolicyHit)) {
+ *fromCache = true;
+ }
+ /* Apply Post filtering policies */
+
+ if (d_wantsRPZ && !stoppedByPolicyHit) {
+ auto luaLocal = g_luaconfs.getLocal();
+ if (luaLocal->dfe.getPostPolicy(ret, d_discardedPolicies, d_appliedPolicy)) {
+ mergePolicyTags(d_policyTags, d_appliedPolicy.getTags());
+ bool done = false;
+ handlePolicyHit(prefix, qname, qtype, ret, done, res, depth);
+ if (done && fromCache != nullptr) {
+ *fromCache = true;
}
}
- if (fromCache != nullptr && !*fromCache && haveFinalAnswer(qname, qtype, res, ret)) {
- *fromCache = true;
- }
- return res;
}
+ if (fromCache != nullptr && !*fromCache && haveFinalAnswer(qname, qtype, res, ret)) {
+ *fromCache = true;
+ }
+ return res;
}
if (d_cacheonly) {
if (d_refresh) {
flags |= MemRecursorCache::Refresh;
}
+ if (d_forcedRefresh) {
+ flags |= MemRecursorCache::ForcedRefresh;
+ }
if (d_serveStale) {
flags |= MemRecursorCache::ServeStale;
}
if (d_refresh) {
flags |= MemRecursorCache::Refresh;
}
+ if (d_forcedRefresh) {
+ flags |= MemRecursorCache::ForcedRefresh;
+ }
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) {
resolver.setUpdatingRootNS();
resolver.setAsyncCallback(std::move(asyncCallback));
resolver.setRefreshAlmostExpired(true);
+ resolver.setForcedRefresh(true);
const string msg = "Failed to update . records";
vector<DNSRecord> ret;