]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
22 | #pragma once | |
23 | #include <string> | |
24 | #include <atomic> | |
25 | #include "utility.hh" | |
26 | #include "dns.hh" | |
27 | #include "qtype.hh" | |
28 | #include <vector> | |
29 | #include <set> | |
30 | #include <unordered_set> | |
31 | #include <map> | |
32 | #include <cmath> | |
33 | #include <iostream> | |
34 | #include <utility> | |
35 | #include "misc.hh" | |
36 | #include "lwres.hh" | |
37 | #include <boost/optional.hpp> | |
38 | #include <boost/utility.hpp> | |
39 | #include "circular_buffer.hh" | |
40 | #include "sstuff.hh" | |
41 | #include "recursor_cache.hh" | |
42 | #include "recpacketcache.hh" | |
43 | #include <boost/tuple/tuple.hpp> | |
44 | #include <boost/optional.hpp> | |
45 | #include <boost/tuple/tuple_comparison.hpp> | |
46 | #include "mtasker.hh" | |
47 | #include "iputils.hh" | |
48 | #include "validate.hh" | |
49 | #include "ednssubnet.hh" | |
50 | #include "filterpo.hh" | |
51 | #include "negcache.hh" | |
52 | #include "sholder.hh" | |
53 | ||
54 | #ifdef HAVE_CONFIG_H | |
55 | #include "config.h" | |
56 | #endif | |
57 | ||
58 | #ifdef HAVE_PROTOBUF | |
59 | #include <boost/uuid/uuid.hpp> | |
60 | #ifdef HAVE_FSTRM | |
61 | #include "fstrm_logger.hh" | |
62 | #endif /* HAVE_FSTRM */ | |
63 | #endif | |
64 | ||
65 | extern GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames; | |
66 | extern GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks; | |
67 | ||
68 | class RecursorLua4; | |
69 | ||
70 | typedef std::unordered_map< | |
71 | DNSName, | |
72 | pair< | |
73 | vector<ComboAddress>, | |
74 | bool | |
75 | > | |
76 | > NsSet; | |
77 | ||
78 | template<class Thing> class Throttle : public boost::noncopyable | |
79 | { | |
80 | public: | |
81 | Throttle() : d_limit(3), d_ttl(60), d_last_clean(time(nullptr)) | |
82 | { | |
83 | } | |
84 | ||
85 | struct entry | |
86 | { | |
87 | time_t ttd; | |
88 | unsigned int count; | |
89 | }; | |
90 | typedef map<Thing,entry> cont_t; | |
91 | ||
92 | bool shouldThrottle(time_t now, const Thing& t) | |
93 | { | |
94 | if(now > d_last_clean + 300 ) { | |
95 | ||
96 | d_last_clean=now; | |
97 | for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) { | |
98 | if( i->second.ttd < now) { | |
99 | d_cont.erase(i++); | |
100 | } | |
101 | else | |
102 | ++i; | |
103 | } | |
104 | } | |
105 | ||
106 | typename cont_t::iterator i=d_cont.find(t); | |
107 | if(i==d_cont.end()) | |
108 | return false; | |
109 | if(now > i->second.ttd || i->second.count == 0) { | |
110 | d_cont.erase(i); | |
111 | return false; | |
112 | } | |
113 | i->second.count--; | |
114 | ||
115 | return true; // still listed, still blocked | |
116 | } | |
117 | void throttle(time_t now, const Thing& t, time_t ttl=0, unsigned int tries=0) | |
118 | { | |
119 | typename cont_t::iterator i=d_cont.find(t); | |
120 | entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit}; | |
121 | ||
122 | if(i==d_cont.end()) { | |
123 | d_cont[t]=e; | |
124 | } | |
125 | else if(i->second.ttd > e.ttd || (i->second.count) < e.count) | |
126 | d_cont[t]=e; | |
127 | } | |
128 | ||
129 | unsigned int size() const | |
130 | { | |
131 | return (unsigned int)d_cont.size(); | |
132 | } | |
133 | ||
134 | const cont_t& getThrottleMap() const | |
135 | { | |
136 | return d_cont; | |
137 | } | |
138 | ||
139 | void clear() | |
140 | { | |
141 | d_cont.clear(); | |
142 | } | |
143 | ||
144 | private: | |
145 | unsigned int d_limit; | |
146 | time_t d_ttl; | |
147 | time_t d_last_clean; | |
148 | cont_t d_cont; | |
149 | }; | |
150 | ||
151 | ||
152 | /** Class that implements a decaying EWMA. | |
153 | This class keeps an exponentially weighted moving average which, additionally, decays over time. | |
154 | The decaying is only done on get. | |
155 | */ | |
156 | class DecayingEwma | |
157 | { | |
158 | public: | |
159 | DecayingEwma() : d_val(0.0) | |
160 | { | |
161 | d_needinit=true; | |
162 | d_last.tv_sec = d_last.tv_usec = 0; | |
163 | d_lastget=d_last; | |
164 | } | |
165 | ||
166 | DecayingEwma(const DecayingEwma& orig) : d_last(orig.d_last), d_lastget(orig.d_lastget), d_val(orig.d_val), d_needinit(orig.d_needinit) | |
167 | { | |
168 | } | |
169 | ||
170 | void submit(int val, const struct timeval* tv) | |
171 | { | |
172 | struct timeval now=*tv; | |
173 | ||
174 | if(d_needinit) { | |
175 | d_last=now; | |
176 | d_lastget=now; | |
177 | d_needinit=false; | |
178 | d_val = val; | |
179 | } | |
180 | else { | |
181 | float diff= makeFloat(d_last - now); | |
182 | ||
183 | d_last=now; | |
184 | float factor=expf(diff)/2.0f; // might be '0.5', or 0.0001 | |
185 | d_val=(1-factor)*val + factor*d_val; | |
186 | } | |
187 | } | |
188 | ||
189 | float get(const struct timeval* tv) | |
190 | { | |
191 | struct timeval now=*tv; | |
192 | float diff=makeFloat(d_lastget-now); | |
193 | d_lastget=now; | |
194 | float factor=expf(diff/60.0f); // is 1.0 or less | |
195 | return d_val*=factor; | |
196 | } | |
197 | ||
198 | float peek(void) const | |
199 | { | |
200 | return d_val; | |
201 | } | |
202 | ||
203 | bool stale(time_t limit) const | |
204 | { | |
205 | return limit > d_lastget.tv_sec; | |
206 | } | |
207 | ||
208 | private: | |
209 | struct timeval d_last; // stores time | |
210 | struct timeval d_lastget; // stores time | |
211 | float d_val; | |
212 | bool d_needinit; | |
213 | }; | |
214 | ||
215 | template<class Thing> class Counters : public boost::noncopyable | |
216 | { | |
217 | public: | |
218 | Counters() | |
219 | { | |
220 | } | |
221 | unsigned long value(const Thing& t) const | |
222 | { | |
223 | typename cont_t::const_iterator i=d_cont.find(t); | |
224 | ||
225 | if(i==d_cont.end()) { | |
226 | return 0; | |
227 | } | |
228 | return (unsigned long)i->second; | |
229 | } | |
230 | unsigned long incr(const Thing& t) | |
231 | { | |
232 | typename cont_t::iterator i=d_cont.find(t); | |
233 | ||
234 | if(i==d_cont.end()) { | |
235 | d_cont[t]=1; | |
236 | return 1; | |
237 | } | |
238 | else { | |
239 | if (i->second < std::numeric_limits<unsigned long>::max()) | |
240 | i->second++; | |
241 | return (unsigned long)i->second; | |
242 | } | |
243 | } | |
244 | unsigned long decr(const Thing& t) | |
245 | { | |
246 | typename cont_t::iterator i=d_cont.find(t); | |
247 | ||
248 | if(i!=d_cont.end() && --i->second == 0) { | |
249 | d_cont.erase(i); | |
250 | return 0; | |
251 | } else | |
252 | return (unsigned long)i->second; | |
253 | } | |
254 | void clear(const Thing& t) | |
255 | { | |
256 | typename cont_t::iterator i=d_cont.find(t); | |
257 | ||
258 | if(i!=d_cont.end()) { | |
259 | d_cont.erase(i); | |
260 | } | |
261 | } | |
262 | void clear() | |
263 | { | |
264 | d_cont.clear(); | |
265 | } | |
266 | size_t size() const | |
267 | { | |
268 | return d_cont.size(); | |
269 | } | |
270 | private: | |
271 | typedef map<Thing,unsigned long> cont_t; | |
272 | cont_t d_cont; | |
273 | }; | |
274 | ||
275 | ||
276 | class SyncRes : public boost::noncopyable | |
277 | { | |
278 | public: | |
279 | enum LogMode { LogNone, Log, Store}; | |
280 | typedef std::function<int(const ComboAddress& ip, const DNSName& qdomain, int qtype, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult *lwr, bool* chained)> asyncresolve_t; | |
281 | ||
282 | struct EDNSStatus | |
283 | { | |
284 | EDNSStatus() : mode(UNKNOWN), modeSetAt(0) {} | |
285 | enum EDNSMode { UNKNOWN=0, EDNSOK=1, EDNSIGNORANT=2, NOEDNS=3 } mode; | |
286 | time_t modeSetAt; | |
287 | }; | |
288 | ||
289 | //! This represents a number of decaying Ewmas, used to store performance per nameserver-name. | |
290 | /** Modelled to work mostly like the underlying DecayingEwma. After you've called get, | |
291 | d_best is filled out with the best address for this collection */ | |
292 | struct DecayingEwmaCollection | |
293 | { | |
294 | void submit(const ComboAddress& remote, int usecs, const struct timeval* now) | |
295 | { | |
296 | d_collection[remote].submit(usecs, now); | |
297 | } | |
298 | ||
299 | double get(const struct timeval* now) | |
300 | { | |
301 | if(d_collection.empty()) | |
302 | return 0; | |
303 | double ret=std::numeric_limits<double>::max(); | |
304 | double tmp; | |
305 | for (auto& entry : d_collection) { | |
306 | if((tmp = entry.second.get(now)) < ret) { | |
307 | ret=tmp; | |
308 | d_best=entry.first; | |
309 | } | |
310 | } | |
311 | ||
312 | return ret; | |
313 | } | |
314 | ||
315 | bool stale(time_t limit) const | |
316 | { | |
317 | for(const auto& entry : d_collection) | |
318 | if(!entry.second.stale(limit)) | |
319 | return false; | |
320 | return true; | |
321 | } | |
322 | ||
323 | void purge(const std::map<ComboAddress, double>& keep) | |
324 | { | |
325 | for (auto iter = d_collection.begin(); iter != d_collection.end(); ) { | |
326 | if (keep.find(iter->first) != keep.end()) { | |
327 | ++iter; | |
328 | } | |
329 | else { | |
330 | iter = d_collection.erase(iter); | |
331 | } | |
332 | } | |
333 | } | |
334 | ||
335 | typedef std::map<ComboAddress, DecayingEwma> collection_t; | |
336 | collection_t d_collection; | |
337 | ComboAddress d_best; | |
338 | }; | |
339 | ||
340 | typedef std::unordered_map<DNSName, DecayingEwmaCollection> nsspeeds_t; | |
341 | typedef map<ComboAddress, EDNSStatus> ednsstatus_t; | |
342 | ||
343 | vState getDSRecords(const DNSName& zone, dsmap_t& ds, bool onlyTA, unsigned int depth, bool bogusOnNXD=true, bool* foundCut=nullptr); | |
344 | ||
345 | class AuthDomain | |
346 | { | |
347 | public: | |
348 | typedef multi_index_container < | |
349 | DNSRecord, | |
350 | indexed_by < | |
351 | ordered_non_unique< | |
352 | composite_key< DNSRecord, | |
353 | member<DNSRecord, DNSName, &DNSRecord::d_name>, | |
354 | member<DNSRecord, uint16_t, &DNSRecord::d_type> | |
355 | >, | |
356 | composite_key_compare<std::less<DNSName>, std::less<uint16_t> > | |
357 | > | |
358 | > | |
359 | > records_t; | |
360 | ||
361 | records_t d_records; | |
362 | vector<ComboAddress> d_servers; | |
363 | DNSName d_name; | |
364 | bool d_rdForward{false}; | |
365 | ||
366 | int getRecords(const DNSName& qname, uint16_t qtype, std::vector<DNSRecord>& records) const; | |
367 | bool isAuth() const | |
368 | { | |
369 | return d_servers.empty(); | |
370 | } | |
371 | bool isForward() const | |
372 | { | |
373 | return !isAuth(); | |
374 | } | |
375 | bool shouldRecurse() const | |
376 | { | |
377 | return d_rdForward; | |
378 | } | |
379 | const DNSName& getName() const | |
380 | { | |
381 | return d_name; | |
382 | } | |
383 | ||
384 | private: | |
385 | void addSOA(std::vector<DNSRecord>& records) const; | |
386 | }; | |
387 | ||
388 | typedef std::unordered_map<DNSName, AuthDomain> domainmap_t; | |
389 | typedef Throttle<boost::tuple<ComboAddress,DNSName,uint16_t> > throttle_t; | |
390 | typedef Counters<ComboAddress> fails_t; | |
391 | ||
392 | struct ThreadLocalStorage { | |
393 | NegCache negcache; | |
394 | nsspeeds_t nsSpeeds; | |
395 | throttle_t throttle; | |
396 | ednsstatus_t ednsstatus; | |
397 | fails_t fails; | |
398 | std::shared_ptr<domainmap_t> domainmap; | |
399 | }; | |
400 | ||
401 | static void setDefaultLogMode(LogMode lm) | |
402 | { | |
403 | s_lm = lm; | |
404 | } | |
405 | static uint64_t doEDNSDump(int fd); | |
406 | static uint64_t doDumpNSSpeeds(int fd); | |
407 | static uint64_t doDumpThrottleMap(int fd); | |
408 | static int getRootNS(struct timeval now, asyncresolve_t asyncCallback); | |
409 | static void clearDelegationOnly() | |
410 | { | |
411 | s_delegationOnly.clear(); | |
412 | } | |
413 | static void addDelegationOnly(const DNSName& name) | |
414 | { | |
415 | s_delegationOnly.insert(name); | |
416 | } | |
417 | static void addDontQuery(const std::string& mask) | |
418 | { | |
419 | if (!s_dontQuery) | |
420 | s_dontQuery = std::unique_ptr<NetmaskGroup>(new NetmaskGroup()); | |
421 | ||
422 | s_dontQuery->addMask(mask); | |
423 | } | |
424 | static void addDontQuery(const Netmask& mask) | |
425 | { | |
426 | if (!s_dontQuery) | |
427 | s_dontQuery = std::unique_ptr<NetmaskGroup>(new NetmaskGroup()); | |
428 | ||
429 | s_dontQuery->addMask(mask); | |
430 | } | |
431 | static void clearDontQuery() | |
432 | { | |
433 | s_dontQuery = nullptr; | |
434 | } | |
435 | static void parseEDNSSubnetWhitelist(const std::string& wlist); | |
436 | static void parseEDNSSubnetAddFor(const std::string& subnetlist); | |
437 | static void addEDNSLocalSubnet(const std::string& subnet) | |
438 | { | |
439 | s_ednslocalsubnets.addMask(subnet); | |
440 | } | |
441 | static void addEDNSRemoteSubnet(const std::string& subnet) | |
442 | { | |
443 | s_ednsremotesubnets.addMask(subnet); | |
444 | } | |
445 | static void addEDNSDomain(const DNSName& domain) | |
446 | { | |
447 | s_ednsdomains.add(domain); | |
448 | } | |
449 | static void clearEDNSLocalSubnets() | |
450 | { | |
451 | s_ednslocalsubnets.clear(); | |
452 | } | |
453 | static void clearEDNSRemoteSubnets() | |
454 | { | |
455 | s_ednsremotesubnets.clear(); | |
456 | } | |
457 | static void clearEDNSDomains() | |
458 | { | |
459 | s_ednsdomains = SuffixMatchNode(); | |
460 | } | |
461 | static void pruneNSSpeeds(time_t limit) | |
462 | { | |
463 | for(auto i = t_sstorage.nsSpeeds.begin(), end = t_sstorage.nsSpeeds.end(); i != end; ) { | |
464 | if(i->second.stale(limit)) { | |
465 | i = t_sstorage.nsSpeeds.erase(i); | |
466 | } | |
467 | else { | |
468 | ++i; | |
469 | } | |
470 | } | |
471 | } | |
472 | static uint64_t getNSSpeedsSize() | |
473 | { | |
474 | return t_sstorage.nsSpeeds.size(); | |
475 | } | |
476 | static void submitNSSpeed(const DNSName& server, const ComboAddress& ca, uint32_t usec, const struct timeval* now) | |
477 | { | |
478 | t_sstorage.nsSpeeds[server].submit(ca, usec, now); | |
479 | } | |
480 | static void clearNSSpeeds() | |
481 | { | |
482 | t_sstorage.nsSpeeds.clear(); | |
483 | } | |
484 | static EDNSStatus::EDNSMode getEDNSStatus(const ComboAddress& server) | |
485 | { | |
486 | const auto& it = t_sstorage.ednsstatus.find(server); | |
487 | if (it == t_sstorage.ednsstatus.end()) | |
488 | return EDNSStatus::UNKNOWN; | |
489 | ||
490 | return it->second.mode; | |
491 | } | |
492 | static uint64_t getEDNSStatusesSize() | |
493 | { | |
494 | return t_sstorage.ednsstatus.size(); | |
495 | } | |
496 | static void clearEDNSStatuses() | |
497 | { | |
498 | t_sstorage.ednsstatus.clear(); | |
499 | } | |
500 | static uint64_t getThrottledServersSize() | |
501 | { | |
502 | return t_sstorage.throttle.size(); | |
503 | } | |
504 | static void clearThrottle() | |
505 | { | |
506 | t_sstorage.throttle.clear(); | |
507 | } | |
508 | static bool isThrottled(time_t now, const ComboAddress& server, const DNSName& target, uint16_t qtype) | |
509 | { | |
510 | return t_sstorage.throttle.shouldThrottle(now, boost::make_tuple(server, target, qtype)); | |
511 | } | |
512 | static bool isThrottled(time_t now, const ComboAddress& server) | |
513 | { | |
514 | return t_sstorage.throttle.shouldThrottle(now, boost::make_tuple(server, "", 0)); | |
515 | } | |
516 | static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries) | |
517 | { | |
518 | t_sstorage.throttle.throttle(now, boost::make_tuple(server, "", 0), duration, tries); | |
519 | } | |
520 | static uint64_t getFailedServersSize() | |
521 | { | |
522 | return t_sstorage.fails.size(); | |
523 | } | |
524 | static void clearFailedServers() | |
525 | { | |
526 | t_sstorage.fails.clear(); | |
527 | } | |
528 | static unsigned long getServerFailsCount(const ComboAddress& server) | |
529 | { | |
530 | return t_sstorage.fails.value(server); | |
531 | } | |
532 | ||
533 | static void clearNegCache() | |
534 | { | |
535 | t_sstorage.negcache.clear(); | |
536 | } | |
537 | ||
538 | static uint64_t getNegCacheSize() | |
539 | { | |
540 | return t_sstorage.negcache.size(); | |
541 | } | |
542 | ||
543 | static void pruneNegCache(unsigned int maxEntries) | |
544 | { | |
545 | t_sstorage.negcache.prune(maxEntries); | |
546 | } | |
547 | ||
548 | static uint64_t wipeNegCache(const DNSName& name, bool subtree = false) | |
549 | { | |
550 | return t_sstorage.negcache.wipe(name, subtree); | |
551 | } | |
552 | ||
553 | static void setDomainMap(std::shared_ptr<domainmap_t> newMap) | |
554 | { | |
555 | t_sstorage.domainmap = newMap; | |
556 | } | |
557 | ||
558 | static const std::shared_ptr<domainmap_t> getDomainMap() | |
559 | { | |
560 | return t_sstorage.domainmap; | |
561 | } | |
562 | ||
563 | static void setECSScopeZeroAddress(const Netmask& scopeZeroMask) | |
564 | { | |
565 | s_ecsScopeZero.source = scopeZeroMask; | |
566 | } | |
567 | ||
568 | static void clearECSStats() | |
569 | { | |
570 | s_ecsqueries.store(0); | |
571 | s_ecsresponses.store(0); | |
572 | ||
573 | for (size_t idx = 0; idx < 32; idx++) { | |
574 | SyncRes::s_ecsResponsesBySubnetSize4[idx].store(0); | |
575 | } | |
576 | ||
577 | for (size_t idx = 0; idx < 128; idx++) { | |
578 | SyncRes::s_ecsResponsesBySubnetSize6[idx].store(0); | |
579 | } | |
580 | } | |
581 | ||
582 | explicit SyncRes(const struct timeval& now); | |
583 | ||
584 | int beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret); | |
585 | void setId(int id) | |
586 | { | |
587 | if(doLog()) | |
588 | d_prefix="["+itoa(id)+"] "; | |
589 | } | |
590 | ||
591 | void setLogMode(LogMode lm) | |
592 | { | |
593 | d_lm = lm; | |
594 | } | |
595 | ||
596 | bool doLog() const | |
597 | { | |
598 | return d_lm != LogNone; | |
599 | } | |
600 | ||
601 | bool setCacheOnly(bool state = true) | |
602 | { | |
603 | bool old = d_cacheonly; | |
604 | d_cacheonly = state; | |
605 | return old; | |
606 | } | |
607 | ||
608 | void setQNameMinimization(bool state=true) | |
609 | { | |
610 | d_qNameMinimization=state; | |
611 | } | |
612 | ||
613 | void setDoEDNS0(bool state=true) | |
614 | { | |
615 | d_doEDNS0=state; | |
616 | } | |
617 | ||
618 | void setDoDNSSEC(bool state=true) | |
619 | { | |
620 | d_doDNSSEC=state; | |
621 | } | |
622 | ||
623 | void setDNSSECValidationRequested(bool requested=true) | |
624 | { | |
625 | d_DNSSECValidationRequested = requested; | |
626 | } | |
627 | ||
628 | bool isDNSSECValidationRequested() const | |
629 | { | |
630 | return d_DNSSECValidationRequested; | |
631 | } | |
632 | ||
633 | bool shouldValidate() const | |
634 | { | |
635 | return d_DNSSECValidationRequested && !d_wasOutOfBand; | |
636 | } | |
637 | ||
638 | void setWantsRPZ(bool state=true) | |
639 | { | |
640 | d_wantsRPZ=state; | |
641 | } | |
642 | ||
643 | bool getWantsRPZ() const | |
644 | { | |
645 | return d_wantsRPZ; | |
646 | } | |
647 | ||
648 | string getTrace() const | |
649 | { | |
650 | return d_trace.str(); | |
651 | } | |
652 | ||
653 | bool getQNameMinimization() const | |
654 | { | |
655 | return d_qNameMinimization; | |
656 | } | |
657 | ||
658 | void setLuaEngine(shared_ptr<RecursorLua4> pdl) | |
659 | { | |
660 | d_pdl = pdl; | |
661 | } | |
662 | ||
663 | bool wasVariable() const | |
664 | { | |
665 | return d_wasVariable; | |
666 | } | |
667 | ||
668 | bool wasOutOfBand() const | |
669 | { | |
670 | return d_wasOutOfBand; | |
671 | } | |
672 | ||
673 | struct timeval getNow() const | |
674 | { | |
675 | return d_now; | |
676 | } | |
677 | ||
678 | void setSkipCNAMECheck(bool skip = false) | |
679 | { | |
680 | d_skipCNAMECheck = skip; | |
681 | } | |
682 | ||
683 | void setQuerySource(const ComboAddress& requestor, boost::optional<const EDNSSubnetOpts&> incomingECS); | |
684 | ||
685 | #ifdef HAVE_PROTOBUF | |
686 | void setInitialRequestId(boost::optional<const boost::uuids::uuid&> initialRequestId) | |
687 | { | |
688 | d_initialRequestId = initialRequestId; | |
689 | } | |
690 | ||
691 | void setOutgoingProtobufServers(std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& servers) | |
692 | { | |
693 | d_outgoingProtobufServers = servers; | |
694 | } | |
695 | #endif | |
696 | ||
697 | #ifdef HAVE_FSTRM | |
698 | void setFrameStreamServers(std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& servers) | |
699 | { | |
700 | d_frameStreamServers = servers; | |
701 | } | |
702 | #endif /* HAVE_FSTRM */ | |
703 | ||
704 | void setAsyncCallback(asyncresolve_t func) | |
705 | { | |
706 | d_asyncResolve = func; | |
707 | } | |
708 | ||
709 | vState getValidationState() const | |
710 | { | |
711 | return d_queryValidationState; | |
712 | } | |
713 | ||
714 | static thread_local ThreadLocalStorage t_sstorage; | |
715 | ||
716 | static std::atomic<uint64_t> s_queries; | |
717 | static std::atomic<uint64_t> s_outgoingtimeouts; | |
718 | static std::atomic<uint64_t> s_outgoing4timeouts; | |
719 | static std::atomic<uint64_t> s_outgoing6timeouts; | |
720 | static std::atomic<uint64_t> s_throttledqueries; | |
721 | static std::atomic<uint64_t> s_dontqueries; | |
722 | static std::atomic<uint64_t> s_authzonequeries; | |
723 | static std::atomic<uint64_t> s_outqueries; | |
724 | static std::atomic<uint64_t> s_tcpoutqueries; | |
725 | static std::atomic<uint64_t> s_nodelegated; | |
726 | static std::atomic<uint64_t> s_unreachables; | |
727 | static std::atomic<uint64_t> s_ecsqueries; | |
728 | static std::atomic<uint64_t> s_ecsresponses; | |
729 | static std::map<uint8_t, std::atomic<uint64_t>> s_ecsResponsesBySubnetSize4; | |
730 | static std::map<uint8_t, std::atomic<uint64_t>> s_ecsResponsesBySubnetSize6; | |
731 | ||
732 | static string s_serverID; | |
733 | static unsigned int s_minimumTTL; | |
734 | static unsigned int s_minimumECSTTL; | |
735 | static unsigned int s_maxqperq; | |
736 | static unsigned int s_maxtotusec; | |
737 | static unsigned int s_maxdepth; | |
738 | static unsigned int s_maxnegttl; | |
739 | static unsigned int s_maxbogusttl; | |
740 | static unsigned int s_maxcachettl; | |
741 | static unsigned int s_packetcachettl; | |
742 | static unsigned int s_packetcacheservfailttl; | |
743 | static unsigned int s_serverdownmaxfails; | |
744 | static unsigned int s_serverdownthrottletime; | |
745 | static unsigned int s_ecscachelimitttl; | |
746 | static uint8_t s_ecsipv4limit; | |
747 | static uint8_t s_ecsipv6limit; | |
748 | static uint8_t s_ecsipv4cachelimit; | |
749 | static uint8_t s_ecsipv6cachelimit; | |
750 | static bool s_doIPv6; | |
751 | static bool s_noEDNSPing; | |
752 | static bool s_noEDNS; | |
753 | static bool s_rootNXTrust; | |
754 | static bool s_nopacketcache; | |
755 | static bool s_qnameminimization; | |
756 | ||
757 | std::unordered_map<std::string,bool> d_discardedPolicies; | |
758 | DNSFilterEngine::Policy d_appliedPolicy; | |
759 | unsigned int d_authzonequeries; | |
760 | unsigned int d_outqueries; | |
761 | unsigned int d_tcpoutqueries; | |
762 | unsigned int d_throttledqueries; | |
763 | unsigned int d_timeouts; | |
764 | unsigned int d_unreachables; | |
765 | unsigned int d_totUsec; | |
766 | ||
767 | private: | |
768 | ComboAddress d_requestor; | |
769 | ComboAddress d_cacheRemote; | |
770 | ||
771 | static std::unordered_set<DNSName> s_delegationOnly; | |
772 | static NetmaskGroup s_ednslocalsubnets; | |
773 | static NetmaskGroup s_ednsremotesubnets; | |
774 | static SuffixMatchNode s_ednsdomains; | |
775 | static EDNSSubnetOpts s_ecsScopeZero; | |
776 | static LogMode s_lm; | |
777 | static std::unique_ptr<NetmaskGroup> s_dontQuery; | |
778 | const static std::unordered_set<uint16_t> s_redirectionQTypes; | |
779 | ||
780 | struct GetBestNSAnswer | |
781 | { | |
782 | DNSName qname; | |
783 | set<pair<DNSName,DNSName> > bestns; | |
784 | uint8_t qtype; | |
785 | bool operator<(const GetBestNSAnswer &b) const | |
786 | { | |
787 | return boost::tie(qtype, qname, bestns) < | |
788 | boost::tie(b.qtype, b.qname, b.bestns); | |
789 | } | |
790 | }; | |
791 | ||
792 | typedef std::map<DNSName,vState> zonesStates_t; | |
793 | enum StopAtDelegation { DontStop, Stop, Stopped }; | |
794 | ||
795 | int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, | |
796 | unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state, StopAtDelegation* stopAtDelegation); | |
797 | bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool const sendRDQuery, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool* truncated); | |
798 | bool processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state); | |
799 | ||
800 | int doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state); | |
801 | int doResolveNoQNameMinimization(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state, bool* fromCache = NULL, StopAtDelegation* stopAtDelegation = NULL); | |
802 | bool doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res); | |
803 | bool doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res); | |
804 | domainmap_t::const_iterator getBestAuthZone(DNSName* qname) const; | |
805 | bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse); | |
806 | bool doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state); | |
807 | void getBestNSFromCache(const DNSName &qname, const QType &qtype, vector<DNSRecord>&bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere); | |
808 | DNSName getBestNSNamesFromCache(const DNSName &qname, const QType &qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere); | |
809 | ||
810 | inline vector<std::pair<DNSName, double>> shuffleInSpeedOrder(NsSet &nameservers, const string &prefix); | |
811 | inline vector<ComboAddress> shuffleForwardSpeed(const vector<ComboAddress> &rnameservers, const string &prefix, const bool wasRd); | |
812 | bool moreSpecificThan(const DNSName& a, const DNSName &b) const; | |
813 | vector<ComboAddress> getAddrs(const DNSName &qname, unsigned int depth, set<GetBestNSAnswer>& beenthere, bool cacheOnly); | |
814 | ||
815 | bool nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers); | |
816 | bool nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress&); | |
817 | bool throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery); | |
818 | ||
819 | vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<std::pair<DNSName, double>>::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<std::pair<DNSName, double>>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly); | |
820 | ||
821 | void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery); | |
822 | RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery); | |
823 | bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const bool gatherwildcardProof, const unsigned int wildcardLabelsCount); | |
824 | ||
825 | bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret); | |
826 | ||
827 | int asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, const DNSName& auth, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res, bool* chained) const; | |
828 | ||
829 | boost::optional<Netmask> getEDNSSubnetMask(const DNSName&dn, const ComboAddress& rem); | |
830 | ||
831 | bool validationEnabled() const; | |
832 | uint32_t computeLowestTTD(const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, uint32_t signaturesTTL) const; | |
833 | void updateValidationState(vState& state, const vState stateUpdate); | |
834 | vState validateRecordsWithSigs(unsigned int depth, const DNSName& qname, const QType& qtype, const DNSName& name, const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures); | |
835 | vState validateDNSKeys(const DNSName& zone, const std::vector<DNSRecord>& dnskeys, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, unsigned int depth); | |
836 | vState getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth); | |
837 | dState getDenialValidationState(const NegCache::NegCacheEntry& ne, const vState state, const dState expectedState, bool referralToUnsigned); | |
838 | void updateDenialValidationState(vState& neValidationState, const DNSName& neName, vState& state, const dState denialState, const dState expectedState, bool allowOptOut); | |
839 | void computeNegCacheValidationStatus(const NegCache::NegCacheEntry* ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth); | |
840 | vState getTA(const DNSName& zone, dsmap_t& ds); | |
841 | bool haveExactValidationStatus(const DNSName& domain); | |
842 | vState getValidationStatus(const DNSName& subdomain, bool allowIndeterminate=true); | |
843 | void updateValidationStatusInCache(const DNSName &qname, const QType& qt, bool aa, vState newState) const; | |
844 | ||
845 | bool lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState); | |
846 | void computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth); | |
847 | ||
848 | void setUpdatingRootNS() | |
849 | { | |
850 | d_updatingRootNS = true; | |
851 | } | |
852 | ||
853 | zonesStates_t d_cutStates; | |
854 | ostringstream d_trace; | |
855 | shared_ptr<RecursorLua4> d_pdl; | |
856 | boost::optional<Netmask> d_outgoingECSNetwork; | |
857 | std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>> d_outgoingProtobufServers{nullptr}; | |
858 | std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>> d_frameStreamServers{nullptr}; | |
859 | #ifdef HAVE_PROTOBUF | |
860 | boost::optional<const boost::uuids::uuid&> d_initialRequestId; | |
861 | #endif | |
862 | asyncresolve_t d_asyncResolve{nullptr}; | |
863 | struct timeval d_now; | |
864 | string d_prefix; | |
865 | vState d_queryValidationState{Indeterminate}; | |
866 | ||
867 | /* When d_cacheonly is set to true, we will only check the cache. | |
868 | * This is set when the RD bit is unset in the incoming query | |
869 | */ | |
870 | bool d_cacheonly; | |
871 | bool d_doDNSSEC; | |
872 | bool d_DNSSECValidationRequested{false}; | |
873 | bool d_doEDNS0{true}; | |
874 | bool d_requireAuthData{true}; | |
875 | bool d_skipCNAMECheck{false}; | |
876 | bool d_updatingRootNS{false}; | |
877 | bool d_wantsRPZ{true}; | |
878 | bool d_wasOutOfBand{false}; | |
879 | bool d_wasVariable{false}; | |
880 | bool d_qNameMinimization{false}; | |
881 | ||
882 | LogMode d_lm; | |
883 | }; | |
884 | ||
885 | class Socket; | |
886 | /* external functions, opaque to us */ | |
887 | int asendtcp(const string& data, Socket* sock); | |
888 | int arecvtcp(string& data, size_t len, Socket* sock, bool incompleteOkay); | |
889 | ||
890 | ||
891 | struct PacketID | |
892 | { | |
893 | PacketID() : id(0), type(0), sock(0), inNeeded(0), inIncompleteOkay(false), outPos(0), nearMisses(0), fd(-1) | |
894 | { | |
895 | remote.reset(); | |
896 | } | |
897 | ||
898 | uint16_t id; // wait for a specific id/remote pair | |
899 | uint16_t type; // and this is its type | |
900 | ComboAddress remote; // this is the remote | |
901 | DNSName domain; // this is the question | |
902 | ||
903 | Socket* sock; // or wait for an event on a TCP fd | |
904 | string inMSG; // they'll go here | |
905 | size_t inNeeded; // if this is set, we'll read until inNeeded bytes are read | |
906 | bool inIncompleteOkay; | |
907 | ||
908 | string outMSG; // the outgoing message that needs to be sent | |
909 | string::size_type outPos; // how far we are along in the outMSG | |
910 | ||
911 | typedef set<uint16_t > chain_t; | |
912 | mutable chain_t chain; | |
913 | mutable uint32_t nearMisses; // number of near misses - host correct, id wrong | |
914 | int fd; | |
915 | ||
916 | bool operator<(const PacketID& b) const | |
917 | { | |
918 | int ourSock= sock ? sock->getHandle() : 0; | |
919 | int bSock = b.sock ? b.sock->getHandle() : 0; | |
920 | if( tie(remote, ourSock, type) < tie(b.remote, bSock, b.type)) | |
921 | return true; | |
922 | if( tie(remote, ourSock, type) > tie(b.remote, bSock, b.type)) | |
923 | return false; | |
924 | ||
925 | return tie(fd, id, domain) < tie(b.fd, b.id, b.domain); | |
926 | } | |
927 | }; | |
928 | ||
929 | struct PacketIDBirthdayCompare: public std::binary_function<PacketID, PacketID, bool> | |
930 | { | |
931 | bool operator()(const PacketID& a, const PacketID& b) const | |
932 | { | |
933 | int ourSock= a.sock ? a.sock->getHandle() : 0; | |
934 | int bSock = b.sock ? b.sock->getHandle() : 0; | |
935 | if( tie(a.remote, ourSock, a.type) < tie(b.remote, bSock, b.type)) | |
936 | return true; | |
937 | if( tie(a.remote, ourSock, a.type) > tie(b.remote, bSock, b.type)) | |
938 | return false; | |
939 | ||
940 | return a.domain < b.domain; | |
941 | } | |
942 | }; | |
943 | extern thread_local std::unique_ptr<MemRecursorCache> t_RC; | |
944 | extern thread_local std::unique_ptr<RecursorPacketCache> t_packetCache; | |
945 | typedef MTasker<PacketID,string> MT_t; | |
946 | MT_t* getMT(); | |
947 | ||
948 | struct RecursorStats | |
949 | { | |
950 | std::atomic<uint64_t> servFails; | |
951 | std::atomic<uint64_t> nxDomains; | |
952 | std::atomic<uint64_t> noErrors; | |
953 | std::atomic<uint64_t> answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow; | |
954 | std::atomic<uint64_t> auth4Answers0_1, auth4Answers1_10, auth4Answers10_100, auth4Answers100_1000, auth4AnswersSlow; | |
955 | std::atomic<uint64_t> auth6Answers0_1, auth6Answers1_10, auth6Answers10_100, auth6Answers100_1000, auth6AnswersSlow; | |
956 | std::atomic<uint64_t> ourtime0_1, ourtime1_2, ourtime2_4, ourtime4_8, ourtime8_16, ourtime16_32, ourtimeSlow; | |
957 | double avgLatencyUsec{0}; | |
958 | double avgLatencyOursUsec{0}; | |
959 | std::atomic<uint64_t> qcounter; // not increased for unauth packets | |
960 | std::atomic<uint64_t> ipv6qcounter; | |
961 | std::atomic<uint64_t> tcpqcounter; | |
962 | std::atomic<uint64_t> unauthorizedUDP; // when this is increased, qcounter isn't | |
963 | std::atomic<uint64_t> unauthorizedTCP; // when this is increased, qcounter isn't | |
964 | std::atomic<uint64_t> policyDrops; | |
965 | std::atomic<uint64_t> tcpClientOverflow; | |
966 | std::atomic<uint64_t> clientParseError; | |
967 | std::atomic<uint64_t> serverParseError; | |
968 | std::atomic<uint64_t> tooOldDrops; | |
969 | std::atomic<uint64_t> truncatedDrops; | |
970 | std::atomic<uint64_t> queryPipeFullDrops; | |
971 | std::atomic<uint64_t> unexpectedCount; | |
972 | std::atomic<uint64_t> caseMismatchCount; | |
973 | std::atomic<uint64_t> spoofCount; | |
974 | std::atomic<uint64_t> resourceLimits; | |
975 | std::atomic<uint64_t> overCapacityDrops; | |
976 | std::atomic<uint64_t> ipv6queries; | |
977 | std::atomic<uint64_t> chainResends; | |
978 | std::atomic<uint64_t> nsSetInvalidations; | |
979 | std::atomic<uint64_t> ednsPingMatches; | |
980 | std::atomic<uint64_t> ednsPingMismatches; | |
981 | std::atomic<uint64_t> noPingOutQueries, noEdnsOutQueries; | |
982 | std::atomic<uint64_t> packetCacheHits; | |
983 | std::atomic<uint64_t> noPacketError; | |
984 | std::atomic<uint64_t> ignoredCount; | |
985 | std::atomic<uint64_t> emptyQueriesCount; | |
986 | time_t startupTime; | |
987 | std::atomic<uint64_t> dnssecQueries; | |
988 | std::atomic<uint64_t> dnssecAuthenticDataQueries; | |
989 | std::atomic<uint64_t> dnssecCheckDisabledQueries; | |
990 | std::atomic<uint64_t> variableResponses; | |
991 | unsigned int maxMThreadStackUsage; | |
992 | std::atomic<uint64_t> dnssecValidations; // should be the sum of all dnssecResult* stats | |
993 | std::map<vState, std::atomic<uint64_t> > dnssecResults; | |
994 | std::map<DNSFilterEngine::PolicyKind, std::atomic<uint64_t> > policyResults; | |
995 | std::atomic<uint64_t> rebalancedQueries{0}; | |
996 | }; | |
997 | ||
998 | //! represents a running TCP/IP client session | |
999 | class TCPConnection : public boost::noncopyable | |
1000 | { | |
1001 | public: | |
1002 | TCPConnection(int fd, const ComboAddress& addr); | |
1003 | ~TCPConnection(); | |
1004 | ||
1005 | int getFD() const | |
1006 | { | |
1007 | return d_fd; | |
1008 | } | |
1009 | ||
1010 | std::string data; | |
1011 | const ComboAddress d_remote; | |
1012 | size_t queriesCount{0}; | |
1013 | enum stateenum {BYTE0, BYTE1, GETQUESTION, DONE} state{BYTE0}; | |
1014 | uint16_t qlen{0}; | |
1015 | uint16_t bytesread{0}; | |
1016 | ||
1017 | static unsigned int getCurrentConnections() { return s_currentConnections; } | |
1018 | private: | |
1019 | const int d_fd; | |
1020 | static AtomicCounter s_currentConnections; //!< total number of current TCP connections | |
1021 | }; | |
1022 | ||
1023 | class ImmediateServFailException | |
1024 | { | |
1025 | public: | |
1026 | ImmediateServFailException(string r) : reason(r) {}; | |
1027 | ||
1028 | string reason; //! Print this to tell the user what went wrong | |
1029 | }; | |
1030 | ||
1031 | typedef boost::circular_buffer<ComboAddress> addrringbuf_t; | |
1032 | extern thread_local std::unique_ptr<addrringbuf_t> t_servfailremotes, t_largeanswerremotes, t_remotes, t_bogusremotes, t_timeouts; | |
1033 | ||
1034 | extern thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName,uint16_t> > > t_queryring, t_servfailqueryring, t_bogusqueryring; | |
1035 | extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom; | |
1036 | string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end); | |
1037 | string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end); | |
1038 | void parseACLs(); | |
1039 | extern RecursorStats g_stats; | |
1040 | extern unsigned int g_networkTimeoutMsec; | |
1041 | extern unsigned int g_numThreads; | |
1042 | extern uint16_t g_outgoingEDNSBufsize; | |
1043 | extern std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries; | |
1044 | extern bool g_lowercaseOutgoing; | |
1045 | ||
1046 | ||
1047 | std::string reloadAuthAndForwards(); | |
1048 | ComboAddress parseIPAndPort(const std::string& input, uint16_t port); | |
1049 | ComboAddress getQueryLocalAddress(int family, uint16_t port); | |
1050 | typedef boost::function<void*(void)> pipefunc_t; | |
1051 | void broadcastFunction(const pipefunc_t& func); | |
1052 | void distributeAsyncFunction(const std::string& question, const pipefunc_t& func); | |
1053 | ||
1054 | int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret); | |
1055 | int followCNAMERecords(std::vector<DNSRecord>& ret, const QType& qtype); | |
1056 | ||
1057 | template<class T> T broadcastAccFunction(const boost::function<T*()>& func); | |
1058 | ||
1059 | std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards(); | |
1060 | uint64_t* pleaseGetNsSpeedsSize(); | |
1061 | uint64_t* pleaseGetCacheSize(); | |
1062 | uint64_t* pleaseGetNegCacheSize(); | |
1063 | uint64_t* pleaseGetCacheHits(); | |
1064 | uint64_t* pleaseGetCacheMisses(); | |
1065 | uint64_t* pleaseGetConcurrentQueries(); | |
1066 | uint64_t* pleaseGetThrottleSize(); | |
1067 | uint64_t* pleaseGetPacketCacheHits(); | |
1068 | uint64_t* pleaseGetPacketCacheSize(); | |
1069 | uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree=false); | |
1070 | uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree); | |
1071 | uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree=false); | |
1072 | void doCarbonDump(void*); | |
1073 | void primeHints(void); | |
1074 | ||
1075 | extern __thread struct timeval g_now; | |
1076 | ||
1077 | struct ThreadTimes | |
1078 | { | |
1079 | uint64_t msec; | |
1080 | vector<uint64_t> times; | |
1081 | ThreadTimes& operator+=(const ThreadTimes& rhs) | |
1082 | { | |
1083 | times.push_back(rhs.msec); | |
1084 | return *this; | |
1085 | } | |
1086 | }; |