From 9f89a5f19fac65f230098aef393e8d89de6d97a4 Mon Sep 17 00:00:00 2001 From: bert hubert Date: Sun, 27 Dec 2015 21:21:55 +0000 Subject: [PATCH] implement dynamic metric creation from Lua & code to rapidly update these metrics securely. Plus some changes to example code to use metrics & comboaddress equal metric. --- pdns/lua-recursor4.cc | 23 +++++++++++++++++++++-- pdns/misc.hh | 2 +- pdns/powerdns-example-script.lua | 12 +++++++++++- pdns/rec_channel.hh | 1 + pdns/rec_channel_rec.cc | 23 ++++++++++++++++++++++- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/pdns/lua-recursor4.cc b/pdns/lua-recursor4.cc index 9895c4090b..12916218ab 100644 --- a/pdns/lua-recursor4.cc +++ b/pdns/lua-recursor4.cc @@ -4,7 +4,7 @@ #include "dnsparser.hh" #include "syncres.hh" #include "namespaces.hh" - +#include "rec_channel.hh" #if !defined(HAVE_LUA) RecursorLua4::RecursorLua4(const std::string &fname) @@ -154,7 +154,16 @@ void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& cont { addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name); } - + +struct DynMetric +{ + std::atomic* ptr; + void inc() { (*ptr)++; } + void incBy(unsigned int by) { (*ptr)+= by; } + unsigned long get() { return *ptr; } + void set(unsigned long val) { *ptr =val; } +}; + RecursorLua4::RecursorLua4(const std::string& fname) { d_lw = new LuaContext; @@ -241,6 +250,16 @@ RecursorLua4::RecursorLua4(const std::string& fname) for(const auto& n : QType::names) pd.push_back({n.first, n.second}); d_lw->writeVariable("pdns", pd); + + d_lw->writeFunction("getMetric", [](const std::string& str) { + return DynMetric{getDynMetric(str)}; + }); + + d_lw->registerFunction("inc", &DynMetric::inc); + d_lw->registerFunction("incBy", &DynMetric::incBy); + d_lw->registerFunction("set", &DynMetric::set); + d_lw->registerFunction("get", &DynMetric::get); + ifstream ifs(fname); if(!ifs) { diff --git a/pdns/misc.hh b/pdns/misc.hh index 260ee7c36f..4ba73f92a9 100644 --- a/pdns/misc.hh +++ b/pdns/misc.hh @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2002-2012 PowerDNS.COM BV + Copyright (C) 2002-2015 PowerDNS.COM BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 diff --git a/pdns/powerdns-example-script.lua b/pdns/powerdns-example-script.lua index 96825c9ffc..8177b0ab34 100644 --- a/pdns/powerdns-example-script.lua +++ b/pdns/powerdns-example-script.lua @@ -11,15 +11,25 @@ malwareset:add("nl") magic2 = newDN("www.magic2.com") + +magicMetric = getMetric("magic") + -- shows the various ways of blocking, dropping, changing questions -- return false to say you did not take over the question, but we'll still listen to 'variable' -- to selectively disable the cache function preresolve(dq) print("Got question for "..dq.qname:toString().." from "..dq.remoteaddr:toString().." to "..dq.localaddr:toString()) + loc = newCA("127.0.0.1") + if(dq.remoteaddr:equal(loc)) + then + print("Query from loopback") + end + -- note that the comparisons below are CaSe InSensiTivE and you don't have to worry about trailing dots if(dq.qname:equal("magic.com")) then + magicMetric:inc() print("Magic!") else print("not magic..") @@ -78,7 +88,7 @@ end badips = newNMG() -badips:addMask("127.0.0.0/8") +badips:addMask("127.1.0.0/16") -- this check is applied before any packet parsing is done function ipfilter(loc, rem) diff --git a/pdns/rec_channel.hh b/pdns/rec_channel.hh index 94f4ae82a2..c5b62fb10b 100644 --- a/pdns/rec_channel.hh +++ b/pdns/rec_channel.hh @@ -50,4 +50,5 @@ std::vector* pleaseGetRemotes(); std::vector* pleaseGetServfailRemotes(); std::vector* pleaseGetLargeAnswerRemotes(); DNSName getRegisteredName(const DNSName& dom); +std::atomic* getDynMetric(const std::string& str); #endif diff --git a/pdns/rec_channel_rec.cc b/pdns/rec_channel_rec.cc index 3123a49358..15a33ab9a8 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -37,7 +37,8 @@ pthread_mutex_t g_carbon_config_lock=PTHREAD_MUTEX_INITIALIZER; map d_get32bitpointers; map d_get64bitpointers; map > d_get32bitmembers; - +pthread_mutex_t d_dynmetricslock = PTHREAD_MUTEX_INITIALIZER; +map* > d_dynmetrics; void addGetStat(const string& name, const uint32_t* place) { d_get32bitpointers[name]=place; @@ -51,6 +52,18 @@ void addGetStat(const string& name, function f ) d_get32bitmembers[name]=f; } +std::atomic* getDynMetric(const std::string& str) +{ + Lock l(&d_dynmetricslock); + auto f = d_dynmetrics.find(str); + if(f != d_dynmetrics.end()) + return f->second; + + auto ret = new std::atomic(); + d_dynmetrics[str]= ret; + return ret; +} + optional get(const string& name) { optional ret; @@ -62,6 +75,11 @@ optional get(const string& name) if(d_get32bitmembers.count(name)) return d_get32bitmembers.find(name)->second(); + Lock l(&d_dynmetricslock); + auto f =rplookup(d_dynmetrics, name); + if(f) + return (*f)->load(); + return ret; } @@ -80,6 +98,9 @@ map getAllStatsMap() continue; // too slow for 'get-all' ret.insert(make_pair(the32bitmembers.first, std::to_string(the32bitmembers.second()))); } + Lock l(&d_dynmetricslock); + for(const auto& a : d_dynmetrics) + ret.insert({a.first, std::to_string(*a.second)}); return ret; } -- 2.47.2