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