g_lua.writeFunction("newServer",
[client](boost::variant<string,newserver_t> pvars, boost::optional<int> qps)
{
+ setLuaSideEffect();
if(client) {
return std::make_shared<DownstreamState>(ComboAddress());
}
g_lua.writeFunction("addAnyTCRule", []() {
+ setLuaSideEffect();
auto rules=g_rulactions.getCopy();
rules.push_back({ std::make_shared<QTypeRule>(0xff), std::make_shared<TCAction>()});
g_rulactions.setState(rules);
});
g_lua.writeFunction("rmRule", [](unsigned int num) {
+ setLuaSideEffect();
auto rules = g_rulactions.getCopy();
if(num >= rules.size()) {
g_outputBuffer = "Error: attempt to delete non-existing rule\n";
});
g_lua.writeFunction("topRule", []() {
+ setLuaSideEffect();
auto rules = g_rulactions.getCopy();
if(rules.empty())
return;
g_rulactions.setState(rules);
});
g_lua.writeFunction("mvRule", [](unsigned int from, unsigned int to) {
+ setLuaSideEffect();
auto rules = g_rulactions.getCopy();
if(from >= rules.size() || to > rules.size()) {
g_outputBuffer = "Error: attempt to move rules from/to invalid index\n";
g_lua.writeFunction("rmServer",
[](boost::variant<std::shared_ptr<DownstreamState>, int> var)
{
+ setLuaSideEffect();
auto states = g_dstates.getCopy();
if(auto* rem = boost::get<shared_ptr<DownstreamState>>(&var))
states.erase(remove(states.begin(), states.end(), *rem), states.end());
g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) {
+ setLuaSideEffect();
g_policy.setState(policy);
});
g_lua.writeFunction("setServerPolicyLua", [](string name, policy_t policy) {
+ setLuaSideEffect();
g_policy.setState(ServerPolicy{name, policy});
});
g_lua.writeFunction("showServerPolicy", []() {
+ setLuaSideEffect();
g_outputBuffer=g_policy.getLocal()->name+"\n";
});
- g_lua.writeFunction("truncateTC", [](bool tc) { g_truncateTC=tc; });
- g_lua.writeFunction("fixupCase", [](bool fu) { g_fixupCase=fu; });
+ g_lua.writeFunction("truncateTC", [](bool tc) { setLuaSideEffect(); g_truncateTC=tc; });
+ g_lua.writeFunction("fixupCase", [](bool fu) { setLuaSideEffect(); g_fixupCase=fu; });
g_lua.registerMember("name", &ServerPolicy::name);
g_lua.registerMember("policy", &ServerPolicy::policy);
g_lua.writeVariable("whashed", ServerPolicy{"whashed", whashed});
g_lua.writeVariable("leastOutstanding", ServerPolicy{"leastOutstanding", leastOutstanding});
g_lua.writeFunction("addACL", [](const std::string& domain) {
+ setLuaSideEffect();
g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); });
});
g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional<bool> doTCP) {
+ setLuaSideEffect();
if(client)
return;
if (g_configurationDone) {
});
g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional<bool> doTCP) {
+ setLuaSideEffect();
if(client)
return;
if (g_configurationDone) {
}
});
g_lua.writeFunction("setACL", [](boost::variant<string,vector<pair<int, string>>> inp) {
+ setLuaSideEffect();
NetmaskGroup nmg;
if(auto str = boost::get<string>(&inp)) {
nmg.addMask(*str);
g_ACL.setState(nmg);
});
g_lua.writeFunction("showACL", []() {
+ setLuaNoSideEffect();
vector<string> vec;
g_ACL.getCopy().toStringVector(&vec);
g_lua.writeFunction("addDomainBlock", [](const std::string& domain) {
+ setLuaSideEffect();
SuffixMatchNode smn;
smn.add(DNSName(domain));
g_rulactions.modify([smn](decltype(g_rulactions)::value_type& rulactions) {
});
g_lua.writeFunction("showServers", []() {
+ setLuaNoSideEffect();
try {
ostringstream ret;
boost::format fmt("%1$-3d %2$-20.20s %|25t|%3% %|55t|%4$5s %|51t|%5$7.1f %|66t|%6$7d %|69t|%7$3d %|78t|%8$2d %|80t|%9$10d %|86t|%10$7d %|91t|%11$5.1f %|109t|%12$5.1f %13%" );
g_lua.writeFunction("addLuaAction", [](luadnsrule_t var, LuaAction::func_t func)
{
+ setLuaSideEffect();
auto rule=makeRule(var);
g_rulactions.modify([rule,func](decltype(g_rulactions)::value_type& rulactions){
rulactions.push_back({rule,
});
g_lua.writeFunction("addDomainSpoof", [](const std::string& domain, const std::string& ip, boost::optional<string> ip6) {
+ setLuaSideEffect();
SuffixMatchNode smn;
ComboAddress a, b;
b.sin6.sin6_family=0;
g_lua.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 {
g_lua.writeFunction("addAction", [](luadnsrule_t var, std::shared_ptr<DNSAction> ea)
{
+ setLuaSideEffect();
auto rule=makeRule(var);
g_rulactions.modify([rule, ea](decltype(g_rulactions)::value_type& rulactions){
rulactions.push_back({rule, ea});
g_lua.writeFunction("addPoolRule", [](luadnsrule_t var, string pool) {
+ setLuaSideEffect();
auto rule=makeRule(var);
g_rulactions.modify([rule, pool](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({
});
g_lua.writeFunction("addNoRecurseRule", [](luadnsrule_t var) {
+ setLuaSideEffect();
auto rule=makeRule(var);
g_rulactions.modify([rule](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({
});
g_lua.writeFunction("addDisableValidationRule", [](luadnsrule_t var) {
+ setLuaSideEffect();
auto rule=makeRule(var);
g_rulactions.modify([rule](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({
g_lua.writeFunction("addQPSPoolRule", [](luadnsrule_t var, int limit, string pool) {
+ setLuaSideEffect();
auto rule = makeRule(var);
g_rulactions.modify([rule, pool,limit](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({
});
g_lua.writeFunction("setDNSSECPool", [](const std::string& pool) {
+ setLuaSideEffect();
g_rulactions.modify([pool](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({std::make_shared<DNSSECRule>(),
std::make_shared<PoolAction>(pool)});
});
g_lua.writeFunction("addQPSLimit", [](luadnsrule_t var, int lim) {
+ setLuaSideEffect();
auto rule = makeRule(var);
g_rulactions.modify([lim,rule](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({rule,
});
g_lua.writeFunction("addDelay", [](luadnsrule_t var, int msec) {
+ setLuaSideEffect();
auto rule = makeRule(var);
g_rulactions.modify([msec,rule](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({rule,
g_lua.writeFunction("showRules", []() {
+ setLuaNoSideEffect();
boost::format fmt("%-3d %9d %-50s %s\n");
g_outputBuffer += (fmt % "#" % "Matches" % "Rule" % "Action").str();
int num=0;
});
g_lua.writeFunction("getServers", []() {
+ setLuaNoSideEffect();
vector<pair<int, std::shared_ptr<DownstreamState> > > ret;
int count=1;
for(const auto& s : g_dstates.getCopy()) {
g_lua.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName,
boost::optional<int> interval) {
+ setLuaSideEffect();
auto ours = g_carbon.getCopy();
ours.server=ComboAddress(address, 2003);
if(ourName)
});
g_lua.writeFunction("webserver", [client](const std::string& address, const std::string& password) {
+ setLuaSideEffect();
if(client)
return;
ComboAddress local(address);
});
g_lua.writeFunction("controlSocket", [client](const std::string& str) {
+ setLuaSideEffect();
ComboAddress local(str, 5199);
if(client) {
g_lua.writeFunction("topClients", [](boost::optional<unsigned int> top_) {
+ setLuaNoSideEffect();
auto top = top_.get_value_or(10);
map<ComboAddress, int,ComboAddress::addressOnlyLessThan > counts;
unsigned int total=0;
});
g_lua.writeFunction("getTopQueries", [](unsigned int top, boost::optional<int> labels) {
+ setLuaNoSideEffect();
map<DNSName, int> counts;
unsigned int total=0;
if(!labels) {
g_lua.writeFunction("getResponseRing", []() {
+ setLuaNoSideEffect();
decltype(g_rings.respRing) ring;
{
std::lock_guard<std::mutex> lock(g_rings.respMutex);
});
g_lua.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional<int> labels) {
+ setLuaNoSideEffect();
map<DNSName, int> counts;
unsigned int total=0;
{
g_lua.writeFunction("showResponseLatency", []() {
-
+ setLuaNoSideEffect();
map<double, unsigned int> histo;
double bin=100;
for(int i=0; i < 15; ++i) {
g_lua.writeFunction("makeKey", []() {
+ setLuaNoSideEffect();
g_outputBuffer="setKey("+newKey()+")\n";
});
g_lua.writeFunction("setKey", [](const std::string& key) {
+ setLuaSideEffect();
if(B64Decode(key, g_key) < 0) {
g_outputBuffer=string("Unable to decode ")+key+" as Base64";
errlog("%s", g_outputBuffer);
g_lua.writeFunction("testCrypto", [](boost::optional<string> optTestMsg)
{
+ setLuaNoSideEffect();
try {
string testmsg;
g_lua.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; });
g_lua.writeFunction("dumpStats", [] {
+ setLuaNoSideEffect();
vector<string> leftcolumn, rightcolumn;
boost::format fmt("%-23s\t%+11s");
#include "lock.hh"
#include <map>
#include <fstream>
+#include <boost/logic/tribool.hpp>
+
+boost::tribool g_noLuaSideEffect;
+
+/* this is a best effort way to prevent logging calls with no side-effects in the output of delta()
+ Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing
+ has done so before on this invocation, this call won't be part of delta() output */
+void setLuaNoSideEffect()
+{
+ if(g_noLuaSideEffect==false) // there has been a side effect already
+ return;
+ g_noLuaSideEffect=true;
+}
+
+void setLuaSideEffect()
+{
+ g_noLuaSideEffect=false;
+}
+
+bool getLuaNoSideEffect()
+{
+ return g_noLuaSideEffect==true;
+}
+
+void resetLuaSideEffect()
+{
+ g_noLuaSideEffect = boost::logic::indeterminate;
+}
map<ComboAddress,int> filterScore(const map<ComboAddress, unsigned int,ComboAddress::addressOnlyLessThan >& counts,
double delta, int rate)
});
g_lua.writeFunction("setDynBlockNMG", [](const nmts_t& nmg) {
+ setLuaSideEffect();
g_dynblockNMG.setState(nmg);
});
g_lua.writeFunction("showDynBlocks", []() {
+ setLuaNoSideEffect();
auto slow = g_dynblockNMG.getCopy();
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
});
g_lua.writeFunction("clearDynBlocks", []() {
+ setLuaSideEffect();
nmts_t nmg;
g_dynblockNMG.setState(nmg);
});
g_lua.writeFunction("addDynBlocks",
[](const map<ComboAddress,int>& m, const std::string& msg, boost::optional<int> seconds) {
+ setLuaSideEffect();
auto slow = g_dynblockNMG.getCopy();
struct timespec until, now;
clock_gettime(CLOCK_MONOTONIC, &now);
[](nmts_t& s, const ComboAddress& ca) { return s.match(ca); });
g_lua.writeFunction("exceedServfails", [](unsigned int rate, int seconds) {
+ setLuaNoSideEffect();
return exceedRCode(rate, seconds, RCode::ServFail);
});
g_lua.writeFunction("exceedNXDOMAINs", [](unsigned int rate, int seconds) {
+ setLuaNoSideEffect();
return exceedRCode(rate, seconds, RCode::NXDomain);
});
g_lua.writeFunction("exceedRespByterate", [](unsigned int rate, int seconds) {
+ setLuaNoSideEffect();
return exceedRespByterate(rate, seconds);
});
g_lua.writeFunction("exceedQTypeRate", [](uint16_t type, unsigned int rate, int seconds) {
+ setLuaNoSideEffect();
return exceedQueryGen(rate, seconds, [type](counts_t& counts, const Rings::Query& q) {
if(q.qtype==type)
counts[q.requestor]++;
});
g_lua.writeFunction("topBandwidth", [](unsigned int top) {
+ setLuaNoSideEffect();
auto res = g_rings.getTopBandwidth(top);
boost::format fmt("%7d %s\n");
for(const auto& l : res) {
}
});
+ g_lua.writeFunction("delta", []() {
+ setLuaNoSideEffect();
+ // we hold the lua lock already!
+ for(const auto& d : g_confDelta) {
+ struct tm tm;
+ localtime_r(&d.first.tv_sec, &tm);
+ char date[80];
+ strftime(date, sizeof(date)-1, "# %a %b %d %Y %H:%M:%S %Z\n", &tm);
+ g_outputBuffer += date;
+ g_outputBuffer += d.second + "\n";
+ }
+ });
+
g_lua.writeFunction("grepq", [](const std::string& s, boost::optional<unsigned int> limit) {
boost::optional<Netmask> nm;
boost::optional<DNSName> dn;