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