]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist-lua.cc
add DNSSEC selection rule, plus setDNSSECPool() command
[thirdparty/pdns.git] / pdns / dnsdist-lua.cc
CommitLineData
df111b53 1#include "dnsdist.hh"
0940e4eb 2#include "dnsrulactions.hh"
df111b53 3#include <thread>
4#include "dolog.hh"
5#include "sodcrypto.hh"
6#include "base64.hh"
7#include <fstream>
8
9using std::thread;
10
2e72cc0e 11static vector<std::function<void(void)>>* g_launchWork;
12
13vector<std::function<void(void)>> setupLua(bool client)
df111b53 14{
2e72cc0e 15 g_launchWork= new vector<std::function<void(void)>>();
df111b53 16 g_lua.writeFunction("newServer",
2e72cc0e 17 [client](boost::variant<string,std::unordered_map<std::string, std::string>> pvars, boost::optional<int> qps)
df111b53 18 {
2e72cc0e 19 if(client) {
20 return shared_ptr<DownstreamState>();
21 }
df111b53 22 if(auto address = boost::get<string>(&pvars)) {
23 auto ret=std::make_shared<DownstreamState>(ComboAddress(*address, 53));
2e72cc0e 24
df111b53 25 if(qps) {
26 ret->qps=QPSLimiter(*qps, *qps);
27 }
ecbe9133 28 g_dstates.modify([ret](servers_t& servers) {
29 servers.push_back(ret);
30 std::stable_sort(servers.begin(), servers.end(), [](const decltype(ret)& a, const decltype(ret)& b) {
31 return a->order < b->order;
32 });
33
34 });
2e72cc0e 35
36 if(g_launchWork) {
37 g_launchWork->push_back([ret]() {
38 ret->tid = move(thread(responderThread, ret));
39 });
40 }
41 else {
42 ret->tid = move(thread(responderThread, ret));
43 }
44
df111b53 45 return ret;
46 }
47 auto vars=boost::get<std::unordered_map<std::string, std::string>>(pvars);
48 auto ret=std::make_shared<DownstreamState>(ComboAddress(vars["address"], 53));
2e72cc0e 49
df111b53 50 if(vars.count("qps")) {
51 ret->qps=QPSLimiter(boost::lexical_cast<int>(vars["qps"]),boost::lexical_cast<int>(vars["qps"]));
52 }
53
54 if(vars.count("pool")) {
55 ret->pools.insert(vars["pool"]);
56 }
57
58 if(vars.count("order")) {
59 ret->order=boost::lexical_cast<int>(vars["order"]);
60 }
61
62 if(vars.count("weight")) {
63 ret->weight=boost::lexical_cast<int>(vars["weight"]);
64 }
65
2e72cc0e 66 if(g_launchWork) {
67 g_launchWork->push_back([ret]() {
68 ret->tid = move(thread(responderThread, ret));
69 });
70 }
71 else {
72 ret->tid = move(thread(responderThread, ret));
73 }
df111b53 74
ecbe9133 75 auto states = g_dstates.getCopy();
e5a14b2b 76 states.push_back(ret);
77 std::stable_sort(states.begin(), states.end(), [](const decltype(ret)& a, const decltype(ret)& b) {
df111b53 78 return a->order < b->order;
79 });
ecbe9133 80 g_dstates.setState(states);
df111b53 81 return ret;
82 } );
83
0940e4eb 84 g_lua.writeFunction("addAnyTCRule", []() {
85 auto rules=g_rulactions.getCopy();
86 rules.push_back({ std::make_shared<QTypeRule>(0xff), std::make_shared<TCAction>()});
87 g_rulactions.setState(rules);
88 });
df111b53 89
0940e4eb 90 g_lua.writeFunction("rmRule", [](unsigned int num) {
91 auto rules = g_rulactions.getCopy();
92 if(num >= rules.size()) {
93 g_outputBuffer = "Error: attempt to delete non-existing rule\n";
94 return;
95 }
96 rules.erase(rules.begin()+num);
97 g_rulactions.setState(rules);
98 });
99
100 g_lua.writeFunction("mvRule", [](unsigned int from, unsigned int to) {
101 auto rules = g_rulactions.getCopy();
102 if(from >= rules.size() || to > rules.size()) {
103 g_outputBuffer = "Error: attempt to move rules from/to invalid index\n";
104 return;
105 }
0940e4eb 106
107 auto subject = rules[from];
108 rules.erase(rules.begin()+from);
109 if(to == rules.size())
110 rules.push_back(subject);
111 else {
112 if(from < to)
113 --to;
114 rules.insert(rules.begin()+to, subject);
115 }
116 g_rulactions.setState(rules);
117 });
df111b53 118
119
120 g_lua.writeFunction("rmServer",
121 [](boost::variant<std::shared_ptr<DownstreamState>, int> var)
122 {
ecbe9133 123 auto states = g_dstates.getCopy();
df111b53 124 if(auto* rem = boost::get<shared_ptr<DownstreamState>>(&var))
e5a14b2b 125 states.erase(remove(states.begin(), states.end(), *rem), states.end());
df111b53 126 else
e5a14b2b 127 states.erase(states.begin() + boost::get<int>(var));
ecbe9133 128 g_dstates.setState(states);
df111b53 129 } );
130
131
132 g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) {
e5a14b2b 133 g_policy.setState(policy);
df111b53 134 });
df111b53 135 g_lua.writeFunction("setServerPolicyLua", [](string name, policy_t policy) {
e5a14b2b 136 g_policy.setState(ServerPolicy{name, policy});
df111b53 137 });
138
139 g_lua.writeFunction("showServerPolicy", []() {
ecbe9133 140 g_outputBuffer=g_policy.getLocal()->name+"\n";
df111b53 141 });
142
143
144 g_lua.registerMember("name", &ServerPolicy::name);
145 g_lua.registerMember("policy", &ServerPolicy::policy);
146 g_lua.writeFunction("newServerPolicy", [](string name, policy_t policy) { return ServerPolicy{name, policy};});
147 g_lua.writeVariable("firstAvailable", ServerPolicy{"firstAvailable", firstAvailable});
148 g_lua.writeVariable("roundrobin", ServerPolicy{"roundrobin", roundrobin});
149 g_lua.writeVariable("wrandom", ServerPolicy{"wrandom", wrandom});
150 g_lua.writeVariable("leastOutstanding", ServerPolicy{"leastOutstanding", leastOutstanding});
151 g_lua.writeFunction("addACL", [](const std::string& domain) {
e5a14b2b 152 g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); });
df111b53 153 });
2e72cc0e 154
155 g_lua.writeFunction("addLocal", [client](const std::string& addr) {
156 if(client)
157 return;
158 try {
159 ComboAddress loc(addr, 53);
ecbe9133 160 g_locals.push_back(loc); /// only works pre-startup, so no sync necessary
2e72cc0e 161 }
162 catch(std::exception& e) {
163 g_outputBuffer="Error: "+string(e.what())+"\n";
164 }
165 });
df111b53 166 g_lua.writeFunction("setACL", [](const vector<pair<int, string>>& parts) {
e5a14b2b 167 NetmaskGroup nmg;
cffde2fd 168 for(const auto& p : parts) {
e5a14b2b 169 nmg.addMask(p.second);
cffde2fd 170 }
171 g_ACL.setState(nmg);
df111b53 172 });
173 g_lua.writeFunction("showACL", []() {
174 vector<string> vec;
cffde2fd 175
e5a14b2b 176 g_ACL.getCopy().toStringVector(&vec);
cffde2fd 177
df111b53 178 for(const auto& s : vec)
cffde2fd 179 g_outputBuffer+=s+"\n";
180
df111b53 181 });
182 g_lua.writeFunction("shutdown", []() { _exit(0);} );
183
184
ecbe9133 185 g_lua.writeFunction("addDomainBlock", [](const std::string& domain) {
0940e4eb 186 SuffixMatchNode smn;
187 smn.add(domain);
188 g_rulactions.modify([smn](decltype(g_rulactions)::value_type& rulactions) {
189 rulactions.push_back({
190 std::make_shared<SuffixMatchNodeRule>(smn),
191 std::make_shared<DropAction>() });
192 });
193
ecbe9133 194 });
df111b53 195 g_lua.writeFunction("showServers", []() {
196 try {
197 ostringstream ret;
198
199 boost::format fmt("%1$-3d %2% %|30t|%3$5s %|36t|%4$7.1f %|41t|%5$7d %|44t|%6$3d %|53t|%7$2d %|55t|%8$10d %|61t|%9$7d %|76t|%10$5.1f %|84t|%11$5.1f %12%" );
200 // 1 2 3 4 5 6 7 8 9 10 11
201 ret << (fmt % "#" % "Address" % "State" % "Qps" % "Qlim" % "Ord" % "Wt" % "Queries" % "Drops" % "Drate" % "Lat" % "Pools") << endl;
202
203 uint64_t totQPS{0}, totQueries{0}, totDrops{0};
204 int counter=0;
ecbe9133 205 auto states = g_dstates.getCopy();
e5a14b2b 206 for(const auto& s : states) {
df111b53 207 string status;
208 if(s->availability == DownstreamState::Availability::Up)
209 status = "UP";
210 else if(s->availability == DownstreamState::Availability::Down)
211 status = "DOWN";
212 else
213 status = (s->upStatus ? "up" : "down");
214
215 string pools;
216 for(auto& p : s->pools) {
217 if(!pools.empty())
218 pools+=" ";
219 pools+=p;
220 }
221
222 ret << (fmt % counter % s->remote.toStringWithPort() %
223 status %
224 s->queryLoad % s->qps.getRate() % s->order % s->weight % s->queries.load() % s->reuseds.load() % (s->dropRate) % (s->latencyUsec/1000.0) % pools) << endl;
225
226 totQPS += s->queryLoad;
227 totQueries += s->queries.load();
228 totDrops += s->reuseds.load();
229 ++counter;
230 }
231 ret<< (fmt % "All" % "" % ""
232 %
233 (double)totQPS % "" % "" % "" % totQueries % totDrops % "" % "" % "" ) << endl;
234
235 g_outputBuffer=ret.str();
236 }catch(std::exception& e) { g_outputBuffer=e.what(); throw; }
237 });
238
239 g_lua.writeFunction("addPoolRule", [](boost::variant<string,vector<pair<int, string>> > var, string pool) {
240 SuffixMatchNode smn;
241 NetmaskGroup nmg;
242
243 auto add=[&](string src) {
244 try {
245 smn.add(DNSName(src));
246 } catch(...) {
247 nmg.addMask(src);
248 }
249 };
250 if(auto src = boost::get<string>(&var))
251 add(*src);
252 else {
253 for(auto& a : boost::get<vector<pair<int, string>>>(var)) {
254 add(a.second);
255 }
256 }
257 if(nmg.empty())
0940e4eb 258 g_rulactions.modify([smn, pool](decltype(g_rulactions)::value_type& rulactions) {
259 rulactions.push_back({
260 std::make_shared<SuffixMatchNodeRule>(smn),
261 std::make_shared<PoolAction>(pool) });
ecbe9133 262 });
df111b53 263 else
0940e4eb 264 g_rulactions.modify([nmg,pool](decltype(g_rulactions)::value_type& rulactions) {
265 rulactions.push_back({std::make_shared<NetmaskGroupRule>(nmg),
266 std::make_shared<PoolAction>(pool)});
ecbe9133 267 });
df111b53 268
269 });
270
520eb5a0 271 g_lua.writeFunction("setDNSSECPool", [](const std::string& pool) {
272 g_rulactions.modify([pool](decltype(g_rulactions)::value_type& rulactions) {
273 rulactions.push_back({std::make_shared<DNSSECRule>(),
274 std::make_shared<PoolAction>(pool)});
275 });
276 });
df111b53 277
278 g_lua.writeFunction("addQPSLimit", [](boost::variant<string,vector<pair<int, string>> > var, int lim) {
279 SuffixMatchNode smn;
280 NetmaskGroup nmg;
281
282 auto add=[&](string src) {
283 try {
284 smn.add(DNSName(src));
285 } catch(...) {
286 nmg.addMask(src);
287 }
288 };
289 if(auto src = boost::get<string>(&var))
290 add(*src);
291 else {
292 for(auto& a : boost::get<vector<pair<int, string>>>(var)) {
293 add(a.second);
294 }
295 }
296 if(nmg.empty())
0940e4eb 297 g_rulactions.modify([smn, lim](decltype(g_rulactions)::value_type& rulactions) {
298 rulactions.push_back({std::make_shared<SuffixMatchNodeRule>(smn),
299 std::make_shared<QPSAction>(lim)});
ecbe9133 300 });
df111b53 301 else
0940e4eb 302 g_rulactions.modify([nmg, lim](decltype(g_rulactions)::value_type& rulactions) {
303 rulactions.push_back({std::make_shared<NetmaskGroupRule>(nmg),
304 std::make_shared<QPSAction>(lim)});
ecbe9133 305 });
df111b53 306 });
307
df111b53 308
0940e4eb 309 g_lua.writeFunction("showRules", []() {
310 boost::format fmt("%-3d %9d %-50s %s\n");
311 g_outputBuffer += (fmt % "#" % "Matches" % "Rule" % "Action").str();
312 int num=0;
313 for(const auto& lim : g_rulactions.getCopy()) {
314 string name = lim.first->toString();
315 g_outputBuffer += (fmt % num % lim.first->d_matches % name % lim.second->toString()).str();
df111b53 316 ++num;
317 }
318 });
319
df111b53 320 g_lua.writeFunction("getServers", []() {
321 vector<pair<int, std::shared_ptr<DownstreamState> > > ret;
322 int count=1;
e5a14b2b 323 for(const auto& s : g_dstates.getCopy()) {
df111b53 324 ret.push_back(make_pair(count++, s));
325 }
326 return ret;
327 });
328
da4e7813 329 g_lua.writeFunction("getPoolServers", [](string pool) {
330 return getDownstreamCandidates(g_dstates.getCopy(), pool);
331 });
332
e5a14b2b 333 g_lua.writeFunction("getServer", [](int i) { return g_dstates.getCopy().at(i); });
df111b53 334
df111b53 335 g_lua.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& s, int lim) { s.qps = lim ? QPSLimiter(lim, lim) : QPSLimiter(); });
336 g_lua.registerFunction<void(DownstreamState::*)(string)>("addPool", [](DownstreamState& s, string pool) { s.pools.insert(pool);});
337 g_lua.registerFunction<void(DownstreamState::*)(string)>("rmPool", [](DownstreamState& s, string pool) { s.pools.erase(pool);});
338
339 g_lua.registerFunction<void(DownstreamState::*)()>("getOutstanding", [](const DownstreamState& s) { g_outputBuffer=std::to_string(s.outstanding.load()); });
340
341
342 g_lua.registerFunction("isUp", &DownstreamState::isUp);
343 g_lua.registerFunction("setDown", &DownstreamState::setDown);
344 g_lua.registerFunction("setUp", &DownstreamState::setUp);
345 g_lua.registerFunction("setAuto", &DownstreamState::setAuto);
b0976f44 346 g_lua.registerMember("upStatus", &DownstreamState::upStatus);
df111b53 347 g_lua.registerMember("weight", &DownstreamState::weight);
348 g_lua.registerMember("order", &DownstreamState::order);
349
4c6f4321 350 g_lua.writeFunction("infolog", [](const string& arg) {
351 infolog("%s", arg);
352 });
353 g_lua.writeFunction("errlog", [](const string& arg) {
354 errlog("%s", arg);
355 });
356 g_lua.writeFunction("warnlog", [](const string& arg) {
357 warnlog("%s", arg);
358 });
359
360
df111b53 361 g_lua.writeFunction("show", [](const string& arg) {
362 g_outputBuffer+=arg;
363 g_outputBuffer+="\n";
364 });
365
366 g_lua.registerFunction<void(dnsheader::*)(bool)>("setRD", [](dnsheader& dh, bool v) {
367 dh.rd=v;
368 });
369
370 g_lua.registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) {
371 return (bool)dh.rd;
372 });
373
374
375 g_lua.registerFunction<void(dnsheader::*)(bool)>("setTC", [](dnsheader& dh, bool v) {
376 dh.tc=v;
377 });
378
379 g_lua.registerFunction<void(dnsheader::*)(bool)>("setQR", [](dnsheader& dh, bool v) {
380 dh.qr=v;
381 });
382
df111b53 383
384 g_lua.registerFunction("tostring", &ComboAddress::toString);
385
386 g_lua.registerFunction("isPartOf", &DNSName::isPartOf);
387 g_lua.registerFunction("tostring", &DNSName::toString);
388 g_lua.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); });
b0976f44 389 g_lua.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); });
df111b53 390
391 g_lua.registerFunction("add",(void (SuffixMatchNode::*)(const DNSName&)) &SuffixMatchNode::add);
392 g_lua.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
393
394 g_lua.writeFunction("controlSocket", [client](const std::string& str) {
395 ComboAddress local(str, 5199);
396
397 if(client) {
398 g_serverControl = local;
399 return;
400 }
401
402 try {
403 int sock = socket(local.sin4.sin_family, SOCK_STREAM, 0);
404 SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
405 SBind(sock, local);
406 SListen(sock, 5);
2e72cc0e 407 auto launch=[sock, local]() {
408 thread t(controlThread, sock, local);
409 t.detach();
410 };
411 if(g_launchWork)
412 g_launchWork->push_back(launch);
413 else
414 launch();
415
df111b53 416 }
417 catch(std::exception& e) {
418 errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), e.what());
419 }
420 });
421
0e5b3cff 422 // something needs to be done about this, unlocked will 'mostly' work
423 g_lua.writeFunction("topClients", [](unsigned int top) {
424 map<ComboAddress, int,ComboAddress::addressOnlyLessThan > counts;
425 unsigned int total=0;
426 for(const auto& c : g_rings.clientRing) {
427 counts[c]++;
428 total++;
429 }
430 vector<pair<int, ComboAddress>> rcounts;
431 for(const auto& c : counts)
432 rcounts.push_back(make_pair(c.second, c.first));
433
434 sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a,
435 const decltype(rcounts)::value_type& b) {
436 return b.first < a.first;
437 });
438 unsigned int count=1, rest=0;
439 boost::format fmt("%4d %-40s %4d %4.1f%%\n");
440 for(const auto& rc : rcounts) {
441 if(count==top+1)
442 rest+=rc.first;
443 else
444 g_outputBuffer += (fmt % (count++) % rc.second.toString() % rc.first % (100.0*rc.first/total)).str();
445 }
446 g_outputBuffer += (fmt % (count) % "Rest" % rest % (100.0*rest/total)).str();
447 });
448
ecbe9133 449
450 // something needs to be done about this, unlocked will 'mostly' work
df111b53 451 g_lua.writeFunction("getTopQueries", [](unsigned int top, boost::optional<int> labels) {
452 map<DNSName, int> counts;
453 unsigned int total=0;
454 if(!labels) {
455 for(const auto& a : g_rings.queryRing) {
456 counts[a]++;
457 total++;
458 }
459 }
460 else {
461 unsigned int lab = *labels;
462 for(auto a : g_rings.queryRing) {
463 a.trimToLabels(lab);
464 counts[a]++;
465 total++;
466 }
467
468 }
cffde2fd 469 // cout<<"Looked at "<<total<<" queries, "<<counts.size()<<" different ones"<<endl;
df111b53 470 vector<pair<int, DNSName>> rcounts;
471 for(const auto& c : counts)
472 rcounts.push_back(make_pair(c.second, c.first));
473
474 sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a,
475 const decltype(rcounts)::value_type& b) {
476 return b.first < a.first;
477 });
478
479 std::unordered_map<int, vector<boost::variant<string,double>>> ret;
480 unsigned int count=1, rest=0;
481 for(const auto& rc : rcounts) {
482 if(count==top+1)
483 rest+=rc.first;
484 else
485 ret.insert({count++, {rc.second.toString(), rc.first, 100.0*rc.first/total}});
486 }
487 ret.insert({count, {"Rest", rest, 100.0*rest/total}});
488 return ret;
489
490 });
491
492 g_lua.executeCode(R"(function topQueries(top, labels) 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)");
493
520eb5a0 494
495 g_lua.writeFunction("getResponseRing", []() {
496 decltype(g_rings.respRing) ring;
497 {
498 std::lock_guard<std::mutex> lock(g_rings.respMutex);
499 ring = g_rings.respRing;
500 }
501 vector<std::unordered_map<string, boost::variant<string, unsigned int> > > ret;
502 ret.reserve(ring.size());
503 decltype(ret)::value_type item;
504 for(const auto& r : ring) {
505 item["name"]=r.name.toString();
506 item["qtype"]=r.qtype;
507 item["rcode"]=r.rcode;
508 item["usec"]=r.usec;
509 ret.push_back(item);
510 }
511 return ret;
512 });
513
df111b53 514 g_lua.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional<int> labels) {
515 map<DNSName, int> counts;
516 unsigned int total=0;
517 {
518 std::lock_guard<std::mutex> lock(g_rings.respMutex);
519 if(!labels) {
520 for(const auto& a : g_rings.respRing) {
521 if(a.rcode!=kind)
522 continue;
523 counts[a.name]++;
524 total++;
525 }
526 }
527 else {
528 unsigned int lab = *labels;
529 for(auto a : g_rings.respRing) {
530 if(a.rcode!=kind)
531 continue;
532
533 a.name.trimToLabels(lab);
534 counts[a.name]++;
535 total++;
536 }
537
538 }
539 }
540 // cout<<"Looked at "<<total<<" responses, "<<counts.size()<<" different ones"<<endl;
541 vector<pair<int, DNSName>> rcounts;
542 for(const auto& c : counts)
543 rcounts.push_back(make_pair(c.second, c.first));
544
545 sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a,
546 const decltype(rcounts)::value_type& b) {
547 return b.first < a.first;
548 });
549
550 std::unordered_map<int, vector<boost::variant<string,double>>> ret;
551 unsigned int count=1, rest=0;
552 for(const auto& rc : rcounts) {
553 if(count==top+1)
554 rest+=rc.first;
555 else
556 ret.insert({count++, {rc.second.toString(), rc.first, 100.0*rc.first/total}});
557 }
558 ret.insert({count, {"Rest", rest, 100.0*rest/total}});
559 return ret;
560
561 });
562
563 g_lua.executeCode(R"(function topResponses(top, kind, labels) 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)");
564
565
566 g_lua.writeFunction("showResponseLatency", []() {
567
568 map<double, unsigned int> histo;
569 double bin=100;
570 for(int i=0; i < 15; ++i) {
571 histo[bin];
572 bin*=2;
573 }
574
575 double totlat=0;
576 int size=0;
577 {
578 std::lock_guard<std::mutex> lock(g_rings.respMutex);
579 for(const auto& r : g_rings.respRing) {
580 ++size;
581 auto iter = histo.lower_bound(r.usec);
582 if(iter != histo.end())
583 iter->second++;
584 else
585 histo.rbegin()++;
586 totlat+=r.usec;
587 }
588 }
589
590 g_outputBuffer = (boost::format("Average response latency: %.02f msec\n") % (0.001*totlat/size)).str();
591 double highest=0;
592
593 for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) {
594 highest=std::max(highest, iter->second*1.0);
595 }
596 boost::format fmt("%7.2f\t%s\n");
597 g_outputBuffer += (fmt % "msec" % "").str();
598
599 for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) {
600 int stars = (70.0 * iter->second/highest);
601 char c='*';
602 if(!stars && iter->second) {
603 stars=1; // you get 1 . to show something is there..
604 if(70.0*iter->second/highest > 0.5)
605 c=':';
606 else
607 c='.';
608 }
609 g_outputBuffer += (fmt % (iter->first/1000.0) % string(stars, c)).str();
610 }
611 });
612
613 g_lua.writeFunction("newQPSLimiter", [](int rate, int burst) { return QPSLimiter(rate, burst); });
614 g_lua.registerFunction("check", &QPSLimiter::check);
615
616
617 g_lua.writeFunction("makeKey", []() {
618 g_outputBuffer="setKey("+newKey()+")\n";
619 });
620
621 g_lua.writeFunction("setKey", [](const std::string& key) {
845a82c4 622 if(B64Decode(key, g_key) < 0) {
623 g_outputBuffer=string("Unable to decode ")+key+" as Base64";
624 errlog("%s", g_outputBuffer);
625 }
df111b53 626 });
627
628
629 g_lua.writeFunction("testCrypto", [](string testmsg)
630 {
631 try {
632 SodiumNonce sn, sn2;
633 sn.init();
634 sn2=sn;
635 string encrypted = sodEncryptSym(testmsg, g_key, sn);
636 string decrypted = sodDecryptSym(encrypted, g_key, sn2);
637
2e72cc0e 638 sn.increment();
639 sn2.increment();
640
641 encrypted = sodEncryptSym(testmsg, g_key, sn);
642 decrypted = sodDecryptSym(encrypted, g_key, sn2);
643
df111b53 644 if(testmsg == decrypted)
645 g_outputBuffer="Everything is ok!\n";
646 else
647 g_outputBuffer="Crypto failed..\n";
648
649 }
650 catch(...) {
651 g_outputBuffer="Crypto failed..\n";
652 }});
653
654
2e72cc0e 655 std::ifstream ifs(g_vm["config"].as<string>());
656 if(!ifs)
657 warnlog("Unable to read configuration from '%s'", g_vm["config"].as<string>());
658 else
659 infolog("Read configuration from '%s'", g_vm["config"].as<string>());
df111b53 660
661 g_lua.executeCode(ifs);
2e72cc0e 662 auto ret=*g_launchWork;
663 delete g_launchWork;
664 g_launchWork=0;
665 return ret;
df111b53 666}