SyncRes::clearECSStats();
SyncRes::s_ecsipv4cachelimit = ::arg().asNum("ecs-ipv4-cache-bits");
SyncRes::s_ecsipv6cachelimit = ::arg().asNum("ecs-ipv6-cache-bits");
+ SyncRes::s_ecscachelimitttl = ::arg().asNum("ecs-cache-limit-ttl");
if (!::arg().isEmpty("ecs-scope-zero-address")) {
ComboAddress scopeZero(::arg()["ecs-scope-zero-address"]);
::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
::arg().set("ecs-ipv6-cache-bits", "Maximum number of bits of IPv6 mask to cache ECS response")="56";
::arg().set("ecs-minimum-ttl-override", "Set under adverse conditions, a minimum TTL for records in ECS-specific answers")="0";
+ ::arg().set("ecs-cache-limit-ttl", "Minimum TTL to cache ECS response")="0";
+ ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
::arg().set("ecs-add-for", "List of client netmasks for which EDNS Client Subnet will be added")="0.0.0.0/0, ::/0, " LOCAL_NETS_INVERSE;
::arg().set("ecs-scope-zero-address", "Address to send to whitelisted authoritative servers for incoming queries with ECS prefix-length source of 0")="";
return -1;
}
-void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask, vState state)
+void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask, time_t minTTD, vState state)
{
d_cachecachevalid = false;
// cerr<<"Replacing "<<qname<<" for "<< (ednsmask ? ednsmask->toString() : "everyone") << endl;
for(const auto i : content) {
/* Yes, we have altered the d_ttl value by adding time(nullptr) to it
prior to calling this function, so the TTL actually holds a TTD. */
- ce.d_ttd=min(maxTTD, static_cast<time_t>(i.d_ttl)); // XXX this does weird things if TTLs differ in the set
- // cerr<<"To store: "<<i.d_content->getZoneRepresentation()<<" with ttl/ttd "<<i.d_ttl<<", capped at: "<<maxTTD<<endl;
- ce.d_records.push_back(i.d_content);
+ if (minTTD == 0 || static_cast<time_t>(i.d_ttl) >= minTTD) {
+ ce.d_ttd = min(maxTTD, static_cast<time_t>(i.d_ttl)); // XXX this does weird things if TTLs differ in the set
+ // cerr<<"To store: "<<i.d_content->getZoneRepresentation()<<" with ttl/ttd "<<i.d_ttl<<", capped at: "<<maxTTD<<endl;
+ ce.d_records.push_back(i.d_content);
+ }
}
if (!isNew) {
int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, vector<std::shared_ptr<RRSIGRecordContent>>* signatures=nullptr, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr);
- void replace(time_t, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask=boost::none, vState state=Indeterminate);
+ void replace(time_t, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask=boost::none, time_t minTTD = 0, vState state=Indeterminate);
void doPrune(unsigned int keep);
uint64_t doDump(int fd);
uint8_t SyncRes::s_ecsipv6limit;
uint8_t SyncRes::s_ecsipv4cachelimit;
uint8_t SyncRes::s_ecsipv6cachelimit;
+unsigned int SyncRes::s_ecscachelimitttl;
+
bool SyncRes::s_doIPv6;
bool SyncRes::s_nopacketcache;
bool SyncRes::s_rootNXTrust;
SyncRes::SyncRes(const struct timeval& now) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
d_totUsec(0), d_now(now),
d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm)
-
-{
+
+{
}
/** everything begins here - this is the entry point just after receiving a packet */
Another cause of "No answer" may simply be a network condition.
Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
- Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
+ Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
- clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
- elsewhere. It may not have happened yet.
+ clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
+ elsewhere. It may not have happened yet.
For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
*/
the goal is to get as many remotes as possible on the highest level of EDNS support
The levels are:
- 0) UNKNOWN Unknown state
+ 0) UNKNOWN Unknown state
1) EDNS: Honors EDNS0
2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
3) NOEDNS: Generates FORMERR on EDNS queries
Everybody starts out assumed to be '0'.
If '0', send out EDNS0
- If you FORMERR us, go to '3',
+ If you FORMERR us, go to '3',
If no EDNS in response, go to '2'
If '1', send out EDNS0
If FORMERR, downgrade to 3
If '2', keep on including EDNS0, see what happens
- Same behaviour as 0
+ Same behaviour as 0
If '3', send bare queries
*/
int ret;
for(int tries = 0; tries < 3; ++tries) {
// cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
-
+
if(mode==EDNSStatus::NOEDNS) {
g_stats.noEdnsOutQueries++;
EDNSLevel = 0; // level != mode
mode = EDNSStatus::EDNSOK;
// cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
}
-
+
}
if(oldmode != mode || !ednsstatus->modeSetAt)
ednsstatus->modeSetAt=d_now.tv_sec;
- // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
+ // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
return ret;
}
return ret;
DNSRecord dr;
dr.d_type=QType::RRSIG;
dr.d_name=sqname;
- dr.d_ttl=ttl;
+ dr.d_ttl=ttl;
dr.d_content=signature;
dr.d_place = DNSResourceRecord::ANSWER;
dr.d_class=QClass::IN;
!ednsmask ||
(ednsmask->isIpv4() && ednsmask->getBits() <= SyncRes::s_ecsipv4cachelimit) ||
(ednsmask->isIpv6() && ednsmask->getBits() <= SyncRes::s_ecsipv6cachelimit)) {
- t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, recordState);
+ time_t minTTD = 0;
+ if (ednsmask && SyncRes::s_ecscachelimitttl > 0) {
+ minTTD = SyncRes::s_ecscachelimitttl + d_now.tv_sec;
+ }
+ t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, minTTD, recordState);
}
}
g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got an exception"<<endl;
ret.clear();
}
-
+
return res;
}