summaryrefslogtreecommitdiffstats
path: root/dnsdist-lua-rules.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dnsdist-lua-rules.cc')
-rw-r--r--dnsdist-lua-rules.cc621
1 files changed, 621 insertions, 0 deletions
diff --git a/dnsdist-lua-rules.cc b/dnsdist-lua-rules.cc
new file mode 100644
index 0000000..19eec4c
--- /dev/null
+++ b/dnsdist-lua-rules.cc
@@ -0,0 +1,621 @@
+/*
+ * 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<DNSRule> makeRule(const luadnsrule_t& var)
+{
+ if (var.type() == typeid(std::shared_ptr<DNSRule>))
+ return *boost::get<std::shared_ptr<DNSRule>>(&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<string>(&var));
+
+ else if (var.type() == typeid(vector<pair<int, string>>))
+ for(const auto& a : *boost::get<vector<pair<int, string>>>(&var))
+ add(a.second);
+
+ else if (var.type() == typeid(DNSName))
+ smn.add(*boost::get<DNSName>(&var));
+
+ else if (var.type() == typeid(vector<pair<int, DNSName>>))
+ for(const auto& a : *boost::get<vector<pair<int, DNSName>>>(&var))
+ smn.add(a.second);
+
+ if(nmg.empty())
+ return std::make_shared<SuffixMatchNodeRule>(smn);
+ else
+ return std::make_shared<NetmaskGroupRule>(nmg, true);
+}
+
+static boost::uuids::uuid makeRuleID(std::string& id)
+{
+ if (id.empty()) {
+ return getUniqueID();
+ }
+
+ return getUniqueID(id);
+}
+
+void parseRuleParams(boost::optional<luaruleparams_t> params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder)
+{
+ static uint64_t s_creationOrder = 0;
+
+ string uuidStr;
+
+ if (params) {
+ if (params->count("uuid")) {
+ uuidStr = boost::get<std::string>((*params)["uuid"]);
+ }
+ if (params->count("name")) {
+ name = boost::get<std::string>((*params)["name"]);
+ }
+ }
+
+ uuid = makeRuleID(uuidStr);
+ creationOrder = s_creationOrder++;
+}
+
+typedef std::unordered_map<std::string, boost::variant<bool, int, std::string, std::vector<std::pair<int,int> > > > ruleparams_t;
+
+template<typename T>
+static std::string rulesToString(const std::vector<T>& rules, boost::optional<ruleparams_t> vars)
+{
+ int num = 0;
+ bool showUUIDs = false;
+ size_t truncateRuleWidth = string::npos;
+ std::string result;
+
+ if (vars) {
+ if (vars->count("showUUIDs")) {
+ showUUIDs = boost::get<bool>((*vars)["showUUIDs"]);
+ }
+ if (vars->count("truncateRuleWidth")) {
+ truncateRuleWidth = boost::get<int>((*vars)["truncateRuleWidth"]);
+ }
+ }
+
+ 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<typename T>
+static void showRules(GlobalStateHolder<vector<T> > *someRuleActions, boost::optional<ruleparams_t> vars) {
+ setLuaNoSideEffect();
+
+ auto rules = someRuleActions->getLocal();
+ g_outputBuffer += rulesToString(*rules, vars);
+}
+
+template<typename T>
+static void rmRule(GlobalStateHolder<vector<T> > *someRuleActions, boost::variant<unsigned int, std::string> id) {
+ setLuaSideEffect();
+ auto rules = someRuleActions->getCopy();
+ if (auto str = boost::get<std::string>(&id)) {
+ try {
+ const auto uuid = getUniqueID(*str);
+ if (rules.erase(std::remove_if(rules.begin(),
+ rules.end(),
+ [uuid](const T& a) { return a.d_id == uuid; }),
+ rules.end()) == rules.end()) {
+ g_outputBuffer = "Error: no rule matched\n";
+ return;
+ }
+ }
+ catch (const std::runtime_error& e) {
+ /* it was not an UUID, let's see if it was a name instead */
+ if (rules.erase(std::remove_if(rules.begin(),
+ rules.end(),
+ [&str](const T& a) { return a.d_name == *str; }),
+ rules.end()) == rules.end()) {
+ g_outputBuffer = "Error: no rule matched\n";
+ return;
+ }
+ }
+ }
+ else if (auto pos = boost::get<unsigned int>(&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<typename T>
+static void moveRuleToTop(GlobalStateHolder<vector<T> > *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<typename T>
+static void mvRule(GlobalStateHolder<vector<T> > *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<typename T>
+static std::vector<T> getTopRules(const std::vector<T>& rules, unsigned int top)
+{
+ std::vector<std::pair<size_t, size_t>> 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<T> 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<string(std::shared_ptr<DNSRule>::*)()const>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); });
+
+ luaCtx.writeFunction("showResponseRules", [](boost::optional<ruleparams_t> vars) {
+ showRules(&g_respruleactions, vars);
+ });
+
+ luaCtx.writeFunction("rmResponseRule", [](boost::variant<unsigned int, std::string> 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<ruleparams_t> vars) {
+ showRules(&g_cachehitrespruleactions, vars);
+ });
+
+ luaCtx.writeFunction("rmCacheHitResponseRule", [](boost::variant<unsigned int, std::string> 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("showSelfAnsweredResponseRules", [](boost::optional<ruleparams_t> vars) {
+ showRules(&g_selfansweredrespruleactions, vars);
+ });
+
+ luaCtx.writeFunction("rmSelfAnsweredResponseRule", [](boost::variant<unsigned int, std::string> 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<unsigned int, std::string> 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 std::vector<std::pair<int, std::shared_ptr<DNSDistRuleAction>>>& 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<unsigned int> top) {
+ setLuaNoSideEffect();
+ auto rules = g_ruleactions.getLocal();
+ return getTopRules(*rules, top.get_value_or(10));
+ });
+
+ luaCtx.writeFunction("topRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
+ setLuaNoSideEffect();
+ auto rules = g_ruleactions.getLocal();
+ return rulesToString(getTopRules(*rules, top.get_value_or(10)), vars);
+ });
+
+ luaCtx.writeFunction("getCacheHitResponseRules", [](boost::optional<unsigned int> top) {
+ setLuaNoSideEffect();
+ auto rules = g_cachehitrespruleactions.getLocal();
+ return getTopRules(*rules, top.get_value_or(10));
+ });
+
+ luaCtx.writeFunction("topCacheHitRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
+ setLuaNoSideEffect();
+ auto rules = g_cachehitrespruleactions.getLocal();
+ return rulesToString(getTopRules(*rules, top.get_value_or(10)), vars);
+ });
+
+ luaCtx.writeFunction("getTopResponseRules", [](boost::optional<unsigned int> top) {
+ setLuaNoSideEffect();
+ auto rules = g_respruleactions.getLocal();
+ return getTopRules(*rules, top.get_value_or(10));
+ });
+
+ luaCtx.writeFunction("topResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
+ setLuaNoSideEffect();
+ auto rules = g_respruleactions.getLocal();
+ return rulesToString(getTopRules(*rules, top.get_value_or(10)), vars);
+ });
+
+ luaCtx.writeFunction("getTopSelfAnsweredResponseRules", [](boost::optional<unsigned int> top) {
+ setLuaNoSideEffect();
+ auto rules = g_selfansweredrespruleactions.getLocal();
+ return getTopRules(*rules, top.get_value_or(10));
+ });
+
+ luaCtx.writeFunction("topSelfAnsweredResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
+ setLuaNoSideEffect();
+ auto rules = g_selfansweredrespruleactions.getLocal();
+ return rulesToString(getTopRules(*rules, top.get_value_or(10)), vars);
+ });
+
+ luaCtx.writeFunction("MaxQPSIPRule", [](unsigned int qps, boost::optional<int> ipv4trunc, boost::optional<int> ipv6trunc, boost::optional<int> burst, boost::optional<unsigned int> expiration, boost::optional<unsigned int> cleanupDelay, boost::optional<unsigned int> scanFraction) {
+ return std::shared_ptr<DNSRule>(new MaxQPSIPRule(qps, burst.get_value_or(qps), ipv4trunc.get_value_or(32), ipv6trunc.get_value_or(64), expiration.get_value_or(300), cleanupDelay.get_value_or(60), scanFraction.get_value_or(10)));
+ });
+
+ luaCtx.writeFunction("MaxQPSRule", [](unsigned int qps, boost::optional<int> burst) {
+ if(!burst)
+ return std::shared_ptr<DNSRule>(new MaxQPSRule(qps));
+ else
+ return std::shared_ptr<DNSRule>(new MaxQPSRule(qps, *burst));
+ });
+
+ luaCtx.writeFunction("RegexRule", [](const std::string& str) {
+ return std::shared_ptr<DNSRule>(new RegexRule(str));
+ });
+
+#ifdef HAVE_DNS_OVER_HTTPS
+ luaCtx.writeFunction("HTTPHeaderRule", [](const std::string& header, const std::string& regex) {
+ return std::shared_ptr<DNSRule>(new HTTPHeaderRule(header, regex));
+ });
+ luaCtx.writeFunction("HTTPPathRule", [](const std::string& path) {
+ return std::shared_ptr<DNSRule>(new HTTPPathRule(path));
+ });
+ luaCtx.writeFunction("HTTPPathRegexRule", [](const std::string& regex) {
+ return std::shared_ptr<DNSRule>(new HTTPPathRegexRule(regex));
+ });
+#endif
+
+#ifdef HAVE_RE2
+ luaCtx.writeFunction("RE2Rule", [](const std::string& str) {
+ return std::shared_ptr<DNSRule>(new RE2Rule(str));
+ });
+#endif
+
+ luaCtx.writeFunction("SNIRule", [](const std::string& name) {
+ return std::shared_ptr<DNSRule>(new SNIRule(name));
+ });
+
+ luaCtx.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional<bool> quiet) {
+ return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
+ });
+
+ luaCtx.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional<bool> src, boost::optional<bool> quiet) {
+ return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
+ });
+
+ luaCtx.writeFunction("benchRule", [](std::shared_ptr<DNSRule> rule, boost::optional<int> times_, boost::optional<string> suffix_) {
+ setLuaNoSideEffect();
+ int times = times_.get_value_or(100000);
+ DNSName suffix(suffix_.get_value_or("powerdns.com"));
+ struct item {
+ PacketBuffer packet;
+ ComboAddress rem;
+ DNSName qname;
+ uint16_t qtype, qclass;
+ };
+ vector<item> items;
+ items.reserve(1000);
+ for(int n=0; n < 1000; ++n) {
+ struct item i;
+ i.qname=DNSName(std::to_string(random()));
+ i.qname += suffix;
+ i.qtype = random() % 0xff;
+ i.qclass = 1;
+ i.rem=ComboAddress("127.0.0.1");
+ i.rem.sin4.sin_addr.s_addr = random();
+ GenericDNSPacketWriter<PacketBuffer> pw(i.packet, i.qname, i.qtype);
+ items.push_back(i);
+ }
+
+ int matches=0;
+ ComboAddress dummy("127.0.0.1");
+ StopWatch sw;
+ sw.start();
+ for(int n=0; n < times; ++n) {
+ item& i = items[n % items.size()];
+ DNSQuestion dq(&i.qname, i.qtype, i.qclass, &i.rem, &i.rem, i.packet, dnsdist::Protocol::DoUDP, &sw.d_start);
+ 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<DNSRule>(new AllRule());
+ });
+
+ luaCtx.writeFunction("ProbaRule", [](double proba) {
+ return std::shared_ptr<DNSRule>(new ProbaRule(proba));
+ });
+
+ luaCtx.writeFunction("QNameRule", [](const std::string& qname) {
+ return std::shared_ptr<DNSRule>(new QNameRule(DNSName(qname)));
+ });
+
+ luaCtx.writeFunction("QTypeRule", [](boost::variant<int, std::string> str) {
+ uint16_t qtype;
+ if(auto dir = boost::get<int>(&str)) {
+ qtype = *dir;
+ }
+ else {
+ string val=boost::get<string>(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<DNSRule>(new QTypeRule(qtype));
+ });
+
+ luaCtx.writeFunction("QClassRule", [](int c) {
+ return std::shared_ptr<DNSRule>(new QClassRule(c));
+ });
+
+ luaCtx.writeFunction("OpcodeRule", [](uint8_t code) {
+ return std::shared_ptr<DNSRule>(new OpcodeRule(code));
+ });
+
+ luaCtx.writeFunction("AndRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) {
+ return std::shared_ptr<DNSRule>(new AndRule(a));
+ });
+
+ luaCtx.writeFunction("OrRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) {
+ return std::shared_ptr<DNSRule>(new OrRule(a));
+ });
+
+ luaCtx.writeFunction("DSTPortRule", [](uint16_t port) {
+ return std::shared_ptr<DNSRule>(new DSTPortRule(port));
+ });
+
+ luaCtx.writeFunction("TCPRule", [](bool tcp) {
+ return std::shared_ptr<DNSRule>(new TCPRule(tcp));
+ });
+
+ luaCtx.writeFunction("DNSSECRule", []() {
+ return std::shared_ptr<DNSRule>(new DNSSECRule());
+ });
+
+ luaCtx.writeFunction("NotRule", [](std::shared_ptr<DNSRule>rule) {
+ return std::shared_ptr<DNSRule>(new NotRule(rule));
+ });
+
+ luaCtx.writeFunction("RecordsCountRule", [](uint8_t section, uint16_t minCount, uint16_t maxCount) {
+ return std::shared_ptr<DNSRule>(new RecordsCountRule(section, minCount, maxCount));
+ });
+
+ luaCtx.writeFunction("RecordsTypeCountRule", [](uint8_t section, uint16_t type, uint16_t minCount, uint16_t maxCount) {
+ return std::shared_ptr<DNSRule>(new RecordsTypeCountRule(section, type, minCount, maxCount));
+ });
+
+ luaCtx.writeFunction("TrailingDataRule", []() {
+ return std::shared_ptr<DNSRule>(new TrailingDataRule());
+ });
+
+ luaCtx.writeFunction("QNameLabelsCountRule", [](unsigned int minLabelsCount, unsigned int maxLabelsCount) {
+ return std::shared_ptr<DNSRule>(new QNameLabelsCountRule(minLabelsCount, maxLabelsCount));
+ });
+
+ luaCtx.writeFunction("QNameWireLengthRule", [](size_t min, size_t max) {
+ return std::shared_ptr<DNSRule>(new QNameWireLengthRule(min, max));
+ });
+
+ luaCtx.writeFunction("RCodeRule", [](uint8_t rcode) {
+ return std::shared_ptr<DNSRule>(new RCodeRule(rcode));
+ });
+
+ luaCtx.writeFunction("ERCodeRule", [](uint8_t rcode) {
+ return std::shared_ptr<DNSRule>(new ERCodeRule(rcode));
+ });
+
+ luaCtx.writeFunction("EDNSVersionRule", [](uint8_t version) {
+ return std::shared_ptr<DNSRule>(new EDNSVersionRule(version));
+ });
+
+ luaCtx.writeFunction("EDNSOptionRule", [](uint16_t optcode) {
+ return std::shared_ptr<DNSRule>(new EDNSOptionRule(optcode));
+ });
+
+ luaCtx.writeFunction("showRules", [](boost::optional<ruleparams_t> vars) {
+ showRules(&g_ruleactions, vars);
+ });
+
+ luaCtx.writeFunction("RDRule", []() {
+ return std::shared_ptr<DNSRule>(new RDRule());
+ });
+
+ luaCtx.writeFunction("TagRule", [](std::string tag, boost::optional<std::string> value) {
+ return std::shared_ptr<DNSRule>(new TagRule(tag, value));
+ });
+
+ luaCtx.writeFunction("TimedIPSetRule", []() {
+ return std::shared_ptr<TimedIPSetRule>(new TimedIPSetRule());
+ });
+
+ luaCtx.writeFunction("PoolAvailableRule", [](std::string poolname) {
+ return std::shared_ptr<DNSRule>(new PoolAvailableRule(poolname));
+ });
+
+ luaCtx.writeFunction("PoolOutstandingRule", [](std::string poolname, size_t limit) {
+ return std::shared_ptr<DNSRule>(new PoolOutstandingRule(poolname, limit));
+ });
+
+ luaCtx.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("clear", [](std::shared_ptr<TimedIPSetRule> tisr) {
+ tisr->clear();
+ });
+
+ luaCtx.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("cleanup", [](std::shared_ptr<TimedIPSetRule> tisr) {
+ tisr->cleanup();
+ });
+
+ luaCtx.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)(const ComboAddress& ca, int t)>("add", [](std::shared_ptr<TimedIPSetRule> tisr, const ComboAddress& ca, int t) {
+ tisr->add(ca, time(0)+t);
+ });
+
+ luaCtx.registerFunction<std::shared_ptr<DNSRule>(std::shared_ptr<TimedIPSetRule>::*)()>("slice", [](std::shared_ptr<TimedIPSetRule> tisr) {
+ return std::dynamic_pointer_cast<DNSRule>(tisr);
+ });
+ luaCtx.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("__tostring", [](std::shared_ptr<TimedIPSetRule> tisr) {
+ tisr->toString();
+ });
+
+ luaCtx.writeFunction("QNameSetRule", [](const DNSNameSet& names) {
+ return std::shared_ptr<DNSRule>(new QNameSetRule(names));
+ });
+
+ luaCtx.writeFunction("KeyValueStoreLookupRule", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey) {
+ return std::shared_ptr<DNSRule>(new KeyValueStoreLookupRule(kvs, lookupKey));
+ });
+
+ luaCtx.writeFunction("KeyValueStoreRangeLookupRule", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey) {
+ return std::shared_ptr<DNSRule>(new KeyValueStoreRangeLookupRule(kvs, lookupKey));
+ });
+
+ luaCtx.writeFunction("LuaRule", [](LuaRule::func_t func) {
+ return std::shared_ptr<DNSRule>(new LuaRule(func));
+ });
+
+ luaCtx.writeFunction("LuaFFIRule", [](LuaFFIRule::func_t func) {
+ return std::shared_ptr<DNSRule>(new LuaFFIRule(func));
+ });
+
+ luaCtx.writeFunction("LuaFFIPerThreadRule", [](std::string code) {
+ return std::shared_ptr<DNSRule>(new LuaFFIPerThreadRule(code));
+ });
+
+ luaCtx.writeFunction("ProxyProtocolValueRule", [](uint8_t type, boost::optional<std::string> value) {
+ return std::shared_ptr<DNSRule>(new ProxyProtocolValueRule(type, value));
+ });
+}