diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:34:30 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:34:30 +0000 |
commit | 4fc2f55f761d71aae1f145d5aa94ba929cc39676 (patch) | |
tree | 5c1e1db3b46dd4edbe11f612d93cb94b96891ce3 /dnsdist-lua-bindings.cc | |
parent | Initial commit. (diff) | |
download | dnsdist-4fc2f55f761d71aae1f145d5aa94ba929cc39676.tar.xz dnsdist-4fc2f55f761d71aae1f145d5aa94ba929cc39676.zip |
Adding upstream version 1.7.3.upstream/1.7.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dnsdist-lua-bindings.cc')
-rw-r--r-- | dnsdist-lua-bindings.cc | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/dnsdist-lua-bindings.cc b/dnsdist-lua-bindings.cc new file mode 100644 index 0000000..e0abed5 --- /dev/null +++ b/dnsdist-lua-bindings.cc @@ -0,0 +1,624 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "config.h" +#include "dnsdist.hh" +#include "dnsdist-lua.hh" +#include "dnsdist-svc.hh" + +#include "dolog.hh" + +void setupLuaBindings(LuaContext& luaCtx, bool client) +{ + luaCtx.writeFunction("infolog", [](const string& arg) { + infolog("%s", arg); + }); + luaCtx.writeFunction("errlog", [](const string& arg) { + errlog("%s", arg); + }); + luaCtx.writeFunction("warnlog", [](const string& arg) { + warnlog("%s", arg); + }); + luaCtx.writeFunction("show", [](const string& arg) { + g_outputBuffer+=arg; + g_outputBuffer+="\n"; + }); + + /* Exceptions */ + luaCtx.registerFunction<string(std::exception_ptr::*)()const>("__tostring", [](const std::exception_ptr& eptr) { + try { + if (eptr) { + std::rethrow_exception(eptr); + } + } catch(const std::exception& e) { + return string(e.what()); + } catch(const PDNSException& e) { + return e.reason; + } catch(...) { + return string("Unknown exception"); + } + return string("No exception"); + }); + /* ServerPolicy */ + luaCtx.writeFunction("newServerPolicy", [](string name, ServerPolicy::policyfunc_t policy) { return std::make_shared<ServerPolicy>(name, policy, true);}); + luaCtx.registerMember("name", &ServerPolicy::d_name); + luaCtx.registerMember("policy", &ServerPolicy::d_policy); + luaCtx.registerMember("ffipolicy", &ServerPolicy::d_ffipolicy); + luaCtx.registerMember("isLua", &ServerPolicy::d_isLua); + luaCtx.registerMember("isFFI", &ServerPolicy::d_isFFI); + luaCtx.registerMember("isPerThread", &ServerPolicy::d_isPerThread); + luaCtx.registerFunction("toString", &ServerPolicy::toString); + luaCtx.registerFunction("__tostring", &ServerPolicy::toString); + + ServerPolicy policies[] = { + ServerPolicy{"firstAvailable", firstAvailable, false}, + ServerPolicy{"roundrobin", roundrobin, false}, + ServerPolicy{"wrandom", wrandom, false}, + ServerPolicy{"whashed", whashed, false}, + ServerPolicy{"chashed", chashed, false}, + ServerPolicy{"leastOutstanding", leastOutstanding, false} + }; + for (auto& policy : policies) { + luaCtx.writeVariable(policy.d_name, policy); + } + + /* ServerPool */ + luaCtx.registerFunction<void(std::shared_ptr<ServerPool>::*)(std::shared_ptr<DNSDistPacketCache>)>("setCache", [](std::shared_ptr<ServerPool> pool, std::shared_ptr<DNSDistPacketCache> cache) { + if (pool) { + pool->packetCache = cache; + } + }); + luaCtx.registerFunction("getCache", &ServerPool::getCache); + luaCtx.registerFunction<void(std::shared_ptr<ServerPool>::*)()>("unsetCache", [](std::shared_ptr<ServerPool> pool) { + if (pool) { + pool->packetCache = nullptr; + } + }); + luaCtx.registerFunction("getECS", &ServerPool::getECS); + luaCtx.registerFunction("setECS", &ServerPool::setECS); + + /* DownstreamState */ + luaCtx.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& s, int lim) { s.qps = lim ? QPSLimiter(lim, lim) : QPSLimiter(); }); + luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](std::shared_ptr<DownstreamState> s, string pool) { + auto localPools = g_pools.getCopy(); + addServerToPool(localPools, pool, s); + g_pools.setState(localPools); + s->pools.insert(pool); + }); + luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](std::shared_ptr<DownstreamState> s, string pool) { + auto localPools = g_pools.getCopy(); + removeServerFromPool(localPools, pool, s); + g_pools.setState(localPools); + s->pools.erase(pool); + }); + luaCtx.registerFunction<uint64_t(DownstreamState::*)()const>("getOutstanding", [](const DownstreamState& s) { return s.outstanding.load(); }); + luaCtx.registerFunction<uint64_t(DownstreamState::*)()const>("getDrops", [](const DownstreamState& s) { return s.reuseds.load(); }); + luaCtx.registerFunction<double(DownstreamState::*)()const>("getLatency", [](const DownstreamState& s) { return s.latencyUsec; }); + luaCtx.registerFunction("isUp", &DownstreamState::isUp); + luaCtx.registerFunction("setDown", &DownstreamState::setDown); + luaCtx.registerFunction("setUp", &DownstreamState::setUp); + luaCtx.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setAuto", [](DownstreamState& s, boost::optional<bool> newStatus) { + if (newStatus) { + s.setUpStatus(*newStatus); + } + s.setAuto(); + }); + luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getName", [](const DownstreamState& s) { return s.getName(); }); + luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getNameWithAddr", [](const DownstreamState& s) { return s.getNameWithAddr(); }); + luaCtx.registerMember("upStatus", &DownstreamState::upStatus); + luaCtx.registerMember<int (DownstreamState::*)>("weight", + [](const DownstreamState& s) -> int {return s.weight;}, + [](DownstreamState& s, int newWeight) {s.setWeight(newWeight);} + ); + luaCtx.registerMember("order", &DownstreamState::order); + luaCtx.registerMember<const std::string(DownstreamState::*)>("name", [](const DownstreamState& backend) -> const std::string { return backend.getName(); }, [](DownstreamState& backend, const std::string& newName) { backend.setName(newName); }); + luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getID", [](const DownstreamState& s) { return boost::uuids::to_string(s.id); }); + + /* dnsheader */ + luaCtx.registerFunction<void(dnsheader::*)(bool)>("setRD", [](dnsheader& dh, bool v) { + dh.rd=v; + }); + + luaCtx.registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) { + return (bool)dh.rd; + }); + + luaCtx.registerFunction<void(dnsheader::*)(bool)>("setRA", [](dnsheader& dh, bool v) { + dh.ra=v; + }); + + luaCtx.registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) { + return (bool)dh.ra; + }); + + luaCtx.registerFunction<void(dnsheader::*)(bool)>("setAD", [](dnsheader& dh, bool v) { + dh.ad=v; + }); + + luaCtx.registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) { + return (bool)dh.ad; + }); + + luaCtx.registerFunction<void(dnsheader::*)(bool)>("setAA", [](dnsheader& dh, bool v) { + dh.aa=v; + }); + + luaCtx.registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) { + return (bool)dh.aa; + }); + + luaCtx.registerFunction<void(dnsheader::*)(bool)>("setCD", [](dnsheader& dh, bool v) { + dh.cd=v; + }); + + luaCtx.registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) { + return (bool)dh.cd; + }); + + luaCtx.registerFunction<void(dnsheader::*)(bool)>("setTC", [](dnsheader& dh, bool v) { + dh.tc=v; + if(v) dh.ra = dh.rd; // you'll always need this, otherwise TC=1 gets ignored + }); + + luaCtx.registerFunction<void(dnsheader::*)(bool)>("setQR", [](dnsheader& dh, bool v) { + dh.qr=v; + }); + + /* ComboAddress */ + luaCtx.writeFunction("newCA", [](const std::string& name) { return ComboAddress(name); }); + luaCtx.writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional<uint16_t> port) { + if (raw.size() == 4) { + struct sockaddr_in sin4; + memset(&sin4, 0, sizeof(sin4)); + sin4.sin_family = AF_INET; + memcpy(&sin4.sin_addr.s_addr, raw.c_str(), raw.size()); + if (port) { + sin4.sin_port = htons(*port); + } + return ComboAddress(&sin4); + } + else if (raw.size() == 16) { + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr.s6_addr, raw.c_str(), raw.size()); + if (port) { + sin6.sin6_port = htons(*port); + } + return ComboAddress(&sin6); + } + return ComboAddress(); + }); + luaCtx.registerFunction<string(ComboAddress::*)()const>("tostring", [](const ComboAddress& ca) { return ca.toString(); }); + luaCtx.registerFunction<string(ComboAddress::*)()const>("tostringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); + luaCtx.registerFunction<string(ComboAddress::*)()const>("__tostring", [](const ComboAddress& ca) { return ca.toString(); }); + luaCtx.registerFunction<string(ComboAddress::*)()const>("toString", [](const ComboAddress& ca) { return ca.toString(); }); + luaCtx.registerFunction<string(ComboAddress::*)()const>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); + luaCtx.registerFunction<uint16_t(ComboAddress::*)()const>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } ); + luaCtx.registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); }); + luaCtx.registerFunction<bool(ComboAddress::*)()const>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; }); + luaCtx.registerFunction<bool(ComboAddress::*)()const>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; }); + luaCtx.registerFunction<bool(ComboAddress::*)()const>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); }); + luaCtx.registerFunction<ComboAddress(ComboAddress::*)()const>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); }); + luaCtx.registerFunction<bool(nmts_t::*)(const ComboAddress&)>("match", [](nmts_t& s, const ComboAddress& ca) { return s.match(ca); }); + + /* DNSName */ + luaCtx.registerFunction("isPartOf", &DNSName::isPartOf); + luaCtx.registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); }); + luaCtx.registerFunction<unsigned int(DNSName::*)()const>("countLabels", [](const DNSName& name) { return name.countLabels(); }); + luaCtx.registerFunction<size_t(DNSName::*)()const>("hash", [](const DNSName& name) { return name.hash(); }); + luaCtx.registerFunction<size_t(DNSName::*)()const>("wirelength", [](const DNSName& name) { return name.wirelength(); }); + luaCtx.registerFunction<string(DNSName::*)()const>("tostring", [](const DNSName&dn ) { return dn.toString(); }); + luaCtx.registerFunction<string(DNSName::*)()const>("toString", [](const DNSName&dn ) { return dn.toString(); }); + luaCtx.registerFunction<string(DNSName::*)()const>("__tostring", [](const DNSName&dn ) { return dn.toString(); }); + luaCtx.registerFunction<string(DNSName::*)()const>("toDNSString", [](const DNSName&dn ) { return dn.toDNSString(); }); + luaCtx.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); }); + luaCtx.writeFunction("newDNSNameFromRaw", [](const std::string& name) { return DNSName(name.c_str(), name.size(), 0, false); }); + luaCtx.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); }); + luaCtx.writeFunction("newDNSNameSet", []() { return DNSNameSet(); }); + + /* DNSNameSet */ + luaCtx.registerFunction<string(DNSNameSet::*)()const>("toString", [](const DNSNameSet&dns ) { return dns.toString(); }); + luaCtx.registerFunction<string(DNSNameSet::*)()const>("__tostring", [](const DNSNameSet&dns ) { return dns.toString(); }); + luaCtx.registerFunction<void(DNSNameSet::*)(DNSName&)>("add", [](DNSNameSet& dns, DNSName& dn) { dns.insert(dn); }); + luaCtx.registerFunction<bool(DNSNameSet::*)(DNSName&)>("check", [](DNSNameSet& dns, DNSName& dn) { return dns.find(dn) != dns.end(); }); + luaCtx.registerFunction("delete",(size_t (DNSNameSet::*)(const DNSName&)) &DNSNameSet::erase); + luaCtx.registerFunction("size",(size_t (DNSNameSet::*)() const) &DNSNameSet::size); + luaCtx.registerFunction("clear",(void (DNSNameSet::*)()) &DNSNameSet::clear); + luaCtx.registerFunction("empty",(bool (DNSNameSet::*)() const) &DNSNameSet::empty); + + /* SuffixMatchNode */ + luaCtx.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) { + if (name.type() == typeid(DNSName)) { + auto n = boost::get<DNSName>(name); + smn.add(n); + return; + } + if (name.type() == typeid(string)) { + auto n = boost::get<string>(name); + smn.add(n); + return; + } + if (name.type() == typeid(vector<pair<int, DNSName>>)) { + auto names = boost::get<vector<pair<int, DNSName>>>(name); + for (const auto& n : names) { + smn.add(n.second); + } + return; + } + if (name.type() == typeid(vector<pair<int, string>>)) { + auto names = boost::get<vector<pair<int, string>>>(name); + for (const auto& n : names) { + smn.add(n.second); + } + return; + } + }); + luaCtx.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name)>("remove", [](SuffixMatchNode &smn, const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name) { + if (name.type() == typeid(DNSName)) { + auto n = boost::get<DNSName>(name); + smn.remove(n); + return; + } + if (name.type() == typeid(string)) { + auto n = boost::get<string>(name); + DNSName d(n); + smn.remove(d); + return; + } + if (name.type() == typeid(vector<pair<int, DNSName>>)) { + auto names = boost::get<vector<pair<int, DNSName>>>(name); + for (const auto& n : names) { + smn.remove(n.second); + } + return; + } + if (name.type() == typeid(vector<pair<int, string>>)) { + auto names = boost::get<vector<pair<int, string>>>(name); + for (const auto& n : names) { + DNSName d(n.second); + smn.remove(d); + } + return; + } + }); + + luaCtx.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); + + /* Netmask */ + luaCtx.writeFunction("newNetmask", [](boost::variant<std::string,ComboAddress> s, boost::optional<uint8_t> bits) { + if (s.type() == typeid(ComboAddress)) { + auto ca = boost::get<ComboAddress>(s); + if (bits) { + return Netmask(ca, *bits); + } + return Netmask(ca); + } + else if (s.type() == typeid(std::string)) { + auto str = boost::get<std::string>(s); + return Netmask(str); + } + throw std::runtime_error("Invalid parameter passed to 'newNetmask()'"); + }); + luaCtx.registerFunction("empty", &Netmask::empty); + luaCtx.registerFunction("getBits", &Netmask::getBits); + luaCtx.registerFunction<ComboAddress(Netmask::*)()const>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary + luaCtx.registerFunction<ComboAddress(Netmask::*)()const>("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } ); + luaCtx.registerFunction("isIpv4", &Netmask::isIPv4); + luaCtx.registerFunction("isIPv4", &Netmask::isIPv4); + luaCtx.registerFunction("isIpv6", &Netmask::isIPv6); + luaCtx.registerFunction("isIPv6", &Netmask::isIPv6); + luaCtx.registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match); + luaCtx.registerFunction("toString", &Netmask::toString); + luaCtx.registerFunction("__tostring", &Netmask::toString); + luaCtx.registerEqFunction(&Netmask::operator==); + luaCtx.registerToStringFunction(&Netmask::toString); + + /* NetmaskGroup */ + luaCtx.writeFunction("newNMG", []() { return NetmaskGroup(); }); + luaCtx.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask) + { + nmg.addMask(mask); + }); + luaCtx.registerFunction<void(NetmaskGroup::*)(const std::map<ComboAddress,int>& map)>("addMasks", [](NetmaskGroup&nmg, const std::map<ComboAddress,int>& map) + { + for (const auto& entry : map) { + nmg.addMask(Netmask(entry.first)); + } + }); + + luaCtx.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match); + luaCtx.registerFunction("size", &NetmaskGroup::size); + luaCtx.registerFunction("clear", &NetmaskGroup::clear); + luaCtx.registerFunction<string(NetmaskGroup::*)()const>("toString", [](const NetmaskGroup& nmg ) { return "NetmaskGroup " + nmg.toString(); }); + luaCtx.registerFunction<string(NetmaskGroup::*)()const>("__tostring", [](const NetmaskGroup& nmg ) { return "NetmaskGroup " + nmg.toString(); }); + + /* QPSLimiter */ + luaCtx.writeFunction("newQPSLimiter", [](int rate, int burst) { return QPSLimiter(rate, burst); }); + luaCtx.registerFunction("check", &QPSLimiter::check); + + /* ClientState */ + luaCtx.registerFunction<std::string(ClientState::*)()const>("toString", [](const ClientState& fe) { + setLuaNoSideEffect(); + return fe.local.toStringWithPort(); + }); + luaCtx.registerFunction<std::string(ClientState::*)()const>("__tostring", [](const ClientState& fe) { + setLuaNoSideEffect(); + return fe.local.toStringWithPort(); + }); + luaCtx.registerFunction<std::string(ClientState::*)()const>("getType", [](const ClientState& fe) { + setLuaNoSideEffect(); + return fe.getType(); + }); + luaCtx.registerFunction<std::string(ClientState::*)()const>("getConfiguredTLSProvider", [](const ClientState& fe) { + setLuaNoSideEffect(); + if (fe.tlsFrontend != nullptr) { + return fe.tlsFrontend->getRequestedProvider(); + } + else if (fe.dohFrontend != nullptr) { + return std::string("openssl"); + } + return std::string(); + }); + luaCtx.registerFunction<std::string(ClientState::*)()const>("getEffectiveTLSProvider", [](const ClientState& fe) { + setLuaNoSideEffect(); + if (fe.tlsFrontend != nullptr) { + return fe.tlsFrontend->getEffectiveProvider(); + } + else if (fe.dohFrontend != nullptr) { + return std::string("openssl"); + } + return std::string(); + }); + luaCtx.registerMember("muted", &ClientState::muted); +#ifdef HAVE_EBPF + luaCtx.registerFunction<void(ClientState::*)(std::shared_ptr<BPFFilter>)>("attachFilter", [](ClientState& frontend, std::shared_ptr<BPFFilter> bpf) { + if (bpf) { + frontend.attachFilter(bpf); + } + }); + luaCtx.registerFunction<void(ClientState::*)()>("detachFilter", [](ClientState& frontend) { + frontend.detachFilter(); + }); +#endif /* HAVE_EBPF */ + + /* BPF Filter */ +#ifdef HAVE_EBPF + using bpfFilterMapParams = boost::variant<uint32_t, std::unordered_map<std::string, boost::variant<uint32_t, std::string>>>; + luaCtx.writeFunction("newBPFFilter", [client](bpfFilterMapParams v4Params, bpfFilterMapParams v6Params, bpfFilterMapParams qnameParams, boost::optional<bool> external) { + if (client) { + return std::shared_ptr<BPFFilter>(nullptr); + } + + BPFFilter::MapConfiguration v4Config, v6Config, qnameConfig; + + auto convertParamsToConfig = [](bpfFilterMapParams& params, BPFFilter::MapType type, BPFFilter::MapConfiguration& config) { + config.d_type = type; + if (params.type() == typeid(uint32_t)) { + config.d_maxItems = boost::get<uint32_t>(params); + } + else if (params.type() == typeid(std::unordered_map<std::string, boost::variant<uint32_t, std::string>>)) { + auto map = boost::get<std::unordered_map<std::string, boost::variant<uint32_t, std::string>>>(params); + if (map.count("maxItems")) { + config.d_maxItems = boost::get<uint32_t>(map.at("maxItems")); + } + if (map.count("pinnedPath")) { + config.d_pinnedPath = boost::get<std::string>(map.at("pinnedPath")); + } + } + }; + + convertParamsToConfig(v4Params, BPFFilter::MapType::IPv4, v4Config); + convertParamsToConfig(v6Params, BPFFilter::MapType::IPv6, v6Config); + convertParamsToConfig(qnameParams, BPFFilter::MapType::QNames, qnameConfig); + + BPFFilter::MapFormat format = BPFFilter::MapFormat::Legacy; + if (external && *external) { + format = BPFFilter::MapFormat::WithActions; + } + + return std::make_shared<BPFFilter>(v4Config, v6Config, qnameConfig, format, external.value_or(false)); + }); + + luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca, boost::optional<uint32_t> action)>("block", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca, boost::optional<uint32_t> action) { + if (bpf) { + if (!action) { + return bpf->block(ca, BPFFilter::MatchAction::Drop); + } + else { + BPFFilter::MatchAction match; + + switch (*action) { + case 0: + match = BPFFilter::MatchAction::Pass; + break; + case 1: + match = BPFFilter::MatchAction::Drop; + break; + case 2: + match = BPFFilter::MatchAction::Truncate; + break; + default: + throw std::runtime_error("Unsupported action for BPFFilter::block"); + } + return bpf->block(ca, match); + } + } + }); + + luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype, boost::optional<uint32_t> action)>("blockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype, boost::optional<uint32_t> action) { + if (bpf) { + if (!action) { + return bpf->block(qname, BPFFilter::MatchAction::Drop, qtype.value_or(255)); + } + else { + BPFFilter::MatchAction match; + + switch (*action) { + case 0: + match = BPFFilter::MatchAction::Pass; + break; + case 1: + match = BPFFilter::MatchAction::Drop; + break; + case 2: + match = BPFFilter::MatchAction::Truncate; + break; + default: + throw std::runtime_error("Unsupported action for BPFFilter::blockQName"); + } + return bpf->block(qname, match, qtype.value_or(255)); + } + } + }); + + luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("unblock", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) { + if (bpf) { + return bpf->unblock(ca); + } + }); + + luaCtx.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) { + if (bpf) { + return bpf->unblock(qname, qtype ? *qtype : 255); + } + }); + + luaCtx.registerFunction<std::string(std::shared_ptr<BPFFilter>::*)()const>("getStats", [](const std::shared_ptr<BPFFilter> bpf) { + setLuaNoSideEffect(); + std::string res; + if (bpf) { + auto stats = bpf->getAddrStats(); + for (const auto& value : stats) { + if (value.first.sin4.sin_family == AF_INET) { + res += value.first.toString() + ": " + std::to_string(value.second) + "\n"; + } + else if (value.first.sin4.sin_family == AF_INET6) { + res += "[" + value.first.toString() + "]: " + std::to_string(value.second) + "\n"; + } + } + auto qstats = bpf->getQNameStats(); + for (const auto& value : qstats) { + res += std::get<0>(value).toString() + " " + std::to_string(std::get<1>(value)) + ": " + std::to_string(std::get<2>(value)) + "\n"; + } + } + return res; + }); + + luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter> bpf) { + std::string res; + if (bpf) { + for (const auto& frontend : g_frontends) { + frontend->attachFilter(bpf); + } + } + }); + + luaCtx.writeFunction("newDynBPFFilter", [client](std::shared_ptr<BPFFilter> bpf) { + if (client) { + return std::shared_ptr<DynBPFFilter>(nullptr); + } + return std::make_shared<DynBPFFilter>(bpf); + }); + + luaCtx.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) { + if (dbpf) { + struct timespec until; + clock_gettime(CLOCK_MONOTONIC, &until); + until.tv_sec += seconds ? *seconds : 10; + dbpf->block(addr, until); + } + }); + + luaCtx.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)()>("purgeExpired", [](std::shared_ptr<DynBPFFilter> dbpf) { + if (dbpf) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + dbpf->purgeExpired(now); + } + }); + + luaCtx.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) { + if (!dbpf) { + return; + } + + if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) { + for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) { + dbpf->excludeRange(Netmask(range.second)); + } + } + else { + dbpf->excludeRange(Netmask(*boost::get<std::string>(&ranges))); + } + }); + + luaCtx.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) { + if (!dbpf) { + return; + } + + if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) { + for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) { + dbpf->includeRange(Netmask(range.second)); + } + } + else { + dbpf->includeRange(Netmask(*boost::get<std::string>(&ranges))); + } + }); +#endif /* HAVE_EBPF */ + + /* EDNSOptionView */ + luaCtx.registerFunction<size_t(EDNSOptionView::*)()const>("count", [](const EDNSOptionView& option) { + return option.values.size(); + }); + luaCtx.registerFunction<std::vector<string>(EDNSOptionView::*)()const>("getValues", [] (const EDNSOptionView& option) { + std::vector<string> values; + for (const auto& value : option.values) { + values.push_back(std::string(value.content, value.size)); + } + return values; + }); + + luaCtx.writeFunction("newDOHResponseMapEntry", [](const std::string& regex, uint16_t status, const std::string& content, boost::optional<std::map<std::string, std::string>> customHeaders) { + boost::optional<std::vector<std::pair<std::string, std::string>>> headers{boost::none}; + if (customHeaders) { + headers = std::vector<std::pair<std::string, std::string>>(); + for (const auto& header : *customHeaders) { + headers->push_back({ boost::to_lower_copy(header.first), header.second }); + } + } + return std::make_shared<DOHResponseMapEntry>(regex, status, PacketBuffer(content.begin(), content.end()), headers); + }); + + luaCtx.writeFunction("newSVCRecordParameters", [](uint16_t priority, const std::string& target, boost::optional<svcParamsLua_t> additionalParameters) + { + SVCRecordParameters parameters; + if (additionalParameters) { + parameters = parseSVCParameters(*additionalParameters); + } + parameters.priority = priority; + parameters.target = DNSName(target); + + return parameters; + }); +} |