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