]>
Commit | Line | Data |
---|---|---|
12471842 PL |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
9ef9b494 PD |
22 | #include <sys/types.h> |
23 | #include <sys/socket.h> | |
65613131 | 24 | #include <net/if.h> |
df111b53 | 25 | #include "dnsdist.hh" |
0940e4eb | 26 | #include "dnsrulactions.hh" |
df111b53 | 27 | #include <thread> |
28 | #include "dolog.hh" | |
29 | #include "sodcrypto.hh" | |
30 | #include "base64.hh" | |
31 | #include <fstream> | |
b7860997 | 32 | #include "dnswriter.hh" |
0e41337b | 33 | #include "lock.hh" |
cf48b0ce | 34 | #include "dnsdist-lua.hh" |
df111b53 | 35 | |
6ab65223 PL |
36 | #ifdef HAVE_SYSTEMD |
37 | #include <systemd/sd-daemon.h> | |
38 | #endif | |
39 | ||
df111b53 | 40 | using std::thread; |
41 | ||
2e72cc0e | 42 | static vector<std::function<void(void)>>* g_launchWork; |
43 | ||
d8d85a30 | 44 | class LuaAction : public DNSAction |
45 | { | |
46 | public: | |
497a6e3a | 47 | typedef std::function<std::tuple<int, string>(DNSQuestion* dq)> func_t; |
d8d85a30 | 48 | LuaAction(LuaAction::func_t func) : d_func(func) |
49 | {} | |
50 | ||
497a6e3a | 51 | Action operator()(DNSQuestion* dq, string* ruleresult) const override |
d8d85a30 | 52 | { |
01d9286f | 53 | std::lock_guard<std::mutex> lock(g_luamutex); |
497a6e3a | 54 | auto ret = d_func(dq); |
d8d85a30 | 55 | if(ruleresult) |
56 | *ruleresult=std::get<1>(ret); | |
57 | return (Action)std::get<0>(ret); | |
58 | } | |
59 | ||
497a6e3a | 60 | string toString() const override |
d8d85a30 | 61 | { |
62 | return "Lua script"; | |
63 | } | |
64 | ||
65 | private: | |
66 | func_t d_func; | |
67 | }; | |
68 | ||
153d5065 RG |
69 | class LuaResponseAction : public DNSResponseAction |
70 | { | |
71 | public: | |
72 | typedef std::function<std::tuple<int, string>(DNSResponse* dr)> func_t; | |
73 | LuaResponseAction(LuaResponseAction::func_t func) : d_func(func) | |
74 | {} | |
75 | ||
76 | Action operator()(DNSResponse* dr, string* ruleresult) const override | |
77 | { | |
78 | std::lock_guard<std::mutex> lock(g_luamutex); | |
79 | auto ret = d_func(dr); | |
80 | if(ruleresult) | |
81 | *ruleresult=std::get<1>(ret); | |
82 | return (Action)std::get<0>(ret); | |
83 | } | |
84 | ||
85 | string toString() const override | |
86 | { | |
87 | return "Lua response script"; | |
88 | } | |
89 | ||
90 | private: | |
91 | func_t d_func; | |
92 | }; | |
93 | ||
6bba426c | 94 | std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var) |
d8d85a30 | 95 | { |
f850b032 PL |
96 | if (var.type() == typeid(std::shared_ptr<DNSRule>)) |
97 | return *boost::get<std::shared_ptr<DNSRule>>(&var); | |
98 | ||
d8d85a30 | 99 | SuffixMatchNode smn; |
100 | NetmaskGroup nmg; | |
d8d85a30 | 101 | auto add=[&](string src) { |
102 | try { | |
5ad8b87a | 103 | nmg.addMask(src); // need to try mask first, all masks are domain names! |
d8d85a30 | 104 | } catch(...) { |
5ad8b87a | 105 | smn.add(DNSName(src)); |
d8d85a30 | 106 | } |
107 | }; | |
f850b032 PL |
108 | |
109 | if (var.type() == typeid(string)) | |
110 | add(*boost::get<string>(&var)); | |
111 | ||
112 | else if (var.type() == typeid(vector<pair<int, string>>)) | |
113 | for(const auto& a : *boost::get<vector<pair<int, string>>>(&var)) | |
d8d85a30 | 114 | add(a.second); |
f850b032 PL |
115 | |
116 | else if (var.type() == typeid(DNSName)) | |
117 | smn.add(*boost::get<DNSName>(&var)); | |
118 | ||
119 | else if (var.type() == typeid(vector<pair<int, DNSName>>)) | |
120 | for(const auto& a : *boost::get<vector<pair<int, DNSName>>>(&var)) | |
121 | smn.add(a.second); | |
122 | ||
d8d85a30 | 123 | if(nmg.empty()) |
124 | return std::make_shared<SuffixMatchNodeRule>(smn); | |
125 | else | |
8a616250 | 126 | return std::make_shared<NetmaskGroupRule>(nmg, true); |
d8d85a30 | 127 | } |
128 | ||
2d11d1b2 | 129 | std::unordered_map<int, vector<boost::variant<string,double>>> getGenResponses(unsigned int top, boost::optional<int> labels, std::function<bool(const Rings::Response&)> pred) |
130 | { | |
131 | setLuaNoSideEffect(); | |
132 | map<DNSName, int> counts; | |
133 | unsigned int total=0; | |
134 | { | |
135 | std::lock_guard<std::mutex> lock(g_rings.respMutex); | |
136 | if(!labels) { | |
137 | for(const auto& a : g_rings.respRing) { | |
138 | if(!pred(a)) | |
139 | continue; | |
140 | counts[a.name]++; | |
141 | total++; | |
142 | } | |
143 | } | |
144 | else { | |
145 | unsigned int lab = *labels; | |
146 | for(auto a : g_rings.respRing) { | |
147 | if(!pred(a)) | |
148 | continue; | |
149 | ||
150 | a.name.trimToLabels(lab); | |
151 | counts[a.name]++; | |
152 | total++; | |
153 | } | |
154 | ||
155 | } | |
156 | } | |
157 | // cout<<"Looked at "<<total<<" responses, "<<counts.size()<<" different ones"<<endl; | |
158 | vector<pair<int, DNSName>> rcounts; | |
159 | rcounts.reserve(counts.size()); | |
160 | for(const auto& c : counts) | |
2f95ab40 | 161 | rcounts.push_back(make_pair(c.second, c.first.makeLowerCase())); |
2d11d1b2 | 162 | |
163 | sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a, | |
164 | const decltype(rcounts)::value_type& b) { | |
165 | return b.first < a.first; | |
166 | }); | |
167 | ||
168 | std::unordered_map<int, vector<boost::variant<string,double>>> ret; | |
169 | unsigned int count=1, rest=0; | |
170 | for(const auto& rc : rcounts) { | |
171 | if(count==top+1) | |
172 | rest+=rc.first; | |
173 | else | |
174 | ret.insert({count++, {rc.second.toString(), rc.first, 100.0*rc.first/total}}); | |
175 | } | |
6a62c0e3 | 176 | ret.insert({count, {"Rest", rest, total > 0 ? 100.0*rest/total : 100.0}}); |
2d11d1b2 | 177 | return ret; |
178 | } | |
179 | ||
efd35aa8 RG |
180 | void parseLocalBindVars(boost::optional<localbind_t> vars, bool& doTCP, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface) |
181 | { | |
182 | if (vars) { | |
183 | if (vars->count("doTCP")) { | |
184 | doTCP = boost::get<bool>((*vars)["doTCP"]); | |
185 | } | |
186 | if (vars->count("reusePort")) { | |
187 | reusePort = boost::get<bool>((*vars)["reusePort"]); | |
188 | } | |
189 | if (vars->count("tcpFastOpenQueueSize")) { | |
190 | tcpFastOpenQueueSize = boost::get<int>((*vars)["tcpFastOpenQueueSize"]); | |
191 | } | |
192 | if (vars->count("interface")) { | |
193 | interface = boost::get<std::string>((*vars)["interface"]); | |
194 | } | |
195 | } | |
196 | } | |
197 | ||
839f3021 | 198 | vector<std::function<void(void)>> setupLua(bool client, const std::string& config) |
df111b53 | 199 | { |
2e72cc0e | 200 | g_launchWork= new vector<std::function<void(void)>>(); |
a6e02424 | 201 | typedef std::unordered_map<std::string, boost::variant<bool, std::string, vector<pair<int, std::string> > > > newserver_t; |
e48090d1 | 202 | |
d8d85a30 | 203 | g_lua.writeVariable("DNSAction", std::unordered_map<string,int>{ |
dd46e5e3 RG |
204 | {"Drop", (int)DNSAction::Action::Drop}, |
205 | {"Nxdomain", (int)DNSAction::Action::Nxdomain}, | |
206 | {"Refused", (int)DNSAction::Action::Refused}, | |
207 | {"Spoof", (int)DNSAction::Action::Spoof}, | |
208 | {"Allow", (int)DNSAction::Action::Allow}, | |
d8d85a30 | 209 | {"HeaderModify", (int)DNSAction::Action::HeaderModify}, |
dd46e5e3 | 210 | {"Pool", (int)DNSAction::Action::Pool}, |
21c2cdd8 | 211 | {"None",(int)DNSAction::Action::None}, |
c4f5aeff RG |
212 | {"Delay", (int)DNSAction::Action::Delay}, |
213 | {"Truncate", (int)DNSAction::Action::Truncate} | |
214 | }); | |
bac6e8fb | 215 | |
55baa1f2 | 216 | g_lua.writeVariable("DNSResponseAction", std::unordered_map<string,int>{ |
788c3243 RG |
217 | {"Allow", (int)DNSResponseAction::Action::Allow }, |
218 | {"Delay", (int)DNSResponseAction::Action::Delay }, | |
219 | {"HeaderModify", (int)DNSResponseAction::Action::HeaderModify }, | |
220 | {"None", (int)DNSResponseAction::Action::None } | |
221 | }); | |
8146444b | 222 | |
55baa1f2 RG |
223 | g_lua.writeVariable("DNSClass", std::unordered_map<string,int>{ |
224 | {"IN", QClass::IN }, | |
225 | {"CHAOS", QClass::CHAOS }, | |
226 | {"NONE", QClass::NONE }, | |
227 | {"ANY", QClass::ANY } | |
228 | }); | |
229 | ||
230 | g_lua.writeVariable("DNSOpcode", std::unordered_map<string,int>{ | |
231 | {"Query", Opcode::Query }, | |
232 | {"IQuery", Opcode::IQuery }, | |
233 | {"Status", Opcode::Status }, | |
234 | {"Notify", Opcode::Notify }, | |
235 | {"Update", Opcode::Update } | |
236 | }); | |
237 | ||
238 | g_lua.writeVariable("DNSSection", std::unordered_map<string,int>{ | |
239 | {"Question", 0 }, | |
240 | {"Answer", 1 }, | |
241 | {"Authority", 2 }, | |
242 | {"Additional",3 } | |
243 | }); | |
244 | ||
245 | vector<pair<string, int> > rcodes = {{"NOERROR", RCode::NoError }, | |
246 | {"FORMERR", RCode::FormErr }, | |
247 | {"SERVFAIL", RCode::ServFail }, | |
248 | {"NXDOMAIN", RCode::NXDomain }, | |
249 | {"NOTIMP", RCode::NotImp }, | |
250 | {"REFUSED", RCode::Refused }, | |
251 | {"YXDOMAIN", RCode::YXDomain }, | |
252 | {"YXRRSET", RCode::YXRRSet }, | |
253 | {"NXRRSET", RCode::NXRRSet }, | |
254 | {"NOTAUTH", RCode::NotAuth }, | |
255 | {"NOTZONE", RCode::NotZone } | |
256 | }; | |
bac6e8fb | 257 | vector<pair<string, int> > dd; |
258 | for(const auto& n : QType::names) | |
259 | dd.push_back({n.first, n.second}); | |
55baa1f2 RG |
260 | for(const auto& n : rcodes) |
261 | dd.push_back({n.first, n.second}); | |
bac6e8fb | 262 | g_lua.writeVariable("dnsdist", dd); |
d8d85a30 | 263 | |
df111b53 | 264 | g_lua.writeFunction("newServer", |
839f3021 | 265 | [client](boost::variant<string,newserver_t> pvars, boost::optional<int> qps) |
df111b53 | 266 | { |
f758857a | 267 | setLuaSideEffect(); |
2e72cc0e | 268 | if(client) { |
b4fd86c3 | 269 | return std::make_shared<DownstreamState>(ComboAddress()); |
2e72cc0e | 270 | } |
fbe2a2e0 RG |
271 | ComboAddress sourceAddr; |
272 | unsigned int sourceItf = 0; | |
557d7631 | 273 | if(auto addressStr = boost::get<string>(&pvars)) { |
cbbd1533 | 274 | std::shared_ptr<DownstreamState> ret; |
275 | try { | |
bd01350a RG |
276 | ComboAddress address(*addressStr, 53); |
277 | if(IsAnyAddress(address)) { | |
278 | g_outputBuffer="Error creating new server: invalid address for a downstream server."; | |
279 | errlog("Error creating new server: %s is not a valid address for a downstream server", *addressStr); | |
280 | return ret; | |
281 | } | |
557d7631 | 282 | ret=std::make_shared<DownstreamState>(address); |
cbbd1533 | 283 | } |
bd01350a RG |
284 | catch(const PDNSException& e) { |
285 | g_outputBuffer="Error creating new server: "+string(e.reason); | |
286 | errlog("Error creating new server with address %s: %s", addressStr, e.reason); | |
287 | return ret; | |
288 | } | |
cbbd1533 | 289 | catch(std::exception& e) { |
290 | g_outputBuffer="Error creating new server: "+string(e.what()); | |
557d7631 | 291 | errlog("Error creating new server with address %s: %s", addressStr, e.what()); |
cbbd1533 | 292 | return ret; |
293 | } | |
2e72cc0e | 294 | |
df111b53 | 295 | if(qps) { |
296 | ret->qps=QPSLimiter(*qps, *qps); | |
297 | } | |
ecbe9133 | 298 | g_dstates.modify([ret](servers_t& servers) { |
299 | servers.push_back(ret); | |
300 | std::stable_sort(servers.begin(), servers.end(), [](const decltype(ret)& a, const decltype(ret)& b) { | |
301 | return a->order < b->order; | |
302 | }); | |
303 | ||
304 | }); | |
2e72cc0e | 305 | |
46a839bf RG |
306 | auto localPools = g_pools.getCopy(); |
307 | addServerToPool(localPools, "", ret); | |
308 | g_pools.setState(localPools); | |
309 | ||
7565f4e6 RG |
310 | if (ret->connected) { |
311 | if(g_launchWork) { | |
312 | g_launchWork->push_back([ret]() { | |
2717a92f | 313 | ret->tid = thread(responderThread, ret); |
2e72cc0e | 314 | }); |
7565f4e6 RG |
315 | } |
316 | else { | |
2717a92f | 317 | ret->tid = thread(responderThread, ret); |
7565f4e6 | 318 | } |
2e72cc0e | 319 | } |
320 | ||
df111b53 | 321 | return ret; |
322 | } | |
839f3021 | 323 | auto vars=boost::get<newserver_t>(pvars); |
fbe2a2e0 RG |
324 | |
325 | if(vars.count("source")) { | |
326 | /* handle source in the following forms: | |
327 | - v4 address ("192.0.2.1") | |
328 | - v6 address ("2001:DB8::1") | |
329 | - interface name ("eth0") | |
330 | - v4 address and interface name ("192.0.2.1@eth0") | |
331 | - v6 address and interface name ("2001:DB8::1@eth0") | |
332 | */ | |
333 | const string source = boost::get<string>(vars["source"]); | |
334 | bool parsed = false; | |
335 | std::string::size_type pos = source.find("@"); | |
336 | if (pos == std::string::npos) { | |
337 | /* no '@', try to parse that as a valid v4/v6 address */ | |
338 | try { | |
339 | sourceAddr = ComboAddress(source); | |
340 | parsed = true; | |
341 | } | |
342 | catch(...) | |
343 | { | |
344 | } | |
345 | } | |
346 | ||
347 | if (parsed == false) | |
348 | { | |
349 | /* try to parse as interface name, or v4/v6@itf */ | |
350 | string itfName = source.substr(pos == std::string::npos ? 0 : pos + 1); | |
351 | unsigned int itfIdx = if_nametoindex(itfName.c_str()); | |
352 | ||
353 | if (itfIdx != 0) { | |
354 | if (pos == 0 || pos == std::string::npos) { | |
355 | /* "eth0" or "@eth0" */ | |
356 | sourceItf = itfIdx; | |
357 | } | |
358 | else { | |
359 | /* "192.0.2.1@eth0" */ | |
360 | sourceAddr = ComboAddress(source.substr(0, pos)); | |
361 | sourceItf = itfIdx; | |
362 | } | |
363 | } | |
364 | else | |
365 | { | |
366 | warnlog("Dismissing source %s because '%s' is not a valid interface name", source, itfName); | |
367 | } | |
368 | } | |
369 | } | |
370 | ||
cbbd1533 | 371 | std::shared_ptr<DownstreamState> ret; |
372 | try { | |
bd01350a RG |
373 | ComboAddress address(boost::get<string>(vars["address"]), 53); |
374 | if(IsAnyAddress(address)) { | |
375 | g_outputBuffer="Error creating new server: invalid address for a downstream server."; | |
376 | errlog("Error creating new server: %s is not a valid address for a downstream server", boost::get<string>(vars["address"])); | |
377 | return ret; | |
378 | } | |
557d7631 | 379 | ret=std::make_shared<DownstreamState>(address, sourceAddr, sourceItf); |
cbbd1533 | 380 | } |
bd01350a RG |
381 | catch(const PDNSException& e) { |
382 | g_outputBuffer="Error creating new server: "+string(e.reason); | |
383 | errlog("Error creating new server with address %s: %s", boost::get<string>(vars["address"]), e.reason); | |
384 | return ret; | |
385 | } | |
cbbd1533 | 386 | catch(std::exception& e) { |
387 | g_outputBuffer="Error creating new server: "+string(e.what()); | |
388 | errlog("Error creating new server with address %s: %s", boost::get<string>(vars["address"]), e.what()); | |
389 | return ret; | |
390 | } | |
fbe2a2e0 | 391 | |
df111b53 | 392 | if(vars.count("qps")) { |
af619119 RG |
393 | int qpsVal=std::stoi(boost::get<string>(vars["qps"])); |
394 | ret->qps=QPSLimiter(qpsVal, qpsVal); | |
df111b53 | 395 | } |
396 | ||
886e2cf2 | 397 | auto localPools = g_pools.getCopy(); |
df111b53 | 398 | if(vars.count("pool")) { |
839f3021 | 399 | if(auto* pool = boost::get<string>(&vars["pool"])) |
400 | ret->pools.insert(*pool); | |
401 | else { | |
402 | auto* pools = boost::get<vector<pair<int, string> > >(&vars["pool"]); | |
403 | for(auto& p : *pools) | |
404 | ret->pools.insert(p.second); | |
405 | } | |
886e2cf2 RG |
406 | for(const auto& poolName: ret->pools) { |
407 | addServerToPool(localPools, poolName, ret); | |
408 | } | |
409 | } | |
410 | else { | |
411 | addServerToPool(localPools, "", ret); | |
df111b53 | 412 | } |
886e2cf2 | 413 | g_pools.setState(localPools); |
df111b53 | 414 | |
415 | if(vars.count("order")) { | |
335da0ba | 416 | ret->order=std::stoi(boost::get<string>(vars["order"])); |
df111b53 | 417 | } |
418 | ||
419 | if(vars.count("weight")) { | |
335da0ba | 420 | ret->weight=std::stoi(boost::get<string>(vars["weight"])); |
df111b53 | 421 | } |
422 | ||
3f6d07a4 | 423 | if(vars.count("retries")) { |
335da0ba | 424 | ret->retries=std::stoi(boost::get<string>(vars["retries"])); |
3f6d07a4 RG |
425 | } |
426 | ||
b40cffe7 RG |
427 | if(vars.count("tcpConnectTimeout")) { |
428 | ret->tcpConnectTimeout=std::stoi(boost::get<string>(vars["tcpConnectTimeout"])); | |
429 | } | |
430 | ||
3f6d07a4 | 431 | if(vars.count("tcpSendTimeout")) { |
335da0ba | 432 | ret->tcpSendTimeout=std::stoi(boost::get<string>(vars["tcpSendTimeout"])); |
3f6d07a4 RG |
433 | } |
434 | ||
435 | if(vars.count("tcpRecvTimeout")) { | |
335da0ba | 436 | ret->tcpRecvTimeout=std::stoi(boost::get<string>(vars["tcpRecvTimeout"])); |
3f6d07a4 RG |
437 | } |
438 | ||
284d460c | 439 | if(vars.count("tcpFastOpen")) { |
d987f632 RG |
440 | bool fastOpen = boost::get<bool>(vars["tcpFastOpen"]); |
441 | if (fastOpen) { | |
442 | #ifdef MSG_FASTOPEN | |
443 | ret->tcpFastOpen=true; | |
444 | #else | |
445 | warnlog("TCP Fast Open has been configured on downstream server %s but is not supported", boost::get<string>(vars["address"])); | |
446 | #endif | |
447 | } | |
284d460c RG |
448 | } |
449 | ||
18eeccc9 RG |
450 | if(vars.count("name")) { |
451 | ret->name=boost::get<string>(vars["name"]); | |
452 | } | |
453 | ||
ad485896 RG |
454 | if(vars.count("checkName")) { |
455 | ret->checkName=DNSName(boost::get<string>(vars["checkName"])); | |
456 | } | |
457 | ||
458 | if(vars.count("checkType")) { | |
459 | ret->checkType=boost::get<string>(vars["checkType"]); | |
460 | } | |
461 | ||
21830638 RG |
462 | if(vars.count("setCD")) { |
463 | ret->setCD=boost::get<bool>(vars["setCD"]); | |
464 | } | |
465 | ||
a6e02424 RG |
466 | if(vars.count("mustResolve")) { |
467 | ret->mustResolve=boost::get<bool>(vars["mustResolve"]); | |
468 | } | |
469 | ||
ca404e94 RG |
470 | if(vars.count("useClientSubnet")) { |
471 | ret->useECS=boost::get<bool>(vars["useClientSubnet"]); | |
472 | } | |
473 | ||
9e87dcb8 RG |
474 | if(vars.count("maxCheckFailures")) { |
475 | ret->maxCheckFailures=std::stoi(boost::get<string>(vars["maxCheckFailures"])); | |
476 | } | |
477 | ||
7565f4e6 RG |
478 | if (ret->connected) { |
479 | if(g_launchWork) { | |
480 | g_launchWork->push_back([ret]() { | |
2717a92f | 481 | ret->tid = thread(responderThread, ret); |
2e72cc0e | 482 | }); |
7565f4e6 RG |
483 | } |
484 | else { | |
2717a92f | 485 | ret->tid = thread(responderThread, ret); |
7565f4e6 | 486 | } |
2e72cc0e | 487 | } |
df111b53 | 488 | |
ecbe9133 | 489 | auto states = g_dstates.getCopy(); |
e5a14b2b | 490 | states.push_back(ret); |
491 | std::stable_sort(states.begin(), states.end(), [](const decltype(ret)& a, const decltype(ret)& b) { | |
df111b53 | 492 | return a->order < b->order; |
493 | }); | |
ecbe9133 | 494 | g_dstates.setState(states); |
df111b53 | 495 | return ret; |
496 | } ); | |
497 | ||
ecc8a33b | 498 | g_lua.writeFunction("makeRule", makeRule); |
490a29bb | 499 | |
0940e4eb | 500 | g_lua.writeFunction("addAnyTCRule", []() { |
f758857a | 501 | setLuaSideEffect(); |
0940e4eb | 502 | auto rules=g_rulactions.getCopy(); |
490a29bb RG |
503 | std::vector<pair<int, shared_ptr<DNSRule> >> v; |
504 | v.push_back({1, std::make_shared<QTypeRule>(0xff)}); | |
505 | v.push_back({2, std::make_shared<TCPRule>(false)}); | |
506 | rules.push_back({ std::shared_ptr<DNSRule>(new AndRule(v)), std::make_shared<TCAction>()}); | |
0940e4eb | 507 | g_rulactions.setState(rules); |
508 | }); | |
df111b53 | 509 | |
0940e4eb | 510 | g_lua.writeFunction("rmRule", [](unsigned int num) { |
f758857a | 511 | setLuaSideEffect(); |
0940e4eb | 512 | auto rules = g_rulactions.getCopy(); |
513 | if(num >= rules.size()) { | |
514 | g_outputBuffer = "Error: attempt to delete non-existing rule\n"; | |
515 | return; | |
516 | } | |
517 | rules.erase(rules.begin()+num); | |
518 | g_rulactions.setState(rules); | |
519 | }); | |
520 | ||
b4fd86c3 | 521 | g_lua.writeFunction("topRule", []() { |
f758857a | 522 | setLuaSideEffect(); |
b4fd86c3 | 523 | auto rules = g_rulactions.getCopy(); |
524 | if(rules.empty()) | |
525 | return; | |
526 | auto subject = *rules.rbegin(); | |
527 | rules.erase(std::prev(rules.end())); | |
528 | rules.insert(rules.begin(), subject); | |
529 | g_rulactions.setState(rules); | |
530 | }); | |
0940e4eb | 531 | g_lua.writeFunction("mvRule", [](unsigned int from, unsigned int to) { |
f758857a | 532 | setLuaSideEffect(); |
0940e4eb | 533 | auto rules = g_rulactions.getCopy(); |
534 | if(from >= rules.size() || to > rules.size()) { | |
535 | g_outputBuffer = "Error: attempt to move rules from/to invalid index\n"; | |
536 | return; | |
537 | } | |
0940e4eb | 538 | |
539 | auto subject = rules[from]; | |
540 | rules.erase(rules.begin()+from); | |
541 | if(to == rules.size()) | |
542 | rules.push_back(subject); | |
543 | else { | |
544 | if(from < to) | |
545 | --to; | |
546 | rules.insert(rules.begin()+to, subject); | |
547 | } | |
548 | g_rulactions.setState(rules); | |
549 | }); | |
50ce537a RG |
550 | g_lua.writeFunction("clearRules", []() { |
551 | setLuaSideEffect(); | |
552 | g_rulactions.modify([](decltype(g_rulactions)::value_type& rulactions) { | |
553 | rulactions.clear(); | |
554 | }); | |
555 | }); | |
556 | ||
557 | g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action) { | |
558 | auto rule=makeRule(dnsrule); | |
559 | return std::make_shared<std::pair< luadnsrule_t, std::shared_ptr<DNSAction> > >(rule, action); | |
560 | }); | |
df111b53 | 561 | |
50ce537a RG |
562 | g_lua.writeFunction("setRules", [](std::vector< std::pair<int, std::shared_ptr<std::pair<luadnsrule_t, std::shared_ptr<DNSAction> > > > > newruleactions) { |
563 | setLuaSideEffect(); | |
564 | g_rulactions.modify([newruleactions](decltype(g_rulactions)::value_type& gruleactions) { | |
565 | gruleactions.clear(); | |
566 | for (const auto& newruleaction : newruleactions) { | |
567 | if (newruleaction.second) { | |
568 | auto rule=makeRule(newruleaction.second->first); | |
569 | gruleactions.push_back({rule, newruleaction.second->second}); | |
570 | } | |
571 | } | |
572 | }); | |
573 | }); | |
df111b53 | 574 | |
575 | g_lua.writeFunction("rmServer", | |
576 | [](boost::variant<std::shared_ptr<DownstreamState>, int> var) | |
577 | { | |
f758857a | 578 | setLuaSideEffect(); |
886e2cf2 RG |
579 | shared_ptr<DownstreamState> server; |
580 | auto* rem = boost::get<shared_ptr<DownstreamState>>(&var); | |
581 | auto states = g_dstates.getCopy(); | |
582 | if(rem) { | |
583 | server = *rem; | |
584 | } | |
585 | else { | |
586 | int idx = boost::get<int>(var); | |
0f06cd4c | 587 | server = states.at(idx); |
886e2cf2 RG |
588 | } |
589 | auto localPools = g_pools.getCopy(); | |
590 | for (const string& poolName : server->pools) { | |
591 | removeServerFromPool(localPools, poolName, server); | |
592 | } | |
0f06cd4c RG |
593 | /* the server might also be in the default pool */ |
594 | removeServerFromPool(localPools, "", server); | |
886e2cf2 RG |
595 | g_pools.setState(localPools); |
596 | states.erase(remove(states.begin(), states.end(), server), states.end()); | |
597 | g_dstates.setState(states); | |
df111b53 | 598 | } ); |
599 | ||
600 | ||
601 | g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) { | |
f758857a | 602 | setLuaSideEffect(); |
e5a14b2b | 603 | g_policy.setState(policy); |
df111b53 | 604 | }); |
70a57b05 | 605 | g_lua.writeFunction("setServerPolicyLua", [](string name, policyfunc_t policy) { |
f758857a | 606 | setLuaSideEffect(); |
e5a14b2b | 607 | g_policy.setState(ServerPolicy{name, policy}); |
df111b53 | 608 | }); |
609 | ||
610 | g_lua.writeFunction("showServerPolicy", []() { | |
f758857a | 611 | setLuaSideEffect(); |
ecbe9133 | 612 | g_outputBuffer=g_policy.getLocal()->name+"\n"; |
df111b53 | 613 | }); |
614 | ||
f758857a | 615 | g_lua.writeFunction("truncateTC", [](bool tc) { setLuaSideEffect(); g_truncateTC=tc; }); |
616 | g_lua.writeFunction("fixupCase", [](bool fu) { setLuaSideEffect(); g_fixupCase=fu; }); | |
df111b53 | 617 | |
618 | g_lua.registerMember("name", &ServerPolicy::name); | |
619 | g_lua.registerMember("policy", &ServerPolicy::policy); | |
70a57b05 | 620 | g_lua.writeFunction("newServerPolicy", [](string name, policyfunc_t policy) { return ServerPolicy{name, policy};}); |
df111b53 | 621 | g_lua.writeVariable("firstAvailable", ServerPolicy{"firstAvailable", firstAvailable}); |
622 | g_lua.writeVariable("roundrobin", ServerPolicy{"roundrobin", roundrobin}); | |
623 | g_lua.writeVariable("wrandom", ServerPolicy{"wrandom", wrandom}); | |
a7f3108c | 624 | g_lua.writeVariable("whashed", ServerPolicy{"whashed", whashed}); |
df111b53 | 625 | g_lua.writeVariable("leastOutstanding", ServerPolicy{"leastOutstanding", leastOutstanding}); |
626 | g_lua.writeFunction("addACL", [](const std::string& domain) { | |
f758857a | 627 | setLuaSideEffect(); |
e5a14b2b | 628 | g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); }); |
df111b53 | 629 | }); |
2e72cc0e | 630 | |
efd35aa8 | 631 | g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) { |
f758857a | 632 | setLuaSideEffect(); |
5949b95b | 633 | if(client) |
634 | return; | |
85e4ce52 RG |
635 | if (g_configurationDone) { |
636 | g_outputBuffer="setLocal cannot be used at runtime!\n"; | |
637 | return; | |
638 | } | |
efd35aa8 RG |
639 | bool doTCP = true; |
640 | bool reusePort = false; | |
641 | int tcpFastOpenQueueSize = 0; | |
642 | std::string interface; | |
643 | ||
644 | parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface); | |
645 | ||
5949b95b | 646 | try { |
647 | ComboAddress loc(addr, 53); | |
648 | g_locals.clear(); | |
efd35aa8 | 649 | g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface)); /// only works pre-startup, so no sync necessary |
5949b95b | 650 | } |
651 | catch(std::exception& e) { | |
652 | g_outputBuffer="Error: "+string(e.what())+"\n"; | |
653 | } | |
654 | }); | |
655 | ||
efd35aa8 | 656 | g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) { |
f758857a | 657 | setLuaSideEffect(); |
2e72cc0e | 658 | if(client) |
659 | return; | |
85e4ce52 RG |
660 | if (g_configurationDone) { |
661 | g_outputBuffer="addLocal cannot be used at runtime!\n"; | |
662 | return; | |
663 | } | |
efd35aa8 RG |
664 | bool doTCP = true; |
665 | bool reusePort = false; | |
666 | int tcpFastOpenQueueSize = 0; | |
667 | std::string interface; | |
668 | ||
669 | parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface); | |
670 | ||
2e72cc0e | 671 | try { |
672 | ComboAddress loc(addr, 53); | |
efd35aa8 | 673 | g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface)); /// only works pre-startup, so no sync necessary |
2e72cc0e | 674 | } |
675 | catch(std::exception& e) { | |
676 | g_outputBuffer="Error: "+string(e.what())+"\n"; | |
677 | } | |
678 | }); | |
e4944ea0 | 679 | g_lua.writeFunction("setACL", [](boost::variant<string,vector<pair<int, string>>> inp) { |
f758857a | 680 | setLuaSideEffect(); |
e5a14b2b | 681 | NetmaskGroup nmg; |
e4944ea0 | 682 | if(auto str = boost::get<string>(&inp)) { |
683 | nmg.addMask(*str); | |
684 | } | |
685 | else for(const auto& p : boost::get<vector<pair<int,string>>>(inp)) { | |
e5a14b2b | 686 | nmg.addMask(p.second); |
cffde2fd | 687 | } |
688 | g_ACL.setState(nmg); | |
df111b53 | 689 | }); |
690 | g_lua.writeFunction("showACL", []() { | |
f758857a | 691 | setLuaNoSideEffect(); |
df111b53 | 692 | vector<string> vec; |
cffde2fd | 693 | |
e5a14b2b | 694 | g_ACL.getCopy().toStringVector(&vec); |
cffde2fd | 695 | |
df111b53 | 696 | for(const auto& s : vec) |
cffde2fd | 697 | g_outputBuffer+=s+"\n"; |
698 | ||
df111b53 | 699 | }); |
6ab65223 PL |
700 | g_lua.writeFunction("shutdown", []() { |
701 | #ifdef HAVE_SYSTEMD | |
702 | sd_notify(0, "STOPPING=1"); | |
703 | #endif | |
704 | _exit(0); | |
705 | } ); | |
df111b53 | 706 | |
707 | ||
ecbe9133 | 708 | g_lua.writeFunction("addDomainBlock", [](const std::string& domain) { |
f758857a | 709 | setLuaSideEffect(); |
0940e4eb | 710 | SuffixMatchNode smn; |
1f9100a7 | 711 | smn.add(DNSName(domain)); |
0940e4eb | 712 | g_rulactions.modify([smn](decltype(g_rulactions)::value_type& rulactions) { |
713 | rulactions.push_back({ | |
714 | std::make_shared<SuffixMatchNodeRule>(smn), | |
715 | std::make_shared<DropAction>() }); | |
716 | }); | |
717 | ||
ecbe9133 | 718 | }); |
df111b53 | 719 | g_lua.writeFunction("showServers", []() { |
f758857a | 720 | setLuaNoSideEffect(); |
df111b53 | 721 | try { |
722 | ostringstream ret; | |
1287674c RG |
723 | boost::format fmt("%1$-3d %2$-20.20s %|25t|%3% %|55t|%4$5s %|51t|%5$7.1f %|66t|%6$7d %|69t|%7$3d %|78t|%8$2d %|80t|%9$10d %|86t|%10$7d %|91t|%11$5.1f %|109t|%12$5.1f %|115t|%13$11d %14%" ); |
724 | // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
725 | ret << (fmt % "#" % "Name" % "Address" % "State" % "Qps" % "Qlim" % "Ord" % "Wt" % "Queries" % "Drops" % "Drate" % "Lat" % "Outstanding" % "Pools") << endl; | |
df111b53 | 726 | |
727 | uint64_t totQPS{0}, totQueries{0}, totDrops{0}; | |
728 | int counter=0; | |
ecbe9133 | 729 | auto states = g_dstates.getCopy(); |
e5a14b2b | 730 | for(const auto& s : states) { |
9f4eb5cc | 731 | string status = s->getStatus(); |
df111b53 | 732 | string pools; |
733 | for(auto& p : s->pools) { | |
734 | if(!pools.empty()) | |
735 | pools+=" "; | |
736 | pools+=p; | |
737 | } | |
738 | ||
18eeccc9 | 739 | ret << (fmt % counter % s->name % s->remote.toStringWithPort() % |
df111b53 | 740 | status % |
1287674c | 741 | s->queryLoad % s->qps.getRate() % s->order % s->weight % s->queries.load() % s->reuseds.load() % (s->dropRate) % (s->latencyUsec/1000.0) % s->outstanding.load() % pools) << endl; |
df111b53 | 742 | |
743 | totQPS += s->queryLoad; | |
744 | totQueries += s->queries.load(); | |
745 | totDrops += s->reuseds.load(); | |
746 | ++counter; | |
747 | } | |
18eeccc9 | 748 | ret<< (fmt % "All" % "" % "" % "" |
df111b53 | 749 | % |
1287674c | 750 | (double)totQPS % "" % "" % "" % totQueries % totDrops % "" % "" % "" % "" ) << endl; |
df111b53 | 751 | |
752 | g_outputBuffer=ret.str(); | |
753 | }catch(std::exception& e) { g_outputBuffer=e.what(); throw; } | |
754 | }); | |
755 | ||
6bba426c | 756 | g_lua.writeFunction("addLuaAction", [](luadnsrule_t var, LuaAction::func_t func) |
d8d85a30 | 757 | { |
f758857a | 758 | setLuaSideEffect(); |
d8d85a30 | 759 | auto rule=makeRule(var); |
760 | g_rulactions.modify([rule,func](decltype(g_rulactions)::value_type& rulactions){ | |
761 | rulactions.push_back({rule, | |
762 | std::make_shared<LuaAction>(func)}); | |
763 | }); | |
764 | }); | |
df111b53 | 765 | |
153d5065 RG |
766 | g_lua.writeFunction("addLuaResponseAction", [](luadnsrule_t var, LuaResponseAction::func_t func) { |
767 | setLuaSideEffect(); | |
768 | auto rule=makeRule(var); | |
769 | g_resprulactions.modify([rule,func](decltype(g_resprulactions)::value_type& rulactions){ | |
770 | rulactions.push_back({rule, | |
771 | std::make_shared<LuaResponseAction>(func)}); | |
772 | }); | |
773 | }); | |
d8d85a30 | 774 | |
6bba426c | 775 | g_lua.writeFunction("NoRecurseAction", []() { |
776 | return std::shared_ptr<DNSAction>(new NoRecurseAction); | |
777 | }); | |
778 | ||
6907f014 | 779 | g_lua.writeFunction("MacAddrAction", [](int code) { |
780 | return std::shared_ptr<DNSAction>(new MacAddrAction(code)); | |
781 | }); | |
782 | ||
783 | ||
e27097e4 | 784 | g_lua.writeFunction("PoolAction", [](const string& a) { |
785 | return std::shared_ptr<DNSAction>(new PoolAction(a)); | |
786 | }); | |
787 | ||
b1bec9f0 RG |
788 | g_lua.writeFunction("QPSPoolAction", [](int limit, const string& a) { |
789 | return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a)); | |
790 | }); | |
791 | ||
9ebc0e91 | 792 | g_lua.writeFunction("SpoofAction", [](boost::variant<string,vector<pair<int, string>>> inp, boost::optional<string> b ) { |
793 | vector<ComboAddress> addrs; | |
794 | if(auto s = boost::get<string>(&inp)) | |
795 | addrs.push_back(ComboAddress(*s)); | |
796 | else { | |
797 | const auto& v = boost::get<vector<pair<int,string>>>(inp); | |
798 | for(const auto& a: v) | |
799 | addrs.push_back(ComboAddress(a.second)); | |
800 | } | |
801 | if(b) | |
802 | addrs.push_back(ComboAddress(*b)); | |
803 | return std::shared_ptr<DNSAction>(new SpoofAction(addrs)); | |
731774a8 | 804 | }); |
805 | ||
87c605c4 RG |
806 | g_lua.writeFunction("SpoofCNAMEAction", [](const string& a) { |
807 | return std::shared_ptr<DNSAction>(new SpoofAction(a)); | |
808 | }); | |
809 | ||
9ebc0e91 | 810 | g_lua.writeFunction("addDomainSpoof", [](const std::string& domain, boost::variant<string,vector<pair<int, string>>> inp, boost::optional<string> b) { |
f758857a | 811 | setLuaSideEffect(); |
731774a8 | 812 | SuffixMatchNode smn; |
9ebc0e91 | 813 | vector<ComboAddress> outp; |
731774a8 | 814 | try |
815 | { | |
816 | smn.add(DNSName(domain)); | |
9ebc0e91 | 817 | |
818 | if(auto s = boost::get<string>(&inp)) | |
819 | outp.push_back(ComboAddress(*s)); | |
820 | else { | |
821 | const auto& v = boost::get<vector<pair<int,string>>>(inp); | |
822 | for(const auto& a: v) | |
823 | outp.push_back(ComboAddress(a.second)); | |
824 | } | |
825 | if(b) | |
826 | outp.push_back(ComboAddress(*b)); | |
827 | ||
731774a8 | 828 | } |
829 | catch(std::exception& e) { | |
830 | g_outputBuffer="Error parsing parameters: "+string(e.what()); | |
831 | return; | |
832 | } | |
9ebc0e91 | 833 | g_rulactions.modify([&smn,&outp](decltype(g_rulactions)::value_type& rulactions) { |
731774a8 | 834 | rulactions.push_back({ |
835 | std::make_shared<SuffixMatchNodeRule>(smn), | |
9ebc0e91 | 836 | std::make_shared<SpoofAction>(outp) }); |
731774a8 | 837 | }); |
838 | ||
839 | }); | |
840 | ||
87c605c4 RG |
841 | g_lua.writeFunction("addDomainCNAMESpoof", [](const std::string& domain, const std::string& cname) { |
842 | setLuaSideEffect(); | |
843 | SuffixMatchNode smn; | |
844 | try | |
845 | { | |
846 | smn.add(DNSName(domain)); | |
847 | } | |
848 | catch(std::exception& e) { | |
849 | g_outputBuffer="Error parsing parameters: "+string(e.what()); | |
850 | return; | |
851 | } | |
852 | g_rulactions.modify([&smn,&cname](decltype(g_rulactions)::value_type& rulactions) { | |
853 | rulactions.push_back({ | |
854 | std::make_shared<SuffixMatchNodeRule>(smn), | |
855 | std::make_shared<SpoofAction>(cname) }); | |
856 | }); | |
857 | }); | |
731774a8 | 858 | |
ae3dfa48 | 859 | g_lua.writeFunction("DropAction", []() { |
860 | return std::shared_ptr<DNSAction>(new DropAction); | |
861 | }); | |
862 | ||
63beb26d G |
863 | g_lua.writeFunction("AllowAction", []() { |
864 | return std::shared_ptr<DNSAction>(new AllowAction); | |
865 | }); | |
866 | ||
6eecd4c2 | 867 | g_lua.writeFunction("DelayAction", [](int msec) { |
868 | return std::shared_ptr<DNSAction>(new DelayAction(msec)); | |
869 | }); | |
870 | ||
2332b03c | 871 | g_lua.writeFunction("TCAction", []() { |
872 | return std::shared_ptr<DNSAction>(new TCAction); | |
873 | }); | |
874 | ||
f39b7598 RG |
875 | g_lua.writeFunction("DisableValidationAction", []() { |
876 | return std::shared_ptr<DNSAction>(new DisableValidationAction); | |
877 | }); | |
878 | ||
456fc645 | 879 | g_lua.writeFunction("LogAction", [](const std::string& fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered) { |
880 | return std::shared_ptr<DNSAction>(new LogAction(fname, binary ? *binary : true, append ? *append : false, buffered ? *buffered : false)); | |
808c5ef7 | 881 | }); |
882 | ||
0bd31ccc RG |
883 | g_lua.writeFunction("RCodeAction", [](int rcode) { |
884 | return std::shared_ptr<DNSAction>(new RCodeAction(rcode)); | |
885 | }); | |
ae3dfa48 | 886 | |
886e2cf2 RG |
887 | g_lua.writeFunction("SkipCacheAction", []() { |
888 | return std::shared_ptr<DNSAction>(new SkipCacheAction); | |
889 | }); | |
890 | ||
1b726acf | 891 | g_lua.writeFunction("MaxQPSIPRule", [](unsigned int qps, boost::optional<int> ipv4trunc, boost::optional<int> ipv6trunc) { |
892 | return std::shared_ptr<DNSRule>(new MaxQPSIPRule(qps, ipv4trunc.get_value_or(32), ipv6trunc.get_value_or(64))); | |
6bba426c | 893 | }); |
894 | ||
895 | ||
2332b03c | 896 | g_lua.writeFunction("MaxQPSRule", [](unsigned int qps, boost::optional<int> burst) { |
897 | if(!burst) | |
898 | return std::shared_ptr<DNSRule>(new MaxQPSRule(qps)); | |
899 | else | |
900 | return std::shared_ptr<DNSRule>(new MaxQPSRule(qps, *burst)); | |
901 | }); | |
902 | ||
903 | ||
6eecd4c2 | 904 | g_lua.writeFunction("RegexRule", [](const std::string& str) { |
905 | return std::shared_ptr<DNSRule>(new RegexRule(str)); | |
906 | }); | |
907 | ||
4ed8dfeb | 908 | #ifdef HAVE_RE2 |
909 | g_lua.writeFunction("RE2Rule", [](const std::string& str) { | |
910 | return std::shared_ptr<DNSRule>(new RE2Rule(str)); | |
911 | }); | |
912 | #endif | |
913 | ||
291729f3 | 914 | g_lua.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional<bool> quiet) { |
915 | return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); | |
0bd31ccc | 916 | }); |
b7860997 | 917 | |
b6dcb2f7 RS |
918 | g_lua.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional<bool> src) { |
919 | return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true)); | |
36da3ecd RG |
920 | }); |
921 | ||
b7860997 | 922 | g_lua.writeFunction("benchRule", [](std::shared_ptr<DNSRule> rule, boost::optional<int> times_, boost::optional<string> suffix_) { |
f758857a | 923 | setLuaNoSideEffect(); |
b7860997 | 924 | int times = times_.get_value_or(100000); |
925 | DNSName suffix(suffix_.get_value_or("powerdns.com")); | |
926 | struct item { | |
927 | vector<uint8_t> packet; | |
928 | ComboAddress rem; | |
929 | DNSName qname; | |
3b069df2 | 930 | uint16_t qtype, qclass; |
b7860997 | 931 | }; |
932 | vector<item> items; | |
933 | items.reserve(1000); | |
934 | for(int n=0; n < 1000; ++n) { | |
935 | struct item i; | |
936 | i.qname=DNSName(std::to_string(random())); | |
937 | i.qname += suffix; | |
938 | i.qtype = random() % 0xff; | |
3b069df2 | 939 | i.qclass = 1; |
b7860997 | 940 | i.rem=ComboAddress("127.0.0.1"); |
941 | i.rem.sin4.sin_addr.s_addr = random(); | |
942 | DNSPacketWriter pw(i.packet, i.qname, i.qtype); | |
943 | items.push_back(i); | |
944 | } | |
945 | ||
946 | int matches=0; | |
497a6e3a | 947 | ComboAddress dummy("127.0.0.1"); |
b7860997 | 948 | DTime dt; |
949 | dt.set(); | |
950 | for(int n=0; n < times; ++n) { | |
951 | const item& i = items[n % items.size()]; | |
3b069df2 | 952 | DNSQuestion dq(&i.qname, i.qtype, i.qclass, &i.rem, &i.rem, (struct dnsheader*)&i.packet[0], i.packet.size(), i.packet.size(), false); |
497a6e3a | 953 | if(rule->matches(&dq)) |
b7860997 | 954 | matches++; |
955 | } | |
956 | double udiff=dt.udiff(); | |
957 | g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f usec\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str(); | |
958 | ||
959 | }); | |
89cb6f9a | 960 | |
961 | g_lua.writeFunction("AllRule", []() { | |
962 | return std::shared_ptr<DNSRule>(new AllRule()); | |
963 | }); | |
964 | ||
0f697c45 | 965 | g_lua.writeFunction("QNameRule", [](const std::string& qname) { |
966 | return std::shared_ptr<DNSRule>(new QNameRule(DNSName(qname))); | |
967 | }); | |
968 | ||
b7860997 | 969 | g_lua.writeFunction("QTypeRule", [](boost::variant<int, std::string> str) { |
970 | uint16_t qtype; | |
971 | if(auto dir = boost::get<int>(&str)) { | |
972 | qtype = *dir; | |
973 | } | |
974 | else { | |
975 | string val=boost::get<string>(str); | |
976 | qtype = QType::chartocode(val.c_str()); | |
977 | if(!qtype) | |
978 | throw std::runtime_error("Unable to convert '"+val+"' to a DNS type"); | |
979 | } | |
980 | return std::shared_ptr<DNSRule>(new QTypeRule(qtype)); | |
981 | }); | |
55baa1f2 | 982 | g_lua.writeFunction("QClassRule", [](int c) { |
3b069df2 | 983 | return std::shared_ptr<DNSRule>(new QClassRule(c)); |
984 | }); | |
985 | ||
55baa1f2 RG |
986 | g_lua.writeFunction("OpcodeRule", [](uint8_t code) { |
987 | return std::shared_ptr<DNSRule>(new OpcodeRule(code)); | |
988 | }); | |
b7860997 | 989 | |
990 | g_lua.writeFunction("AndRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) { | |
991 | return std::shared_ptr<DNSRule>(new AndRule(a)); | |
992 | }); | |
993 | ||
e7a1029c RG |
994 | g_lua.writeFunction("OrRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) { |
995 | return std::shared_ptr<DNSRule>(new OrRule(a)); | |
996 | }); | |
997 | ||
490a29bb RG |
998 | g_lua.writeFunction("TCPRule", [](bool tcp) { |
999 | return std::shared_ptr<DNSRule>(new TCPRule(tcp)); | |
1000 | }); | |
b7860997 | 1001 | |
b1bec9f0 RG |
1002 | g_lua.writeFunction("DNSSECRule", []() { |
1003 | return std::shared_ptr<DNSRule>(new DNSSECRule()); | |
1004 | }); | |
1005 | ||
e7a1029c RG |
1006 | g_lua.writeFunction("NotRule", [](std::shared_ptr<DNSRule>rule) { |
1007 | return std::shared_ptr<DNSRule>(new NotRule(rule)); | |
1008 | }); | |
1009 | ||
55baa1f2 RG |
1010 | g_lua.writeFunction("RecordsCountRule", [](uint8_t section, uint16_t minCount, uint16_t maxCount) { |
1011 | return std::shared_ptr<DNSRule>(new RecordsCountRule(section, minCount, maxCount)); | |
1012 | }); | |
1013 | ||
1014 | g_lua.writeFunction("RecordsTypeCountRule", [](uint8_t section, uint16_t type, uint16_t minCount, uint16_t maxCount) { | |
1015 | return std::shared_ptr<DNSRule>(new RecordsTypeCountRule(section, type, minCount, maxCount)); | |
1016 | }); | |
1017 | ||
1018 | g_lua.writeFunction("TrailingDataRule", []() { | |
1019 | return std::shared_ptr<DNSRule>(new TrailingDataRule()); | |
1020 | }); | |
1021 | ||
57c61ce9 RG |
1022 | g_lua.writeFunction("QNameLabelsCountRule", [](unsigned int minLabelsCount, unsigned int maxLabelsCount) { |
1023 | return std::shared_ptr<DNSRule>(new QNameLabelsCountRule(minLabelsCount, maxLabelsCount)); | |
1024 | }); | |
1025 | ||
1026 | g_lua.writeFunction("QNameWireLengthRule", [](size_t min, size_t max) { | |
1027 | return std::shared_ptr<DNSRule>(new QNameWireLengthRule(min, max)); | |
1028 | }); | |
1029 | ||
788c3243 RG |
1030 | g_lua.writeFunction("RCodeRule", [](int rcode) { |
1031 | return std::shared_ptr<DNSRule>(new RCodeRule(rcode)); | |
1032 | }); | |
1033 | ||
f186603d | 1034 | g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era) |
6bba426c | 1035 | { |
f186603d RG |
1036 | if (era.type() == typeid(std::shared_ptr<DNSResponseAction>)) { |
1037 | throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); | |
1038 | } | |
1039 | ||
1040 | auto ea = *boost::get<std::shared_ptr<DNSAction>>(&era); | |
f758857a | 1041 | setLuaSideEffect(); |
6bba426c | 1042 | auto rule=makeRule(var); |
1043 | g_rulactions.modify([rule, ea](decltype(g_rulactions)::value_type& rulactions){ | |
1044 | rulactions.push_back({rule, ea}); | |
1045 | }); | |
1046 | }); | |
1047 | ||
1048 | ||
1049 | g_lua.writeFunction("addPoolRule", [](luadnsrule_t var, string pool) { | |
f758857a | 1050 | setLuaSideEffect(); |
d8d85a30 | 1051 | auto rule=makeRule(var); |
1052 | g_rulactions.modify([rule, pool](decltype(g_rulactions)::value_type& rulactions) { | |
0940e4eb | 1053 | rulactions.push_back({ |
d8d85a30 | 1054 | rule, |
1055 | std::make_shared<PoolAction>(pool) }); | |
ecbe9133 | 1056 | }); |
df111b53 | 1057 | }); |
0570f37c | 1058 | |
6bba426c | 1059 | g_lua.writeFunction("addNoRecurseRule", [](luadnsrule_t var) { |
f758857a | 1060 | setLuaSideEffect(); |
0570f37c | 1061 | auto rule=makeRule(var); |
1062 | g_rulactions.modify([rule](decltype(g_rulactions)::value_type& rulactions) { | |
1063 | rulactions.push_back({ | |
1064 | rule, | |
1065 | std::make_shared<NoRecurseAction>() }); | |
1066 | }); | |
1067 | }); | |
1068 | ||
f39b7598 | 1069 | g_lua.writeFunction("addDisableValidationRule", [](luadnsrule_t var) { |
f758857a | 1070 | setLuaSideEffect(); |
f39b7598 RG |
1071 | auto rule=makeRule(var); |
1072 | g_rulactions.modify([rule](decltype(g_rulactions)::value_type& rulactions) { | |
1073 | rulactions.push_back({ | |
1074 | rule, | |
1075 | std::make_shared<DisableValidationAction>() }); | |
1076 | }); | |
1077 | }); | |
1078 | ||
0570f37c | 1079 | |
6bba426c | 1080 | g_lua.writeFunction("addQPSPoolRule", [](luadnsrule_t var, int limit, string pool) { |
f758857a | 1081 | setLuaSideEffect(); |
d8d85a30 | 1082 | auto rule = makeRule(var); |
1083 | g_rulactions.modify([rule, pool,limit](decltype(g_rulactions)::value_type& rulactions) { | |
1084 | rulactions.push_back({ | |
1085 | rule, | |
1086 | std::make_shared<QPSPoolAction>(limit, pool) }); | |
1087 | }); | |
fd010ca3 | 1088 | }); |
df111b53 | 1089 | |
520eb5a0 | 1090 | g_lua.writeFunction("setDNSSECPool", [](const std::string& pool) { |
f758857a | 1091 | setLuaSideEffect(); |
520eb5a0 | 1092 | g_rulactions.modify([pool](decltype(g_rulactions)::value_type& rulactions) { |
1093 | rulactions.push_back({std::make_shared<DNSSECRule>(), | |
1094 | std::make_shared<PoolAction>(pool)}); | |
1095 | }); | |
1096 | }); | |
df111b53 | 1097 | |
6bba426c | 1098 | g_lua.writeFunction("addQPSLimit", [](luadnsrule_t var, int lim) { |
f758857a | 1099 | setLuaSideEffect(); |
d8d85a30 | 1100 | auto rule = makeRule(var); |
1101 | g_rulactions.modify([lim,rule](decltype(g_rulactions)::value_type& rulactions) { | |
1102 | rulactions.push_back({rule, | |
1103 | std::make_shared<QPSAction>(lim)}); | |
1104 | }); | |
df111b53 | 1105 | }); |
d8d85a30 | 1106 | |
6bba426c | 1107 | g_lua.writeFunction("addDelay", [](luadnsrule_t var, int msec) { |
f758857a | 1108 | setLuaSideEffect(); |
7b3865cd | 1109 | auto rule = makeRule(var); |
1110 | g_rulactions.modify([msec,rule](decltype(g_rulactions)::value_type& rulactions) { | |
1111 | rulactions.push_back({rule, | |
1112 | std::make_shared<DelayAction>(msec)}); | |
1113 | }); | |
1114 | }); | |
df111b53 | 1115 | |
df111b53 | 1116 | |
0940e4eb | 1117 | g_lua.writeFunction("showRules", []() { |
f758857a | 1118 | setLuaNoSideEffect(); |
0940e4eb | 1119 | boost::format fmt("%-3d %9d %-50s %s\n"); |
1120 | g_outputBuffer += (fmt % "#" % "Matches" % "Rule" % "Action").str(); | |
1121 | int num=0; | |
1122 | for(const auto& lim : g_rulactions.getCopy()) { | |
1123 | string name = lim.first->toString(); | |
1124 | g_outputBuffer += (fmt % num % lim.first->d_matches % name % lim.second->toString()).str(); | |
df111b53 | 1125 | ++num; |
1126 | } | |
1127 | }); | |
1128 | ||
df111b53 | 1129 | g_lua.writeFunction("getServers", []() { |
f758857a | 1130 | setLuaNoSideEffect(); |
df111b53 | 1131 | vector<pair<int, std::shared_ptr<DownstreamState> > > ret; |
1132 | int count=1; | |
e5a14b2b | 1133 | for(const auto& s : g_dstates.getCopy()) { |
df111b53 | 1134 | ret.push_back(make_pair(count++, s)); |
1135 | } | |
1136 | return ret; | |
1137 | }); | |
1138 | ||
da4e7813 | 1139 | g_lua.writeFunction("getPoolServers", [](string pool) { |
886e2cf2 | 1140 | return getDownstreamCandidates(g_pools.getCopy(), pool); |
da4e7813 | 1141 | }); |
1142 | ||
8780ba53 RG |
1143 | g_lua.writeFunction("getServer", [client](int i) { |
1144 | if (client) | |
1145 | return std::make_shared<DownstreamState>(ComboAddress()); | |
1146 | return g_dstates.getCopy().at(i); | |
1147 | }); | |
df111b53 | 1148 | |
df111b53 | 1149 | g_lua.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& s, int lim) { s.qps = lim ? QPSLimiter(lim, lim) : QPSLimiter(); }); |
886e2cf2 RG |
1150 | g_lua.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](std::shared_ptr<DownstreamState> s, string pool) { |
1151 | auto localPools = g_pools.getCopy(); | |
1152 | addServerToPool(localPools, pool, s); | |
1153 | g_pools.setState(localPools); | |
1154 | s->pools.insert(pool); | |
1155 | }); | |
1156 | g_lua.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](std::shared_ptr<DownstreamState> s, string pool) { | |
1157 | auto localPools = g_pools.getCopy(); | |
1158 | removeServerFromPool(localPools, pool, s); | |
1159 | g_pools.setState(localPools); | |
1160 | s->pools.erase(pool); | |
1161 | }); | |
df111b53 | 1162 | |
1163 | g_lua.registerFunction<void(DownstreamState::*)()>("getOutstanding", [](const DownstreamState& s) { g_outputBuffer=std::to_string(s.outstanding.load()); }); | |
1164 | ||
1165 | ||
1166 | g_lua.registerFunction("isUp", &DownstreamState::isUp); | |
1167 | g_lua.registerFunction("setDown", &DownstreamState::setDown); | |
1168 | g_lua.registerFunction("setUp", &DownstreamState::setUp); | |
1169 | g_lua.registerFunction("setAuto", &DownstreamState::setAuto); | |
46a839bf RG |
1170 | g_lua.registerFunction("getName", &DownstreamState::getName); |
1171 | g_lua.registerFunction("getNameWithAddr", &DownstreamState::getNameWithAddr); | |
b0976f44 | 1172 | g_lua.registerMember("upStatus", &DownstreamState::upStatus); |
df111b53 | 1173 | g_lua.registerMember("weight", &DownstreamState::weight); |
1174 | g_lua.registerMember("order", &DownstreamState::order); | |
46a839bf | 1175 | g_lua.registerMember("name", &DownstreamState::name); |
df111b53 | 1176 | |
4c6f4321 | 1177 | g_lua.writeFunction("infolog", [](const string& arg) { |
1178 | infolog("%s", arg); | |
1179 | }); | |
1180 | g_lua.writeFunction("errlog", [](const string& arg) { | |
1181 | errlog("%s", arg); | |
1182 | }); | |
1183 | g_lua.writeFunction("warnlog", [](const string& arg) { | |
1184 | warnlog("%s", arg); | |
1185 | }); | |
1186 | ||
1187 | ||
df111b53 | 1188 | g_lua.writeFunction("show", [](const string& arg) { |
1189 | g_outputBuffer+=arg; | |
1190 | g_outputBuffer+="\n"; | |
1191 | }); | |
1192 | ||
1193 | g_lua.registerFunction<void(dnsheader::*)(bool)>("setRD", [](dnsheader& dh, bool v) { | |
1194 | dh.rd=v; | |
1195 | }); | |
1196 | ||
1197 | g_lua.registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) { | |
1198 | return (bool)dh.rd; | |
1199 | }); | |
1200 | ||
aeb36780 RG |
1201 | g_lua.registerFunction<void(dnsheader::*)(bool)>("setCD", [](dnsheader& dh, bool v) { |
1202 | dh.cd=v; | |
1203 | }); | |
1204 | ||
1205 | g_lua.registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) { | |
1206 | return (bool)dh.cd; | |
1207 | }); | |
1208 | ||
df111b53 | 1209 | |
1210 | g_lua.registerFunction<void(dnsheader::*)(bool)>("setTC", [](dnsheader& dh, bool v) { | |
1211 | dh.tc=v; | |
bde3ab96 | 1212 | if(v) dh.ra = dh.rd; // you'll always need this, otherwise TC=1 gets ignored |
df111b53 | 1213 | }); |
1214 | ||
1215 | g_lua.registerFunction<void(dnsheader::*)(bool)>("setQR", [](dnsheader& dh, bool v) { | |
1216 | dh.qr=v; | |
1217 | }); | |
1218 | ||
b769dbb7 RG |
1219 | g_lua.registerFunction<string(std::shared_ptr<DNSRule>::*)()>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); }); |
1220 | ||
d6a9a395 RG |
1221 | g_lua.registerFunction<string(ComboAddress::*)()>("tostring", [](const ComboAddress& ca) { return ca.toString(); }); |
1222 | g_lua.registerFunction<string(ComboAddress::*)()>("tostringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); | |
1223 | g_lua.registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); }); | |
1224 | g_lua.registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); | |
0a112365 | 1225 | g_lua.registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } ); |
d6a9a395 RG |
1226 | g_lua.registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); }); |
1227 | g_lua.registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; }); | |
1228 | g_lua.registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; }); | |
1229 | g_lua.registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); }); | |
1230 | g_lua.registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); }); | |
a94673ea | 1231 | |
df111b53 | 1232 | g_lua.registerFunction("isPartOf", &DNSName::isPartOf); |
2b18ac9f | 1233 | g_lua.registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); }); |
d6a9a395 RG |
1234 | g_lua.registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); }); |
1235 | g_lua.registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); }); | |
b5425a3d | 1236 | g_lua.registerFunction<string(DNSName::*)()>("tostring", [](const DNSName&dn ) { return dn.toString(); }); |
497a6e3a | 1237 | g_lua.registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); }); |
df111b53 | 1238 | g_lua.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); }); |
b0976f44 | 1239 | g_lua.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); }); |
df111b53 | 1240 | |
1241 | g_lua.registerFunction("add",(void (SuffixMatchNode::*)(const DNSName&)) &SuffixMatchNode::add); | |
1242 | g_lua.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); | |
1243 | ||
42fae326 | 1244 | g_lua.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName, |
d617b22c | 1245 | boost::optional<unsigned int> interval) { |
f758857a | 1246 | setLuaSideEffect(); |
42fae326 | 1247 | auto ours = g_carbon.getCopy(); |
d617b22c | 1248 | ours.push_back({ComboAddress(address, 2003), ourName ? *ourName : "", interval ? *interval : 30}); |
42fae326 | 1249 | g_carbon.setState(ours); |
1250 | }); | |
1251 | ||
002decab | 1252 | g_lua.writeFunction("webserver", [client](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders) { |
f758857a | 1253 | setLuaSideEffect(); |
50bed881 | 1254 | if(client) |
1255 | return; | |
1256 | ComboAddress local(address); | |
1257 | try { | |
8d06661a | 1258 | int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0); |
50bed881 | 1259 | SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1); |
1260 | SBind(sock, local); | |
1261 | SListen(sock, 5); | |
002decab RG |
1262 | auto launch=[sock, local, password, apiKey, customHeaders]() { |
1263 | thread t(dnsdistWebserverThread, sock, local, password, apiKey ? *apiKey : "", customHeaders); | |
50bed881 | 1264 | t.detach(); |
1265 | }; | |
1266 | if(g_launchWork) | |
1267 | g_launchWork->push_back(launch); | |
1268 | else | |
1269 | launch(); | |
1270 | } | |
1271 | catch(std::exception& e) { | |
0c8e7c58 | 1272 | g_outputBuffer="Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what(); |
50bed881 | 1273 | errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what()); |
1274 | } | |
1275 | ||
1276 | }); | |
df111b53 | 1277 | g_lua.writeFunction("controlSocket", [client](const std::string& str) { |
f758857a | 1278 | setLuaSideEffect(); |
df111b53 | 1279 | ComboAddress local(str, 5199); |
1280 | ||
1281 | if(client) { | |
1282 | g_serverControl = local; | |
1283 | return; | |
1284 | } | |
1285 | ||
1286 | try { | |
8d06661a | 1287 | int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0); |
df111b53 | 1288 | SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1); |
1289 | SBind(sock, local); | |
1290 | SListen(sock, 5); | |
2e72cc0e | 1291 | auto launch=[sock, local]() { |
1292 | thread t(controlThread, sock, local); | |
1293 | t.detach(); | |
1294 | }; | |
1295 | if(g_launchWork) | |
1296 | g_launchWork->push_back(launch); | |
1297 | else | |
1298 | launch(); | |
1299 | ||
df111b53 | 1300 | } |
1301 | catch(std::exception& e) { | |
0c8e7c58 | 1302 | g_outputBuffer="Unable to bind to control socket on " + local.toStringWithPort() + ": " + e.what(); |
df111b53 | 1303 | errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), e.what()); |
1304 | } | |
1305 | }); | |
1306 | ||
03ebf8b2 | 1307 | |
d179bc47 | 1308 | g_lua.writeFunction("topClients", [](boost::optional<unsigned int> top_) { |
f758857a | 1309 | setLuaNoSideEffect(); |
d179bc47 | 1310 | auto top = top_.get_value_or(10); |
0e5b3cff | 1311 | map<ComboAddress, int,ComboAddress::addressOnlyLessThan > counts; |
1312 | unsigned int total=0; | |
0e41337b RG |
1313 | { |
1314 | ReadLock rl(&g_rings.queryLock); | |
1315 | for(const auto& c : g_rings.queryRing) { | |
1316 | counts[c.requestor]++; | |
1317 | total++; | |
1318 | } | |
0e5b3cff | 1319 | } |
1320 | vector<pair<int, ComboAddress>> rcounts; | |
a73fc812 | 1321 | rcounts.reserve(counts.size()); |
0e5b3cff | 1322 | for(const auto& c : counts) |
1323 | rcounts.push_back(make_pair(c.second, c.first)); | |
1324 | ||
1325 | sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a, | |
1326 | const decltype(rcounts)::value_type& b) { | |
1327 | return b.first < a.first; | |
1328 | }); | |
1329 | unsigned int count=1, rest=0; | |
1330 | boost::format fmt("%4d %-40s %4d %4.1f%%\n"); | |
1331 | for(const auto& rc : rcounts) { | |
1332 | if(count==top+1) | |
1333 | rest+=rc.first; | |
1334 | else | |
1335 | g_outputBuffer += (fmt % (count++) % rc.second.toString() % rc.first % (100.0*rc.first/total)).str(); | |
1336 | } | |
6a62c0e3 | 1337 | g_outputBuffer += (fmt % (count) % "Rest" % rest % (total > 0 ? 100.0*rest/total : 100.0)).str(); |
0e5b3cff | 1338 | }); |
1339 | ||
df111b53 | 1340 | g_lua.writeFunction("getTopQueries", [](unsigned int top, boost::optional<int> labels) { |
f758857a | 1341 | setLuaNoSideEffect(); |
df111b53 | 1342 | map<DNSName, int> counts; |
1343 | unsigned int total=0; | |
1344 | if(!labels) { | |
0e41337b | 1345 | ReadLock rl(&g_rings.queryLock); |
df111b53 | 1346 | for(const auto& a : g_rings.queryRing) { |
0ba5eecf | 1347 | counts[a.name]++; |
df111b53 | 1348 | total++; |
1349 | } | |
1350 | } | |
1351 | else { | |
1352 | unsigned int lab = *labels; | |
0e41337b | 1353 | ReadLock rl(&g_rings.queryLock); |
df111b53 | 1354 | for(auto a : g_rings.queryRing) { |
0ba5eecf | 1355 | a.name.trimToLabels(lab); |
1356 | counts[a.name]++; | |
df111b53 | 1357 | total++; |
1358 | } | |
df111b53 | 1359 | } |
cffde2fd | 1360 | // cout<<"Looked at "<<total<<" queries, "<<counts.size()<<" different ones"<<endl; |
df111b53 | 1361 | vector<pair<int, DNSName>> rcounts; |
3821bfe2 | 1362 | rcounts.reserve(counts.size()); |
df111b53 | 1363 | for(const auto& c : counts) |
2f95ab40 | 1364 | rcounts.push_back(make_pair(c.second, c.first.makeLowerCase())); |
df111b53 | 1365 | |
1366 | sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a, | |
1367 | const decltype(rcounts)::value_type& b) { | |
1368 | return b.first < a.first; | |
1369 | }); | |
1370 | ||
1371 | std::unordered_map<int, vector<boost::variant<string,double>>> ret; | |
1372 | unsigned int count=1, rest=0; | |
1373 | for(const auto& rc : rcounts) { | |
1374 | if(count==top+1) | |
1375 | rest+=rc.first; | |
1376 | else | |
1377 | ret.insert({count++, {rc.second.toString(), rc.first, 100.0*rc.first/total}}); | |
1378 | } | |
6a62c0e3 | 1379 | ret.insert({count, {"Rest", rest, total > 0 ? 100.0*rest/total : 100.0}}); |
df111b53 | 1380 | return ret; |
1381 | ||
1382 | }); | |
786e4d8c | 1383 | |
a78a3a0e | 1384 | g_lua.executeCode(R"(function topQueries(top, labels) top = top or 10; for k,v in ipairs(getTopQueries(top,labels)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2], v[3])) end end)"); |
df111b53 | 1385 | |
786e4d8c RS |
1386 | g_lua.writeFunction("clearQueryCounters", []() { |
1387 | unsigned int size{0}; | |
1388 | { | |
1389 | WriteLock wl(&g_qcount.queryLock); | |
1390 | size = g_qcount.records.size(); | |
1391 | g_qcount.records.clear(); | |
1392 | } | |
1393 | ||
1394 | boost::format fmt("%d records cleared from query counter buffer\n"); | |
1395 | g_outputBuffer = (fmt % size).str(); | |
1396 | }); | |
520eb5a0 | 1397 | |
786e4d8c RS |
1398 | g_lua.writeFunction("getQueryCounters", [](boost::optional<unsigned int> optMax) { |
1399 | setLuaNoSideEffect(); | |
1400 | ReadLock rl(&g_qcount.queryLock); | |
1401 | g_outputBuffer = "query counting is currently: "; | |
1402 | g_outputBuffer+= g_qcount.enabled ? "enabled" : "disabled"; | |
1403 | g_outputBuffer+= (boost::format(" (%d records in buffer)\n") % g_qcount.records.size()).str(); | |
1404 | ||
1405 | boost::format fmt("%-3d %s: %d request(s)\n"); | |
1406 | QueryCountRecords::iterator it; | |
1407 | unsigned int max = optMax ? *optMax : 10; | |
1408 | unsigned int index{1}; | |
1409 | for(it = g_qcount.records.begin(); it != g_qcount.records.end() && index <= max; ++it, ++index) { | |
1410 | g_outputBuffer += (fmt % index % it->first % it->second).str(); | |
1411 | } | |
1412 | }); | |
1413 | ||
1414 | g_lua.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled=enabled; }); | |
1415 | g_lua.writeFunction("setQueryCountFilter", [](QueryCountFilter func) { | |
1416 | g_qcount.filter = func; | |
1417 | }); | |
62edea30 | 1418 | |
520eb5a0 | 1419 | g_lua.writeFunction("getResponseRing", []() { |
f758857a | 1420 | setLuaNoSideEffect(); |
520eb5a0 | 1421 | decltype(g_rings.respRing) ring; |
1422 | { | |
1423 | std::lock_guard<std::mutex> lock(g_rings.respMutex); | |
1424 | ring = g_rings.respRing; | |
1425 | } | |
1426 | vector<std::unordered_map<string, boost::variant<string, unsigned int> > > ret; | |
1427 | ret.reserve(ring.size()); | |
1428 | decltype(ret)::value_type item; | |
1429 | for(const auto& r : ring) { | |
1430 | item["name"]=r.name.toString(); | |
1431 | item["qtype"]=r.qtype; | |
3fcaeeac | 1432 | item["rcode"]=r.dh.rcode; |
520eb5a0 | 1433 | item["usec"]=r.usec; |
1434 | ret.push_back(item); | |
1435 | } | |
1436 | return ret; | |
1437 | }); | |
f5b58807 | 1438 | |
df111b53 | 1439 | g_lua.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional<int> labels) { |
2d11d1b2 | 1440 | return getGenResponses(top, labels, [kind](const Rings::Response& r) { return r.dh.rcode == kind; }); |
1441 | }); | |
df111b53 | 1442 | |
2d11d1b2 | 1443 | g_lua.executeCode(R"(function topResponses(top, kind, labels) top = top or 10; kind = kind or 0; for k,v in ipairs(getTopResponses(top, kind, labels)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)"); |
df111b53 | 1444 | |
df111b53 | 1445 | |
2d11d1b2 | 1446 | g_lua.writeFunction("getSlowResponses", [](unsigned int top, unsigned int msec, boost::optional<int> labels) { |
1447 | return getGenResponses(top, labels, [msec](const Rings::Response& r) { return r.usec > msec*1000; }); | |
df111b53 | 1448 | }); |
62edea30 | 1449 | |
2d11d1b2 | 1450 | |
2a05b4a9 | 1451 | g_lua.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec, labels)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)"); |
df111b53 | 1452 | |
1453 | ||
1454 | g_lua.writeFunction("showResponseLatency", []() { | |
f758857a | 1455 | setLuaNoSideEffect(); |
df111b53 | 1456 | map<double, unsigned int> histo; |
1457 | double bin=100; | |
1458 | for(int i=0; i < 15; ++i) { | |
1459 | histo[bin]; | |
1460 | bin*=2; | |
1461 | } | |
1462 | ||
1463 | double totlat=0; | |
2b2ab383 | 1464 | unsigned int size=0; |
df111b53 | 1465 | { |
1466 | std::lock_guard<std::mutex> lock(g_rings.respMutex); | |
1467 | for(const auto& r : g_rings.respRing) { | |
2b2ab383 RG |
1468 | /* skip actively discovered timeouts */ |
1469 | if (r.usec == std::numeric_limits<unsigned int>::max()) | |
1470 | continue; | |
1471 | ||
df111b53 | 1472 | ++size; |
1473 | auto iter = histo.lower_bound(r.usec); | |
1474 | if(iter != histo.end()) | |
1475 | iter->second++; | |
1476 | else | |
1477 | histo.rbegin()++; | |
1478 | totlat+=r.usec; | |
1479 | } | |
1480 | } | |
1481 | ||
e12b3374 RG |
1482 | if (size == 0) { |
1483 | g_outputBuffer = "No traffic yet.\n"; | |
1484 | return; | |
1485 | } | |
1486 | ||
df111b53 | 1487 | g_outputBuffer = (boost::format("Average response latency: %.02f msec\n") % (0.001*totlat/size)).str(); |
1488 | double highest=0; | |
1489 | ||
1490 | for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) { | |
1491 | highest=std::max(highest, iter->second*1.0); | |
1492 | } | |
1493 | boost::format fmt("%7.2f\t%s\n"); | |
1494 | g_outputBuffer += (fmt % "msec" % "").str(); | |
1495 | ||
1496 | for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) { | |
1497 | int stars = (70.0 * iter->second/highest); | |
1498 | char c='*'; | |
1499 | if(!stars && iter->second) { | |
1500 | stars=1; // you get 1 . to show something is there.. | |
1501 | if(70.0*iter->second/highest > 0.5) | |
1502 | c=':'; | |
1503 | else | |
1504 | c='.'; | |
1505 | } | |
1506 | g_outputBuffer += (fmt % (iter->first/1000.0) % string(stars, c)).str(); | |
1507 | } | |
1508 | }); | |
1509 | ||
1510 | g_lua.writeFunction("newQPSLimiter", [](int rate, int burst) { return QPSLimiter(rate, burst); }); | |
1511 | g_lua.registerFunction("check", &QPSLimiter::check); | |
1512 | ||
1513 | ||
1514 | g_lua.writeFunction("makeKey", []() { | |
f758857a | 1515 | setLuaNoSideEffect(); |
df111b53 | 1516 | g_outputBuffer="setKey("+newKey()+")\n"; |
1517 | }); | |
1518 | ||
1519 | g_lua.writeFunction("setKey", [](const std::string& key) { | |
6f6b4d69 | 1520 | if(!g_configurationDone && ! g_key.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf |
1521 | return; // but later setKeys() trump the -k value again | |
1522 | } | |
1523 | ||
f758857a | 1524 | setLuaSideEffect(); |
3a23cd0f | 1525 | string newkey; |
1526 | if(B64Decode(key, newkey) < 0) { | |
6f6b4d69 | 1527 | g_outputBuffer=string("Unable to decode ")+key+" as Base64"; |
1528 | errlog("%s", g_outputBuffer); | |
1529 | } | |
3a23cd0f | 1530 | else |
1531 | g_key=newkey; | |
df111b53 | 1532 | }); |
1533 | ||
1534 | ||
107d4911 | 1535 | g_lua.writeFunction("testCrypto", [](boost::optional<string> optTestMsg) |
df111b53 | 1536 | { |
f758857a | 1537 | setLuaNoSideEffect(); |
a8eafc52 | 1538 | #ifdef HAVE_LIBSODIUM |
df111b53 | 1539 | try { |
107d4911 RG |
1540 | string testmsg; |
1541 | ||
1542 | if (optTestMsg) { | |
1543 | testmsg = *optTestMsg; | |
1544 | } | |
1545 | else { | |
1546 | testmsg = "testStringForCryptoTests"; | |
1547 | } | |
1548 | ||
df111b53 | 1549 | SodiumNonce sn, sn2; |
1550 | sn.init(); | |
1551 | sn2=sn; | |
1552 | string encrypted = sodEncryptSym(testmsg, g_key, sn); | |
1553 | string decrypted = sodDecryptSym(encrypted, g_key, sn2); | |
1554 | ||
2e72cc0e | 1555 | sn.increment(); |
1556 | sn2.increment(); | |
1557 | ||
1558 | encrypted = sodEncryptSym(testmsg, g_key, sn); | |
1559 | decrypted = sodDecryptSym(encrypted, g_key, sn2); | |
1560 | ||
df111b53 | 1561 | if(testmsg == decrypted) |
1562 | g_outputBuffer="Everything is ok!\n"; | |
1563 | else | |
1564 | g_outputBuffer="Crypto failed..\n"; | |
1565 | ||
1566 | } | |
1567 | catch(...) { | |
1568 | g_outputBuffer="Crypto failed..\n"; | |
a8eafc52 MK |
1569 | } |
1570 | #else | |
1571 | g_outputBuffer="Crypto not available.\n"; | |
1572 | #endif | |
1573 | }); | |
df111b53 | 1574 | |
3f6d07a4 RG |
1575 | g_lua.writeFunction("setTCPRecvTimeout", [](int timeout) { g_tcpRecvTimeout=timeout; }); |
1576 | ||
1577 | g_lua.writeFunction("setTCPSendTimeout", [](int timeout) { g_tcpSendTimeout=timeout; }); | |
2a817e5a | 1578 | |
e0b5e49d RG |
1579 | g_lua.writeFunction("setUDPTimeout", [](int timeout) { g_udpTimeout=timeout; }); |
1580 | ||
e41f8165 RG |
1581 | g_lua.writeFunction("setMaxUDPOutstanding", [](uint16_t max) { |
1582 | if (!g_configurationDone) { | |
1583 | g_maxOutstanding = max; | |
1584 | } else { | |
1585 | g_outputBuffer="Max UDP outstanding cannot be altered at runtime!\n"; | |
1586 | } | |
1587 | }); | |
1588 | ||
497a6e3a RG |
1589 | /* DNSQuestion bindings */ |
1590 | /* PowerDNS DNSQuestion compat */ | |
1591 | g_lua.registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.local; }, [](DNSQuestion& dq, const ComboAddress newLocal) { (void) newLocal; }); | |
1592 | g_lua.registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName { return *dq.qname; }, [](DNSQuestion& dq, const DNSName newName) { (void) newName; }); | |
1593 | g_lua.registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; }); | |
3b069df2 | 1594 | g_lua.registerMember<uint16_t (DNSQuestion::*)>("qclass", [](const DNSQuestion& dq) -> uint16_t { return dq.qclass; }, [](DNSQuestion& dq, uint16_t newClass) { (void) newClass; }); |
497a6e3a RG |
1595 | g_lua.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.dh->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.dh->rcode = newRCode; }); |
1596 | g_lua.registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.remote; }, [](DNSQuestion& dq, const ComboAddress newRemote) { (void) newRemote; }); | |
1597 | /* DNSDist DNSQuestion */ | |
1598 | g_lua.registerMember("dh", &DNSQuestion::dh); | |
1599 | g_lua.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.len; }, [](DNSQuestion& dq, uint16_t newlen) { dq.len = newlen; }); | |
55baa1f2 | 1600 | g_lua.registerMember<uint8_t (DNSQuestion::*)>("opcode", [](const DNSQuestion& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSQuestion& dq, uint8_t newOpcode) { (void) newOpcode; }); |
497a6e3a RG |
1601 | g_lua.registerMember<size_t (DNSQuestion::*)>("size", [](const DNSQuestion& dq) -> size_t { return dq.size; }, [](DNSQuestion& dq, size_t newSize) { (void) newSize; }); |
1602 | g_lua.registerMember<bool (DNSQuestion::*)>("tcp", [](const DNSQuestion& dq) -> bool { return dq.tcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; }); | |
a14c7f7b | 1603 | g_lua.registerMember<bool (DNSQuestion::*)>("skipCache", [](const DNSQuestion& dq) -> bool { return dq.skipCache; }, [](DNSQuestion& dq, bool newSkipCache) { dq.skipCache = newSkipCache; }); |
ff0902ec RG |
1604 | g_lua.registerMember<bool (DNSQuestion::*)>("useECS", [](const DNSQuestion& dq) -> bool { return dq.useECS; }, [](DNSQuestion& dq, bool useECS) { dq.useECS = useECS; }); |
1605 | g_lua.registerMember<bool (DNSQuestion::*)>("ecsOverride", [](const DNSQuestion& dq) -> bool { return dq.ecsOverride; }, [](DNSQuestion& dq, bool ecsOverride) { dq.ecsOverride = ecsOverride; }); | |
1606 | g_lua.registerMember<uint16_t (DNSQuestion::*)>("ecsPrefixLength", [](const DNSQuestion& dq) -> uint16_t { return dq.ecsPrefixLength; }, [](DNSQuestion& dq, uint16_t newPrefixLength) { dq.ecsPrefixLength = newPrefixLength; }); | |
b82f0bc2 RG |
1607 | g_lua.registerFunction<bool(DNSQuestion::*)()>("getDO", [](const DNSQuestion& dq) { |
1608 | return getEDNSZ((const char*)dq.dh, dq.len) & EDNS_HEADER_FLAG_DO; | |
1609 | }); | |
9f4eb5cc RG |
1610 | g_lua.registerFunction<void(DNSQuestion::*)(std::string)>("sendTrap", [](const DNSQuestion& dq, boost::optional<std::string> reason) { |
1611 | #ifdef HAVE_NET_SNMP | |
1612 | if (g_snmpAgent && g_snmpTrapsEnabled) { | |
1613 | g_snmpAgent->sendDNSTrap(dq, reason ? *reason : ""); | |
1614 | } | |
1615 | #endif /* HAVE_NET_SNMP */ | |
1616 | }); | |
497a6e3a | 1617 | |
6beb5731 RG |
1618 | /* LuaWrapper doesn't support inheritance */ |
1619 | g_lua.registerMember<const ComboAddress (DNSResponse::*)>("localaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.local; }, [](DNSResponse& dq, const ComboAddress newLocal) { (void) newLocal; }); | |
1620 | g_lua.registerMember<const DNSName (DNSResponse::*)>("qname", [](const DNSResponse& dq) -> const DNSName { return *dq.qname; }, [](DNSResponse& dq, const DNSName newName) { (void) newName; }); | |
1621 | g_lua.registerMember<uint16_t (DNSResponse::*)>("qtype", [](const DNSResponse& dq) -> uint16_t { return dq.qtype; }, [](DNSResponse& dq, uint16_t newType) { (void) newType; }); | |
1622 | g_lua.registerMember<uint16_t (DNSResponse::*)>("qclass", [](const DNSResponse& dq) -> uint16_t { return dq.qclass; }, [](DNSResponse& dq, uint16_t newClass) { (void) newClass; }); | |
1623 | g_lua.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return dq.dh->rcode; }, [](DNSResponse& dq, int newRCode) { dq.dh->rcode = newRCode; }); | |
1624 | g_lua.registerMember<const ComboAddress (DNSResponse::*)>("remoteaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.remote; }, [](DNSResponse& dq, const ComboAddress newRemote) { (void) newRemote; }); | |
1625 | g_lua.registerMember("dh", &DNSResponse::dh); | |
1626 | g_lua.registerMember<uint16_t (DNSResponse::*)>("len", [](const DNSResponse& dq) -> uint16_t { return dq.len; }, [](DNSResponse& dq, uint16_t newlen) { dq.len = newlen; }); | |
1627 | g_lua.registerMember<uint8_t (DNSResponse::*)>("opcode", [](const DNSResponse& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSResponse& dq, uint8_t newOpcode) { (void) newOpcode; }); | |
1628 | g_lua.registerMember<size_t (DNSResponse::*)>("size", [](const DNSResponse& dq) -> size_t { return dq.size; }, [](DNSResponse& dq, size_t newSize) { (void) newSize; }); | |
1629 | g_lua.registerMember<bool (DNSResponse::*)>("tcp", [](const DNSResponse& dq) -> bool { return dq.tcp; }, [](DNSResponse& dq, bool newTcp) { (void) newTcp; }); | |
1630 | g_lua.registerMember<bool (DNSResponse::*)>("skipCache", [](const DNSResponse& dq) -> bool { return dq.skipCache; }, [](DNSResponse& dq, bool newSkipCache) { dq.skipCache = newSkipCache; }); | |
153d5065 RG |
1631 | g_lua.registerFunction<void(DNSResponse::*)(std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc)>("editTTLs", [](const DNSResponse& dr, std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc) { |
1632 | editDNSPacketTTL((char*) dr.dh, dr.len, editFunc); | |
1633 | }); | |
9f4eb5cc RG |
1634 | g_lua.registerFunction<void(DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dr, boost::optional<std::string> reason) { |
1635 | #ifdef HAVE_NET_SNMP | |
1636 | if (g_snmpAgent && g_snmpTrapsEnabled) { | |
1637 | g_snmpAgent->sendDNSTrap(dr, reason ? *reason : ""); | |
1638 | } | |
1639 | #endif /* HAVE_NET_SNMP */ | |
1640 | }); | |
6beb5731 | 1641 | |
6c1ca990 RG |
1642 | g_lua.writeFunction("setMaxTCPClientThreads", [](uint64_t max) { |
1643 | if (!g_configurationDone) { | |
1644 | g_maxTCPClientThreads = max; | |
1645 | } else { | |
1646 | g_outputBuffer="Maximum TCP client threads count cannot be altered at runtime!\n"; | |
1647 | } | |
1648 | }); | |
1649 | ||
1650 | g_lua.writeFunction("setMaxTCPQueuedConnections", [](uint64_t max) { | |
1651 | if (!g_configurationDone) { | |
1652 | g_maxTCPQueuedConnections = max; | |
1653 | } else { | |
1654 | g_outputBuffer="The maximum number of queued TCP connections cannot be altered at runtime!\n"; | |
1655 | } | |
1656 | }); | |
e41f8165 | 1657 | |
9396d955 RG |
1658 | g_lua.writeFunction("setMaxTCPQueriesPerConnection", [](size_t max) { |
1659 | if (!g_configurationDone) { | |
1660 | g_maxTCPQueriesPerConn = max; | |
1661 | } else { | |
1662 | g_outputBuffer="The maximum number of queries per TCP connection cannot be altered at runtime!\n"; | |
1663 | } | |
1664 | }); | |
1665 | ||
1666 | g_lua.writeFunction("setMaxTCPConnectionsPerClient", [](size_t max) { | |
1667 | if (!g_configurationDone) { | |
1668 | g_maxTCPConnectionsPerClient = max; | |
1669 | } else { | |
1670 | g_outputBuffer="The maximum number of TCP connection per client cannot be altered at runtime!\n"; | |
1671 | } | |
1672 | }); | |
1673 | ||
1674 | g_lua.writeFunction("setMaxTCPConnectionDuration", [](size_t max) { | |
1675 | if (!g_configurationDone) { | |
1676 | g_maxTCPConnectionDuration = max; | |
1677 | } else { | |
1678 | g_outputBuffer="The maximum duration of a TCP connection cannot be altered at runtime!\n"; | |
1679 | } | |
1680 | }); | |
1681 | ||
e65ae260 RG |
1682 | g_lua.writeFunction("showTCPStats", [] { |
1683 | setLuaNoSideEffect(); | |
1684 | boost::format fmt("%-10d %-10d %-10d %-10d\n"); | |
1685 | g_outputBuffer += (fmt % "Clients" % "MaxClients" % "Queued" % "MaxQueued").str(); | |
ded1985a | 1686 | g_outputBuffer += (fmt % g_tcpclientthreads->getThreadsCount() % g_maxTCPClientThreads % g_tcpclientthreads->getQueuedCount() % g_maxTCPQueuedConnections).str(); |
edbda1ad | 1687 | g_outputBuffer += "Query distribution mode is: " + std::string(g_useTCPSinglePipe ? "single queue" : "per-thread queues") + "\n"; |
e65ae260 RG |
1688 | }); |
1689 | ||
886e2cf2 | 1690 | g_lua.writeFunction("setCacheCleaningDelay", [](uint32_t delay) { g_cacheCleaningDelay = delay; }); |
f65ea0c2 | 1691 | g_lua.writeFunction("setCacheCleaningPercentage", [](uint16_t percentage) { if (percentage < 100) g_cacheCleaningPercentage = percentage; else g_cacheCleaningPercentage = 100; }); |
886e2cf2 | 1692 | |
ca404e94 RG |
1693 | g_lua.writeFunction("setECSSourcePrefixV4", [](uint16_t prefix) { g_ECSSourcePrefixV4=prefix; }); |
1694 | ||
1695 | g_lua.writeFunction("setECSSourcePrefixV6", [](uint16_t prefix) { g_ECSSourcePrefixV6=prefix; }); | |
1696 | ||
1697 | g_lua.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; }); | |
1698 | ||
2a817e5a | 1699 | g_lua.writeFunction("dumpStats", [] { |
f758857a | 1700 | setLuaNoSideEffect(); |
2a817e5a | 1701 | vector<string> leftcolumn, rightcolumn; |
1702 | ||
1703 | boost::format fmt("%-23s\t%+11s"); | |
1704 | g_outputBuffer.clear(); | |
1705 | auto entries = g_stats.entries; | |
1706 | sort(entries.begin(), entries.end(), | |
1707 | [](const decltype(entries)::value_type& a, const decltype(entries)::value_type& b) { | |
1708 | return a.first < b.first; | |
1709 | }); | |
1710 | boost::format flt(" %9.1f"); | |
1711 | for(const auto& e : entries) { | |
1712 | string second; | |
1713 | if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second)) | |
1714 | second=std::to_string((*val)->load()); | |
af619119 RG |
1715 | else if (const auto& dval = boost::get<double*>(&e.second)) |
1716 | second=(flt % (**dval)).str(); | |
2a817e5a | 1717 | else |
1718 | second=std::to_string((*boost::get<DNSDistStats::statfunction_t>(&e.second))(e.first)); | |
1719 | ||
1720 | if(leftcolumn.size() < g_stats.entries.size()/2) | |
1721 | leftcolumn.push_back((fmt % e.first % second).str()); | |
1722 | else | |
1723 | rightcolumn.push_back((fmt % e.first % second).str()); | |
1724 | } | |
1725 | ||
1726 | auto leftiter=leftcolumn.begin(), rightiter=rightcolumn.begin(); | |
1727 | boost::format clmn("%|0t|%1% %|39t|%2%\n"); | |
1728 | ||
1729 | for(;leftiter != leftcolumn.end() || rightiter != rightcolumn.end();) { | |
1730 | string lentry, rentry; | |
1731 | if(leftiter!= leftcolumn.end()) { | |
1732 | lentry = *leftiter; | |
1733 | leftiter++; | |
1734 | } | |
1735 | if(rightiter!= rightcolumn.end()) { | |
1736 | rentry = *rightiter; | |
1737 | rightiter++; | |
1738 | } | |
1739 | g_outputBuffer += (clmn % lentry % rentry).str(); | |
1740 | } | |
1741 | }); | |
80a216c9 | 1742 | |
886e2cf2 | 1743 | moreLua(client); |
df111b53 | 1744 | |
839f3021 | 1745 | std::ifstream ifs(config); |
2e72cc0e | 1746 | if(!ifs) |
839f3021 | 1747 | warnlog("Unable to read configuration from '%s'", config); |
2e72cc0e | 1748 | else |
cdc04ede | 1749 | vinfolog("Read configuration from '%s'", config); |
df111b53 | 1750 | |
1751 | g_lua.executeCode(ifs); | |
d8c19b98 | 1752 | |
2e72cc0e | 1753 | auto ret=*g_launchWork; |
1754 | delete g_launchWork; | |
1755 | g_launchWork=0; | |
1756 | return ret; | |
df111b53 | 1757 | } |