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