Also fix DNSSEC validation statistics.
uint32_t minTTL=std::numeric_limits<uint32_t>::max();
SyncRes sr(dc->d_now);
+
bool DNSSECOK=false;
if(t_pdl) {
sr.setLuaEngine(t_pdl);
// Ignore the client-set CD flag
pw.getHeader()->cd=0;
}
+ sr.setDNSSECValidationRequested(g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode==DNSSECMode::ValidateForLog || ((dc->d_mdp.d_header.ad || DNSSECOK) && g_dnssecmode==DNSSECMode::Process));
+
#ifdef HAVE_PROTOBUF
sr.setInitialRequestId(dc->d_uuid);
#endif
+
if (g_useIncomingECS) {
sr.setIncomingECSFound(dc->d_ecsFound);
if (dc->d_ecsFound) {
pw.getHeader()->rcode=res;
// Does the validation mode or query demand validation?
- if(!shouldNotValidate && (g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode==DNSSECMode::ValidateForLog || ((dc->d_mdp.d_header.ad || DNSSECOK) && g_dnssecmode==DNSSECMode::Process))) {
+ if(!shouldNotValidate && sr.isDNSSECValidationRequested()) {
try {
if(sr.doLog()) {
L<<Logger::Warning<<"Starting validation of answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->d_remote.toStringWithPort()<<endl;
sr = std::unique_ptr<SyncRes>(new SyncRes(now));
sr->setDoEDNS0(true);
- sr->setDoDNSSEC(dnssec);
+ if (dnssec) {
+ sr->setDoDNSSEC(dnssec);
+ }
+
sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
SyncRes::clearNegCache();
}
+static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
+{
+ sr->setDNSSECValidationRequested(true);
+ g_dnssecmode = mode;
+}
+
static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
{
res->d_rcode = rcode;
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("nx.powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("www.powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("www.powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("www.powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("www.sub.powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("www.sub.powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("power-dns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("power-dns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("power-dns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("power-dns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target("powerdns.com.");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
- g_dnssecmode = DNSSECMode::ValidateAll;
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
primeHints();
const DNSName target(".");
struct timeval now;
gettimeofday(&now, 0);
SyncRes sr(now);
- if (g_dnssecmode != DNSSECMode::Off)
+ if (g_dnssecmode != DNSSECMode::Off) {
sr.setDoDNSSEC(true);
+ sr.setDNSSECValidationRequested(true);
+ }
+
vector<DNSRecord> ret;
string version = "recursor-" +pkgv;
set<GetBestNSAnswer> beenthere;
int res=doResolve(qname, qtype, ret, 0, beenthere, state);
d_queryValidationState = state;
+
+ if (d_queryValidationState != Indeterminate) {
+ g_stats.dnssecValidations++;
+ }
+ if (d_DNSSECValidationRequested) {
+ increaseDNSSECStateCounter(d_queryValidationState);
+ }
+
return res;
}
for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
if(j->d_ttl>(unsigned int) d_now.tv_sec) {
- if (validationEnabled() && wasAuth && state == Indeterminate && d_requireAuthData) {
+ if (d_DNSSECValidationRequested && wasAuth && state == Indeterminate && d_requireAuthData) {
/* This means we couldn't figure out the state when this entry was cached,
most likely because we hadn't computed the zone cuts yet. */
/* make sure they are computed before validating */
LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
- if (validationEnabled() && sqt != QType::DNSKEY && wasCachedAuth && cachedState == Indeterminate && d_requireAuthData) {
+ if (d_DNSSECValidationRequested && sqt != QType::DNSKEY && wasCachedAuth && cachedState == Indeterminate && d_requireAuthData) {
/* This means we couldn't figure out the state when this entry was cached,
most likely because we hadn't computed the zone cuts yet. */
for(const auto& record : records)
lowestTTD = min(lowestTTD, record.d_ttl);
+ /* even if it was not requested for that request (Process, and neither AD nor DO set),
+ it might be requested at a later time so we need to be careful with the TTL. */
if (validationEnabled() && !signatures.empty()) {
/* if we are validating, we don't want to cache records after their signatures
expires. */
bool SyncRes::haveExactValidationStatus(const DNSName& domain)
{
- if (!validationEnabled()) {
+ if (!d_DNSSECValidationRequested) {
return false;
}
const auto& it = d_cutStates.find(domain);
{
vState result = Indeterminate;
- if (!validationEnabled()) {
+ if (!d_DNSSECValidationRequested) {
return result;
}
DNSName name(subdomain);
LOG(d_prefix<<": setting cut state for "<<end<<" to "<<vStates[cutState]<<endl);
d_cutStates[end] = cutState;
- if (!validationEnabled()) {
+ if (!d_DNSSECValidationRequested) {
return;
}
vState recordState = getValidationStatus(auth);
LOG(d_prefix<<": got initial zone status "<<vStates[recordState]<<" for record "<<i->first.name<<endl);
- if (validationEnabled() && recordState == Secure) {
+ if (d_DNSSECValidationRequested && recordState == Secure) {
if (isAA) {
if (i->first.place != DNSResourceRecord::ADDITIONAL) {
/* the additional entries can be insecure,
updateValidationState(state, recordState);
}
else {
- if (validationEnabled()) {
+ if (d_DNSSECValidationRequested) {
LOG(d_prefix<<"Skipping validation because the current state is "<<vStates[recordState]<<endl);
}
}
sr.setDoEDNS0(true);
sr.setUpdatingRootNS();
sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off);
+ sr.setDNSSECValidationRequested(g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate);
sr.setAsyncCallback(asyncCallback);
vector<DNSRecord> ret;
d_doDNSSEC=state;
}
+ void setDNSSECValidationRequested(bool requested=true)
+ {
+ d_DNSSECValidationRequested = requested;
+ }
+
+ bool isDNSSECValidationRequested() const
+ {
+ return d_DNSSECValidationRequested;
+ }
+
void setWantsRPZ(bool state=true)
{
d_wantsRPZ=state;
*/
bool d_cacheonly;
bool d_doDNSSEC;
+ bool d_DNSSECValidationRequested{false};
bool d_doEDNS0{true};
bool d_incomingECSFound{false};
bool d_requireAuthData{true};
DNSSECMode g_dnssecmode{DNSSECMode::ProcessNoValidate};
bool g_dnssecLogBogus;
-extern int getMTaskerTID();
-
-#define LOG(x) if(g_dnssecLOG) { L <<Logger::Warning << x; }
-
-class SRRecordOracle : public DNSRecordOracle
-{
-public:
- SRRecordOracle(const ResolveContext& ctx): d_ctx(ctx)
- {
- }
- vector<DNSRecord> get(const DNSName& qname, uint16_t qtype) override
- {
- struct timeval tv;
- gettimeofday(&tv, 0);
- SyncRes sr(tv);
- sr.setId(getMTaskerTID());
-#ifdef HAVE_PROTOBUF
- sr.setInitialRequestId(d_ctx.d_initialRequestId);
-#endif
-
- vector<DNSRecord> ret;
- sr.setDoDNSSEC(true);
- if (qtype == QType::DS || qtype == QType::DNSKEY || qtype == QType::NS)
- sr.setSkipCNAMECheck(true);
- sr.beginResolve(qname, QType(qtype), 1, ret);
- d_queries += sr.d_outqueries;
- return ret;
- }
- const ResolveContext& d_ctx;
- unsigned int d_queries{0};
-};
-
bool checkDNSSECDisabled() {
return warnIfDNSSECDisabled("");
}
return false;
}
-static vState increaseDNSSECStateCounter(const vState& state)
+vState increaseDNSSECStateCounter(const vState& state)
{
g_stats.dnssecResults[state]++;
return state;
}
-
-/*
- * This inline possibly sets currentState based on the new state. It will only
- * set it to Secure iff the newState is Secure and mayUpgradeToSecure == true.
- * This should be set by the calling function when checking more than one record
- * and this is not the first record, this way, we can never go *back* to Secure
- * from an Insecure vState
- */
-static void processNewState(vState& currentState, const vState& newState, bool& hadNTA, const bool& mayUpgradeToSecure)
-{
- if (mayUpgradeToSecure && newState == Secure)
- currentState = Secure;
-
- if (newState == Insecure || newState == NTA) // We can never go back to Secure
- currentState = Insecure;
-
- if (newState == NTA)
- hadNTA = true;
-}
-
-vState validateRecords(const ResolveContext& ctx, const vector<DNSRecord>& recs)
-{
- if(recs.empty())
- return Insecure; // can't secure nothing
-
- g_stats.dnssecValidations++;
-
- cspmap_t cspmap=harvestCSPFromRecs(recs);
- LOG("Got "<<cspmap.size()<<" RRSETs: "<<endl);
- size_t numsigs=0;
- for(const auto& csp : cspmap) {
- LOG("Going to validate: "<<csp.first.first<<"/"<<DNSRecordContent::NumberToType(csp.first.second)<<": "<<csp.second.signatures.size()<<" sigs for "<<csp.second.records.size()<<" records"<<endl);
- numsigs+= csp.second.signatures.size();
- }
-
- skeyset_t keys;
- cspmap_t validrrsets;
-
- SRRecordOracle sro(ctx);
-
- vState state=Insecure;
- bool hadNTA = false;
- if(numsigs) {
- bool first = true;
- for(const auto& csp : cspmap) {
- for(const auto& sig : csp.second.signatures) {
- vState newState = getKeysFor(sro, sig->d_signer, keys); // XXX check validity here
-
- if (newState == Bogus) // No hope
- return increaseDNSSECStateCounter(Bogus);
-
- processNewState(state, newState, hadNTA, first);
-
- first = false;
-
- LOG("! state = "<<vStates[state]<<", now have "<<keys.size()<<" keys"<<endl);
- for(const auto& k : keys) {
- LOG("Key: "<<k->getZoneRepresentation()<< " {tag="<<k->getTag()<<"}"<<endl);
- }
- }
- }
- validateWithKeySet(cspmap, validrrsets, keys);
- }
- else {
- LOG("! no sigs, hoping for Insecure status of "<<recs.begin()->d_name<<endl);
-
- bool first = true;
- for(const auto& rec : recs) {
- vState newState = getKeysFor(sro, rec.d_name, keys);
-
- if (newState == Bogus) // We're done
- return increaseDNSSECStateCounter(Bogus);
-
- processNewState(state, newState, hadNTA, first);
- first = false;
-
- LOG("! state = "<<vStates[state]<<", now have "<<keys.size()<<" keys "<<endl);
-
- if (state != Insecure && state != NTA) {
- /* we had no sigs, remember? */
- return increaseDNSSECStateCounter(Bogus);
- }
- }
- return increaseDNSSECStateCounter(state);
- }
-
- LOG("Took "<<sro.d_queries<<" queries"<<endl);
- if(validrrsets.size() == cspmap.size())// shortcut - everything was ok
- return increaseDNSSECStateCounter(Secure);
-
- if(state == Insecure || keys.empty()) {
- if (hadNTA) {
- increaseDNSSECStateCounter(NTA);
- return Insecure;
- }
- return increaseDNSSECStateCounter(Insecure);
- }
-
-#if 0
- cerr<<"! validated "<<validrrsets.size()<<" RRsets out of "<<cspmap.size()<<endl;
-
- cerr<<"% validated RRs:"<<endl;
- for(auto i=validrrsets.begin(); i!=validrrsets.end(); i++) {
- cerr<<"% "<<i->first.first<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<endl;
- for(auto j=i->second.records.begin(); j!=i->second.records.end(); j++) {
- cerr<<"\t% > "<<(*j)->getZoneRepresentation()<<endl;
- }
- }
-#endif
- // cerr<<"Input to validate: "<<endl;
- for(const auto& csp : cspmap) {
- LOG(csp.first.first<<"|"<<DNSRecordContent::NumberToType(csp.first.second)<<" with "<<csp.second.signatures.size()<<" signatures"<<endl);
- if(!csp.second.signatures.empty() && !validrrsets.count(csp.first)) {
- LOG("Lacks signature, must have one, signatures: "<<csp.second.signatures.size()<<", valid rrsets: "<<validrrsets.count(csp.first)<<endl);
- return increaseDNSSECStateCounter(Bogus);
- }
- }
- return increaseDNSSECStateCounter(Insecure);
-}
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
-#include "dnsparser.hh"
#include "namespaces.hh"
#include "validate.hh"
#include "logger.hh"
-#include "resolve-context.hh"
-
-vState validateRecords(const ResolveContext& ctx, const vector<DNSRecord>& recs);
/* Off: 3.x behaviour, we do no DNSSEC, no EDNS
ProcessNoValidate: we gather DNSSEC records on all queries, but we will never validate
bool checkDNSSECDisabled();
bool warnIfDNSSECDisabled(const string& msg);
+vState increaseDNSSECStateCounter(const vState& state);