]>
Commit | Line | Data |
---|---|---|
12471842 PL |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
ea0aa517 | 22 | #include "dnsdist.hh" |
886e2cf2 | 23 | #include "dnsdist-cache.hh" |
ea0aa517 | 24 | #include "dnsrulactions.hh" |
25 | #include <thread> | |
26 | #include "dolog.hh" | |
27 | #include "sodcrypto.hh" | |
28 | #include "base64.hh" | |
0e41337b | 29 | #include "lock.hh" |
85c7ca75 | 30 | #include "gettime.hh" |
ea0aa517 | 31 | #include <map> |
32 | #include <fstream> | |
f758857a | 33 | #include <boost/logic/tribool.hpp> |
71c94675 | 34 | #include "statnode.hh" |
69389510 RG |
35 | #include <sys/types.h> |
36 | #include <dirent.h> | |
37 | #include <sys/stat.h> | |
38 | #include <unistd.h> | |
f758857a | 39 | |
cf48b0ce RG |
40 | #include "dnsdist-lua.hh" |
41 | ||
f758857a | 42 | boost::tribool g_noLuaSideEffect; |
69389510 | 43 | static bool g_included{false}; |
f758857a | 44 | |
45 | /* this is a best effort way to prevent logging calls with no side-effects in the output of delta() | |
46 | Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing | |
47 | has done so before on this invocation, this call won't be part of delta() output */ | |
48 | void setLuaNoSideEffect() | |
49 | { | |
50 | if(g_noLuaSideEffect==false) // there has been a side effect already | |
51 | return; | |
52 | g_noLuaSideEffect=true; | |
53 | } | |
54 | ||
55 | void setLuaSideEffect() | |
56 | { | |
57 | g_noLuaSideEffect=false; | |
58 | } | |
59 | ||
60 | bool getLuaNoSideEffect() | |
61 | { | |
62 | return g_noLuaSideEffect==true; | |
63 | } | |
64 | ||
65 | void resetLuaSideEffect() | |
66 | { | |
67 | g_noLuaSideEffect = boost::logic::indeterminate; | |
68 | } | |
ea0aa517 | 69 | |
ea0aa517 | 70 | map<ComboAddress,int> filterScore(const map<ComboAddress, unsigned int,ComboAddress::addressOnlyLessThan >& counts, |
479a5404 | 71 | double delta, int rate) |
ea0aa517 | 72 | { |
73 | std::multimap<unsigned int,ComboAddress> score; | |
74 | for(const auto& e : counts) | |
75 | score.insert({e.second, e.first}); | |
76 | ||
77 | map<ComboAddress,int> ret; | |
78 | ||
ea0aa517 | 79 | double lim = delta*rate; |
ea0aa517 | 80 | for(auto s = score.crbegin(); s != score.crend() && s->first > lim; ++s) { |
81 | ret[s->second]=s->first; | |
82 | } | |
83 | return ret; | |
84 | } | |
85 | ||
86 | ||
71c94675 | 87 | typedef std::function<void(const StatNode&, const StatNode::Stat&, const StatNode::Stat&)> statvisitor_t; |
88 | ||
26b86deb | 89 | static void statNodeRespRing(statvisitor_t visitor, unsigned int seconds) |
71c94675 | 90 | { |
26b86deb RG |
91 | struct timespec cutoff, now; |
92 | gettime(&now); | |
93 | if (seconds) { | |
94 | cutoff = now; | |
95 | cutoff.tv_sec -= seconds; | |
96 | } | |
97 | ||
71c94675 | 98 | std::lock_guard<std::mutex> lock(g_rings.respMutex); |
99 | ||
100 | StatNode root; | |
101 | for(const auto& c : g_rings.respRing) { | |
26b86deb RG |
102 | if (now < c.when) |
103 | continue; | |
104 | ||
105 | if (seconds && c.when < cutoff) | |
106 | continue; | |
107 | ||
71c94675 | 108 | root.submit(c.name, c.dh.rcode, c.requestor); |
109 | } | |
110 | StatNode::Stat node; | |
803d4b5d | 111 | |
af619119 RG |
112 | root.visit([&visitor](const StatNode* node_, const StatNode::Stat& self, const StatNode::Stat& children) { |
113 | visitor(*node_, self, children);}, node); | |
71c94675 | 114 | |
115 | } | |
116 | ||
117 | vector<pair<unsigned int, std::unordered_map<string,string> > > getRespRing(boost::optional<int> rcode) | |
118 | { | |
119 | typedef std::unordered_map<string,string> entry_t; | |
120 | vector<pair<unsigned int, entry_t > > ret; | |
121 | std::lock_guard<std::mutex> lock(g_rings.respMutex); | |
122 | ||
123 | entry_t e; | |
124 | unsigned int count=1; | |
125 | for(const auto& c : g_rings.respRing) { | |
126 | if(rcode && (rcode.get() != c.dh.rcode)) | |
127 | continue; | |
128 | e["qname"]=c.name.toString(); | |
129 | e["rcode"]=std::to_string(c.dh.rcode); | |
130 | ret.push_back(std::make_pair(count,e)); | |
131 | count++; | |
132 | } | |
133 | return ret; | |
134 | } | |
135 | ||
ea0aa517 | 136 | typedef map<ComboAddress, unsigned int,ComboAddress::addressOnlyLessThan > counts_t; |
137 | map<ComboAddress,int> exceedRespGen(int rate, int seconds, std::function<void(counts_t&, const Rings::Response&)> T) | |
138 | { | |
139 | counts_t counts; | |
479a5404 | 140 | struct timespec cutoff, mintime, now; |
85c7ca75 | 141 | gettime(&now); |
479a5404 | 142 | cutoff = mintime = now; |
ea0aa517 | 143 | cutoff.tv_sec -= seconds; |
5d9f9650 RG |
144 | |
145 | std::lock_guard<std::mutex> lock(g_rings.respMutex); | |
ea0aa517 | 146 | for(const auto& c : g_rings.respRing) { |
147 | if(seconds && c.when < cutoff) | |
148 | continue; | |
479a5404 | 149 | if(now < c.when) |
150 | continue; | |
ea0aa517 | 151 | |
152 | T(counts, c); | |
153 | if(c.when < mintime) | |
154 | mintime = c.when; | |
155 | } | |
479a5404 | 156 | double delta = seconds ? seconds : DiffTime(now, mintime); |
157 | return filterScore(counts, delta, rate); | |
ea0aa517 | 158 | } |
159 | ||
0ba5eecf | 160 | map<ComboAddress,int> exceedQueryGen(int rate, int seconds, std::function<void(counts_t&, const Rings::Query&)> T) |
161 | { | |
162 | counts_t counts; | |
479a5404 | 163 | struct timespec cutoff, mintime, now; |
85c7ca75 | 164 | gettime(&now); |
479a5404 | 165 | cutoff = mintime = now; |
0ba5eecf | 166 | cutoff.tv_sec -= seconds; |
479a5404 | 167 | |
0e41337b | 168 | ReadLock rl(&g_rings.queryLock); |
0ba5eecf | 169 | for(const auto& c : g_rings.queryRing) { |
170 | if(seconds && c.when < cutoff) | |
171 | continue; | |
479a5404 | 172 | if(now < c.when) |
173 | continue; | |
0ba5eecf | 174 | T(counts, c); |
175 | if(c.when < mintime) | |
176 | mintime = c.when; | |
177 | } | |
479a5404 | 178 | double delta = seconds ? seconds : DiffTime(now, mintime); |
179 | return filterScore(counts, delta, rate); | |
0ba5eecf | 180 | } |
181 | ||
ea0aa517 | 182 | |
183 | map<ComboAddress,int> exceedRCode(int rate, int seconds, int rcode) | |
184 | { | |
185 | return exceedRespGen(rate, seconds, [rcode](counts_t& counts, const Rings::Response& r) | |
186 | { | |
3fcaeeac | 187 | if(r.dh.rcode == rcode) |
ea0aa517 | 188 | counts[r.requestor]++; |
189 | }); | |
190 | } | |
191 | ||
192 | map<ComboAddress,int> exceedRespByterate(int rate, int seconds) | |
193 | { | |
194 | return exceedRespGen(rate, seconds, [](counts_t& counts, const Rings::Response& r) | |
195 | { | |
196 | counts[r.requestor]+=r.size; | |
197 | }); | |
198 | } | |
199 | ||
79500db5 RG |
200 | #ifdef HAVE_DNSCRYPT |
201 | static bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DnsCryptCert& certOut, DnsCryptPrivateKey& keyOut) | |
202 | { | |
203 | bool success = false; | |
204 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
205 | sodium_mlock(providerPrivateKey, sizeof(providerPrivateKey)); | |
206 | sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey)); | |
207 | ||
208 | try { | |
209 | ifstream providerKStream(providerPrivateKeyFile); | |
210 | providerKStream.read((char*) providerPrivateKey, sizeof(providerPrivateKey)); | |
211 | if (providerKStream.fail()) { | |
212 | providerKStream.close(); | |
213 | throw std::runtime_error("Invalid DNSCrypt provider key file " + providerPrivateKeyFile); | |
214 | } | |
215 | ||
216 | DnsCryptContext::generateCertificate(serial, begin, end, providerPrivateKey, keyOut, certOut); | |
217 | success = true; | |
218 | } | |
219 | catch(const std::exception& e) { | |
220 | errlog(e.what()); | |
221 | } | |
ea0aa517 | 222 | |
79500db5 RG |
223 | sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey)); |
224 | sodium_munlock(providerPrivateKey, sizeof(providerPrivateKey)); | |
225 | return success; | |
226 | } | |
227 | #endif /* HAVE_DNSCRYPT */ | |
71c94675 | 228 | |
886e2cf2 | 229 | void moreLua(bool client) |
ea0aa517 | 230 | { |
78ffa782 | 231 | typedef NetmaskTree<DynBlock> nmts_t; |
ea0aa517 | 232 | g_lua.writeFunction("newCA", [](const std::string& name) { return ComboAddress(name); }); |
68e82cf9 | 233 | |
68e82cf9 | 234 | g_lua.writeFunction("newNMG", []() { return NetmaskGroup(); }); |
235 | g_lua.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask) | |
7a25c01b RG |
236 | { |
237 | nmg.addMask(mask); | |
238 | }); | |
1b096265 | 239 | g_lua.registerFunction<void(NetmaskGroup::*)(const std::map<ComboAddress,int>& map)>("addMasks", [](NetmaskGroup&nmg, const std::map<ComboAddress,int>& map) |
7a25c01b RG |
240 | { |
241 | for (const auto& entry : map) { | |
242 | nmg.addMask(Netmask(entry.first)); | |
243 | } | |
244 | }); | |
68e82cf9 | 245 | |
246 | g_lua.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match); | |
247 | g_lua.registerFunction("size", &NetmaskGroup::size); | |
248 | g_lua.registerFunction("clear", &NetmaskGroup::clear); | |
249 | ||
bd1c631b | 250 | |
6da5d988 | 251 | g_lua.writeFunction("showDynBlocks", []() { |
f758857a | 252 | setLuaNoSideEffect(); |
6da5d988 | 253 | auto slow = g_dynblockNMG.getCopy(); |
78ffa782 | 254 | struct timespec now; |
85c7ca75 | 255 | gettime(&now); |
8d774826 | 256 | boost::format fmt("%-24s %8d %8d %s\n"); |
71c94675 | 257 | g_outputBuffer = (fmt % "What" % "Seconds" % "Blocks" % "Reason").str(); |
6da5d988 | 258 | for(const auto& e: slow) { |
78ffa782 | 259 | if(now < e->second.until) |
8d774826 | 260 | g_outputBuffer+= (fmt % e->first.toString() % (e->second.until.tv_sec - now.tv_sec) % e->second.blocks % e->second.reason).str(); |
6da5d988 | 261 | } |
71c94675 | 262 | auto slow2 = g_dynblockSMT.getCopy(); |
263 | slow2.visit([&now, &fmt](const SuffixMatchTree<DynBlock>& node) { | |
264 | if(now <node.d_value.until) { | |
265 | string dom("empty"); | |
266 | if(!node.d_value.domain.empty()) | |
267 | dom = node.d_value.domain.toString(); | |
268 | g_outputBuffer+= (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % node.d_value.reason).str(); | |
269 | } | |
270 | }); | |
271 | ||
6da5d988 | 272 | }); |
273 | ||
78ffa782 | 274 | g_lua.writeFunction("clearDynBlocks", []() { |
f758857a | 275 | setLuaSideEffect(); |
78ffa782 | 276 | nmts_t nmg; |
277 | g_dynblockNMG.setState(nmg); | |
71c94675 | 278 | SuffixMatchTree<DynBlock> smt; |
279 | g_dynblockSMT.setState(smt); | |
78ffa782 | 280 | }); |
281 | ||
282 | g_lua.writeFunction("addDynBlocks", | |
7b925432 | 283 | [](const map<ComboAddress,int>& m, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) { |
f758857a | 284 | setLuaSideEffect(); |
78ffa782 | 285 | auto slow = g_dynblockNMG.getCopy(); |
94b44bfa | 286 | struct timespec until, now; |
85c7ca75 | 287 | gettime(&now); |
94b44bfa | 288 | until=now; |
32c99b3d | 289 | int actualSeconds = seconds ? *seconds : 10; |
290 | until.tv_sec += actualSeconds; | |
94b44bfa | 291 | for(const auto& capair : m) { |
8d06661a | 292 | unsigned int count = 0; |
bac6e8fb | 293 | auto got = slow.lookup(Netmask(capair.first)); |
e126e7dd | 294 | bool expired=false; |
bac6e8fb | 295 | if(got) { |
94b44bfa | 296 | if(until < got->second.until) // had a longer policy |
297 | continue; | |
e126e7dd | 298 | if(now < got->second.until) // only inherit count on fresh query we are extending |
94b44bfa | 299 | count=got->second.blocks; |
e126e7dd | 300 | else |
301 | expired=true; | |
94b44bfa | 302 | } |
7b925432 | 303 | DynBlock db{msg,until,DNSName(),(action ? *action : DNSAction::Action::None)}; |
94b44bfa | 304 | db.blocks=count; |
e126e7dd | 305 | if(!got || expired) |
bac6e8fb | 306 | warnlog("Inserting dynamic block for %s for %d seconds: %s", capair.first.toString(), actualSeconds, msg); |
94b44bfa | 307 | slow.insert(Netmask(capair.first)).second=db; |
308 | } | |
78ffa782 | 309 | g_dynblockNMG.setState(slow); |
310 | }); | |
311 | ||
71c94675 | 312 | g_lua.writeFunction("addDynBlockSMT", |
7b925432 | 313 | [](const vector<pair<unsigned int, string> >&names, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) { |
71c94675 | 314 | setLuaSideEffect(); |
315 | auto slow = g_dynblockSMT.getCopy(); | |
316 | struct timespec until, now; | |
317 | gettime(&now); | |
318 | until=now; | |
319 | int actualSeconds = seconds ? *seconds : 10; | |
320 | until.tv_sec += actualSeconds; | |
321 | ||
322 | for(const auto& capair : names) { | |
323 | unsigned int count = 0; | |
324 | DNSName domain(capair.second); | |
325 | auto got = slow.lookup(domain); | |
326 | bool expired=false; | |
327 | if(got) { | |
328 | if(until < got->until) // had a longer policy | |
329 | continue; | |
330 | if(now < got->until) // only inherit count on fresh query we are extending | |
331 | count=got->blocks; | |
332 | else | |
333 | expired=true; | |
334 | } | |
335 | ||
7b925432 | 336 | DynBlock db{msg,until,domain,(action ? *action : DNSAction::Action::None)}; |
71c94675 | 337 | db.blocks=count; |
338 | if(!got || expired) | |
339 | warnlog("Inserting dynamic block for %s for %d seconds: %s", domain, actualSeconds, msg); | |
340 | slow.add(domain, db); | |
341 | } | |
342 | g_dynblockSMT.setState(slow); | |
343 | }); | |
344 | ||
dd46e5e3 RG |
345 | g_lua.writeFunction("setDynBlocksAction", [](DNSAction::Action action) { |
346 | if (!g_configurationDone) { | |
c4f5aeff | 347 | if (action == DNSAction::Action::Drop || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate) { |
dd46e5e3 RG |
348 | g_dynBlockAction = action; |
349 | } | |
350 | else { | |
c4f5aeff RG |
351 | errlog("Dynamic blocks action can only be Drop, Refused or Truncate!"); |
352 | g_outputBuffer="Dynamic blocks action can only be Drop, Refused or Truncate!\n"; | |
dd46e5e3 RG |
353 | } |
354 | } else { | |
355 | g_outputBuffer="Dynamic blocks action cannot be altered at runtime!\n"; | |
356 | } | |
357 | }); | |
78ffa782 | 358 | |
6da5d988 | 359 | g_lua.registerFunction<bool(nmts_t::*)(const ComboAddress&)>("match", |
360 | [](nmts_t& s, const ComboAddress& ca) { return s.match(ca); }); | |
ea0aa517 | 361 | |
f8d85d5b | 362 | g_lua.writeFunction("exceedServFails", [](unsigned int rate, int seconds) { |
f758857a | 363 | setLuaNoSideEffect(); |
ea0aa517 | 364 | return exceedRCode(rate, seconds, RCode::ServFail); |
365 | }); | |
366 | g_lua.writeFunction("exceedNXDOMAINs", [](unsigned int rate, int seconds) { | |
f758857a | 367 | setLuaNoSideEffect(); |
ea0aa517 | 368 | return exceedRCode(rate, seconds, RCode::NXDomain); |
369 | }); | |
370 | ||
0ba5eecf | 371 | |
372 | ||
ea0aa517 | 373 | g_lua.writeFunction("exceedRespByterate", [](unsigned int rate, int seconds) { |
f758857a | 374 | setLuaNoSideEffect(); |
ea0aa517 | 375 | return exceedRespByterate(rate, seconds); |
376 | }); | |
377 | ||
0ba5eecf | 378 | g_lua.writeFunction("exceedQTypeRate", [](uint16_t type, unsigned int rate, int seconds) { |
f758857a | 379 | setLuaNoSideEffect(); |
0ba5eecf | 380 | return exceedQueryGen(rate, seconds, [type](counts_t& counts, const Rings::Query& q) { |
381 | if(q.qtype==type) | |
382 | counts[q.requestor]++; | |
383 | }); | |
bac6e8fb | 384 | }); |
0ba5eecf | 385 | |
bac6e8fb | 386 | g_lua.writeFunction("exceedQRate", [](unsigned int rate, int seconds) { |
387 | setLuaNoSideEffect(); | |
388 | return exceedQueryGen(rate, seconds, [](counts_t& counts, const Rings::Query& q) { | |
389 | counts[q.requestor]++; | |
390 | }); | |
0ba5eecf | 391 | }); |
392 | ||
71c94675 | 393 | g_lua.writeFunction("getRespRing", getRespRing); |
394 | ||
395 | g_lua.registerFunction<StatNode, unsigned int()>("numChildren", | |
396 | [](StatNode& sn) -> unsigned int { | |
397 | ||
398 | return sn.children.size(); | |
399 | } ); | |
400 | ||
401 | g_lua.registerMember("fullname", &StatNode::fullname); | |
431c4359 | 402 | g_lua.registerMember("labelsCount", &StatNode::labelsCount); |
71c94675 | 403 | g_lua.registerMember("servfails", &StatNode::Stat::servfails); |
404 | g_lua.registerMember("nxdomains", &StatNode::Stat::nxdomains); | |
405 | g_lua.registerMember("queries", &StatNode::Stat::queries); | |
406 | ||
26b86deb RG |
407 | g_lua.writeFunction("statNodeRespRing", [](statvisitor_t visitor, boost::optional<unsigned int> seconds) { |
408 | statNodeRespRing(visitor, seconds ? *seconds : 0); | |
409 | }); | |
bac6e8fb | 410 | |
7fc00937 | 411 | g_lua.writeFunction("getTopBandwidth", [](unsigned int top) { |
f758857a | 412 | setLuaNoSideEffect(); |
7fc00937 | 413 | return g_rings.getTopBandwidth(top); |
ddafcf1e | 414 | }); |
7fc00937 | 415 | g_lua.executeCode(R"(function topBandwidth(top) top = top or 10; for k,v in ipairs(getTopBandwidth(top)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)"); |
77f8ae1a | 416 | |
f758857a | 417 | g_lua.writeFunction("delta", []() { |
418 | setLuaNoSideEffect(); | |
419 | // we hold the lua lock already! | |
420 | for(const auto& d : g_confDelta) { | |
421 | struct tm tm; | |
422 | localtime_r(&d.first.tv_sec, &tm); | |
423 | char date[80]; | |
171fca9a | 424 | strftime(date, sizeof(date)-1, "-- %a %b %d %Y %H:%M:%S %Z\n", &tm); |
f758857a | 425 | g_outputBuffer += date; |
426 | g_outputBuffer += d.second + "\n"; | |
427 | } | |
428 | }); | |
429 | ||
2a05b4a9 | 430 | g_lua.writeFunction("grepq", [](boost::variant<string, vector<pair<int,string> > > inp, boost::optional<unsigned int> limit) { |
f0ff4ec2 | 431 | setLuaNoSideEffect(); |
77f8ae1a | 432 | boost::optional<Netmask> nm; |
433 | boost::optional<DNSName> dn; | |
2a05b4a9 | 434 | int msec=-1; |
435 | ||
436 | vector<string> vec; | |
437 | auto str=boost::get<string>(&inp); | |
438 | if(str) | |
439 | vec.push_back(*str); | |
440 | else { | |
441 | auto v = boost::get<vector<pair<int, string> > >(inp); | |
442 | for(const auto& a: v) | |
443 | vec.push_back(a.second); | |
77f8ae1a | 444 | } |
2a05b4a9 | 445 | |
446 | for(const auto& s : vec) { | |
447 | try | |
448 | { | |
449 | nm = Netmask(s); | |
450 | } | |
451 | catch(...) { | |
452 | if(boost::ends_with(s,"ms") && sscanf(s.c_str(), "%ums", &msec)) { | |
453 | ; | |
454 | } | |
455 | else { | |
456 | try { dn=DNSName(s); } | |
457 | catch(...) | |
458 | { | |
459 | g_outputBuffer = "Could not parse '"+s+"' as domain name or netmask"; | |
460 | return; | |
461 | } | |
462 | } | |
2d11d1b2 | 463 | } |
77f8ae1a | 464 | } |
465 | ||
466 | decltype(g_rings.queryRing) qr; | |
467 | decltype(g_rings.respRing) rr; | |
468 | { | |
469 | ReadLock rl(&g_rings.queryLock); | |
470 | qr=g_rings.queryRing; | |
471 | } | |
b049c29b | 472 | sort(qr.begin(), qr.end(), [](const decltype(qr)::value_type& a, const decltype(qr)::value_type& b) { |
473 | return b.when < a.when; | |
474 | }); | |
77f8ae1a | 475 | { |
476 | std::lock_guard<std::mutex> lock(g_rings.respMutex); | |
477 | rr=g_rings.respRing; | |
478 | } | |
b049c29b | 479 | |
480 | sort(rr.begin(), rr.end(), [](const decltype(rr)::value_type& a, const decltype(rr)::value_type& b) { | |
481 | return b.when < a.when; | |
482 | }); | |
77f8ae1a | 483 | |
484 | unsigned int num=0; | |
485 | struct timespec now; | |
85c7ca75 | 486 | gettime(&now); |
b049c29b | 487 | |
77f8ae1a | 488 | std::multimap<struct timespec, string> out; |
3fcaeeac | 489 | |
2a05b4a9 | 490 | boost::format fmt("%-7.1f %-47s %-12s %-5d %-25s %-5s %-6.1f %-2s %-2s %-2s %s\n"); |
2d11d1b2 | 491 | g_outputBuffer+= (fmt % "Time" % "Client" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str(); |
3fcaeeac | 492 | |
2a05b4a9 | 493 | if(msec==-1) { |
494 | for(const auto& c : qr) { | |
495 | bool nmmatch=true, dnmatch=true; | |
496 | if(nm) | |
497 | nmmatch = nm->match(c.requestor); | |
498 | if(dn) | |
499 | dnmatch = c.name.isPartOf(*dn); | |
500 | if(nmmatch && dnmatch) { | |
501 | QType qt(c.qtype); | |
502 | out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % "" % htons(c.dh.id) % c.name.toString() % qt.getName() % "" % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % "Question").str() )) ; | |
503 | ||
504 | if(limit && *limit==++num) | |
505 | break; | |
506 | } | |
77f8ae1a | 507 | } |
508 | } | |
509 | num=0; | |
510 | ||
3fcaeeac | 511 | |
d68acc7a | 512 | string extra; |
77f8ae1a | 513 | for(const auto& c : rr) { |
2a05b4a9 | 514 | bool nmmatch=true, dnmatch=true, msecmatch=true; |
515 | if(nm) | |
516 | nmmatch = nm->match(c.requestor); | |
517 | if(dn) | |
518 | dnmatch = c.name.isPartOf(*dn); | |
519 | if(msec != -1) | |
520 | msecmatch=(c.usec/1000 > (unsigned int)msec); | |
521 | ||
522 | if(nmmatch && dnmatch && msecmatch) { | |
77f8ae1a | 523 | QType qt(c.qtype); |
d68acc7a | 524 | if(!c.dh.rcode) |
525 | extra=". " +std::to_string(htons(c.dh.ancount))+ " answers"; | |
526 | else | |
527 | extra.clear(); | |
2d11d1b2 | 528 | if(c.usec != std::numeric_limits<decltype(c.usec)>::max()) |
529 | out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % c.ds.toStringWithPort() % htons(c.dh.id) % c.name.toString() % qt.getName() % (c.usec/1000.0) % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % (RCode::to_s(c.dh.rcode) + extra)).str() )) ; | |
530 | else | |
531 | out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % c.ds.toStringWithPort() % htons(c.dh.id) % c.name.toString() % qt.getName() % "T.O" % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % (RCode::to_s(c.dh.rcode) + extra)).str() )) ; | |
77f8ae1a | 532 | |
533 | if(limit && *limit==++num) | |
534 | break; | |
535 | } | |
536 | } | |
537 | ||
538 | for(const auto& p : out) { | |
539 | g_outputBuffer+=p.second; | |
77f8ae1a | 540 | } |
541 | }); | |
11e1e08b | 542 | |
efd35aa8 | 543 | g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, const std::string& certFile, const std::string keyFile, boost::optional<localbind_t> vars) { |
11e1e08b RG |
544 | if (g_configurationDone) { |
545 | g_outputBuffer="addDNSCryptBind cannot be used at runtime!\n"; | |
546 | return; | |
547 | } | |
548 | #ifdef HAVE_DNSCRYPT | |
efd35aa8 RG |
549 | bool doTCP = true; |
550 | bool reusePort = false; | |
551 | int tcpFastOpenQueueSize = 0; | |
552 | std::string interface; | |
553 | ||
554 | parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface); | |
555 | ||
11e1e08b RG |
556 | try { |
557 | DnsCryptContext ctx(providerName, certFile, keyFile); | |
efd35aa8 | 558 | g_dnsCryptLocals.push_back(std::make_tuple(ComboAddress(addr, 443), ctx, reusePort, tcpFastOpenQueueSize, interface)); |
11e1e08b RG |
559 | } |
560 | catch(std::exception& e) { | |
561 | errlog(e.what()); | |
562 | g_outputBuffer="Error: "+string(e.what())+"\n"; | |
563 | } | |
564 | #else | |
565 | g_outputBuffer="Error: DNSCrypt support is not enabled.\n"; | |
566 | #endif | |
567 | }); | |
568 | ||
569 | g_lua.writeFunction("showDNSCryptBinds", []() { | |
570 | setLuaNoSideEffect(); | |
571 | #ifdef HAVE_DNSCRYPT | |
572 | ostringstream ret; | |
573 | boost::format fmt("%1$-3d %2% %|25t|%3$-20.20s %|26t|%4$-8d %|35t|%5$-21.21s %|56t|%6$-9d %|66t|%7$-21.21s" ); | |
574 | ret << (fmt % "#" % "Address" % "Provider Name" % "Serial" % "Validity" % "P. Serial" % "P. Validity") << endl; | |
575 | size_t idx = 0; | |
576 | ||
577 | for (const auto& local : g_dnsCryptLocals) { | |
4c34246d | 578 | const DnsCryptContext& ctx = std::get<1>(local); |
79500db5 | 579 | bool const hasOldCert = ctx.hasOldCertificate(); |
11e1e08b RG |
580 | const DnsCryptCert& cert = ctx.getCurrentCertificate(); |
581 | const DnsCryptCert& oldCert = ctx.getOldCertificate(); | |
582 | ||
4c34246d | 583 | ret<< (fmt % idx % std::get<0>(local).toStringWithPort() % ctx.getProviderName() % cert.signedData.serial % DnsCryptContext::certificateDateToStr(cert.signedData.tsEnd) % (hasOldCert ? oldCert.signedData.serial : 0) % (hasOldCert ? DnsCryptContext::certificateDateToStr(oldCert.signedData.tsEnd) : "-")) << endl; |
11e1e08b RG |
584 | idx++; |
585 | } | |
586 | ||
587 | g_outputBuffer=ret.str(); | |
588 | #else | |
589 | g_outputBuffer="Error: DNSCrypt support is not enabled.\n"; | |
590 | #endif | |
591 | }); | |
592 | ||
79500db5 RG |
593 | g_lua.writeFunction("getDNSCryptBind", [client](size_t idx) { |
594 | setLuaNoSideEffect(); | |
595 | #ifdef HAVE_DNSCRYPT | |
596 | DnsCryptContext* ret = nullptr; | |
597 | if (idx < g_dnsCryptLocals.size()) { | |
598 | ret = &(std::get<1>(g_dnsCryptLocals.at(idx))); | |
599 | } | |
600 | return ret; | |
601 | #else | |
602 | g_outputBuffer="Error: DNSCrypt support is not enabled.\n"; | |
603 | #endif | |
604 | }); | |
605 | ||
606 | #ifdef HAVE_DNSCRYPT | |
607 | /* DnsCryptContext bindings */ | |
608 | g_lua.registerFunction<std::string(DnsCryptContext::*)()>("getProviderName", [](const DnsCryptContext& ctx) { return ctx.getProviderName(); }); | |
609 | g_lua.registerFunction<DnsCryptCert(DnsCryptContext::*)()>("getCurrentCertificate", [](const DnsCryptContext& ctx) { return ctx.getCurrentCertificate(); }); | |
610 | g_lua.registerFunction<DnsCryptCert(DnsCryptContext::*)()>("getOldCertificate", [](const DnsCryptContext& ctx) { return ctx.getOldCertificate(); }); | |
611 | g_lua.registerFunction("hasOldCertificate", &DnsCryptContext::hasOldCertificate); | |
612 | g_lua.registerFunction("loadNewCertificate", &DnsCryptContext::loadNewCertificate); | |
613 | g_lua.registerFunction<void(DnsCryptContext::*)(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end)>("generateAndLoadInMemoryCertificate", [](DnsCryptContext& ctx, const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end) { | |
614 | DnsCryptPrivateKey privateKey; | |
615 | DnsCryptCert cert; | |
616 | ||
617 | try { | |
618 | if (generateDNSCryptCertificate(providerPrivateKeyFile, serial, begin, end, cert, privateKey)) { | |
619 | ctx.setNewCertificate(cert, privateKey); | |
620 | } | |
621 | } | |
622 | catch(const std::exception& e) { | |
623 | errlog(e.what()); | |
624 | g_outputBuffer="Error: "+string(e.what())+"\n"; | |
625 | } | |
626 | }); | |
627 | ||
628 | /* DnsCryptCert */ | |
629 | g_lua.registerFunction<std::string(DnsCryptCert::*)()>("getMagic", [](const DnsCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.magic), sizeof(cert.magic)); }); | |
630 | g_lua.registerFunction<std::string(DnsCryptCert::*)()>("getEsVersion", [](const DnsCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.esVersion), sizeof(cert.esVersion)); }); | |
631 | g_lua.registerFunction<std::string(DnsCryptCert::*)()>("getProtocolMinorVersion", [](const DnsCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.protocolMinorVersion), sizeof(cert.protocolMinorVersion)); }); | |
632 | g_lua.registerFunction<std::string(DnsCryptCert::*)()>("getSignature", [](const DnsCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signature), sizeof(cert.signature)); }); | |
633 | g_lua.registerFunction<std::string(DnsCryptCert::*)()>("getResolverPublicKey", [](const DnsCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.resolverPK), sizeof(cert.signedData.resolverPK)); }); | |
634 | g_lua.registerFunction<std::string(DnsCryptCert::*)()>("getClientMagic", [](const DnsCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.clientMagic), sizeof(cert.signedData.clientMagic)); }); | |
635 | g_lua.registerFunction<uint32_t(DnsCryptCert::*)()>("getSerial", [](const DnsCryptCert& cert) { return cert.signedData.serial; }); | |
13a325f5 RG |
636 | g_lua.registerFunction<uint32_t(DnsCryptCert::*)()>("getTSStart", [](const DnsCryptCert& cert) { return ntohl(cert.signedData.tsStart); }); |
637 | g_lua.registerFunction<uint32_t(DnsCryptCert::*)()>("getTSEnd", [](const DnsCryptCert& cert) { return ntohl(cert.signedData.tsEnd); }); | |
79500db5 RG |
638 | #endif |
639 | ||
11e1e08b RG |
640 | g_lua.writeFunction("generateDNSCryptProviderKeys", [](const std::string& publicKeyFile, const std::string privateKeyFile) { |
641 | setLuaNoSideEffect(); | |
642 | #ifdef HAVE_DNSCRYPT | |
643 | unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
644 | unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
645 | sodium_mlock(privateKey, sizeof(privateKey)); | |
646 | ||
647 | try { | |
648 | DnsCryptContext::generateProviderKeys(publicKey, privateKey); | |
649 | ||
650 | ofstream pubKStream(publicKeyFile); | |
651 | pubKStream.write((char*) publicKey, sizeof(publicKey)); | |
652 | pubKStream.close(); | |
653 | ||
654 | ofstream privKStream(privateKeyFile); | |
655 | privKStream.write((char*) privateKey, sizeof(privateKey)); | |
656 | privKStream.close(); | |
657 | ||
658 | g_outputBuffer="Provider fingerprint is: " + DnsCryptContext::getProviderFingerprint(publicKey) + "\n"; | |
659 | } | |
660 | catch(std::exception& e) { | |
661 | errlog(e.what()); | |
662 | g_outputBuffer="Error: "+string(e.what())+"\n"; | |
663 | } | |
664 | ||
665 | sodium_memzero(privateKey, sizeof(privateKey)); | |
666 | sodium_munlock(privateKey, sizeof(privateKey)); | |
667 | #else | |
668 | g_outputBuffer="Error: DNSCrypt support is not enabled.\n"; | |
669 | #endif | |
670 | }); | |
671 | ||
b8db58a2 RG |
672 | g_lua.writeFunction("printDNSCryptProviderFingerprint", [](const std::string& publicKeyFile) { |
673 | setLuaNoSideEffect(); | |
674 | #ifdef HAVE_DNSCRYPT | |
675 | unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]; | |
676 | ||
677 | try { | |
678 | ifstream file(publicKeyFile); | |
679 | file.read((char *) &publicKey, sizeof(publicKey)); | |
680 | ||
681 | if (file.fail()) | |
682 | throw std::runtime_error("Invalid dnscrypt provider public key file " + publicKeyFile); | |
683 | ||
684 | file.close(); | |
685 | g_outputBuffer="Provider fingerprint is: " + DnsCryptContext::getProviderFingerprint(publicKey) + "\n"; | |
686 | } | |
687 | catch(std::exception& e) { | |
688 | errlog(e.what()); | |
689 | g_outputBuffer="Error: "+string(e.what())+"\n"; | |
690 | } | |
691 | #else | |
692 | g_outputBuffer="Error: DNSCrypt support is not enabled.\n"; | |
693 | #endif | |
694 | }); | |
695 | ||
11e1e08b RG |
696 | 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) { |
697 | setLuaNoSideEffect(); | |
698 | #ifdef HAVE_DNSCRYPT | |
79500db5 RG |
699 | DnsCryptPrivateKey privateKey; |
700 | DnsCryptCert cert; | |
11e1e08b RG |
701 | |
702 | try { | |
79500db5 RG |
703 | if (generateDNSCryptCertificate(providerPrivateKeyFile, serial, begin, end, cert, privateKey)) { |
704 | privateKey.saveToFile(privateKeyFile); | |
705 | DnsCryptContext::saveCertFromFile(cert, certificateFile); | |
11e1e08b | 706 | } |
11e1e08b | 707 | } |
79500db5 | 708 | catch(const std::exception& e) { |
11e1e08b RG |
709 | errlog(e.what()); |
710 | g_outputBuffer="Error: "+string(e.what())+"\n"; | |
711 | } | |
11e1e08b RG |
712 | #else |
713 | g_outputBuffer="Error: DNSCrypt support is not enabled.\n"; | |
714 | #endif | |
715 | }); | |
716 | ||
886e2cf2 RG |
717 | g_lua.writeFunction("showPools", []() { |
718 | setLuaNoSideEffect(); | |
719 | try { | |
720 | ostringstream ret; | |
938184df RG |
721 | boost::format fmt("%1$-20.20s %|25t|%2$20s %|25t|%3$20s %|50t|%4%" ); |
722 | // 1 2 3 4 | |
723 | ret << (fmt % "Name" % "Cache" % "ServerPolicy" % "Servers" ) << endl; | |
886e2cf2 RG |
724 | |
725 | const auto localPools = g_pools.getCopy(); | |
726 | for (const auto& entry : localPools) { | |
727 | const string& name = entry.first; | |
728 | const std::shared_ptr<ServerPool> pool = entry.second; | |
729 | string cache = pool->packetCache != nullptr ? pool->packetCache->toString() : ""; | |
938184df | 730 | string policy = g_policy.getLocal()->name; |
b9f8a6c8 | 731 | if (pool->policy != nullptr) { |
938184df RG |
732 | policy = pool->policy->name; |
733 | } | |
886e2cf2 RG |
734 | string servers; |
735 | ||
736 | for (const auto& server: pool->servers) { | |
737 | if (!servers.empty()) { | |
738 | servers += ", "; | |
739 | } | |
740 | if (!server.second->name.empty()) { | |
741 | servers += server.second->name; | |
742 | servers += " "; | |
743 | } | |
744 | servers += server.second->remote.toStringWithPort(); | |
745 | } | |
746 | ||
938184df | 747 | ret << (fmt % name % cache % policy % servers) << endl; |
886e2cf2 RG |
748 | } |
749 | g_outputBuffer=ret.str(); | |
750 | }catch(std::exception& e) { g_outputBuffer=e.what(); throw; } | |
751 | }); | |
752 | ||
753 | g_lua.registerFunction<void(std::shared_ptr<ServerPool>::*)(std::shared_ptr<DNSDistPacketCache>)>("setCache", [](std::shared_ptr<ServerPool> pool, std::shared_ptr<DNSDistPacketCache> cache) { | |
2e439533 RG |
754 | if (pool) { |
755 | pool->packetCache = cache; | |
756 | } | |
886e2cf2 RG |
757 | }); |
758 | g_lua.registerFunction("getCache", &ServerPool::getCache); | |
f87c4aff | 759 | g_lua.registerFunction<void(std::shared_ptr<ServerPool>::*)()>("unsetCache", [](std::shared_ptr<ServerPool> pool) { |
2e439533 RG |
760 | if (pool) { |
761 | pool->packetCache = nullptr; | |
762 | } | |
f87c4aff | 763 | }); |
886e2cf2 | 764 | |
2b67180c RG |
765 | g_lua.writeFunction("newPacketCache", [client](size_t maxEntries, boost::optional<uint32_t> maxTTL, boost::optional<uint32_t> minTTL, boost::optional<uint32_t> tempFailTTL, boost::optional<uint32_t> staleTTL, boost::optional<bool> dontAge) { |
766 | return std::make_shared<DNSDistPacketCache>(maxEntries, maxTTL ? *maxTTL : 86400, minTTL ? *minTTL : 0, tempFailTTL ? *tempFailTTL : 60, staleTTL ? *staleTTL : 60, dontAge ? *dontAge : false); | |
886e2cf2 RG |
767 | }); |
768 | g_lua.registerFunction("toString", &DNSDistPacketCache::toString); | |
769 | g_lua.registerFunction("isFull", &DNSDistPacketCache::isFull); | |
4275aaba RG |
770 | g_lua.registerFunction("purgeExpired", &DNSDistPacketCache::purgeExpired); |
771 | g_lua.registerFunction("expunge", &DNSDistPacketCache::expunge); | |
490dc586 RG |
772 | g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)(const DNSName& dname, boost::optional<uint16_t> qtype, boost::optional<bool> suffixMatch)>("expungeByName", []( |
773 | std::shared_ptr<DNSDistPacketCache> cache, | |
774 | const DNSName& dname, | |
775 | boost::optional<uint16_t> qtype, | |
776 | boost::optional<bool> suffixMatch) { | |
2e439533 | 777 | if (cache) { |
490dc586 | 778 | cache->expungeByName(dname, qtype ? *qtype : QType::ANY, suffixMatch ? *suffixMatch : false); |
2e439533 | 779 | } |
886e2cf2 RG |
780 | }); |
781 | g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)()>("printStats", [](const std::shared_ptr<DNSDistPacketCache> cache) { | |
2e439533 | 782 | if (cache) { |
9e9be156 RG |
783 | g_outputBuffer="Entries: " + std::to_string(cache->getEntriesCount()) + "/" + std::to_string(cache->getMaxEntries()) + "\n"; |
784 | g_outputBuffer+="Hits: " + std::to_string(cache->getHits()) + "\n"; | |
2e439533 RG |
785 | g_outputBuffer+="Misses: " + std::to_string(cache->getMisses()) + "\n"; |
786 | g_outputBuffer+="Deferred inserts: " + std::to_string(cache->getDeferredInserts()) + "\n"; | |
787 | g_outputBuffer+="Deferred lookups: " + std::to_string(cache->getDeferredLookups()) + "\n"; | |
788 | g_outputBuffer+="Lookup Collisions: " + std::to_string(cache->getLookupCollisions()) + "\n"; | |
789 | g_outputBuffer+="Insert Collisions: " + std::to_string(cache->getInsertCollisions()) + "\n"; | |
cc8cefe1 | 790 | g_outputBuffer+="TTL Too Shorts: " + std::to_string(cache->getTTLTooShorts()) + "\n"; |
2e439533 | 791 | } |
886e2cf2 RG |
792 | }); |
793 | ||
794 | g_lua.writeFunction("getPool", [client](const string& poolName) { | |
795 | if (client) { | |
796 | return std::make_shared<ServerPool>(); | |
797 | } | |
798 | auto localPools = g_pools.getCopy(); | |
799 | std::shared_ptr<ServerPool> pool = createPoolIfNotExists(localPools, poolName); | |
800 | g_pools.setState(localPools); | |
801 | return pool; | |
802 | }); | |
9e87dcb8 RG |
803 | |
804 | g_lua.writeFunction("setVerboseHealthChecks", [](bool verbose) { g_verboseHealthChecks=verbose; }); | |
1ea747c0 | 805 | g_lua.writeFunction("setStaleCacheEntriesTTL", [](uint32_t ttl) { g_staleCacheEntriesTTL = ttl; }); |
d8c19b98 | 806 | |
788c3243 RG |
807 | g_lua.writeFunction("DropResponseAction", []() { |
808 | return std::shared_ptr<DNSResponseAction>(new DropResponseAction); | |
809 | }); | |
810 | ||
811 | g_lua.writeFunction("AllowResponseAction", []() { | |
812 | return std::shared_ptr<DNSResponseAction>(new AllowResponseAction); | |
813 | }); | |
814 | ||
815 | g_lua.writeFunction("DelayResponseAction", [](int msec) { | |
816 | return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec)); | |
817 | }); | |
818 | ||
a94673ea | 819 | g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLogger> logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc) { |
5965ea6a | 820 | #ifdef HAVE_PROTOBUF |
a94673ea | 821 | return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc)); |
5965ea6a RG |
822 | #else |
823 | throw std::runtime_error("Protobuf support is required to use RemoteLogAction"); | |
824 | #endif | |
d8c19b98 | 825 | }); |
165c9030 | 826 | g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLogger> logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME) { |
5965ea6a | 827 | #ifdef HAVE_PROTOBUF |
165c9030 | 828 | return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, includeCNAME ? *includeCNAME : false)); |
5965ea6a RG |
829 | #else |
830 | throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction"); | |
831 | #endif | |
d8c19b98 | 832 | }); |
a94673ea RG |
833 | |
834 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const Netmask&)>("setEDNSSubnet", [](DNSDistProtoBufMessage& message, const Netmask& subnet) { message.setEDNSSubnet(subnet); }); | |
835 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const DNSName&, uint16_t, uint16_t)>("setQuestion", [](DNSDistProtoBufMessage& message, const DNSName& qname, uint16_t qtype, uint16_t qclass) { message.setQuestion(qname, qtype, qclass); }); | |
836 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(size_t)>("setBytes", [](DNSDistProtoBufMessage& message, size_t bytes) { message.setBytes(bytes); }); | |
837 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setTime(sec, usec); }); | |
838 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setQueryTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setQueryTime(sec, usec); }); | |
839 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(uint8_t)>("setResponseCode", [](DNSDistProtoBufMessage& message, uint8_t rcode) { message.setResponseCode(rcode); }); | |
840 | g_lua.registerFunction<std::string(DNSDistProtoBufMessage::*)()>("toDebugString", [](const DNSDistProtoBufMessage& message) { return message.toDebugString(); }); | |
841 | ||
842 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&)>("setRequestor", [](DNSDistProtoBufMessage& message, const ComboAddress& addr) { | |
843 | message.setRequestor(addr); | |
844 | }); | |
845 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setRequestorFromString", [](DNSDistProtoBufMessage& message, const std::string& str) { | |
846 | message.setRequestor(str); | |
847 | }); | |
848 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&)>("setResponder", [](DNSDistProtoBufMessage& message, const ComboAddress& addr) { | |
849 | message.setResponder(addr); | |
850 | }); | |
851 | g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setResponderFromString", [](DNSDistProtoBufMessage& message, const std::string& str) { | |
852 | message.setResponder(str); | |
853 | }); | |
854 | ||
ec469dd7 RG |
855 | g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) { |
856 | return std::make_shared<RemoteLogger>(ComboAddress(remote), timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1); | |
d8c19b98 RG |
857 | }); |
858 | ||
384c2cb2 RG |
859 | g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) { |
860 | return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false)); | |
cf6874ba | 861 | }); |
862 | ||
ff0902ec RG |
863 | g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) { |
864 | return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength)); | |
865 | }); | |
866 | ||
867 | g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) { | |
868 | return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride)); | |
869 | }); | |
870 | ||
871 | g_lua.writeFunction("DisableECSAction", []() { | |
872 | return std::shared_ptr<DNSAction>(new DisableECSAction()); | |
873 | }); | |
874 | ||
cf6874ba | 875 | g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) { |
3d8a6b1d | 876 | setLuaNoSideEffect(); |
cf6874ba | 877 | auto stats = ta.getStats(); |
878 | for(const auto& s : stats) { | |
3d8a6b1d | 879 | g_outputBuffer+=s.first+"\t"; |
880 | if((uint64_t)s.second == s.second) | |
881 | g_outputBuffer += std::to_string((uint64_t)s.second)+"\n"; | |
882 | else | |
883 | g_outputBuffer += std::to_string(s.second)+"\n"; | |
cf6874ba | 884 | } |
885 | }); | |
3d8a6b1d | 886 | |
887 | g_lua.writeFunction("getAction", [](unsigned int num) { | |
888 | setLuaNoSideEffect(); | |
17f52224 | 889 | boost::optional<std::shared_ptr<DNSAction>> ret; |
3d8a6b1d | 890 | auto rulactions = g_rulactions.getCopy(); |
17f52224 | 891 | if(num < rulactions.size()) |
892 | ret=rulactions[num].second; | |
893 | return ret; | |
3d8a6b1d | 894 | }); |
895 | ||
896 | g_lua.registerFunction("getStats", &DNSAction::getStats); | |
897 | ||
f186603d RG |
898 | g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era) { |
899 | if (era.type() == typeid(std::shared_ptr<DNSAction>)) { | |
900 | throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); | |
901 | } | |
902 | ||
903 | auto ea = *boost::get<std::shared_ptr<DNSResponseAction>>(&era); | |
904 | ||
905 | setLuaSideEffect(); | |
906 | auto rule=makeRule(var); | |
907 | g_resprulactions.modify([rule, ea](decltype(g_resprulactions)::value_type& rulactions){ | |
908 | rulactions.push_back({rule, ea}); | |
909 | }); | |
910 | }); | |
cf48b0ce | 911 | |
d4d5c5c3 RG |
912 | g_lua.writeFunction("showResponseRules", []() { |
913 | setLuaNoSideEffect(); | |
914 | boost::format fmt("%-3d %9d %-50s %s\n"); | |
915 | g_outputBuffer += (fmt % "#" % "Matches" % "Rule" % "Action").str(); | |
916 | int num=0; | |
917 | for(const auto& lim : g_resprulactions.getCopy()) { | |
918 | string name = lim.first->toString(); | |
919 | g_outputBuffer += (fmt % num % lim.first->d_matches % name % lim.second->toString()).str(); | |
920 | ++num; | |
921 | } | |
922 | }); | |
923 | ||
924 | g_lua.writeFunction("rmResponseRule", [](unsigned int num) { | |
925 | setLuaSideEffect(); | |
926 | auto rules = g_resprulactions.getCopy(); | |
927 | if(num >= rules.size()) { | |
928 | g_outputBuffer = "Error: attempt to delete non-existing rule\n"; | |
929 | return; | |
930 | } | |
931 | rules.erase(rules.begin()+num); | |
932 | g_resprulactions.setState(rules); | |
933 | }); | |
934 | ||
935 | g_lua.writeFunction("topResponseRule", []() { | |
936 | setLuaSideEffect(); | |
937 | auto rules = g_resprulactions.getCopy(); | |
938 | if(rules.empty()) | |
939 | return; | |
940 | auto subject = *rules.rbegin(); | |
941 | rules.erase(std::prev(rules.end())); | |
942 | rules.insert(rules.begin(), subject); | |
943 | g_resprulactions.setState(rules); | |
944 | }); | |
945 | ||
946 | g_lua.writeFunction("mvResponseRule", [](unsigned int from, unsigned int to) { | |
947 | setLuaSideEffect(); | |
948 | auto rules = g_resprulactions.getCopy(); | |
949 | if(from >= rules.size() || to > rules.size()) { | |
950 | g_outputBuffer = "Error: attempt to move rules from/to invalid index\n"; | |
951 | return; | |
952 | } | |
953 | auto subject = rules[from]; | |
954 | rules.erase(rules.begin()+from); | |
955 | if(to == rules.size()) | |
956 | rules.push_back(subject); | |
957 | else { | |
958 | if(from < to) | |
959 | --to; | |
960 | rules.insert(rules.begin()+to, subject); | |
961 | } | |
962 | g_resprulactions.setState(rules); | |
963 | }); | |
964 | ||
cf48b0ce RG |
965 | g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, std::shared_ptr<DNSResponseAction> ea) { |
966 | setLuaSideEffect(); | |
967 | auto rule=makeRule(var); | |
968 | g_cachehitresprulactions.modify([rule, ea](decltype(g_cachehitresprulactions)::value_type& rulactions){ | |
969 | rulactions.push_back({rule, ea}); | |
970 | }); | |
971 | }); | |
972 | ||
973 | g_lua.writeFunction("showCacheHitResponseRules", []() { | |
974 | setLuaNoSideEffect(); | |
975 | boost::format fmt("%-3d %9d %-50s %s\n"); | |
976 | g_outputBuffer += (fmt % "#" % "Matches" % "Rule" % "Action").str(); | |
977 | int num=0; | |
978 | for(const auto& lim : g_cachehitresprulactions.getCopy()) { | |
979 | string name = lim.first->toString(); | |
980 | g_outputBuffer += (fmt % num % lim.first->d_matches % name % lim.second->toString()).str(); | |
981 | ++num; | |
982 | } | |
983 | }); | |
984 | ||
985 | g_lua.writeFunction("rmCacheHitResponseRule", [](unsigned int num) { | |
986 | setLuaSideEffect(); | |
987 | auto rules = g_cachehitresprulactions.getCopy(); | |
988 | if(num >= rules.size()) { | |
989 | g_outputBuffer = "Error: attempt to delete non-existing rule\n"; | |
990 | return; | |
991 | } | |
992 | rules.erase(rules.begin()+num); | |
993 | g_cachehitresprulactions.setState(rules); | |
994 | }); | |
995 | ||
996 | g_lua.writeFunction("topCacheHitResponseRule", []() { | |
997 | setLuaSideEffect(); | |
998 | auto rules = g_cachehitresprulactions.getCopy(); | |
999 | if(rules.empty()) | |
1000 | return; | |
1001 | auto subject = *rules.rbegin(); | |
1002 | rules.erase(std::prev(rules.end())); | |
1003 | rules.insert(rules.begin(), subject); | |
1004 | g_cachehitresprulactions.setState(rules); | |
1005 | }); | |
1006 | ||
1007 | g_lua.writeFunction("mvCacheHitResponseRule", [](unsigned int from, unsigned int to) { | |
1008 | setLuaSideEffect(); | |
1009 | auto rules = g_cachehitresprulactions.getCopy(); | |
1010 | if(from >= rules.size() || to > rules.size()) { | |
1011 | g_outputBuffer = "Error: attempt to move rules from/to invalid index\n"; | |
1012 | return; | |
1013 | } | |
1014 | auto subject = rules[from]; | |
1015 | rules.erase(rules.begin()+from); | |
1016 | if(to == rules.size()) | |
1017 | rules.push_back(subject); | |
1018 | else { | |
1019 | if(from < to) | |
1020 | --to; | |
1021 | rules.insert(rules.begin()+to, subject); | |
1022 | } | |
1023 | g_cachehitresprulactions.setState(rules); | |
1024 | }); | |
1025 | ||
87b515ed RG |
1026 | g_lua.writeFunction("showBinds", []() { |
1027 | setLuaNoSideEffect(); | |
1028 | try { | |
1029 | ostringstream ret; | |
1030 | boost::format fmt("%1$-3d %2$-20.20s %|25t|%3$-8.8s %|35t|%4%" ); | |
1031 | // 1 2 3 4 | |
1032 | ret << (fmt % "#" % "Address" % "Protocol" % "Queries" ) << endl; | |
1033 | ||
1034 | size_t counter = 0; | |
1035 | for (const auto& front : g_frontends) { | |
1036 | ret << (fmt % counter % front->local.toStringWithPort() % (front->udpFD != -1 ? "UDP" : "TCP") % front->queries) << endl; | |
1037 | counter++; | |
1038 | } | |
1039 | g_outputBuffer=ret.str(); | |
1040 | }catch(std::exception& e) { g_outputBuffer=e.what(); throw; } | |
1041 | }); | |
1042 | ||
1043 | g_lua.writeFunction("getBind", [](size_t num) { | |
1044 | setLuaNoSideEffect(); | |
1045 | ClientState* ret = nullptr; | |
1046 | if(num < g_frontends.size()) { | |
1047 | ret=g_frontends[num]; | |
1048 | } | |
1049 | return ret; | |
1050 | }); | |
1051 | ||
1052 | g_lua.registerFunction<std::string(ClientState::*)()>("toString", [](const ClientState& fe) { | |
1053 | setLuaNoSideEffect(); | |
1054 | return fe.local.toStringWithPort(); | |
1055 | }); | |
1056 | ||
b5b93e0b RG |
1057 | g_lua.registerMember("muted", &ClientState::muted); |
1058 | ||
ca4252e0 RG |
1059 | g_lua.writeFunction("help", [](boost::optional<std::string> command) { |
1060 | setLuaNoSideEffect(); | |
1061 | g_outputBuffer = ""; | |
1062 | for (const auto& keyword : g_consoleKeywords) { | |
1063 | if (!command) { | |
1064 | g_outputBuffer += keyword.toString() + "\n"; | |
1065 | } | |
1066 | else if (keyword.name == command) { | |
1067 | g_outputBuffer = keyword.toString() + "\n"; | |
1068 | return; | |
1069 | } | |
1070 | } | |
1071 | if (command) { | |
1072 | g_outputBuffer = "Nothing found for " + *command + "\n"; | |
1073 | } | |
1074 | }); | |
1075 | ||
1076 | g_lua.writeFunction("showVersion", []() { | |
1077 | setLuaNoSideEffect(); | |
1078 | g_outputBuffer = "dnsdist " + std::string(VERSION) + "\n"; | |
1079 | }); | |
1080 | ||
87b515ed | 1081 | #ifdef HAVE_EBPF |
478c786e RG |
1082 | g_lua.writeFunction("newBPFFilter", [client](uint32_t maxV4, uint32_t maxV6, uint32_t maxQNames) { |
1083 | if (client) { | |
1084 | return std::shared_ptr<BPFFilter>(nullptr); | |
1085 | } | |
87b515ed RG |
1086 | return std::make_shared<BPFFilter>(maxV4, maxV6, maxQNames); |
1087 | }); | |
1088 | ||
1089 | g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("block", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) { | |
1090 | if (bpf) { | |
1091 | return bpf->block(ca); | |
1092 | } | |
1093 | }); | |
1094 | ||
1095 | g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("blockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype) { | |
1096 | if (bpf) { | |
1097 | return bpf->block(qname, qtype ? *qtype : 255); | |
1098 | } | |
1099 | }); | |
1100 | ||
1101 | g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("unblock", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) { | |
1102 | if (bpf) { | |
1103 | return bpf->unblock(ca); | |
1104 | } | |
1105 | }); | |
1106 | ||
1107 | g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("unblockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype) { | |
1108 | if (bpf) { | |
1109 | return bpf->unblock(qname, qtype ? *qtype : 255); | |
1110 | } | |
1111 | }); | |
1112 | ||
1113 | g_lua.registerFunction<std::string(std::shared_ptr<BPFFilter>::*)()>("getStats", [](const std::shared_ptr<BPFFilter> bpf) { | |
1114 | setLuaNoSideEffect(); | |
1115 | std::string res; | |
1116 | if (bpf) { | |
1117 | std::vector<std::pair<ComboAddress, uint64_t> > stats = bpf->getAddrStats(); | |
1118 | for (const auto& value : stats) { | |
1119 | if (value.first.sin4.sin_family == AF_INET) { | |
1120 | res += value.first.toString() + ": " + std::to_string(value.second) + "\n"; | |
1121 | } | |
1122 | else if (value.first.sin4.sin_family == AF_INET6) { | |
1123 | res += "[" + value.first.toString() + "]: " + std::to_string(value.second) + "\n"; | |
1124 | } | |
1125 | } | |
1126 | std::vector<std::tuple<DNSName, uint16_t, uint64_t> > qstats = bpf->getQNameStats(); | |
1127 | for (const auto& value : qstats) { | |
1128 | res += std::get<0>(value).toString() + " " + std::to_string(std::get<1>(value)) + ": " + std::to_string(std::get<2>(value)) + "\n"; | |
1129 | } | |
1130 | } | |
1131 | return res; | |
1132 | }); | |
1133 | ||
1134 | g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter> bpf) { | |
1135 | std::string res; | |
1136 | if (bpf) { | |
8429ad04 RG |
1137 | for (const auto& frontend : g_frontends) { |
1138 | frontend->attachFilter(bpf); | |
87b515ed RG |
1139 | } |
1140 | } | |
1141 | }); | |
1142 | ||
8429ad04 RG |
1143 | g_lua.registerFunction<void(ClientState::*)()>("detachFilter", [](ClientState& frontend) { |
1144 | frontend.detachFilter(); | |
1145 | }); | |
1146 | ||
87b515ed RG |
1147 | g_lua.registerFunction<void(ClientState::*)(std::shared_ptr<BPFFilter>)>("attachFilter", [](ClientState& frontend, std::shared_ptr<BPFFilter> bpf) { |
1148 | if (bpf) { | |
8429ad04 | 1149 | frontend.attachFilter(bpf); |
87b515ed RG |
1150 | } |
1151 | }); | |
1152 | ||
1153 | g_lua.writeFunction("setDefaultBPFFilter", [](std::shared_ptr<BPFFilter> bpf) { | |
1154 | if (g_configurationDone) { | |
1155 | g_outputBuffer="setDefaultBPFFilter() cannot be used at runtime!\n"; | |
1156 | return; | |
1157 | } | |
1158 | g_defaultBPFFilter = bpf; | |
1159 | }); | |
1160 | ||
478c786e RG |
1161 | g_lua.writeFunction("newDynBPFFilter", [client](std::shared_ptr<BPFFilter> bpf) { |
1162 | if (client) { | |
1163 | return std::shared_ptr<DynBPFFilter>(nullptr); | |
1164 | } | |
87b515ed RG |
1165 | return std::make_shared<DynBPFFilter>(bpf); |
1166 | }); | |
1167 | ||
8429ad04 RG |
1168 | g_lua.writeFunction("registerDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) { |
1169 | if (dbpf) { | |
1170 | g_dynBPFFilters.push_back(dbpf); | |
1171 | } | |
1172 | }); | |
1173 | ||
1174 | g_lua.writeFunction("unregisterDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) { | |
1175 | if (dbpf) { | |
5459f1d8 | 1176 | for (auto it = g_dynBPFFilters.begin(); it != g_dynBPFFilters.end(); it++) { |
8429ad04 RG |
1177 | if (*it == dbpf) { |
1178 | g_dynBPFFilters.erase(it); | |
1179 | break; | |
1180 | } | |
1181 | } | |
1182 | } | |
1183 | }); | |
1184 | ||
87b515ed RG |
1185 | g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(const ComboAddress& addr, boost::optional<int> seconds)>("block", [](std::shared_ptr<DynBPFFilter> dbpf, const ComboAddress& addr, boost::optional<int> seconds) { |
1186 | if (dbpf) { | |
1187 | struct timespec until; | |
1188 | clock_gettime(CLOCK_MONOTONIC, &until); | |
1189 | until.tv_sec += seconds ? *seconds : 10; | |
1190 | dbpf->block(addr, until); | |
1191 | } | |
1192 | }); | |
1193 | ||
1194 | g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)()>("purgeExpired", [](std::shared_ptr<DynBPFFilter> dbpf) { | |
1195 | if (dbpf) { | |
1196 | struct timespec now; | |
1197 | clock_gettime(CLOCK_MONOTONIC, &now); | |
1198 | dbpf->purgeExpired(now); | |
1199 | } | |
1200 | }); | |
1201 | ||
1202 | g_lua.writeFunction("addBPFFilterDynBlocks", [](const map<ComboAddress,int>& m, std::shared_ptr<DynBPFFilter> dynbpf, boost::optional<int> seconds) { | |
1203 | setLuaSideEffect(); | |
1204 | struct timespec until, now; | |
1205 | clock_gettime(CLOCK_MONOTONIC, &now); | |
1206 | until=now; | |
1207 | int actualSeconds = seconds ? *seconds : 10; | |
1208 | until.tv_sec += actualSeconds; | |
1209 | for(const auto& capair : m) { | |
1210 | dynbpf->block(capair.first, until); | |
1211 | } | |
1212 | }); | |
1213 | ||
1214 | #endif /* HAVE_EBPF */ | |
86baa8df RG |
1215 | |
1216 | g_lua.writeFunction<std::unordered_map<string,uint64_t>()>("getStatisticsCounters", []() { | |
1217 | setLuaNoSideEffect(); | |
1218 | std::unordered_map<string,uint64_t> res; | |
1219 | for(const auto& entry : g_stats.entries) { | |
1220 | if(const auto& val = boost::get<DNSDistStats::stat_t*>(&entry.second)) | |
1221 | res[entry.first] = (*val)->load(); | |
1222 | } | |
1223 | return res; | |
1224 | }); | |
69389510 RG |
1225 | |
1226 | g_lua.writeFunction("includeDirectory", [](const std::string& dirname) { | |
1227 | if (g_configurationDone) { | |
1228 | errlog("includeDirectory() cannot be used at runtime!"); | |
1229 | g_outputBuffer="includeDirectory() cannot be used at runtime!\n"; | |
1230 | return; | |
1231 | } | |
1232 | ||
1233 | if (g_included) { | |
1234 | errlog("includeDirectory() cannot be used recursively!"); | |
1235 | g_outputBuffer="includeDirectory() cannot be used recursively!\n"; | |
1236 | return; | |
1237 | } | |
1238 | ||
1239 | g_included = true; | |
1240 | struct stat st; | |
1241 | ||
1242 | if (stat(dirname.c_str(), &st)) { | |
1243 | errlog("The included directory %s does not exist!", dirname.c_str()); | |
1244 | g_outputBuffer="The included directory " + dirname + " does not exist!"; | |
1245 | return; | |
1246 | } | |
1247 | ||
1248 | if (!S_ISDIR(st.st_mode)) { | |
1249 | errlog("The included directory %s is not a directory!", dirname.c_str()); | |
1250 | g_outputBuffer="The included directory " + dirname + " is not a directory!"; | |
1251 | return; | |
1252 | } | |
1253 | ||
1254 | DIR *dirp; | |
1255 | struct dirent *ent; | |
00bf2fb9 | 1256 | std::list<std::string> files; |
69389510 RG |
1257 | if (!(dirp = opendir(dirname.c_str()))) { |
1258 | errlog("Error opening the included directory %s!", dirname.c_str()); | |
1259 | g_outputBuffer="Error opening the included directory " + dirname + "!"; | |
1260 | return; | |
1261 | } | |
1262 | ||
1263 | while((ent = readdir(dirp)) != NULL) { | |
1264 | if (ent->d_name[0] == '.') { | |
1265 | continue; | |
1266 | } | |
1267 | ||
1268 | if (boost::ends_with(ent->d_name, ".conf")) { | |
1269 | std::ostringstream namebuf; | |
1270 | namebuf << dirname.c_str() << "/" << ent->d_name; | |
1271 | ||
1272 | if (stat(namebuf.str().c_str(), &st) || !S_ISREG(st.st_mode)) { | |
1273 | continue; | |
1274 | } | |
1275 | ||
00bf2fb9 | 1276 | files.push_back(namebuf.str()); |
69389510 RG |
1277 | } |
1278 | } | |
00bf2fb9 | 1279 | |
69389510 | 1280 | closedir(dirp); |
00bf2fb9 RG |
1281 | files.sort(); |
1282 | ||
1283 | for (auto file = files.begin(); file != files.end(); ++file) { | |
1284 | std::ifstream ifs(*file); | |
1285 | if (!ifs) { | |
1286 | warnlog("Unable to read configuration from '%s'", *file); | |
1287 | } else { | |
1288 | vinfolog("Read configuration from '%s'", *file); | |
1289 | } | |
1290 | ||
1291 | g_lua.executeCode(ifs); | |
1292 | } | |
69389510 RG |
1293 | |
1294 | g_included = false; | |
1295 | }); | |
56d68fad RG |
1296 | |
1297 | g_lua.writeFunction("setAPIWritable", [](bool writable, boost::optional<std::string> apiConfigDir) { | |
1298 | setLuaSideEffect(); | |
1299 | g_apiReadWrite = writable; | |
1300 | if (apiConfigDir) { | |
1301 | if (!(*apiConfigDir).empty()) { | |
1302 | g_apiConfigDirectory = *apiConfigDir; | |
1303 | } | |
1304 | else { | |
1305 | errlog("The API configuration directory value cannot be empty!"); | |
1306 | g_outputBuffer="The API configuration directory value cannot be empty!"; | |
1307 | } | |
1308 | } | |
1309 | }); | |
26a3cdb7 RG |
1310 | |
1311 | g_lua.writeFunction("setServFailWhenNoServer", [](bool servfail) { | |
1312 | setLuaSideEffect(); | |
1313 | g_servFailOnNoPolicy = servfail; | |
1314 | }); | |
e4c24bb3 RG |
1315 | |
1316 | g_lua.writeFunction("setRingBuffersSize", [](size_t capacity) { | |
1317 | setLuaSideEffect(); | |
1318 | if (g_configurationDone) { | |
1319 | errlog("setRingBuffersSize() cannot be used at runtime!"); | |
1320 | g_outputBuffer="setRingBuffersSize() cannot be used at runtime!\n"; | |
1321 | return; | |
1322 | } | |
1323 | g_rings.setCapacity(capacity); | |
7caebbb2 RG |
1324 | }); |
1325 | ||
1326 | g_lua.writeFunction("RDRule", []() { | |
1327 | return std::shared_ptr<DNSRule>(new RDRule()); | |
1328 | }); | |
1329 | ||
2b58b625 | 1330 | g_lua.writeFunction("TimedIPSetRule", []() { |
1331 | return std::shared_ptr<TimedIPSetRule>(new TimedIPSetRule()); | |
1332 | }); | |
1333 | ||
1334 | g_lua.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("clear", [](std::shared_ptr<TimedIPSetRule> tisr) { | |
1335 | tisr->clear(); | |
1336 | }); | |
1337 | ||
01b8149e | 1338 | g_lua.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("cleanup", [](std::shared_ptr<TimedIPSetRule> tisr) { |
1339 | tisr->cleanup(); | |
1340 | }); | |
1341 | ||
2b58b625 | 1342 | g_lua.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)(const ComboAddress& ca, int t)>("add", [](std::shared_ptr<TimedIPSetRule> tisr, const ComboAddress& ca, int t) { |
1343 | tisr->add(ca, time(0)+t); | |
1344 | }); | |
1345 | ||
1346 | g_lua.registerFunction<std::shared_ptr<DNSRule>(std::shared_ptr<TimedIPSetRule>::*)()>("slice", [](std::shared_ptr<TimedIPSetRule> tisr) { | |
1347 | return std::dynamic_pointer_cast<DNSRule>(tisr); | |
1348 | }); | |
1349 | ||
36e763fa RG |
1350 | g_lua.writeFunction("setWHashedPertubation", [](uint32_t pertub) { |
1351 | setLuaSideEffect(); | |
1352 | g_hashperturb = pertub; | |
1353 | }); | |
1354 | ||
edbda1ad RG |
1355 | g_lua.writeFunction("setTCPUseSinglePipe", [](bool flag) { |
1356 | if (g_configurationDone) { | |
1357 | g_outputBuffer="setTCPUseSinglePipe() cannot be used at runtime!\n"; | |
1358 | return; | |
1359 | } | |
1360 | setLuaSideEffect(); | |
1361 | g_useTCPSinglePipe = flag; | |
1362 | }); | |
1363 | ||
9f4eb5cc RG |
1364 | g_lua.writeFunction("snmpAgent", [](bool enableTraps, boost::optional<std::string> masterSocket) { |
1365 | #ifdef HAVE_NET_SNMP | |
1366 | if (g_configurationDone) { | |
1367 | errlog("snmpAgent() cannot be used at runtime!"); | |
1368 | g_outputBuffer="snmpAgent() cannot be used at runtime!\n"; | |
1369 | return; | |
1370 | } | |
1371 | ||
1372 | if (g_snmpEnabled) { | |
1373 | errlog("snmpAgent() cannot be used twice!"); | |
1374 | g_outputBuffer="snmpAgent() cannot be used twice!\n"; | |
1375 | return; | |
1376 | } | |
1377 | ||
1378 | g_snmpEnabled = true; | |
1379 | g_snmpTrapsEnabled = enableTraps; | |
1380 | g_snmpAgent = new DNSDistSNMPAgent("dnsdist", masterSocket ? *masterSocket : std::string()); | |
1381 | #else | |
1382 | errlog("NET SNMP support is required to use snmpAgent()"); | |
1383 | g_outputBuffer="NET SNMP support is required to use snmpAgent()\n"; | |
1384 | #endif /* HAVE_NET_SNMP */ | |
1385 | }); | |
1386 | ||
1387 | g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) { | |
1388 | #ifdef HAVE_NET_SNMP | |
1389 | return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : "")); | |
1390 | #else | |
1391 | throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()"); | |
1392 | #endif /* HAVE_NET_SNMP */ | |
1393 | }); | |
1394 | ||
1395 | g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) { | |
1396 | #ifdef HAVE_NET_SNMP | |
1397 | return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : "")); | |
1398 | #else | |
1399 | throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()"); | |
1400 | #endif /* HAVE_NET_SNMP */ | |
1401 | }); | |
1402 | ||
1403 | g_lua.writeFunction("sendCustomTrap", [](const std::string& str) { | |
1404 | #ifdef HAVE_NET_SNMP | |
1405 | if (g_snmpAgent && g_snmpTrapsEnabled) { | |
1406 | g_snmpAgent->sendCustomTrap(str); | |
1407 | } | |
1408 | #endif /* HAVE_NET_SNMP */ | |
1409 | }); | |
742c079a RG |
1410 | |
1411 | g_lua.writeFunction("setPoolServerPolicy", [](ServerPolicy policy, string pool) { | |
1412 | setLuaSideEffect(); | |
1413 | auto localPools = g_pools.getCopy(); | |
1414 | setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(policy)); | |
b9f8a6c8 | 1415 | g_pools.setState(localPools); |
742c079a RG |
1416 | }); |
1417 | ||
1418 | g_lua.writeFunction("setPoolServerPolicyLua", [](string name, policyfunc_t policy, string pool) { | |
1419 | setLuaSideEffect(); | |
1420 | auto localPools = g_pools.getCopy(); | |
1421 | setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy})); | |
b9f8a6c8 | 1422 | g_pools.setState(localPools); |
742c079a RG |
1423 | }); |
1424 | ||
1425 | g_lua.writeFunction("showPoolServerPolicy", [](string pool) { | |
1426 | setLuaSideEffect(); | |
1427 | auto localPools = g_pools.getCopy(); | |
1428 | auto poolObj = getPool(localPools, pool); | |
b9f8a6c8 | 1429 | if (poolObj->policy == nullptr) { |
742c079a RG |
1430 | g_outputBuffer=g_policy.getLocal()->name+"\n"; |
1431 | } else { | |
1432 | g_outputBuffer=poolObj->policy->name+"\n"; | |
1433 | } | |
1434 | }); | |
840ed663 RG |
1435 | |
1436 | g_lua.writeFunction("setTCPDownstreamCleanupInterval", [](uint16_t interval) { | |
1437 | setLuaSideEffect(); | |
1438 | g_downstreamTCPCleanupInterval = interval; | |
1439 | }); | |
ea0aa517 | 1440 | } |