]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.hh
Merge pull request #7538 from omoerbeek/rec-dnstap
[thirdparty/pdns.git] / pdns / syncres.hh
CommitLineData
12471842
PL
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 */
32cdc494 22#pragma once
00a19ff7 23#include <string>
aebb81e4 24#include <atomic>
3897b9e1 25#include "utility.hh"
00a19ff7
BH
26#include "dns.hh"
27#include "qtype.hh"
28#include <vector>
29#include <set>
9ea28e46 30#include <unordered_set>
00a19ff7 31#include <map>
eefd15f9
BH
32#include <cmath>
33#include <iostream>
34#include <utility>
c836dc19 35#include "misc.hh"
00a19ff7 36#include "lwres.hh"
4898a348 37#include <boost/optional.hpp>
92011b8f 38#include <boost/circular_buffer.hpp>
d6d5dea7 39#include <boost/utility.hpp>
1d5b3ce6 40#include "sstuff.hh"
9fdf67d5 41#include "recursor_cache.hh"
16beeaa4 42#include "recpacketcache.hh"
1d5b3ce6 43#include <boost/tuple/tuple.hpp>
71dea98d 44#include <boost/optional.hpp>
1d5b3ce6
BH
45#include <boost/tuple/tuple_comparison.hpp>
46#include "mtasker.hh"
a9af3782 47#include "iputils.hh"
849fe8d2 48#include "validate.hh"
b40562da 49#include "ednssubnet.hh"
644dd1da 50#include "filterpo.hh"
39ce10b2 51#include "negcache.hh"
559b6c93 52#include "sholder.hh"
644dd1da 53
20642494 54#ifdef HAVE_CONFIG_H
4898a348 55#include "config.h"
20642494
PL
56#endif
57
4898a348
RG
58#ifdef HAVE_PROTOBUF
59#include <boost/uuid/uuid.hpp>
b9fa43e0
OM
60#ifdef HAVE_FSTRM
61#include "fstrm_logger.hh"
62#endif /* HAVE_FSTRM */
4898a348
RG
63#endif
64
559b6c93
PL
65extern GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
66extern GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
67
a3e7b735 68class RecursorLua4;
620db2c8 69
fa1b87ff
PL
70typedef map<
71 DNSName,
72 pair<
73 vector<ComboAddress>,
74 bool
75 >
76> NsSet;
49f076e8 77
bb4bdbaf 78template<class Thing> class Throttle : public boost::noncopyable
49f076e8
BH
79{
80public:
3cbe2773 81 Throttle() : d_limit(3), d_ttl(60), d_last_clean(time(nullptr))
49f076e8 82 {
49f076e8 83 }
96e2f64f 84
85 struct entry
86 {
87 time_t ttd;
88 unsigned int count;
89 };
90 typedef map<Thing,entry> cont_t;
91
87da00e7 92 bool shouldThrottle(time_t now, const Thing& t)
49f076e8 93 {
cd7bf56b 94 if(now > d_last_clean + 300 ) {
bb4bdbaf 95
49f076e8 96 d_last_clean=now;
594c2ee7 97 for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) {
4957a608
BH
98 if( i->second.ttd < now) {
99 d_cont.erase(i++);
100 }
101 else
102 ++i;
594c2ee7 103 }
49f076e8
BH
104 }
105
49f076e8
BH
106 typename cont_t::iterator i=d_cont.find(t);
107 if(i==d_cont.end())
108 return false;
ccb07d93 109 if(now > i->second.ttd || i->second.count == 0) {
49f076e8 110 d_cont.erase(i);
139c2911 111 return false;
49f076e8 112 }
ccb07d93 113 i->second.count--;
014c60c3
BH
114
115 return true; // still listed, still blocked
49f076e8 116 }
3ddb9247 117 void throttle(time_t now, const Thing& t, time_t ttl=0, unsigned int tries=0)
49f076e8
BH
118 {
119 typename cont_t::iterator i=d_cont.find(t);
87da00e7 120 entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit};
49f076e8 121
c214232f 122 if(i==d_cont.end()) {
49f076e8 123 d_cont[t]=e;
3ddb9247
PD
124 }
125 else if(i->second.ttd > e.ttd || (i->second.count) < e.count)
c214232f 126 d_cont[t]=e;
8a5602d4 127 }
3ddb9247 128
30ee601a 129 unsigned int size() const
8a5602d4 130 {
705f31ae 131 return (unsigned int)d_cont.size();
49f076e8 132 }
30ee601a 133
96e2f64f 134 const cont_t& getThrottleMap() const
135 {
136 return d_cont;
c1e20fba 137 }
138
30ee601a
RG
139 void clear()
140 {
141 d_cont.clear();
142 }
c1e20fba 143
49f076e8 144private:
b747bce8
AT
145 unsigned int d_limit;
146 time_t d_ttl;
49f076e8 147 time_t d_last_clean;
49f076e8
BH
148 cont_t d_cont;
149};
150
151
eefd15f9 152/** Class that implements a decaying EWMA.
36c5ee42 153 This class keeps an exponentially weighted moving average which, additionally, decays over time.
eefd15f9
BH
154 The decaying is only done on get.
155*/
156class DecayingEwma
157{
158public:
3ddb9247 159 DecayingEwma() : d_val(0.0)
71dea98d
BH
160 {
161 d_needinit=true;
118dcc93 162 d_last.tv_sec = d_last.tv_usec = 0;
71dea98d 163 d_lastget=d_last;
36c5ee42 164 }
d6d5dea7 165
71dea98d 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)
eefd15f9 167 {
71dea98d 168 }
d6d5dea7 169
a712cb56 170 void submit(int val, const struct timeval* tv)
71dea98d 171 {
a712cb56 172 struct timeval now=*tv;
71dea98d
BH
173
174 if(d_needinit) {
175 d_last=now;
21f0f88b 176 d_lastget=now;
71dea98d 177 d_needinit=false;
21f0f88b 178 d_val = val;
71dea98d 179 }
21f0f88b
BH
180 else {
181 float diff= makeFloat(d_last - now);
71dea98d 182
21f0f88b
BH
183 d_last=now;
184 double factor=exp(diff)/2.0; // might be '0.5', or 0.0001
3ddb9247 185 d_val=(float)((1-factor)*val+ (float)factor*d_val);
21f0f88b 186 }
eefd15f9 187 }
d6d5dea7 188
a712cb56 189 double get(const struct timeval* tv)
71dea98d 190 {
a712cb56 191 struct timeval now=*tv;
71dea98d 192 float diff=makeFloat(d_lastget-now);
36c5ee42 193 d_lastget=now;
705f31ae 194 float factor=exp(diff/60.0f); // is 1.0 or less
eefd15f9
BH
195 return d_val*=factor;
196 }
197
30ee601a 198 double peek(void) const
a82ce718
PD
199 {
200 return d_val;
201 }
202
996c89cc 203 bool stale(time_t limit) const
9fdf67d5 204 {
71dea98d 205 return limit > d_lastget.tv_sec;
9fdf67d5
BH
206 }
207
eefd15f9 208private:
71dea98d
BH
209 struct timeval d_last; // stores time
210 struct timeval d_lastget; // stores time
211 float d_val;
212 bool d_needinit;
213};
214
628e2c7b
PA
215template<class Thing> class Counters : public boost::noncopyable
216{
217public:
218 Counters()
219 {
220 }
30ee601a 221 unsigned long value(const Thing& t) const
628e2c7b 222 {
30ee601a 223 typename cont_t::const_iterator i=d_cont.find(t);
628e2c7b
PA
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 }
30ee601a
RG
262 void clear()
263 {
264 d_cont.clear();
265 }
266 size_t size() const
406f46f9 267 {
268 return d_cont.size();
269 }
628e2c7b
PA
270private:
271 typedef map<Thing,unsigned long> cont_t;
272 cont_t d_cont;
273};
274
71dea98d 275
bb4bdbaf 276class SyncRes : public boost::noncopyable
00a19ff7
BH
277{
278public:
3ddb9247 279 enum LogMode { LogNone, Log, Store};
0bd2e252 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;
77499b05 281
a712cb56
RG
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 {
0e4675a9 296 d_collection[remote].submit(usecs, now);
a712cb56
RG
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;
0e4675a9
RG
305 for (auto& entry : d_collection) {
306 if((tmp = entry.second.get(now)) < ret) {
a712cb56 307 ret=tmp;
0e4675a9 308 d_best=entry.first;
a712cb56
RG
309 }
310 }
311
312 return ret;
313 }
314
315 bool stale(time_t limit) const
316 {
0e4675a9
RG
317 for(const auto& entry : d_collection)
318 if(!entry.second.stale(limit))
a712cb56
RG
319 return false;
320 return true;
321 }
322
0e4675a9
RG
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;
a712cb56
RG
336 collection_t d_collection;
337 ComboAddress d_best;
338 };
339
340 typedef map<DNSName, DecayingEwmaCollection> nsspeeds_t;
341 typedef map<ComboAddress, EDNSStatus> ednsstatus_t;
342
1e332f68
PL
343 vState getDSRecords(const DNSName& zone, dsmap_t& ds, bool onlyTA, unsigned int depth, bool bogusOnNXD=true, bool* foundCut=nullptr);
344
3337c2f7 345 class AuthDomain
a712cb56 346 {
3337c2f7 347 public:
a712cb56
RG
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;
3337c2f7 360
a712cb56 361 records_t d_records;
3337c2f7
RG
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;
a712cb56
RG
386 };
387
388 typedef 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
9065eb05
RG
401 static void setDefaultLogMode(LogMode lm)
402 {
403 s_lm = lm;
404 }
addde5c1 405 static uint64_t doEDNSDump(int fd);
9065eb05 406 static uint64_t doDumpNSSpeeds(int fd);
c1e20fba 407 static uint64_t doDumpThrottleMap(int fd);
9065eb05
RG
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());
bb4bdbaf 421
9065eb05
RG
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);
2fe3354d
CH
436 static void parseEDNSSubnetAddFor(const std::string& subnetlist);
437 static void addEDNSLocalSubnet(const std::string& subnet)
9065eb05 438 {
2fe3354d
CH
439 s_ednslocalsubnets.addMask(subnet);
440 }
441 static void addEDNSRemoteSubnet(const std::string& subnet)
442 {
443 s_ednsremotesubnets.addMask(subnet);
9065eb05
RG
444 }
445 static void addEDNSDomain(const DNSName& domain)
446 {
447 s_ednsdomains.add(domain);
448 }
2fe3354d 449 static void clearEDNSLocalSubnets()
9065eb05 450 {
2fe3354d
CH
451 s_ednslocalsubnets.clear();
452 }
453 static void clearEDNSRemoteSubnets()
454 {
455 s_ednsremotesubnets.clear();
9065eb05
RG
456 }
457 static void clearEDNSDomains()
458 {
459 s_ednsdomains = SuffixMatchNode();
460 }
a712cb56
RG
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 }
9065eb05 562
8a3a3822
RG
563 static void setECSScopeZeroAddress(const Netmask& scopeZeroMask)
564 {
565 s_ecsScopeZero.source = scopeZeroMask;
566 }
567
c9783016
RG
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
9065eb05 582 explicit SyncRes(const struct timeval& now);
30ee601a 583
e325f20c 584 int beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret);
c836dc19
BH
585 void setId(int id)
586 {
77499b05 587 if(doLog())
9fdf67d5 588 d_prefix="["+itoa(id)+"] ";
c836dc19 589 }
3ddb9247
PD
590
591 void setLogMode(LogMode lm)
77499b05
BH
592 {
593 d_lm = lm;
594 }
595
69cbdef9 596 bool doLog() const
c836dc19 597 {
3ddb9247 598 return d_lm != LogNone;
c836dc19 599 }
77499b05 600
c836dc19
BH
601 void setCacheOnly(bool state=true)
602 {
603 d_cacheonly=state;
604 }
2188dcc3
BH
605
606 void setDoEDNS0(bool state=true)
607 {
608 d_doEDNS0=state;
609 }
610
30ee601a
RG
611 void setDoDNSSEC(bool state=true)
612 {
613 d_doDNSSEC=state;
614 }
615
0c43f455
RG
616 void setDNSSECValidationRequested(bool requested=true)
617 {
618 d_DNSSECValidationRequested = requested;
619 }
620
621 bool isDNSSECValidationRequested() const
622 {
623 return d_DNSSECValidationRequested;
624 }
625
e1636f82
RG
626 bool shouldValidate() const
627 {
628 return d_DNSSECValidationRequested && !d_wasOutOfBand;
629 }
630
30ee601a
RG
631 void setWantsRPZ(bool state=true)
632 {
633 d_wantsRPZ=state;
634 }
635
636 bool getWantsRPZ() const
637 {
638 return d_wantsRPZ;
639 }
640
77499b05
BH
641 string getTrace() const
642 {
643 return d_trace.str();
644 }
645
a3e7b735 646 void setLuaEngine(shared_ptr<RecursorLua4> pdl)
3457a2a0 647 {
648 d_pdl = pdl;
649 }
650
3762e821 651 bool wasVariable() const
652 {
653 return d_wasVariable;
654 }
3457a2a0 655
9fc36e90
PL
656 bool wasOutOfBand() const
657 {
658 return d_wasOutOfBand;
659 }
660
30ee601a
RG
661 struct timeval getNow() const
662 {
663 return d_now;
664 }
665
a672e9de
PL
666 void setSkipCNAMECheck(bool skip = false)
667 {
668 d_skipCNAMECheck = skip;
669 }
670
2fe3354d 671 void setQuerySource(const ComboAddress& requestor, boost::optional<const EDNSSubnetOpts&> incomingECS);
30ee601a
RG
672
673#ifdef HAVE_PROTOBUF
674 void setInitialRequestId(boost::optional<const boost::uuids::uuid&> initialRequestId)
675 {
676 d_initialRequestId = initialRequestId;
677 }
63341e8d 678
3fe06137 679 void setOutgoingProtobufServers(std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& servers)
63341e8d 680 {
b773359c 681 d_outgoingProtobufServers = servers;
63341e8d 682 }
30ee601a
RG
683#endif
684
b9fa43e0 685#ifdef HAVE_FSTRM
10ba6d01 686 void setFrameStreamServers(std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& servers)
b9fa43e0
OM
687 {
688 d_frameStreamServers = servers;
689 }
690#endif /* HAVE_FSTRM */
691
30ee601a
RG
692 void setAsyncCallback(asyncresolve_t func)
693 {
694 d_asyncResolve = func;
695 }
3ddb9247 696
4d2be65d
RG
697 vState getValidationState() const
698 {
699 return d_queryValidationState;
700 }
701
a712cb56
RG
702 static thread_local ThreadLocalStorage t_sstorage;
703
aebb81e4 704 static std::atomic<uint64_t> s_queries;
705 static std::atomic<uint64_t> s_outgoingtimeouts;
706 static std::atomic<uint64_t> s_outgoing4timeouts;
707 static std::atomic<uint64_t> s_outgoing6timeouts;
708 static std::atomic<uint64_t> s_throttledqueries;
709 static std::atomic<uint64_t> s_dontqueries;
e9a628a2 710 static std::atomic<uint64_t> s_authzonequeries;
aebb81e4 711 static std::atomic<uint64_t> s_outqueries;
712 static std::atomic<uint64_t> s_tcpoutqueries;
713 static std::atomic<uint64_t> s_nodelegated;
714 static std::atomic<uint64_t> s_unreachables;
d6923beb 715 static std::atomic<uint64_t> s_ecsqueries;
716 static std::atomic<uint64_t> s_ecsresponses;
c9783016
RG
717 static std::map<uint8_t, std::atomic<uint64_t>> s_ecsResponsesBySubnetSize4;
718 static std::map<uint8_t, std::atomic<uint64_t>> s_ecsResponsesBySubnetSize6;
9065eb05 719
9065eb05
RG
720 static string s_serverID;
721 static unsigned int s_minimumTTL;
5cf4b2e7 722 static unsigned int s_minimumECSTTL;
9065eb05
RG
723 static unsigned int s_maxqperq;
724 static unsigned int s_maxtotusec;
725 static unsigned int s_maxdepth;
a9af3782 726 static unsigned int s_maxnegttl;
b9473937 727 static unsigned int s_maxbogusttl;
c3e753c7 728 static unsigned int s_maxcachettl;
1051f8a9
BH
729 static unsigned int s_packetcachettl;
730 static unsigned int s_packetcacheservfailttl;
628e2c7b
PA
731 static unsigned int s_serverdownmaxfails;
732 static unsigned int s_serverdownthrottletime;
e7861cc4 733 static unsigned int s_ecscachelimitttl;
e9f9b8ec
RG
734 static uint8_t s_ecsipv4limit;
735 static uint8_t s_ecsipv6limit;
fd8898fb 736 static uint8_t s_ecsipv4cachelimit;
737 static uint8_t s_ecsipv6cachelimit;
9065eb05
RG
738 static bool s_doIPv6;
739 static bool s_noEDNSPing;
740 static bool s_noEDNS;
741 static bool s_rootNXTrust;
1051f8a9 742 static bool s_nopacketcache;
3ddb9247 743
a712cb56
RG
744 std::unordered_map<std::string,bool> d_discardedPolicies;
745 DNSFilterEngine::Policy d_appliedPolicy;
f7b8cffa 746 unsigned int d_authzonequeries;
a712cb56
RG
747 unsigned int d_outqueries;
748 unsigned int d_tcpoutqueries;
749 unsigned int d_throttledqueries;
750 unsigned int d_timeouts;
751 unsigned int d_unreachables;
752 unsigned int d_totUsec;
49a699c4 753
00a19ff7 754private:
2fe3354d
CH
755 ComboAddress d_requestor;
756 ComboAddress d_cacheRemote;
a712cb56 757
9065eb05 758 static std::unordered_set<DNSName> s_delegationOnly;
2fe3354d
CH
759 static NetmaskGroup s_ednslocalsubnets;
760 static NetmaskGroup s_ednsremotesubnets;
9065eb05 761 static SuffixMatchNode s_ednsdomains;
8a3a3822 762 static EDNSSubnetOpts s_ecsScopeZero;
9065eb05
RG
763 static LogMode s_lm;
764 static std::unique_ptr<NetmaskGroup> s_dontQuery;
123da0f8 765 const static std::unordered_set<uint16_t> s_redirectionQTypes;
9065eb05
RG
766
767 struct GetBestNSAnswer
768 {
769 DNSName qname;
770 set<pair<DNSName,DNSName> > bestns;
771 uint8_t qtype; // only A and AAAA anyhow
772 bool operator<(const GetBestNSAnswer &b) const
773 {
774 return boost::tie(qname, qtype, bestns) <
775 boost::tie(b.qname, b.qtype, b.bestns);
776 }
777 };
778
70b3fe7a
RG
779 typedef std::map<DNSName,vState> zonesStates_t;
780
fa1b87ff 781 int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret,
51b6b728 782 unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state);
6dfff36f 783 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);
51b6b728 784 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);
6dfff36f 785
51b6b728 786 int doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state);
f7b8cffa 787 bool doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res);
7c3398aa 788 bool doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res);
69cbdef9 789 domainmap_t::const_iterator getBestAuthZone(DNSName* qname) const;
ad797d94
RG
790 bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse);
791 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);
7c3398aa
RG
792 void getBestNSFromCache(const DNSName &qname, const QType &qtype, vector<DNSRecord>&bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere);
793 DNSName getBestNSNamesFromCache(const DNSName &qname, const QType &qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere);
c5c066bf 794
feccaf7f 795 inline vector<std::pair<DNSName, double>> shuffleInSpeedOrder(NsSet &nameservers, const string &prefix);
cc11d7f4 796 inline vector<ComboAddress> shuffleForwardSpeed(const vector<ComboAddress> &rnameservers, const string &prefix, const bool wasRd);
69cbdef9 797 bool moreSpecificThan(const DNSName& a, const DNSName &b) const;
b4c8789a 798 vector<ComboAddress> getAddrs(const DNSName &qname, unsigned int depth, set<GetBestNSAnswer>& beenthere, bool cacheOnly);
26ca3513 799
69cbdef9
RG
800 bool nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers);
801 bool nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress&);
26ca3513
RG
802 bool throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery);
803
feccaf7f 804 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);
7155c3e5
RG
805
806 void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
78cdf520
RG
807 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);
808 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);
26ca3513 809
6dfff36f 810 bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret);
db50a7f4 811
deca7d8f 812 int asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res, bool* chained) const;
30ee601a 813
2fe3354d 814 boost::optional<Netmask> getEDNSSubnetMask(const DNSName&dn, const ComboAddress& rem);
e9f9b8ec 815
4d2be65d 816 bool validationEnabled() const;
4d2be65d
RG
817 uint32_t computeLowestTTD(const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, uint32_t signaturesTTL) const;
818 void updateValidationState(vState& state, const vState stateUpdate);
51b6b728
RG
819 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);
820 vState validateDNSKeys(const DNSName& zone, const std::vector<DNSRecord>& dnskeys, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, unsigned int depth);
51b6b728 821 vState getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth);
28364e4b
RG
822 dState getDenialValidationState(const NegCache::NegCacheEntry& ne, const vState state, const dState expectedState, bool referralToUnsigned);
823 void updateDenialValidationState(vState& neValidationState, const DNSName& neName, vState& state, const dState denialState, const dState expectedState, bool allowOptOut);
824 void computeNegCacheValidationStatus(const NegCache::NegCacheEntry* ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth);
4d2be65d 825 vState getTA(const DNSName& zone, dsmap_t& ds);
0735b60f 826 bool haveExactValidationStatus(const DNSName& domain);
5374b03b 827 vState getValidationStatus(const DNSName& subdomain, bool allowIndeterminate=true);
b9473937 828 void updateValidationStatusInCache(const DNSName &qname, const QType& qt, bool aa, vState newState) const;
70b3fe7a 829
c405e222 830 bool lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState);
51b6b728 831 void computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth);
4d2be65d 832
0b29b9c5
RG
833 void setUpdatingRootNS()
834 {
835 d_updatingRootNS = true;
836 }
837
51b6b728 838 zonesStates_t d_cutStates;
77499b05 839 ostringstream d_trace;
a3e7b735 840 shared_ptr<RecursorLua4> d_pdl;
2fe3354d 841 boost::optional<Netmask> d_outgoingECSNetwork;
3fe06137 842 std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>> d_outgoingProtobufServers{nullptr};
10ba6d01 843 std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>> d_frameStreamServers{nullptr};
30ee601a
RG
844#ifdef HAVE_PROTOBUF
845 boost::optional<const boost::uuids::uuid&> d_initialRequestId;
846#endif
847 asyncresolve_t d_asyncResolve{nullptr};
848 struct timeval d_now;
c836dc19 849 string d_prefix;
4d2be65d 850 vState d_queryValidationState{Indeterminate};
b88526ce
PL
851
852 /* When d_cacheonly is set to true, we will only check the cache.
853 * This is set when the RD bit is unset in the incoming query
854 */
c836dc19 855 bool d_cacheonly;
30ee601a 856 bool d_doDNSSEC;
0c43f455 857 bool d_DNSSECValidationRequested{false};
30ee601a 858 bool d_doEDNS0{true};
24bb9b58 859 bool d_requireAuthData{true};
30ee601a 860 bool d_skipCNAMECheck{false};
0b29b9c5 861 bool d_updatingRootNS{false};
30ee601a
RG
862 bool d_wantsRPZ{true};
863 bool d_wasOutOfBand{false};
864 bool d_wasVariable{false};
57769f13 865
77499b05 866 LogMode d_lm;
00a19ff7 867};
ac0e821b 868
5c633640 869class Socket;
a9af3782 870/* external functions, opaque to us */
5c633640 871int asendtcp(const string& data, Socket* sock);
a683e8bd 872int arecvtcp(string& data, size_t len, Socket* sock, bool incompleteOkay);
1d5b3ce6
BH
873
874
875struct PacketID
876{
825fa717 877 PacketID() : id(0), type(0), sock(0), inNeeded(0), inIncompleteOkay(false), outPos(0), nearMisses(0), fd(-1)
67770277 878 {
d38e2ba9 879 remote.reset();
67770277 880 }
1d5b3ce6
BH
881
882 uint16_t id; // wait for a specific id/remote pair
91ffe057 883 uint16_t type; // and this is its type
996c89cc 884 ComboAddress remote; // this is the remote
3ddb9247 885 DNSName domain; // this is the question
1d5b3ce6
BH
886
887 Socket* sock; // or wait for an event on a TCP fd
1d5b3ce6 888 string inMSG; // they'll go here
a683e8bd 889 size_t inNeeded; // if this is set, we'll read until inNeeded bytes are read
825fa717 890 bool inIncompleteOkay;
1d5b3ce6
BH
891
892 string outMSG; // the outgoing message that needs to be sent
893 string::size_type outPos; // how far we are along in the outMSG
894
96f81a93
BH
895 typedef set<uint16_t > chain_t;
896 mutable chain_t chain;
91ffe057 897 mutable uint32_t nearMisses; // number of near misses - host correct, id wrong
4ef015cd 898 int fd;
35ce8576 899
1d5b3ce6
BH
900 bool operator<(const PacketID& b) const
901 {
902 int ourSock= sock ? sock->getHandle() : 0;
903 int bSock = b.sock ? b.sock->getHandle() : 0;
787e5eab 904 if( tie(remote, ourSock, type) < tie(b.remote, bSock, b.type))
0d5f0a9f 905 return true;
787e5eab 906 if( tie(remote, ourSock, type) > tie(b.remote, bSock, b.type))
0d5f0a9f
BH
907 return false;
908
c5c066bf 909 return tie(domain, fd, id) < tie(b.domain, b.fd, b.id);
1d5b3ce6
BH
910 }
911};
912
3ddb9247 913struct PacketIDBirthdayCompare: public std::binary_function<PacketID, PacketID, bool>
96f81a93
BH
914{
915 bool operator()(const PacketID& a, const PacketID& b) const
916 {
917 int ourSock= a.sock ? a.sock->getHandle() : 0;
918 int bSock = b.sock ? b.sock->getHandle() : 0;
787e5eab 919 if( tie(a.remote, ourSock, a.type) < tie(b.remote, bSock, b.type))
96f81a93 920 return true;
787e5eab 921 if( tie(a.remote, ourSock, a.type) > tie(b.remote, bSock, b.type))
96f81a93
BH
922 return false;
923
72849e12 924 return a.domain < b.domain;
96f81a93
BH
925 }
926};
f26bf547
RG
927extern thread_local std::unique_ptr<MemRecursorCache> t_RC;
928extern thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
d2392145 929typedef MTasker<PacketID,string> MT_t;
f165a1f4 930MT_t* getMT();
1d5b3ce6
BH
931
932struct RecursorStats
933{
aebb81e4 934 std::atomic<uint64_t> servFails;
935 std::atomic<uint64_t> nxDomains;
936 std::atomic<uint64_t> noErrors;
937 std::atomic<uint64_t> answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow;
938 std::atomic<uint64_t> auth4Answers0_1, auth4Answers1_10, auth4Answers10_100, auth4Answers100_1000, auth4AnswersSlow;
939 std::atomic<uint64_t> auth6Answers0_1, auth6Answers1_10, auth6Answers10_100, auth6Answers100_1000, auth6AnswersSlow;
19178da9 940 std::atomic<uint64_t> ourtime0_1, ourtime1_2, ourtime2_4, ourtime4_8, ourtime8_16, ourtime16_32, ourtimeSlow;
941 double avgLatencyUsec{0};
942 double avgLatencyOursUsec{0};
aebb81e4 943 std::atomic<uint64_t> qcounter; // not increased for unauth packets
944 std::atomic<uint64_t> ipv6qcounter;
945 std::atomic<uint64_t> tcpqcounter;
946 std::atomic<uint64_t> unauthorizedUDP; // when this is increased, qcounter isn't
947 std::atomic<uint64_t> unauthorizedTCP; // when this is increased, qcounter isn't
948 std::atomic<uint64_t> policyDrops;
949 std::atomic<uint64_t> tcpClientOverflow;
950 std::atomic<uint64_t> clientParseError;
951 std::atomic<uint64_t> serverParseError;
952 std::atomic<uint64_t> tooOldDrops;
ba892c7f 953 std::atomic<uint64_t> truncatedDrops;
cf8cda18 954 std::atomic<uint64_t> queryPipeFullDrops;
aebb81e4 955 std::atomic<uint64_t> unexpectedCount;
956 std::atomic<uint64_t> caseMismatchCount;
957 std::atomic<uint64_t> spoofCount;
958 std::atomic<uint64_t> resourceLimits;
959 std::atomic<uint64_t> overCapacityDrops;
960 std::atomic<uint64_t> ipv6queries;
961 std::atomic<uint64_t> chainResends;
962 std::atomic<uint64_t> nsSetInvalidations;
963 std::atomic<uint64_t> ednsPingMatches;
964 std::atomic<uint64_t> ednsPingMismatches;
965 std::atomic<uint64_t> noPingOutQueries, noEdnsOutQueries;
966 std::atomic<uint64_t> packetCacheHits;
967 std::atomic<uint64_t> noPacketError;
968 std::atomic<uint64_t> ignoredCount;
c0f9be19 969 std::atomic<uint64_t> emptyQueriesCount;
5e3de507 970 time_t startupTime;
aebb81e4 971 std::atomic<uint64_t> dnssecQueries;
88c33dca
RG
972 std::atomic<uint64_t> dnssecAuthenticDataQueries;
973 std::atomic<uint64_t> dnssecCheckDisabledQueries;
49dc532e 974 std::atomic<uint64_t> variableResponses;
ec6eacbc 975 unsigned int maxMThreadStackUsage;
849fe8d2
PL
976 std::atomic<uint64_t> dnssecValidations; // should be the sum of all dnssecResult* stats
977 std::map<vState, std::atomic<uint64_t> > dnssecResults;
7a25883a 978 std::map<DNSFilterEngine::PolicyKind, std::atomic<uint64_t> > policyResults;
596bf482 979 std::atomic<uint64_t> rebalancedQueries{0};
b3b5459d 980};
996c89cc 981
0e408828 982//! represents a running TCP/IP client session
cd989c87 983class TCPConnection : public boost::noncopyable
0e408828 984{
50a5ef72 985public:
cd989c87
BH
986 TCPConnection(int fd, const ComboAddress& addr);
987 ~TCPConnection();
3ddb9247 988
30ee601a 989 int getFD() const
cd989c87
BH
990 {
991 return d_fd;
992 }
2749c3fe
RG
993
994 std::string data;
995 const ComboAddress d_remote;
996 size_t queriesCount{0};
b841314c
RG
997 enum stateenum {BYTE0, BYTE1, GETQUESTION, DONE} state{BYTE0};
998 uint16_t qlen{0};
999 uint16_t bytesread{0};
0e408828 1000
50a5ef72 1001 static unsigned int getCurrentConnections() { return s_currentConnections; }
50a5ef72 1002private:
cd989c87 1003 const int d_fd;
1bc9e6bd 1004 static AtomicCounter s_currentConnections; //!< total number of current TCP connections
0e408828
BH
1005};
1006
44971ca0
PD
1007class ImmediateServFailException
1008{
1009public:
8a70e507 1010 ImmediateServFailException(string r) : reason(r) {};
44971ca0
PD
1011
1012 string reason; //! Print this to tell the user what went wrong
1013};
0e408828 1014
f635ed7b 1015typedef boost::circular_buffer<ComboAddress> addrringbuf_t;
621ccf89 1016extern thread_local std::unique_ptr<addrringbuf_t> t_servfailremotes, t_largeanswerremotes, t_remotes, t_bogusremotes, t_timeouts;
a9af3782 1017
66f2e6ad 1018extern thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName,uint16_t> > > t_queryring, t_servfailqueryring, t_bogusqueryring;
f26bf547 1019extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
674cf0f6 1020string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end);
77499b05 1021string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end);
18af64a8 1022void parseACLs();
1d5b3ce6 1023extern RecursorStats g_stats;
a512e3d1 1024extern unsigned int g_networkTimeoutMsec;
c3828c03 1025extern unsigned int g_numThreads;
b33c2462 1026extern uint16_t g_outgoingEDNSBufsize;
a6f7f5fe 1027extern std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries;
c1c29961 1028extern bool g_lowercaseOutgoing;
12ce523e 1029
1030
ee1ada80 1031std::string reloadAuthAndForwards();
c1d73d94 1032ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
1652a63e 1033ComboAddress getQueryLocalAddress(int family, uint16_t port);
3427fa8a 1034typedef boost::function<void*(void)> pipefunc_t;
b4e76a18 1035void broadcastFunction(const pipefunc_t& func);
8171ab83 1036void distributeAsyncFunction(const std::string& question, const pipefunc_t& func);
3427fa8a 1037
e325f20c 1038int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret);
3427fa8a 1039
b4e76a18 1040template<class T> T broadcastAccFunction(const boost::function<T*()>& func);
3427fa8a 1041
9065eb05 1042std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards();
13034931
BH
1043uint64_t* pleaseGetNsSpeedsSize();
1044uint64_t* pleaseGetCacheSize();
1045uint64_t* pleaseGetNegCacheSize();
1046uint64_t* pleaseGetCacheHits();
1047uint64_t* pleaseGetCacheMisses();
1048uint64_t* pleaseGetConcurrentQueries();
1049uint64_t* pleaseGetThrottleSize();
16beeaa4
BH
1050uint64_t* pleaseGetPacketCacheHits();
1051uint64_t* pleaseGetPacketCacheSize();
86f3ca51 1052uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree=false);
1053uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree);
1054uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree=false);
2c78bd57 1055void doCarbonDump(void*);
9065eb05 1056void primeHints(void);
795215f2 1057
f703f766 1058extern __thread struct timeval g_now;
5ac6d761 1059
1060struct ThreadTimes
1061{
1062 uint64_t msec;
1063 vector<uint64_t> times;
1064 ThreadTimes& operator+=(const ThreadTimes& rhs)
1065 {
1066 times.push_back(rhs.msec);
1067 return *this;
1068 }
1069};