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;
}
}
std::vector<std::shared_ptr<DNSRecord>> authorityRecs;
+ bool isCNAMEAnswer = false;
for(const auto& rec : lwr.d_records) {
+ if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname) {
+ isCNAMEAnswer = true;
+ }
+
if(needWildcardProof) {
if (nsecTypes.count(rec.d_type)) {
authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
continue;
+ bool isAA = lwr.d_aabit;
+ if (isAA && isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME)) {
+ /*
+ rfc2181 states:
+ Note that the answer section of an authoritative answer normally
+ contains only authoritative data. However when the name sought is an
+ alias (see section 10.1.1) only the record describing that alias is
+ necessarily authoritative. Clients should assume that other records
+ may have come from the server's cache. Where authoritative answers
+ are required, the client should query again, using the canonical name
+ associated with the alias.
+ */
+ isAA = false;
+ }
+
vState recordState = getValidationStatus(auth);
LOG(d_prefix<<": got initial zone status "<<vStates[recordState]<<" for record "<<i->first.name<<endl);
- if (validationEnabled() && recordState == Secure) {
- if (lwr.d_aabit) {
+ if (d_DNSSECValidationRequested && recordState == Secure) {
+ if (isAA) {
if (i->first.place != DNSResourceRecord::ADDITIONAL) {
/* the additional entries can be insecure,
like glue:
}
}
else {
- /* for non authoritative answer, we only care about the DS record (or lack of) */
+ /* in a non authoritative answer, we only care about the DS record (or lack of) */
if ((i->first.type == QType::DS || i->first.type == QType::NSEC || i->first.type == QType::NSEC3) && i->first.place == DNSResourceRecord::AUTHORITY) {
LOG(d_prefix<<"Validating DS record for "<<i->first.name<<endl);
recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
updateValidationState(state, recordState);
}
else {
- if (validationEnabled()) {
+ if (d_DNSSECValidationRequested) {
LOG(d_prefix<<"Skipping validation because the current state is "<<vStates[recordState]<<endl);
}
}
- t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, lwr.d_aabit, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, recordState);
+ t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, recordState);
if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
d_wasVariable=true;
rec.d_ttl = min(rec.d_ttl, s_maxnegttl);
if(newtarget.empty()) // only add a SOA if we're not going anywhere after this
ret.push_back(rec);
- if(!wasVariable()) {
- NegCache::NegCacheEntry ne;
- ne.d_ttd = d_now.tv_sec + rec.d_ttl;
- ne.d_name = qname;
- ne.d_qtype = QType(0); // this encodes 'whole record'
- ne.d_auth = rec.d_name;
- harvestNXRecords(lwr.d_records, ne);
- getDenialValidationState(ne, state, NXDOMAIN, false);
+ NegCache::NegCacheEntry ne;
+
+ ne.d_ttd = d_now.tv_sec + rec.d_ttl;
+ ne.d_name = qname;
+ ne.d_qtype = QType(0); // this encodes 'whole record'
+ ne.d_auth = rec.d_name;
+ harvestNXRecords(lwr.d_records, ne);
+ getDenialValidationState(ne, state, NXDOMAIN, false);
+
+ if(!wasVariable()) {
t_sstorage.negcache.add(ne);
if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot()) {
ne.d_name = ne.d_name.getLastLabel();
else {
rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
ret.push_back(rec);
+
+ NegCache::NegCacheEntry ne;
+ ne.d_auth = rec.d_name;
+ ne.d_ttd = d_now.tv_sec + rec.d_ttl;
+ ne.d_name = qname;
+ ne.d_qtype = qtype;
+ harvestNXRecords(lwr.d_records, ne);
+ getDenialValidationState(ne, state, NXQTYPE, qtype == QType::DS);
+
if(!wasVariable()) {
- NegCache::NegCacheEntry ne;
- ne.d_auth = rec.d_name;
- ne.d_ttd = d_now.tv_sec + rec.d_ttl;
- ne.d_name = qname;
- ne.d_qtype = qtype;
- harvestNXRecords(lwr.d_records, ne);
- getDenialValidationState(ne, state, NXQTYPE, qtype == QType::DS);
if(qtype.getCode()) { // prevents us from blacking out a whole domain
t_sstorage.negcache.add(ne);
}
if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
+ if(state == Secure && lwr.d_aabit && !negindic) {
+ updateValidationState(state, Bogus);
+ }
+
if(d_doDNSSEC)
addNXNSECS(ret, lwr.d_records);
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;