BOOST_CHECK_EQUAL(ret.size(), 1);
}
-BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_oob) {
+BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
std::unique_ptr<SyncRes> sr;
- init();
- initSR(sr, true, false);
+ initSR(sr, true);
primeHints();
size_t queriesCount = 0;
const DNSName target("test.xx.");
const ComboAddress targetAddr("127.0.0.1");
- const DNSName ns("localhost.");
- const ComboAddress nsAddr("127.0.0.1");
const DNSName authZone("test.xx");
SyncRes::AuthDomain ad;
DNSRecord dr;
- dr.d_place = DNSResourceRecord::ANSWER;
- dr.d_name = authZone;
- dr.d_type = QType::NS;
- dr.d_ttl = 1800;
- dr.d_content = std::make_shared<NSRecordContent>("localhost.");
- ad.d_records.insert(dr);
dr.d_place = DNSResourceRecord::ANSWER;
- dr.d_name = authZone;
+ dr.d_name = target;
dr.d_type = QType::A;
dr.d_ttl = 1800;
- dr.d_content = std::make_shared<ARecordContent>(nsAddr);
+ dr.d_content = std::make_shared<ARecordContent>(targetAddr);
ad.d_records.insert(dr);
(*SyncRes::t_sstorage.domainmap)[authZone] = ad;
- sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ sr->setAsyncCallback([&queriesCount](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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
queriesCount++;
return 0;
});
BOOST_CHECK(ret[0].d_type == QType::A);
BOOST_CHECK_EQUAL(queriesCount, 0);
BOOST_CHECK(sr->wasOutOfBand());
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
/* a second time, to check that the OOB flag is set when the query cache is used */
ret.clear();
BOOST_CHECK(ret[0].d_type == QType::A);
BOOST_CHECK_EQUAL(queriesCount, 0);
BOOST_CHECK(sr->wasOutOfBand());
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
+
+ /* a third time, to check that the validation is disabled when the OOB flag is set */
+ ret.clear();
+ sr->setDNSSECValidationRequested(true);
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::A);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+ BOOST_CHECK(sr->wasOutOfBand());
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("cname.test.xx.");
+ const DNSName targetCname("cname-target.test.xx.");
+ const ComboAddress targetCnameAddr("127.0.0.1");
+ const DNSName authZone("test.xx");
+
+ SyncRes::AuthDomain ad;
+ DNSRecord dr;
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::CNAME;
+ dr.d_ttl = 1800;
+ dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = targetCname;
+ dr.d_type = QType::A;
+ dr.d_ttl = 1800;
+ dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
+ ad.d_records.insert(dr);
+
+ (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
+
+ sr->setAsyncCallback([&queriesCount](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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 2);
+ BOOST_CHECK(ret[0].d_type == QType::CNAME);
+ BOOST_CHECK(ret[1].d_type == QType::A);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+ BOOST_CHECK(sr->wasOutOfBand());
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
+
+ /* a second time, to check that the OOB flag is set when the query cache is used */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 2);
+ BOOST_CHECK(ret[0].d_type == QType::CNAME);
+ BOOST_CHECK(ret[1].d_type == QType::A);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+ BOOST_CHECK(sr->wasOutOfBand());
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
+
+ /* a third time, to check that the validation is disabled when the OOB flag is set */
+ ret.clear();
+ sr->setDNSSECValidationRequested(true);
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 2);
+ BOOST_CHECK(ret[0].d_type == QType::CNAME);
+ BOOST_CHECK(ret[1].d_type == QType::A);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+ BOOST_CHECK(sr->wasOutOfBand());
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
}
BOOST_AUTO_TEST_CASE(test_auth_zone) {
BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
std::unique_ptr<SyncRes> sr;
- initSR(sr);
+ initSR(sr, true, false);
primeHints();
(*map)[authZone] = ad;
SyncRes::setDomainMap(map);
- sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr](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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ testkeysset_t keys;
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
+ g_luaconfs.setState(luaconfsCopy);
+
+ sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr,authZone,keys](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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
queriesCount++;
+ if (type == QType::DS || type == QType::DNSKEY) {
+ return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
+ }
+
if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
setLWResult(res, 0, true, false, true);
addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
return 0;
});
+ sr->setDNSSECValidationRequested(true);
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_REQUIRE_EQUAL(ret.size(), 1);
BOOST_CHECK(ret[0].d_type == QType::A);
- BOOST_CHECK_EQUAL(queriesCount, 1);
+ BOOST_CHECK_EQUAL(queriesCount, 4);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
}
BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
if (d_queryValidationState != Indeterminate) {
g_stats.dnssecValidations++;
}
- if (d_DNSSECValidationRequested) {
+ if (shouldValidate()) {
increaseDNSSECStateCounter(d_queryValidationState);
}
}
}
- if(!d_skipCNAMECheck && doCNAMECacheCheck(qname,qtype,ret,depth,res,state)) // will reroute us if needed
+ DNSName authname(qname);
+ bool wasForwardedOrAuthZone = false;
+ bool wasAuthZone = false;
+ domainmap_t::const_iterator iter = getBestAuthZone(&authname);
+ if(iter != t_sstorage.domainmap->end()) {
+ wasForwardedOrAuthZone = true;
+ const vector<ComboAddress>& servers = iter->second.d_servers;
+ if(servers.empty()) {
+ wasAuthZone = true;
+ }
+ }
+
+ if(!d_skipCNAMECheck && doCNAMECacheCheck(qname, qtype, ret, depth, res, state, wasAuthZone)) { // will reroute us if needed
+ d_wasOutOfBand = wasAuthZone;
return res;
+ }
- if(doCacheCheck(qname,qtype,ret,depth,res,state)) // we done
+ if(doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, qtype, ret, depth, res, state)) {
+ // we done
+ d_wasOutOfBand = wasAuthZone;
return res;
+ }
}
if(d_cacheonly)
return subdomain;
}
-bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state)
+bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone)
{
string prefix;
if(doLog()) {
for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
if(j->d_ttl>(unsigned int) d_now.tv_sec) {
- if (d_DNSSECValidationRequested && wasAuth && state == Indeterminate && d_requireAuthData) {
+ if (!wasAuthZone && shouldValidate() && 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 */
}
}
-bool SyncRes::doCacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state)
+bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state)
{
bool giveNegative=false;
QType sqt(qtype);
uint32_t sttl=0;
// cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
-
- DNSName authname(qname);
vState cachedState;
- bool wasForwardedOrAuth = false;
- bool wasAuth = false;
- domainmap_t::const_iterator iter=getBestAuthZone(&authname);
- if(iter != t_sstorage.domainmap->end()) {
- wasForwardedOrAuth = true;
- const vector<ComboAddress>& servers = iter->second.d_servers;
- if(servers.empty()) {
- wasAuth = true;
- }
- }
NegCache::NegCacheEntry ne;
if(s_rootNXTrust &&
t_sstorage.negcache.getRootNXTrust(qname, d_now, ne) &&
ne.d_auth.isRoot() &&
- !(wasForwardedOrAuth && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
+ !(wasForwardedOrAuthZone && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
sttl = ne.d_ttd - d_now.tv_sec;
LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne.d_auth<<"' & '"<<ne.d_name<<"' for another "<<sttl<<" seconds"<<endl);
res = RCode::NXDomain;
cachedState = ne.d_validationState;
}
else if (t_sstorage.negcache.get(qname, qtype, d_now, ne) &&
- !(wasForwardedOrAuth && ne.d_auth != authname)) { // Only the authname nameserver can neg cache entries
+ !(wasForwardedOrAuthZone && ne.d_auth != authname)) { // Only the authname nameserver can neg cache entries
/* If we are looking for a DS, discard NXD if auth == qname
and ask for a specific denial instead */
state = cachedState;
- if (d_DNSSECValidationRequested && state == Indeterminate) {
+ 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);
}
LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
- if (d_DNSSECValidationRequested && wasCachedAuth && cachedState == Indeterminate && d_requireAuthData) {
+ if (!wasAuthZone && shouldValidate() && 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. */
if(found && !expired) {
if (!giveNegative)
res=0;
- d_wasOutOfBand = wasAuth;
LOG(prefix<<qname<<": updating validation state with cache content for "<<qname<<" to "<<vStates[cachedState]<<endl);
state = cachedState;
return true;
bool SyncRes::haveExactValidationStatus(const DNSName& domain)
{
- if (!d_DNSSECValidationRequested) {
+ if (!shouldValidate()) {
return false;
}
const auto& it = d_cutStates.find(domain);
{
vState result = Indeterminate;
- if (!d_DNSSECValidationRequested) {
+ if (!shouldValidate()) {
return result;
}
DNSName name(subdomain);
LOG(d_prefix<<": setting cut state for "<<end<<" to "<<vStates[cutState]<<endl);
d_cutStates[end] = cutState;
- if (!d_DNSSECValidationRequested) {
+ if (!shouldValidate()) {
return;
}
vState recordState = getValidationStatus(i->first.name, false);
LOG(d_prefix<<": got initial zone status "<<vStates[recordState]<<" for record "<<i->first.name<<endl);
- if (d_DNSSECValidationRequested && recordState == Secure) {
+ if (shouldValidate() && recordState == Secure) {
vState initialState = recordState;
if (isAA) {
}
}
else {
- if (d_DNSSECValidationRequested) {
+ if (shouldValidate()) {
LOG(d_prefix<<"Skipping validation because the current state is "<<vStates[recordState]<<endl);
}
}
if(tns->empty() && !wasForwarded) {
LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
- state = Insecure;
+ /* setting state to indeterminate since validation is disabled for local auth zone,
+ and Insecure would be misleading. */
+ state = Indeterminate;
d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
lwr.d_tcbit=false;
lwr.d_aabit=true;
return d_DNSSECValidationRequested;
}
+ bool shouldValidate() const
+ {
+ return d_DNSSECValidationRequested && !d_wasOutOfBand;
+ }
+
void setWantsRPZ(bool state=true)
{
d_wantsRPZ=state;
bool doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res) const;
bool doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res);
domainmap_t::const_iterator getBestAuthZone(DNSName* qname) const;
- bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state);
- bool doCacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state);
+ bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state, bool wasAuthZone);
+ bool doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state);
void getBestNSFromCache(const DNSName &qname, const QType &qtype, vector<DNSRecord>&bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere);
DNSName getBestNSNamesFromCache(const DNSName &qname, const QType &qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere);