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