]>
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); |
e48090d1 | 15 | struct 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 | 58 | extern struct DNSDistStats g_stats; |
59 | ||
638184e9 | 60 | |
df111b53 | 61 | struct 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 | ||
93 | class QPSLimiter | |
94 | { | |
95 | public: | |
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 | } | |
142 | private: | |
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 | ||
153 | struct 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 | ||
179 | struct 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 | 207 | extern Rings g_rings; // XXX locking for this is still substandard, queryRing and clientRing need RW lock |
df111b53 | 208 | |
8a5d5053 | 209 | struct ClientState |
210 | { | |
211 | ComboAddress local; | |
a36ce055 RG |
212 | int udpFD{-1}; |
213 | int tcpFD{-1}; | |
8a5d5053 | 214 | }; |
215 | ||
216 | class TCPClientCollection { | |
217 | std::vector<int> d_tcpclientthreads; | |
218 | std::atomic<uint64_t> d_pos; | |
219 | public: | |
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 | ||
236 | extern TCPClientCollection g_tcpclientthreads; | |
237 | ||
df111b53 | 238 | struct 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 | }; |
291 | using servers_t =vector<std::shared_ptr<DownstreamState>>; | |
df111b53 | 292 | |
da4e7813 | 293 | template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >; |
294 | ||
295 | void* responderThread(std::shared_ptr<DownstreamState> state); | |
296 | extern std::mutex g_luamutex; | |
297 | extern LuaContext g_lua; | |
298 | extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex | |
299 | ||
0940e4eb | 300 | class DNSRule |
301 | { | |
302 | public: | |
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 | ||
317 | class DNSAction | |
318 | { | |
319 | public: | |
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 | 325 | using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>; |
326 | typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)> policy_t; | |
df111b53 | 327 | |
328 | struct ServerPolicy | |
329 | { | |
330 | string name; | |
331 | policy_t policy; | |
332 | }; | |
333 | ||
42fae326 | 334 | struct CarbonConfig |
335 | { | |
336 | ComboAddress server{"0.0.0.0", 0}; | |
337 | std::string ourname; | |
338 | unsigned int interval{30}; | |
339 | }; | |
340 | ||
341 | extern GlobalStateHolder<CarbonConfig> g_carbon; | |
ecbe9133 | 342 | extern GlobalStateHolder<ServerPolicy> g_policy; |
343 | extern GlobalStateHolder<servers_t> g_dstates; | |
0940e4eb | 344 | extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions; |
638184e9 | 345 | extern GlobalStateHolder<NetmaskGroup> g_ACL; |
2e72cc0e | 346 | |
ecbe9133 | 347 | extern ComboAddress g_serverControl; // not changed during runtime |
348 | ||
652a7355 | 349 | extern std::vector<std::pair<ComboAddress, bool>> g_locals; // not changed at runtime (we hope XXX) |
ecbe9133 | 350 | extern std::string g_key; // in theory needs locking |
6ad8b29a | 351 | extern bool g_truncateTC; |
3f6d07a4 RG |
352 | extern int g_tcpRecvTimeout; |
353 | extern int g_tcpSendTimeout; | |
ecbe9133 | 354 | struct dnsheader; |
355 | ||
356 | void controlThread(int fd, ComboAddress local); | |
839f3021 | 357 | vector<std::function<void(void)>> setupLua(bool client, const std::string& config); |
da4e7813 | 358 | NumberedServerVector getDownstreamCandidates(const servers_t& servers, const std::string& pool); |
359 | ||
360 | std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh); | |
ecbe9133 | 361 | |
da4e7813 | 362 | std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh); |
363 | std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh); | |
a7f3108c | 364 | std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh); |
da4e7813 | 365 | std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh); |
520eb5a0 | 366 | int getEDNSZ(const char* packet, unsigned int len); |
50bed881 | 367 | void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password); |
8a5d5053 | 368 | bool getMsgLen(int fd, uint16_t* len); |
369 | bool putMsgLen(int fd, uint16_t len); | |
d8d85a30 | 370 | void* tcpAcceptorThread(void* p); |
80a216c9 | 371 | |
372 | void moreLua(); |