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