From 3cd01b932e1c85394272ae64fae67ebeda92fb00 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 23:11:59 +0200 Subject: Adding upstream version 1.8.3. Signed-off-by: Daniel Baumann --- dnsdist-lua-rules.cc | 662 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 662 insertions(+) create mode 100644 dnsdist-lua-rules.cc (limited to 'dnsdist-lua-rules.cc') diff --git a/dnsdist-lua-rules.cc b/dnsdist-lua-rules.cc new file mode 100644 index 0000000..da309e5 --- /dev/null +++ b/dnsdist-lua-rules.cc @@ -0,0 +1,662 @@ +/* + * 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 "dnsdist.hh" +#include "dnsdist-lua.hh" +#include "dnsdist-rules.hh" + +std::shared_ptr makeRule(const luadnsrule_t& var) +{ + if (var.type() == typeid(std::shared_ptr)) + return *boost::get>(&var); + + SuffixMatchNode smn; + NetmaskGroup nmg; + auto add=[&](string src) { + try { + nmg.addMask(src); // need to try mask first, all masks are domain names! + } catch(...) { + smn.add(DNSName(src)); + } + }; + + if (var.type() == typeid(string)) + add(*boost::get(&var)); + + else if (var.type() == typeid(LuaArray)) + for(const auto& a : *boost::get>(&var)) + add(a.second); + + else if (var.type() == typeid(DNSName)) + smn.add(*boost::get(&var)); + + else if (var.type() == typeid(LuaArray)) + for(const auto& a : *boost::get>(&var)) + smn.add(a.second); + + if(nmg.empty()) + return std::make_shared(smn); + else + return std::make_shared(nmg, true); +} + +static boost::uuids::uuid makeRuleID(std::string& id) +{ + if (id.empty()) { + return getUniqueID(); + } + + return getUniqueID(id); +} + +void parseRuleParams(boost::optional& params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder) +{ + static uint64_t s_creationOrder = 0; + + string uuidStr; + + getOptionalValue(params, "uuid", uuidStr); + getOptionalValue(params, "name", name); + + uuid = makeRuleID(uuidStr); + creationOrder = s_creationOrder++; +} + +typedef LuaAssociativeTable > > ruleparams_t; + +template +static std::string rulesToString(const std::vector& rules, boost::optional vars) +{ + int num = 0; + bool showUUIDs = false; + size_t truncateRuleWidth = string::npos; + std::string result; + + getOptionalValue(vars, "showUUIDs", showUUIDs); + getOptionalValue(vars, "truncateRuleWidth", truncateRuleWidth); + checkAllParametersConsumed("rulesToString", vars); + + if (showUUIDs) { + boost::format fmt("%-3d %-30s %-38s %9d %9d %-56s %s\n"); + result += (fmt % "#" % "Name" % "UUID" % "Cr. Order" % "Matches" % "Rule" % "Action").str(); + for(const auto& lim : rules) { + string desc = lim.d_rule->toString().substr(0, truncateRuleWidth); + result += (fmt % num % lim.d_name % boost::uuids::to_string(lim.d_id) % lim.d_creationOrder % lim.d_rule->d_matches % desc % lim.d_action->toString()).str(); + ++num; + } + } + else { + boost::format fmt("%-3d %-30s %9d %-56s %s\n"); + result += (fmt % "#" % "Name" % "Matches" % "Rule" % "Action").str(); + for(const auto& lim : rules) { + string desc = lim.d_rule->toString().substr(0, truncateRuleWidth); + result += (fmt % num % lim.d_name % lim.d_rule->d_matches % desc % lim.d_action->toString()).str(); + ++num; + } + } + return result; +} + +template +static void showRules(GlobalStateHolder > *someRuleActions, boost::optional vars) { + setLuaNoSideEffect(); + + auto rules = someRuleActions->getLocal(); + g_outputBuffer += rulesToString(*rules, vars); +} + +template +static void rmRule(GlobalStateHolder > *someRuleActions, boost::variant id) { + setLuaSideEffect(); + auto rules = someRuleActions->getCopy(); + if (auto str = boost::get(&id)) { + try { + const auto uuid = getUniqueID(*str); + auto removeIt = std::remove_if(rules.begin(), + rules.end(), + [&uuid](const T& rule) { return rule.d_id == uuid; }); + if (removeIt == rules.end()) { + g_outputBuffer = "Error: no rule matched\n"; + return; + } + rules.erase(removeIt, + rules.end()); + } + catch (const std::runtime_error& e) { + /* it was not an UUID, let's see if it was a name instead */ + auto removeIt = std::remove_if(rules.begin(), + rules.end(), + [&str](const T& rule) { return rule.d_name == *str; }); + if (removeIt == rules.end()) { + g_outputBuffer = "Error: no rule matched\n"; + return; + } + rules.erase(removeIt, + rules.end()); + } + } + else if (auto pos = boost::get(&id)) { + if (*pos >= rules.size()) { + g_outputBuffer = "Error: attempt to delete non-existing rule\n"; + return; + } + rules.erase(rules.begin()+*pos); + } + someRuleActions->setState(std::move(rules)); +} + +template +static void moveRuleToTop(GlobalStateHolder > *someRuleActions) { + setLuaSideEffect(); + auto rules = someRuleActions->getCopy(); + if(rules.empty()) + return; + auto subject = *rules.rbegin(); + rules.erase(std::prev(rules.end())); + rules.insert(rules.begin(), subject); + someRuleActions->setState(std::move(rules)); +} + +template +static void mvRule(GlobalStateHolder > *someRespRuleActions, unsigned int from, unsigned int to) { + setLuaSideEffect(); + auto rules = someRespRuleActions->getCopy(); + if(from >= rules.size() || to > rules.size()) { + g_outputBuffer = "Error: attempt to move rules from/to invalid index\n"; + return; + } + auto subject = rules[from]; + rules.erase(rules.begin()+from); + if(to > rules.size()) + rules.push_back(subject); + else { + if(from < to) + --to; + rules.insert(rules.begin()+to, subject); + } + someRespRuleActions->setState(std::move(rules)); +} + +template +static std::vector getTopRules(const std::vector& rules, unsigned int top) +{ + std::vector> counts; + counts.reserve(rules.size()); + + size_t pos = 0; + for (const auto& rule : rules) { + counts.push_back({rule.d_rule->d_matches.load(), pos}); + pos++; + } + + sort(counts.begin(), counts.end(), [](const decltype(counts)::value_type& a, + const decltype(counts)::value_type& b) { + return b.first < a.first; + }); + + std::vector results; + results.reserve(top); + + size_t count = 0; + for (const auto& entry : counts) { + results.emplace_back(rules.at(entry.second)); + ++count; + if (count == top) { + break; + } + } + + return results; +} + +void setupLuaRules(LuaContext& luaCtx) +{ + luaCtx.writeFunction("makeRule", makeRule); + + luaCtx.registerFunction::*)()const>("toString", [](const std::shared_ptr& rule) { return rule->toString(); }); + + luaCtx.writeFunction("showResponseRules", [](boost::optional vars) { + showRules(&g_respruleactions, vars); + }); + + luaCtx.writeFunction("rmResponseRule", [](boost::variant id) { + rmRule(&g_respruleactions, id); + }); + + luaCtx.writeFunction("mvResponseRuleToTop", []() { + moveRuleToTop(&g_respruleactions); + }); + + luaCtx.writeFunction("mvResponseRule", [](unsigned int from, unsigned int to) { + mvRule(&g_respruleactions, from, to); + }); + + luaCtx.writeFunction("showCacheHitResponseRules", [](boost::optional vars) { + showRules(&g_cachehitrespruleactions, vars); + }); + + luaCtx.writeFunction("rmCacheHitResponseRule", [](boost::variant id) { + rmRule(&g_cachehitrespruleactions, id); + }); + + luaCtx.writeFunction("mvCacheHitResponseRuleToTop", []() { + moveRuleToTop(&g_cachehitrespruleactions); + }); + + luaCtx.writeFunction("mvCacheHitResponseRule", [](unsigned int from, unsigned int to) { + mvRule(&g_cachehitrespruleactions, from, to); + }); + + luaCtx.writeFunction("showCacheInsertedResponseRules", [](boost::optional vars) { + showRules(&g_cacheInsertedRespRuleActions, vars); + }); + + luaCtx.writeFunction("rmCacheInsertedResponseRule", [](boost::variant id) { + rmRule(&g_cacheInsertedRespRuleActions, id); + }); + + luaCtx.writeFunction("mvCacheInsertedResponseRuleToTop", []() { + moveRuleToTop(&g_cacheInsertedRespRuleActions); + }); + + luaCtx.writeFunction("mvCacheInsertedResponseRule", [](unsigned int from, unsigned int to) { + mvRule(&g_cacheInsertedRespRuleActions, from, to); + }); + + luaCtx.writeFunction("showSelfAnsweredResponseRules", [](boost::optional vars) { + showRules(&g_selfansweredrespruleactions, vars); + }); + + luaCtx.writeFunction("rmSelfAnsweredResponseRule", [](boost::variant id) { + rmRule(&g_selfansweredrespruleactions, id); + }); + + luaCtx.writeFunction("mvSelfAnsweredResponseRuleToTop", []() { + moveRuleToTop(&g_selfansweredrespruleactions); + }); + + luaCtx.writeFunction("mvSelfAnsweredResponseRule", [](unsigned int from, unsigned int to) { + mvRule(&g_selfansweredrespruleactions, from, to); + }); + + luaCtx.writeFunction("rmRule", [](boost::variant id) { + rmRule(&g_ruleactions, id); + }); + + luaCtx.writeFunction("mvRuleToTop", []() { + moveRuleToTop(&g_ruleactions); + }); + + luaCtx.writeFunction("mvRule", [](unsigned int from, unsigned int to) { + mvRule(&g_ruleactions, from, to); + }); + + luaCtx.writeFunction("clearRules", []() { + setLuaSideEffect(); + g_ruleactions.modify([](decltype(g_ruleactions)::value_type& ruleactions) { + ruleactions.clear(); + }); + }); + + luaCtx.writeFunction("setRules", [](const LuaArray>& newruleactions) { + setLuaSideEffect(); + g_ruleactions.modify([newruleactions](decltype(g_ruleactions)::value_type& gruleactions) { + gruleactions.clear(); + for (const auto& pair : newruleactions) { + const auto& newruleaction = pair.second; + if (newruleaction->d_action) { + auto rule = makeRule(newruleaction->d_rule); + gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder}); + } + } + }); + }); + + luaCtx.writeFunction("getTopRules", [](boost::optional top) { + setLuaNoSideEffect(); + auto rules = g_ruleactions.getLocal(); + return getTopRules(*rules, (top ? *top : 10)); + }); + + luaCtx.writeFunction("topRules", [](boost::optional top, boost::optional vars) { + setLuaNoSideEffect(); + auto rules = g_ruleactions.getLocal(); + return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); + }); + + luaCtx.writeFunction("getTopCacheHitResponseRules", [](boost::optional top) { + setLuaNoSideEffect(); + auto rules = g_cachehitrespruleactions.getLocal(); + return getTopRules(*rules, (top ? *top : 10)); + }); + + luaCtx.writeFunction("topCacheHitResponseRules", [](boost::optional top, boost::optional vars) { + setLuaNoSideEffect(); + auto rules = g_cachehitrespruleactions.getLocal(); + return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); + }); + + luaCtx.writeFunction("getTopCacheInsertedResponseRules", [](boost::optional top) { + setLuaNoSideEffect(); + auto rules = g_cacheInsertedRespRuleActions.getLocal(); + return getTopRules(*rules, (top ? *top : 10)); + }); + + luaCtx.writeFunction("topCacheInsertedResponseRules", [](boost::optional top, boost::optional vars) { + setLuaNoSideEffect(); + auto rules = g_cacheInsertedRespRuleActions.getLocal(); + return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); + }); + + luaCtx.writeFunction("getTopResponseRules", [](boost::optional top) { + setLuaNoSideEffect(); + auto rules = g_respruleactions.getLocal(); + return getTopRules(*rules, (top ? *top : 10)); + }); + + luaCtx.writeFunction("topResponseRules", [](boost::optional top, boost::optional vars) { + setLuaNoSideEffect(); + auto rules = g_respruleactions.getLocal(); + return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); + }); + + luaCtx.writeFunction("getTopSelfAnsweredResponseRules", [](boost::optional top) { + setLuaNoSideEffect(); + auto rules = g_selfansweredrespruleactions.getLocal(); + return getTopRules(*rules, (top ? *top : 10)); + }); + + luaCtx.writeFunction("topSelfAnsweredResponseRules", [](boost::optional top, boost::optional vars) { + setLuaNoSideEffect(); + auto rules = g_selfansweredrespruleactions.getLocal(); + return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); + }); + + luaCtx.writeFunction("MaxQPSIPRule", [](unsigned int qps, boost::optional ipv4trunc, boost::optional ipv6trunc, boost::optional burst, boost::optional expiration, boost::optional cleanupDelay, boost::optional scanFraction, boost::optional shards) { + return std::shared_ptr(new MaxQPSIPRule(qps, (burst ? *burst : qps), (ipv4trunc ? *ipv4trunc : 32), (ipv6trunc ? *ipv6trunc : 64), (expiration ? *expiration : 300), (cleanupDelay ? *cleanupDelay : 60), (scanFraction ? *scanFraction : 10), (shards ? *shards : 10))); + }); + + luaCtx.writeFunction("MaxQPSRule", [](unsigned int qps, boost::optional burst) { + if(!burst) + return std::shared_ptr(new MaxQPSRule(qps)); + else + return std::shared_ptr(new MaxQPSRule(qps, *burst)); + }); + + luaCtx.writeFunction("RegexRule", [](const std::string& str) { + return std::shared_ptr(new RegexRule(str)); + }); + +#ifdef HAVE_DNS_OVER_HTTPS + luaCtx.writeFunction("HTTPHeaderRule", [](const std::string& header, const std::string& regex) { + return std::shared_ptr(new HTTPHeaderRule(header, regex)); + }); + luaCtx.writeFunction("HTTPPathRule", [](const std::string& path) { + return std::shared_ptr(new HTTPPathRule(path)); + }); + luaCtx.writeFunction("HTTPPathRegexRule", [](const std::string& regex) { + return std::shared_ptr(new HTTPPathRegexRule(regex)); + }); +#endif + +#ifdef HAVE_RE2 + luaCtx.writeFunction("RE2Rule", [](const std::string& str) { + return std::shared_ptr(new RE2Rule(str)); + }); +#endif + + luaCtx.writeFunction("SNIRule", [](const std::string& name) { + return std::shared_ptr(new SNIRule(name)); + }); + + luaCtx.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional quiet) { + return std::shared_ptr(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); + }); + + luaCtx.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional src, boost::optional quiet) { + return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); + }); + + luaCtx.writeFunction("benchRule", [](std::shared_ptr rule, boost::optional times_, boost::optional suffix_) { + setLuaNoSideEffect(); + unsigned int times = times_ ? *times_ : 100000; + DNSName suffix(suffix_ ? *suffix_ : "powerdns.com"); + struct item { + PacketBuffer packet; + InternalQueryState ids; + }; + vector items; + items.reserve(1000); + for (int n = 0; n < 1000; ++n) { + struct item i; + i.ids.qname = DNSName(std::to_string(random())); + i.ids.qname += suffix; + i.ids.qtype = random() % 0xff; + i.ids.qclass = QClass::IN; + i.ids.protocol = dnsdist::Protocol::DoUDP; + i.ids.origRemote = ComboAddress("127.0.0.1"); + i.ids.origRemote.sin4.sin_addr.s_addr = random(); + i.ids.queryRealTime.start(); + GenericDNSPacketWriter pw(i.packet, i.ids.qname, i.ids.qtype); + items.push_back(std::move(i)); + } + + int matches = 0; + ComboAddress dummy("127.0.0.1"); + StopWatch sw; + sw.start(); + for (unsigned int n = 0; n < times; ++n) { + item& i = items[n % items.size()]; + DNSQuestion dq(i.ids, i.packet); + + if (rule->matches(&dq)) { + matches++; + } + } + double udiff = sw.udiff(); + g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f usec\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str(); + + }); + + luaCtx.writeFunction("AllRule", []() { + return std::shared_ptr(new AllRule()); + }); + + luaCtx.writeFunction("ProbaRule", [](double proba) { + return std::shared_ptr(new ProbaRule(proba)); + }); + + luaCtx.writeFunction("QNameRule", [](const std::string& qname) { + return std::shared_ptr(new QNameRule(DNSName(qname))); + }); + + luaCtx.writeFunction("QTypeRule", [](boost::variant str) { + uint16_t qtype; + if (auto dir = boost::get(&str)) { + qtype = *dir; + } + else { + string val = boost::get(str); + qtype = QType::chartocode(val.c_str()); + if (!qtype) { + throw std::runtime_error("Unable to convert '"+val+"' to a DNS type"); + } + } + return std::shared_ptr(new QTypeRule(qtype)); + }); + + luaCtx.writeFunction("QClassRule", [](uint64_t c) { + checkParameterBound("QClassRule", c, std::numeric_limits::max()); + return std::shared_ptr(new QClassRule(c)); + }); + + luaCtx.writeFunction("OpcodeRule", [](uint64_t code) { + checkParameterBound("OpcodeRule", code, std::numeric_limits::max()); + return std::shared_ptr(new OpcodeRule(code)); + }); + + luaCtx.writeFunction("AndRule", [](const LuaArray>& a) { + return std::shared_ptr(new AndRule(a)); + }); + + luaCtx.writeFunction("OrRule", [](const LuaArray>& a) { + return std::shared_ptr(new OrRule(a)); + }); + + luaCtx.writeFunction("DSTPortRule", [](uint64_t port) { + checkParameterBound("DSTPortRule", port, std::numeric_limits::max()); + return std::shared_ptr(new DSTPortRule(port)); + }); + + luaCtx.writeFunction("TCPRule", [](bool tcp) { + return std::shared_ptr(new TCPRule(tcp)); + }); + + luaCtx.writeFunction("DNSSECRule", []() { + return std::shared_ptr(new DNSSECRule()); + }); + + luaCtx.writeFunction("NotRule", [](const std::shared_ptr& rule) { + return std::shared_ptr(new NotRule(rule)); + }); + + luaCtx.writeFunction("RecordsCountRule", [](uint64_t section, uint64_t minCount, uint64_t maxCount) { + checkParameterBound("RecordsCountRule", section, std::numeric_limits::max()); + checkParameterBound("RecordsCountRule", minCount, std::numeric_limits::max()); + checkParameterBound("RecordsCountRule", maxCount, std::numeric_limits::max()); + return std::shared_ptr(new RecordsCountRule(section, minCount, maxCount)); + }); + + luaCtx.writeFunction("RecordsTypeCountRule", [](uint64_t section, uint64_t type, uint64_t minCount, uint64_t maxCount) { + checkParameterBound("RecordsTypeCountRule", section, std::numeric_limits::max()); + checkParameterBound("RecordsTypeCountRule", type, std::numeric_limits::max()); + checkParameterBound("RecordsTypeCountRule", minCount, std::numeric_limits::max()); + checkParameterBound("RecordsTypeCountRule", maxCount, std::numeric_limits::max()); + return std::shared_ptr(new RecordsTypeCountRule(section, type, minCount, maxCount)); + }); + + luaCtx.writeFunction("TrailingDataRule", []() { + return std::shared_ptr(new TrailingDataRule()); + }); + + luaCtx.writeFunction("QNameLabelsCountRule", [](uint64_t minLabelsCount, uint64_t maxLabelsCount) { + checkParameterBound("QNameLabelsCountRule", minLabelsCount, std::numeric_limits::max()); + checkParameterBound("QNameLabelsCountRule", maxLabelsCount, std::numeric_limits::max()); + return std::shared_ptr(new QNameLabelsCountRule(minLabelsCount, maxLabelsCount)); + }); + + luaCtx.writeFunction("QNameWireLengthRule", [](uint64_t min, uint64_t max) { + return std::shared_ptr(new QNameWireLengthRule(min, max)); + }); + + luaCtx.writeFunction("RCodeRule", [](uint64_t rcode) { + checkParameterBound("RCodeRule", rcode, std::numeric_limits::max()); + return std::shared_ptr(new RCodeRule(rcode)); + }); + + luaCtx.writeFunction("ERCodeRule", [](uint64_t rcode) { + checkParameterBound("ERCodeRule", rcode, std::numeric_limits::max()); + return std::shared_ptr(new ERCodeRule(rcode)); + }); + + luaCtx.writeFunction("EDNSVersionRule", [](uint64_t version) { + checkParameterBound("EDNSVersionRule", version, std::numeric_limits::max()); + return std::shared_ptr(new EDNSVersionRule(version)); + }); + + luaCtx.writeFunction("EDNSOptionRule", [](uint64_t optcode) { + checkParameterBound("EDNSOptionRule", optcode, std::numeric_limits::max()); + return std::shared_ptr(new EDNSOptionRule(optcode)); + }); + + luaCtx.writeFunction("showRules", [](boost::optional vars) { + showRules(&g_ruleactions, vars); + }); + + luaCtx.writeFunction("RDRule", []() { + return std::shared_ptr(new RDRule()); + }); + + luaCtx.writeFunction("TagRule", [](const std::string& tag, boost::optional value) { + return std::shared_ptr(new TagRule(tag, value)); + }); + + luaCtx.writeFunction("TimedIPSetRule", []() { + return std::shared_ptr(new TimedIPSetRule()); + }); + + luaCtx.writeFunction("PoolAvailableRule", [](const std::string& poolname) { + return std::shared_ptr(new PoolAvailableRule(poolname)); + }); + + luaCtx.writeFunction("PoolOutstandingRule", [](const std::string& poolname, uint64_t limit) { + return std::shared_ptr(new PoolOutstandingRule(poolname, limit)); + }); + + luaCtx.registerFunction::*)()>("clear", [](std::shared_ptr tisr) { + tisr->clear(); + }); + + luaCtx.registerFunction::*)()>("cleanup", [](std::shared_ptr tisr) { + tisr->cleanup(); + }); + + luaCtx.registerFunction::*)(const ComboAddress& ca, int t)>("add", [](std::shared_ptr tisr, const ComboAddress& ca, int t) { + tisr->add(ca, time(0)+t); + }); + + luaCtx.registerFunction(std::shared_ptr::*)()>("slice", [](std::shared_ptr tisr) { + return std::dynamic_pointer_cast(tisr); + }); + luaCtx.registerFunction::*)()>("__tostring", [](std::shared_ptr tisr) { + tisr->toString(); + }); + + luaCtx.writeFunction("QNameSetRule", [](const DNSNameSet& names) { + return std::shared_ptr(new QNameSetRule(names)); + }); + +#if defined(HAVE_LMDB) || defined(HAVE_CDB) + luaCtx.writeFunction("KeyValueStoreLookupRule", [](std::shared_ptr& kvs, std::shared_ptr& lookupKey) { + return std::shared_ptr(new KeyValueStoreLookupRule(kvs, lookupKey)); + }); + + luaCtx.writeFunction("KeyValueStoreRangeLookupRule", [](std::shared_ptr& kvs, std::shared_ptr& lookupKey) { + return std::shared_ptr(new KeyValueStoreRangeLookupRule(kvs, lookupKey)); + }); +#endif /* defined(HAVE_LMDB) || defined(HAVE_CDB) */ + + luaCtx.writeFunction("LuaRule", [](LuaRule::func_t func) { + return std::shared_ptr(new LuaRule(func)); + }); + + luaCtx.writeFunction("LuaFFIRule", [](LuaFFIRule::func_t func) { + return std::shared_ptr(new LuaFFIRule(func)); + }); + + luaCtx.writeFunction("LuaFFIPerThreadRule", [](const std::string& code) { + return std::shared_ptr(new LuaFFIPerThreadRule(code)); + }); + + luaCtx.writeFunction("ProxyProtocolValueRule", [](uint8_t type, boost::optional value) { + return std::shared_ptr(new ProxyProtocolValueRule(type, value)); + }); +} -- cgit v1.2.3