]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist.hh
unify various rings, make generic query infra NOTE - WE STILL DON'T LOCK THE RINGS...
[thirdparty/pdns.git] / pdns / dnsdist.hh
CommitLineData
df111b53 1#pragma once
2#include "ext/luawrapper/include/LuaContext.hpp"
3#include <time.h>
4#include "misc.hh"
5#include "iputils.hh"
6#include "dnsname.hh"
7#include <atomic>
8#include <boost/circular_buffer.hpp>
e16fd59c 9#include <boost/variant.hpp>
df111b53 10#include <mutex>
11#include <thread>
ecbe9133 12#include "sholder.hh"
42fae326 13void* carbonDumpThread();
61d1b966 14uint64_t uptimeOfProcess(const std::string& str);
e48090d1 15struct DNSDistStats
16{
6ad8b29a 17 using stat_t=std::atomic<uint64_t>; // aww yiss ;-)
e48090d1 18 stat_t responses{0};
19 stat_t servfailResponses{0};
20 stat_t queries{0};
e73ec7d3 21 stat_t nonCompliantQueries{0};
e48090d1 22 stat_t aclDrops{0};
23 stat_t blockFilter{0};
24 stat_t ruleDrop{0};
25 stat_t ruleNXDomain{0};
26 stat_t selfAnswered{0};
27 stat_t downstreamTimeouts{0};
28 stat_t downstreamSendErrors{0};
6ad8b29a 29 stat_t truncFail{0};
b8bc7e61 30 stat_t noPolicy{0};
42fae326 31 stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0};
e48090d1 32
e16fd59c 33 double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
a1a787dc 34 typedef std::function<uint64_t(const std::string&)> statfunction_t;
35 typedef boost::variant<stat_t*, double*, statfunction_t> entry_t;
e16fd59c 36 std::vector<std::pair<std::string, entry_t>> entries{
42fae326 37 {"responses", &responses}, {"servfail-responses", &servfailResponses},
38 {"queries", &queries}, {"acl-drops", &aclDrops},
39 {"block-filter", &blockFilter}, {"rule-drop", &ruleDrop},
40 {"rule-nxdomain", &ruleNXDomain}, {"self-answered", &selfAnswered},
41 {"downstream-timeouts", &downstreamTimeouts}, {"downstream-send-errors", &downstreamSendErrors},
42 {"trunc-failures", &truncFail}, {"no-policy", &noPolicy},
43 {"latency0-1", &latency0_1}, {"latency1-10", &latency1_10},
44 {"latency10-50", &latency10_50}, {"latency50-100", &latency50_100},
e16fd59c 45 {"latency100-1000", &latency100_1000}, {"latency-slow", &latencySlow},
46 {"latency-avg100", &latencyAvg100}, {"latency-avg1000", &latencyAvg1000},
a1a787dc 47 {"latency-avg10000", &latencyAvg10000}, {"latency-avg1000000", &latencyAvg1000000},
61d1b966 48 {"uptime", uptimeOfProcess},
a9b6db56 49 {"real-memory-usage", getRealMemoryUsage},
a2aa00ed 50 {"noncompliant-queries", &nonCompliantQueries},
4f99f3d3
RG
51 {"cpu-user-msec", getCPUTimeUser},
52 {"cpu-sys-msec", getCPUTimeSystem},
a9b6db56 53 {"fd-usage", getOpenFileDescriptors}
42fae326 54 };
e48090d1 55};
56
e16fd59c 57
e48090d1 58extern struct DNSDistStats g_stats;
59
638184e9 60
df111b53 61struct StopWatch
62{
63#ifndef CLOCK_MONOTONIC_RAW
64#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
65#endif
66 struct timespec d_start{0,0};
67 void start() {
68 if(clock_gettime(CLOCK_MONOTONIC_RAW, &d_start) < 0)
69 unixDie("Getting timestamp");
70
71 }
72
73 double udiff() const {
74 struct timespec now;
75 if(clock_gettime(CLOCK_MONOTONIC_RAW, &now) < 0)
76 unixDie("Getting timestamp");
77
78 return 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
79 }
80
81 double udiffAndSet() {
82 struct timespec now;
83 if(clock_gettime(CLOCK_MONOTONIC_RAW, &now) < 0)
84 unixDie("Getting timestamp");
85
86 auto ret= 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
87 d_start = now;
88 return ret;
89 }
90
91};
92
93class QPSLimiter
94{
95public:
96 QPSLimiter()
97 {
98 }
99
100 QPSLimiter(unsigned int rate, unsigned int burst) : d_rate(rate), d_burst(burst), d_tokens(burst)
101 {
102 d_passthrough=false;
103 d_prev.start();
104 }
105
106 unsigned int getRate() const
107 {
108 return d_passthrough? 0 : d_rate;
109 }
110
111 int getPassed() const
112 {
113 return d_passed;
114 }
115 int getBlocked() const
116 {
117 return d_blocked;
118 }
119
ecbe9133 120 bool check() const // this is not quite fair
df111b53 121 {
122 if(d_passthrough)
123 return true;
124 auto delta = d_prev.udiffAndSet();
125
126 d_tokens += 1.0*d_rate * (delta/1000000.0);
127
128 if(d_tokens > d_burst)
129 d_tokens = d_burst;
130
131 bool ret=false;
132 if(d_tokens >= 1.0) { // we need this because burst=1 is weird otherwise
133 ret=true;
134 --d_tokens;
135 d_passed++;
136 }
137 else
138 d_blocked++;
139
140 return ret;
141 }
142private:
143 bool d_passthrough{true};
144 unsigned int d_rate;
145 unsigned int d_burst;
ecbe9133 146 mutable double d_tokens;
147 mutable StopWatch d_prev;
148 mutable unsigned int d_passed{0};
149 mutable unsigned int d_blocked{0};
df111b53 150};
151
152
153struct IDState
154{
7b3865cd 155 IDState() : origFD(-1), delayMsec(0) { origDest.sin4.sin_family = 0;}
df111b53 156 IDState(const IDState& orig)
157 {
158 origFD = orig.origFD;
159 origID = orig.origID;
160 origRemote = orig.origRemote;
549d63c9 161 origDest = orig.origDest;
7b3865cd 162 delayMsec = orig.delayMsec;
df111b53 163 age.store(orig.age.load());
164 }
165
2bf26975 166 int origFD; // set to <0 to indicate this state is empty // 4
167
168 ComboAddress origRemote; // 28
549d63c9 169 ComboAddress origDest; // 28
2bf26975 170 StopWatch sentTime; // 16
171 DNSName qname; // 80
172 std::atomic<uint16_t> age; // 4
173 uint16_t qtype; // 2
174 uint16_t origID; // 2
aeb36780 175 uint16_t origFlags; // 2
7b3865cd 176 int delayMsec;
df111b53 177};
178
179struct Rings {
180 Rings()
181 {
df111b53 182 queryRing.set_capacity(10000);
183 respRing.set_capacity(10000);
184 }
0ba5eecf 185 struct Query
186 {
187 struct timespec when;
188 ComboAddress requestor;
189 DNSName name;
190 uint16_t qtype;
191 };
192 boost::circular_buffer<Query> queryRing;
df111b53 193 struct Response
194 {
80a216c9 195 struct timespec when;
196 ComboAddress requestor;
df111b53 197 DNSName name;
198 uint16_t qtype;
199 uint8_t rcode;
200 unsigned int usec;
80a216c9 201 unsigned int size;
df111b53 202 };
203 boost::circular_buffer<Response> respRing;
204 std::mutex respMutex;
205};
206
ecbe9133 207extern Rings g_rings; // XXX locking for this is still substandard, queryRing and clientRing need RW lock
df111b53 208
8a5d5053 209struct ClientState
210{
211 ComboAddress local;
a36ce055
RG
212 int udpFD{-1};
213 int tcpFD{-1};
8a5d5053 214};
215
216class TCPClientCollection {
217 std::vector<int> d_tcpclientthreads;
218 std::atomic<uint64_t> d_pos;
219public:
220 std::atomic<uint64_t> d_queued, d_numthreads;
221
222 TCPClientCollection()
223 {
224 d_tcpclientthreads.reserve(1024);
225 }
226
227 int getThread()
228 {
229 int pos = d_pos++;
230 ++d_queued;
231 return d_tcpclientthreads[pos % d_numthreads];
232 }
233 void addTCPClientThread();
234};
235
236extern TCPClientCollection g_tcpclientthreads;
237
df111b53 238struct DownstreamState
239{
240 DownstreamState(const ComboAddress& remote_);
241
242 int fd;
243 std::thread tid;
244 ComboAddress remote;
245 QPSLimiter qps;
246 vector<IDState> idStates;
ad485896
RG
247 DNSName checkName;
248 QType checkType;
df111b53 249 std::atomic<uint64_t> idOffset{0};
250 std::atomic<uint64_t> sendErrors{0};
251 std::atomic<uint64_t> outstanding{0};
252 std::atomic<uint64_t> reuseds{0};
253 std::atomic<uint64_t> queries{0};
254 struct {
255 std::atomic<uint64_t> sendErrors{0};
256 std::atomic<uint64_t> reuseds{0};
257 std::atomic<uint64_t> queries{0};
258 } prev;
18eeccc9 259 string name;
df111b53 260 double queryLoad{0.0};
261 double dropRate{0.0};
262 double latencyUsec{0.0};
263 int order{1};
264 int weight{1};
3f6d07a4
RG
265 int tcpRecvTimeout{30};
266 int tcpSendTimeout{30};
267 uint16_t retries{5};
df111b53 268 StopWatch sw;
269 set<string> pools;
270 enum class Availability { Up, Down, Auto} availability{Availability::Auto};
a6e02424 271 bool mustResolve;
df111b53 272 bool upStatus{false};
273 bool isUp() const
274 {
275 if(availability == Availability::Down)
276 return false;
277 if(availability == Availability::Up)
278 return true;
279 return upStatus;
280 }
281 void setUp() { availability = Availability::Up; }
282 void setDown() { availability = Availability::Down; }
283 void setAuto() { availability = Availability::Auto; }
18eeccc9
RG
284 string getName() const {
285 if (name.empty()) {
286 return remote.toStringWithPort();
287 }
288 return name;
289 }
df111b53 290};
291using servers_t =vector<std::shared_ptr<DownstreamState>>;
df111b53 292
da4e7813 293template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
294
295void* responderThread(std::shared_ptr<DownstreamState> state);
296extern std::mutex g_luamutex;
297extern LuaContext g_lua;
298extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
299
0940e4eb 300class DNSRule
301{
302public:
520eb5a0 303 virtual bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const =0;
0940e4eb 304 virtual string toString() const = 0;
305 mutable std::atomic<uint64_t> d_matches{0};
306};
307
308/* so what could you do:
309 drop,
310 fake up nxdomain,
311 provide actual answer,
312 allow & and stop processing,
313 continue processing,
314 modify header: (servfail|refused|notimp), set TC=1,
315 send to pool */
316
317class DNSAction
318{
319public:
7b3865cd 320 enum class Action { Drop, Nxdomain, Spoof, Allow, HeaderModify, Pool, Delay, None};
520eb5a0 321 virtual Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const =0;
0940e4eb 322 virtual string toString() const = 0;
323};
324
da4e7813 325using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
326typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)> policy_t;
df111b53 327
328struct ServerPolicy
329{
330 string name;
331 policy_t policy;
332};
333
42fae326 334struct CarbonConfig
335{
336 ComboAddress server{"0.0.0.0", 0};
337 std::string ourname;
338 unsigned int interval{30};
339};
340
341extern GlobalStateHolder<CarbonConfig> g_carbon;
ecbe9133 342extern GlobalStateHolder<ServerPolicy> g_policy;
343extern GlobalStateHolder<servers_t> g_dstates;
0940e4eb 344extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions;
638184e9 345extern GlobalStateHolder<NetmaskGroup> g_ACL;
2e72cc0e 346
ecbe9133 347extern ComboAddress g_serverControl; // not changed during runtime
348
652a7355 349extern std::vector<std::pair<ComboAddress, bool>> g_locals; // not changed at runtime (we hope XXX)
ecbe9133 350extern std::string g_key; // in theory needs locking
6ad8b29a 351extern bool g_truncateTC;
3f6d07a4
RG
352extern int g_tcpRecvTimeout;
353extern int g_tcpSendTimeout;
ecbe9133 354struct dnsheader;
355
356void controlThread(int fd, ComboAddress local);
839f3021 357vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
da4e7813 358NumberedServerVector getDownstreamCandidates(const servers_t& servers, const std::string& pool);
359
360std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
ecbe9133 361
da4e7813 362std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
363std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
a7f3108c 364std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
da4e7813 365std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
520eb5a0 366int getEDNSZ(const char* packet, unsigned int len);
50bed881 367void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password);
8a5d5053 368bool getMsgLen(int fd, uint16_t* len);
369bool putMsgLen(int fd, uint16_t len);
d8d85a30 370void* tcpAcceptorThread(void* p);
80a216c9 371
372void moreLua();