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