]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-lua-bindings.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / dnsdist-lua-bindings.cc
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 */
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 #include "config.h"
27 #include "dnsdist.hh"
28 #include "dnsdist-lua.hh"
29 #include "dnsdist-protobuf.hh"
30
31 #include "dnstap.hh"
32 #include "dolog.hh"
33 #include "fstrm_logger.hh"
34 #include "remote_logger.hh"
35
36 #ifdef HAVE_LIBCRYPTO
37 #include "ipcipher.hh"
38 #endif /* HAVE_LIBCRYPTO */
39
40 void setupLuaBindings(bool client)
41 {
42 g_lua.writeFunction("infolog", [](const string& arg) {
43 infolog("%s", arg);
44 });
45 g_lua.writeFunction("errlog", [](const string& arg) {
46 errlog("%s", arg);
47 });
48 g_lua.writeFunction("warnlog", [](const string& arg) {
49 warnlog("%s", arg);
50 });
51 g_lua.writeFunction("show", [](const string& arg) {
52 g_outputBuffer+=arg;
53 g_outputBuffer+="\n";
54 });
55
56 /* Exceptions */
57 g_lua.registerFunction<string(std::exception_ptr::*)()>("__tostring", [](const std::exception_ptr& eptr) {
58 try {
59 if (eptr) {
60 std::rethrow_exception(eptr);
61 }
62 } catch(const std::exception& e) {
63 return string(e.what());
64 } catch(const PDNSException& e) {
65 return e.reason;
66 } catch(...) {
67 return string("Unknown exception");
68 }
69 return string("No exception");
70 });
71 /* ServerPolicy */
72 g_lua.writeFunction("newServerPolicy", [](string name, policyfunc_t policy) { return ServerPolicy{name, policy, true};});
73 g_lua.registerMember("name", &ServerPolicy::name);
74 g_lua.registerMember("policy", &ServerPolicy::policy);
75 g_lua.registerMember("isLua", &ServerPolicy::isLua);
76 g_lua.registerFunction("toString", &ServerPolicy::toString);
77
78 g_lua.writeVariable("firstAvailable", ServerPolicy{"firstAvailable", firstAvailable, false});
79 g_lua.writeVariable("roundrobin", ServerPolicy{"roundrobin", roundrobin, false});
80 g_lua.writeVariable("wrandom", ServerPolicy{"wrandom", wrandom, false});
81 g_lua.writeVariable("whashed", ServerPolicy{"whashed", whashed, false});
82 g_lua.writeVariable("chashed", ServerPolicy{"chashed", chashed, false});
83 g_lua.writeVariable("leastOutstanding", ServerPolicy{"leastOutstanding", leastOutstanding, false});
84
85 /* ServerPool */
86 g_lua.registerFunction<void(std::shared_ptr<ServerPool>::*)(std::shared_ptr<DNSDistPacketCache>)>("setCache", [](std::shared_ptr<ServerPool> pool, std::shared_ptr<DNSDistPacketCache> cache) {
87 if (pool) {
88 pool->packetCache = cache;
89 }
90 });
91 g_lua.registerFunction("getCache", &ServerPool::getCache);
92 g_lua.registerFunction<void(std::shared_ptr<ServerPool>::*)()>("unsetCache", [](std::shared_ptr<ServerPool> pool) {
93 if (pool) {
94 pool->packetCache = nullptr;
95 }
96 });
97 g_lua.registerFunction("getECS", &ServerPool::getECS);
98 g_lua.registerFunction("setECS", &ServerPool::setECS);
99
100 /* DownstreamState */
101 g_lua.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& s, int lim) { s.qps = lim ? QPSLimiter(lim, lim) : QPSLimiter(); });
102 g_lua.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](std::shared_ptr<DownstreamState> s, string pool) {
103 auto localPools = g_pools.getCopy();
104 addServerToPool(localPools, pool, s);
105 g_pools.setState(localPools);
106 s->pools.insert(pool);
107 });
108 g_lua.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](std::shared_ptr<DownstreamState> s, string pool) {
109 auto localPools = g_pools.getCopy();
110 removeServerFromPool(localPools, pool, s);
111 g_pools.setState(localPools);
112 s->pools.erase(pool);
113 });
114 g_lua.registerFunction<uint64_t(DownstreamState::*)()>("getOutstanding", [](const DownstreamState& s) { return s.outstanding.load(); });
115 g_lua.registerFunction("isUp", &DownstreamState::isUp);
116 g_lua.registerFunction("setDown", &DownstreamState::setDown);
117 g_lua.registerFunction("setUp", &DownstreamState::setUp);
118 g_lua.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setAuto", [](DownstreamState& s, boost::optional<bool> newStatus) {
119 if (newStatus) {
120 s.upStatus = *newStatus;
121 }
122 s.setAuto();
123 });
124 g_lua.registerFunction("getName", &DownstreamState::getName);
125 g_lua.registerFunction("getNameWithAddr", &DownstreamState::getNameWithAddr);
126 g_lua.registerMember("upStatus", &DownstreamState::upStatus);
127 g_lua.registerMember<int (DownstreamState::*)>("weight",
128 [](const DownstreamState& s) -> int {return s.weight;},
129 [](DownstreamState& s, int newWeight) {s.setWeight(newWeight);}
130 );
131 g_lua.registerMember("order", &DownstreamState::order);
132 g_lua.registerMember("name", &DownstreamState::name);
133
134 /* dnsheader */
135 g_lua.registerFunction<void(dnsheader::*)(bool)>("setRD", [](dnsheader& dh, bool v) {
136 dh.rd=v;
137 });
138
139 g_lua.registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) {
140 return (bool)dh.rd;
141 });
142
143 g_lua.registerFunction<void(dnsheader::*)(bool)>("setCD", [](dnsheader& dh, bool v) {
144 dh.cd=v;
145 });
146
147 g_lua.registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) {
148 return (bool)dh.cd;
149 });
150
151 g_lua.registerFunction<void(dnsheader::*)(bool)>("setTC", [](dnsheader& dh, bool v) {
152 dh.tc=v;
153 if(v) dh.ra = dh.rd; // you'll always need this, otherwise TC=1 gets ignored
154 });
155
156 g_lua.registerFunction<void(dnsheader::*)(bool)>("setQR", [](dnsheader& dh, bool v) {
157 dh.qr=v;
158 });
159
160 /* ComboAddress */
161 g_lua.writeFunction("newCA", [](const std::string& name) { return ComboAddress(name); });
162 g_lua.registerFunction<string(ComboAddress::*)()>("tostring", [](const ComboAddress& ca) { return ca.toString(); });
163 g_lua.registerFunction<string(ComboAddress::*)()>("tostringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
164 g_lua.registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
165 g_lua.registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
166 g_lua.registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
167 g_lua.registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
168 g_lua.registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
169 g_lua.registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
170 g_lua.registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
171 g_lua.registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
172 g_lua.registerFunction<bool(nmts_t::*)(const ComboAddress&)>("match", [](nmts_t& s, const ComboAddress& ca) { return s.match(ca); });
173
174 #ifdef HAVE_LIBCRYPTO
175 g_lua.registerFunction<ComboAddress(ComboAddress::*)(const std::string& key)>("ipencrypt", [](const ComboAddress& ca, const std::string& key) {
176 return encryptCA(ca, key);
177 });
178 g_lua.registerFunction<ComboAddress(ComboAddress::*)(const std::string& key)>("ipdecrypt", [](const ComboAddress& ca, const std::string& key) {
179 return decryptCA(ca, key);
180 });
181
182 g_lua.writeFunction("makeIPCipherKey", [](const std::string& password) {
183 return makeIPCipherKey(password);
184 });
185 #endif /* HAVE_LIBCRYPTO */
186
187 /* DNSName */
188 g_lua.registerFunction("isPartOf", &DNSName::isPartOf);
189 g_lua.registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
190 g_lua.registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
191 g_lua.registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
192 g_lua.registerFunction<string(DNSName::*)()>("tostring", [](const DNSName&dn ) { return dn.toString(); });
193 g_lua.registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
194 g_lua.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); });
195 g_lua.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); });
196 g_lua.writeFunction("newDNSNameSet", []() { return DNSNameSet(); });
197
198 /* DNSNameSet */
199 g_lua.registerFunction<string(DNSNameSet::*)()>("toString", [](const DNSNameSet&dns ) { return dns.toString(); });
200 g_lua.registerFunction<void(DNSNameSet::*)(DNSName&)>("add", [](DNSNameSet& dns, DNSName& dn) { dns.insert(dn); });
201 g_lua.registerFunction<bool(DNSNameSet::*)(DNSName&)>("check", [](DNSNameSet& dns, DNSName& dn) { return dns.find(dn) != dns.end(); });
202 g_lua.registerFunction("delete",(size_t (DNSNameSet::*)(const DNSName&)) &DNSNameSet::erase);
203 g_lua.registerFunction("size",(size_t (DNSNameSet::*)() const) &DNSNameSet::size);
204 g_lua.registerFunction("clear",(void (DNSNameSet::*)()) &DNSNameSet::clear);
205 g_lua.registerFunction("empty",(bool (DNSNameSet::*)()) &DNSNameSet::empty);
206
207 /* SuffixMatchNode */
208 g_lua.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name)>("add", [](SuffixMatchNode &smn, const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name) {
209 if (name.type() == typeid(DNSName)) {
210 auto n = boost::get<DNSName>(name);
211 smn.add(n);
212 return;
213 }
214 if (name.type() == typeid(string)) {
215 auto n = boost::get<string>(name);
216 smn.add(n);
217 return;
218 }
219 if (name.type() == typeid(vector<pair<int, DNSName>>)) {
220 auto names = boost::get<vector<pair<int, DNSName>>>(name);
221 for (auto const n : names) {
222 smn.add(n.second);
223 }
224 return;
225 }
226 if (name.type() == typeid(vector<pair<int, string>>)) {
227 auto names = boost::get<vector<pair<int, string>>>(name);
228 for (auto const n : names) {
229 smn.add(n.second);
230 }
231 return;
232 }
233 });
234 g_lua.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
235
236 /* NetmaskGroup */
237 g_lua.writeFunction("newNMG", []() { return NetmaskGroup(); });
238 g_lua.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
239 {
240 nmg.addMask(mask);
241 });
242 g_lua.registerFunction<void(NetmaskGroup::*)(const std::map<ComboAddress,int>& map)>("addMasks", [](NetmaskGroup&nmg, const std::map<ComboAddress,int>& map)
243 {
244 for (const auto& entry : map) {
245 nmg.addMask(Netmask(entry.first));
246 }
247 });
248
249 g_lua.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
250 g_lua.registerFunction("size", &NetmaskGroup::size);
251 g_lua.registerFunction("clear", &NetmaskGroup::clear);
252 g_lua.registerFunction<string(NetmaskGroup::*)()>("toString", [](const NetmaskGroup& nmg ) { return "NetmaskGroup " + nmg.toString(); });
253
254 /* QPSLimiter */
255 g_lua.writeFunction("newQPSLimiter", [](int rate, int burst) { return QPSLimiter(rate, burst); });
256 g_lua.registerFunction("check", &QPSLimiter::check);
257
258 /* ClientState */
259 g_lua.registerFunction<std::string(ClientState::*)()>("toString", [](const ClientState& fe) {
260 setLuaNoSideEffect();
261 return fe.local.toStringWithPort();
262 });
263 g_lua.registerMember("muted", &ClientState::muted);
264 #ifdef HAVE_EBPF
265 g_lua.registerFunction<void(ClientState::*)(std::shared_ptr<BPFFilter>)>("attachFilter", [](ClientState& frontend, std::shared_ptr<BPFFilter> bpf) {
266 if (bpf) {
267 frontend.attachFilter(bpf);
268 }
269 });
270 g_lua.registerFunction<void(ClientState::*)()>("detachFilter", [](ClientState& frontend) {
271 frontend.detachFilter();
272 });
273 #endif /* HAVE_EBPF */
274
275 /* PacketCache */
276 g_lua.writeFunction("newPacketCache", [](size_t maxEntries, boost::optional<std::unordered_map<std::string, boost::variant<bool, size_t>>> vars) {
277
278 bool keepStaleData = false;
279 size_t maxTTL = 86400;
280 size_t minTTL = 0;
281 size_t tempFailTTL = 60;
282 size_t maxNegativeTTL = 3600;
283 size_t staleTTL = 60;
284 size_t numberOfShards = 1;
285 bool dontAge = false;
286 bool deferrableInsertLock = true;
287 bool ecsParsing = false;
288
289 if (vars) {
290
291 if (vars->count("deferrableInsertLock")) {
292 deferrableInsertLock = boost::get<bool>((*vars)["deferrableInsertLock"]);
293 }
294
295 if (vars->count("dontAge")) {
296 dontAge = boost::get<bool>((*vars)["dontAge"]);
297 }
298
299 if (vars->count("keepStaleData")) {
300 keepStaleData = boost::get<bool>((*vars)["keepStaleData"]);
301 }
302
303 if (vars->count("maxNegativeTTL")) {
304 maxNegativeTTL = boost::get<size_t>((*vars)["maxNegativeTTL"]);
305 }
306
307 if (vars->count("maxTTL")) {
308 maxTTL = boost::get<size_t>((*vars)["maxTTL"]);
309 }
310
311 if (vars->count("minTTL")) {
312 minTTL = boost::get<size_t>((*vars)["minTTL"]);
313 }
314
315 if (vars->count("numberOfShards")) {
316 numberOfShards = boost::get<size_t>((*vars)["numberOfShards"]);
317 }
318
319 if (vars->count("parseECS")) {
320 ecsParsing = boost::get<bool>((*vars)["parseECS"]);
321 }
322
323 if (vars->count("staleTTL")) {
324 staleTTL = boost::get<size_t>((*vars)["staleTTL"]);
325 }
326
327 if (vars->count("temporaryFailureTTL")) {
328 tempFailTTL = boost::get<size_t>((*vars)["temporaryFailureTTL"]);
329 }
330 }
331
332 auto res = std::make_shared<DNSDistPacketCache>(maxEntries, maxTTL, minTTL, tempFailTTL, maxNegativeTTL, staleTTL, dontAge, numberOfShards, deferrableInsertLock, ecsParsing);
333
334 res->setKeepStaleData(keepStaleData);
335
336 return res;
337 });
338 g_lua.registerFunction("toString", &DNSDistPacketCache::toString);
339 g_lua.registerFunction("isFull", &DNSDistPacketCache::isFull);
340 g_lua.registerFunction("purgeExpired", &DNSDistPacketCache::purgeExpired);
341 g_lua.registerFunction("expunge", &DNSDistPacketCache::expunge);
342 g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)(const DNSName& dname, boost::optional<uint16_t> qtype, boost::optional<bool> suffixMatch)>("expungeByName", [](
343 std::shared_ptr<DNSDistPacketCache> cache,
344 const DNSName& dname,
345 boost::optional<uint16_t> qtype,
346 boost::optional<bool> suffixMatch) {
347 if (cache) {
348 g_outputBuffer="Expunged " + std::to_string(cache->expungeByName(dname, qtype ? *qtype : QType(QType::ANY).getCode(), suffixMatch ? *suffixMatch : false)) + " records\n";
349 }
350 });
351 g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)()>("printStats", [](const std::shared_ptr<DNSDistPacketCache> cache) {
352 if (cache) {
353 g_outputBuffer="Entries: " + std::to_string(cache->getEntriesCount()) + "/" + std::to_string(cache->getMaxEntries()) + "\n";
354 g_outputBuffer+="Hits: " + std::to_string(cache->getHits()) + "\n";
355 g_outputBuffer+="Misses: " + std::to_string(cache->getMisses()) + "\n";
356 g_outputBuffer+="Deferred inserts: " + std::to_string(cache->getDeferredInserts()) + "\n";
357 g_outputBuffer+="Deferred lookups: " + std::to_string(cache->getDeferredLookups()) + "\n";
358 g_outputBuffer+="Lookup Collisions: " + std::to_string(cache->getLookupCollisions()) + "\n";
359 g_outputBuffer+="Insert Collisions: " + std::to_string(cache->getInsertCollisions()) + "\n";
360 g_outputBuffer+="TTL Too Shorts: " + std::to_string(cache->getTTLTooShorts()) + "\n";
361 }
362 });
363 g_lua.registerFunction<std::unordered_map<std::string, uint64_t>(std::shared_ptr<DNSDistPacketCache>::*)()>("getStats", [](const std::shared_ptr<DNSDistPacketCache> cache) {
364 std::unordered_map<std::string, uint64_t> stats;
365 if (cache) {
366 stats["entries"] = cache->getEntriesCount();
367 stats["maxEntries"] = cache->getMaxEntries();
368 stats["hits"] = cache->getHits();
369 stats["misses"] = cache->getMisses();
370 stats["deferredInserts"] = cache->getDeferredInserts();
371 stats["deferredLookups"] = cache->getDeferredLookups();
372 stats["lookupCollisions"] = cache->getLookupCollisions();
373 stats["insertCollisions"] = cache->getInsertCollisions();
374 stats["ttlTooShorts"] = cache->getTTLTooShorts();
375 }
376 return stats;
377 });
378 g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)(const std::string& fname)>("dump", [](const std::shared_ptr<DNSDistPacketCache> cache, const std::string& fname) {
379 if (cache) {
380
381 int fd = open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
382 if (fd < 0) {
383 g_outputBuffer = "Error opening dump file for writing: " + string(strerror(errno)) + "\n";
384 return;
385 }
386
387 uint64_t records = 0;
388 try {
389 records = cache->dump(fd);
390 }
391 catch (const std::exception& e) {
392 close(fd);
393 throw;
394 }
395
396 close(fd);
397
398 g_outputBuffer += "Dumped " + std::to_string(records) + " records\n";
399 }
400 });
401
402 /* ProtobufMessage */
403 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(std::string)>("setTag", [](DNSDistProtoBufMessage& message, const std::string& strValue) {
404 message.addTag(strValue);
405 });
406 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(vector<pair<int, string>>)>("setTagArray", [](DNSDistProtoBufMessage& message, const vector<pair<int, string>>&tags) {
407 for (const auto& tag : tags) {
408 message.addTag(tag.second);
409 }
410 });
411 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(boost::optional <time_t> sec, boost::optional <uint32_t> uSec)>("setProtobufResponseType",
412 [](DNSDistProtoBufMessage& message, boost::optional <time_t> sec, boost::optional <uint32_t> uSec) {
413 message.setType(DNSProtoBufMessage::Response);
414 message.setQueryTime(sec?*sec:0, uSec?*uSec:0);
415 });
416 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string& strQueryName, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob)>("addResponseRR", [](DNSDistProtoBufMessage& message,
417 const std::string& strQueryName, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob) {
418 message.addRR(DNSName(strQueryName), uType, uClass, uTTL, strBlob);
419 });
420 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const Netmask&)>("setEDNSSubnet", [](DNSDistProtoBufMessage& message, const Netmask& subnet) { message.setEDNSSubnet(subnet); });
421 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); });
422 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(size_t)>("setBytes", [](DNSDistProtoBufMessage& message, size_t bytes) { message.setBytes(bytes); });
423 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setTime(sec, usec); });
424 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setQueryTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setQueryTime(sec, usec); });
425 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(uint8_t)>("setResponseCode", [](DNSDistProtoBufMessage& message, uint8_t rcode) { message.setResponseCode(rcode); });
426 g_lua.registerFunction<std::string(DNSDistProtoBufMessage::*)()>("toDebugString", [](const DNSDistProtoBufMessage& message) { return message.toDebugString(); });
427 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&)>("setRequestor", [](DNSDistProtoBufMessage& message, const ComboAddress& addr) {
428 message.setRequestor(addr);
429 });
430 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setRequestorFromString", [](DNSDistProtoBufMessage& message, const std::string& str) {
431 message.setRequestor(str);
432 });
433 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&)>("setResponder", [](DNSDistProtoBufMessage& message, const ComboAddress& addr) {
434 message.setResponder(addr);
435 });
436 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setResponderFromString", [](DNSDistProtoBufMessage& message, const std::string& str) {
437 message.setResponder(str);
438 });
439 g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setServerIdentity", [](DNSDistProtoBufMessage& message, const std::string& str) {
440 message.setServerIdentity(str);
441 });
442
443 g_lua.registerFunction<std::string(DnstapMessage::*)()>("toDebugString", [](const DnstapMessage& message) { return message.toDebugString(); });
444 g_lua.registerFunction<void(DnstapMessage::*)(const std::string&)>("setExtra", [](DnstapMessage& message, const std::string& str) {
445 message.setExtra(str);
446 });
447
448 /* RemoteLogger */
449 g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) {
450 return std::shared_ptr<RemoteLoggerInterface>(new RemoteLogger(ComboAddress(remote), timeout ? *timeout : 2, maxQueuedEntries ? (*maxQueuedEntries*100) : 10000, reconnectWaitTime ? *reconnectWaitTime : 1, client));
451 });
452
453 g_lua.writeFunction("newFrameStreamUnixLogger", [client](const std::string& address) {
454 #ifdef HAVE_FSTRM
455 return std::shared_ptr<RemoteLoggerInterface>(new FrameStreamLogger(AF_UNIX, address, !client));
456 #else
457 throw std::runtime_error("fstrm support is required to build an AF_UNIX FrameStreamLogger");
458 #endif /* HAVE_FSTRM */
459 });
460
461 g_lua.writeFunction("newFrameStreamTcpLogger", [client](const std::string& address) {
462 #if defined(HAVE_FSTRM) && defined(HAVE_FSTRM_TCP_WRITER_INIT)
463 return std::shared_ptr<RemoteLoggerInterface>(new FrameStreamLogger(AF_INET, address, !client));
464 #else
465 throw std::runtime_error("fstrm with TCP support is required to build an AF_INET FrameStreamLogger");
466 #endif /* HAVE_FSTRM */
467 });
468
469 g_lua.registerFunction("toString", &RemoteLoggerInterface::toString);
470
471 #ifdef HAVE_DNSCRYPT
472 /* DNSCryptContext bindings */
473 g_lua.registerFunction<std::string(DNSCryptContext::*)()>("getProviderName", [](const DNSCryptContext& ctx) { return ctx.getProviderName().toStringNoDot(); });
474 g_lua.registerFunction("markActive", &DNSCryptContext::markActive);
475 g_lua.registerFunction("markInactive", &DNSCryptContext::markInactive);
476 g_lua.registerFunction("removeInactiveCertificate", &DNSCryptContext::removeInactiveCertificate);
477 g_lua.registerFunction<void(std::shared_ptr<DNSCryptContext>::*)(const std::string& certFile, const std::string& keyFile, boost::optional<bool> active)>("loadNewCertificate", [](std::shared_ptr<DNSCryptContext> ctx, const std::string& certFile, const std::string& keyFile, boost::optional<bool> active) {
478
479 if (ctx == nullptr) {
480 throw std::runtime_error("DNSCryptContext::loadNewCertificate() called on a nil value");
481 }
482
483 ctx->loadNewCertificate(certFile, keyFile, active ? *active : true);
484 });
485 g_lua.registerFunction<void(std::shared_ptr<DNSCryptContext>::*)(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, boost::optional<bool> active)>("addNewCertificate", [](std::shared_ptr<DNSCryptContext> ctx, const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, boost::optional<bool> active) {
486
487 if (ctx == nullptr) {
488 throw std::runtime_error("DNSCryptContext::addNewCertificate() called on a nil value");
489 }
490
491 ctx->addNewCertificate(newCert, newKey, active ? *active : true);
492 });
493 g_lua.registerFunction<std::map<int, std::shared_ptr<DNSCryptCertificatePair>>(std::shared_ptr<DNSCryptContext>::*)()>("getCertificatePairs", [](std::shared_ptr<DNSCryptContext> ctx) {
494 std::map<int, std::shared_ptr<DNSCryptCertificatePair>> result;
495
496 if (ctx != nullptr) {
497 size_t idx = 1;
498 for (auto pair : ctx->getCertificates()) {
499 result[idx++] = pair;
500 }
501 }
502
503 return result;
504 });
505
506 g_lua.registerFunction<std::shared_ptr<DNSCryptCertificatePair>(std::shared_ptr<DNSCryptContext>::*)(size_t idx)>("getCertificatePair", [](std::shared_ptr<DNSCryptContext> ctx, size_t idx) {
507
508 if (ctx == nullptr) {
509 throw std::runtime_error("DNSCryptContext::getCertificatePair() called on a nil value");
510 }
511
512 std::shared_ptr<DNSCryptCertificatePair> result = nullptr;
513 auto pairs = ctx->getCertificates();
514 if (idx < pairs.size()) {
515 result = pairs.at(idx);
516 }
517
518 return result;
519 });
520
521 g_lua.registerFunction<const DNSCryptCert(std::shared_ptr<DNSCryptContext>::*)(size_t idx)>("getCertificate", [](std::shared_ptr<DNSCryptContext> ctx, size_t idx) {
522
523 if (ctx == nullptr) {
524 throw std::runtime_error("DNSCryptContext::getCertificate() called on a nil value");
525 }
526
527 auto pairs = ctx->getCertificates();
528 if (idx < pairs.size()) {
529 return pairs.at(idx)->cert;
530 }
531
532 throw std::runtime_error("This DNSCrypt context has no certificate at index " + std::to_string(idx));
533 });
534
535 g_lua.registerFunction<std::string(std::shared_ptr<DNSCryptContext>::*)()>("printCertificates", [](const std::shared_ptr<DNSCryptContext> ctx) {
536 ostringstream ret;
537
538 if (ctx != nullptr) {
539 size_t idx = 1;
540 boost::format fmt("%1$-3d %|5t|%2$-8d %|10t|%3$-7d %|20t|%4$-21.21s %|41t|%5$-21.21s");
541 ret << (fmt % "#" % "Serial" % "Version" % "From" % "To" ) << endl;
542
543 for (auto pair : ctx->getCertificates()) {
544 const auto cert = pair->cert;
545 const DNSCryptExchangeVersion version = DNSCryptContext::getExchangeVersion(cert);
546
547 ret << (fmt % idx % cert.getSerial() % (version == DNSCryptExchangeVersion::VERSION1 ? 1 : 2) % DNSCryptContext::certificateDateToStr(cert.getTSStart()) % DNSCryptContext::certificateDateToStr(cert.getTSEnd())) << endl;
548 }
549 }
550
551 return ret.str();
552 });
553
554 g_lua.registerFunction<void(DNSCryptContext::*)(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version)>("generateAndLoadInMemoryCertificate", [](DNSCryptContext& ctx, const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
555 DNSCryptPrivateKey privateKey;
556 DNSCryptCert cert;
557
558 try {
559 if (generateDNSCryptCertificate(providerPrivateKeyFile, serial, begin, end, version ? *version : DNSCryptExchangeVersion::VERSION1, cert, privateKey)) {
560 ctx.addNewCertificate(cert, privateKey);
561 }
562 }
563 catch(const std::exception& e) {
564 errlog(e.what());
565 g_outputBuffer="Error: "+string(e.what())+"\n";
566 }
567 });
568
569 /* DNSCryptCertificatePair */
570 g_lua.registerFunction<const DNSCryptCert(std::shared_ptr<DNSCryptCertificatePair>::*)()>("getCertificate", [](const std::shared_ptr<DNSCryptCertificatePair> pair) {
571 if (pair == nullptr) {
572 throw std::runtime_error("DNSCryptCertificatePair::getCertificate() called on a nil value");
573 }
574 return pair->cert;
575 });
576 g_lua.registerFunction<bool(std::shared_ptr<DNSCryptCertificatePair>::*)()>("isActive", [](const std::shared_ptr<DNSCryptCertificatePair> pair) {
577 if (pair == nullptr) {
578 throw std::runtime_error("DNSCryptCertificatePair::isActive() called on a nil value");
579 }
580 return pair->active;
581 });
582
583 /* DNSCryptCert */
584 g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getMagic", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.magic), sizeof(cert.magic)); });
585 g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getEsVersion", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.esVersion), sizeof(cert.esVersion)); });
586 g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getProtocolMinorVersion", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.protocolMinorVersion), sizeof(cert.protocolMinorVersion)); });
587 g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getSignature", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signature), sizeof(cert.signature)); });
588 g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getResolverPublicKey", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.resolverPK), sizeof(cert.signedData.resolverPK)); });
589 g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getClientMagic", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.clientMagic), sizeof(cert.signedData.clientMagic)); });
590 g_lua.registerFunction<uint32_t(DNSCryptCert::*)()>("getSerial", [](const DNSCryptCert& cert) { return cert.getSerial(); });
591 g_lua.registerFunction<uint32_t(DNSCryptCert::*)()>("getTSStart", [](const DNSCryptCert& cert) { return ntohl(cert.getTSStart()); });
592 g_lua.registerFunction<uint32_t(DNSCryptCert::*)()>("getTSEnd", [](const DNSCryptCert& cert) { return ntohl(cert.getTSEnd()); });
593 #endif
594
595 /* BPF Filter */
596 #ifdef HAVE_EBPF
597 g_lua.writeFunction("newBPFFilter", [client](uint32_t maxV4, uint32_t maxV6, uint32_t maxQNames) {
598 if (client) {
599 return std::shared_ptr<BPFFilter>(nullptr);
600 }
601 return std::make_shared<BPFFilter>(maxV4, maxV6, maxQNames);
602 });
603
604 g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("block", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) {
605 if (bpf) {
606 return bpf->block(ca);
607 }
608 });
609
610 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) {
611 if (bpf) {
612 return bpf->block(qname, qtype ? *qtype : 255);
613 }
614 });
615
616 g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("unblock", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) {
617 if (bpf) {
618 return bpf->unblock(ca);
619 }
620 });
621
622 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) {
623 if (bpf) {
624 return bpf->unblock(qname, qtype ? *qtype : 255);
625 }
626 });
627
628 g_lua.registerFunction<std::string(std::shared_ptr<BPFFilter>::*)()>("getStats", [](const std::shared_ptr<BPFFilter> bpf) {
629 setLuaNoSideEffect();
630 std::string res;
631 if (bpf) {
632 std::vector<std::pair<ComboAddress, uint64_t> > stats = bpf->getAddrStats();
633 for (const auto& value : stats) {
634 if (value.first.sin4.sin_family == AF_INET) {
635 res += value.first.toString() + ": " + std::to_string(value.second) + "\n";
636 }
637 else if (value.first.sin4.sin_family == AF_INET6) {
638 res += "[" + value.first.toString() + "]: " + std::to_string(value.second) + "\n";
639 }
640 }
641 std::vector<std::tuple<DNSName, uint16_t, uint64_t> > qstats = bpf->getQNameStats();
642 for (const auto& value : qstats) {
643 res += std::get<0>(value).toString() + " " + std::to_string(std::get<1>(value)) + ": " + std::to_string(std::get<2>(value)) + "\n";
644 }
645 }
646 return res;
647 });
648
649 g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter> bpf) {
650 std::string res;
651 if (bpf) {
652 for (const auto& frontend : g_frontends) {
653 frontend->attachFilter(bpf);
654 }
655 }
656 });
657
658 g_lua.writeFunction("newDynBPFFilter", [client](std::shared_ptr<BPFFilter> bpf) {
659 if (client) {
660 return std::shared_ptr<DynBPFFilter>(nullptr);
661 }
662 return std::make_shared<DynBPFFilter>(bpf);
663 });
664
665 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) {
666 if (dbpf) {
667 struct timespec until;
668 clock_gettime(CLOCK_MONOTONIC, &until);
669 until.tv_sec += seconds ? *seconds : 10;
670 dbpf->block(addr, until);
671 }
672 });
673
674 g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)()>("purgeExpired", [](std::shared_ptr<DynBPFFilter> dbpf) {
675 if (dbpf) {
676 struct timespec now;
677 clock_gettime(CLOCK_MONOTONIC, &now);
678 dbpf->purgeExpired(now);
679 }
680 });
681
682 g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeRange", [](std::shared_ptr<DynBPFFilter> dbpf, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
683 if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
684 for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
685 dbpf->excludeRange(Netmask(range.second));
686 }
687 }
688 else {
689 dbpf->excludeRange(Netmask(*boost::get<std::string>(&ranges)));
690 }
691 });
692
693 g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("includeRange", [](std::shared_ptr<DynBPFFilter> dbpf, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
694 if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
695 for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
696 dbpf->includeRange(Netmask(range.second));
697 }
698 }
699 else {
700 dbpf->includeRange(Netmask(*boost::get<std::string>(&ranges)));
701 }
702 });
703 #endif /* HAVE_EBPF */
704
705 /* EDNSOptionView */
706 g_lua.registerFunction<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView& option) {
707 return option.values.size();
708 });
709 g_lua.registerFunction<std::vector<string>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView& option) {
710 std::vector<string> values;
711 for (const auto& value : option.values) {
712 values.push_back(std::string(value.content, value.size));
713 }
714 return values;
715 });
716 }