]>
Commit | Line | Data |
---|---|---|
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" |
1d5b3ce6 | 17 | #include <boost/tuple/tuple.hpp> |
71dea98d | 18 | #include <boost/optional.hpp> |
1d5b3ce6 BH |
19 | #include <boost/tuple/tuple_comparison.hpp> |
20 | #include "mtasker.hh" | |
a9af3782 | 21 | #include "iputils.hh" |
eefd15f9 | 22 | |
bdf40704 | 23 | void primeHints(void); |
00a19ff7 | 24 | |
38e22b5a BH |
25 | struct NegCacheEntry |
26 | { | |
f4df5e89 | 27 | string d_name; |
be718669 | 28 | QType d_qtype; |
33988bfb | 29 | string d_qname; |
33988bfb | 30 | uint32_t d_ttd; |
38e22b5a | 31 | }; |
00a19ff7 | 32 | |
49f076e8 BH |
33 | |
34 | template<class Thing> class Throttle | |
35 | { | |
36 | public: | |
37 | Throttle() | |
38 | { | |
39 | d_limit=3; | |
40 | d_ttl=60; | |
41 | d_last_clean=time(0); | |
42 | } | |
87da00e7 | 43 | bool shouldThrottle(time_t now, const Thing& t) |
49f076e8 | 44 | { |
cd7bf56b | 45 | if(now > d_last_clean + 300 ) { |
49f076e8 | 46 | d_last_clean=now; |
594c2ee7 BH |
47 | for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) { |
48 | if( i->second.ttd < now) { | |
49f076e8 BH |
49 | d_cont.erase(i++); |
50 | } | |
51 | else | |
52 | ++i; | |
594c2ee7 | 53 | } |
49f076e8 BH |
54 | } |
55 | ||
49f076e8 BH |
56 | typename cont_t::iterator i=d_cont.find(t); |
57 | if(i==d_cont.end()) | |
58 | return false; | |
014c60c3 | 59 | if(now > i->second.ttd || i->second.count-- < 0) { |
49f076e8 | 60 | d_cont.erase(i); |
49f076e8 | 61 | } |
014c60c3 BH |
62 | |
63 | return true; // still listed, still blocked | |
49f076e8 | 64 | } |
87da00e7 | 65 | void throttle(time_t now, const Thing& t, unsigned int ttl=0, unsigned int tries=0) |
49f076e8 BH |
66 | { |
67 | typename cont_t::iterator i=d_cont.find(t); | |
87da00e7 | 68 | entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit}; |
49f076e8 | 69 | |
c214232f | 70 | if(i==d_cont.end()) { |
49f076e8 | 71 | d_cont[t]=e; |
c214232f BH |
72 | } |
73 | else if(i->second.ttd > e.ttd || (i->second.count) < e.count) | |
74 | d_cont[t]=e; | |
8a5602d4 BH |
75 | } |
76 | ||
77 | unsigned int size() | |
78 | { | |
705f31ae | 79 | return (unsigned int)d_cont.size(); |
49f076e8 BH |
80 | } |
81 | private: | |
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 | ||
eefd15f9 | 95 | /** Class that implements a decaying EWMA. |
36c5ee42 | 96 | This class keeps an exponentially weighted moving average which, additionally, decays over time. |
eefd15f9 BH |
97 | The decaying is only done on get. |
98 | */ | |
99 | class DecayingEwma | |
100 | { | |
101 | public: | |
71dea98d BH |
102 | DecayingEwma() : d_val(0.0) |
103 | { | |
104 | d_needinit=true; | |
105 | d_lastget=d_last; | |
36c5ee42 | 106 | } |
d6d5dea7 | 107 | |
71dea98d | 108 | 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 | 109 | { |
71dea98d | 110 | } |
d6d5dea7 | 111 | |
71dea98d BH |
112 | struct timeval getOrMakeTime(struct timeval* tv) |
113 | { | |
114 | if(tv) | |
115 | return *tv; | |
116 | else { | |
117 | struct timeval ret; | |
f2b6ccd6 | 118 | Utility::gettimeofday(&ret, 0); |
71dea98d BH |
119 | return ret; |
120 | } | |
d6d5dea7 BH |
121 | } |
122 | ||
123 | void submit(int val, struct timeval*tv = 0) | |
124 | { | |
71dea98d BH |
125 | struct timeval now=getOrMakeTime(tv); |
126 | ||
127 | if(d_needinit) { | |
128 | d_last=now; | |
129 | d_needinit=false; | |
130 | } | |
131 | ||
132 | float diff= makeFloat(d_last - now); | |
d6d5dea7 | 133 | |
36c5ee42 | 134 | d_last=now; |
71dea98d | 135 | double factor=exp(diff)/2.0; // might be '0.5', or 0.0001 |
705f31ae | 136 | d_val=(float)((1-factor)*val+ (float)factor*d_val); |
eefd15f9 | 137 | } |
d6d5dea7 | 138 | |
71dea98d BH |
139 | double get(struct timeval*tv = 0) |
140 | { | |
141 | struct timeval now=getOrMakeTime(tv); | |
142 | float diff=makeFloat(d_lastget-now); | |
36c5ee42 | 143 | d_lastget=now; |
705f31ae | 144 | float factor=exp(diff/60.0f); // is 1.0 or less |
eefd15f9 BH |
145 | return d_val*=factor; |
146 | } | |
147 | ||
996c89cc | 148 | bool stale(time_t limit) const |
9fdf67d5 | 149 | { |
71dea98d | 150 | return limit > d_lastget.tv_sec; |
9fdf67d5 BH |
151 | } |
152 | ||
eefd15f9 | 153 | private: |
71dea98d BH |
154 | struct timeval d_last; // stores time |
155 | struct timeval d_lastget; // stores time | |
156 | float d_val; | |
157 | bool d_needinit; | |
158 | }; | |
159 | ||
160 | ||
161 | class PulseRate | |
162 | { | |
163 | public: | |
164 | PulseRate() : d_val(0.0) | |
165 | { | |
f2b6ccd6 | 166 | Utility::gettimeofday(&d_last, 0); |
71dea98d BH |
167 | } |
168 | ||
169 | PulseRate(const PulseRate& orig) : d_last(orig.d_last), d_val(orig.d_val) | |
170 | { | |
171 | } | |
172 | ||
173 | void pulse(const struct timeval& now) | |
174 | { | |
175 | // cout<<"about to submit: "<< 1000.0*makeFloat(now - d_last)<<"\n"; | |
176 | submit((int)(1000.0*(makeFloat(now-d_last))), now); | |
177 | } | |
178 | ||
179 | optional<float> get(struct timeval& now, unsigned int limit) const | |
180 | { | |
181 | optional<float> ret; | |
182 | float diff=makeFloat(now - d_last); | |
183 | if(diff < limit) | |
184 | ret=d_val; | |
185 | return ret; | |
186 | } | |
187 | ||
996c89cc | 188 | bool stale(time_t limit) const |
71dea98d BH |
189 | { |
190 | return limit > d_last.tv_sec; | |
191 | } | |
192 | ||
193 | private: | |
194 | void submit(int val, const struct timeval& now) | |
195 | { | |
196 | float diff= makeFloat(d_last - now); | |
197 | ||
198 | d_last=now; | |
199 | double factor=exp(diff/2.0)/2.0; // might be '0.5', or 0.0001 | |
705f31ae | 200 | d_val=(float)((1-factor)*val+ (float)factor*d_val); |
71dea98d BH |
201 | } |
202 | ||
203 | PulseRate& operator=(const PulseRate&); | |
204 | struct timeval d_last; // stores time | |
9fdf67d5 | 205 | float d_val; |
eefd15f9 BH |
206 | }; |
207 | ||
208 | ||
7b35aa49 | 209 | class SyncRes |
00a19ff7 BH |
210 | { |
211 | public: | |
c571588b BH |
212 | explicit SyncRes(const struct timeval& now) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0), |
213 | d_now(now), | |
214 | d_cacheonly(false), d_nocache(false) { } | |
a9af3782 | 215 | int beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector<DNSResourceRecord>&ret); |
c836dc19 BH |
216 | void setId(int id) |
217 | { | |
9fdf67d5 BH |
218 | if(s_log) |
219 | d_prefix="["+itoa(id)+"] "; | |
c836dc19 BH |
220 | } |
221 | static void setLog(bool log) | |
222 | { | |
223 | s_log=log; | |
224 | } | |
225 | void setCacheOnly(bool state=true) | |
226 | { | |
227 | d_cacheonly=state; | |
228 | } | |
229 | void setNoCache(bool state=true) | |
230 | { | |
231 | d_nocache=state; | |
232 | } | |
233 | static unsigned int s_queries; | |
7becf07f | 234 | static unsigned int s_outgoingtimeouts; |
3de83124 | 235 | static unsigned int s_throttledqueries; |
c836dc19 | 236 | static unsigned int s_outqueries; |
5c633640 | 237 | static unsigned int s_tcpoutqueries; |
525b8a7c | 238 | static unsigned int s_nodelegated; |
c571588b | 239 | static unsigned int s_unreachables; |
996c89cc | 240 | static bool s_doIPv6; |
c836dc19 | 241 | unsigned int d_outqueries; |
5c633640 | 242 | unsigned int d_tcpoutqueries; |
3de83124 | 243 | unsigned int d_throttledqueries; |
d77df2e1 | 244 | unsigned int d_timeouts; |
c571588b BH |
245 | unsigned int d_unreachables; |
246 | ||
33988bfb BH |
247 | // typedef map<string,NegCacheEntry> negcache_t; |
248 | ||
249 | typedef multi_index_container < | |
250 | NegCacheEntry, | |
251 | indexed_by < | |
252 | ordered_unique< | |
f4df5e89 BH |
253 | composite_key< |
254 | NegCacheEntry, | |
255 | member<NegCacheEntry, string, &NegCacheEntry::d_name>, | |
256 | member<NegCacheEntry, QType, &NegCacheEntry::d_qtype> | |
7738a23f BH |
257 | >, |
258 | composite_key_compare<CIStringCompare, std::less<QType> > | |
33988bfb BH |
259 | >, |
260 | ordered_non_unique< | |
261 | member<NegCacheEntry, uint32_t, &NegCacheEntry::d_ttd> | |
262 | > | |
263 | > | |
264 | >negcache_t; | |
9fdf67d5 BH |
265 | static negcache_t s_negcache; |
266 | ||
996c89cc BH |
267 | //! This represents a number of decaying Ewmas, used to store performance per namerserver-name. |
268 | /** Modelled to work mostly like the underlying DecayingEwma. After you've called get, | |
269 | d_best is filled out with the best address for this collection */ | |
270 | struct DecayingEwmaCollection | |
271 | { | |
272 | void submit(const ComboAddress& remote, int usecs, struct timeval* now) | |
273 | { | |
274 | collection_t::iterator pos; | |
275 | for(pos=d_collection.begin(); pos != d_collection.end(); ++pos) | |
276 | if(pos->first==remote) | |
277 | break; | |
278 | if(pos!=d_collection.end()) { | |
279 | pos->second.submit(usecs, now); | |
280 | } | |
281 | else { | |
282 | DecayingEwma de; | |
283 | de.submit(usecs, now); | |
284 | d_collection.push_back(make_pair(remote, de)); | |
285 | } | |
286 | } | |
287 | ||
288 | double get(struct timeval* now) | |
289 | { | |
290 | if(d_collection.empty()) | |
291 | return 0; | |
292 | double ret=numeric_limits<double>::max(); | |
293 | double tmp; | |
294 | for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) { | |
295 | if((tmp=pos->second.get()) < ret) { | |
296 | ret=tmp; | |
297 | d_best=pos->first; | |
298 | } | |
299 | } | |
300 | ||
301 | return ret; | |
302 | } | |
303 | ||
304 | bool stale(time_t limit) const | |
305 | { | |
306 | for(collection_t::const_iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) | |
307 | if(!pos->second.stale(limit)) | |
308 | return false; | |
309 | return true; | |
310 | } | |
311 | ||
312 | typedef vector<pair<ComboAddress, DecayingEwma> > collection_t; | |
313 | collection_t d_collection; | |
314 | ComboAddress d_best; | |
315 | }; | |
316 | ||
317 | typedef map<string, DecayingEwmaCollection , CIStringCompare> nsspeeds_t; | |
9fdf67d5 BH |
318 | static nsspeeds_t s_nsSpeeds; |
319 | ||
5605c067 BH |
320 | struct AuthDomain |
321 | { | |
322 | string d_server; | |
323 | typedef multi_index_container < | |
324 | DNSResourceRecord, | |
325 | indexed_by < | |
326 | ordered_non_unique< | |
327 | composite_key< DNSResourceRecord, | |
328 | member<DNSResourceRecord, string, &DNSResourceRecord::qname>, | |
329 | member<DNSResourceRecord, QType, &DNSResourceRecord::qtype> | |
330 | >, | |
331 | composite_key_compare<CIStringCompare, std::less<QType> > | |
332 | > | |
333 | > | |
334 | > records_t; | |
335 | records_t d_records; | |
336 | }; | |
337 | ||
338 | ||
339 | typedef map<string, AuthDomain, CIStringCompare> domainmap_t; | |
340 | static domainmap_t s_domainmap; | |
341 | ||
996c89cc | 342 | typedef Throttle<tuple<ComboAddress,string,uint16_t> > throttle_t; |
1d5b3ce6 | 343 | static throttle_t s_throttle; |
fe213470 | 344 | struct timeval d_now; |
a9af3782 BH |
345 | static unsigned int s_maxnegttl; |
346 | static string s_serverID; | |
00a19ff7 BH |
347 | private: |
348 | struct GetBestNSAnswer; | |
7738a23f | 349 | int doResolveAt(set<string, CIStringCompare> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, |
00a19ff7 BH |
350 | int depth, set<GetBestNSAnswer>&beenthere); |
351 | int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere); | |
e93c956b | 352 | bool doOOBResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res); |
5605c067 | 353 | domainmap_t::const_iterator getBestAuthZone(string* qname); |
00a19ff7 BH |
354 | bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res); |
355 | bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res); | |
356 | void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere); | |
357 | void addCruft(const string &qname, vector<DNSResourceRecord>& ret); | |
7738a23f | 358 | string getBestNSNamesFromCache(const string &qname,set<string, CIStringCompare>& nsset, int depth, set<GetBestNSAnswer>&beenthere); |
00a19ff7 BH |
359 | void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth); |
360 | ||
996c89cc | 361 | inline vector<string> shuffleInSpeedOrder(set<string, CIStringCompare> &nameservers, const string &prefix); |
00a19ff7 | 362 | bool moreSpecificThan(const string& a, const string &b); |
996c89cc | 363 | vector<ComboAddress> getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere); |
c75a6a9e | 364 | |
36c5ee42 BH |
365 | SyncRes(const SyncRes&); |
366 | SyncRes& operator=(const SyncRes&); | |
fe213470 BH |
367 | |
368 | ||
00a19ff7 | 369 | private: |
c836dc19 BH |
370 | string d_prefix; |
371 | static bool s_log; | |
372 | bool d_cacheonly; | |
373 | bool d_nocache; | |
7b35aa49 | 374 | LWRes d_lwr; |
c75a6a9e | 375 | |
00a19ff7 BH |
376 | struct GetBestNSAnswer |
377 | { | |
378 | string qname; | |
379 | set<DNSResourceRecord> bestns; | |
380 | bool operator<(const GetBestNSAnswer &b) const | |
381 | { | |
382 | if(qname<b.qname) | |
383 | return true; | |
384 | if(qname==b.qname) | |
385 | return bestns<b.bestns; | |
386 | return false; | |
387 | } | |
388 | }; | |
389 | ||
390 | }; | |
5c633640 | 391 | class Socket; |
a9af3782 | 392 | /* external functions, opaque to us */ |
5c633640 BH |
393 | int asendtcp(const string& data, Socket* sock); |
394 | int arecvtcp(string& data, int len, Socket* sock); | |
1d5b3ce6 BH |
395 | |
396 | ||
397 | struct PacketID | |
398 | { | |
67770277 BH |
399 | PacketID() : id(0), sock(0), inNeeded(0), outPos(0), nearMisses(0), fd(-1) |
400 | { | |
401 | memset(&remote, 0, sizeof(remote)); | |
402 | } | |
1d5b3ce6 BH |
403 | |
404 | uint16_t id; // wait for a specific id/remote pair | |
996c89cc | 405 | ComboAddress remote; // this is the remote |
0d5f0a9f | 406 | string domain; // this is the question |
1d5b3ce6 BH |
407 | |
408 | Socket* sock; // or wait for an event on a TCP fd | |
409 | int inNeeded; // if this is set, we'll read until inNeeded bytes are read | |
410 | string inMSG; // they'll go here | |
411 | ||
412 | string outMSG; // the outgoing message that needs to be sent | |
413 | string::size_type outPos; // how far we are along in the outMSG | |
414 | ||
35ce8576 | 415 | mutable uint32_t nearMisses; // number of near misses - host correct, id wrong |
4ef015cd | 416 | int fd; |
35ce8576 | 417 | |
1d5b3ce6 BH |
418 | bool operator<(const PacketID& b) const |
419 | { | |
420 | int ourSock= sock ? sock->getHandle() : 0; | |
421 | int bSock = b.sock ? b.sock->getHandle() : 0; | |
996c89cc BH |
422 | if( tie(id, remote, fd, ourSock) < |
423 | tie(b.id, remote, b.fd, bSock)) | |
0d5f0a9f | 424 | return true; |
996c89cc BH |
425 | if( tie(id, remote, fd, ourSock) > |
426 | tie(b.id, remote, b.fd, bSock)) | |
0d5f0a9f BH |
427 | return false; |
428 | ||
705f31ae | 429 | return Utility::strcasecmp(domain.c_str(), b.domain.c_str()) < 0; |
1d5b3ce6 BH |
430 | } |
431 | }; | |
432 | ||
433 | extern MemRecursorCache RC; | |
1d5b3ce6 BH |
434 | extern MTasker<PacketID,string>* MT; |
435 | ||
436 | struct RecursorStats | |
437 | { | |
438 | uint64_t servFails; | |
439 | uint64_t nxDomains; | |
440 | uint64_t noErrors; | |
71dea98d | 441 | PulseRate queryrate; |
fe213470 | 442 | uint64_t answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow; |
574af7ea | 443 | uint64_t avgLatencyUsec; |
aaacf7f2 BH |
444 | uint64_t qcounter; |
445 | uint64_t tcpqcounter; | |
c8ddb7c2 BH |
446 | uint64_t unauthorizedUDP; |
447 | uint64_t unauthorizedTCP; | |
4e120339 | 448 | uint64_t tcpClientOverflow; |
0e9d9ce2 BH |
449 | uint64_t clientParseError; |
450 | uint64_t serverParseError; | |
01ed3112 | 451 | uint64_t unexpectedCount; |
0d5f0a9f | 452 | uint64_t spoofCount; |
998a4334 | 453 | uint64_t resourceLimits; |
996c89cc BH |
454 | uint64_t ipv6queries; |
455 | ||
a9af3782 BH |
456 | typedef vector<ComboAddress> remotes_t; |
457 | remotes_t remotes; | |
458 | int d_remotepos; | |
459 | void addRemote(const ComboAddress& remote) | |
460 | { | |
461 | if(!remotes.size()) | |
462 | return; | |
463 | ||
464 | remotes[(d_remotepos++) % remotes.size()]=remote; | |
465 | } | |
1d5b3ce6 BH |
466 | }; |
467 | ||
468 | extern RecursorStats g_stats; | |
739f6278 BH |
469 | |
470 | ||
471 | template<typename Index> | |
472 | std::pair<typename Index::iterator,bool> | |
473 | replacing_insert(Index& i,const typename Index::value_type& x) | |
474 | { | |
475 | std::pair<typename Index::iterator,bool> res=i.insert(x); | |
476 | if(!res.second)res.second=i.replace(res.first,x); | |
477 | return res; | |
478 | } | |
479 | ||
00a19ff7 | 480 | #endif |