]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist-lua.cc
dnsdist: Add HTTPStatusAction to return a specific HTTP response
[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 */
6bb38cd6
RG
22
23#include <dirent.h>
24#include <fstream>
aff9ca62
PD
25
26// for OpenBSD, sys/socket.h needs to come before net/if.h
27#include <sys/socket.h>
6bb38cd6 28#include <net/if.h>
aff9ca62 29
9ef9b494 30#include <sys/types.h>
6bb38cd6 31#include <sys/stat.h>
df111b53 32#include <thread>
6bb38cd6
RG
33
34#include "dnsdist.hh"
b5521206 35#include "dnsdist-console.hh"
e7c732b8 36#include "dnsdist-ecs.hh"
6bb38cd6 37#include "dnsdist-lua.hh"
03b00917 38#include "dnsdist-rings.hh"
5d4e1ef8 39#include "dnsdist-secpoll.hh"
6bb38cd6 40
df111b53 41#include "base64.hh"
b7860997 42#include "dnswriter.hh"
6bb38cd6 43#include "dolog.hh"
0e41337b 44#include "lock.hh"
a227f47d 45#include "protobuf.hh"
6bb38cd6
RG
46#include "sodcrypto.hh"
47
48#include <boost/logic/tribool.hpp>
1720247e 49#include <boost/lexical_cast.hpp>
df111b53 50
6ab65223
PL
51#ifdef HAVE_SYSTEMD
52#include <systemd/sd-daemon.h>
53#endif
54
df111b53 55using std::thread;
56
6bb38cd6 57static vector<std::function<void(void)>>* g_launchWork = nullptr;
2e72cc0e 58
6bb38cd6
RG
59boost::tribool g_noLuaSideEffect;
60static bool g_included{false};
d8d85a30 61
6bb38cd6
RG
62/* this is a best effort way to prevent logging calls with no side-effects in the output of delta()
63 Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing
64 has done so before on this invocation, this call won't be part of delta() output */
65void setLuaNoSideEffect()
153d5065 66{
6bb38cd6
RG
67 if(g_noLuaSideEffect==false) // there has been a side effect already
68 return;
69 g_noLuaSideEffect=true;
70}
153d5065 71
6bb38cd6 72void setLuaSideEffect()
d8d85a30 73{
6bb38cd6
RG
74 g_noLuaSideEffect=false;
75}
f850b032 76
6bb38cd6
RG
77bool getLuaNoSideEffect()
78{
d7a26377
RG
79 if (g_noLuaSideEffect) {
80 return true;
81 }
82 return false;
d8d85a30 83}
84
6bb38cd6 85void resetLuaSideEffect()
2d11d1b2 86{
6bb38cd6 87 g_noLuaSideEffect = boost::logic::indeterminate;
2d11d1b2 88}
89
ee01507f 90typedef std::unordered_map<std::string, boost::variant<bool, int, std::string, std::vector<std::pair<int,int> >, std::map<std::string,std::string> > > localbind_t;
6bb38cd6 91
0230e350 92static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus)
efd35aa8
RG
93{
94 if (vars) {
efd35aa8
RG
95 if (vars->count("reusePort")) {
96 reusePort = boost::get<bool>((*vars)["reusePort"]);
97 }
98 if (vars->count("tcpFastOpenQueueSize")) {
99 tcpFastOpenQueueSize = boost::get<int>((*vars)["tcpFastOpenQueueSize"]);
100 }
101 if (vars->count("interface")) {
102 interface = boost::get<std::string>((*vars)["interface"]);
103 }
f0e4dcba
RG
104 if (vars->count("cpus")) {
105 for (const auto cpu : boost::get<std::vector<std::pair<int,int>>>((*vars)["cpus"])) {
106 cpus.insert(cpu.second);
107 }
108 }
efd35aa8
RG
109 }
110}
111
39006144 112#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
bf8cd40d 113static bool loadTLSCertificateAndKeys(const std::string& context, std::vector<std::pair<std::string, std::string>>& pairs, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)
8ef43a02
RG
114{
115 if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
116 auto certFile = boost::get<std::string>(certFiles);
117 auto keyFile = boost::get<std::string>(keyFiles);
bf8cd40d
RG
118 pairs.clear();
119 pairs.push_back({certFile, keyFile});
8ef43a02
RG
120 }
121 else if (certFiles.type() == typeid(std::vector<std::pair<int,std::string>>) && keyFiles.type() == typeid(std::vector<std::pair<int,std::string>>))
122 {
123 auto certFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(certFiles);
124 auto keyFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(keyFiles);
125 if (certFilesVect.size() == keyFilesVect.size()) {
bf8cd40d 126 pairs.clear();
8ef43a02 127 for (size_t idx = 0; idx < certFilesVect.size(); idx++) {
bf8cd40d 128 pairs.push_back({certFilesVect.at(idx).second, keyFilesVect.at(idx).second});
8ef43a02
RG
129 }
130 }
131 else {
bf8cd40d
RG
132 errlog("Error, mismatching number of certificates and keys in call to %s()!", context);
133 g_outputBuffer="Error, mismatching number of certificates and keys in call to " + context + "()!";
8ef43a02
RG
134 return false;
135 }
136 }
137 else {
bf8cd40d
RG
138 errlog("Error, mismatching number of certificates and keys in call to %s()!", context);
139 g_outputBuffer="Error, mismatching number of certificates and keys in call to " + context + "()!";
8ef43a02
RG
140 return false;
141 }
142
143 return true;
144}
39006144 145#endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
8ef43a02 146
6bb38cd6 147void setupLuaConfig(bool client)
df111b53 148{
98650fde 149 typedef std::unordered_map<std::string, boost::variant<bool, std::string, vector<pair<int, std::string> >, DownstreamState::checkfunc_t > > newserver_t;
6f2a4580 150 g_lua.writeFunction("inClientStartup", [client]() {
541dd48f 151 return client && !g_configurationDone;
6f2a4580
PD
152 });
153
6bb38cd6 154 g_lua.writeFunction("newServer",
a5526b57
CH
155 [client](boost::variant<string,newserver_t> pvars, boost::optional<int> qps) {
156 setLuaSideEffect();
157
158 std::shared_ptr<DownstreamState> ret = std::make_shared<DownstreamState>(ComboAddress());
159 newserver_t vars;
160
161 ComboAddress serverAddr;
162 std::string serverAddressStr;
163 if(auto addrStr = boost::get<string>(&pvars)) {
164 serverAddressStr = *addrStr;
165 if(qps) {
166 vars["qps"] = std::to_string(*qps);
167 }
168 } else {
169 vars = boost::get<newserver_t>(pvars);
170 serverAddressStr = boost::get<string>(vars["address"]);
171 }
2e72cc0e 172
a5526b57
CH
173 try {
174 serverAddr = ComboAddress(serverAddressStr, 53);
175 }
176 catch(const PDNSException& e) {
177 g_outputBuffer="Error creating new server: "+string(e.reason);
178 errlog("Error creating new server with address %s: %s", serverAddressStr, e.reason);
179 return ret;
180 }
181 catch(std::exception& e) {
182 g_outputBuffer="Error creating new server: "+string(e.what());
183 errlog("Error creating new server with address %s: %s", serverAddressStr, e.what());
184 return ret;
185 }
2e72cc0e 186
a5526b57
CH
187 if(IsAnyAddress(serverAddr)) {
188 g_outputBuffer="Error creating new server: invalid address for a downstream server.";
189 errlog("Error creating new server: %s is not a valid address for a downstream server", serverAddressStr);
190 return ret;
191 }
192
193 ComboAddress sourceAddr;
194 unsigned int sourceItf = 0;
195 size_t numberOfSockets = 1;
196 std::set<int> cpus;
fbe2a2e0
RG
197
198 if(vars.count("source")) {
199 /* handle source in the following forms:
200 - v4 address ("192.0.2.1")
201 - v6 address ("2001:DB8::1")
202 - interface name ("eth0")
203 - v4 address and interface name ("192.0.2.1@eth0")
204 - v6 address and interface name ("2001:DB8::1@eth0")
205 */
206 const string source = boost::get<string>(vars["source"]);
207 bool parsed = false;
208 std::string::size_type pos = source.find("@");
209 if (pos == std::string::npos) {
210 /* no '@', try to parse that as a valid v4/v6 address */
211 try {
212 sourceAddr = ComboAddress(source);
213 parsed = true;
214 }
215 catch(...)
216 {
217 }
218 }
219
220 if (parsed == false)
221 {
222 /* try to parse as interface name, or v4/v6@itf */
223 string itfName = source.substr(pos == std::string::npos ? 0 : pos + 1);
224 unsigned int itfIdx = if_nametoindex(itfName.c_str());
225
226 if (itfIdx != 0) {
227 if (pos == 0 || pos == std::string::npos) {
228 /* "eth0" or "@eth0" */
229 sourceItf = itfIdx;
230 }
231 else {
232 /* "192.0.2.1@eth0" */
233 sourceAddr = ComboAddress(source.substr(0, pos));
234 sourceItf = itfIdx;
235 }
236 }
237 else
238 {
239 warnlog("Dismissing source %s because '%s' is not a valid interface name", source, itfName);
240 }
241 }
242 }
243
e998def2
RG
244 if (vars.count("sockets")) {
245 numberOfSockets = std::stoul(boost::get<string>(vars["sockets"]));
246 if (numberOfSockets == 0) {
247 warnlog("Dismissing invalid number of sockets '%s', using 1 instead", boost::get<string>(vars["sockets"]));
248 numberOfSockets = 1;
249 }
250 }
150105a2 251
a5526b57
CH
252 if(client) {
253 // do not construct DownstreamState now, it would try binding sockets.
254 return ret;
255 }
256 ret=std::make_shared<DownstreamState>(serverAddr, sourceAddr, sourceItf, numberOfSockets);
fbe2a2e0 257
df111b53 258 if(vars.count("qps")) {
af619119
RG
259 int qpsVal=std::stoi(boost::get<string>(vars["qps"]));
260 ret->qps=QPSLimiter(qpsVal, qpsVal);
df111b53 261 }
262
df111b53 263 if(vars.count("order")) {
335da0ba 264 ret->order=std::stoi(boost::get<string>(vars["order"]));
df111b53 265 }
266
267 if(vars.count("weight")) {
278403d3
DM
268 try {
269 int weightVal=std::stoi(boost::get<string>(vars["weight"]));
270
271 if(weightVal < 1) {
272 errlog("Error creating new server: downstream weight value must be greater than 0.");
273 return ret;
274 }
275
f2caf657 276 ret->setWeight(weightVal);
278403d3
DM
277 }
278 catch(std::exception& e) {
279 // std::stoi will throw an exception if the string isn't in a value int range
280 errlog("Error creating new server: downstream weight value must be between %s and %s", 1, std::numeric_limits<int>::max());
281 return ret;
282 }
df111b53 283 }
284
3f6d07a4 285 if(vars.count("retries")) {
335da0ba 286 ret->retries=std::stoi(boost::get<string>(vars["retries"]));
3f6d07a4
RG
287 }
288
7c9bf18d 289 if(vars.count("checkInterval")) {
290 ret->checkInterval=static_cast<unsigned int>(std::stoul(boost::get<string>(vars["checkInterval"])));
291 }
292
b40cffe7
RG
293 if(vars.count("tcpConnectTimeout")) {
294 ret->tcpConnectTimeout=std::stoi(boost::get<string>(vars["tcpConnectTimeout"]));
295 }
296
3f6d07a4 297 if(vars.count("tcpSendTimeout")) {
335da0ba 298 ret->tcpSendTimeout=std::stoi(boost::get<string>(vars["tcpSendTimeout"]));
3f6d07a4
RG
299 }
300
301 if(vars.count("tcpRecvTimeout")) {
335da0ba 302 ret->tcpRecvTimeout=std::stoi(boost::get<string>(vars["tcpRecvTimeout"]));
3f6d07a4
RG
303 }
304
284d460c 305 if(vars.count("tcpFastOpen")) {
d987f632
RG
306 bool fastOpen = boost::get<bool>(vars["tcpFastOpen"]);
307 if (fastOpen) {
308#ifdef MSG_FASTOPEN
309 ret->tcpFastOpen=true;
310#else
311 warnlog("TCP Fast Open has been configured on downstream server %s but is not supported", boost::get<string>(vars["address"]));
312#endif
313 }
284d460c
RG
314 }
315
18eeccc9
RG
316 if(vars.count("name")) {
317 ret->name=boost::get<string>(vars["name"]);
318 }
319
1720247e 320 if (vars.count("id")) {
f2caf657 321 ret->setId(boost::lexical_cast<boost::uuids::uuid>(boost::get<string>(vars["id"])));
1720247e
CHB
322 }
323
ad485896
RG
324 if(vars.count("checkName")) {
325 ret->checkName=DNSName(boost::get<string>(vars["checkName"]));
326 }
327
328 if(vars.count("checkType")) {
329 ret->checkType=boost::get<string>(vars["checkType"]);
330 }
331
de9f7157
RG
332 if(vars.count("checkClass")) {
333 ret->checkClass=std::stoi(boost::get<string>(vars["checkClass"]));
334 }
335
98650fde
RG
336 if(vars.count("checkFunction")) {
337 ret->checkFunction= boost::get<DownstreamState::checkfunc_t>(vars["checkFunction"]);
338 }
339
b7e6f4a1
RG
340 if(vars.count("checkTimeout")) {
341 ret->checkTimeout = std::stoi(boost::get<string>(vars["checkTimeout"]));
342 }
343
21830638
RG
344 if(vars.count("setCD")) {
345 ret->setCD=boost::get<bool>(vars["setCD"]);
346 }
347
a6e02424
RG
348 if(vars.count("mustResolve")) {
349 ret->mustResolve=boost::get<bool>(vars["mustResolve"]);
350 }
351
ca404e94
RG
352 if(vars.count("useClientSubnet")) {
353 ret->useECS=boost::get<bool>(vars["useClientSubnet"]);
354 }
355
996db8e9
RG
356 if(vars.count("disableZeroScope")) {
357 ret->disableZeroScope=boost::get<bool>(vars["disableZeroScope"]);
358 }
359
5602f131
DM
360 if(vars.count("ipBindAddrNoPort")) {
361 ret->ipBindAddrNoPort=boost::get<bool>(vars["ipBindAddrNoPort"]);
18f707fa 362 }
5cc8371b
RG
363
364 if(vars.count("addXPF")) {
c85f69a8 365 ret->xpfRRCode=std::stoi(boost::get<string>(vars["addXPF"]));
5602f131
DM
366 }
367
9e87dcb8
RG
368 if(vars.count("maxCheckFailures")) {
369 ret->maxCheckFailures=std::stoi(boost::get<string>(vars["maxCheckFailures"]));
370 }
371
1b633bec
RG
372 if(vars.count("rise")) {
373 ret->minRiseSuccesses=std::stoi(boost::get<string>(vars["rise"]));
374 }
375
3a8ee8bf
RG
376 if(vars.count("cpus")) {
377 for (const auto cpu : boost::get<vector<pair<int,string>>>(vars["cpus"])) {
378 cpus.insert(std::stoi(cpu.second));
379 }
380 }
381
8c82c02d
RG
382 /* this needs to be done _AFTER_ the order has been set,
383 since the server are kept ordered inside the pool */
384 auto localPools = g_pools.getCopy();
385 if(vars.count("pool")) {
386 if(auto* pool = boost::get<string>(&vars["pool"])) {
387 ret->pools.insert(*pool);
388 }
389 else {
390 auto pools = boost::get<vector<pair<int, string> > >(vars["pool"]);
391 for(auto& p : pools) {
392 ret->pools.insert(p.second);
393 }
394 }
395 for(const auto& poolName: ret->pools) {
396 addServerToPool(localPools, poolName, ret);
397 }
398 }
399 else {
400 addServerToPool(localPools, "", ret);
401 }
402 g_pools.setState(localPools);
403
7565f4e6 404 if (ret->connected) {
5d7e6765
RG
405 ret->threadStarted.test_and_set();
406
7565f4e6 407 if(g_launchWork) {
3a8ee8bf 408 g_launchWork->push_back([ret,cpus]() {
6d31c8b6 409 ret->tid = thread(responderThread, ret);
3a8ee8bf
RG
410 if (!cpus.empty()) {
411 mapThreadToCPUList(ret->tid.native_handle(), cpus);
412 }
2e72cc0e 413 });
7565f4e6
RG
414 }
415 else {
6d31c8b6 416 ret->tid = thread(responderThread, ret);
3a8ee8bf
RG
417 if (!cpus.empty()) {
418 mapThreadToCPUList(ret->tid.native_handle(), cpus);
419 }
7565f4e6 420 }
2e72cc0e 421 }
df111b53 422
ecbe9133 423 auto states = g_dstates.getCopy();
e5a14b2b 424 states.push_back(ret);
425 std::stable_sort(states.begin(), states.end(), [](const decltype(ret)& a, const decltype(ret)& b) {
df111b53 426 return a->order < b->order;
427 });
ecbe9133 428 g_dstates.setState(states);
df111b53 429 return ret;
430 } );
431
6bb38cd6 432 g_lua.writeFunction("rmServer",
df111b53 433 [](boost::variant<std::shared_ptr<DownstreamState>, int> var)
6bb38cd6 434 {
f758857a 435 setLuaSideEffect();
886e2cf2
RG
436 shared_ptr<DownstreamState> server;
437 auto* rem = boost::get<shared_ptr<DownstreamState>>(&var);
438 auto states = g_dstates.getCopy();
439 if(rem) {
440 server = *rem;
441 }
442 else {
443 int idx = boost::get<int>(var);
0f06cd4c 444 server = states.at(idx);
886e2cf2
RG
445 }
446 auto localPools = g_pools.getCopy();
447 for (const string& poolName : server->pools) {
448 removeServerFromPool(localPools, poolName, server);
449 }
0f06cd4c
RG
450 /* the server might also be in the default pool */
451 removeServerFromPool(localPools, "", server);
886e2cf2
RG
452 g_pools.setState(localPools);
453 states.erase(remove(states.begin(), states.end(), server), states.end());
454 g_dstates.setState(states);
df111b53 455 } );
456
df111b53 457 g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) {
f758857a 458 setLuaSideEffect();
e5a14b2b 459 g_policy.setState(policy);
df111b53 460 });
70a57b05 461 g_lua.writeFunction("setServerPolicyLua", [](string name, policyfunc_t policy) {
f758857a 462 setLuaSideEffect();
a1b1a29d 463 g_policy.setState(ServerPolicy{name, policy, true});
df111b53 464 });
465
466 g_lua.writeFunction("showServerPolicy", []() {
f758857a 467 setLuaSideEffect();
ecbe9133 468 g_outputBuffer=g_policy.getLocal()->name+"\n";
df111b53 469 });
470
f758857a 471 g_lua.writeFunction("truncateTC", [](bool tc) { setLuaSideEffect(); g_truncateTC=tc; });
472 g_lua.writeFunction("fixupCase", [](bool fu) { setLuaSideEffect(); g_fixupCase=fu; });
df111b53 473
df111b53 474 g_lua.writeFunction("addACL", [](const std::string& domain) {
f758857a 475 setLuaSideEffect();
e5a14b2b 476 g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); });
df111b53 477 });
2e72cc0e 478
efd35aa8 479 g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
f758857a 480 setLuaSideEffect();
5949b95b 481 if(client)
482 return;
85e4ce52
RG
483 if (g_configurationDone) {
484 g_outputBuffer="setLocal cannot be used at runtime!\n";
485 return;
486 }
efd35aa8
RG
487 bool reusePort = false;
488 int tcpFastOpenQueueSize = 0;
489 std::string interface;
f0e4dcba 490 std::set<int> cpus;
efd35aa8 491
0230e350 492 parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
efd35aa8 493
5949b95b 494 try {
495 ComboAddress loc(addr, 53);
6e9fd124
RG
496 for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
497 /* TLS and DNSCrypt frontends are separate */
498 if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
499 it = g_frontends.erase(it);
500 }
501 else {
502 ++it;
503 }
504 }
505
506 // only works pre-startup, so no sync necessary
507 g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
0230e350 508 g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
5949b95b 509 }
6e9fd124 510 catch(const std::exception& e) {
5949b95b 511 g_outputBuffer="Error: "+string(e.what())+"\n";
512 }
513 });
514
efd35aa8 515 g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
f758857a 516 setLuaSideEffect();
2e72cc0e 517 if(client)
518 return;
85e4ce52
RG
519 if (g_configurationDone) {
520 g_outputBuffer="addLocal cannot be used at runtime!\n";
521 return;
522 }
efd35aa8
RG
523 bool reusePort = false;
524 int tcpFastOpenQueueSize = 0;
525 std::string interface;
f0e4dcba 526 std::set<int> cpus;
efd35aa8 527
0230e350 528 parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
efd35aa8 529
2e72cc0e 530 try {
531 ComboAddress loc(addr, 53);
6e9fd124
RG
532 // only works pre-startup, so no sync necessary
533 g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
0230e350 534 g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
2e72cc0e 535 }
536 catch(std::exception& e) {
56d44226
RG
537 g_outputBuffer="Error: "+string(e.what())+"\n";
538 errlog("Error while trying to listen on %s: %s\n", addr, string(e.what()));
2e72cc0e 539 }
540 });
6bb38cd6 541
e4944ea0 542 g_lua.writeFunction("setACL", [](boost::variant<string,vector<pair<int, string>>> inp) {
f758857a 543 setLuaSideEffect();
e5a14b2b 544 NetmaskGroup nmg;
e4944ea0 545 if(auto str = boost::get<string>(&inp)) {
546 nmg.addMask(*str);
547 }
548 else for(const auto& p : boost::get<vector<pair<int,string>>>(inp)) {
e5a14b2b 549 nmg.addMask(p.second);
cffde2fd 550 }
551 g_ACL.setState(nmg);
df111b53 552 });
6bb38cd6 553
df111b53 554 g_lua.writeFunction("showACL", []() {
f758857a 555 setLuaNoSideEffect();
df111b53 556 vector<string> vec;
cffde2fd 557
a9c2e4ab 558 g_ACL.getLocal()->toStringVector(&vec);
cffde2fd 559
df111b53 560 for(const auto& s : vec)
cffde2fd 561 g_outputBuffer+=s+"\n";
562
df111b53 563 });
6bb38cd6 564
6ab65223
PL
565 g_lua.writeFunction("shutdown", []() {
566#ifdef HAVE_SYSTEMD
567 sd_notify(0, "STOPPING=1");
a227f47d
RG
568#endif /* HAVE_SYSTEMD */
569#if 0
570 // Useful for debugging leaks, but might lead to race under load
571 // since other threads are still runing.
572 for(auto& frontend : g_tlslocals) {
573 frontend->cleanup();
574 }
575 g_tlslocals.clear();
576#ifdef HAVE_PROTOBUF
577 google::protobuf::ShutdownProtobufLibrary();
578#endif /* HAVE_PROTOBUF */
579#endif /* 0 */
6ab65223
PL
580 _exit(0);
581 } );
df111b53 582
7f768697
CHB
583 typedef std::unordered_map<std::string, boost::variant<bool, std::string> > showserversopts_t;
584
585 g_lua.writeFunction("showServers", [](boost::optional<showserversopts_t> vars) {
f758857a 586 setLuaNoSideEffect();
7f768697
CHB
587 bool showUUIDs = false;
588 if (vars) {
589 if (vars->count("showUUIDs")) {
590 showUUIDs = boost::get<bool>((*vars)["showUUIDs"]);
591 }
df111b53 592 }
7f768697
CHB
593 try {
594 ostringstream ret;
595 boost::format fmt;
596 if (showUUIDs) {
597 fmt = boost::format("%1$-3d %15$-36s %2$-20.20s %|62t|%3% %|92t|%4$5s %|88t|%5$7.1f %|103t|%6$7d %|106t|%7$3d %|115t|%8$2d %|117t|%9$10d %|123t|%10$7d %|128t|%11$5.1f %|146t|%12$5.1f %|152t|%13$11d %14%" );
598 // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
599 ret << (fmt % "#" % "Name" % "Address" % "State" % "Qps" % "Qlim" % "Ord" % "Wt" % "Queries" % "Drops" % "Drate" % "Lat" % "Outstanding" % "Pools" % "UUID") << endl;
600 } else {
601 fmt = boost::format("%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%" );
602 ret << (fmt % "#" % "Name" % "Address" % "State" % "Qps" % "Qlim" % "Ord" % "Wt" % "Queries" % "Drops" % "Drate" % "Lat" % "Outstanding" % "Pools") << endl;
603 }
df111b53 604
7f768697
CHB
605 uint64_t totQPS{0}, totQueries{0}, totDrops{0};
606 int counter=0;
607 auto states = g_dstates.getLocal();
608 for(const auto& s : *states) {
609 string status = s->getStatus();
610 string pools;
611 for(auto& p : s->pools) {
612 if(!pools.empty())
613 pools+=" ";
614 pools+=p;
615 }
616 if (showUUIDs) {
617 ret << (fmt % counter % s->name % s->remote.toStringWithPort() %
618 status %
619 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 % s->id) << endl;
620 } else {
621 ret << (fmt % counter % s->name % s->remote.toStringWithPort() %
622 status %
623 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;
624 }
625 totQPS += s->queryLoad;
626 totQueries += s->queries.load();
627 totDrops += s->reuseds.load();
628 ++counter;
629 }
630 if (showUUIDs) {
631 ret<< (fmt % "All" % "" % "" % ""
632 %
633 (double)totQPS % "" % "" % "" % totQueries % totDrops % "" % "" % "" % "" % "" ) << endl;
634 } else {
635 ret<< (fmt % "All" % "" % "" % ""
636 %
637 (double)totQPS % "" % "" % "" % totQueries % totDrops % "" % "" % "" % "" ) << endl;
638 }
639
640 g_outputBuffer=ret.str();
641 } catch(std::exception& e) {
642 g_outputBuffer=e.what();
643 throw;
644 }
df111b53 645 });
646
6bb38cd6
RG
647 g_lua.writeFunction("getServers", []() {
648 setLuaNoSideEffect();
649 vector<pair<int, std::shared_ptr<DownstreamState> > > ret;
650 int count=1;
651 for(const auto& s : g_dstates.getCopy()) {
652 ret.push_back(make_pair(count++, s));
653 }
654 return ret;
8499caaf 655 });
e27097e4 656
6bb38cd6
RG
657 g_lua.writeFunction("getPoolServers", [](string pool) {
658 return getDownstreamCandidates(g_pools.getCopy(), pool);
b1bec9f0
RG
659 });
660
6bb38cd6
RG
661 g_lua.writeFunction("getServer", [client](int i) {
662 if (client)
663 return std::make_shared<DownstreamState>(ComboAddress());
664 return g_dstates.getCopy().at(i);
731774a8 665 });
666
6bb38cd6 667 g_lua.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName,
48341d8f 668 boost::optional<unsigned int> interval, boost::optional<string> namespace_name,
f7a645ec
RG
669 boost::optional<string> instance_name) {
670 setLuaSideEffect();
671 auto ours = g_carbon.getCopy();
672 ours.push_back({
673 ComboAddress(address, 2003),
674 (namespace_name && !namespace_name->empty()) ? *namespace_name : "dnsdist",
675 ourName ? *ourName : "",
676 (instance_name && !instance_name->empty()) ? *instance_name : "main" ,
677 interval ? *interval : 30
678 });
679 g_carbon.setState(ours);
680 });
87c605c4 681
6bb38cd6 682 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 683 setLuaSideEffect();
6bb38cd6
RG
684 if(client)
685 return;
686 ComboAddress local(address);
687 try {
688 int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0);
689 SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
690 SBind(sock, local);
691 SListen(sock, 5);
692 auto launch=[sock, local, password, apiKey, customHeaders]() {
32c97b56
CHB
693 setWebserverPassword(password);
694 setWebserverAPIKey(apiKey);
695 setWebserverCustomHeaders(customHeaders);
80dbd7d2 696 thread t(dnsdistWebserverThread, sock, local);
6bb38cd6
RG
697 t.detach();
698 };
699 if(g_launchWork)
700 g_launchWork->push_back(launch);
701 else
702 launch();
731774a8 703 }
704 catch(std::exception& e) {
6bb38cd6
RG
705 g_outputBuffer="Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
706 errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what());
731774a8 707 }
731774a8 708
709 });
710
32c97b56
CHB
711 typedef std::unordered_map<std::string, boost::variant<std::string, std::map<std::string, std::string>> > webserveropts_t;
712
713 g_lua.writeFunction("setWebserverConfig", [](boost::optional<webserveropts_t> vars) {
80dbd7d2 714 setLuaSideEffect();
32c97b56
CHB
715
716 if (!vars) {
717 return ;
718 }
719 if(vars->count("password")) {
720 const std::string password = boost::get<std::string>(vars->at("password"));
721
722 setWebserverPassword(password);
723 }
724 if(vars->count("apiKey")) {
32c97b56
CHB
725 const std::string apiKey = boost::get<std::string>(vars->at("apiKey"));
726
727 setWebserverAPIKey(apiKey);
728 }
729 if(vars->count("customHeaders")) {
730 const boost::optional<std::map<std::string, std::string> > headers = boost::get<std::map<std::string, std::string> >(vars->at("customHeaders"));
731
732 setWebserverCustomHeaders(headers);
733 }
80dbd7d2
CHB
734 });
735
6bb38cd6 736 g_lua.writeFunction("controlSocket", [client](const std::string& str) {
87c605c4 737 setLuaSideEffect();
6bb38cd6 738 ComboAddress local(str, 5199);
832c1792 739
6bb38cd6
RG
740 if(client) {
741 g_serverControl = local;
87c605c4
RG
742 return;
743 }
731774a8 744
9c9b4998
RG
745 g_consoleEnabled = true;
746#ifdef HAVE_LIBSODIUM
747 if (g_configurationDone && g_consoleKey.empty()) {
748 warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
749 }
750#endif
751
6bb38cd6
RG
752 try {
753 int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0);
754 SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
755 SBind(sock, local);
756 SListen(sock, 5);
757 auto launch=[sock, local]() {
758 thread t(controlThread, sock, local);
759 t.detach();
760 };
761 if(g_launchWork)
762 g_launchWork->push_back(launch);
763 else
764 launch();
ae3dfa48 765
6bb38cd6
RG
766 }
767 catch(std::exception& e) {
768 g_outputBuffer="Unable to bind to control socket on " + local.toStringWithPort() + ": " + e.what();
769 errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), e.what());
770 }
63beb26d
G
771 });
772
b5521206
RG
773 g_lua.writeFunction("addConsoleACL", [](const std::string& netmask) {
774 setLuaSideEffect();
775#ifndef HAVE_LIBSODIUM
776 warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
777#endif
778
779 g_consoleACL.modify([netmask](NetmaskGroup& nmg) { nmg.addMask(netmask); });
780 });
781
782 g_lua.writeFunction("setConsoleACL", [](boost::variant<string,vector<pair<int, string>>> inp) {
783 setLuaSideEffect();
784
785#ifndef HAVE_LIBSODIUM
786 warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
787#endif
788
789 NetmaskGroup nmg;
790 if(auto str = boost::get<string>(&inp)) {
791 nmg.addMask(*str);
792 }
793 else for(const auto& p : boost::get<vector<pair<int,string>>>(inp)) {
794 nmg.addMask(p.second);
795 }
796 g_consoleACL.setState(nmg);
797 });
798
799 g_lua.writeFunction("showConsoleACL", []() {
800 setLuaNoSideEffect();
801
802#ifndef HAVE_LIBSODIUM
803 warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
804#endif
805
806 vector<string> vec;
807 g_consoleACL.getLocal()->toStringVector(&vec);
808
809 for(const auto& s : vec) {
810 g_outputBuffer += s + "\n";
811 }
812 });
813
6bb38cd6
RG
814 g_lua.writeFunction("clearQueryCounters", []() {
815 unsigned int size{0};
816 {
817 WriteLock wl(&g_qcount.queryLock);
818 size = g_qcount.records.size();
819 g_qcount.records.clear();
820 }
6eecd4c2 821
6bb38cd6
RG
822 boost::format fmt("%d records cleared from query counter buffer\n");
823 g_outputBuffer = (fmt % size).str();
2332b03c 824 });
825
6bb38cd6
RG
826 g_lua.writeFunction("getQueryCounters", [](boost::optional<unsigned int> optMax) {
827 setLuaNoSideEffect();
828 ReadLock rl(&g_qcount.queryLock);
829 g_outputBuffer = "query counting is currently: ";
830 g_outputBuffer+= g_qcount.enabled ? "enabled" : "disabled";
831 g_outputBuffer+= (boost::format(" (%d records in buffer)\n") % g_qcount.records.size()).str();
f39b7598 832
6bb38cd6
RG
833 boost::format fmt("%-3d %s: %d request(s)\n");
834 QueryCountRecords::iterator it;
835 unsigned int max = optMax ? *optMax : 10;
836 unsigned int index{1};
837 for(it = g_qcount.records.begin(); it != g_qcount.records.end() && index <= max; ++it, ++index) {
838 g_outputBuffer += (fmt % index % it->first % it->second).str();
839 }
808c5ef7 840 });
841
6bb38cd6 842 g_lua.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled=enabled; });
ae3dfa48 843
6bb38cd6
RG
844 g_lua.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
845 g_qcount.filter = func;
886e2cf2
RG
846 });
847
6bb38cd6
RG
848 g_lua.writeFunction("makeKey", []() {
849 setLuaNoSideEffect();
850 g_outputBuffer="setKey("+newKey()+")\n";
6bba426c 851 });
852
6bb38cd6 853 g_lua.writeFunction("setKey", [](const std::string& key) {
b5521206 854 if(!g_configurationDone && ! g_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
6bb38cd6
RG
855 return; // but later setKeys() trump the -k value again
856 }
b5521206
RG
857#ifndef HAVE_LIBSODIUM
858 warnlog("Calling setKey() while libsodium support has not been enabled is not secure, and will result in cleartext communications");
859#endif
6bba426c 860
6bb38cd6
RG
861 setLuaSideEffect();
862 string newkey;
863 if(B64Decode(key, newkey) < 0) {
864 g_outputBuffer=string("Unable to decode ")+key+" as Base64";
865 errlog("%s", g_outputBuffer);
866 }
2332b03c 867 else
b5521206 868 g_consoleKey=newkey;
2332b03c 869 });
870
6bb38cd6
RG
871 g_lua.writeFunction("testCrypto", [](boost::optional<string> optTestMsg)
872 {
873 setLuaNoSideEffect();
874#ifdef HAVE_LIBSODIUM
875 try {
876 string testmsg;
2332b03c 877
6bb38cd6
RG
878 if (optTestMsg) {
879 testmsg = *optTestMsg;
880 }
881 else {
882 testmsg = "testStringForCryptoTests";
883 }
6eecd4c2 884
6bb38cd6
RG
885 SodiumNonce sn, sn2;
886 sn.init();
887 sn2=sn;
b5521206
RG
888 string encrypted = sodEncryptSym(testmsg, g_consoleKey, sn);
889 string decrypted = sodDecryptSym(encrypted, g_consoleKey, sn2);
4ed8dfeb 890
6bb38cd6
RG
891 sn.increment();
892 sn2.increment();
b7860997 893
b5521206
RG
894 encrypted = sodEncryptSym(testmsg, g_consoleKey, sn);
895 decrypted = sodDecryptSym(encrypted, g_consoleKey, sn2);
36da3ecd 896
6bb38cd6
RG
897 if(testmsg == decrypted)
898 g_outputBuffer="Everything is ok!\n";
899 else
c29bf3df
RG
900 g_outputBuffer="Crypto failed.. (the decoded value does not match the cleartext one)\n";
901 }
902 catch(const std::exception& e) {
903 g_outputBuffer="Crypto failed: "+std::string(e.what())+"\n";
6bb38cd6
RG
904 }
905 catch(...) {
906 g_outputBuffer="Crypto failed..\n";
907 }
908#else
909 g_outputBuffer="Crypto not available.\n";
910#endif
911 });
b7860997 912
6bb38cd6 913 g_lua.writeFunction("setTCPRecvTimeout", [](int timeout) { g_tcpRecvTimeout=timeout; });
89cb6f9a 914
6bb38cd6 915 g_lua.writeFunction("setTCPSendTimeout", [](int timeout) { g_tcpSendTimeout=timeout; });
89cb6f9a 916
6bb38cd6 917 g_lua.writeFunction("setUDPTimeout", [](int timeout) { g_udpTimeout=timeout; });
d3826006 918
6bb38cd6
RG
919 g_lua.writeFunction("setMaxUDPOutstanding", [](uint16_t max) {
920 if (!g_configurationDone) {
921 g_maxOutstanding = max;
922 } else {
923 g_outputBuffer="Max UDP outstanding cannot be altered at runtime!\n";
b7860997 924 }
55baa1f2
RG
925 });
926
6bb38cd6
RG
927 g_lua.writeFunction("setMaxTCPClientThreads", [](uint64_t max) {
928 if (!g_configurationDone) {
929 g_maxTCPClientThreads = max;
930 } else {
931 g_outputBuffer="Maximum TCP client threads count cannot be altered at runtime!\n";
932 }
55baa1f2
RG
933 });
934
6bb38cd6
RG
935 g_lua.writeFunction("setMaxTCPQueuedConnections", [](uint64_t max) {
936 if (!g_configurationDone) {
937 g_maxTCPQueuedConnections = max;
938 } else {
939 g_outputBuffer="The maximum number of queued TCP connections cannot be altered at runtime!\n";
940 }
55baa1f2
RG
941 });
942
6bb38cd6
RG
943 g_lua.writeFunction("setMaxTCPQueriesPerConnection", [](size_t max) {
944 if (!g_configurationDone) {
945 g_maxTCPQueriesPerConn = max;
946 } else {
947 g_outputBuffer="The maximum number of queries per TCP connection cannot be altered at runtime!\n";
948 }
57c61ce9
RG
949 });
950
6bb38cd6
RG
951 g_lua.writeFunction("setMaxTCPConnectionsPerClient", [](size_t max) {
952 if (!g_configurationDone) {
953 g_maxTCPConnectionsPerClient = max;
954 } else {
955 g_outputBuffer="The maximum number of TCP connection per client cannot be altered at runtime!\n";
956 }
57c61ce9
RG
957 });
958
6bb38cd6
RG
959 g_lua.writeFunction("setMaxTCPConnectionDuration", [](size_t max) {
960 if (!g_configurationDone) {
961 g_maxTCPConnectionDuration = max;
962 } else {
963 g_outputBuffer="The maximum duration of a TCP connection cannot be altered at runtime!\n";
964 }
788c3243
RG
965 });
966
6bb38cd6 967 g_lua.writeFunction("setCacheCleaningDelay", [](uint32_t delay) { g_cacheCleaningDelay = delay; });
0570f37c 968
6bb38cd6 969 g_lua.writeFunction("setCacheCleaningPercentage", [](uint16_t percentage) { if (percentage < 100) g_cacheCleaningPercentage = percentage; else g_cacheCleaningPercentage = 100; });
0570f37c 970
6bb38cd6 971 g_lua.writeFunction("setECSSourcePrefixV4", [](uint16_t prefix) { g_ECSSourcePrefixV4=prefix; });
f39b7598 972
6bb38cd6 973 g_lua.writeFunction("setECSSourcePrefixV6", [](uint16_t prefix) { g_ECSSourcePrefixV6=prefix; });
0570f37c 974
6bb38cd6 975 g_lua.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; });
df111b53 976
53c57da7
RG
977 g_lua.writeFunction("setPreserveTrailingData", [](bool preserve) { g_preserveTrailingData = preserve; });
978
6bb38cd6
RG
979 g_lua.writeFunction("showDynBlocks", []() {
980 setLuaNoSideEffect();
981 auto slow = g_dynblockNMG.getCopy();
982 struct timespec now;
983 gettime(&now);
1d3ba133
RG
984 boost::format fmt("%-24s %8d %8d %-10s %-20s %s\n");
985 g_outputBuffer = (fmt % "What" % "Seconds" % "Blocks" % "Warning" % "Action" % "Reason").str();
6bb38cd6
RG
986 for(const auto& e: slow) {
987 if(now < e->second.until)
1d3ba133 988 g_outputBuffer+= (fmt % e->first.toString() % (e->second.until.tv_sec - now.tv_sec) % e->second.blocks % (e->second.warning ? "true" : "false") % DNSAction::typeToString(e->second.action != DNSAction::Action::None ? e->second.action : g_dynBlockAction) % e->second.reason).str();
6bb38cd6
RG
989 }
990 auto slow2 = g_dynblockSMT.getCopy();
991 slow2.visit([&now, &fmt](const SuffixMatchTree<DynBlock>& node) {
992 if(now <node.d_value.until) {
993 string dom("empty");
994 if(!node.d_value.domain.empty())
995 dom = node.d_value.domain.toString();
1d3ba133 996 g_outputBuffer+= (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % (node.d_value.warning ? "true" : "false") % DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : g_dynBlockAction) % node.d_value.reason).str();
6bb38cd6
RG
997 }
998 });
832c1792 999
520eb5a0 1000 });
df111b53 1001
6bb38cd6 1002 g_lua.writeFunction("clearDynBlocks", []() {
f758857a 1003 setLuaSideEffect();
6bb38cd6
RG
1004 nmts_t nmg;
1005 g_dynblockNMG.setState(nmg);
1006 SuffixMatchTree<DynBlock> smt;
1007 g_dynblockSMT.setState(smt);
1008 });
1009
1010 g_lua.writeFunction("addDynBlocks",
f8327125 1011 [](const std::unordered_map<ComboAddress,unsigned int, ComboAddress::addressOnlyHash, ComboAddress::addressOnlyEqual>& m, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) {
6ddb008a
RG
1012 if (m.empty()) {
1013 return;
1014 }
6bb38cd6
RG
1015 setLuaSideEffect();
1016 auto slow = g_dynblockNMG.getCopy();
1017 struct timespec until, now;
1018 gettime(&now);
1019 until=now;
1020 int actualSeconds = seconds ? *seconds : 10;
1021 until.tv_sec += actualSeconds;
1022 for(const auto& capair : m) {
1023 unsigned int count = 0;
1024 auto got = slow.lookup(Netmask(capair.first));
1025 bool expired=false;
1026 if(got) {
1027 if(until < got->second.until) // had a longer policy
1028 continue;
1029 if(now < got->second.until) // only inherit count on fresh query we are extending
1030 count=got->second.blocks;
1031 else
1032 expired=true;
1033 }
1034 DynBlock db{msg,until,DNSName(),(action ? *action : DNSAction::Action::None)};
1035 db.blocks=count;
1036 if(!got || expired)
1037 warnlog("Inserting dynamic block for %s for %d seconds: %s", capair.first.toString(), actualSeconds, msg);
1038 slow.insert(Netmask(capair.first)).second=db;
1039 }
1040 g_dynblockNMG.setState(slow);
1041 });
1042
1043 g_lua.writeFunction("addDynBlockSMT",
1044 [](const vector<pair<unsigned int, string> >&names, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) {
6ddb008a
RG
1045 if (names.empty()) {
1046 return;
1047 }
6bb38cd6
RG
1048 setLuaSideEffect();
1049 auto slow = g_dynblockSMT.getCopy();
1050 struct timespec until, now;
1051 gettime(&now);
1052 until=now;
1053 int actualSeconds = seconds ? *seconds : 10;
1054 until.tv_sec += actualSeconds;
1055
1056 for(const auto& capair : names) {
1057 unsigned int count = 0;
1058 DNSName domain(capair.second);
1059 auto got = slow.lookup(domain);
1060 bool expired=false;
1061 if(got) {
1062 if(until < got->until) // had a longer policy
1063 continue;
1064 if(now < got->until) // only inherit count on fresh query we are extending
1065 count=got->blocks;
1066 else
1067 expired=true;
1068 }
1069
1070 DynBlock db{msg,until,domain,(action ? *action : DNSAction::Action::None)};
1071 db.blocks=count;
1072 if(!got || expired)
1073 warnlog("Inserting dynamic block for %s for %d seconds: %s", domain, actualSeconds, msg);
1074 slow.add(domain, db);
1075 }
1076 g_dynblockSMT.setState(slow);
1077 });
1078
1079 g_lua.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
1080 if (!g_configurationDone) {
3d60b39a 1081 if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
6bb38cd6
RG
1082 g_dynBlockAction = action;
1083 }
1084 else {
3d60b39a 1085 errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
1086 g_outputBuffer="Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!\n";
6bb38cd6
RG
1087 }
1088 } else {
1089 g_outputBuffer="Dynamic blocks action cannot be altered at runtime!\n";
1090 }
df111b53 1091 });
832c1792 1092
37b6d73d 1093 g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, boost::variant<std::string, std::vector<std::pair<int, std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int, std::string>>> keyFiles, boost::optional<localbind_t> vars) {
6bb38cd6
RG
1094 if (g_configurationDone) {
1095 g_outputBuffer="addDNSCryptBind cannot be used at runtime!\n";
1096 return;
1097 }
1098#ifdef HAVE_DNSCRYPT
6bb38cd6
RG
1099 bool reusePort = false;
1100 int tcpFastOpenQueueSize = 0;
1101 std::string interface;
1102 std::set<int> cpus;
37b6d73d 1103 std::vector<DNSCryptContext::CertKeyPaths> certKeys;
df111b53 1104
0230e350 1105 parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
df111b53 1106
37b6d73d
RG
1107 if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
1108 auto certFile = boost::get<std::string>(certFiles);
1109 auto keyFile = boost::get<std::string>(keyFiles);
1110 certKeys.push_back({certFile, keyFile});
1111 }
1112 else if (certFiles.type() == typeid(std::vector<std::pair<int,std::string>>) && keyFiles.type() == typeid(std::vector<std::pair<int,std::string>>)) {
1113 auto certFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(certFiles);
1114 auto keyFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(keyFiles);
1115 if (certFilesVect.size() == keyFilesVect.size()) {
1116 for (size_t idx = 0; idx < certFilesVect.size(); idx++) {
1117 certKeys.push_back({certFilesVect.at(idx).second, keyFilesVect.at(idx).second});
1118 }
1119 }
1120 else {
1121 errlog("Error, mismatching number of certificates and keys in call to addDNSCryptBind!");
1122 g_outputBuffer="Error, mismatching number of certificates and keys in call to addDNSCryptBind()!";
1123 return;
1124 }
1125 }
1126 else {
1127 errlog("Error, mismatching number of certificates and keys in call to addDNSCryptBind()!");
1128 g_outputBuffer="Error, mismatching number of certificates and keys in call to addDNSCryptBind()!";
1129 return;
1130 }
1131
6bb38cd6 1132 try {
37b6d73d 1133 auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
6e9fd124
RG
1134
1135 /* UDP */
1136 auto cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus));
1137 cs->dnscryptCtx = ctx;
1138 g_dnsCryptLocals.push_back(ctx);
1139 g_frontends.push_back(std::move(cs));
1140
1141 /* TCP */
1142 cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus));
1143 cs->dnscryptCtx = ctx;
1144 g_frontends.push_back(std::move(cs));
df111b53 1145 }
6bb38cd6
RG
1146 catch(std::exception& e) {
1147 errlog(e.what());
1148 g_outputBuffer="Error: "+string(e.what())+"\n";
1149 }
1150#else
1151 g_outputBuffer="Error: DNSCrypt support is not enabled.\n";
1152#endif
4d5959e6 1153
df111b53 1154 });
1155
6bb38cd6 1156 g_lua.writeFunction("showDNSCryptBinds", []() {
f758857a 1157 setLuaNoSideEffect();
6bb38cd6
RG
1158#ifdef HAVE_DNSCRYPT
1159 ostringstream ret;
43234e76
RG
1160 boost::format fmt("%1$-3d %2% %|25t|%3$-20.20s");
1161 ret << (fmt % "#" % "Address" % "Provider Name") << endl;
6bb38cd6
RG
1162 size_t idx = 0;
1163
26438bc9 1164 std::unordered_set<std::shared_ptr<DNSCryptContext>> contexts;
6e9fd124
RG
1165 for (const auto& frontend : g_frontends) {
1166 const std::shared_ptr<DNSCryptContext> ctx = frontend->dnscryptCtx;
26438bc9 1167 if (!ctx || contexts.count(ctx) != 0) {
a6544e62
RG
1168 continue;
1169 }
26438bc9 1170 contexts.insert(ctx);
6e9fd124 1171 ret<< (fmt % idx % frontend->local.toStringWithPort() % ctx->getProviderName()) << endl;
6bb38cd6 1172 idx++;
df111b53 1173 }
df111b53 1174
6bb38cd6
RG
1175 g_outputBuffer=ret.str();
1176#else
1177 g_outputBuffer="Error: DNSCrypt support is not enabled.\n";
1178#endif
886e2cf2 1179 });
df111b53 1180
43234e76 1181 g_lua.writeFunction("getDNSCryptBind", [](size_t idx) {
6bb38cd6
RG
1182 setLuaNoSideEffect();
1183#ifdef HAVE_DNSCRYPT
43234e76 1184 std::shared_ptr<DNSCryptContext> ret = nullptr;
6bb38cd6 1185 if (idx < g_dnsCryptLocals.size()) {
6e9fd124 1186 ret = g_dnsCryptLocals.at(idx);
d92708ed 1187 }
6bb38cd6
RG
1188 return ret;
1189#else
1190 g_outputBuffer="Error: DNSCrypt support is not enabled.\n";
1191#endif
d92708ed
RG
1192 });
1193
6bb38cd6
RG
1194 g_lua.writeFunction("generateDNSCryptProviderKeys", [](const std::string& publicKeyFile, const std::string privateKeyFile) {
1195 setLuaNoSideEffect();
1196#ifdef HAVE_DNSCRYPT
1197 unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
1198 unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
1199 sodium_mlock(privateKey, sizeof(privateKey));
4c6f4321 1200
6bb38cd6 1201 try {
43234e76 1202 DNSCryptContext::generateProviderKeys(publicKey, privateKey);
4c6f4321 1203
6bb38cd6
RG
1204 ofstream pubKStream(publicKeyFile);
1205 pubKStream.write((char*) publicKey, sizeof(publicKey));
1206 pubKStream.close();
df111b53 1207
6bb38cd6
RG
1208 ofstream privKStream(privateKeyFile);
1209 privKStream.write((char*) privateKey, sizeof(privateKey));
1210 privKStream.close();
df111b53 1211
43234e76 1212 g_outputBuffer="Provider fingerprint is: " + DNSCryptContext::getProviderFingerprint(publicKey) + "\n";
6bb38cd6
RG
1213 }
1214 catch(std::exception& e) {
1215 errlog(e.what());
1216 g_outputBuffer="Error: "+string(e.what())+"\n";
1217 }
df111b53 1218
6bb38cd6
RG
1219 sodium_memzero(privateKey, sizeof(privateKey));
1220 sodium_munlock(privateKey, sizeof(privateKey));
1221#else
1222 g_outputBuffer="Error: DNSCrypt support is not enabled.\n";
1223#endif
aeb36780
RG
1224 });
1225
6bb38cd6
RG
1226 g_lua.writeFunction("printDNSCryptProviderFingerprint", [](const std::string& publicKeyFile) {
1227 setLuaNoSideEffect();
1228#ifdef HAVE_DNSCRYPT
1229 unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
aeb36780 1230
6bb38cd6
RG
1231 try {
1232 ifstream file(publicKeyFile);
1233 file.read((char *) &publicKey, sizeof(publicKey));
df111b53 1234
6bb38cd6
RG
1235 if (file.fail())
1236 throw std::runtime_error("Invalid dnscrypt provider public key file " + publicKeyFile);
df111b53 1237
6bb38cd6 1238 file.close();
43234e76 1239 g_outputBuffer="Provider fingerprint is: " + DNSCryptContext::getProviderFingerprint(publicKey) + "\n";
6bb38cd6
RG
1240 }
1241 catch(std::exception& e) {
1242 errlog(e.what());
1243 g_outputBuffer="Error: "+string(e.what())+"\n";
1244 }
1245#else
1246 g_outputBuffer="Error: DNSCrypt support is not enabled.\n";
1247#endif
df111b53 1248 });
1249
501983cd 1250#ifdef HAVE_DNSCRYPT
43234e76 1251 g_lua.writeFunction("generateDNSCryptCertificate", [](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
6bb38cd6 1252 setLuaNoSideEffect();
43234e76
RG
1253 DNSCryptPrivateKey privateKey;
1254 DNSCryptCert cert;
42fae326 1255
50bed881 1256 try {
43234e76 1257 if (generateDNSCryptCertificate(providerPrivateKeyFile, serial, begin, end, version ? *version : DNSCryptExchangeVersion::VERSION1, cert, privateKey)) {
6bb38cd6 1258 privateKey.saveToFile(privateKeyFile);
43234e76 1259 DNSCryptContext::saveCertFromFile(cert, certificateFile);
6bb38cd6 1260 }
50bed881 1261 }
6bb38cd6
RG
1262 catch(const std::exception& e) {
1263 errlog(e.what());
1264 g_outputBuffer="Error: "+string(e.what())+"\n";
50bed881 1265 }
50bed881 1266 });
501983cd 1267#endif
df111b53 1268
6bb38cd6
RG
1269 g_lua.writeFunction("showPools", []() {
1270 setLuaNoSideEffect();
df111b53 1271 try {
6bb38cd6
RG
1272 ostringstream ret;
1273 boost::format fmt("%1$-20.20s %|25t|%2$20s %|25t|%3$20s %|50t|%4%" );
1274 // 1 2 3 4
1275 ret << (fmt % "Name" % "Cache" % "ServerPolicy" % "Servers" ) << endl;
1276
1277 const auto localPools = g_pools.getCopy();
1278 for (const auto& entry : localPools) {
1279 const string& name = entry.first;
1280 const std::shared_ptr<ServerPool> pool = entry.second;
1281 string cache = pool->packetCache != nullptr ? pool->packetCache->toString() : "";
1282 string policy = g_policy.getLocal()->name;
1283 if (pool->policy != nullptr) {
1284 policy = pool->policy->name;
1285 }
1286 string servers;
1287
a1b1a29d 1288 for (const auto& server: pool->getServers()) {
6bb38cd6
RG
1289 if (!servers.empty()) {
1290 servers += ", ";
1291 }
1292 if (!server.second->name.empty()) {
1293 servers += server.second->name;
1294 servers += " ";
1295 }
1296 servers += server.second->remote.toStringWithPort();
1297 }
1298
1299 ret << (fmt % name % cache % policy % servers) << endl;
1300 }
1301 g_outputBuffer=ret.str();
1302 }catch(std::exception& e) { g_outputBuffer=e.what(); throw; }
1303 });
1304
1305 g_lua.writeFunction("getPool", [client](const string& poolName) {
1306 if (client) {
1307 return std::make_shared<ServerPool>();
df111b53 1308 }
6bb38cd6
RG
1309 auto localPools = g_pools.getCopy();
1310 std::shared_ptr<ServerPool> pool = createPoolIfNotExists(localPools, poolName);
1311 g_pools.setState(localPools);
1312 return pool;
df111b53 1313 });
1314
6bb38cd6
RG
1315 g_lua.writeFunction("setVerboseHealthChecks", [](bool verbose) { g_verboseHealthChecks=verbose; });
1316 g_lua.writeFunction("setStaleCacheEntriesTTL", [](uint32_t ttl) { g_staleCacheEntriesTTL = ttl; });
03ebf8b2 1317
6bb38cd6 1318 g_lua.writeFunction("showBinds", []() {
f758857a 1319 setLuaNoSideEffect();
6bb38cd6
RG
1320 try {
1321 ostringstream ret;
ba7ec340 1322 boost::format fmt("%1$-3d %2$-20.20s %|35t|%3$-20.20s %|57t|%4%" );
6bb38cd6
RG
1323 // 1 2 3 4
1324 ret << (fmt % "#" % "Address" % "Protocol" % "Queries" ) << endl;
1325
1326 size_t counter = 0;
1327 for (const auto& front : g_frontends) {
ba7ec340 1328 ret << (fmt % counter % front->local.toStringWithPort() % front->getType() % front->queries) << endl;
6bb38cd6 1329 counter++;
0e41337b 1330 }
6bb38cd6
RG
1331 g_outputBuffer=ret.str();
1332 }catch(std::exception& e) { g_outputBuffer=e.what(); throw; }
0e5b3cff 1333 });
1334
6bb38cd6 1335 g_lua.writeFunction("getBind", [](size_t num) {
f758857a 1336 setLuaNoSideEffect();
6bb38cd6
RG
1337 ClientState* ret = nullptr;
1338 if(num < g_frontends.size()) {
6e9fd124 1339 ret=g_frontends[num].get();
df111b53 1340 }
df111b53 1341 return ret;
6bb38cd6 1342 });
df111b53 1343
6bb38cd6
RG
1344 g_lua.writeFunction("help", [](boost::optional<std::string> command) {
1345 setLuaNoSideEffect();
1346 g_outputBuffer = "";
1347 for (const auto& keyword : g_consoleKeywords) {
1348 if (!command) {
1349 g_outputBuffer += keyword.toString() + "\n";
1350 }
1351 else if (keyword.name == command) {
1352 g_outputBuffer = keyword.toString() + "\n";
1353 return;
1354 }
1355 }
1356 if (command) {
1357 g_outputBuffer = "Nothing found for " + *command + "\n";
786e4d8c 1358 }
786e4d8c 1359 });
520eb5a0 1360
6bb38cd6 1361 g_lua.writeFunction("showVersion", []() {
786e4d8c 1362 setLuaNoSideEffect();
6bb38cd6 1363 g_outputBuffer = "dnsdist " + std::string(VERSION) + "\n";
786e4d8c
RS
1364 });
1365
eb0ca460
PL
1366 g_lua.writeFunction("showSecurityStatus", []() {
1367 setLuaNoSideEffect();
1368 g_outputBuffer = std::to_string(g_stats.securityStatus) + "\n";
1369 });
1370
6bb38cd6
RG
1371#ifdef HAVE_EBPF
1372 g_lua.writeFunction("setDefaultBPFFilter", [](std::shared_ptr<BPFFilter> bpf) {
1373 if (g_configurationDone) {
1374 g_outputBuffer="setDefaultBPFFilter() cannot be used at runtime!\n";
1375 return;
1376 }
1377 g_defaultBPFFilter = bpf;
786e4d8c 1378 });
62edea30 1379
6bb38cd6
RG
1380 g_lua.writeFunction("registerDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
1381 if (dbpf) {
1382 g_dynBPFFilters.push_back(dbpf);
520eb5a0 1383 }
520eb5a0 1384 });
f5b58807 1385
6bb38cd6
RG
1386 g_lua.writeFunction("unregisterDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
1387 if (dbpf) {
1388 for (auto it = g_dynBPFFilters.begin(); it != g_dynBPFFilters.end(); it++) {
1389 if (*it == dbpf) {
1390 g_dynBPFFilters.erase(it);
1391 break;
1392 }
1393 }
1394 }
2d11d1b2 1395 });
df111b53 1396
b6ba8123 1397 g_lua.writeFunction("addBPFFilterDynBlocks", [](const std::unordered_map<ComboAddress,unsigned int, ComboAddress::addressOnlyHash, ComboAddress::addressOnlyEqual>& m, std::shared_ptr<DynBPFFilter> dynbpf, boost::optional<int> seconds, boost::optional<std::string> msg) {
6bb38cd6
RG
1398 setLuaSideEffect();
1399 struct timespec until, now;
1400 clock_gettime(CLOCK_MONOTONIC, &now);
1401 until=now;
1402 int actualSeconds = seconds ? *seconds : 10;
1403 until.tv_sec += actualSeconds;
1404 for(const auto& capair : m) {
4900be3f
RG
1405 if (dynbpf->block(capair.first, until)) {
1406 warnlog("Inserting eBPF dynamic block for %s for %d seconds: %s", capair.first.toString(), actualSeconds, msg ? *msg : "");
1407 }
6bb38cd6 1408 }
df111b53 1409 });
62edea30 1410
6bb38cd6 1411#endif /* HAVE_EBPF */
2d11d1b2 1412
6bb38cd6 1413 g_lua.writeFunction<std::unordered_map<string,uint64_t>()>("getStatisticsCounters", []() {
f758857a 1414 setLuaNoSideEffect();
6bb38cd6
RG
1415 std::unordered_map<string,uint64_t> res;
1416 for(const auto& entry : g_stats.entries) {
1417 if(const auto& val = boost::get<DNSDistStats::stat_t*>(&entry.second))
1418 res[entry.first] = (*val)->load();
df111b53 1419 }
6bb38cd6
RG
1420 return res;
1421 });
df111b53 1422
6bb38cd6
RG
1423 g_lua.writeFunction("includeDirectory", [](const std::string& dirname) {
1424 if (g_configurationDone) {
1425 errlog("includeDirectory() cannot be used at runtime!");
1426 g_outputBuffer="includeDirectory() cannot be used at runtime!\n";
1427 return;
df111b53 1428 }
1429
6bb38cd6
RG
1430 if (g_included) {
1431 errlog("includeDirectory() cannot be used recursively!");
1432 g_outputBuffer="includeDirectory() cannot be used recursively!\n";
e12b3374
RG
1433 return;
1434 }
1435
6bb38cd6
RG
1436 g_included = true;
1437 struct stat st;
1438 if (stat(dirname.c_str(), &st)) {
1439 errlog("The included directory %s does not exist!", dirname.c_str());
1440 g_outputBuffer="The included directory " + dirname + " does not exist!";
1441 return;
df111b53 1442 }
df111b53 1443
6bb38cd6
RG
1444 if (!S_ISDIR(st.st_mode)) {
1445 errlog("The included directory %s is not a directory!", dirname.c_str());
1446 g_outputBuffer="The included directory " + dirname + " is not a directory!";
1447 return;
6f6b4d69 1448 }
1449
6bb38cd6
RG
1450 DIR *dirp;
1451 struct dirent *ent;
1452 std::list<std::string> files;
1453 if (!(dirp = opendir(dirname.c_str()))) {
1454 errlog("Error opening the included directory %s!", dirname.c_str());
1455 g_outputBuffer="Error opening the included directory " + dirname + "!";
1456 return;
6f6b4d69 1457 }
df111b53 1458
6bb38cd6
RG
1459 while((ent = readdir(dirp)) != NULL) {
1460 if (ent->d_name[0] == '.') {
1461 continue;
1462 }
3f6d07a4 1463
6bb38cd6
RG
1464 if (boost::ends_with(ent->d_name, ".conf")) {
1465 std::ostringstream namebuf;
1466 namebuf << dirname.c_str() << "/" << ent->d_name;
2a817e5a 1467
6bb38cd6
RG
1468 if (stat(namebuf.str().c_str(), &st) || !S_ISREG(st.st_mode)) {
1469 continue;
1470 }
e0b5e49d 1471
6bb38cd6
RG
1472 files.push_back(namebuf.str());
1473 }
e41f8165 1474 }
e41f8165 1475
6bb38cd6
RG
1476 closedir(dirp);
1477 files.sort();
1478
1479 for (auto file = files.begin(); file != files.end(); ++file) {
1480 std::ifstream ifs(*file);
1481 if (!ifs) {
1482 warnlog("Unable to read configuration from '%s'", *file);
1483 } else {
1484 vinfolog("Read configuration from '%s'", *file);
1485 }
26a6373d 1486
6bb38cd6 1487 g_lua.executeCode(ifs);
741ebe08 1488 }
26a6373d 1489
6bb38cd6 1490 g_included = false;
26a6373d
SO
1491 });
1492
6bb38cd6
RG
1493 g_lua.writeFunction("setAPIWritable", [](bool writable, boost::optional<std::string> apiConfigDir) {
1494 setLuaSideEffect();
1495 g_apiReadWrite = writable;
1496 if (apiConfigDir) {
1497 if (!(*apiConfigDir).empty()) {
1498 g_apiConfigDirectory = *apiConfigDir;
1499 }
1500 else {
1501 errlog("The API configuration directory value cannot be empty!");
1502 g_outputBuffer="The API configuration directory value cannot be empty!";
1503 }
741ebe08 1504 }
5b8255ba 1505 });
26a6373d 1506
6bb38cd6
RG
1507 g_lua.writeFunction("setServFailWhenNoServer", [](bool servfail) {
1508 setLuaSideEffect();
1509 g_servFailOnNoPolicy = servfail;
1510 });
26a6373d 1511
32b86928
RG
1512 g_lua.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
1513 setLuaSideEffect();
1514 g_roundrobinFailOnNoServer = fail;
1515 });
1516
01f6920b 1517 g_lua.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional<size_t> numberOfShards) {
6bb38cd6
RG
1518 setLuaSideEffect();
1519 if (g_configurationDone) {
1520 errlog("setRingBuffersSize() cannot be used at runtime!");
1521 g_outputBuffer="setRingBuffersSize() cannot be used at runtime!\n";
1522 return;
5b8255ba 1523 }
01f6920b 1524 g_rings.setCapacity(capacity, numberOfShards ? *numberOfShards : 1);
5b8255ba 1525 });
26a6373d 1526
6d31c8b6
RG
1527 g_lua.writeFunction("setRingBuffersLockRetries", [](size_t retries) {
1528 setLuaSideEffect();
1529 g_rings.setNumberOfLockRetries(retries);
5b8255ba 1530 });
26a6373d 1531
6bb38cd6
RG
1532 g_lua.writeFunction("setWHashedPertubation", [](uint32_t pertub) {
1533 setLuaSideEffect();
1534 g_hashperturb = pertub;
1535 });
26a6373d 1536
6bb38cd6
RG
1537 g_lua.writeFunction("setTCPUseSinglePipe", [](bool flag) {
1538 if (g_configurationDone) {
1539 g_outputBuffer="setTCPUseSinglePipe() cannot be used at runtime!\n";
1540 return;
5b8255ba 1541 }
6bb38cd6
RG
1542 setLuaSideEffect();
1543 g_useTCPSinglePipe = flag;
5b8255ba 1544 });
26a6373d 1545
cd4bb56b
PD
1546 g_lua.writeFunction("snmpAgent", [client](bool enableTraps, boost::optional<std::string> masterSocket) {
1547 if(client)
1548 return;
9f4eb5cc 1549#ifdef HAVE_NET_SNMP
6bb38cd6
RG
1550 if (g_configurationDone) {
1551 errlog("snmpAgent() cannot be used at runtime!");
1552 g_outputBuffer="snmpAgent() cannot be used at runtime!\n";
1553 return;
1554 }
1555
1556 if (g_snmpEnabled) {
1557 errlog("snmpAgent() cannot be used twice!");
1558 g_outputBuffer="snmpAgent() cannot be used twice!\n";
1559 return;
9f4eb5cc 1560 }
6bb38cd6
RG
1561
1562 g_snmpEnabled = true;
1563 g_snmpTrapsEnabled = enableTraps;
1564 g_snmpAgent = new DNSDistSNMPAgent("dnsdist", masterSocket ? *masterSocket : std::string());
1565#else
1566 errlog("NET SNMP support is required to use snmpAgent()");
1567 g_outputBuffer="NET SNMP support is required to use snmpAgent()\n";
9f4eb5cc
RG
1568#endif /* HAVE_NET_SNMP */
1569 });
497a6e3a 1570
6bb38cd6 1571 g_lua.writeFunction("sendCustomTrap", [](const std::string& str) {
9f4eb5cc
RG
1572#ifdef HAVE_NET_SNMP
1573 if (g_snmpAgent && g_snmpTrapsEnabled) {
6bb38cd6 1574 g_snmpAgent->sendCustomTrap(str);
9f4eb5cc
RG
1575 }
1576#endif /* HAVE_NET_SNMP */
1577 });
6beb5731 1578
6bb38cd6
RG
1579 g_lua.writeFunction("setPoolServerPolicy", [](ServerPolicy policy, string pool) {
1580 setLuaSideEffect();
1581 auto localPools = g_pools.getCopy();
1582 setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(policy));
1583 g_pools.setState(localPools);
6c1ca990 1584 });
e41f8165 1585
6bb38cd6
RG
1586 g_lua.writeFunction("setPoolServerPolicyLua", [](string name, policyfunc_t policy, string pool) {
1587 setLuaSideEffect();
1588 auto localPools = g_pools.getCopy();
a1b1a29d 1589 setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy, true}));
6bb38cd6 1590 g_pools.setState(localPools);
9396d955
RG
1591 });
1592
6bb38cd6
RG
1593 g_lua.writeFunction("showPoolServerPolicy", [](string pool) {
1594 setLuaSideEffect();
1595 auto localPools = g_pools.getCopy();
1596 auto poolObj = getPool(localPools, pool);
1597 if (poolObj->policy == nullptr) {
1598 g_outputBuffer=g_policy.getLocal()->name+"\n";
9396d955 1599 } else {
6bb38cd6 1600 g_outputBuffer=poolObj->policy->name+"\n";
9396d955
RG
1601 }
1602 });
1603
6bb38cd6
RG
1604 g_lua.writeFunction("setTCPDownstreamCleanupInterval", [](uint16_t interval) {
1605 setLuaSideEffect();
1606 g_downstreamTCPCleanupInterval = interval;
9396d955
RG
1607 });
1608
6bb38cd6
RG
1609 g_lua.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
1610 g_logConsoleConnections = enabled;
e65ae260
RG
1611 });
1612
03c05963
CHB
1613 g_lua.writeFunction("setConsoleOutputMaxMsgSize", [](uint32_t size) {
1614 g_consoleOutputMsgMaxSize = size;
1615 });
1616
6bb38cd6
RG
1617 g_lua.writeFunction("setUDPMultipleMessagesVectorSize", [](size_t vSize) {
1618 if (g_configurationDone) {
1619 errlog("setUDPMultipleMessagesVectorSize() cannot be used at runtime!");
1620 g_outputBuffer="setUDPMultipleMessagesVectorSize() cannot be used at runtime!\n";
1621 return;
2a817e5a 1622 }
6bb38cd6
RG
1623#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
1624 setLuaSideEffect();
1625 g_udpVectorSize = vSize;
1626#else
1627 errlog("recvmmsg() support is not available!");
1628 g_outputBuffer="recvmmsg support is not available!\n";
1629#endif
1630 });
a227f47d 1631
e7c732b8
RG
1632 g_lua.writeFunction("setAddEDNSToSelfGeneratedResponses", [](bool add) {
1633 g_addEDNSToSelfGeneratedResponses = add;
1634 });
1635
1636 g_lua.writeFunction("setPayloadSizeOnSelfGeneratedAnswers", [](uint16_t payloadSize) {
1637 if (payloadSize < 512) {
1638 warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
1639 g_outputBuffer="setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
1640 payloadSize = 512;
1641 }
1642 if (payloadSize > s_udpIncomingBufferSize) {
1643 warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to %d instead!", s_udpIncomingBufferSize);
1644 g_outputBuffer="setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to " + std::to_string(s_udpIncomingBufferSize) + " instead";
1645 payloadSize = s_udpIncomingBufferSize;
1646 }
1647 g_PayloadSizeSelfGenAnswers = payloadSize;
1648 });
1649
5d4e1ef8
RG
1650 g_lua.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
1651 if (g_configurationDone) {
1652 g_outputBuffer="setSecurityPollSuffix() cannot be used at runtime!\n";
1653 return;
1654 }
1655
1656 g_secPollSuffix = suffix;
1657 });
1658
1659 g_lua.writeFunction("setSecurityPollInterval", [](time_t newInterval) {
1660 if (newInterval <= 0) {
1661 warnlog("setSecurityPollInterval() should be > 0, skipping");
1662 g_outputBuffer="setSecurityPollInterval() should be > 0, skipping";
1663 }
1664
1665 g_secPollInterval = newInterval;
1666 });
1667
0ca6a67f
RG
1668 g_lua.writeFunction("setSyslogFacility", [](int facility) {
1669 setLuaSideEffect();
1670 if (g_configurationDone) {
1671 g_outputBuffer="setSyslogFacility cannot be used at runtime!\n";
1672 return;
1673 }
1674 setSyslogFacility(facility);
1675 });
1676
0718e562 1677 g_lua.writeFunction("addDOHLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<boost::variant<std::string, vector<pair<int, std::string> > > > urls, boost::optional<localbind_t> vars) {
56d44226 1678#ifdef HAVE_DNS_OVER_HTTPS
fbf14b03
RG
1679 if (client) {
1680 return;
1681 }
fbf14b03
RG
1682 setLuaSideEffect();
1683 if (g_configurationDone) {
1684 g_outputBuffer="addDOHLocal cannot be used at runtime!\n";
1685 return;
1686 }
1687 auto frontend = std::make_shared<DOHFrontend>();
bf8cd40d
RG
1688
1689 if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_certKeyPairs, certFiles, keyFiles)) {
1690 return;
1691 }
1692
fbf14b03 1693 frontend->d_local = ComboAddress(addr, 443);
0718e562
RG
1694 if (urls) {
1695 if (urls->type() == typeid(std::string)) {
1696 frontend->d_urls.push_back(boost::get<std::string>(*urls));
1697 }
1698 else if (urls->type() == typeid(std::vector<std::pair<int,std::string>>)) {
1699 auto urlsVect = boost::get<std::vector<std::pair<int,std::string>>>(*urls);
1700 for(const auto& p : urlsVect) {
1701 frontend->d_urls.push_back(p.second);
1702 }
fbf14b03
RG
1703 }
1704 }
1705 else {
1706 frontend->d_urls = {"/"};
1707 }
1708
2b0cb8f8
RG
1709 bool reusePort = false;
1710 int tcpFastOpenQueueSize = 0;
1711 std::string interface;
1712 std::set<int> cpus;
2b0cb8f8 1713
fbf14b03 1714 if(vars) {
0230e350 1715 parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
2b0cb8f8 1716
fbf14b03
RG
1717 if (vars->count("idleTimeout")) {
1718 frontend->d_idleTimeout = boost::get<int>((*vars)["idleTimeout"]);
1719 }
6e3a9fe4
RG
1720 if (vars->count("ciphers")) {
1721 frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
1722 }
1723 if (vars->count("ciphersTLS13")) {
1724 frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
1725 }
3d0371b3
RG
1726 if (vars->count("serverTokens")) {
1727 frontend->d_serverTokens = boost::get<const string>((*vars)["serverTokens"]);
1728 }
ee01507f
CR
1729 if (vars->count("customResponseHeaders")) {
1730 for (auto const& headerMap : boost::get<std::map<std::string,std::string>>((*vars)["customResponseHeaders"])) {
1731 std::pair<std::string,std::string> headerResponse = std::make_pair(headerMap.first, headerMap.second);
1732 frontend->d_customResponseHeaders.push_back(headerResponse);
1733 }
1734 }
fbf14b03
RG
1735 }
1736 g_dohlocals.push_back(frontend);
2b0cb8f8 1737 auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_local, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
fbf14b03
RG
1738 cs->dohFrontend = frontend;
1739 g_frontends.push_back(std::move(cs));
1740#else
56d44226 1741 throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
fbf14b03
RG
1742#endif
1743 });
1744
1b51c0f3
RG
1745 g_lua.writeFunction("showDOHFrontends", []() {
1746#ifdef HAVE_DNS_OVER_HTTPS
1747 setLuaNoSideEffect();
1748 try {
1749 ostringstream ret;
1750 boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
1751 ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "TLS 1.0" % "TLS 1.1" % "TLS 1.2" % "TLS 1.3" % "TLS other" % "GET" % "POST" % "Bad" % "Errors" % "Valid") << endl;
1752 size_t counter = 0;
1753 for (const auto& ctx : g_dohlocals) {
5bbcbea0 1754 ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http1Stats.d_nbQueries % ctx->d_tls10queries % ctx->d_tls11queries % ctx->d_tls12queries % ctx->d_tls13queries % ctx->d_tlsUnknownqueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_validresponses) << endl;
1b51c0f3
RG
1755 counter++;
1756 }
1757 g_outputBuffer = ret.str();
1758 }
1759 catch(const std::exception& e) {
1760 g_outputBuffer = e.what();
1761 throw;
1762 }
1763#else
1764 g_outputBuffer="DNS over HTTPS support is not present!\n";
1765#endif
1766 });
1767
5bbcbea0
RG
1768 g_lua.writeFunction("showDOHResponseCodes", []() {
1769#ifdef HAVE_DNS_OVER_HTTPS
1770 setLuaNoSideEffect();
1771 try {
1772 ostringstream ret;
1773 boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d");
1774 g_outputBuffer = "\n- HTTP/1:\n\n";
1775 ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others" ) << endl;
1776 size_t counter = 0;
1777 for (const auto& ctx : g_dohlocals) {
1778 ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_http1Stats.d_nb200Responses % ctx->d_http1Stats.d_nb400Responses % ctx->d_http1Stats.d_nb403Responses % ctx->d_http1Stats.d_nb500Responses % ctx->d_http1Stats.d_nb502Responses % ctx->d_http1Stats.d_nbOtherResponses) << endl;
1779 counter++;
1780 }
1781 g_outputBuffer += ret.str();
1782 ret.str("");
1783
1784 g_outputBuffer += "\n- HTTP/2:\n\n";
1785 ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others" ) << endl;
1786 counter = 0;
1787 for (const auto& ctx : g_dohlocals) {
1788 ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_http2Stats.d_nb200Responses % ctx->d_http2Stats.d_nb400Responses % ctx->d_http2Stats.d_nb403Responses % ctx->d_http2Stats.d_nb500Responses % ctx->d_http2Stats.d_nb502Responses % ctx->d_http2Stats.d_nbOtherResponses) << endl;
1789 counter++;
1790 }
1791 g_outputBuffer += ret.str();
1792 }
1793 catch(const std::exception& e) {
1794 g_outputBuffer = e.what();
1795 throw;
1796 }
1797#else
1798 g_outputBuffer="DNS over HTTPS support is not present!\n";
1799#endif
1800 });
1801
1b51c0f3
RG
1802 g_lua.writeFunction("getDOHFrontend", [](size_t index) {
1803 std::shared_ptr<DOHFrontend> result = nullptr;
1804#ifdef HAVE_DNS_OVER_HTTPS
1805 setLuaNoSideEffect();
1806 try {
1807 if (index < g_dohlocals.size()) {
1808 result = g_dohlocals.at(index);
1809 }
1810 else {
0718e562
RG
1811 errlog("Error: trying to get DOH frontend with index %zu but we only have %zu frontend(s)\n", index, g_dohlocals.size());
1812 g_outputBuffer="Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_dohlocals.size()) + " frontend(s)\n";
1b51c0f3
RG
1813 }
1814 }
1815 catch(const std::exception& e) {
0718e562 1816 g_outputBuffer="Error while trying to get DOH frontend with index " + std::to_string(index) + ": "+string(e.what())+"\n";
56d44226 1817 errlog("Error while trying to get DOH frontend with index %zu: %s\n", index, string(e.what()));
1b51c0f3
RG
1818 }
1819#else
1820 g_outputBuffer="DNS over HTTPS support is not present!\n";
1821#endif
1822 return result;
1823 });
1824
6c7cec08 1825 g_lua.registerFunction<void(std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOHFrontend> frontend) {
1b51c0f3 1826 if (frontend != nullptr) {
6c7cec08 1827 frontend->reloadCertificates();
1b51c0f3
RG
1828 }
1829 });
1830
fa974ada 1831 g_lua.writeFunction("addTLSLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<localbind_t> vars) {
56d44226 1832#ifdef HAVE_DNS_OVER_TLS
a227f47d
RG
1833 if (client)
1834 return;
a227f47d
RG
1835 setLuaSideEffect();
1836 if (g_configurationDone) {
1837 g_outputBuffer="addTLSLocal cannot be used at runtime!\n";
1838 return;
1839 }
1840 shared_ptr<TLSFrontend> frontend = std::make_shared<TLSFrontend>();
fa974ada 1841
bf8cd40d 1842 if (!loadTLSCertificateAndKeys("addTLSLocal", frontend->d_certKeyPairs, certFiles, keyFiles)) {
fa974ada
RG
1843 return;
1844 }
a227f47d 1845
6e9fd124
RG
1846 bool reusePort = false;
1847 int tcpFastOpenQueueSize = 0;
1848 std::string interface;
1849 std::set<int> cpus;
6e9fd124 1850
a227f47d 1851 if (vars) {
0230e350 1852 parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
a227f47d
RG
1853
1854 if (vars->count("provider")) {
1855 frontend->d_provider = boost::get<const string>((*vars)["provider"]);
1856 }
1857
1858 if (vars->count("ciphers")) {
1859 frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
1860 }
1861
9e67ac67
RG
1862 if (vars->count("ciphersTLS13")) {
1863 frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
1864 }
1865
a227f47d
RG
1866 if (vars->count("ticketKeyFile")) {
1867 frontend->d_ticketKeyFile = boost::get<const string>((*vars)["ticketKeyFile"]);
1868 }
1869
1870 if (vars->count("ticketsKeysRotationDelay")) {
c80110cb 1871 frontend->d_ticketsKeyRotationDelay = boost::get<int>((*vars)["ticketsKeysRotationDelay"]);
a227f47d
RG
1872 }
1873
1874 if (vars->count("numberOfTicketsKeys")) {
c80110cb 1875 frontend->d_numberOfTicketsKeys = boost::get<int>((*vars)["numberOfTicketsKeys"]);
a227f47d 1876 }
c8d7b468 1877
ba20dc97
RG
1878 if (vars->count("sessionTickets")) {
1879 frontend->d_enableTickets = boost::get<bool>((*vars)["sessionTickets"]);
c8d7b468 1880 }
d395c941
RG
1881
1882 if (vars->count("numberOfStoredSessions")) {
aa4f798e
RG
1883 auto value = boost::get<int>((*vars)["numberOfStoredSessions"]);
1884 if (value < 0) {
1885 errlog("Invalid value '%d' for addTLSLocal() parameter 'numberOfStoredSessions', should be >= 0, dismissing", value);
1886 g_outputBuffer="Invalid value '" + std::to_string(value) + "' for addTLSLocal() parameter 'numberOfStoredSessions', should be >= 0, dimissing";
1887 return;
1888 }
1889 frontend->d_maxStoredSessions = value;
d395c941 1890 }
a227f47d
RG
1891 }
1892
1893 try {
1894 frontend->d_addr = ComboAddress(addr, 853);
1895 vinfolog("Loading TLS provider %s", frontend->d_provider);
6e9fd124
RG
1896 // only works pre-startup, so no sync necessary
1897 auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
1898 cs->tlsFrontend = frontend;
1899 g_tlslocals.push_back(cs->tlsFrontend);
1900 g_frontends.push_back(std::move(cs));
a227f47d
RG
1901 }
1902 catch(const std::exception& e) {
1903 g_outputBuffer="Error: "+string(e.what())+"\n";
1904 }
1905#else
56d44226 1906 throw std::runtime_error("addTLSLocal() called but DNS over TLS support is not present!");
a227f47d
RG
1907#endif
1908 });
1909
7f2f825d 1910 g_lua.writeFunction("showTLSContexts", []() {
a227f47d
RG
1911#ifdef HAVE_DNS_OVER_TLS
1912 setLuaNoSideEffect();
1913 try {
1914 ostringstream ret;
1915 boost::format fmt("%1$-3d %2$-20.20s %|25t|%3$-14d %|40t|%4$-14d %|54t|%5$-21.21s");
1916 // 1 2 3 4 5
1917 ret << (fmt % "#" % "Address" % "# ticket keys" % "Rotation delay" % "Next rotation" ) << endl;
1918 size_t counter = 0;
1919 for (const auto& ctx : g_tlslocals) {
1920 ret << (fmt % counter % ctx->d_addr.toStringWithPort() % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
1921 counter++;
1922 }
1923 g_outputBuffer = ret.str();
1924 }
1925 catch(const std::exception& e) {
1926 g_outputBuffer = e.what();
1927 throw;
1928 }
1929#else
1930 g_outputBuffer="DNS over TLS support is not present!\n";
1931#endif
1932 });
1933
7f2f825d 1934 g_lua.writeFunction("getTLSContext", [](size_t index) {
a227f47d
RG
1935 std::shared_ptr<TLSCtx> result = nullptr;
1936#ifdef HAVE_DNS_OVER_TLS
1937 setLuaNoSideEffect();
1938 try {
1939 if (index < g_tlslocals.size()) {
1940 result = g_tlslocals.at(index)->getContext();
1941 }
1942 else {
0718e562
RG
1943 errlog("Error: trying to get TLS context with index %zu but we only have %zu context(s)\n", index, g_tlslocals.size());
1944 g_outputBuffer="Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " context(s)\n";
a227f47d
RG
1945 }
1946 }
1947 catch(const std::exception& e) {
0718e562
RG
1948 g_outputBuffer="Error while trying to get TLS context with index " + std::to_string(index) + ": "+string(e.what())+"\n";
1949 errlog("Error while trying to get TLS context with index %zu: %s\n", index, string(e.what()));
a227f47d
RG
1950 }
1951#else
1952 g_outputBuffer="DNS over TLS support is not present!\n";
1953#endif
1954 return result;
1955 });
1956
8ef43a02
RG
1957 g_lua.writeFunction("getTLSFrontend", [](size_t index) {
1958 std::shared_ptr<TLSFrontend> result = nullptr;
1959#ifdef HAVE_DNS_OVER_TLS
1960 setLuaNoSideEffect();
1961 try {
1962 if (index < g_tlslocals.size()) {
1963 result = g_tlslocals.at(index);
1964 }
1965 else {
0718e562
RG
1966 errlog("Error: trying to get TLS frontend with index %zu but we only have %zu frontends\n", index, g_tlslocals.size());
1967 g_outputBuffer="Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " frontend(s)\n";
8ef43a02
RG
1968 }
1969 }
1970 catch(const std::exception& e) {
0718e562
RG
1971 g_outputBuffer="Error while trying to get TLS frontend with index " + std::to_string(index) + ": "+string(e.what())+"\n";
1972 errlog("Error while trying to get TLS frontend with index %zu: %s\n", index, string(e.what()));
8ef43a02
RG
1973 }
1974#else
1975 g_outputBuffer="DNS over TLS support is not present!\n";
1976#endif
1977 return result;
1978 });
1979
a227f47d
RG
1980 g_lua.registerFunction<void(std::shared_ptr<TLSCtx>::*)()>("rotateTicketsKey", [](std::shared_ptr<TLSCtx> ctx) {
1981 if (ctx != nullptr) {
1982 ctx->rotateTicketsKey(time(nullptr));
1983 }
1984 });
1985
1986 g_lua.registerFunction<void(std::shared_ptr<TLSCtx>::*)(const std::string&)>("loadTicketsKeys", [](std::shared_ptr<TLSCtx> ctx, const std::string& file) {
1987 if (ctx != nullptr) {
1988 ctx->loadTicketsKeys(file);
1989 }
1990 });
8ef43a02
RG
1991
1992 g_lua.registerFunction<void(std::shared_ptr<TLSFrontend>::*)(boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles) {
9ce6a273 1993#ifdef HAVE_DNS_OVER_TLS
bf8cd40d 1994 if (loadTLSCertificateAndKeys("loadNewCertificatesAndKeys", frontend->d_certKeyPairs, certFiles, keyFiles)) {
8ef43a02
RG
1995 frontend->setupTLS();
1996 }
9ce6a273 1997#endif
8ef43a02 1998 });
0dffe9e3 1999
bcc62bfb
RG
2000 g_lua.writeFunction("reloadAllCertificates", []() {
2001 for (auto& frontend : g_frontends) {
2002 if (!frontend) {
2003 continue;
2004 }
2005 try {
2006#ifdef HAVE_DNSCRYPT
2007 if (frontend->dnscryptCtx) {
37b6d73d 2008 frontend->dnscryptCtx->reloadCertificates();
bcc62bfb
RG
2009 }
2010#endif /* HAVE_DNSCRYPT */
2011#ifdef HAVE_DNS_OVER_TLS
2012 if (frontend->tlsFrontend) {
2013 frontend->tlsFrontend->setupTLS();
2014 }
2015#endif /* HAVE_DNS_OVER_TLS */
6e3a9fe4
RG
2016#ifdef HAVE_DNS_OVER_HTTPS
2017 if (frontend->dohFrontend) {
6c7cec08 2018 frontend->dohFrontend->reloadCertificates();
6e3a9fe4
RG
2019 }
2020#endif /* HAVE_DNS_OVER_HTTPS */
bcc62bfb
RG
2021 }
2022 catch(const std::exception& e) {
2023 errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what());
2024 }
2025 }
2026 });
2027
2028 g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
6bb38cd6 2029}
2a817e5a 2030
6bb38cd6
RG
2031vector<std::function<void(void)>> setupLua(bool client, const std::string& config)
2032{
2033 g_launchWork= new vector<std::function<void(void)>>();
2a817e5a 2034
6bb38cd6
RG
2035 setupLuaActions();
2036 setupLuaConfig(client);
2037 setupLuaBindings(client);
2038 setupLuaBindingsDNSQuestion();
2039 setupLuaInspection();
2040 setupLuaRules();
2041 setupLuaVars();
80a216c9 2042
839f3021 2043 std::ifstream ifs(config);
6bb38cd6 2044 if(!ifs)
839f3021 2045 warnlog("Unable to read configuration from '%s'", config);
2e72cc0e 2046 else
cdc04ede 2047 vinfolog("Read configuration from '%s'", config);
df111b53 2048
2049 g_lua.executeCode(ifs);
d8c19b98 2050
6bb38cd6 2051 auto ret = *g_launchWork;
2e72cc0e 2052 delete g_launchWork;
6bb38cd6 2053 g_launchWork = nullptr;
2e72cc0e 2054 return ret;
df111b53 2055}