g_log<<Logger::Notice<<"stats: throttle map: "
<< broadcastAccFunction<uint64_t>(pleaseGetThrottleSize) <<", ns speeds: "
- << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<endl;
+ << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<", failed ns: "
+ << broadcastAccFunction<uint64_t>(pleaseGetFailedServersSize)<<endl;
g_log<<Logger::Notice<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
g_log<<Logger::Notice<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
<<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
if(!((cleanCounter++)%40)) { // this is a full scan!
time_t limit=now.tv_sec-300;
SyncRes::pruneNSSpeeds(limit);
+ limit = now.tv_sec - SyncRes::s_serverdownthrottletime * 10;
+ SyncRes::pruneFailedServers(limit);
}
last_prune=time(0);
}
return new uint64_t(SyncRes::doDumpThrottleMap(fd));
}
+static uint64_t* pleaseDumpFailedServers(int fd)
+{
+ return new uint64_t(SyncRes::doDumpFailedServers(fd));
+}
+
template<typename T>
static string doDumpNSSpeeds(T begin, T end)
{
return "dumped "+std::to_string(total)+" records\n";
}
+template<typename T>
+static string doDumpFailedServers(T begin, T end)
+{
+ T i=begin;
+ string fname;
+
+ if(i!=end)
+ fname=*i;
+
+ int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
+ if(fd < 0)
+ return "Error opening dump file for writing: "+stringerror()+"\n";
+ uint64_t total = 0;
+ try {
+ total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDumpFailedServers, fd));
+ }
+ catch(...){}
+
+ close(fd);
+ return "dumped "+std::to_string(total)+" records\n";
+}
+
uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree)
{
return new uint64_t(t_RC->doWipeCache(canon, subtree));
return broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize);
}
+uint64_t* pleaseGetFailedServersSize()
+{
+ return new uint64_t(SyncRes::getFailedServersSize());
+}
+
uint64_t* pleaseGetConcurrentQueries()
{
return new uint64_t(getMT() ? getMT()->numProcesses() : 0);
"dump-edns [status] <filename> dump EDNS status to the named file\n"
"dump-nsspeeds <filename> dump nsspeeds statistics to the named file\n"
"dump-rpz <zone name> <filename> dump the content of a RPZ zone to the named file\n"
-"dump-throttlemap <filename> dump the contents of the throttle to the named file\n"
+"dump-throttlemap <filename> dump the contents of the throttle map to the named file\n"
+"dump-failedservers <filename> dump the failed servers to the named file\n"
"get [key1] [key2] .. get specific statistics\n"
"get-all get all statistics\n"
"get-dont-throttle-names get the list of names that are not allowed to be throttled\n"
if(cmd=="dump-nsspeeds")
return doDumpNSSpeeds(begin, end);
+ if(cmd=="dump-failedservers")
+ return doDumpFailedServers(begin, end);
+
if(cmd=="dump-rpz") {
return doDumpRPZ(begin, end);
}
return count;
}
+uint64_t SyncRes::doDumpFailedServers(int fd)
+{
+ auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
+ if(!fp)
+ return 0;
+ fprintf(fp.get(), "; failed servers dump follows\n");
+ fprintf(fp.get(), "; remote IP\tcount\ttimestamp\n");
+ uint64_t count=0;
+
+ for(const auto& i : t_sstorage.fails.getMap())
+ {
+ count++;
+ char tmp[26];
+ ctime_r(&i.second.last, tmp);
+ fprintf(fp.get(), "%s\t%lld\t%s", i.first.toString().c_str(),
+ static_cast<long long>(i.second.value), tmp);
+ }
+
+ return count;
+}
+
/* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
so that if there are RRSIGs for a name, we'll have them.
t_sstorage.nsSpeeds[nsName.empty()? DNSName(remoteIP.toStringWithPort()) : nsName].submit(remoteIP, 1000000, &d_now); // 1 sec
// code below makes sure we don't filter COM or the root
- if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP) >= s_serverdownmaxfails) {
+ if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP, d_now) >= s_serverdownmaxfails) {
LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP.toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
// mark server as down
t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0), s_serverdownthrottletime, 10000);
template<class Thing> class Counters : public boost::noncopyable
{
public:
- Counters()
- {
+ typedef unsigned long counter_t;
+ struct value_t {
+ counter_t value;
+ time_t last;
+ };
+ typedef std::map<Thing, value_t> cont_t;
+
+ cont_t getMap() const {
+ return d_cont;
}
- unsigned long value(const Thing& t) const
+ counter_t value(const Thing& t) const
{
- typename cont_t::const_iterator i=d_cont.find(t);
+ typename cont_t::const_iterator i = d_cont.find(t);
- if(i==d_cont.end()) {
+ if (i == d_cont.end()) {
return 0;
}
- return (unsigned long)i->second;
+ return i->second.value;
}
- unsigned long incr(const Thing& t)
+
+ counter_t incr(const Thing& t, const struct timeval & now)
{
- typename cont_t::iterator i=d_cont.find(t);
+ typename cont_t::iterator i = d_cont.find(t);
- if(i==d_cont.end()) {
- d_cont[t]=1;
+ if (i == d_cont.end()) {
+ d_cont[t].value = 1;
+ d_cont[t].last = now.tv_sec;
return 1;
}
else {
- if (i->second < std::numeric_limits<unsigned long>::max())
- i->second++;
- return (unsigned long)i->second;
- }
+ if (i->second.value < std::numeric_limits<counter_t>::max()) {
+ i->second.value++;
+ }
+ i->second.last = now.tv_sec;
+ return i->second.value;
+ }
}
- unsigned long decr(const Thing& t)
- {
- typename cont_t::iterator i=d_cont.find(t);
- if(i!=d_cont.end() && --i->second == 0) {
- d_cont.erase(i);
- return 0;
- } else
- return (unsigned long)i->second;
- }
void clear(const Thing& t)
{
- typename cont_t::iterator i=d_cont.find(t);
+ typename cont_t::iterator i = d_cont.find(t);
- if(i!=d_cont.end()) {
+ if (i != d_cont.end()) {
d_cont.erase(i);
}
}
+
void clear()
{
d_cont.clear();
}
+
size_t size() const
{
return d_cont.size();
}
+
+ void prune(time_t cutoff) {
+ for (auto it = d_cont.begin(); it != d_cont.end(); ) {
+ if (it->second.last <= cutoff) {
+ it = d_cont.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
private:
- typedef map<Thing,unsigned long> cont_t;
cont_t d_cont;
};
static uint64_t doEDNSDump(int fd);
static uint64_t doDumpNSSpeeds(int fd);
static uint64_t doDumpThrottleMap(int fd);
+ static uint64_t doDumpFailedServers(int fd);
static int getRootNS(struct timeval now, asyncresolve_t asyncCallback);
static void clearDelegationOnly()
{
{
t_sstorage.fails.clear();
}
+ static void pruneFailedServers(time_t cutoff)
+ {
+ t_sstorage.fails.prune(cutoff);
+ }
static unsigned long getServerFailsCount(const ComboAddress& server)
{
return t_sstorage.fails.value(server);
std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards();
uint64_t* pleaseGetNsSpeedsSize();
+uint64_t* pleaseGetFailedServersSize();
uint64_t* pleaseGetCacheSize();
uint64_t* pleaseGetNegCacheSize();
uint64_t* pleaseGetCacheHits();