]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist.hh
dnsdist: Add support for sharding the packet cache
[thirdparty/pdns.git] / pdns / dnsdist.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 */
df111b53 22#pragma once
11e1e08b 23#include "config.h"
df111b53 24#include "ext/luawrapper/include/LuaContext.hpp"
25#include <time.h>
26#include "misc.hh"
27#include "iputils.hh"
28#include "dnsname.hh"
29#include <atomic>
30#include <boost/circular_buffer.hpp>
e16fd59c 31#include <boost/variant.hpp>
df111b53 32#include <mutex>
33#include <thread>
bffca8b9 34#include <unistd.h>
ecbe9133 35#include "sholder.hh"
11e1e08b 36#include "dnscrypt.hh"
886e2cf2 37#include "dnsdist-cache.hh"
85c7ca75 38#include "gettime.hh"
87b515ed
RG
39#include "dnsdist-dynbpf.hh"
40#include "bpf-filter.hh"
26a6373d
SO
41#include <string>
42#include <unordered_map>
26a6373d
SO
43
44
d8c19b98
RG
45#ifdef HAVE_PROTOBUF
46#include <boost/uuid/uuid.hpp>
47#include <boost/uuid/uuid_generators.hpp>
48#endif
49
42fae326 50void* carbonDumpThread();
61d1b966 51uint64_t uptimeOfProcess(const std::string& str);
bd1c631b 52
7b925432
RG
53extern uint16_t g_ECSSourcePrefixV4;
54extern uint16_t g_ECSSourcePrefixV6;
55extern bool g_ECSOverride;
56
26a6373d 57
26a6373d
SO
58class QTag
59{
26a6373d 60public:
5b8255ba
RG
61 QTag()
62 {
63 }
26a6373d 64
5b8255ba
RG
65 ~QTag()
66 {
67 }
26a6373d 68
5b8255ba
RG
69 void add(const std::string strLabel, const std::string strValue)
70 {
71 tagData.insert( {strLabel, strValue});
72 return;
741ebe08 73 }
26a6373d 74
5b8255ba
RG
75 std::string getMatch(const std::string& strLabel) const
76 {
77 std::unordered_map<std::string, std::string>::const_iterator got =tagData.find (strLabel);
78 if(got == tagData.end()) {
79 return "";
80 } else {
81 return got->second;
741ebe08
SO
82 }
83 }
e6956c91 84
5b8255ba
RG
85 std::string getEntry(size_t iEntry) const
86 {
87 std::string strEntry;
88 size_t iCounter = 0;
89
90 for (const auto& itr : tagData) {
91 iCounter++;
92 if(iCounter == iEntry) {
93 strEntry = itr.first;
94 strEntry += strSep;
95 strEntry += itr.second;
96 break;
97 }
98 }
26a6373d 99
5b8255ba
RG
100 return strEntry;
101 }
26a6373d 102
5b8255ba
RG
103 size_t count() const
104 {
105 return tagData.size();
106 }
26a6373d 107
5b8255ba
RG
108 std::string dumpString() const
109 {
110 std::string strRet;
e6956c91 111
5b8255ba
RG
112 for (const auto& itr : tagData) {
113 strRet += itr.first;
114 strRet += strSep;
115 strRet += itr.second;
116 strRet += "\n";
117 }
118 return strRet;
741ebe08 119 }
26a6373d 120
29cd61cc 121 std::unordered_map<std::string, std::string>tagData;
26a6373d
SO
122
123private:
c959e01a 124 static constexpr char const *strSep = "\t";
26a6373d
SO
125};
126
26a6373d 127
7b925432
RG
128struct DNSQuestion
129{
130 DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp): qname(name), qtype(type), qclass(class_), local(lc), remote(rem), dh(header), size(bufferSize), len(queryLen), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tcp(isTcp), ecsOverride(g_ECSOverride) { }
131
132#ifdef HAVE_PROTOBUF
133 boost::uuids::uuid uniqueId;
134#endif
135 const DNSName* qname;
136 const uint16_t qtype;
137 const uint16_t qclass;
138 const ComboAddress* local;
139 const ComboAddress* remote;
e6956c91 140 std::shared_ptr<QTag> qTag;
7b925432
RG
141 struct dnsheader* dh;
142 size_t size;
143 uint16_t len;
144 uint16_t ecsPrefixLength;
145 const bool tcp;
146 bool skipCache{false};
147 bool ecsOverride;
5b8255ba 148 bool useECS{true};
7b925432
RG
149};
150
151struct DNSResponse : DNSQuestion
152{
2b3eefc3 153 DNSResponse(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t responseLen, bool isTcp, const struct timespec* queryTime_): DNSQuestion(name, type, class_, lc, rem, header, bufferSize, responseLen, isTcp), queryTime(queryTime_) { }
7b925432
RG
154
155 const struct timespec* queryTime;
156};
157
158/* so what could you do:
159 drop,
160 fake up nxdomain,
161 provide actual answer,
162 allow & and stop processing,
163 continue processing,
164 modify header: (servfail|refused|notimp), set TC=1,
165 send to pool */
166
167class DNSAction
168{
169public:
c4f5aeff 170 enum class Action { Drop, Nxdomain, Refused, Spoof, Allow, HeaderModify, Pool, Delay, Truncate, None};
7b925432 171 virtual Action operator()(DNSQuestion*, string* ruleresult) const =0;
205f2081
RG
172 virtual ~DNSAction()
173 {
174 }
7b925432
RG
175 virtual string toString() const = 0;
176 virtual std::unordered_map<string, double> getStats() const
177 {
178 return {{}};
179 }
180};
181
182class DNSResponseAction
183{
184public:
185 enum class Action { Allow, Delay, Drop, HeaderModify, None };
186 virtual Action operator()(DNSResponse*, string* ruleresult) const =0;
205f2081
RG
187 virtual ~DNSResponseAction()
188 {
189 }
7b925432
RG
190 virtual string toString() const = 0;
191};
192
78ffa782 193struct DynBlock
194{
195 DynBlock& operator=(const DynBlock& rhs)
196 {
197 reason=rhs.reason;
198 until=rhs.until;
71c94675 199 domain=rhs.domain;
7b925432 200 action=rhs.action;
78ffa782 201 blocks.store(rhs.blocks);
202 return *this;
203 }
71c94675 204
78ffa782 205 string reason;
206 struct timespec until;
71c94675 207 DNSName domain;
7b925432 208 DNSAction::Action action;
78ffa782 209 mutable std::atomic<unsigned int> blocks;
210};
211
212extern GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
f758857a 213
214extern vector<pair<struct timeval, std::string> > g_confDelta;
215
e48090d1 216struct DNSDistStats
217{
6ad8b29a 218 using stat_t=std::atomic<uint64_t>; // aww yiss ;-)
e48090d1 219 stat_t responses{0};
220 stat_t servfailResponses{0};
221 stat_t queries{0};
e73ec7d3 222 stat_t nonCompliantQueries{0};
d08b1cdf 223 stat_t nonCompliantResponses{0};
643a182a 224 stat_t rdQueries{0};
2efd427d 225 stat_t emptyQueries{0};
e48090d1 226 stat_t aclDrops{0};
bd1c631b 227 stat_t dynBlocked{0};
e48090d1 228 stat_t ruleDrop{0};
229 stat_t ruleNXDomain{0};
dd46e5e3 230 stat_t ruleRefused{0};
e48090d1 231 stat_t selfAnswered{0};
232 stat_t downstreamTimeouts{0};
233 stat_t downstreamSendErrors{0};
6ad8b29a 234 stat_t truncFail{0};
b8bc7e61 235 stat_t noPolicy{0};
886e2cf2
RG
236 stat_t cacheHits{0};
237 stat_t cacheMisses{0};
42fae326 238 stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0};
e48090d1 239
e16fd59c 240 double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
a1a787dc 241 typedef std::function<uint64_t(const std::string&)> statfunction_t;
242 typedef boost::variant<stat_t*, double*, statfunction_t> entry_t;
e16fd59c 243 std::vector<std::pair<std::string, entry_t>> entries{
dd46e5e3
RG
244 {"responses", &responses},
245 {"servfail-responses", &servfailResponses},
246 {"queries", &queries},
247 {"acl-drops", &aclDrops},
dd46e5e3
RG
248 {"rule-drop", &ruleDrop},
249 {"rule-nxdomain", &ruleNXDomain},
250 {"rule-refused", &ruleRefused},
251 {"self-answered", &selfAnswered},
252 {"downstream-timeouts", &downstreamTimeouts},
253 {"downstream-send-errors", &downstreamSendErrors},
254 {"trunc-failures", &truncFail},
255 {"no-policy", &noPolicy},
256 {"latency0-1", &latency0_1},
257 {"latency1-10", &latency1_10},
258 {"latency10-50", &latency10_50},
259 {"latency50-100", &latency50_100},
260 {"latency100-1000", &latency100_1000},
261 {"latency-slow", &latencySlow},
262 {"latency-avg100", &latencyAvg100},
263 {"latency-avg1000", &latencyAvg1000},
264 {"latency-avg10000", &latencyAvg10000},
265 {"latency-avg1000000", &latencyAvg1000000},
61d1b966 266 {"uptime", uptimeOfProcess},
a9b6db56 267 {"real-memory-usage", getRealMemoryUsage},
a2aa00ed 268 {"noncompliant-queries", &nonCompliantQueries},
d08b1cdf 269 {"noncompliant-responses", &nonCompliantResponses},
643a182a 270 {"rdqueries", &rdQueries},
2efd427d 271 {"empty-queries", &emptyQueries},
886e2cf2
RG
272 {"cache-hits", &cacheHits},
273 {"cache-misses", &cacheMisses},
4f99f3d3
RG
274 {"cpu-user-msec", getCPUTimeUser},
275 {"cpu-sys-msec", getCPUTimeSystem},
dd46e5e3
RG
276 {"fd-usage", getOpenFileDescriptors},
277 {"dyn-blocked", &dynBlocked},
bd1c631b 278 {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }}
42fae326 279 };
e48090d1 280};
281
e16fd59c 282
e48090d1 283extern struct DNSDistStats g_stats;
284
638184e9 285
df111b53 286struct StopWatch
287{
58307a85
RG
288 StopWatch(bool realTime=false): d_needRealTime(realTime)
289 {
290 }
df111b53 291 struct timespec d_start{0,0};
58307a85
RG
292 bool d_needRealTime{false};
293
df111b53 294 void start() {
58307a85 295 if(gettime(&d_start, d_needRealTime) < 0)
df111b53 296 unixDie("Getting timestamp");
297
298 }
cf48b0ce
RG
299
300 void set(const struct timespec& from) {
301 d_start = from;
302 }
df111b53 303
304 double udiff() const {
305 struct timespec now;
58307a85 306 if(gettime(&now, d_needRealTime) < 0)
df111b53 307 unixDie("Getting timestamp");
308
309 return 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
310 }
311
312 double udiffAndSet() {
313 struct timespec now;
58307a85 314 if(gettime(&now, d_needRealTime) < 0)
df111b53 315 unixDie("Getting timestamp");
316
317 auto ret= 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
318 d_start = now;
319 return ret;
320 }
321
322};
323
324class QPSLimiter
325{
326public:
327 QPSLimiter()
328 {
329 }
330
331 QPSLimiter(unsigned int rate, unsigned int burst) : d_rate(rate), d_burst(burst), d_tokens(burst)
332 {
333 d_passthrough=false;
334 d_prev.start();
335 }
336
337 unsigned int getRate() const
338 {
339 return d_passthrough? 0 : d_rate;
340 }
341
342 int getPassed() const
343 {
344 return d_passed;
345 }
346 int getBlocked() const
347 {
348 return d_blocked;
349 }
350
ecbe9133 351 bool check() const // this is not quite fair
df111b53 352 {
353 if(d_passthrough)
354 return true;
355 auto delta = d_prev.udiffAndSet();
356
357 d_tokens += 1.0*d_rate * (delta/1000000.0);
358
359 if(d_tokens > d_burst)
360 d_tokens = d_burst;
361
362 bool ret=false;
363 if(d_tokens >= 1.0) { // we need this because burst=1 is weird otherwise
364 ret=true;
365 --d_tokens;
366 d_passed++;
367 }
368 else
369 d_blocked++;
370
371 return ret;
372 }
373private:
374 bool d_passthrough{true};
375 unsigned int d_rate;
376 unsigned int d_burst;
ecbe9133 377 mutable double d_tokens;
378 mutable StopWatch d_prev;
379 mutable unsigned int d_passed{0};
380 mutable unsigned int d_blocked{0};
df111b53 381};
382
b5b93e0b
RG
383struct ClientState;
384
df111b53 385struct IDState
386{
58307a85 387 IDState() : origFD(-1), sentTime(true), delayMsec(0) { origDest.sin4.sin_family = 0;}
df111b53 388 IDState(const IDState& orig)
389 {
390 origFD = orig.origFD;
391 origID = orig.origID;
392 origRemote = orig.origRemote;
549d63c9 393 origDest = orig.origDest;
7b3865cd 394 delayMsec = orig.delayMsec;
df111b53 395 age.store(orig.age.load());
396 }
397
2bf26975 398 int origFD; // set to <0 to indicate this state is empty // 4
399
400 ComboAddress origRemote; // 28
549d63c9 401 ComboAddress origDest; // 28
2bf26975 402 StopWatch sentTime; // 16
403 DNSName qname; // 80
11e1e08b
RG
404#ifdef HAVE_DNSCRYPT
405 std::shared_ptr<DnsCryptQuery> dnsCryptQuery{0};
d8c19b98
RG
406#endif
407#ifdef HAVE_PROTOBUF
408 boost::uuids::uuid uniqueId;
11e1e08b 409#endif
886e2cf2 410 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
b5b93e0b 411 const ClientState* cs{nullptr};
886e2cf2 412 uint32_t cacheKey; // 8
2bf26975 413 std::atomic<uint16_t> age; // 4
414 uint16_t qtype; // 2
886e2cf2 415 uint16_t qclass; // 2
2bf26975 416 uint16_t origID; // 2
aeb36780 417 uint16_t origFlags; // 2
7b3865cd 418 int delayMsec;
ca404e94 419 bool ednsAdded{false};
ff73f02b 420 bool ecsAdded{false};
886e2cf2 421 bool skipCache{false};
7cea4e39 422 bool destHarvested{false}; // if true, origDest holds the original dest addr, otherwise the listening addr
df111b53 423};
424
425struct Rings {
e4c24bb3 426 Rings(size_t capacity=10000)
df111b53 427 {
e4c24bb3
RG
428 queryRing.set_capacity(capacity);
429 respRing.set_capacity(capacity);
0e41337b 430 pthread_rwlock_init(&queryLock, 0);
df111b53 431 }
0ba5eecf 432 struct Query
433 {
434 struct timespec when;
435 ComboAddress requestor;
436 DNSName name;
03ebf8b2 437 uint16_t size;
0ba5eecf 438 uint16_t qtype;
3fcaeeac 439 struct dnsheader dh;
0ba5eecf 440 };
441 boost::circular_buffer<Query> queryRing;
df111b53 442 struct Response
443 {
80a216c9 444 struct timespec when;
445 ComboAddress requestor;
df111b53 446 DNSName name;
447 uint16_t qtype;
df111b53 448 unsigned int usec;
80a216c9 449 unsigned int size;
3fcaeeac 450 struct dnsheader dh;
2d11d1b2 451 ComboAddress ds; // who handled it
df111b53 452 };
453 boost::circular_buffer<Response> respRing;
454 std::mutex respMutex;
0e41337b 455 pthread_rwlock_t queryLock;
03ebf8b2 456
7fc00937 457 std::unordered_map<int, vector<boost::variant<string,double> > > getTopBandwidth(unsigned int numentries);
a683e8bd 458 size_t numDistinctRequestors();
e4c24bb3
RG
459 void setCapacity(size_t newCapacity)
460 {
461 {
462 WriteLock wl(&queryLock);
463 queryRing.set_capacity(newCapacity);
464 }
465 {
466 std::lock_guard<std::mutex> lock(respMutex);
467 respRing.set_capacity(newCapacity);
468 }
469 }
df111b53 470};
471
0e41337b 472extern Rings g_rings;
df111b53 473
786e4d8c
RS
474typedef std::unordered_map<string, unsigned int> QueryCountRecords;
475typedef std::function<std::tuple<bool, string>(DNSQuestion dq)> QueryCountFilter;
476struct QueryCount {
477 QueryCount()
478 {
479 pthread_rwlock_init(&queryLock, 0);
480 }
481 QueryCountRecords records;
482 QueryCountFilter filter;
483 pthread_rwlock_t queryLock;
484 bool enabled{false};
485};
486
487extern QueryCount g_qcount;
488
8a5d5053 489struct ClientState
490{
491 ComboAddress local;
11e1e08b
RG
492#ifdef HAVE_DNSCRYPT
493 DnsCryptContext* dnscryptCtx{0};
494#endif
963bef8d 495 std::atomic<uint64_t> queries{0};
a36ce055
RG
496 int udpFD{-1};
497 int tcpFD{-1};
b5b93e0b 498 bool muted{false};
8429ad04
RG
499
500 int getSocket() const
501 {
502 return udpFD != -1 ? udpFD : tcpFD;
503 }
504
505#ifdef HAVE_EBPF
506 shared_ptr<BPFFilter> d_filter;
507
508 void detachFilter()
509 {
510 if (d_filter) {
511 d_filter->removeSocket(getSocket());
512 d_filter = nullptr;
513 }
514 }
515
516 void attachFilter(shared_ptr<BPFFilter> bpf)
517 {
518 detachFilter();
519
520 bpf->addSocket(getSocket());
521 d_filter = bpf;
522 }
523#endif /* HAVE_EBPF */
8a5d5053 524};
525
526class TCPClientCollection {
527 std::vector<int> d_tcpclientthreads;
ded1985a 528 std::atomic<uint64_t> d_numthreads{0};
a9bf3ec4 529 std::atomic<uint64_t> d_pos{0};
ded1985a 530 std::atomic<uint64_t> d_queued{0};
6c1ca990 531 uint64_t d_maxthreads{0};
ded1985a 532 std::mutex d_mutex;
edbda1ad
RG
533 int d_singlePipe[2];
534 bool d_useSinglePipe;
ded1985a 535public:
8a5d5053 536
b79e4996
RG
537 TCPClientCollection(size_t maxThreads, bool useSinglePipe=false): d_maxthreads(maxThreads), d_singlePipe{-1,-1}, d_useSinglePipe(useSinglePipe)
538
8a5d5053 539 {
a9bf3ec4 540 d_tcpclientthreads.reserve(maxThreads);
edbda1ad
RG
541
542 if (d_useSinglePipe) {
543 if (pipe(d_singlePipe) < 0) {
544 throw std::runtime_error("Error creating the TCP single communication pipe: " + string(strerror(errno)));
545 }
546 if (!setNonBlocking(d_singlePipe[1])) {
547 int err = errno;
548 close(d_singlePipe[0]);
549 close(d_singlePipe[1]);
550 throw std::runtime_error("Error setting the TCP single communication pipe non-blocking: " + string(strerror(err)));
551 }
552 }
8a5d5053 553 }
a9bf3ec4 554 int getThread()
8a5d5053 555 {
6c1ca990 556 uint64_t pos = d_pos++;
8a5d5053 557 ++d_queued;
558 return d_tcpclientthreads[pos % d_numthreads];
559 }
ded1985a
RG
560 bool hasReachedMaxThreads() const
561 {
562 return d_numthreads >= d_maxthreads;
563 }
564 uint64_t getThreadsCount() const
565 {
566 return d_numthreads;
567 }
568 uint64_t getQueuedCount() const
569 {
570 return d_queued;
571 }
572 void decrementQueuedCount()
573 {
574 --d_queued;
575 }
8a5d5053 576 void addTCPClientThread();
577};
578
a9bf3ec4 579extern std::shared_ptr<TCPClientCollection> g_tcpclientthreads;
8a5d5053 580
df111b53 581struct DownstreamState
582{
fbe2a2e0
RG
583 DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf);
584 DownstreamState(const ComboAddress& remote_): DownstreamState(remote_, ComboAddress(), 0) {}
6a62c0e3
RG
585 ~DownstreamState()
586 {
587 if (fd >= 0)
588 close(fd);
589 }
df111b53 590
f99e3aaf 591 int fd{-1};
df111b53 592 std::thread tid;
593 ComboAddress remote;
594 QPSLimiter qps;
595 vector<IDState> idStates;
fbe2a2e0
RG
596 ComboAddress sourceAddr;
597 DNSName checkName{"a.root-servers.net."};
598 QType checkType{QType::A};
df111b53 599 std::atomic<uint64_t> idOffset{0};
600 std::atomic<uint64_t> sendErrors{0};
601 std::atomic<uint64_t> outstanding{0};
602 std::atomic<uint64_t> reuseds{0};
603 std::atomic<uint64_t> queries{0};
604 struct {
605 std::atomic<uint64_t> sendErrors{0};
606 std::atomic<uint64_t> reuseds{0};
607 std::atomic<uint64_t> queries{0};
608 } prev;
18eeccc9 609 string name;
df111b53 610 double queryLoad{0.0};
611 double dropRate{0.0};
612 double latencyUsec{0.0};
613 int order{1};
614 int weight{1};
b40cffe7 615 int tcpConnectTimeout{5};
3f6d07a4
RG
616 int tcpRecvTimeout{30};
617 int tcpSendTimeout{30};
fbe2a2e0 618 unsigned int sourceItf{0};
3f6d07a4 619 uint16_t retries{5};
9e87dcb8
RG
620 uint8_t currentCheckFailures{0};
621 uint8_t maxCheckFailures{1};
df111b53 622 StopWatch sw;
623 set<string> pools;
624 enum class Availability { Up, Down, Auto} availability{Availability::Auto};
fbe2a2e0 625 bool mustResolve{false};
df111b53 626 bool upStatus{false};
ca404e94 627 bool useECS{false};
21830638 628 bool setCD{false};
7565f4e6 629 std::atomic<bool> connected{false};
284d460c 630 bool tcpFastOpen{false};
df111b53 631 bool isUp() const
632 {
633 if(availability == Availability::Down)
634 return false;
635 if(availability == Availability::Up)
636 return true;
637 return upStatus;
638 }
639 void setUp() { availability = Availability::Up; }
640 void setDown() { availability = Availability::Down; }
641 void setAuto() { availability = Availability::Auto; }
18eeccc9
RG
642 string getName() const {
643 if (name.empty()) {
644 return remote.toStringWithPort();
645 }
646 return name;
647 }
a7940c06 648 string getNameWithAddr() const {
649 if (name.empty()) {
650 return remote.toStringWithPort();
651 }
652 return name + " (" + remote.toStringWithPort()+ ")";
653 }
9f4eb5cc
RG
654 string getStatus() const
655 {
656 string status;
657 if(availability == DownstreamState::Availability::Up)
658 status = "UP";
659 else if(availability == DownstreamState::Availability::Down)
660 status = "DOWN";
661 else
662 status = (upStatus ? "up" : "down");
663 return status;
664 }
b58f08e5 665 void reconnect();
df111b53 666};
667using servers_t =vector<std::shared_ptr<DownstreamState>>;
df111b53 668
da4e7813 669template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
670
671void* responderThread(std::shared_ptr<DownstreamState> state);
672extern std::mutex g_luamutex;
673extern LuaContext g_lua;
674extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
675
0940e4eb 676class DNSRule
677{
678public:
205f2081
RG
679 virtual ~DNSRule ()
680 {
681 }
497a6e3a 682 virtual bool matches(const DNSQuestion* dq) const =0;
0940e4eb 683 virtual string toString() const = 0;
684 mutable std::atomic<uint64_t> d_matches{0};
685};
686
da4e7813 687using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
497a6e3a 688typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
df111b53 689
690struct ServerPolicy
691{
692 string name;
70a57b05 693 policyfunc_t policy;
df111b53 694};
695
886e2cf2
RG
696struct ServerPool
697{
698 const std::shared_ptr<DNSDistPacketCache> getCache() const { return packetCache; };
699
700 NumberedVector<shared_ptr<DownstreamState>> servers;
701 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
b9f8a6c8 702 std::shared_ptr<ServerPolicy> policy{nullptr};
886e2cf2
RG
703};
704using pools_t=map<std::string,std::shared_ptr<ServerPool>>;
742c079a 705void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<ServerPolicy> policy);
886e2cf2
RG
706void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
707void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
708
42fae326 709struct CarbonConfig
710{
d617b22c 711 ComboAddress server;
42fae326 712 std::string ourname;
d617b22c 713 unsigned int interval;
42fae326 714};
715
ca404e94
RG
716enum ednsHeaderFlags {
717 EDNS_HEADER_FLAG_NONE = 0,
718 EDNS_HEADER_FLAG_DO = 32768
719};
720
71c94675 721extern GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
dd46e5e3 722extern DNSAction::Action g_dynBlockAction;
71c94675 723
d617b22c 724extern GlobalStateHolder<vector<CarbonConfig> > g_carbon;
ecbe9133 725extern GlobalStateHolder<ServerPolicy> g_policy;
726extern GlobalStateHolder<servers_t> g_dstates;
886e2cf2 727extern GlobalStateHolder<pools_t> g_pools;
0940e4eb 728extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions;
8146444b 729extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSResponseAction> > > > g_resprulactions;
cf48b0ce 730extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSResponseAction> > > > g_cachehitresprulactions;
638184e9 731extern GlobalStateHolder<NetmaskGroup> g_ACL;
2e72cc0e 732
ecbe9133 733extern ComboAddress g_serverControl; // not changed during runtime
734
9f67b883 735extern std::vector<std::tuple<ComboAddress, bool, bool, int, std::string>> g_locals; // not changed at runtime (we hope XXX)
963bef8d 736extern vector<ClientState*> g_frontends;
ecbe9133 737extern std::string g_key; // in theory needs locking
6ad8b29a 738extern bool g_truncateTC;
b29edbee 739extern bool g_fixupCase;
3f6d07a4
RG
740extern int g_tcpRecvTimeout;
741extern int g_tcpSendTimeout;
e0b5e49d 742extern int g_udpTimeout;
e41f8165
RG
743extern uint16_t g_maxOutstanding;
744extern std::atomic<bool> g_configurationDone;
6c1ca990
RG
745extern uint64_t g_maxTCPClientThreads;
746extern uint64_t g_maxTCPQueuedConnections;
9396d955
RG
747extern size_t g_maxTCPQueriesPerConn;
748extern size_t g_maxTCPConnectionDuration;
749extern size_t g_maxTCPConnectionsPerClient;
886e2cf2 750extern std::atomic<uint16_t> g_cacheCleaningDelay;
f65ea0c2 751extern std::atomic<uint16_t> g_cacheCleaningPercentage;
9e87dcb8 752extern bool g_verboseHealthChecks;
1ea747c0 753extern uint32_t g_staleCacheEntriesTTL;
56d68fad
RG
754extern bool g_apiReadWrite;
755extern std::string g_apiConfigDirectory;
26a3cdb7 756extern bool g_servFailOnNoPolicy;
36e763fa 757extern uint32_t g_hashperturb;
edbda1ad 758extern bool g_useTCPSinglePipe;
840ed663 759extern std::atomic<uint16_t> g_downstreamTCPCleanupInterval;
ca404e94 760
ca4252e0
RG
761struct ConsoleKeyword {
762 std::string name;
763 bool function;
764 std::string parameters;
765 std::string description;
766 std::string toString() const
767 {
768 std::string res(name);
769 if (function) {
770 res += "(" + parameters + ")";
771 }
772 res += ": ";
773 res += description;
774 return res;
775 }
776};
777extern const std::vector<ConsoleKeyword> g_consoleKeywords;
506bb661 778extern bool g_logConsoleConnections;
ca4252e0 779
87b515ed
RG
780#ifdef HAVE_EBPF
781extern shared_ptr<BPFFilter> g_defaultBPFFilter;
8429ad04 782extern std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
87b515ed
RG
783#endif /* HAVE_EBPF */
784
ecbe9133 785struct dnsheader;
786
787void controlThread(int fd, ComboAddress local);
839f3021 788vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
886e2cf2
RG
789std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
790std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName);
791const NumberedServerVector& getDownstreamCandidates(const pools_t& pools, const std::string& poolName);
da4e7813 792
497a6e3a 793std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq);
ecbe9133 794
497a6e3a
RG
795std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq);
796std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq);
797std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq);
798std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq);
520eb5a0 799int getEDNSZ(const char* packet, unsigned int len);
ca404e94 800uint16_t getEDNSOptionCode(const char * packet, size_t len);
002decab 801void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password, const string& apiKey, const boost::optional<std::map<std::string, std::string> >&);
6885d4bf 802bool getMsgLen32(int fd, uint32_t* len);
803bool putMsgLen32(int fd, uint32_t len);
d8d85a30 804void* tcpAcceptorThread(void* p);
80a216c9 805
886e2cf2 806void moreLua(bool client);
ffb07158 807void doClient(ComboAddress server, const std::string& command);
808void doConsole();
809void controlClientThread(int fd, ComboAddress client);
810extern "C" {
811char** my_completion( const char * text , int start, int end);
812}
f758857a 813void setLuaNoSideEffect(); // if nothing has been declared, set that there are no side effects
814void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ side effect calls
815bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
816void resetLuaSideEffect(); // reset to indeterminate state
11e1e08b 817
fcffc585 818bool responseContentMatches(const char* response, const uint16_t responseLen, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote);
71c94675 819bool processQuery(LocalStateHolder<NetmaskTree<DynBlock> >& localDynBlockNMG,
0c369ddc 820 LocalStateHolder<SuffixMatchTree<DynBlock> >& localDynBlockSMT, LocalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > >& localRulactions, DNSQuestion& dq, string& poolname, int* delayMsec, const struct timespec& now);
788c3243 821bool processResponse(LocalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSResponseAction> > > >& localRespRulactions, DNSResponse& dr, int* delayMsec);
ff73f02b 822bool fixUpResponse(char** response, uint16_t* responseLen, size_t* responseSize, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, std::vector<uint8_t>& rewrittenResponse, uint16_t addRoom);
0f72fd5c 823void restoreFlags(struct dnsheader* dh, uint16_t origFlags);
fcffc585 824
11e1e08b 825#ifdef HAVE_DNSCRYPT
9f67b883 826extern std::vector<std::tuple<ComboAddress,DnsCryptContext,bool,int, std::string>> g_dnsCryptLocals;
11e1e08b 827
3596a52b 828int handleDnsCryptQuery(DnsCryptContext* ctx, char* packet, uint16_t len, std::shared_ptr<DnsCryptQuery>& query, uint16_t* decryptedQueryLen, bool tcp, std::vector<uint8_t>& response);
57847d65 829bool encryptResponse(char* response, uint16_t* responseLen, size_t responseSize, bool tcp, std::shared_ptr<DnsCryptQuery> dnsCryptQuery, dnsheader** dh, dnsheader* dhCopy);
11e1e08b 830#endif
9f4eb5cc
RG
831
832#include "dnsdist-snmp.hh"
833
834extern bool g_snmpEnabled;
835extern bool g_snmpTrapsEnabled;
836extern DNSDistSNMPAgent* g_snmpAgent;