/* * 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" #include "dns_random.hh" std::shared_ptr makeRule(const luadnsrule_t& var, const std::string& calledFrom) { if (var.type() == typeid(std::shared_ptr)) { return *boost::get>(&var); } bool suffixSeen = false; SuffixMatchNode smn; NetmaskGroup nmg; auto add = [&nmg, &smn, &suffixSeen](const string& src) { try { nmg.addMask(src); // need to try mask first, all masks are domain names! } catch (...) { suffixSeen = true; smn.add(DNSName(src)); } }; if (var.type() == typeid(string)) { add(*boost::get(&var)); } else if (var.type() == typeid(LuaArray)) { for (const auto& str : *boost::get>(&var)) { add(str.second); } } else if (var.type() == typeid(DNSName)) { smn.add(*boost::get(&var)); } else if (var.type() == typeid(LuaArray)) { smn = SuffixMatchNode(); for (const auto& name : *boost::get>(&var)) { smn.add(name.second); } } if (nmg.empty()) { return std::make_shared(smn); } if (suffixSeen) { warnlog("At least one parameter to %s has been parsed as a domain name amongst network masks, and will be ignored!", calledFrom); } 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, const 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; } template static LuaArray toLuaArray(std::vector&& rules) { LuaArray results; results.reserve(rules.size()); size_t pos = 1; for (auto& rule : rules) { results.emplace_back(pos, std::move(rule)); pos++; } return results; } template static boost::optional getRuleFromSelector(const std::vector& rules, const boost::variant& selector) { if (auto str = boost::get(&selector)) { /* let's see if this a UUID */ try { const auto uuid = getUniqueID(*str); for (const auto& rule : rules) { if (rule.d_id == uuid) { return rule; } } } catch (const std::exception& e) { /* a name, then */ for (const auto& rule : rules) { if (rule.d_name == *str) { return rule; } } } } else if (auto pos = boost::get(&selector)) { /* this will throw a std::out_of_range exception if the supplied position is out of bounds, this is fine */ return rules.at(*pos); } return boost::none; } namespace { std::shared_ptr qnameSuffixRule(const boost::variant> names, boost::optional quiet) { if (names.type() == typeid(string)) { SuffixMatchNode smn; smn.add(DNSName(*boost::get(&names))); return std::shared_ptr(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); } if (names.type() == typeid(LuaArray)) { SuffixMatchNode smn; for (const auto& str : *boost::get>(&names)) { smn.add(DNSName(str.second)); } return std::shared_ptr(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); } const auto& smn = *boost::get(&names); return std::shared_ptr(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); } } // NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold void setupLuaRules(LuaContext& luaCtx) { luaCtx.writeFunction("makeRule", [](const luadnsrule_t& var) -> std::shared_ptr { return makeRule(var, "makeRule"); }); luaCtx.registerFunction::*)()const>("toString", [](const std::shared_ptr& rule) { return rule->toString(); }); luaCtx.registerFunction::*)()const>("getMatches", [](const std::shared_ptr& rule) { return rule->d_matches.load(); }); luaCtx.registerFunction(DNSDistRuleAction::*)()const>("getSelector", [](const DNSDistRuleAction& rule) { return rule.d_rule; }); luaCtx.registerFunction(DNSDistRuleAction::*)()const>("getAction", [](const DNSDistRuleAction& rule) { return rule.d_action; }); luaCtx.registerFunction(DNSDistResponseRuleAction::*)()const>("getSelector", [](const DNSDistResponseRuleAction& rule) { return rule.d_rule; }); luaCtx.registerFunction(DNSDistResponseRuleAction::*)()const>("getAction", [](const DNSDistResponseRuleAction& rule) { return rule.d_action; }); 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 = newruleaction->d_rule; gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder}); } } }); }); luaCtx.writeFunction("getRule", [](boost::variant selector) -> boost::optional { auto rules = g_ruleactions.getLocal(); return getRuleFromSelector(*rules, selector); }); luaCtx.writeFunction("getTopRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_ruleactions.getLocal(); return toLuaArray(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("getCacheHitResponseRule", [](boost::variant selector) -> boost::optional { auto rules = g_cachehitrespruleactions.getLocal(); return getRuleFromSelector(*rules, selector); }); luaCtx.writeFunction("getTopCacheHitResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_cachehitrespruleactions.getLocal(); return toLuaArray(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("getCacheInsertedResponseRule", [](boost::variant selector) -> boost::optional { auto rules = g_cacheInsertedRespRuleActions.getLocal(); return getRuleFromSelector(*rules, selector); }); luaCtx.writeFunction("getTopCacheInsertedResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_cacheInsertedRespRuleActions.getLocal(); return toLuaArray(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("getResponseRule", [](boost::variant selector) -> boost::optional { auto rules = g_respruleactions.getLocal(); return getRuleFromSelector(*rules, selector); }); luaCtx.writeFunction("getTopResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_respruleactions.getLocal(); return toLuaArray(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("getSelfAnsweredResponseRule", [](boost::variant selector) -> boost::optional { auto rules = g_selfansweredrespruleactions.getLocal(); return getRuleFromSelector(*rules, selector); }); luaCtx.writeFunction("getTopSelfAnsweredResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_selfansweredrespruleactions.getLocal(); return toLuaArray(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", qnameSuffixRule); luaCtx.writeFunction("NetmaskGroupRule", [](const boost::variant> netmasks, boost::optional src, boost::optional quiet) { if (netmasks.type() == typeid(string)) { NetmaskGroup nmg; nmg.addMask(*boost::get(&netmasks)); return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); } if (netmasks.type() == typeid(LuaArray)) { NetmaskGroup nmg; for (const auto& str : *boost::get>(&netmasks)) { nmg.addMask(str.second); } return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); } const auto& nmg = *boost::get(&netmasks); 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(dns_random_uint32())); i.ids.qname += suffix; i.ids.qtype = dns_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 us\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("QNameSuffixRule", qnameSuffixRule); 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, std::move(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, std::move(value))); }); luaCtx.writeFunction("PayloadSizeRule", [](const std::string& comparison, uint16_t size) { return std::shared_ptr(new PayloadSizeRule(comparison, size)); }); }