root/trunk/pdns/pdns/syncres.hh @ 1331

Revision 1331, 14.1 KB (checked in by ahu, 4 years ago)

define EDNSStatus struct & map, plus define the EDNS and EDNS-ping statistics, plus hook them up

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1#ifndef PDNS_SYNCRES_HH
2#define PDNS_SYNCRES_HH
3#include <string>
4#include "dns.hh"
5#include "qtype.hh"
6#include <vector>
7#include <set>
8#include <map>
9#include <cmath>
10#include <iostream>
11#include <utility>
12#include "misc.hh"
13#include "lwres.hh"
14#include <boost/utility.hpp>
15#include "sstuff.hh"
16#include "recursor_cache.hh"
17#include <boost/tuple/tuple.hpp>
18#include <boost/optional.hpp>
19#include <boost/tuple/tuple_comparison.hpp>
20#include "mtasker.hh"
21#include "iputils.hh"
22
23void primeHints(void);
24
25struct NegCacheEntry
26{
27  string d_name;
28  QType d_qtype;
29  string d_qname;
30  uint32_t d_ttd;
31};
32
33
34template<class Thing> class Throttle
35{
36public:
37  Throttle()
38  {
39    d_limit=3;
40    d_ttl=60;
41    d_last_clean=time(0);
42  }
43  bool shouldThrottle(time_t now, const Thing& t)
44  {
45    if(now > d_last_clean + 300 ) {
46      d_last_clean=now;
47      for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) {
48        if( i->second.ttd < now) {
49          d_cont.erase(i++);
50        }
51        else
52          ++i;
53      }
54    }
55
56    typename cont_t::iterator i=d_cont.find(t);
57    if(i==d_cont.end())
58      return false;
59    if(now > i->second.ttd || i->second.count-- < 0) {
60      d_cont.erase(i);
61    }
62
63    return true; // still listed, still blocked
64  }
65  void throttle(time_t now, const Thing& t, unsigned int ttl=0, unsigned int tries=0) 
66  {
67    typename cont_t::iterator i=d_cont.find(t);
68    entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit};
69
70    if(i==d_cont.end()) {
71      d_cont[t]=e;
72    } 
73    else if(i->second.ttd > e.ttd || (i->second.count) < e.count) 
74      d_cont[t]=e;
75  }
76 
77  unsigned int size()
78  {
79    return (unsigned int)d_cont.size();
80  }
81private:
82  int d_limit;
83  int d_ttl;
84  time_t d_last_clean;
85  struct entry
86  {
87    time_t ttd;
88    int count;
89  };
90  typedef map<Thing,entry> cont_t;
91  cont_t d_cont;
92};
93
94
95/** Class that implements a decaying EWMA.
96    This class keeps an exponentially weighted moving average which, additionally, decays over time.
97    The decaying is only done on get.
98*/
99class DecayingEwma
100{
101public:
102  DecayingEwma() :  d_val(0.0) 
103  {
104    d_needinit=true;
105    d_last.tv_sec = d_last.tv_usec = 0;
106    d_lastget=d_last;
107  }
108
109  DecayingEwma(const DecayingEwma& orig) : d_last(orig.d_last),  d_lastget(orig.d_lastget), d_val(orig.d_val), d_needinit(orig.d_needinit)
110  {
111  }
112
113  struct timeval getOrMakeTime(struct timeval* tv)
114  {
115    if(tv)
116      return *tv;
117    else {
118      struct timeval ret;
119      Utility::gettimeofday(&ret, 0);
120      return ret;
121    }
122  }
123
124  void submit(int val, struct timeval* tv)
125  {
126    struct timeval now=getOrMakeTime(tv);
127
128    if(d_needinit) {
129      d_last=now;
130      d_needinit=false;
131    }
132
133    float diff= makeFloat(d_last - now);
134
135    d_last=now;
136    double factor=exp(diff)/2.0; // might be '0.5', or 0.0001
137    d_val=(float)((1-factor)*val+ (float)factor*d_val); 
138  }
139
140  double get(struct timeval* tv)
141  {
142    struct timeval now=getOrMakeTime(tv);
143    float diff=makeFloat(d_lastget-now);
144    d_lastget=now;
145    float factor=exp(diff/60.0f); // is 1.0 or less
146    return d_val*=factor;
147  }
148
149  bool stale(time_t limit) const
150  {
151    return limit > d_lastget.tv_sec;
152  }
153
154private:
155  struct timeval d_last;          // stores time
156  struct timeval d_lastget;       // stores time
157  float d_val;
158  bool d_needinit;
159};
160
161
162class PulseRate
163{
164public:
165  PulseRate() :  d_val(0.0) 
166  {
167    Utility::gettimeofday(&d_last, 0);
168  }
169
170  PulseRate(const PulseRate& orig) : d_last(orig.d_last), d_val(orig.d_val)
171  {
172  }
173
174  void pulse(const struct timeval& now)
175  {
176    //    cout<<"about to submit: "<< 1000.0*makeFloat(now - d_last)<<"\n";
177    submit((int)(1000.0*(makeFloat(now-d_last))), now);
178  }
179
180  optional<float> get(struct timeval& now, unsigned int limit) const
181  {
182    optional<float> ret;
183    float diff=makeFloat(now - d_last);
184    if(diff < limit)
185      ret=d_val;
186    return ret;
187  }
188
189  bool stale(time_t limit) const
190  {
191    return limit > d_last.tv_sec;
192  }
193
194private:
195  void submit(int val, const struct timeval& now)
196  {
197    float diff= makeFloat(d_last - now);
198
199    d_last=now;
200    double factor=exp(diff/2.0)/2.0; // might be '0.5', or 0.0001
201    d_val=(float)((1-factor)*val+ (float)factor*d_val); 
202  }
203
204  PulseRate& operator=(const PulseRate&);
205  struct timeval d_last;          // stores time
206  float d_val;
207};
208
209
210class SyncRes
211{
212public:
213  explicit SyncRes(const struct timeval& now) :  d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
214                                                 d_now(now),
215                                                 d_cacheonly(false), d_nocache(false), d_doEDNS0(false) { }
216  int beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector<DNSResourceRecord>&ret);
217  void setId(int id)
218  {
219    if(s_log)
220      d_prefix="["+itoa(id)+"] ";
221  }
222  static void setLog(bool log)
223  {
224    s_log=log;
225  }
226  void setCacheOnly(bool state=true)
227  {
228    d_cacheonly=state;
229  }
230  void setNoCache(bool state=true)
231  {
232    d_nocache=state;
233  }
234
235  void setDoEDNS0(bool state=true)
236  {
237    d_doEDNS0=state;
238  }
239
240  int asyncresolveWrapper(const ComboAddress& ip, const string& domain, int type, bool doTCP, struct timeval* now, LWResult* res);
241
242  static unsigned int s_queries;
243  static unsigned int s_outgoingtimeouts;
244  static unsigned int s_throttledqueries;
245  static unsigned int s_outqueries;
246  static unsigned int s_tcpoutqueries;
247  static unsigned int s_nodelegated;
248  static unsigned int s_unreachables;
249  static bool s_doIPv6;
250  unsigned int d_outqueries;
251  unsigned int d_tcpoutqueries;
252  unsigned int d_throttledqueries;
253  unsigned int d_timeouts;
254  unsigned int d_unreachables;
255
256  //  typedef map<string,NegCacheEntry> negcache_t;
257
258  typedef multi_index_container <
259    NegCacheEntry,
260    indexed_by <
261       ordered_unique<
262           composite_key<
263                 NegCacheEntry,
264                    member<NegCacheEntry, string, &NegCacheEntry::d_name>,
265                    member<NegCacheEntry, QType, &NegCacheEntry::d_qtype>
266           >,
267           composite_key_compare<CIStringCompare, std::less<QType> >
268       >,
269       ordered_non_unique<
270           member<NegCacheEntry, uint32_t, &NegCacheEntry::d_ttd>
271       >
272    >
273  >negcache_t;
274  static negcache_t s_negcache;   
275
276  //! This represents a number of decaying Ewmas, used to store performance per namerserver-name.
277  /** Modelled to work mostly like the underlying DecayingEwma. After you've called get,
278      d_best is filled out with the best address for this collection */
279  struct DecayingEwmaCollection
280  {
281    void submit(const ComboAddress& remote, int usecs, struct timeval* now) 
282    {
283      collection_t::iterator pos;
284      for(pos=d_collection.begin(); pos != d_collection.end(); ++pos)
285        if(pos->first==remote)
286          break;
287      if(pos!=d_collection.end()) {
288        pos->second.submit(usecs, now);
289      }
290      else {
291        DecayingEwma de;
292        de.submit(usecs, now);
293        d_collection.push_back(make_pair(remote, de));
294      }
295    }
296
297    double get(struct timeval* now)
298    {
299      if(d_collection.empty())
300        return 0;
301      double ret=numeric_limits<double>::max();
302      double tmp;
303      for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) {
304        if((tmp=pos->second.get(now)) < ret) {
305          ret=tmp;
306          d_best=pos->first;
307        }
308      }
309     
310      return ret;
311    }
312   
313    bool stale(time_t limit) const
314    {
315      for(collection_t::const_iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) 
316        if(!pos->second.stale(limit))
317          return false;
318      return true;
319    }
320
321    typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
322    collection_t d_collection;
323    ComboAddress d_best;
324  };
325
326  typedef map<string, DecayingEwmaCollection, CIStringCompare> nsspeeds_t;
327  static nsspeeds_t s_nsSpeeds;
328
329  struct EDNSStatus
330  {
331    EDNSStatus() : mode(UNKNOWN), modeSetAt(0), EDNSPingHitCount(0) {}
332    enum EDNSMode { CONFIRMEDPINGER=-1, UNKNOWN=0, EDNSNOPING=1, EDNSPINGOK=2, EDNSIGNORANT=3, NOEDNS=4 } mode;
333    time_t modeSetAt;
334    int EDNSPingHitCount;
335  };
336
337  typedef map<ComboAddress, EDNSStatus> ednsstatus_t;
338  static ednsstatus_t s_ednsstatus;
339
340  struct AuthDomain
341  {
342    vector<ComboAddress> d_servers;
343    typedef multi_index_container <
344      DNSResourceRecord,
345      indexed_by < 
346        ordered_non_unique< 
347          composite_key< DNSResourceRecord,
348                         member<DNSResourceRecord, string, &DNSResourceRecord::qname>,
349                         member<DNSResourceRecord, QType, &DNSResourceRecord::qtype>
350                       >,
351          composite_key_compare<CIStringCompare, std::less<QType> >
352        >
353      >
354    > records_t;
355    records_t d_records;       
356  };
357 
358
359  typedef map<string, AuthDomain, CIStringCompare> domainmap_t;
360  static domainmap_t s_domainmap;
361
362  typedef Throttle<tuple<ComboAddress,string,uint16_t> > throttle_t;
363  static throttle_t s_throttle;
364  struct timeval d_now;
365  static unsigned int s_maxnegttl;
366  static string s_serverID;
367private:
368  struct GetBestNSAnswer;
369  int doResolveAt(set<string, CIStringCompare> nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,
370                  int depth, set<GetBestNSAnswer>&beenthere);
371  int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere);
372  bool doOOBResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
373  domainmap_t::const_iterator getBestAuthZone(string* qname);
374  bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
375  bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
376  void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, bool* flawedNSSet, int depth, set<GetBestNSAnswer>& beenthere);
377  void addCruft(const string &qname, vector<DNSResourceRecord>& ret);
378  string getBestNSNamesFromCache(const string &qname,set<string, CIStringCompare>& nsset, bool* flawedNSSet, int depth, set<GetBestNSAnswer>&beenthere);
379  void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth);
380
381  inline vector<string> shuffleInSpeedOrder(set<string, CIStringCompare> &nameservers, const string &prefix);
382  bool moreSpecificThan(const string& a, const string &b);
383  vector<ComboAddress> getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere);
384
385  SyncRes(const SyncRes&);
386  SyncRes& operator=(const SyncRes&);
387
388
389private:
390  string d_prefix;
391  static bool s_log;
392  bool d_cacheonly;
393  bool d_nocache;
394  bool d_doEDNS0;
395
396  struct GetBestNSAnswer
397  {
398    string qname;
399    set<DNSResourceRecord> bestns;
400    bool operator<(const GetBestNSAnswer &b) const
401    {
402      if(qname<b.qname)
403        return true;
404      if(qname==b.qname)
405        return bestns<b.bestns;
406      return false;
407    }
408  };
409
410};
411class Socket;
412/* external functions, opaque to us */
413int asendtcp(const string& data, Socket* sock);
414int arecvtcp(string& data, int len, Socket* sock);
415
416
417struct PacketID
418{
419  PacketID() : id(0), type(0), sock(0), inNeeded(0), outPos(0), nearMisses(0), fd(-1)
420  {
421    memset(&remote, 0, sizeof(remote));
422  }
423
424  uint16_t id;  // wait for a specific id/remote pair
425  ComboAddress remote;  // this is the remote
426  string domain;             // this is the question
427  uint16_t type;             // and this is its type
428
429  Socket* sock;  // or wait for an event on a TCP fd
430  int inNeeded; // if this is set, we'll read until inNeeded bytes are read
431  string inMSG; // they'll go here
432
433  string outMSG; // the outgoing message that needs to be sent
434  string::size_type outPos;    // how far we are along in the outMSG
435
436  mutable uint32_t nearMisses; // number of near misses - host correct, id wrong
437  typedef set<uint16_t > chain_t;
438  mutable chain_t chain;
439  int fd;
440
441  bool operator<(const PacketID& b) const
442  {
443    int ourSock= sock ? sock->getHandle() : 0;
444    int bSock = b.sock ? b.sock->getHandle() : 0;
445    if( tie(remote, ourSock, type) < tie(b.remote, bSock, b.type))
446      return true;
447    if( tie(remote, ourSock, type) > tie(b.remote, bSock, b.type))
448      return false;
449
450    int cmp=Utility::strcasecmp(domain.c_str(), b.domain.c_str());
451    if(cmp < 0)
452      return true;
453    if(cmp > 0)
454      return false;
455
456    return tie(fd, id) < tie(b.fd, b.id);
457  }
458};
459
460struct PacketIDBirthdayCompare: public binary_function<PacketID, PacketID, bool> 
461{
462  bool operator()(const PacketID& a, const PacketID& b) const
463  {
464    int ourSock= a.sock ? a.sock->getHandle() : 0;
465    int bSock = b.sock ? b.sock->getHandle() : 0;
466    if( tie(a.remote, ourSock, a.type) < tie(b.remote, bSock, b.type))
467      return true;
468    if( tie(a.remote, ourSock, a.type) > tie(b.remote, bSock, b.type))
469      return false;
470
471    int cmp=Utility::strcasecmp(a.domain.c_str(), b.domain.c_str());
472    return cmp < 0;
473  }
474};
475extern MemRecursorCache RC;
476typedef MTasker<PacketID,string> MT_t;
477extern MT_t* MT;
478
479struct RecursorStats
480{
481  uint64_t servFails;
482  uint64_t nxDomains;
483  uint64_t noErrors;
484  PulseRate queryrate;
485  uint64_t answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow;
486  uint64_t avgLatencyUsec;
487  uint64_t qcounter;
488  uint64_t tcpqcounter;
489  uint64_t unauthorizedUDP;
490  uint64_t unauthorizedTCP;
491  uint64_t tcpClientOverflow;
492  uint64_t clientParseError;
493  uint64_t serverParseError;
494  uint64_t unexpectedCount;
495  uint64_t caseMismatchCount;
496  uint64_t spoofCount;
497  uint64_t resourceLimits;
498  uint64_t ipv6queries;
499  uint64_t chainResends;
500  uint64_t nsSetInvalidations;
501  uint64_t shunted;
502  uint64_t noShuntCNAME, noShuntExpired, noShuntSize, noShuntNoMatch, noShuntWrongType, noShuntWrongQuestion;
503  uint64_t ednsPingMatches;
504  uint64_t ednsPingMismatches;
505  uint64_t noPingOutQueries, noEdnsOutQueries;
506  time_t startupTime;
507
508  typedef vector<ComboAddress> remotes_t;
509  remotes_t remotes;
510  int d_remotepos;
511  void addRemote(const ComboAddress& remote)
512  {
513    if(!remotes.size())
514      return;
515
516    remotes[(d_remotepos++) % remotes.size()]=remote;
517  }
518};
519
520string doReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end);
521
522extern RecursorStats g_stats;
523
524
525template<typename Index>
526std::pair<typename Index::iterator,bool>
527replacing_insert(Index& i,const typename Index::value_type& x)
528{
529  std::pair<typename Index::iterator,bool> res=i.insert(x);
530  if(!res.second)res.second=i.replace(res.first,x);
531  return res;
532}
533
534
535std::string reloadAuthAndForwards();
536#endif
Note: See TracBrowser for help on using the browser.