]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist.hh
Merge pull request #3302 from rgacogne/auth-yeti
[thirdparty/pdns.git] / pdns / dnsdist.hh
CommitLineData
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>
ecbe9133 13#include "sholder.hh"
11e1e08b 14#include "dnscrypt.hh"
42fae326 15void* carbonDumpThread();
61d1b966 16uint64_t uptimeOfProcess(const std::string& str);
bd1c631b 17
78ffa782 18struct DynBlock
19{
20 DynBlock& operator=(const DynBlock& rhs)
21 {
22 reason=rhs.reason;
23 until=rhs.until;
24 blocks.store(rhs.blocks);
25 return *this;
26 }
27
28 string reason;
29 struct timespec until;
30 mutable std::atomic<unsigned int> blocks;
31};
32
33extern GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
f758857a 34
35extern vector<pair<struct timeval, std::string> > g_confDelta;
36
e48090d1 37struct DNSDistStats
38{
6ad8b29a 39 using stat_t=std::atomic<uint64_t>; // aww yiss ;-)
e48090d1 40 stat_t responses{0};
41 stat_t servfailResponses{0};
42 stat_t queries{0};
e73ec7d3 43 stat_t nonCompliantQueries{0};
643a182a 44 stat_t rdQueries{0};
2efd427d 45 stat_t emptyQueries{0};
e48090d1 46 stat_t aclDrops{0};
47 stat_t blockFilter{0};
bd1c631b 48 stat_t dynBlocked{0};
e48090d1 49 stat_t ruleDrop{0};
50 stat_t ruleNXDomain{0};
51 stat_t selfAnswered{0};
52 stat_t downstreamTimeouts{0};
53 stat_t downstreamSendErrors{0};
6ad8b29a 54 stat_t truncFail{0};
b8bc7e61 55 stat_t noPolicy{0};
42fae326 56 stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0};
e48090d1 57
e16fd59c 58 double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
a1a787dc 59 typedef std::function<uint64_t(const std::string&)> statfunction_t;
60 typedef boost::variant<stat_t*, double*, statfunction_t> entry_t;
e16fd59c 61 std::vector<std::pair<std::string, entry_t>> entries{
42fae326 62 {"responses", &responses}, {"servfail-responses", &servfailResponses},
63 {"queries", &queries}, {"acl-drops", &aclDrops},
64 {"block-filter", &blockFilter}, {"rule-drop", &ruleDrop},
65 {"rule-nxdomain", &ruleNXDomain}, {"self-answered", &selfAnswered},
66 {"downstream-timeouts", &downstreamTimeouts}, {"downstream-send-errors", &downstreamSendErrors},
67 {"trunc-failures", &truncFail}, {"no-policy", &noPolicy},
68 {"latency0-1", &latency0_1}, {"latency1-10", &latency1_10},
69 {"latency10-50", &latency10_50}, {"latency50-100", &latency50_100},
e16fd59c 70 {"latency100-1000", &latency100_1000}, {"latency-slow", &latencySlow},
71 {"latency-avg100", &latencyAvg100}, {"latency-avg1000", &latencyAvg1000},
a1a787dc 72 {"latency-avg10000", &latencyAvg10000}, {"latency-avg1000000", &latencyAvg1000000},
61d1b966 73 {"uptime", uptimeOfProcess},
a9b6db56 74 {"real-memory-usage", getRealMemoryUsage},
a2aa00ed 75 {"noncompliant-queries", &nonCompliantQueries},
643a182a 76 {"rdqueries", &rdQueries},
2efd427d 77 {"empty-queries", &emptyQueries},
4f99f3d3
RG
78 {"cpu-user-msec", getCPUTimeUser},
79 {"cpu-sys-msec", getCPUTimeSystem},
bd1c631b 80 {"fd-usage", getOpenFileDescriptors}, {"dyn-blocked", &dynBlocked},
81 {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }}
42fae326 82 };
e48090d1 83};
84
e16fd59c 85
e48090d1 86extern struct DNSDistStats g_stats;
87
638184e9 88
df111b53 89struct StopWatch
90{
91#ifndef CLOCK_MONOTONIC_RAW
92#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
93#endif
94 struct timespec d_start{0,0};
95 void start() {
96 if(clock_gettime(CLOCK_MONOTONIC_RAW, &d_start) < 0)
97 unixDie("Getting timestamp");
98
99 }
100
101 double udiff() const {
102 struct timespec now;
103 if(clock_gettime(CLOCK_MONOTONIC_RAW, &now) < 0)
104 unixDie("Getting timestamp");
105
106 return 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
107 }
108
109 double udiffAndSet() {
110 struct timespec now;
111 if(clock_gettime(CLOCK_MONOTONIC_RAW, &now) < 0)
112 unixDie("Getting timestamp");
113
114 auto ret= 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
115 d_start = now;
116 return ret;
117 }
118
119};
120
121class QPSLimiter
122{
123public:
124 QPSLimiter()
125 {
126 }
127
128 QPSLimiter(unsigned int rate, unsigned int burst) : d_rate(rate), d_burst(burst), d_tokens(burst)
129 {
130 d_passthrough=false;
131 d_prev.start();
132 }
133
134 unsigned int getRate() const
135 {
136 return d_passthrough? 0 : d_rate;
137 }
138
139 int getPassed() const
140 {
141 return d_passed;
142 }
143 int getBlocked() const
144 {
145 return d_blocked;
146 }
147
ecbe9133 148 bool check() const // this is not quite fair
df111b53 149 {
150 if(d_passthrough)
151 return true;
152 auto delta = d_prev.udiffAndSet();
153
154 d_tokens += 1.0*d_rate * (delta/1000000.0);
155
156 if(d_tokens > d_burst)
157 d_tokens = d_burst;
158
159 bool ret=false;
160 if(d_tokens >= 1.0) { // we need this because burst=1 is weird otherwise
161 ret=true;
162 --d_tokens;
163 d_passed++;
164 }
165 else
166 d_blocked++;
167
168 return ret;
169 }
170private:
171 bool d_passthrough{true};
172 unsigned int d_rate;
173 unsigned int d_burst;
ecbe9133 174 mutable double d_tokens;
175 mutable StopWatch d_prev;
176 mutable unsigned int d_passed{0};
177 mutable unsigned int d_blocked{0};
df111b53 178};
179
df111b53 180struct IDState
181{
c9ba8478 182 IDState() : origFD(-1), delayMsec(0) { origDest.sin4.sin_family = 0;}
df111b53 183 IDState(const IDState& orig)
184 {
185 origFD = orig.origFD;
186 origID = orig.origID;
187 origRemote = orig.origRemote;
549d63c9 188 origDest = orig.origDest;
7b3865cd 189 delayMsec = orig.delayMsec;
df111b53 190 age.store(orig.age.load());
191 }
192
2bf26975 193 int origFD; // set to <0 to indicate this state is empty // 4
194
195 ComboAddress origRemote; // 28
549d63c9 196 ComboAddress origDest; // 28
2bf26975 197 StopWatch sentTime; // 16
198 DNSName qname; // 80
11e1e08b
RG
199#ifdef HAVE_DNSCRYPT
200 std::shared_ptr<DnsCryptQuery> dnsCryptQuery{0};
201#endif
2bf26975 202 std::atomic<uint16_t> age; // 4
203 uint16_t qtype; // 2
204 uint16_t origID; // 2
aeb36780 205 uint16_t origFlags; // 2
7b3865cd 206 int delayMsec;
ca404e94 207 bool ednsAdded{false};
df111b53 208};
209
210struct Rings {
211 Rings()
212 {
df111b53 213 queryRing.set_capacity(10000);
214 respRing.set_capacity(10000);
0e41337b 215 pthread_rwlock_init(&queryLock, 0);
df111b53 216 }
0ba5eecf 217 struct Query
218 {
219 struct timespec when;
220 ComboAddress requestor;
221 DNSName name;
03ebf8b2 222 uint16_t size;
0ba5eecf 223 uint16_t qtype;
3fcaeeac 224 struct dnsheader dh;
0ba5eecf 225 };
226 boost::circular_buffer<Query> queryRing;
df111b53 227 struct Response
228 {
80a216c9 229 struct timespec when;
230 ComboAddress requestor;
df111b53 231 DNSName name;
232 uint16_t qtype;
df111b53 233 unsigned int usec;
80a216c9 234 unsigned int size;
3fcaeeac 235 struct dnsheader dh;
2d11d1b2 236 ComboAddress ds; // who handled it
df111b53 237 };
238 boost::circular_buffer<Response> respRing;
239 std::mutex respMutex;
0e41337b 240 pthread_rwlock_t queryLock;
03ebf8b2 241
ddafcf1e 242 vector<pair<unsigned int, ComboAddress> > getTopBandwidth(unsigned int numentries);
03ebf8b2 243 unsigned int numDistinctRequestors();
df111b53 244};
245
0e41337b 246extern Rings g_rings;
df111b53 247
8a5d5053 248struct ClientState
249{
250 ComboAddress local;
11e1e08b
RG
251#ifdef HAVE_DNSCRYPT
252 DnsCryptContext* dnscryptCtx{0};
253#endif
963bef8d 254 std::atomic<uint64_t> queries{0};
a36ce055
RG
255 int udpFD{-1};
256 int tcpFD{-1};
8a5d5053 257};
258
259class TCPClientCollection {
260 std::vector<int> d_tcpclientthreads;
261 std::atomic<uint64_t> d_pos;
262public:
263 std::atomic<uint64_t> d_queued, d_numthreads;
264
265 TCPClientCollection()
266 {
267 d_tcpclientthreads.reserve(1024);
268 }
269
270 int getThread()
271 {
272 int pos = d_pos++;
273 ++d_queued;
274 return d_tcpclientthreads[pos % d_numthreads];
275 }
276 void addTCPClientThread();
277};
278
279extern TCPClientCollection g_tcpclientthreads;
280
df111b53 281struct DownstreamState
282{
fbe2a2e0
RG
283 DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf);
284 DownstreamState(const ComboAddress& remote_): DownstreamState(remote_, ComboAddress(), 0) {}
6a62c0e3
RG
285 ~DownstreamState()
286 {
287 if (fd >= 0)
288 close(fd);
289 }
df111b53 290
f99e3aaf 291 int fd{-1};
df111b53 292 std::thread tid;
293 ComboAddress remote;
294 QPSLimiter qps;
295 vector<IDState> idStates;
fbe2a2e0
RG
296 ComboAddress sourceAddr;
297 DNSName checkName{"a.root-servers.net."};
298 QType checkType{QType::A};
df111b53 299 std::atomic<uint64_t> idOffset{0};
300 std::atomic<uint64_t> sendErrors{0};
301 std::atomic<uint64_t> outstanding{0};
302 std::atomic<uint64_t> reuseds{0};
303 std::atomic<uint64_t> queries{0};
304 struct {
305 std::atomic<uint64_t> sendErrors{0};
306 std::atomic<uint64_t> reuseds{0};
307 std::atomic<uint64_t> queries{0};
308 } prev;
18eeccc9 309 string name;
df111b53 310 double queryLoad{0.0};
311 double dropRate{0.0};
312 double latencyUsec{0.0};
313 int order{1};
314 int weight{1};
3f6d07a4
RG
315 int tcpRecvTimeout{30};
316 int tcpSendTimeout{30};
fbe2a2e0 317 unsigned int sourceItf{0};
3f6d07a4 318 uint16_t retries{5};
df111b53 319 StopWatch sw;
320 set<string> pools;
321 enum class Availability { Up, Down, Auto} availability{Availability::Auto};
fbe2a2e0 322 bool mustResolve{false};
df111b53 323 bool upStatus{false};
ca404e94 324 bool useECS{false};
df111b53 325 bool isUp() const
326 {
327 if(availability == Availability::Down)
328 return false;
329 if(availability == Availability::Up)
330 return true;
331 return upStatus;
332 }
333 void setUp() { availability = Availability::Up; }
334 void setDown() { availability = Availability::Down; }
335 void setAuto() { availability = Availability::Auto; }
18eeccc9
RG
336 string getName() const {
337 if (name.empty()) {
338 return remote.toStringWithPort();
339 }
340 return name;
341 }
a7940c06 342 string getNameWithAddr() const {
343 if (name.empty()) {
344 return remote.toStringWithPort();
345 }
346 return name + " (" + remote.toStringWithPort()+ ")";
347 }
348
df111b53 349};
350using servers_t =vector<std::shared_ptr<DownstreamState>>;
df111b53 351
497a6e3a
RG
352struct DNSQuestion
353{
354 DNSQuestion(const DNSName* name, uint16_t type, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp): qname(name), qtype(type), local(lc), remote(rem), dh(header), size(bufferSize), len(queryLen), tcp(isTcp) {};
355
356 const DNSName* qname;
357 const uint16_t qtype;
358 const ComboAddress* local;
359 const ComboAddress* remote;
360 struct dnsheader* dh;
361 size_t size;
362 uint16_t len;
363 const bool tcp;
364};
365
da4e7813 366template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
367
368void* responderThread(std::shared_ptr<DownstreamState> state);
369extern std::mutex g_luamutex;
370extern LuaContext g_lua;
371extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
372
0940e4eb 373class DNSRule
374{
375public:
497a6e3a 376 virtual bool matches(const DNSQuestion* dq) const =0;
0940e4eb 377 virtual string toString() const = 0;
378 mutable std::atomic<uint64_t> d_matches{0};
379};
380
381/* so what could you do:
382 drop,
383 fake up nxdomain,
384 provide actual answer,
385 allow & and stop processing,
386 continue processing,
387 modify header: (servfail|refused|notimp), set TC=1,
388 send to pool */
389
390class DNSAction
391{
392public:
7b3865cd 393 enum class Action { Drop, Nxdomain, Spoof, Allow, HeaderModify, Pool, Delay, None};
497a6e3a 394 virtual Action operator()(DNSQuestion*, string* ruleresult) const =0;
0940e4eb 395 virtual string toString() const = 0;
396};
397
da4e7813 398using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
497a6e3a 399typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
df111b53 400
401struct ServerPolicy
402{
403 string name;
70a57b05 404 policyfunc_t policy;
df111b53 405};
406
42fae326 407struct CarbonConfig
408{
409 ComboAddress server{"0.0.0.0", 0};
410 std::string ourname;
411 unsigned int interval{30};
412};
413
ca404e94
RG
414enum ednsHeaderFlags {
415 EDNS_HEADER_FLAG_NONE = 0,
416 EDNS_HEADER_FLAG_DO = 32768
417};
418
419enum ednsOptionCodes {
420 EDNS0_OPTION_CODE_NONE = 0,
421 EDNS0_OPTION_CODE_ECS = 8,
422};
423
42fae326 424extern GlobalStateHolder<CarbonConfig> g_carbon;
ecbe9133 425extern GlobalStateHolder<ServerPolicy> g_policy;
426extern GlobalStateHolder<servers_t> g_dstates;
0940e4eb 427extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions;
638184e9 428extern GlobalStateHolder<NetmaskGroup> g_ACL;
2e72cc0e 429
ecbe9133 430extern ComboAddress g_serverControl; // not changed during runtime
431
652a7355 432extern std::vector<std::pair<ComboAddress, bool>> g_locals; // not changed at runtime (we hope XXX)
963bef8d 433extern vector<ClientState*> g_frontends;
ecbe9133 434extern std::string g_key; // in theory needs locking
6ad8b29a 435extern bool g_truncateTC;
b29edbee 436extern bool g_fixupCase;
3f6d07a4
RG
437extern int g_tcpRecvTimeout;
438extern int g_tcpSendTimeout;
e41f8165
RG
439extern uint16_t g_maxOutstanding;
440extern std::atomic<bool> g_configurationDone;
441extern std::atomic<uint64_t> g_maxTCPClientThreads;
ca404e94
RG
442extern uint16_t g_ECSSourcePrefixV4;
443extern uint16_t g_ECSSourcePrefixV6;
444extern bool g_ECSOverride;
445
ecbe9133 446struct dnsheader;
447
448void controlThread(int fd, ComboAddress local);
839f3021 449vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
da4e7813 450NumberedServerVector getDownstreamCandidates(const servers_t& servers, const std::string& pool);
451
497a6e3a 452std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq);
ecbe9133 453
497a6e3a
RG
454std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq);
455std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq);
456std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq);
457std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq);
520eb5a0 458int getEDNSZ(const char* packet, unsigned int len);
6ca7a40a 459void spoofResponseFromString(DNSQuestion& dq, const string& spoofContent);
ca404e94 460uint16_t getEDNSOptionCode(const char * packet, size_t len);
50bed881 461void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password);
6885d4bf 462bool getMsgLen32(int fd, uint32_t* len);
463bool putMsgLen32(int fd, uint32_t len);
d8d85a30 464void* tcpAcceptorThread(void* p);
80a216c9 465
466void moreLua();
ffb07158 467void doClient(ComboAddress server, const std::string& command);
468void doConsole();
469void controlClientThread(int fd, ComboAddress client);
470extern "C" {
471char** my_completion( const char * text , int start, int end);
472}
f758857a 473void setLuaNoSideEffect(); // if nothing has been declared, set that there are no side effects
474void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ side effect calls
475bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
476void resetLuaSideEffect(); // reset to indeterminate state
11e1e08b
RG
477
478#ifdef HAVE_DNSCRYPT
479extern std::vector<std::pair<ComboAddress,DnsCryptContext>> g_dnsCryptLocals;
480
481int handleDnsCryptQuery(DnsCryptContext* ctx, char* packet, uint16_t len, std::shared_ptr<DnsCryptQuery>& query, uint16_t* decryptedQueryLen, bool tcp, std::vector<uint8_t>& reponse);
482#endif