SyncRes::s_maxtotusec = 1000*7000;
SyncRes::s_maxdepth = 40;
SyncRes::s_maxnegttl = 3600;
+ SyncRes::s_maxbogusttl = 3600;
SyncRes::s_maxcachettl = 86400;
SyncRes::s_packetcachettl = 3600;
SyncRes::s_packetcacheservfailttl = 60;
return 0;
});
+ SyncRes::s_maxnegttl = 3600;
+
vector<DNSRecord> ret;
int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
- BOOST_CHECK_EQUAL(ret.size(), 1);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK_LE(ret[0].d_ttl, SyncRes::s_maxnegttl);
/* one for target1 and one for the entire TLD */
BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_REQUIRE_EQUAL(ret.size(), 1);
- BOOST_REQUIRE(ret[0].d_type == QType::A);
BOOST_CHECK_EQUAL(ret[0].d_name, target2);
+ BOOST_REQUIRE(ret[0].d_type == QType::A);
BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
char addr[] = "a.root-servers.net.";
for (char idx = 'a'; idx <= 'm'; idx++) {
addr[0] = idx;
- addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
+ addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 86400);
}
/* No RRSIG */
return 0;
});
+ SyncRes::s_maxcachettl = 86400;
+ SyncRes::s_maxbogusttl = 3600;
+
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
BOOST_REQUIRE_EQUAL(ret.size(), 13);
+ /* check that we capped the TTL to max-cache-bogus-ttl */
+ for (const auto& record : ret) {
+ BOOST_CHECK_LE(record.d_ttl, SyncRes::s_maxbogusttl);
+ }
BOOST_CHECK_EQUAL(queriesCount, 1);
}
BOOST_CHECK_EQUAL(queriesCount, 4);
}
+BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_bogus_validity) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+ primeHints();
+ const DNSName target("com.");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+ generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+ const time_t fixedNow = sr->getNow().tv_sec;
+
+ sr->setAsyncCallback([target,&queriesCount,keys,fixedNow](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
+ queriesCount++;
+
+ DNSName auth = domain;
+ auth.chopOff();
+
+ if (type == QType::DS || type == QType::DNSKEY) {
+ return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
+ }
+ else {
+ setLWResult(res, RCode::NoError, true, false, true);
+ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 86400);
+ addRRSIG(keys, res->d_records, domain, 86400);
+ addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 86400, res->d_records);
+ /* no RRSIG */
+ return 1;
+ }
+
+ return 0;
+ });
+
+ SyncRes::s_maxnegttl = 3600;
+ SyncRes::s_maxbogusttl = 360;
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 4);
+
+ /* check that the entry has not been negatively cached but not longer than s_maxbogusttl */
+ const NegCache::NegCacheEntry* ne = nullptr;
+ BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
+ BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
+ BOOST_CHECK_EQUAL(ne->d_ttd, fixedNow + SyncRes::s_maxbogusttl);
+ BOOST_CHECK_EQUAL(ne->d_validationState, Bogus);
+ BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
+ BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
+ BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
+ BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 4);
+}
+
BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
Validation is optional, and the first query does not ask for it,
so the answer is cached as Indeterminate.
The second query asks for validation, answer should be marked as
- Secure.
+ Secure, after just-in-time validation.
*/
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
else {
if (domain == target && type == QType::A) {
setLWResult(res, 0, true, false, true);
- addRecordToLW(res, target, QType::A, "192.0.2.1");
+ addRecordToLW(res, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400);
/* no RRSIG */
return 1;
}
return 0;
});
+ SyncRes::s_maxbogusttl = 3600;
+
vector<DNSRecord> ret;
/* first query does not require validation */
sr->setDNSSECValidationRequested(false);
BOOST_REQUIRE_EQUAL(ret.size(), 1);
for (const auto& record : ret) {
BOOST_CHECK(record.d_type == QType::A);
+ BOOST_CHECK_EQUAL(record.d_ttl, 86400);
}
BOOST_CHECK_EQUAL(queriesCount, 1);
res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ /* check that we correctly capped the TTD for a Bogus record after
+ just-in-time validation */
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ for (const auto& record : ret) {
+ BOOST_CHECK(record.d_type == QType::A);
+ BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
+ }
+ BOOST_CHECK_EQUAL(queriesCount, 3);
+
+ ret.clear();
+ /* third time also _does_ require validation, so we
+ can check that the cache has been updated */
+ sr->setDNSSECValidationRequested(true);
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
BOOST_REQUIRE_EQUAL(ret.size(), 1);
for (const auto& record : ret) {
BOOST_CHECK(record.d_type == QType::A);
+ BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
}
BOOST_CHECK_EQUAL(queriesCount, 3);
}
else {
if (domain == target && type == QType::A) {
setLWResult(res, 0, true, false, true);
- addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
- addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
+ addRecordToLW(res, target, QType::CNAME, cnameTarget.toString(), DNSResourceRecord::ANSWER, 86400);
+ addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400);
/* no RRSIG */
return 1;
} else if (domain == cnameTarget && type == QType::A) {
setLWResult(res, 0, true, false, true);
- addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
+ addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400);
/* no RRSIG */
return 1;
}
return 0;
});
+ SyncRes::s_maxbogusttl = 60;
+ SyncRes::s_maxnegttl = 3600;
+
vector<DNSRecord> ret;
/* first query does not require validation */
sr->setDNSSECValidationRequested(false);
BOOST_REQUIRE_EQUAL(ret.size(), 2);
for (const auto& record : ret) {
BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
+ BOOST_CHECK_EQUAL(record.d_ttl, 86400);
}
BOOST_CHECK_EQUAL(queriesCount, 2);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
BOOST_REQUIRE_EQUAL(ret.size(), 2);
+ /* check that we correctly capped the TTD for a Bogus record after
+ just-in-time validation */
+ for (const auto& record : ret) {
+ BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
+ BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
+ }
+ BOOST_CHECK_EQUAL(queriesCount, 5);
+
+ ret.clear();
+ /* and a third time to make sure that the validation status (and TTL!)
+ was properly updated in the cache */
+ sr->setDNSSECValidationRequested(true);
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 2);
for (const auto& record : ret) {
BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
+ BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
}
BOOST_CHECK_EQUAL(queriesCount, 5);
}
}
else {
setLWResult(res, RCode::NoError, true, false, true);
- addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
- addRRSIG(keys, res->d_records, domain, 300);
+ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 86400);
+ addRRSIG(keys, res->d_records, domain, 86400);
/* no denial */
return 1;
}
return 0;
});
+ SyncRes::s_maxbogusttl = 60;
+ SyncRes::s_maxnegttl = 3600;
+ const auto now = sr->getNow().tv_sec;
+
vector<DNSRecord> ret;
/* first query does not require validation */
sr->setDNSSECValidationRequested(false);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
BOOST_REQUIRE_EQUAL(ret.size(), 2);
+ for (const auto& record : ret) {
+ if (record.d_type == QType::SOA) {
+ BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxnegttl);
+ }
+ }
BOOST_CHECK_EQUAL(queriesCount, 1);
const NegCache::NegCacheEntry* ne = nullptr;
BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
+ BOOST_CHECK_EQUAL(ne->d_ttd, now + SyncRes::s_maxnegttl);
BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
BOOST_REQUIRE_EQUAL(ret.size(), 2);
+ for (const auto& record : ret) {
+ BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
+ }
+ BOOST_CHECK_EQUAL(queriesCount, 4);
+ BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
+ BOOST_CHECK_EQUAL(ne->d_validationState, Bogus);
+ BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
+ BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
+ BOOST_CHECK_EQUAL(ne->d_ttd, now + SyncRes::s_maxbogusttl);
+ BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
+ BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
+
+ ret.clear();
+ /* third one _does_ not require validation, we just check that
+ the cache (status and TTL) has been correctly updated */
+ sr->setDNSSECValidationRequested(false);
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 2);
+ for (const auto& record : ret) {
+ BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
+ }
BOOST_CHECK_EQUAL(queriesCount, 4);
BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
BOOST_CHECK_EQUAL(ne->d_validationState, Bogus);
BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
+ BOOST_CHECK_EQUAL(ne->d_ttd, now + SyncRes::s_maxbogusttl);
BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
}
SyncRes::LogMode SyncRes::s_lm;
unsigned int SyncRes::s_maxnegttl;
+unsigned int SyncRes::s_maxbogusttl;
unsigned int SyncRes::s_maxcachettl;
unsigned int SyncRes::s_maxqperq;
unsigned int SyncRes::s_maxtotusec;
return subdomain;
}
+void SyncRes::updateValidationStatusInCache(const DNSName &qname, const QType& qt, bool aa, vState newState) const
+{
+ if (newState == Bogus) {
+ t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, s_maxbogusttl + d_now.tv_sec);
+ }
+ else {
+ t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, boost::none);
+ }
+}
+
bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse)
{
string prefix;
vector<std::shared_ptr<RRSIGRecordContent>> signatures;
vector<std::shared_ptr<DNSRecord>> authorityRecs;
bool wasAuth;
+ uint32_t capTTL = std::numeric_limits<uint32_t>::max();
/* we don't require auth data for forward-recurse lookups */
if(t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
state = SyncRes::validateRecordsWithSigs(depth, qname, QType(QType::CNAME), qname, cset, signatures);
if (state != Indeterminate) {
LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates[state]<<endl);
- t_RC->updateValidationStatus(d_now.tv_sec, qname, QType(QType::CNAME), d_cacheRemote, d_requireAuthData, state);
+ if (state == Bogus) {
+ capTTL = s_maxbogusttl;
+ }
+ updateValidationStatusInCache(qname, QType(QType::CNAME), wasAuth, state);
}
}
}
LOG(prefix<<qname<<": Found cache CNAME hit for '"<< qname << "|CNAME" <<"' to '"<<j->d_content->getZoneRepresentation()<<"', validation state is "<<vStates[state]<<endl);
DNSRecord dr=*j;
- dr.d_ttl-=d_now.tv_sec;
+ dr.d_ttl -= d_now.tv_sec;
+ dr.d_ttl = std::min(dr.d_ttl, capTTL);
+ const uint32_t ttl = dr.d_ttl;
ret.reserve(ret.size() + 1 + signatures.size() + authorityRecs.size());
ret.push_back(dr);
DNSRecord sigdr;
sigdr.d_type=QType::RRSIG;
sigdr.d_name=qname;
- sigdr.d_ttl=j->d_ttl - d_now.tv_sec;
+ sigdr.d_ttl=ttl;
sigdr.d_content=signature;
sigdr.d_place=DNSResourceRecord::ANSWER;
sigdr.d_class=QClass::IN;
for(const auto& rec : authorityRecs) {
DNSRecord authDR(*rec);
- authDR.d_ttl=j->d_ttl - d_now.tv_sec;
+ authDR.d_ttl=ttl;
ret.push_back(authDR);
}
}
if (state != Indeterminate) {
/* validation succeeded, let's update the cache entry so we don't have to validate again */
- t_sstorage.negcache.updateValidationStatus(ne->d_name, ne->d_qtype, state);
+ boost::optional<uint32_t> capTTD = boost::none;
+ if (state == Bogus) {
+ capTTD = d_now.tv_sec + s_maxbogusttl;
+ }
+ t_sstorage.negcache.updateValidationStatus(ne->d_name, ne->d_qtype, state, capTTD);
}
}
if (!wasAuthZone && shouldValidate() && state == Indeterminate) {
LOG(prefix<<qname<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl);
computeNegCacheValidationStatus(ne, qname, qtype, res, state, depth);
+
+ if (state != cachedState && state == Bogus) {
+ sttl = std::min(sttl, s_maxbogusttl);
+ }
}
// Transplant SOA to the returned packet
vector<std::shared_ptr<RRSIGRecordContent>> signatures;
vector<std::shared_ptr<DNSRecord>> authorityRecs;
uint32_t ttl=0;
+ uint32_t capTTL = std::numeric_limits<uint32_t>::max();
bool wasCachedAuth;
if(t_RC->get(d_now.tv_sec, sqname, sqt, !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) {
if (cachedState != Indeterminate) {
LOG(prefix<<qname<<": got Indeterminate state from the cache, validation result is "<<vStates[cachedState]<<endl);
- t_RC->updateValidationStatus(d_now.tv_sec, sqname, sqt, d_cacheRemote, d_requireAuthData, cachedState);
+ if (cachedState == Bogus) {
+ capTTL = s_maxbogusttl;
+ }
+ updateValidationStatusInCache(sqname, sqt, wasCachedAuth, cachedState);
}
}
if(j->d_ttl>(unsigned int) d_now.tv_sec) {
DNSRecord dr=*j;
- ttl = (dr.d_ttl-=d_now.tv_sec);
+ dr.d_ttl -= d_now.tv_sec;
+ dr.d_ttl = std::min(dr.d_ttl, capTTL);
+ ttl = dr.d_ttl;
ret.push_back(dr);
LOG("[ttl="<<dr.d_ttl<<"] ");
found=true;
}
}
+ if (recordState == Bogus) {
+ /* this is a TTD by now, be careful */
+ for(auto& record : i->second.records) {
+ record.d_ttl = std::min(record.d_ttl, static_cast<uint32_t>(s_maxbogusttl + d_now.tv_sec));
+ }
+ }
+
/* We don't need to store NSEC3 records in the positive cache because:
- we don't allow direct NSEC3 queries
- denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
ne.d_qtype = QType(0); // this encodes 'whole record'
ne.d_auth = rec.d_name;
harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
- ne.d_ttd = d_now.tv_sec + lowestTTL;
if (state == Secure) {
dState denialState = getDenialValidationState(ne, state, NXDOMAIN, false);
ne.d_validationState = state;
}
+ if (ne.d_validationState == Bogus) {
+ lowestTTL = min(lowestTTL, s_maxbogusttl);
+ }
+
+ ne.d_ttd = d_now.tv_sec + lowestTTL;
/* if we get an NXDomain answer with a CNAME, let's not cache the
target, even the server was authoritative for it,
and do an additional query for the CNAME target.
LOG(prefix<<qname<<": answer is in: resolved to '"<< rec.d_content->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"'"<<endl);
done=true;
- ret.push_back(rec);
if (state == Secure && needWildcardProof) {
/* We have a positive answer synthetized from a wildcard, we need to check that we have
}
else {
LOG(d_prefix<<"Invalid denial in wildcard expanded positive response found for "<<qname<<", returning Bogus, res="<<res<<endl);
+ rec.d_ttl = std::min(rec.d_ttl, s_maxbogusttl);
}
updateValidationState(state, st);
/* we already stored the record with a different validation status, let's fix it */
- t_RC->updateValidationStatus(d_now.tv_sec, qname, qtype, d_cacheRemote, lwr.d_aabit, st);
+ updateValidationStatusInCache(qname, qtype, lwr.d_aabit, st);
}
}
+ ret.push_back(rec);
}
else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER) {
if(rec.d_type != QType::RRSIG || rec.d_name == qname)
}
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_name = qname;
ne.d_qtype = qtype;
harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
- ne.d_ttd = d_now.tv_sec + lowestTTL;
if (state == Secure) {
dState denialState = getDenialValidationState(ne, state, NXQTYPE, false);
ne.d_validationState = state;
}
+ if (ne.d_validationState == Bogus) {
+ lowestTTL = min(lowestTTL, s_maxbogusttl);
+ rec.d_ttl = min(rec.d_ttl, s_maxbogusttl);
+ }
+ ne.d_ttd = d_now.tv_sec + lowestTTL;
+
if(!wasVariable()) {
if(qtype.getCode()) { // prevents us from blacking out a whole domain
t_sstorage.negcache.add(ne);
}
}
+
+ ret.push_back(rec);
negindic=true;
}
}