]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist.hh
Merge pull request #4693 from rgacogne/dnsdist-flexible-dynblocks-tests
[thirdparty/pdns.git] / pdns / dnsdist.hh
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #pragma once
23 #include "config.h"
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>
31 #include <boost/variant.hpp>
32 #include <mutex>
33 #include <thread>
34 #include <unistd.h>
35 #include "sholder.hh"
36 #include "dnscrypt.hh"
37 #include "dnsdist-cache.hh"
38 #include "gettime.hh"
39 #include "dnsdist-dynbpf.hh"
40 #include "bpf-filter.hh"
41
42 #ifdef HAVE_PROTOBUF
43 #include <boost/uuid/uuid.hpp>
44 #include <boost/uuid/uuid_generators.hpp>
45 #endif
46
47 void* carbonDumpThread();
48 uint64_t uptimeOfProcess(const std::string& str);
49
50 struct DynBlock
51 {
52 DynBlock& operator=(const DynBlock& rhs)
53 {
54 reason=rhs.reason;
55 until=rhs.until;
56 domain=rhs.domain;
57 blocks.store(rhs.blocks);
58 return *this;
59 }
60
61 string reason;
62 struct timespec until;
63 DNSName domain;
64 mutable std::atomic<unsigned int> blocks;
65 };
66
67 extern GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
68
69 extern vector<pair<struct timeval, std::string> > g_confDelta;
70
71 struct DNSDistStats
72 {
73 using stat_t=std::atomic<uint64_t>; // aww yiss ;-)
74 stat_t responses{0};
75 stat_t servfailResponses{0};
76 stat_t queries{0};
77 stat_t nonCompliantQueries{0};
78 stat_t nonCompliantResponses{0};
79 stat_t rdQueries{0};
80 stat_t emptyQueries{0};
81 stat_t aclDrops{0};
82 stat_t blockFilter{0};
83 stat_t dynBlocked{0};
84 stat_t ruleDrop{0};
85 stat_t ruleNXDomain{0};
86 stat_t ruleRefused{0};
87 stat_t selfAnswered{0};
88 stat_t downstreamTimeouts{0};
89 stat_t downstreamSendErrors{0};
90 stat_t truncFail{0};
91 stat_t noPolicy{0};
92 stat_t cacheHits{0};
93 stat_t cacheMisses{0};
94 stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0};
95
96 double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
97 typedef std::function<uint64_t(const std::string&)> statfunction_t;
98 typedef boost::variant<stat_t*, double*, statfunction_t> entry_t;
99 std::vector<std::pair<std::string, entry_t>> entries{
100 {"responses", &responses},
101 {"servfail-responses", &servfailResponses},
102 {"queries", &queries},
103 {"acl-drops", &aclDrops},
104 {"block-filter", &blockFilter},
105 {"rule-drop", &ruleDrop},
106 {"rule-nxdomain", &ruleNXDomain},
107 {"rule-refused", &ruleRefused},
108 {"self-answered", &selfAnswered},
109 {"downstream-timeouts", &downstreamTimeouts},
110 {"downstream-send-errors", &downstreamSendErrors},
111 {"trunc-failures", &truncFail},
112 {"no-policy", &noPolicy},
113 {"latency0-1", &latency0_1},
114 {"latency1-10", &latency1_10},
115 {"latency10-50", &latency10_50},
116 {"latency50-100", &latency50_100},
117 {"latency100-1000", &latency100_1000},
118 {"latency-slow", &latencySlow},
119 {"latency-avg100", &latencyAvg100},
120 {"latency-avg1000", &latencyAvg1000},
121 {"latency-avg10000", &latencyAvg10000},
122 {"latency-avg1000000", &latencyAvg1000000},
123 {"uptime", uptimeOfProcess},
124 {"real-memory-usage", getRealMemoryUsage},
125 {"noncompliant-queries", &nonCompliantQueries},
126 {"noncompliant-responses", &nonCompliantResponses},
127 {"rdqueries", &rdQueries},
128 {"empty-queries", &emptyQueries},
129 {"cache-hits", &cacheHits},
130 {"cache-misses", &cacheMisses},
131 {"cpu-user-msec", getCPUTimeUser},
132 {"cpu-sys-msec", getCPUTimeSystem},
133 {"fd-usage", getOpenFileDescriptors},
134 {"dyn-blocked", &dynBlocked},
135 {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }}
136 };
137 };
138
139
140 extern struct DNSDistStats g_stats;
141
142
143 struct StopWatch
144 {
145 StopWatch(bool realTime=false): d_needRealTime(realTime)
146 {
147 }
148 struct timespec d_start{0,0};
149 bool d_needRealTime{false};
150
151 void start() {
152 if(gettime(&d_start, d_needRealTime) < 0)
153 unixDie("Getting timestamp");
154
155 }
156
157 double udiff() const {
158 struct timespec now;
159 if(gettime(&now, d_needRealTime) < 0)
160 unixDie("Getting timestamp");
161
162 return 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
163 }
164
165 double udiffAndSet() {
166 struct timespec now;
167 if(gettime(&now, d_needRealTime) < 0)
168 unixDie("Getting timestamp");
169
170 auto ret= 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
171 d_start = now;
172 return ret;
173 }
174
175 };
176
177 class QPSLimiter
178 {
179 public:
180 QPSLimiter()
181 {
182 }
183
184 QPSLimiter(unsigned int rate, unsigned int burst) : d_rate(rate), d_burst(burst), d_tokens(burst)
185 {
186 d_passthrough=false;
187 d_prev.start();
188 }
189
190 unsigned int getRate() const
191 {
192 return d_passthrough? 0 : d_rate;
193 }
194
195 int getPassed() const
196 {
197 return d_passed;
198 }
199 int getBlocked() const
200 {
201 return d_blocked;
202 }
203
204 bool check() const // this is not quite fair
205 {
206 if(d_passthrough)
207 return true;
208 auto delta = d_prev.udiffAndSet();
209
210 d_tokens += 1.0*d_rate * (delta/1000000.0);
211
212 if(d_tokens > d_burst)
213 d_tokens = d_burst;
214
215 bool ret=false;
216 if(d_tokens >= 1.0) { // we need this because burst=1 is weird otherwise
217 ret=true;
218 --d_tokens;
219 d_passed++;
220 }
221 else
222 d_blocked++;
223
224 return ret;
225 }
226 private:
227 bool d_passthrough{true};
228 unsigned int d_rate;
229 unsigned int d_burst;
230 mutable double d_tokens;
231 mutable StopWatch d_prev;
232 mutable unsigned int d_passed{0};
233 mutable unsigned int d_blocked{0};
234 };
235
236 struct IDState
237 {
238 IDState() : origFD(-1), sentTime(true), delayMsec(0) { origDest.sin4.sin_family = 0;}
239 IDState(const IDState& orig)
240 {
241 origFD = orig.origFD;
242 origID = orig.origID;
243 origRemote = orig.origRemote;
244 origDest = orig.origDest;
245 delayMsec = orig.delayMsec;
246 age.store(orig.age.load());
247 }
248
249 int origFD; // set to <0 to indicate this state is empty // 4
250
251 ComboAddress origRemote; // 28
252 ComboAddress origDest; // 28
253 StopWatch sentTime; // 16
254 DNSName qname; // 80
255 #ifdef HAVE_DNSCRYPT
256 std::shared_ptr<DnsCryptQuery> dnsCryptQuery{0};
257 #endif
258 #ifdef HAVE_PROTOBUF
259 boost::uuids::uuid uniqueId;
260 #endif
261 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
262 uint32_t cacheKey; // 8
263 std::atomic<uint16_t> age; // 4
264 uint16_t qtype; // 2
265 uint16_t qclass; // 2
266 uint16_t origID; // 2
267 uint16_t origFlags; // 2
268 int delayMsec;
269 bool ednsAdded{false};
270 bool ecsAdded{false};
271 bool skipCache{false};
272 };
273
274 struct Rings {
275 Rings()
276 {
277 queryRing.set_capacity(10000);
278 respRing.set_capacity(10000);
279 pthread_rwlock_init(&queryLock, 0);
280 }
281 struct Query
282 {
283 struct timespec when;
284 ComboAddress requestor;
285 DNSName name;
286 uint16_t size;
287 uint16_t qtype;
288 struct dnsheader dh;
289 };
290 boost::circular_buffer<Query> queryRing;
291 struct Response
292 {
293 struct timespec when;
294 ComboAddress requestor;
295 DNSName name;
296 uint16_t qtype;
297 unsigned int usec;
298 unsigned int size;
299 struct dnsheader dh;
300 ComboAddress ds; // who handled it
301 };
302 boost::circular_buffer<Response> respRing;
303 std::mutex respMutex;
304 pthread_rwlock_t queryLock;
305
306 std::unordered_map<int, vector<boost::variant<string,double> > > getTopBandwidth(unsigned int numentries);
307 size_t numDistinctRequestors();
308 };
309
310 extern Rings g_rings;
311
312 typedef std::unordered_map<string, unsigned int> QueryCountRecords;
313 typedef std::function<std::tuple<bool, string>(DNSQuestion dq)> QueryCountFilter;
314 struct QueryCount {
315 QueryCount()
316 {
317 pthread_rwlock_init(&queryLock, 0);
318 }
319 QueryCountRecords records;
320 QueryCountFilter filter;
321 pthread_rwlock_t queryLock;
322 bool enabled{false};
323 };
324
325 extern QueryCount g_qcount;
326
327 struct ClientState
328 {
329 ComboAddress local;
330 #ifdef HAVE_DNSCRYPT
331 DnsCryptContext* dnscryptCtx{0};
332 #endif
333 std::atomic<uint64_t> queries{0};
334 int udpFD{-1};
335 int tcpFD{-1};
336
337 int getSocket() const
338 {
339 return udpFD != -1 ? udpFD : tcpFD;
340 }
341
342 #ifdef HAVE_EBPF
343 shared_ptr<BPFFilter> d_filter;
344
345 void detachFilter()
346 {
347 if (d_filter) {
348 d_filter->removeSocket(getSocket());
349 d_filter = nullptr;
350 }
351 }
352
353 void attachFilter(shared_ptr<BPFFilter> bpf)
354 {
355 detachFilter();
356
357 bpf->addSocket(getSocket());
358 d_filter = bpf;
359 }
360 #endif /* HAVE_EBPF */
361 };
362
363 class TCPClientCollection {
364 std::vector<int> d_tcpclientthreads;
365 std::atomic<uint64_t> d_pos{0};
366 public:
367 std::atomic<uint64_t> d_queued{0}, d_numthreads{0};
368 uint64_t d_maxthreads{0};
369
370 TCPClientCollection(size_t maxThreads)
371 {
372 d_maxthreads = maxThreads;
373 d_tcpclientthreads.reserve(maxThreads);
374 }
375
376 int getThread()
377 {
378 uint64_t pos = d_pos++;
379 ++d_queued;
380 return d_tcpclientthreads[pos % d_numthreads];
381 }
382 void addTCPClientThread();
383 };
384
385 extern std::shared_ptr<TCPClientCollection> g_tcpclientthreads;
386
387 struct DownstreamState
388 {
389 DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf);
390 DownstreamState(const ComboAddress& remote_): DownstreamState(remote_, ComboAddress(), 0) {}
391 ~DownstreamState()
392 {
393 if (fd >= 0)
394 close(fd);
395 }
396
397 int fd{-1};
398 std::thread tid;
399 ComboAddress remote;
400 QPSLimiter qps;
401 vector<IDState> idStates;
402 ComboAddress sourceAddr;
403 DNSName checkName{"a.root-servers.net."};
404 QType checkType{QType::A};
405 std::atomic<uint64_t> idOffset{0};
406 std::atomic<uint64_t> sendErrors{0};
407 std::atomic<uint64_t> outstanding{0};
408 std::atomic<uint64_t> reuseds{0};
409 std::atomic<uint64_t> queries{0};
410 struct {
411 std::atomic<uint64_t> sendErrors{0};
412 std::atomic<uint64_t> reuseds{0};
413 std::atomic<uint64_t> queries{0};
414 } prev;
415 string name;
416 double queryLoad{0.0};
417 double dropRate{0.0};
418 double latencyUsec{0.0};
419 int order{1};
420 int weight{1};
421 int tcpRecvTimeout{30};
422 int tcpSendTimeout{30};
423 unsigned int sourceItf{0};
424 uint16_t retries{5};
425 uint8_t currentCheckFailures{0};
426 uint8_t maxCheckFailures{1};
427 StopWatch sw;
428 set<string> pools;
429 enum class Availability { Up, Down, Auto} availability{Availability::Auto};
430 bool mustResolve{false};
431 bool upStatus{false};
432 bool useECS{false};
433 bool setCD{false};
434 bool isUp() const
435 {
436 if(availability == Availability::Down)
437 return false;
438 if(availability == Availability::Up)
439 return true;
440 return upStatus;
441 }
442 void setUp() { availability = Availability::Up; }
443 void setDown() { availability = Availability::Down; }
444 void setAuto() { availability = Availability::Auto; }
445 string getName() const {
446 if (name.empty()) {
447 return remote.toStringWithPort();
448 }
449 return name;
450 }
451 string getNameWithAddr() const {
452 if (name.empty()) {
453 return remote.toStringWithPort();
454 }
455 return name + " (" + remote.toStringWithPort()+ ")";
456 }
457
458 };
459 using servers_t =vector<std::shared_ptr<DownstreamState>>;
460
461 extern uint16_t g_ECSSourcePrefixV4;
462 extern uint16_t g_ECSSourcePrefixV6;
463 extern bool g_ECSOverride;
464
465 struct DNSQuestion
466 {
467 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) { }
468
469 #ifdef HAVE_PROTOBUF
470 boost::uuids::uuid uniqueId;
471 #endif
472 const DNSName* qname;
473 const uint16_t qtype;
474 const uint16_t qclass;
475 const ComboAddress* local;
476 const ComboAddress* remote;
477 struct dnsheader* dh;
478 size_t size;
479 uint16_t len;
480 uint16_t ecsPrefixLength;
481 const bool tcp;
482 bool skipCache{false};
483 bool ecsOverride;
484 bool useECS{true};
485 };
486
487 struct DNSResponse : DNSQuestion
488 {
489 DNSResponse(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_): DNSQuestion(name, type, class_, lc, rem, header, bufferSize, queryLen, isTcp), queryTime(queryTime_) { }
490
491 const struct timespec* queryTime;
492 };
493
494 typedef std::function<bool(const DNSQuestion*)> blockfilter_t;
495 template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
496
497 void* responderThread(std::shared_ptr<DownstreamState> state);
498 extern std::mutex g_luamutex;
499 extern LuaContext g_lua;
500 extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
501
502 class DNSRule
503 {
504 public:
505 virtual bool matches(const DNSQuestion* dq) const =0;
506 virtual string toString() const = 0;
507 mutable std::atomic<uint64_t> d_matches{0};
508 };
509
510 /* so what could you do:
511 drop,
512 fake up nxdomain,
513 provide actual answer,
514 allow & and stop processing,
515 continue processing,
516 modify header: (servfail|refused|notimp), set TC=1,
517 send to pool */
518
519 class DNSAction
520 {
521 public:
522 enum class Action { Drop, Nxdomain, Refused, Spoof, Allow, HeaderModify, Pool, Delay, None};
523 virtual Action operator()(DNSQuestion*, string* ruleresult) const =0;
524 virtual string toString() const = 0;
525 virtual std::unordered_map<string, double> getStats() const
526 {
527 return {{}};
528 }
529 };
530
531 class DNSResponseAction
532 {
533 public:
534 enum class Action { Allow, Delay, Drop, HeaderModify, None };
535 virtual Action operator()(DNSResponse*, string* ruleresult) const =0;
536 virtual string toString() const = 0;
537 };
538
539 using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
540 typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
541
542 struct ServerPolicy
543 {
544 string name;
545 policyfunc_t policy;
546 };
547
548 struct ServerPool
549 {
550 const std::shared_ptr<DNSDistPacketCache> getCache() const { return packetCache; };
551
552 NumberedVector<shared_ptr<DownstreamState>> servers;
553 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
554 };
555 using pools_t=map<std::string,std::shared_ptr<ServerPool>>;
556 void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
557 void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
558
559 struct CarbonConfig
560 {
561 ComboAddress server;
562 std::string ourname;
563 unsigned int interval;
564 };
565
566 enum ednsHeaderFlags {
567 EDNS_HEADER_FLAG_NONE = 0,
568 EDNS_HEADER_FLAG_DO = 32768
569 };
570
571 /* Quest in life: serve as a rapid block list. If you add a DNSName to a root SuffixMatchNode,
572 anything part of that domain will return 'true' in check */
573 template<typename T>
574 struct SuffixMatchTree
575 {
576 SuffixMatchTree(const std::string& name_="", bool endNode_=false) : name(name_), endNode(endNode_)
577 {}
578
579 SuffixMatchTree(const SuffixMatchTree& rhs)
580 {
581 name = rhs.name;
582 d_human = rhs.d_human;
583 children = rhs.children;
584 endNode = rhs.endNode;
585 d_value = rhs.d_value;
586 }
587 std::string name;
588 std::string d_human;
589 mutable std::set<SuffixMatchTree> children;
590 mutable bool endNode;
591 mutable T d_value;
592 bool operator<(const SuffixMatchTree& rhs) const
593 {
594 return strcasecmp(name.c_str(), rhs.name.c_str()) < 0;
595 }
596 typedef SuffixMatchTree value_type;
597
598 template<typename V>
599 void visit(const V& v) const {
600 for(const auto& c : children)
601 c.visit(v);
602 if(endNode)
603 v(*this);
604 }
605
606 void add(const DNSName& name, const T& t)
607 {
608 add(name.getRawLabels(), t);
609 }
610
611 void add(std::vector<std::string> labels, const T& value) const
612 {
613 if(labels.empty()) { // this allows insertion of the root
614 endNode=true;
615 d_value=value;
616 }
617 else if(labels.size()==1) {
618 SuffixMatchTree newChild(*labels.begin(), true);
619 newChild.d_value=value;
620 children.insert(newChild);
621 }
622 else {
623 SuffixMatchTree newnode(*labels.rbegin(), false);
624 auto res=children.insert(newnode);
625 if(!res.second) {
626 children.erase(newnode);
627 res=children.insert(newnode);
628 }
629 labels.pop_back();
630 res.first->add(labels, value);
631 }
632 }
633
634 T* lookup(const DNSName& name) const
635 {
636 if(children.empty()) { // speed up empty set
637 if(endNode)
638 return &d_value;
639 return 0;
640 }
641 return lookup(name.getRawLabels());
642 }
643
644 T* lookup(std::vector<std::string> labels) const
645 {
646 if(labels.empty()) { // optimization
647 if(endNode)
648 return &d_value;
649 return 0;
650 }
651
652 SuffixMatchTree smn(*labels.rbegin());
653 auto child = children.find(smn);
654 if(child == children.end()) {
655 if(endNode)
656 return &d_value;
657 return 0;
658 }
659 labels.pop_back();
660 return child->lookup(labels);
661 }
662
663 };
664
665 extern GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
666 extern DNSAction::Action g_dynBlockAction;
667
668 extern GlobalStateHolder<vector<CarbonConfig> > g_carbon;
669 extern GlobalStateHolder<ServerPolicy> g_policy;
670 extern GlobalStateHolder<servers_t> g_dstates;
671 extern GlobalStateHolder<pools_t> g_pools;
672 extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions;
673 extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSResponseAction> > > > g_resprulactions;
674 extern GlobalStateHolder<NetmaskGroup> g_ACL;
675
676 extern ComboAddress g_serverControl; // not changed during runtime
677
678 extern std::vector<std::tuple<ComboAddress, bool, bool, int>> g_locals; // not changed at runtime (we hope XXX)
679 extern vector<ClientState*> g_frontends;
680 extern std::string g_key; // in theory needs locking
681 extern bool g_truncateTC;
682 extern bool g_fixupCase;
683 extern int g_tcpRecvTimeout;
684 extern int g_tcpSendTimeout;
685 extern uint16_t g_maxOutstanding;
686 extern std::atomic<bool> g_configurationDone;
687 extern uint64_t g_maxTCPClientThreads;
688 extern uint64_t g_maxTCPQueuedConnections;
689 extern std::atomic<uint16_t> g_cacheCleaningDelay;
690 extern bool g_verboseHealthChecks;
691 extern uint32_t g_staleCacheEntriesTTL;
692 extern bool g_apiReadWrite;
693 extern std::string g_apiConfigDirectory;
694
695 struct ConsoleKeyword {
696 std::string name;
697 bool function;
698 std::string parameters;
699 std::string description;
700 std::string toString() const
701 {
702 std::string res(name);
703 if (function) {
704 res += "(" + parameters + ")";
705 }
706 res += ": ";
707 res += description;
708 return res;
709 }
710 };
711 extern const std::vector<ConsoleKeyword> g_consoleKeywords;
712
713 #ifdef HAVE_EBPF
714 extern shared_ptr<BPFFilter> g_defaultBPFFilter;
715 extern std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
716 #endif /* HAVE_EBPF */
717
718 struct dnsheader;
719
720 void controlThread(int fd, ComboAddress local);
721 vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
722 std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
723 std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName);
724 const NumberedServerVector& getDownstreamCandidates(const pools_t& pools, const std::string& poolName);
725
726 std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq);
727
728 std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq);
729 std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq);
730 std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq);
731 std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq);
732 int getEDNSZ(const char* packet, unsigned int len);
733 void spoofResponseFromString(DNSQuestion& dq, const string& spoofContent);
734 uint16_t getEDNSOptionCode(const char * packet, size_t len);
735 void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password, const string& apiKey, const boost::optional<std::map<std::string, std::string> >&);
736 bool getMsgLen32(int fd, uint32_t* len);
737 bool putMsgLen32(int fd, uint32_t len);
738 void* tcpAcceptorThread(void* p);
739
740 void moreLua(bool client);
741 void doClient(ComboAddress server, const std::string& command);
742 void doConsole();
743 void controlClientThread(int fd, ComboAddress client);
744 extern "C" {
745 char** my_completion( const char * text , int start, int end);
746 }
747 void setLuaNoSideEffect(); // if nothing has been declared, set that there are no side effects
748 void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ side effect calls
749 bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
750 void resetLuaSideEffect(); // reset to indeterminate state
751
752 bool responseContentMatches(const char* response, const uint16_t responseLen, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote);
753 bool processQuery(LocalStateHolder<NetmaskTree<DynBlock> >& localDynBlockNMG,
754 LocalStateHolder<SuffixMatchTree<DynBlock> >& localDynBlockSMT, LocalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > >& localRulactions, blockfilter_t blockFilter, DNSQuestion& dq, string& poolname, int* delayMsec, const struct timespec& now);
755 bool processResponse(LocalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSResponseAction> > > >& localRespRulactions, DNSResponse& dr, int* delayMsec);
756 bool 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);
757 void restoreFlags(struct dnsheader* dh, uint16_t origFlags);
758
759 #ifdef HAVE_DNSCRYPT
760 extern std::vector<std::tuple<ComboAddress,DnsCryptContext,bool,int>> g_dnsCryptLocals;
761
762 int handleDnsCryptQuery(DnsCryptContext* ctx, char* packet, uint16_t len, std::shared_ptr<DnsCryptQuery>& query, uint16_t* decryptedQueryLen, bool tcp, std::vector<uint8_t>& reponse);
763 bool encryptResponse(char* response, uint16_t* responseLen, size_t responseSize, bool tcp, std::shared_ptr<DnsCryptQuery> dnsCryptQuery);
764 #endif