]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist.hh
dnsdist: Implement SNIRule for DoT
[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"
cbf4e13a 25
df111b53 26#include <atomic>
df111b53 27#include <mutex>
cbf4e13a 28#include <string>
df111b53 29#include <thread>
cbf4e13a 30#include <time.h>
bffca8b9 31#include <unistd.h>
cbf4e13a
RG
32#include <unordered_map>
33
34#include <boost/circular_buffer.hpp>
35#include <boost/variant.hpp>
36
37#include "bpf-filter.hh"
f12666f2 38#include "capabilities.hh"
11e1e08b 39#include "dnscrypt.hh"
886e2cf2 40#include "dnsdist-cache.hh"
87b515ed 41#include "dnsdist-dynbpf.hh"
cbf4e13a 42#include "dnsname.hh"
fbf14b03 43#include "doh.hh"
cbf4e13a
RG
44#include "ednsoptions.hh"
45#include "gettime.hh"
46#include "iputils.hh"
47#include "misc.hh"
48#include "mplexer.hh"
49#include "sholder.hh"
a227f47d 50#include "tcpiohandler.hh"
d61aa945 51#include "uuid-utils.hh"
d8c19b98 52
9b73b71c 53void carbonDumpThread();
61d1b966 54uint64_t uptimeOfProcess(const std::string& str);
bd1c631b 55
7b925432
RG
56extern uint16_t g_ECSSourcePrefixV4;
57extern uint16_t g_ECSSourcePrefixV6;
58extern bool g_ECSOverride;
26a6373d 59
15fac047
CH
60typedef std::unordered_map<string, string> QTag;
61
7b925432
RG
62struct DNSQuestion
63{
e7c732b8 64 DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, unsigned int consumed_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp, const struct timespec* queryTime_):
4ab01344
RG
65 qname(name), local(lc), remote(rem), dh(header), queryTime(queryTime_), size(bufferSize), consumed(consumed_), tempFailureTTL(boost::none), qtype(type), qclass(class_), len(queryLen), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tcp(isTcp), ecsOverride(g_ECSOverride) {
66 const uint16_t* flags = getFlagsFromDNSHeader(dh);
67 origFlags = *flags;
68 }
dd1a3034
RG
69 DNSQuestion(const DNSQuestion&) = delete;
70 DNSQuestion& operator=(const DNSQuestion&) = delete;
71 DNSQuestion(DNSQuestion&&) = default;
7b925432
RG
72
73#ifdef HAVE_PROTOBUF
ec48a28d 74 boost::optional<boost::uuids::uuid> uniqueId;
7b925432 75#endif
bd14f087 76 Netmask ecs;
4ab01344 77 boost::optional<Netmask> subnet;
046bac5c 78 std::string sni; /* Server Name Indication, if any (DoT or DoH) */
4ab01344
RG
79 const DNSName* qname{nullptr};
80 const ComboAddress* local{nullptr};
81 const ComboAddress* remote{nullptr};
15fac047 82 std::shared_ptr<QTag> qTag{nullptr};
cbf4e13a 83 std::shared_ptr<std::map<uint16_t, EDNSOptionView> > ednsOptions;
4ab01344
RG
84 std::shared_ptr<DNSCryptQuery> dnsCryptQuery{nullptr};
85 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
86 struct dnsheader* dh{nullptr};
87 const struct timespec* queryTime{nullptr};
fbf14b03 88 struct DOHUnit* du{nullptr};
7b925432 89 size_t size;
e7c732b8 90 unsigned int consumed{0};
4ab01344
RG
91 int delayMsec{0};
92 boost::optional<uint32_t> tempFailureTTL;
93 uint32_t cacheKeyNoECS;
94 uint32_t cacheKey;
95 const uint16_t qtype;
96 const uint16_t qclass;
7b925432
RG
97 uint16_t len;
98 uint16_t ecsPrefixLength;
4ab01344 99 uint16_t origFlags;
1ecbd15e 100 uint8_t ednsRCode{0};
7b925432
RG
101 const bool tcp;
102 bool skipCache{false};
103 bool ecsOverride;
5b8255ba 104 bool useECS{true};
5cc8371b 105 bool addXPF{true};
bd14f087 106 bool ecsSet{false};
4ab01344
RG
107 bool ecsAdded{false};
108 bool ednsAdded{false};
109 bool useZeroScope{false};
110 bool dnssecOK{false};
7b925432
RG
111};
112
113struct DNSResponse : DNSQuestion
114{
e7c732b8
RG
115 DNSResponse(const DNSName* name, uint16_t type, uint16_t class_, unsigned int consumed, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t responseLen, bool isTcp, const struct timespec* queryTime_):
116 DNSQuestion(name, type, class_, consumed, lc, rem, header, bufferSize, responseLen, isTcp, queryTime_) { }
dd1a3034
RG
117 DNSResponse(const DNSResponse&) = delete;
118 DNSResponse& operator=(const DNSResponse&) = delete;
119 DNSResponse(DNSResponse&&) = default;
7b925432
RG
120};
121
5c30ec69
LM
122/* so what could you do:
123 drop,
124 fake up nxdomain,
125 provide actual answer,
126 allow & and stop processing,
127 continue processing,
7b925432
RG
128 modify header: (servfail|refused|notimp), set TC=1,
129 send to pool */
130
131class DNSAction
132{
133public:
3d60b39a 134 enum class Action { Drop, Nxdomain, Refused, Spoof, Allow, HeaderModify, Pool, Delay, Truncate, ServFail, None, NoOp, NoRecurse };
b718792f
RG
135 static std::string typeToString(const Action& action)
136 {
137 switch(action) {
138 case Action::Drop:
139 return "Drop";
140 case Action::Nxdomain:
141 return "Send NXDomain";
142 case Action::Refused:
143 return "Send Refused";
144 case Action::Spoof:
145 return "Spoof an answer";
146 case Action::Allow:
147 return "Allow";
148 case Action::HeaderModify:
149 return "Modify the header";
150 case Action::Pool:
151 return "Route to a pool";
152 case Action::Delay:
153 return "Delay";
154 case Action::Truncate:
155 return "Truncate over UDP";
156 case Action::ServFail:
157 return "Send ServFail";
158 case Action::None:
477c86a0 159 case Action::NoOp:
b718792f 160 return "Do nothing";
3d60b39a 161 case Action::NoRecurse:
162 return "Set rd=0";
b718792f
RG
163 }
164
165 return "Unknown";
166 }
167
7b925432 168 virtual Action operator()(DNSQuestion*, string* ruleresult) const =0;
205f2081
RG
169 virtual ~DNSAction()
170 {
171 }
7b925432 172 virtual string toString() const = 0;
b8019cf7 173 virtual std::map<string, double> getStats() const
7b925432
RG
174 {
175 return {{}};
176 }
177};
178
179class DNSResponseAction
180{
181public:
5f23eb98 182 enum class Action { Allow, Delay, Drop, HeaderModify, ServFail, None };
7b925432 183 virtual Action operator()(DNSResponse*, string* ruleresult) const =0;
205f2081
RG
184 virtual ~DNSResponseAction()
185 {
186 }
7b925432
RG
187 virtual string toString() const = 0;
188};
189
78ffa782 190struct DynBlock
191{
1d3ba133 192 DynBlock(): action(DNSAction::Action::None), warning(false)
5708a729
RG
193 {
194 }
195
1d3ba133 196 DynBlock(const std::string& reason_, const struct timespec& until_, const DNSName& domain_, DNSAction::Action action_): reason(reason_), until(until_), domain(domain_), action(action_), warning(false)
5708a729
RG
197 {
198 }
199
1d3ba133 200 DynBlock(const DynBlock& rhs): reason(rhs.reason), until(rhs.until), domain(rhs.domain), action(rhs.action), warning(rhs.warning)
5708a729
RG
201 {
202 blocks.store(rhs.blocks);
203 }
204
78ffa782 205 DynBlock& operator=(const DynBlock& rhs)
206 {
207 reason=rhs.reason;
208 until=rhs.until;
71c94675 209 domain=rhs.domain;
7b925432 210 action=rhs.action;
78ffa782 211 blocks.store(rhs.blocks);
1d3ba133 212 warning=rhs.warning;
78ffa782 213 return *this;
214 }
71c94675 215
78ffa782 216 string reason;
217 struct timespec until;
71c94675 218 DNSName domain;
7b925432 219 DNSAction::Action action;
78ffa782 220 mutable std::atomic<unsigned int> blocks;
1d3ba133 221 bool warning;
78ffa782 222};
223
224extern GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
f758857a 225
226extern vector<pair<struct timeval, std::string> > g_confDelta;
227
e48090d1 228struct DNSDistStats
229{
6ad8b29a 230 using stat_t=std::atomic<uint64_t>; // aww yiss ;-)
e48090d1 231 stat_t responses{0};
232 stat_t servfailResponses{0};
233 stat_t queries{0};
61d10a4d
MH
234 stat_t frontendNXDomain{0};
235 stat_t frontendServFail{0};
236 stat_t frontendNoError{0};
e73ec7d3 237 stat_t nonCompliantQueries{0};
d08b1cdf 238 stat_t nonCompliantResponses{0};
643a182a 239 stat_t rdQueries{0};
2efd427d 240 stat_t emptyQueries{0};
e48090d1 241 stat_t aclDrops{0};
bd1c631b 242 stat_t dynBlocked{0};
e48090d1 243 stat_t ruleDrop{0};
244 stat_t ruleNXDomain{0};
dd46e5e3 245 stat_t ruleRefused{0};
5f23eb98 246 stat_t ruleServFail{0};
e48090d1 247 stat_t selfAnswered{0};
248 stat_t downstreamTimeouts{0};
249 stat_t downstreamSendErrors{0};
6ad8b29a 250 stat_t truncFail{0};
b8bc7e61 251 stat_t noPolicy{0};
886e2cf2
RG
252 stat_t cacheHits{0};
253 stat_t cacheMisses{0};
42fae326 254 stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0};
f29758cc 255 stat_t securityStatus{0};
5c30ec69 256
e16fd59c 257 double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
a1a787dc 258 typedef std::function<uint64_t(const std::string&)> statfunction_t;
72f58a53 259 typedef boost::variant<stat_t*, double*, statfunction_t> entry_t;
e16fd59c 260 std::vector<std::pair<std::string, entry_t>> entries{
dd46e5e3
RG
261 {"responses", &responses},
262 {"servfail-responses", &servfailResponses},
263 {"queries", &queries},
61d10a4d
MH
264 {"frontend-nxdomain", &frontendNXDomain},
265 {"frontend-servfail", &frontendServFail},
266 {"frontend-noerror", &frontendNoError},
dd46e5e3 267 {"acl-drops", &aclDrops},
dd46e5e3
RG
268 {"rule-drop", &ruleDrop},
269 {"rule-nxdomain", &ruleNXDomain},
270 {"rule-refused", &ruleRefused},
5f23eb98 271 {"rule-servfail", &ruleServFail},
dd46e5e3
RG
272 {"self-answered", &selfAnswered},
273 {"downstream-timeouts", &downstreamTimeouts},
5c30ec69 274 {"downstream-send-errors", &downstreamSendErrors},
dd46e5e3
RG
275 {"trunc-failures", &truncFail},
276 {"no-policy", &noPolicy},
277 {"latency0-1", &latency0_1},
278 {"latency1-10", &latency1_10},
279 {"latency10-50", &latency10_50},
280 {"latency50-100", &latency50_100},
281 {"latency100-1000", &latency100_1000},
282 {"latency-slow", &latencySlow},
283 {"latency-avg100", &latencyAvg100},
284 {"latency-avg1000", &latencyAvg1000},
285 {"latency-avg10000", &latencyAvg10000},
286 {"latency-avg1000000", &latencyAvg1000000},
61d1b966 287 {"uptime", uptimeOfProcess},
a9b6db56 288 {"real-memory-usage", getRealMemoryUsage},
330dcb5c 289 {"special-memory-usage", getSpecialMemoryUsage},
a2aa00ed 290 {"noncompliant-queries", &nonCompliantQueries},
d08b1cdf 291 {"noncompliant-responses", &nonCompliantResponses},
643a182a 292 {"rdqueries", &rdQueries},
2efd427d 293 {"empty-queries", &emptyQueries},
886e2cf2
RG
294 {"cache-hits", &cacheHits},
295 {"cache-misses", &cacheMisses},
4f99f3d3
RG
296 {"cpu-user-msec", getCPUTimeUser},
297 {"cpu-sys-msec", getCPUTimeSystem},
dd46e5e3 298 {"fd-usage", getOpenFileDescriptors},
5c30ec69 299 {"dyn-blocked", &dynBlocked},
f29758cc
PL
300 {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }},
301 {"security-status", &securityStatus}
42fae326 302 };
e48090d1 303};
304
2e567c94
PO
305// Metric types for Prometheus
306enum class PrometheusMetricType: int {
307 counter = 1,
308 gauge = 2
309};
310
37a5c2d5
PO
311// Keeps additional information about metrics
312struct MetricDefinition {
3cbe2773 313 MetricDefinition(PrometheusMetricType _prometheusType, const std::string& _description): description(_description), prometheusType(_prometheusType) {
37a5c2d5
PO
314 }
315
316 MetricDefinition() = default;
317
318 // Metric description
319 std::string description;
320 // Metric type for Prometheus
2e567c94 321 PrometheusMetricType prometheusType;
37a5c2d5
PO
322};
323
324struct MetricDefinitionStorage {
325 // Return metric definition by name
326 bool getMetricDetails(std::string metricName, MetricDefinition& metric) {
327 auto metricDetailsIter = metrics.find(metricName);
328
329 if (metricDetailsIter == metrics.end()) {
330 return false;
331 }
332
333 metric = metricDetailsIter->second;
334 return true;
335 };
336
2e567c94
PO
337 // Return string representation of Prometheus metric type
338 std::string getPrometheusStringMetricType(PrometheusMetricType metricType) {
339 switch (metricType) {
340 case PrometheusMetricType::counter:
341 return "counter";
342 break;
343 case PrometheusMetricType::gauge:
344 return "gauge";
345 break;
346 default:
347 return "";
348 break;
349 }
350 };
351
37a5c2d5 352 std::map<std::string, MetricDefinition> metrics = {
2e567c94
PO
353 { "responses", MetricDefinition(PrometheusMetricType::counter, "Number of responses received from backends") },
354 { "servfail-responses", MetricDefinition(PrometheusMetricType::counter, "Number of SERVFAIL answers received from backends") },
355 { "queries", MetricDefinition(PrometheusMetricType::counter, "Number of received queries")},
61d10a4d
MH
356 { "frontend-nxdomain", MetricDefinition(PrometheusMetricType::counter, "Number of NXDomain answers sent to clients")},
357 { "frontend-servfail", MetricDefinition(PrometheusMetricType::counter, "Number of SERVFAIL answers sent to clients")},
358 { "frontend-noerror", MetricDefinition(PrometheusMetricType::counter, "Number of NoError answers sent to clients")},
2e567c94
PO
359 { "acl-drops", MetricDefinition(PrometheusMetricType::counter, "Number of packets dropped because of the ACL")},
360 { "rule-drop", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because of a rule")},
361 { "rule-nxdomain", MetricDefinition(PrometheusMetricType::counter, "Number of NXDomain answers returned because of a rule")},
362 { "rule-refused", MetricDefinition(PrometheusMetricType::counter, "Number of Refused answers returned because of a rule")},
363 { "rule-servfail", MetricDefinition(PrometheusMetricType::counter, "Number of SERVFAIL answers received because of a rule")},
364 { "self-answered", MetricDefinition(PrometheusMetricType::counter, "Number of self-answered responses")},
365 { "downstream-timeouts", MetricDefinition(PrometheusMetricType::counter, "Number of queries not answered in time by a backend")},
366 { "downstream-send-errors", MetricDefinition(PrometheusMetricType::counter, "Number of errors when sending a query to a backend")},
367 { "trunc-failures", MetricDefinition(PrometheusMetricType::counter, "Number of errors encountered while truncating an answer")},
368 { "no-policy", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because no server was available")},
369 { "latency0-1", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in less than 1ms")},
370 { "latency1-10", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in 1-10 ms")},
371 { "latency10-50", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in 10-50 ms")},
372 { "latency50-100", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in 50-100 ms")},
373 { "latency100-1000", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in 100-1000 ms")},
374 { "latency-slow", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in more than 1 second")},
375 { "latency-avg100", MetricDefinition(PrometheusMetricType::gauge, "Average response latency in microseconds of the last 100 packets")},
376 { "latency-avg1000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency in microseconds of the last 1000 packets")},
377 { "latency-avg10000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency in microseconds of the last 10000 packets")},
378 { "latency-avg1000000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency in microseconds of the last 1000000 packets")},
379 { "uptime", MetricDefinition(PrometheusMetricType::gauge, "Uptime of the dnsdist process in seconds")},
380 { "real-memory-usage", MetricDefinition(PrometheusMetricType::gauge, "Current memory usage in bytes")},
381 { "noncompliant-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped as non-compliant")},
382 { "noncompliant-responses", MetricDefinition(PrometheusMetricType::counter, "Number of answers from a backend dropped as non-compliant")},
383 { "rdqueries", MetricDefinition(PrometheusMetricType::counter, "Number of received queries with the recursion desired bit set")},
384 { "empty-queries", MetricDefinition(PrometheusMetricType::counter, "Number of empty queries received from clients")},
385 { "cache-hits", MetricDefinition(PrometheusMetricType::counter, "Number of times an answer was retrieved from cache")},
386 { "cache-misses", MetricDefinition(PrometheusMetricType::counter, "Number of times an answer not found in the cache")},
387 { "cpu-user-msec", MetricDefinition(PrometheusMetricType::counter, "Milliseconds spent by dnsdist in the user state")},
388 { "cpu-sys-msec", MetricDefinition(PrometheusMetricType::counter, "Milliseconds spent by dnsdist in the system state")},
389 { "fd-usage", MetricDefinition(PrometheusMetricType::gauge, "Number of currently used file descriptors")},
1200be3e 390 { "dyn-blocked", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because of a dynamic block")},
2e567c94 391 { "dyn-block-nmg-size", MetricDefinition(PrometheusMetricType::gauge, "Number of dynamic blocks entries") },
f29758cc 392 { "security-status", MetricDefinition(PrometheusMetricType::gauge, "Security status of this software. 0=unknown, 1=OK, 2=upgrade recommended, 3=upgrade mandatory") },
37a5c2d5
PO
393 };
394};
e16fd59c 395
37a5c2d5 396extern MetricDefinitionStorage g_metricDefinitions;
e48090d1 397extern struct DNSDistStats g_stats;
f653b8df 398void doLatencyStats(double udiff);
e48090d1 399
638184e9 400
df111b53 401struct StopWatch
402{
58307a85
RG
403 StopWatch(bool realTime=false): d_needRealTime(realTime)
404 {
405 }
df111b53 406 struct timespec d_start{0,0};
58307a85
RG
407 bool d_needRealTime{false};
408
5c30ec69 409 void start() {
58307a85 410 if(gettime(&d_start, d_needRealTime) < 0)
df111b53 411 unixDie("Getting timestamp");
5c30ec69 412
df111b53 413 }
cf48b0ce
RG
414
415 void set(const struct timespec& from) {
416 d_start = from;
417 }
5c30ec69 418
df111b53 419 double udiff() const {
420 struct timespec now;
58307a85 421 if(gettime(&now, d_needRealTime) < 0)
df111b53 422 unixDie("Getting timestamp");
5c30ec69 423
df111b53 424 return 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
425 }
426
427 double udiffAndSet() {
428 struct timespec now;
58307a85 429 if(gettime(&now, d_needRealTime) < 0)
df111b53 430 unixDie("Getting timestamp");
5c30ec69 431
df111b53 432 auto ret= 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
433 d_start = now;
434 return ret;
435 }
436
437};
438
67ce0bdd 439class BasicQPSLimiter
df111b53 440{
441public:
67ce0bdd 442 BasicQPSLimiter()
df111b53 443 {
444 }
445
2d29e6b7 446 BasicQPSLimiter(unsigned int burst): d_tokens(burst)
67ce0bdd
RG
447 {
448 d_prev.start();
449 }
450
451 bool check(unsigned int rate, unsigned int burst) const // this is not quite fair
452 {
453 auto delta = d_prev.udiffAndSet();
454
1a1787b6 455 if(delta > 0.0) // time, frequently, does go backwards..
456 d_tokens += 1.0 * rate * (delta/1000000.0);
67ce0bdd
RG
457
458 if(d_tokens > burst) {
459 d_tokens = burst;
460 }
461
462 bool ret=false;
463 if(d_tokens >= 1.0) { // we need this because burst=1 is weird otherwise
464 ret=true;
465 --d_tokens;
466 }
467
468 return ret;
469 }
470
471 bool seenSince(const struct timespec& cutOff) const
472 {
473 return cutOff < d_prev.d_start;
474 }
475
476protected:
477 mutable StopWatch d_prev;
478 mutable double d_tokens;
479};
480
481class QPSLimiter : public BasicQPSLimiter
482{
483public:
484 QPSLimiter(): BasicQPSLimiter()
485 {
486 }
487
2d29e6b7 488 QPSLimiter(unsigned int rate, unsigned int burst): BasicQPSLimiter(burst), d_rate(rate), d_burst(burst), d_passthrough(false)
df111b53 489 {
df111b53 490 d_prev.start();
491 }
492
493 unsigned int getRate() const
494 {
67ce0bdd 495 return d_passthrough ? 0 : d_rate;
df111b53 496 }
497
498 int getPassed() const
499 {
500 return d_passed;
501 }
67ce0bdd 502
df111b53 503 int getBlocked() const
504 {
505 return d_blocked;
506 }
507
ecbe9133 508 bool check() const // this is not quite fair
df111b53 509 {
67ce0bdd 510 if (d_passthrough) {
df111b53 511 return true;
67ce0bdd 512 }
df111b53 513
67ce0bdd
RG
514 bool ret = BasicQPSLimiter::check(d_rate, d_burst);
515 if (ret) {
df111b53 516 d_passed++;
517 }
67ce0bdd 518 else {
df111b53 519 d_blocked++;
67ce0bdd 520 }
df111b53 521
5c30ec69 522 return ret;
df111b53 523 }
524private:
ecbe9133 525 mutable unsigned int d_passed{0};
526 mutable unsigned int d_blocked{0};
67ce0bdd
RG
527 unsigned int d_rate;
528 unsigned int d_burst;
529 bool d_passthrough{true};
df111b53 530};
531
b5b93e0b
RG
532struct ClientState;
533
df111b53 534struct IDState
535{
acb8f5d5 536 IDState() : origFD(-1), sentTime(true), delayMsec(0), tempFailureTTL(boost::none) { origDest.sin4.sin_family = 0;}
71b86bd8 537 IDState(const IDState& orig): origRemote(orig.origRemote), origDest(orig.origDest), age(orig.age)
df111b53 538 {
71b86bd8 539 origFD.store(orig.origFD.load());
df111b53 540 origID = orig.origID;
7b3865cd 541 delayMsec = orig.delayMsec;
acb8f5d5 542 tempFailureTTL = orig.tempFailureTTL;
df111b53 543 }
544
71b86bd8 545 std::atomic<int> origFD; // set to <0 to indicate this state is empty // 4
2bf26975 546
547 ComboAddress origRemote; // 28
549d63c9 548 ComboAddress origDest; // 28
2bf26975 549 StopWatch sentTime; // 16
550 DNSName qname; // 80
43234e76 551 std::shared_ptr<DNSCryptQuery> dnsCryptQuery{nullptr};
d8c19b98 552#ifdef HAVE_PROTOBUF
ec48a28d 553 boost::optional<boost::uuids::uuid> uniqueId;
11e1e08b 554#endif
78e3ac9e 555 boost::optional<Netmask> subnet{boost::none};
886e2cf2 556 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
a76b0d63 557 std::shared_ptr<QTag> qTag{nullptr};
b5b93e0b 558 const ClientState* cs{nullptr};
fbf14b03 559 DOHUnit* du{nullptr};
9837850d 560 uint32_t cacheKey; // 4
561 uint32_t cacheKeyNoECS; // 4
71b86bd8 562 uint16_t age; // 4
2bf26975 563 uint16_t qtype; // 2
886e2cf2 564 uint16_t qclass; // 2
2bf26975 565 uint16_t origID; // 2
aeb36780 566 uint16_t origFlags; // 2
7b3865cd 567 int delayMsec;
acb8f5d5 568 boost::optional<uint32_t> tempFailureTTL;
ca404e94 569 bool ednsAdded{false};
ff73f02b 570 bool ecsAdded{false};
886e2cf2 571 bool skipCache{false};
7cea4e39 572 bool destHarvested{false}; // if true, origDest holds the original dest addr, otherwise the listening addr
d7728daf 573 bool dnssecOK{false};
389d903a 574 bool useZeroScope;
df111b53 575};
576
786e4d8c 577typedef std::unordered_map<string, unsigned int> QueryCountRecords;
dd1a3034 578typedef std::function<std::tuple<bool, string>(const DNSQuestion* dq)> QueryCountFilter;
786e4d8c
RS
579struct QueryCount {
580 QueryCount()
581 {
43234e76 582 pthread_rwlock_init(&queryLock, nullptr);
786e4d8c
RS
583 }
584 QueryCountRecords records;
585 QueryCountFilter filter;
586 pthread_rwlock_t queryLock;
587 bool enabled{false};
588};
589
590extern QueryCount g_qcount;
591
8a5d5053 592struct ClientState
593{
6e9fd124
RG
594 ClientState(const ComboAddress& local_, bool isTCP, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_): cpus(cpus_), local(local_), interface(itfName), fastOpenQueueSize(fastOpenQueue), tcp(isTCP), reuseport(doReusePort)
595 {
596 }
597
f0e4dcba 598 std::set<int> cpus;
8a5d5053 599 ComboAddress local;
43234e76 600 std::shared_ptr<DNSCryptContext> dnscryptCtx{nullptr};
6e9fd124 601 std::shared_ptr<TLSFrontend> tlsFrontend{nullptr};
fbf14b03 602 std::shared_ptr<DOHFrontend> dohFrontend{nullptr};
6e9fd124 603 std::string interface;
963bef8d 604 std::atomic<uint64_t> queries{0};
a6e9e107
RG
605 std::atomic<uint64_t> tcpDiedReadingQuery{0};
606 std::atomic<uint64_t> tcpDiedSendingResponse{0};
607 std::atomic<uint64_t> tcpGaveUp{0};
608 std::atomic<uint64_t> tcpClientTimeouts{0};
609 std::atomic<uint64_t> tcpDownstreamTimeouts{0};
cff9aa03
RG
610 std::atomic<uint64_t> tcpCurrentConnections{0};
611 std::atomic<double> tcpAvgQueriesPerConnection{0.0};
612 /* in ms */
613 std::atomic<double> tcpAvgConnectionDuration{0.0};
a36ce055
RG
614 int udpFD{-1};
615 int tcpFD{-1};
6e9fd124 616 int fastOpenQueueSize{0};
b5b93e0b 617 bool muted{false};
6e9fd124
RG
618 bool tcp;
619 bool reuseport;
620 bool ready{false};
8429ad04
RG
621
622 int getSocket() const
623 {
624 return udpFD != -1 ? udpFD : tcpFD;
625 }
626
ba7ec340
RG
627 std::string getType() const
628 {
629 std::string result = udpFD != -1 ? "UDP" : "TCP";
630
fbf14b03
RG
631 if (dohFrontend) {
632 result += " (DNS over HTTPS)";
633 }
634 else if (tlsFrontend) {
ba7ec340
RG
635 result += " (DNS over TLS)";
636 }
637 else if (dnscryptCtx) {
638 result += " (DNSCrypt)";
639 }
640
641 return result;
642 }
643
8429ad04
RG
644#ifdef HAVE_EBPF
645 shared_ptr<BPFFilter> d_filter;
646
647 void detachFilter()
648 {
649 if (d_filter) {
650 d_filter->removeSocket(getSocket());
651 d_filter = nullptr;
652 }
653 }
654
655 void attachFilter(shared_ptr<BPFFilter> bpf)
656 {
657 detachFilter();
658
659 bpf->addSocket(getSocket());
660 d_filter = bpf;
661 }
662#endif /* HAVE_EBPF */
cff9aa03
RG
663
664 void updateTCPMetrics(size_t queries, uint64_t durationMs)
665 {
666 tcpAvgQueriesPerConnection = (99.0 * tcpAvgQueriesPerConnection / 100.0) + (queries / 100.0);
667 tcpAvgConnectionDuration = (99.0 * tcpAvgConnectionDuration / 100.0) + (durationMs / 100.0);
668 }
8a5d5053 669};
670
671class TCPClientCollection {
672 std::vector<int> d_tcpclientthreads;
ded1985a 673 std::atomic<uint64_t> d_numthreads{0};
a9bf3ec4 674 std::atomic<uint64_t> d_pos{0};
ded1985a 675 std::atomic<uint64_t> d_queued{0};
73402775 676 const uint64_t d_maxthreads{0};
ded1985a 677 std::mutex d_mutex;
edbda1ad 678 int d_singlePipe[2];
73402775 679 const bool d_useSinglePipe;
ded1985a 680public:
8a5d5053 681
b79e4996
RG
682 TCPClientCollection(size_t maxThreads, bool useSinglePipe=false): d_maxthreads(maxThreads), d_singlePipe{-1,-1}, d_useSinglePipe(useSinglePipe)
683
8a5d5053 684 {
a9bf3ec4 685 d_tcpclientthreads.reserve(maxThreads);
edbda1ad
RG
686
687 if (d_useSinglePipe) {
688 if (pipe(d_singlePipe) < 0) {
689 throw std::runtime_error("Error creating the TCP single communication pipe: " + string(strerror(errno)));
690 }
3b07fd1b
RG
691
692 if (!setNonBlocking(d_singlePipe[0])) {
693 int err = errno;
694 close(d_singlePipe[0]);
695 close(d_singlePipe[1]);
696 throw std::runtime_error("Error setting the TCP single communication pipe non-blocking: " + string(strerror(err)));
697 }
698
edbda1ad
RG
699 if (!setNonBlocking(d_singlePipe[1])) {
700 int err = errno;
701 close(d_singlePipe[0]);
702 close(d_singlePipe[1]);
703 throw std::runtime_error("Error setting the TCP single communication pipe non-blocking: " + string(strerror(err)));
704 }
705 }
8a5d5053 706 }
a9bf3ec4 707 int getThread()
8a5d5053 708 {
6c1ca990 709 uint64_t pos = d_pos++;
8a5d5053 710 ++d_queued;
711 return d_tcpclientthreads[pos % d_numthreads];
712 }
ded1985a
RG
713 bool hasReachedMaxThreads() const
714 {
715 return d_numthreads >= d_maxthreads;
716 }
717 uint64_t getThreadsCount() const
718 {
719 return d_numthreads;
720 }
721 uint64_t getQueuedCount() const
722 {
723 return d_queued;
724 }
725 void decrementQueuedCount()
726 {
727 --d_queued;
728 }
8a5d5053 729 void addTCPClientThread();
730};
731
1f7646c2 732extern std::unique_ptr<TCPClientCollection> g_tcpclientthreads;
8a5d5053 733
df111b53 734struct DownstreamState
735{
1720247e 736 typedef std::function<std::tuple<DNSName, uint16_t, uint16_t>(const DNSName&, uint16_t, uint16_t, dnsheader*)> checkfunc_t;
98650fde 737
150105a2
RG
738 DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf, size_t numberOfSockets);
739 DownstreamState(const ComboAddress& remote_): DownstreamState(remote_, ComboAddress(), 0, 1) {}
6a62c0e3
RG
740 ~DownstreamState()
741 {
5bdbb83d 742 for (auto& fd : sockets) {
150105a2
RG
743 if (fd >= 0) {
744 close(fd);
745 fd = -1;
746 }
747 }
6a62c0e3 748 }
1720247e
CHB
749 boost::uuids::uuid id;
750 std::set<unsigned int> hashes;
d58e616a 751 mutable pthread_rwlock_t d_lock;
5bdbb83d
RG
752 std::vector<int> sockets;
753 std::mutex socketsLock;
5d7e6765 754 std::mutex connectLock;
5bdbb83d 755 std::unique_ptr<FDMultiplexer> mplexer{nullptr};
df111b53 756 std::thread tid;
a2353842 757 const ComboAddress remote;
df111b53 758 QPSLimiter qps;
759 vector<IDState> idStates;
73402775 760 const ComboAddress sourceAddr;
98650fde 761 checkfunc_t checkFunction;
fbe2a2e0
RG
762 DNSName checkName{"a.root-servers.net."};
763 QType checkType{QType::A};
de9f7157 764 uint16_t checkClass{QClass::IN};
df111b53 765 std::atomic<uint64_t> idOffset{0};
766 std::atomic<uint64_t> sendErrors{0};
767 std::atomic<uint64_t> outstanding{0};
768 std::atomic<uint64_t> reuseds{0};
769 std::atomic<uint64_t> queries{0};
770 struct {
771 std::atomic<uint64_t> sendErrors{0};
772 std::atomic<uint64_t> reuseds{0};
773 std::atomic<uint64_t> queries{0};
774 } prev;
a6e9e107
RG
775 std::atomic<uint64_t> tcpDiedSendingQuery{0};
776 std::atomic<uint64_t> tcpDiedReadingResponse{0};
777 std::atomic<uint64_t> tcpGaveUp{0};
778 std::atomic<uint64_t> tcpReadTimeouts{0};
779 std::atomic<uint64_t> tcpWriteTimeouts{0};
cff9aa03
RG
780 std::atomic<uint64_t> tcpCurrentConnections{0};
781 std::atomic<double> tcpAvgQueriesPerConnection{0.0};
782 /* in ms */
783 std::atomic<double> tcpAvgConnectionDuration{0.0};
18eeccc9 784 string name;
5bdbb83d 785 size_t socketsOffset{0};
df111b53 786 double queryLoad{0.0};
787 double dropRate{0.0};
788 double latencyUsec{0.0};
789 int order{1};
790 int weight{1};
b40cffe7 791 int tcpConnectTimeout{5};
3f6d07a4
RG
792 int tcpRecvTimeout{30};
793 int tcpSendTimeout{30};
7c9bf18d 794 unsigned int checkInterval{1};
795 unsigned int lastCheck{0};
73402775 796 const unsigned int sourceItf{0};
3f6d07a4 797 uint16_t retries{5};
c85f69a8 798 uint16_t xpfRRCode{0};
b7e6f4a1 799 uint16_t checkTimeout{1000}; /* in milliseconds */
9e87dcb8 800 uint8_t currentCheckFailures{0};
853faf61 801 uint8_t consecutiveSuccessfulChecks{0};
9e87dcb8 802 uint8_t maxCheckFailures{1};
1b633bec 803 uint8_t minRiseSuccesses{1};
df111b53 804 StopWatch sw;
805 set<string> pools;
806 enum class Availability { Up, Down, Auto} availability{Availability::Auto};
fbe2a2e0 807 bool mustResolve{false};
df111b53 808 bool upStatus{false};
ca404e94 809 bool useECS{false};
21830638 810 bool setCD{false};
49c33a6c 811 bool disableZeroScope{false};
7565f4e6 812 std::atomic<bool> connected{false};
5d7e6765 813 std::atomic_flag threadStarted;
284d460c 814 bool tcpFastOpen{false};
5602f131 815 bool ipBindAddrNoPort{true};
5d7e6765 816
df111b53 817 bool isUp() const
818 {
819 if(availability == Availability::Down)
820 return false;
821 if(availability == Availability::Up)
822 return true;
823 return upStatus;
824 }
825 void setUp() { availability = Availability::Up; }
826 void setDown() { availability = Availability::Down; }
827 void setAuto() { availability = Availability::Auto; }
18eeccc9
RG
828 string getName() const {
829 if (name.empty()) {
830 return remote.toStringWithPort();
831 }
832 return name;
833 }
a7940c06 834 string getNameWithAddr() const {
835 if (name.empty()) {
836 return remote.toStringWithPort();
837 }
838 return name + " (" + remote.toStringWithPort()+ ")";
839 }
9f4eb5cc
RG
840 string getStatus() const
841 {
842 string status;
843 if(availability == DownstreamState::Availability::Up)
844 status = "UP";
845 else if(availability == DownstreamState::Availability::Down)
846 status = "DOWN";
847 else
848 status = (upStatus ? "up" : "down");
849 return status;
850 }
5d7e6765 851 bool reconnect();
f2caf657
CHB
852 void hash();
853 void setId(const boost::uuids::uuid& newId);
854 void setWeight(int newWeight);
cff9aa03
RG
855
856 void updateTCPMetrics(size_t queries, uint64_t durationMs)
857 {
858 tcpAvgQueriesPerConnection = (99.0 * tcpAvgQueriesPerConnection / 100.0) + (queries / 100.0);
859 tcpAvgConnectionDuration = (99.0 * tcpAvgConnectionDuration / 100.0) + (durationMs / 100.0);
860 }
df111b53 861};
862using servers_t =vector<std::shared_ptr<DownstreamState>>;
df111b53 863
da4e7813 864template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
865
9b73b71c 866void responderThread(std::shared_ptr<DownstreamState> state);
da4e7813 867extern std::mutex g_luamutex;
868extern LuaContext g_lua;
869extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
870
0940e4eb 871class DNSRule
872{
873public:
205f2081
RG
874 virtual ~DNSRule ()
875 {
876 }
497a6e3a 877 virtual bool matches(const DNSQuestion* dq) const =0;
0940e4eb 878 virtual string toString() const = 0;
879 mutable std::atomic<uint64_t> d_matches{0};
880};
881
da4e7813 882using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
497a6e3a 883typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
df111b53 884
885struct ServerPolicy
886{
887 string name;
70a57b05 888 policyfunc_t policy;
a1b1a29d 889 bool isLua;
a4fd2d2f
CH
890 std::string toString() const {
891 return string("ServerPolicy") + (isLua ? " (Lua)" : "") + " \"" + name + "\"";
892 }
df111b53 893};
894
886e2cf2
RG
895struct ServerPool
896{
a1b1a29d
RG
897 ServerPool()
898 {
899 pthread_rwlock_init(&d_lock, nullptr);
900 }
901
886e2cf2
RG
902 const std::shared_ptr<DNSDistPacketCache> getCache() const { return packetCache; };
903
7e687744
RG
904 bool getECS() const
905 {
906 return d_useECS;
907 }
908
909 void setECS(bool useECS)
910 {
911 d_useECS = useECS;
912 }
913
886e2cf2 914 std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
b9f8a6c8 915 std::shared_ptr<ServerPolicy> policy{nullptr};
5c30ec69 916
a1b1a29d
RG
917 size_t countServers(bool upOnly)
918 {
919 size_t count = 0;
920 ReadLock rl(&d_lock);
921 for (const auto& server : d_servers) {
922 if (!upOnly || std::get<1>(server)->isUp() ) {
923 count++;
c1b81381
RG
924 }
925 }
a1b1a29d
RG
926 return count;
927 }
928
929 NumberedVector<shared_ptr<DownstreamState>> getServers()
930 {
931 NumberedVector<shared_ptr<DownstreamState>> result;
932 {
933 ReadLock rl(&d_lock);
934 result = d_servers;
935 }
936 return result;
937 }
938
939 void addServer(shared_ptr<DownstreamState>& server)
940 {
941 WriteLock wl(&d_lock);
942 unsigned int count = (unsigned int) d_servers.size();
943 d_servers.push_back(make_pair(++count, server));
944 /* we need to reorder based on the server 'order' */
945 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) {
946 return a.second->order < b.second->order;
947 });
948 /* and now we need to renumber for Lua (custom policies) */
949 size_t idx = 1;
950 for (auto& serv : d_servers) {
951 serv.first = idx++;
952 }
953 }
954
955 void removeServer(shared_ptr<DownstreamState>& server)
956 {
957 WriteLock wl(&d_lock);
958 size_t idx = 1;
959 bool found = false;
960 for (auto it = d_servers.begin(); it != d_servers.end();) {
961 if (found) {
962 /* we need to renumber the servers placed
963 after the removed one, for Lua (custom policies) */
964 it->first = idx++;
965 it++;
966 }
967 else if (it->second == server) {
968 it = d_servers.erase(it);
969 found = true;
970 } else {
971 idx++;
972 it++;
973 }
974 }
975 }
976
977private:
978 NumberedVector<shared_ptr<DownstreamState>> d_servers;
979 pthread_rwlock_t d_lock;
7e687744 980 bool d_useECS{false};
886e2cf2
RG
981};
982using pools_t=map<std::string,std::shared_ptr<ServerPool>>;
742c079a 983void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<ServerPolicy> policy);
886e2cf2
RG
984void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
985void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
986
42fae326 987struct CarbonConfig
988{
d617b22c 989 ComboAddress server;
813b0ba9 990 std::string namespace_name;
42fae326 991 std::string ourname;
813b0ba9 992 std::string instance_name;
d617b22c 993 unsigned int interval;
42fae326 994};
995
ca404e94
RG
996enum ednsHeaderFlags {
997 EDNS_HEADER_FLAG_NONE = 0,
998 EDNS_HEADER_FLAG_DO = 32768
999};
1000
4d5959e6
RG
1001struct DNSDistRuleAction
1002{
1003 std::shared_ptr<DNSRule> d_rule;
1004 std::shared_ptr<DNSAction> d_action;
1005 boost::uuids::uuid d_id;
f8a222ac 1006 uint64_t d_creationOrder;
4d5959e6
RG
1007};
1008
1009struct DNSDistResponseRuleAction
1010{
1011 std::shared_ptr<DNSRule> d_rule;
1012 std::shared_ptr<DNSResponseAction> d_action;
1013 boost::uuids::uuid d_id;
f8a222ac 1014 uint64_t d_creationOrder;
4d5959e6
RG
1015};
1016
71c94675 1017extern GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
dd46e5e3 1018extern DNSAction::Action g_dynBlockAction;
71c94675 1019
d617b22c 1020extern GlobalStateHolder<vector<CarbonConfig> > g_carbon;
ecbe9133 1021extern GlobalStateHolder<ServerPolicy> g_policy;
1022extern GlobalStateHolder<servers_t> g_dstates;
886e2cf2 1023extern GlobalStateHolder<pools_t> g_pools;
4d5959e6
RG
1024extern GlobalStateHolder<vector<DNSDistRuleAction> > g_rulactions;
1025extern GlobalStateHolder<vector<DNSDistResponseRuleAction> > g_resprulactions;
1026extern GlobalStateHolder<vector<DNSDistResponseRuleAction> > g_cachehitresprulactions;
2d4783a8 1027extern GlobalStateHolder<vector<DNSDistResponseRuleAction> > g_selfansweredresprulactions;
638184e9 1028extern GlobalStateHolder<NetmaskGroup> g_ACL;
2e72cc0e 1029
ecbe9133 1030extern ComboAddress g_serverControl; // not changed during runtime
1031
f0e4dcba 1032extern std::vector<std::tuple<ComboAddress, bool, bool, int, std::string, std::set<int>>> g_locals; // not changed at runtime (we hope XXX)
a227f47d 1033extern std::vector<shared_ptr<TLSFrontend>> g_tlslocals;
fbf14b03 1034extern std::vector<shared_ptr<DOHFrontend>> g_dohlocals;
6e9fd124 1035extern std::vector<std::unique_ptr<ClientState>> g_frontends;
6ad8b29a 1036extern bool g_truncateTC;
b29edbee 1037extern bool g_fixupCase;
3f6d07a4
RG
1038extern int g_tcpRecvTimeout;
1039extern int g_tcpSendTimeout;
e0b5e49d 1040extern int g_udpTimeout;
e41f8165
RG
1041extern uint16_t g_maxOutstanding;
1042extern std::atomic<bool> g_configurationDone;
6c1ca990
RG
1043extern uint64_t g_maxTCPClientThreads;
1044extern uint64_t g_maxTCPQueuedConnections;
9396d955
RG
1045extern size_t g_maxTCPQueriesPerConn;
1046extern size_t g_maxTCPConnectionDuration;
1047extern size_t g_maxTCPConnectionsPerClient;
886e2cf2 1048extern std::atomic<uint16_t> g_cacheCleaningDelay;
f65ea0c2 1049extern std::atomic<uint16_t> g_cacheCleaningPercentage;
9e87dcb8 1050extern bool g_verboseHealthChecks;
1ea747c0 1051extern uint32_t g_staleCacheEntriesTTL;
56d68fad
RG
1052extern bool g_apiReadWrite;
1053extern std::string g_apiConfigDirectory;
26a3cdb7 1054extern bool g_servFailOnNoPolicy;
36e763fa 1055extern uint32_t g_hashperturb;
edbda1ad 1056extern bool g_useTCPSinglePipe;
cff9aa03 1057extern uint16_t g_downstreamTCPCleanupInterval;
0beaa5c8 1058extern size_t g_udpVectorSize;
53c57da7 1059extern bool g_preserveTrailingData;
0dffe9e3 1060extern bool g_allowEmptyResponse;
32b86928 1061extern bool g_roundrobinFailOnNoServer;
ca404e94 1062
87b515ed
RG
1063#ifdef HAVE_EBPF
1064extern shared_ptr<BPFFilter> g_defaultBPFFilter;
8429ad04 1065extern std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
87b515ed
RG
1066#endif /* HAVE_EBPF */
1067
0beaa5c8
RG
1068struct LocalHolders
1069{
2d4783a8 1070 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
1071 {
1072 }
1073
1074 LocalStateHolder<NetmaskGroup> acl;
1075 LocalStateHolder<ServerPolicy> policy;
4d5959e6
RG
1076 LocalStateHolder<vector<DNSDistRuleAction> > rulactions;
1077 LocalStateHolder<vector<DNSDistResponseRuleAction> > cacheHitRespRulactions;
2d4783a8 1078 LocalStateHolder<vector<DNSDistResponseRuleAction> > selfAnsweredRespRulactions;
0beaa5c8
RG
1079 LocalStateHolder<servers_t> servers;
1080 LocalStateHolder<NetmaskTree<DynBlock> > dynNMGBlock;
1081 LocalStateHolder<SuffixMatchTree<DynBlock> > dynSMTBlock;
1082 LocalStateHolder<pools_t> pools;
1083};
1084
ecbe9133 1085struct dnsheader;
1086
1087void controlThread(int fd, ComboAddress local);
839f3021 1088vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
886e2cf2
RG
1089std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
1090std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName);
a1b1a29d 1091NumberedServerVector getDownstreamCandidates(const pools_t& pools, const std::string& poolName);
da4e7813 1092
497a6e3a 1093std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq);
ecbe9133 1094
497a6e3a
RG
1095std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq);
1096std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq);
1097std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq);
1720247e 1098std::shared_ptr<DownstreamState> chashed(const NumberedServerVector& servers, const DNSQuestion* dq);
497a6e3a 1099std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq);
e7c732b8 1100
80dbd7d2
CHB
1101struct WebserverConfig
1102{
1103 std::string password;
1104 std::string apiKey;
1105 boost::optional<std::map<std::string, std::string> > customHeaders;
1106 std::mutex lock;
1107};
1108
32c97b56
CHB
1109void setWebserverAPIKey(const boost::optional<std::string> apiKey);
1110void setWebserverPassword(const std::string& password);
1111void setWebserverCustomHeaders(const boost::optional<std::map<std::string, std::string> > customHeaders);
1112
80dbd7d2 1113void dnsdistWebserverThread(int sock, const ComboAddress& local);
9b73b71c 1114void tcpAcceptorThread(void* p);
fbf14b03
RG
1115#ifdef HAVE_DNS_OVER_HTTPS
1116void dohThread(ClientState* cs);
1117#endif /* HAVE_DNS_OVER_HTTPS */
80a216c9 1118
f758857a 1119void setLuaNoSideEffect(); // if nothing has been declared, set that there are no side effects
1120void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ side effect calls
1121bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
1122void resetLuaSideEffect(); // reset to indeterminate state
11e1e08b 1123
e7c732b8 1124bool responseContentMatches(const char* response, const uint16_t responseLen, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& consumed);
3e425868 1125bool processResponse(char** response, uint16_t* responseLen, size_t* responseSize, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, size_t addRoom, std::vector<uint8_t>& rewrittenResponse, bool muted);
4ab01344 1126
0beaa5c8 1127bool checkQueryHeaders(const struct dnsheader* dh);
fcffc585 1128
6e9fd124 1129extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
43234e76 1130int handleDNSCryptQuery(char* packet, uint16_t len, std::shared_ptr<DNSCryptQuery> query, uint16_t* decryptedQueryLen, bool tcp, time_t now, std::vector<uint8_t>& response);
4ab01344 1131boost::optional<std::vector<uint8_t>> checkDNSCryptQuery(const ClientState& cs, const char* query, uint16_t& len, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
9f4eb5cc 1132
18f707fa 1133bool addXPF(DNSQuestion& dq, uint16_t optionCode);
5cc8371b 1134
555970c9
RG
1135uint16_t getRandomDNSID();
1136
9f4eb5cc
RG
1137#include "dnsdist-snmp.hh"
1138
1139extern bool g_snmpEnabled;
1140extern bool g_snmpTrapsEnabled;
1141extern DNSDistSNMPAgent* g_snmpAgent;
e7c732b8
RG
1142extern bool g_addEDNSToSelfGeneratedResponses;
1143
1144static const size_t s_udpIncomingBufferSize{1500};
4ab01344 1145
3e425868
RG
1146enum class ProcessQueryResult { Drop, SendAnswer, PassToBackend };
1147ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
4ab01344 1148
d0ae6360
RG
1149DNSResponse makeDNSResponseFromIDState(IDState& ids, struct dnsheader* dh, size_t bufferSize, uint16_t responseLen, bool isTCP);
1150void setIDStateFromDNSQuestion(IDState& ids, DNSQuestion& dq, DNSName&& qname);
fbf14b03
RG
1151
1152int pickBackendSocketForSending(std::shared_ptr<DownstreamState>& state);
1153ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const char* request, const size_t requestLen, bool healthCheck=false);