2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "dnsdist-cache.hh"
24 #include "dnsrulactions.hh"
27 #include "sodcrypto.hh"
33 #include <boost/logic/tribool.hpp>
34 #include "statnode.hh"
35 #include <sys/types.h>
40 #include "dnsdist-lua.hh"
42 boost::tribool g_noLuaSideEffect
;
43 static bool g_included
{false};
45 /* this is a best effort way to prevent logging calls with no side-effects in the output of delta()
46 Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing
47 has done so before on this invocation, this call won't be part of delta() output */
48 void setLuaNoSideEffect()
50 if(g_noLuaSideEffect
==false) // there has been a side effect already
52 g_noLuaSideEffect
=true;
55 void setLuaSideEffect()
57 g_noLuaSideEffect
=false;
60 bool getLuaNoSideEffect()
62 return g_noLuaSideEffect
==true;
65 void resetLuaSideEffect()
67 g_noLuaSideEffect
= boost::logic::indeterminate
;
70 map
<ComboAddress
,int> filterScore(const map
<ComboAddress
, unsigned int,ComboAddress::addressOnlyLessThan
>& counts
,
71 double delta
, int rate
)
73 std::multimap
<unsigned int,ComboAddress
> score
;
74 for(const auto& e
: counts
)
75 score
.insert({e
.second
, e
.first
});
77 map
<ComboAddress
,int> ret
;
79 double lim
= delta
*rate
;
80 for(auto s
= score
.crbegin(); s
!= score
.crend() && s
->first
> lim
; ++s
) {
81 ret
[s
->second
]=s
->first
;
87 typedef std::function
<void(const StatNode
&, const StatNode::Stat
&, const StatNode::Stat
&)> statvisitor_t
;
89 static void statNodeRespRing(statvisitor_t visitor
, unsigned int seconds
)
91 struct timespec cutoff
, now
;
95 cutoff
.tv_sec
-= seconds
;
98 std::lock_guard
<std::mutex
> lock(g_rings
.respMutex
);
101 for(const auto& c
: g_rings
.respRing
) {
105 if (seconds
&& c
.when
< cutoff
)
108 root
.submit(c
.name
, c
.dh
.rcode
, c
.requestor
);
112 root
.visit([&visitor
](const StatNode
* node_
, const StatNode::Stat
& self
, const StatNode::Stat
& children
) {
113 visitor(*node_
, self
, children
);}, node
);
117 vector
<pair
<unsigned int, std::unordered_map
<string
,string
> > > getRespRing(boost::optional
<int> rcode
)
119 typedef std::unordered_map
<string
,string
> entry_t
;
120 vector
<pair
<unsigned int, entry_t
> > ret
;
121 std::lock_guard
<std::mutex
> lock(g_rings
.respMutex
);
124 unsigned int count
=1;
125 for(const auto& c
: g_rings
.respRing
) {
126 if(rcode
&& (rcode
.get() != c
.dh
.rcode
))
128 e
["qname"]=c
.name
.toString();
129 e
["rcode"]=std::to_string(c
.dh
.rcode
);
130 ret
.push_back(std::make_pair(count
,e
));
136 typedef map
<ComboAddress
, unsigned int,ComboAddress::addressOnlyLessThan
> counts_t
;
137 map
<ComboAddress
,int> exceedRespGen(int rate
, int seconds
, std::function
<void(counts_t
&, const Rings::Response
&)> T
)
140 struct timespec cutoff
, mintime
, now
;
142 cutoff
= mintime
= now
;
143 cutoff
.tv_sec
-= seconds
;
145 std::lock_guard
<std::mutex
> lock(g_rings
.respMutex
);
146 for(const auto& c
: g_rings
.respRing
) {
147 if(seconds
&& c
.when
< cutoff
)
156 double delta
= seconds
? seconds
: DiffTime(now
, mintime
);
157 return filterScore(counts
, delta
, rate
);
160 map
<ComboAddress
,int> exceedQueryGen(int rate
, int seconds
, std::function
<void(counts_t
&, const Rings::Query
&)> T
)
163 struct timespec cutoff
, mintime
, now
;
165 cutoff
= mintime
= now
;
166 cutoff
.tv_sec
-= seconds
;
168 ReadLock
rl(&g_rings
.queryLock
);
169 for(const auto& c
: g_rings
.queryRing
) {
170 if(seconds
&& c
.when
< cutoff
)
178 double delta
= seconds
? seconds
: DiffTime(now
, mintime
);
179 return filterScore(counts
, delta
, rate
);
183 map
<ComboAddress
,int> exceedRCode(int rate
, int seconds
, int rcode
)
185 return exceedRespGen(rate
, seconds
, [rcode
](counts_t
& counts
, const Rings::Response
& r
)
187 if(r
.dh
.rcode
== rcode
)
188 counts
[r
.requestor
]++;
192 map
<ComboAddress
,int> exceedRespByterate(int rate
, int seconds
)
194 return exceedRespGen(rate
, seconds
, [](counts_t
& counts
, const Rings::Response
& r
)
196 counts
[r
.requestor
]+=r
.size
;
202 void moreLua(bool client
)
204 typedef NetmaskTree
<DynBlock
> nmts_t
;
205 g_lua
.writeFunction("newCA", [](const std::string
& name
) { return ComboAddress(name
); });
207 g_lua
.writeFunction("newNMG", []() { return NetmaskGroup(); });
208 g_lua
.registerFunction
<void(NetmaskGroup::*)(const std::string
&mask
)>("addMask", [](NetmaskGroup
&nmg
, const std::string
& mask
)
212 g_lua
.registerFunction
<void(NetmaskGroup::*)(const std::map
<ComboAddress
,int>& map
)>("addMasks", [](NetmaskGroup
&nmg
, const std::map
<ComboAddress
,int>& map
)
214 for (const auto& entry
: map
) {
215 nmg
.addMask(Netmask(entry
.first
));
219 g_lua
.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress
&) const)&NetmaskGroup::match
);
220 g_lua
.registerFunction("size", &NetmaskGroup::size
);
221 g_lua
.registerFunction("clear", &NetmaskGroup::clear
);
224 g_lua
.writeFunction("showDynBlocks", []() {
225 setLuaNoSideEffect();
226 auto slow
= g_dynblockNMG
.getCopy();
229 boost::format
fmt("%-24s %8d %8d %s\n");
230 g_outputBuffer
= (fmt
% "What" % "Seconds" % "Blocks" % "Reason").str();
231 for(const auto& e
: slow
) {
232 if(now
< e
->second
.until
)
233 g_outputBuffer
+= (fmt
% e
->first
.toString() % (e
->second
.until
.tv_sec
- now
.tv_sec
) % e
->second
.blocks
% e
->second
.reason
).str();
235 auto slow2
= g_dynblockSMT
.getCopy();
236 slow2
.visit([&now
, &fmt
](const SuffixMatchTree
<DynBlock
>& node
) {
237 if(now
<node
.d_value
.until
) {
239 if(!node
.d_value
.domain
.empty())
240 dom
= node
.d_value
.domain
.toString();
241 g_outputBuffer
+= (fmt
% dom
% (node
.d_value
.until
.tv_sec
- now
.tv_sec
) % node
.d_value
.blocks
% node
.d_value
.reason
).str();
247 g_lua
.writeFunction("clearDynBlocks", []() {
250 g_dynblockNMG
.setState(nmg
);
251 SuffixMatchTree
<DynBlock
> smt
;
252 g_dynblockSMT
.setState(smt
);
255 g_lua
.writeFunction("addDynBlocks",
256 [](const map
<ComboAddress
,int>& m
, const std::string
& msg
, boost::optional
<int> seconds
, boost::optional
<DNSAction::Action
> action
) {
258 auto slow
= g_dynblockNMG
.getCopy();
259 struct timespec until
, now
;
262 int actualSeconds
= seconds
? *seconds
: 10;
263 until
.tv_sec
+= actualSeconds
;
264 for(const auto& capair
: m
) {
265 unsigned int count
= 0;
266 auto got
= slow
.lookup(Netmask(capair
.first
));
269 if(until
< got
->second
.until
) // had a longer policy
271 if(now
< got
->second
.until
) // only inherit count on fresh query we are extending
272 count
=got
->second
.blocks
;
276 DynBlock db
{msg
,until
,DNSName(),(action
? *action
: DNSAction::Action::None
)};
279 warnlog("Inserting dynamic block for %s for %d seconds: %s", capair
.first
.toString(), actualSeconds
, msg
);
280 slow
.insert(Netmask(capair
.first
)).second
=db
;
282 g_dynblockNMG
.setState(slow
);
285 g_lua
.writeFunction("addDynBlockSMT",
286 [](const vector
<pair
<unsigned int, string
> >&names
, const std::string
& msg
, boost::optional
<int> seconds
, boost::optional
<DNSAction::Action
> action
) {
288 auto slow
= g_dynblockSMT
.getCopy();
289 struct timespec until
, now
;
292 int actualSeconds
= seconds
? *seconds
: 10;
293 until
.tv_sec
+= actualSeconds
;
295 for(const auto& capair
: names
) {
296 unsigned int count
= 0;
297 DNSName
domain(capair
.second
);
298 auto got
= slow
.lookup(domain
);
301 if(until
< got
->until
) // had a longer policy
303 if(now
< got
->until
) // only inherit count on fresh query we are extending
309 DynBlock db
{msg
,until
,domain
,(action
? *action
: DNSAction::Action::None
)};
312 warnlog("Inserting dynamic block for %s for %d seconds: %s", domain
, actualSeconds
, msg
);
313 slow
.add(domain
, db
);
315 g_dynblockSMT
.setState(slow
);
318 g_lua
.writeFunction("setDynBlocksAction", [](DNSAction::Action action
) {
319 if (!g_configurationDone
) {
320 if (action
== DNSAction::Action::Drop
|| action
== DNSAction::Action::Refused
|| action
== DNSAction::Action::Truncate
) {
321 g_dynBlockAction
= action
;
324 errlog("Dynamic blocks action can only be Drop, Refused or Truncate!");
325 g_outputBuffer
="Dynamic blocks action can only be Drop, Refused or Truncate!\n";
328 g_outputBuffer
="Dynamic blocks action cannot be altered at runtime!\n";
332 g_lua
.registerFunction
<bool(nmts_t::*)(const ComboAddress
&)>("match",
333 [](nmts_t
& s
, const ComboAddress
& ca
) { return s
.match(ca
); });
335 g_lua
.writeFunction("exceedServFails", [](unsigned int rate
, int seconds
) {
336 setLuaNoSideEffect();
337 return exceedRCode(rate
, seconds
, RCode::ServFail
);
339 g_lua
.writeFunction("exceedNXDOMAINs", [](unsigned int rate
, int seconds
) {
340 setLuaNoSideEffect();
341 return exceedRCode(rate
, seconds
, RCode::NXDomain
);
346 g_lua
.writeFunction("exceedRespByterate", [](unsigned int rate
, int seconds
) {
347 setLuaNoSideEffect();
348 return exceedRespByterate(rate
, seconds
);
351 g_lua
.writeFunction("exceedQTypeRate", [](uint16_t type
, unsigned int rate
, int seconds
) {
352 setLuaNoSideEffect();
353 return exceedQueryGen(rate
, seconds
, [type
](counts_t
& counts
, const Rings::Query
& q
) {
355 counts
[q
.requestor
]++;
359 g_lua
.writeFunction("exceedQRate", [](unsigned int rate
, int seconds
) {
360 setLuaNoSideEffect();
361 return exceedQueryGen(rate
, seconds
, [](counts_t
& counts
, const Rings::Query
& q
) {
362 counts
[q
.requestor
]++;
366 g_lua
.writeFunction("getRespRing", getRespRing
);
368 g_lua
.registerFunction
<StatNode
, unsigned int()>("numChildren",
369 [](StatNode
& sn
) -> unsigned int {
371 return sn
.children
.size();
374 g_lua
.registerMember("fullname", &StatNode::fullname
);
375 g_lua
.registerMember("servfails", &StatNode::Stat::servfails
);
376 g_lua
.registerMember("nxdomains", &StatNode::Stat::nxdomains
);
377 g_lua
.registerMember("queries", &StatNode::Stat::queries
);
379 g_lua
.writeFunction("statNodeRespRing", [](statvisitor_t visitor
, boost::optional
<unsigned int> seconds
) {
380 statNodeRespRing(visitor
, seconds
? *seconds
: 0);
383 g_lua
.writeFunction("getTopBandwidth", [](unsigned int top
) {
384 setLuaNoSideEffect();
385 return g_rings
.getTopBandwidth(top
);
387 g_lua
.executeCode(R
"(function topBandwidth(top) top = top or 10; for k,v in ipairs(getTopBandwidth(top)) do show(string.format("%4d
%-40s
%4d
%4.1f
%%",k,v[1],v[2],v[3])) end end)");
389 g_lua
.writeFunction("delta", []() {
390 setLuaNoSideEffect();
391 // we hold the lua lock already!
392 for(const auto& d
: g_confDelta
) {
394 localtime_r(&d
.first
.tv_sec
, &tm
);
396 strftime(date
, sizeof(date
)-1, "-- %a %b %d %Y %H:%M:%S %Z\n", &tm
);
397 g_outputBuffer
+= date
;
398 g_outputBuffer
+= d
.second
+ "\n";
402 g_lua
.writeFunction("grepq", [](boost::variant
<string
, vector
<pair
<int,string
> > > inp
, boost::optional
<unsigned int> limit
) {
403 setLuaNoSideEffect();
404 boost::optional
<Netmask
> nm
;
405 boost::optional
<DNSName
> dn
;
409 auto str
=boost::get
<string
>(&inp
);
413 auto v
= boost::get
<vector
<pair
<int, string
> > >(inp
);
414 for(const auto& a
: v
)
415 vec
.push_back(a
.second
);
418 for(const auto& s
: vec
) {
424 if(boost::ends_with(s
,"ms") && sscanf(s
.c_str(), "%ums", &msec
)) {
428 try { dn
=DNSName(s
); }
431 g_outputBuffer
= "Could not parse '"+s
+"' as domain name or netmask";
438 decltype(g_rings
.queryRing
) qr
;
439 decltype(g_rings
.respRing
) rr
;
441 ReadLock
rl(&g_rings
.queryLock
);
442 qr
=g_rings
.queryRing
;
444 sort(qr
.begin(), qr
.end(), [](const decltype(qr
)::value_type
& a
, const decltype(qr
)::value_type
& b
) {
445 return b
.when
< a
.when
;
448 std::lock_guard
<std::mutex
> lock(g_rings
.respMutex
);
452 sort(rr
.begin(), rr
.end(), [](const decltype(rr
)::value_type
& a
, const decltype(rr
)::value_type
& b
) {
453 return b
.when
< a
.when
;
460 std::multimap
<struct timespec
, string
> out
;
462 boost::format
fmt("%-7.1f %-47s %-12s %-5d %-25s %-5s %-6.1f %-2s %-2s %-2s %s\n");
463 g_outputBuffer
+= (fmt
% "Time" % "Client" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str();
466 for(const auto& c
: qr
) {
467 bool nmmatch
=true, dnmatch
=true;
469 nmmatch
= nm
->match(c
.requestor
);
471 dnmatch
= c
.name
.isPartOf(*dn
);
472 if(nmmatch
&& dnmatch
) {
474 out
.insert(make_pair(c
.when
, (fmt
% DiffTime(now
, c
.when
) % c
.requestor
.toStringWithPort() % "" % htons(c
.dh
.id
) % c
.name
.toString() % qt
.getName() % "" % (c
.dh
.tc
? "TC" : "") % (c
.dh
.rd
? "RD" : "") % (c
.dh
.aa
? "AA" : "") % "Question").str() )) ;
476 if(limit
&& *limit
==++num
)
485 for(const auto& c
: rr
) {
486 bool nmmatch
=true, dnmatch
=true, msecmatch
=true;
488 nmmatch
= nm
->match(c
.requestor
);
490 dnmatch
= c
.name
.isPartOf(*dn
);
492 msecmatch
=(c
.usec
/1000 > (unsigned int)msec
);
494 if(nmmatch
&& dnmatch
&& msecmatch
) {
497 extra
=". " +std::to_string(htons(c
.dh
.ancount
))+ " answers";
500 if(c
.usec
!= std::numeric_limits
<decltype(c
.usec
)>::max())
501 out
.insert(make_pair(c
.when
, (fmt
% DiffTime(now
, c
.when
) % c
.requestor
.toStringWithPort() % c
.ds
.toStringWithPort() % htons(c
.dh
.id
) % c
.name
.toString() % qt
.getName() % (c
.usec
/1000.0) % (c
.dh
.tc
? "TC" : "") % (c
.dh
.rd
? "RD" : "") % (c
.dh
.aa
? "AA" : "") % (RCode::to_s(c
.dh
.rcode
) + extra
)).str() )) ;
503 out
.insert(make_pair(c
.when
, (fmt
% DiffTime(now
, c
.when
) % c
.requestor
.toStringWithPort() % c
.ds
.toStringWithPort() % htons(c
.dh
.id
) % c
.name
.toString() % qt
.getName() % "T.O" % (c
.dh
.tc
? "TC" : "") % (c
.dh
.rd
? "RD" : "") % (c
.dh
.aa
? "AA" : "") % (RCode::to_s(c
.dh
.rcode
) + extra
)).str() )) ;
505 if(limit
&& *limit
==++num
)
510 for(const auto& p
: out
) {
511 g_outputBuffer
+=p
.second
;
515 g_lua
.writeFunction("addDNSCryptBind", [](const std::string
& addr
, const std::string
& providerName
, const std::string
& certFile
, const std::string keyFile
, boost::optional
<localbind_t
> vars
) {
516 if (g_configurationDone
) {
517 g_outputBuffer
="addDNSCryptBind cannot be used at runtime!\n";
522 bool reusePort
= false;
523 int tcpFastOpenQueueSize
= 0;
524 std::string interface
;
526 parseLocalBindVars(vars
, doTCP
, reusePort
, tcpFastOpenQueueSize
, interface
);
529 DnsCryptContext
ctx(providerName
, certFile
, keyFile
);
530 g_dnsCryptLocals
.push_back(std::make_tuple(ComboAddress(addr
, 443), ctx
, reusePort
, tcpFastOpenQueueSize
, interface
));
532 catch(std::exception
& e
) {
534 g_outputBuffer
="Error: "+string(e
.what())+"\n";
537 g_outputBuffer
="Error: DNSCrypt support is not enabled.\n";
541 g_lua
.writeFunction("showDNSCryptBinds", []() {
542 setLuaNoSideEffect();
545 boost::format
fmt("%1$-3d %2% %|25t|%3$-20.20s %|26t|%4$-8d %|35t|%5$-21.21s %|56t|%6$-9d %|66t|%7$-21.21s" );
546 ret
<< (fmt
% "#" % "Address" % "Provider Name" % "Serial" % "Validity" % "P. Serial" % "P. Validity") << endl
;
549 for (const auto& local
: g_dnsCryptLocals
) {
550 const DnsCryptContext
& ctx
= std::get
<1>(local
);
551 bool const hasOldCert
= ctx
.hadOldCertificate();
552 const DnsCryptCert
& cert
= ctx
.getCurrentCertificate();
553 const DnsCryptCert
& oldCert
= ctx
.getOldCertificate();
555 ret
<< (fmt
% idx
% std::get
<0>(local
).toStringWithPort() % ctx
.getProviderName() % cert
.signedData
.serial
% DnsCryptContext::certificateDateToStr(cert
.signedData
.tsEnd
) % (hasOldCert
? oldCert
.signedData
.serial
: 0) % (hasOldCert
? DnsCryptContext::certificateDateToStr(oldCert
.signedData
.tsEnd
) : "-")) << endl
;
559 g_outputBuffer
=ret
.str();
561 g_outputBuffer
="Error: DNSCrypt support is not enabled.\n";
565 g_lua
.writeFunction("generateDNSCryptProviderKeys", [](const std::string
& publicKeyFile
, const std::string privateKeyFile
) {
566 setLuaNoSideEffect();
568 unsigned char publicKey
[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE
];
569 unsigned char privateKey
[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE
];
570 sodium_mlock(privateKey
, sizeof(privateKey
));
573 DnsCryptContext::generateProviderKeys(publicKey
, privateKey
);
575 ofstream
pubKStream(publicKeyFile
);
576 pubKStream
.write((char*) publicKey
, sizeof(publicKey
));
579 ofstream
privKStream(privateKeyFile
);
580 privKStream
.write((char*) privateKey
, sizeof(privateKey
));
583 g_outputBuffer
="Provider fingerprint is: " + DnsCryptContext::getProviderFingerprint(publicKey
) + "\n";
585 catch(std::exception
& e
) {
587 g_outputBuffer
="Error: "+string(e
.what())+"\n";
590 sodium_memzero(privateKey
, sizeof(privateKey
));
591 sodium_munlock(privateKey
, sizeof(privateKey
));
593 g_outputBuffer
="Error: DNSCrypt support is not enabled.\n";
597 g_lua
.writeFunction("printDNSCryptProviderFingerprint", [](const std::string
& publicKeyFile
) {
598 setLuaNoSideEffect();
600 unsigned char publicKey
[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE
];
603 ifstream
file(publicKeyFile
);
604 file
.read((char *) &publicKey
, sizeof(publicKey
));
607 throw std::runtime_error("Invalid dnscrypt provider public key file " + publicKeyFile
);
610 g_outputBuffer
="Provider fingerprint is: " + DnsCryptContext::getProviderFingerprint(publicKey
) + "\n";
612 catch(std::exception
& e
) {
614 g_outputBuffer
="Error: "+string(e
.what())+"\n";
617 g_outputBuffer
="Error: DNSCrypt support is not enabled.\n";
621 g_lua
.writeFunction("generateDNSCryptCertificate", [](const std::string
& providerPrivateKeyFile
, const std::string
& certificateFile
, const std::string privateKeyFile
, uint32_t serial
, time_t begin
, time_t end
) {
622 setLuaNoSideEffect();
624 unsigned char providerPrivateKey
[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE
];
625 sodium_mlock(providerPrivateKey
, sizeof(providerPrivateKey
));
626 sodium_memzero(providerPrivateKey
, sizeof(providerPrivateKey
));
629 DnsCryptPrivateKey privateKey
;
631 ifstream
providerKStream(providerPrivateKeyFile
);
632 providerKStream
.read((char*) providerPrivateKey
, sizeof(providerPrivateKey
));
633 if (providerKStream
.fail()) {
634 providerKStream
.close();
635 throw std::runtime_error("Invalid DNSCrypt provider key file " + providerPrivateKeyFile
);
638 DnsCryptContext::generateCertificate(serial
, begin
, end
, providerPrivateKey
, privateKey
, cert
);
640 privateKey
.saveToFile(privateKeyFile
);
641 DnsCryptContext::saveCertFromFile(cert
, certificateFile
);
643 catch(std::exception
& e
) {
645 g_outputBuffer
="Error: "+string(e
.what())+"\n";
648 sodium_memzero(providerPrivateKey
, sizeof(providerPrivateKey
));
649 sodium_munlock(providerPrivateKey
, sizeof(providerPrivateKey
));
651 g_outputBuffer
="Error: DNSCrypt support is not enabled.\n";
655 g_lua
.writeFunction("showPools", []() {
656 setLuaNoSideEffect();
659 boost::format
fmt("%1$-20.20s %|25t|%2$20s %|25t|%3$20s %|50t|%4%" );
661 ret
<< (fmt
% "Name" % "Cache" % "ServerPolicy" % "Servers" ) << endl
;
663 const auto localPools
= g_pools
.getCopy();
664 for (const auto& entry
: localPools
) {
665 const string
& name
= entry
.first
;
666 const std::shared_ptr
<ServerPool
> pool
= entry
.second
;
667 string cache
= pool
->packetCache
!= nullptr ? pool
->packetCache
->toString() : "";
668 string policy
= g_policy
.getLocal()->name
;
669 if (pool
->policy
!= nullptr) {
670 policy
= pool
->policy
->name
;
674 for (const auto& server
: pool
->servers
) {
675 if (!servers
.empty()) {
678 if (!server
.second
->name
.empty()) {
679 servers
+= server
.second
->name
;
682 servers
+= server
.second
->remote
.toStringWithPort();
685 ret
<< (fmt
% name
% cache
% policy
% servers
) << endl
;
687 g_outputBuffer
=ret
.str();
688 }catch(std::exception
& e
) { g_outputBuffer
=e
.what(); throw; }
691 g_lua
.registerFunction
<void(std::shared_ptr
<ServerPool
>::*)(std::shared_ptr
<DNSDistPacketCache
>)>("setCache", [](std::shared_ptr
<ServerPool
> pool
, std::shared_ptr
<DNSDistPacketCache
> cache
) {
693 pool
->packetCache
= cache
;
696 g_lua
.registerFunction("getCache", &ServerPool::getCache
);
697 g_lua
.registerFunction
<void(std::shared_ptr
<ServerPool
>::*)()>("unsetCache", [](std::shared_ptr
<ServerPool
> pool
) {
699 pool
->packetCache
= nullptr;
703 g_lua
.writeFunction("newPacketCache", [client
](size_t maxEntries
, boost::optional
<uint32_t> maxTTL
, boost::optional
<uint32_t> minTTL
, boost::optional
<uint32_t> tempFailTTL
, boost::optional
<uint32_t> staleTTL
, boost::optional
<bool> dontAge
) {
704 return std::make_shared
<DNSDistPacketCache
>(maxEntries
, maxTTL
? *maxTTL
: 86400, minTTL
? *minTTL
: 0, tempFailTTL
? *tempFailTTL
: 60, staleTTL
? *staleTTL
: 60, dontAge
? *dontAge
: false);
706 g_lua
.registerFunction("toString", &DNSDistPacketCache::toString
);
707 g_lua
.registerFunction("isFull", &DNSDistPacketCache::isFull
);
708 g_lua
.registerFunction("purgeExpired", &DNSDistPacketCache::purgeExpired
);
709 g_lua
.registerFunction("expunge", &DNSDistPacketCache::expunge
);
710 g_lua
.registerFunction
<void(std::shared_ptr
<DNSDistPacketCache
>::*)(const DNSName
& dname
, boost::optional
<uint16_t> qtype
, boost::optional
<bool> suffixMatch
)>("expungeByName", [](
711 std::shared_ptr
<DNSDistPacketCache
> cache
,
712 const DNSName
& dname
,
713 boost::optional
<uint16_t> qtype
,
714 boost::optional
<bool> suffixMatch
) {
716 cache
->expungeByName(dname
, qtype
? *qtype
: QType::ANY
, suffixMatch
? *suffixMatch
: false);
719 g_lua
.registerFunction
<void(std::shared_ptr
<DNSDistPacketCache
>::*)()>("printStats", [](const std::shared_ptr
<DNSDistPacketCache
> cache
) {
721 g_outputBuffer
="Entries: " + std::to_string(cache
->getEntriesCount()) + "/" + std::to_string(cache
->getMaxEntries()) + "\n";
722 g_outputBuffer
+="Hits: " + std::to_string(cache
->getHits()) + "\n";
723 g_outputBuffer
+="Misses: " + std::to_string(cache
->getMisses()) + "\n";
724 g_outputBuffer
+="Deferred inserts: " + std::to_string(cache
->getDeferredInserts()) + "\n";
725 g_outputBuffer
+="Deferred lookups: " + std::to_string(cache
->getDeferredLookups()) + "\n";
726 g_outputBuffer
+="Lookup Collisions: " + std::to_string(cache
->getLookupCollisions()) + "\n";
727 g_outputBuffer
+="Insert Collisions: " + std::to_string(cache
->getInsertCollisions()) + "\n";
728 g_outputBuffer
+="TTL Too Shorts: " + std::to_string(cache
->getTTLTooShorts()) + "\n";
732 g_lua
.writeFunction("getPool", [client
](const string
& poolName
) {
734 return std::make_shared
<ServerPool
>();
736 auto localPools
= g_pools
.getCopy();
737 std::shared_ptr
<ServerPool
> pool
= createPoolIfNotExists(localPools
, poolName
);
738 g_pools
.setState(localPools
);
742 g_lua
.writeFunction("setVerboseHealthChecks", [](bool verbose
) { g_verboseHealthChecks
=verbose
; });
743 g_lua
.writeFunction("setStaleCacheEntriesTTL", [](uint32_t ttl
) { g_staleCacheEntriesTTL
= ttl
; });
745 g_lua
.writeFunction("DropResponseAction", []() {
746 return std::shared_ptr
<DNSResponseAction
>(new DropResponseAction
);
749 g_lua
.writeFunction("AllowResponseAction", []() {
750 return std::shared_ptr
<DNSResponseAction
>(new AllowResponseAction
);
753 g_lua
.writeFunction("DelayResponseAction", [](int msec
) {
754 return std::shared_ptr
<DNSResponseAction
>(new DelayResponseAction(msec
));
757 g_lua
.writeFunction("RemoteLogAction", [](std::shared_ptr
<RemoteLogger
> logger
, boost::optional
<std::function
<void(const DNSQuestion
&, DNSDistProtoBufMessage
*)> > alterFunc
) {
759 return std::shared_ptr
<DNSAction
>(new RemoteLogAction(logger
, alterFunc
));
761 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
764 g_lua
.writeFunction("RemoteLogResponseAction", [](std::shared_ptr
<RemoteLogger
> logger
, boost::optional
<std::function
<void(const DNSResponse
&, DNSDistProtoBufMessage
*)> > alterFunc
, boost::optional
<bool> includeCNAME
) {
766 return std::shared_ptr
<DNSResponseAction
>(new RemoteLogResponseAction(logger
, alterFunc
, includeCNAME
? *includeCNAME
: false));
768 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
772 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(const Netmask
&)>("setEDNSSubnet", [](DNSDistProtoBufMessage
& message
, const Netmask
& subnet
) { message
.setEDNSSubnet(subnet
); });
773 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(const DNSName
&, uint16_t, uint16_t)>("setQuestion", [](DNSDistProtoBufMessage
& message
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
) { message
.setQuestion(qname
, qtype
, qclass
); });
774 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(size_t)>("setBytes", [](DNSDistProtoBufMessage
& message
, size_t bytes
) { message
.setBytes(bytes
); });
775 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setTime", [](DNSDistProtoBufMessage
& message
, time_t sec
, uint32_t usec
) { message
.setTime(sec
, usec
); });
776 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setQueryTime", [](DNSDistProtoBufMessage
& message
, time_t sec
, uint32_t usec
) { message
.setQueryTime(sec
, usec
); });
777 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(uint8_t)>("setResponseCode", [](DNSDistProtoBufMessage
& message
, uint8_t rcode
) { message
.setResponseCode(rcode
); });
778 g_lua
.registerFunction
<std::string(DNSDistProtoBufMessage::*)()>("toDebugString", [](const DNSDistProtoBufMessage
& message
) { return message
.toDebugString(); });
780 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(const ComboAddress
&)>("setRequestor", [](DNSDistProtoBufMessage
& message
, const ComboAddress
& addr
) {
781 message
.setRequestor(addr
);
783 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(const std::string
&)>("setRequestorFromString", [](DNSDistProtoBufMessage
& message
, const std::string
& str
) {
784 message
.setRequestor(str
);
786 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(const ComboAddress
&)>("setResponder", [](DNSDistProtoBufMessage
& message
, const ComboAddress
& addr
) {
787 message
.setResponder(addr
);
789 g_lua
.registerFunction
<void(DNSDistProtoBufMessage::*)(const std::string
&)>("setResponderFromString", [](DNSDistProtoBufMessage
& message
, const std::string
& str
) {
790 message
.setResponder(str
);
793 g_lua
.writeFunction("newRemoteLogger", [client
](const std::string
& remote
, boost::optional
<uint16_t> timeout
, boost::optional
<uint64_t> maxQueuedEntries
, boost::optional
<uint8_t> reconnectWaitTime
) {
794 return std::make_shared
<RemoteLogger
>(ComboAddress(remote
), timeout
? *timeout
: 2, maxQueuedEntries
? *maxQueuedEntries
: 100, reconnectWaitTime
? *reconnectWaitTime
: 1);
797 g_lua
.writeFunction("TeeAction", [](const std::string
& remote
, boost::optional
<bool> addECS
) {
798 return std::shared_ptr
<DNSAction
>(new TeeAction(ComboAddress(remote
, 53), addECS
? *addECS
: false));
801 g_lua
.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength
, uint16_t v6PrefixLength
) {
802 return std::shared_ptr
<DNSAction
>(new ECSPrefixLengthAction(v4PrefixLength
, v6PrefixLength
));
805 g_lua
.writeFunction("ECSOverrideAction", [](bool ecsOverride
) {
806 return std::shared_ptr
<DNSAction
>(new ECSOverrideAction(ecsOverride
));
809 g_lua
.writeFunction("DisableECSAction", []() {
810 return std::shared_ptr
<DNSAction
>(new DisableECSAction());
813 g_lua
.registerFunction
<void(DNSAction::*)()>("printStats", [](const DNSAction
& ta
) {
814 setLuaNoSideEffect();
815 auto stats
= ta
.getStats();
816 for(const auto& s
: stats
) {
817 g_outputBuffer
+=s
.first
+"\t";
818 if((uint64_t)s
.second
== s
.second
)
819 g_outputBuffer
+= std::to_string((uint64_t)s
.second
)+"\n";
821 g_outputBuffer
+= std::to_string(s
.second
)+"\n";
825 g_lua
.writeFunction("getAction", [](unsigned int num
) {
826 setLuaNoSideEffect();
827 boost::optional
<std::shared_ptr
<DNSAction
>> ret
;
828 auto rulactions
= g_rulactions
.getCopy();
829 if(num
< rulactions
.size())
830 ret
=rulactions
[num
].second
;
834 g_lua
.registerFunction("getStats", &DNSAction::getStats
);
836 g_lua
.writeFunction("addResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
> > era
) {
837 if (era
.type() == typeid(std::shared_ptr
<DNSAction
>)) {
838 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
841 auto ea
= *boost::get
<std::shared_ptr
<DNSResponseAction
>>(&era
);
844 auto rule
=makeRule(var
);
845 g_resprulactions
.modify([rule
, ea
](decltype(g_resprulactions
)::value_type
& rulactions
){
846 rulactions
.push_back({rule
, ea
});
850 g_lua
.writeFunction("showResponseRules", []() {
851 setLuaNoSideEffect();
852 boost::format
fmt("%-3d %9d %-50s %s\n");
853 g_outputBuffer
+= (fmt
% "#" % "Matches" % "Rule" % "Action").str();
855 for(const auto& lim
: g_resprulactions
.getCopy()) {
856 string name
= lim
.first
->toString();
857 g_outputBuffer
+= (fmt
% num
% lim
.first
->d_matches
% name
% lim
.second
->toString()).str();
862 g_lua
.writeFunction("rmResponseRule", [](unsigned int num
) {
864 auto rules
= g_resprulactions
.getCopy();
865 if(num
>= rules
.size()) {
866 g_outputBuffer
= "Error: attempt to delete non-existing rule\n";
869 rules
.erase(rules
.begin()+num
);
870 g_resprulactions
.setState(rules
);
873 g_lua
.writeFunction("topResponseRule", []() {
875 auto rules
= g_resprulactions
.getCopy();
878 auto subject
= *rules
.rbegin();
879 rules
.erase(std::prev(rules
.end()));
880 rules
.insert(rules
.begin(), subject
);
881 g_resprulactions
.setState(rules
);
884 g_lua
.writeFunction("mvResponseRule", [](unsigned int from
, unsigned int to
) {
886 auto rules
= g_resprulactions
.getCopy();
887 if(from
>= rules
.size() || to
> rules
.size()) {
888 g_outputBuffer
= "Error: attempt to move rules from/to invalid index\n";
891 auto subject
= rules
[from
];
892 rules
.erase(rules
.begin()+from
);
893 if(to
== rules
.size())
894 rules
.push_back(subject
);
898 rules
.insert(rules
.begin()+to
, subject
);
900 g_resprulactions
.setState(rules
);
903 g_lua
.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var
, std::shared_ptr
<DNSResponseAction
> ea
) {
905 auto rule
=makeRule(var
);
906 g_cachehitresprulactions
.modify([rule
, ea
](decltype(g_cachehitresprulactions
)::value_type
& rulactions
){
907 rulactions
.push_back({rule
, ea
});
911 g_lua
.writeFunction("showCacheHitResponseRules", []() {
912 setLuaNoSideEffect();
913 boost::format
fmt("%-3d %9d %-50s %s\n");
914 g_outputBuffer
+= (fmt
% "#" % "Matches" % "Rule" % "Action").str();
916 for(const auto& lim
: g_cachehitresprulactions
.getCopy()) {
917 string name
= lim
.first
->toString();
918 g_outputBuffer
+= (fmt
% num
% lim
.first
->d_matches
% name
% lim
.second
->toString()).str();
923 g_lua
.writeFunction("rmCacheHitResponseRule", [](unsigned int num
) {
925 auto rules
= g_cachehitresprulactions
.getCopy();
926 if(num
>= rules
.size()) {
927 g_outputBuffer
= "Error: attempt to delete non-existing rule\n";
930 rules
.erase(rules
.begin()+num
);
931 g_cachehitresprulactions
.setState(rules
);
934 g_lua
.writeFunction("topCacheHitResponseRule", []() {
936 auto rules
= g_cachehitresprulactions
.getCopy();
939 auto subject
= *rules
.rbegin();
940 rules
.erase(std::prev(rules
.end()));
941 rules
.insert(rules
.begin(), subject
);
942 g_cachehitresprulactions
.setState(rules
);
945 g_lua
.writeFunction("mvCacheHitResponseRule", [](unsigned int from
, unsigned int to
) {
947 auto rules
= g_cachehitresprulactions
.getCopy();
948 if(from
>= rules
.size() || to
> rules
.size()) {
949 g_outputBuffer
= "Error: attempt to move rules from/to invalid index\n";
952 auto subject
= rules
[from
];
953 rules
.erase(rules
.begin()+from
);
954 if(to
== rules
.size())
955 rules
.push_back(subject
);
959 rules
.insert(rules
.begin()+to
, subject
);
961 g_cachehitresprulactions
.setState(rules
);
964 g_lua
.writeFunction("showBinds", []() {
965 setLuaNoSideEffect();
968 boost::format
fmt("%1$-3d %2$-20.20s %|25t|%3$-8.8s %|35t|%4%" );
970 ret
<< (fmt
% "#" % "Address" % "Protocol" % "Queries" ) << endl
;
973 for (const auto& front
: g_frontends
) {
974 ret
<< (fmt
% counter
% front
->local
.toStringWithPort() % (front
->udpFD
!= -1 ? "UDP" : "TCP") % front
->queries
) << endl
;
977 g_outputBuffer
=ret
.str();
978 }catch(std::exception
& e
) { g_outputBuffer
=e
.what(); throw; }
981 g_lua
.writeFunction("getBind", [](size_t num
) {
982 setLuaNoSideEffect();
983 ClientState
* ret
= nullptr;
984 if(num
< g_frontends
.size()) {
985 ret
=g_frontends
[num
];
990 g_lua
.registerFunction
<std::string(ClientState::*)()>("toString", [](const ClientState
& fe
) {
991 setLuaNoSideEffect();
992 return fe
.local
.toStringWithPort();
995 g_lua
.registerMember("muted", &ClientState::muted
);
997 g_lua
.writeFunction("help", [](boost::optional
<std::string
> command
) {
998 setLuaNoSideEffect();
1000 for (const auto& keyword
: g_consoleKeywords
) {
1002 g_outputBuffer
+= keyword
.toString() + "\n";
1004 else if (keyword
.name
== command
) {
1005 g_outputBuffer
= keyword
.toString() + "\n";
1010 g_outputBuffer
= "Nothing found for " + *command
+ "\n";
1014 g_lua
.writeFunction("showVersion", []() {
1015 setLuaNoSideEffect();
1016 g_outputBuffer
= "dnsdist " + std::string(VERSION
) + "\n";
1020 g_lua
.writeFunction("newBPFFilter", [client
](uint32_t maxV4
, uint32_t maxV6
, uint32_t maxQNames
) {
1022 return std::shared_ptr
<BPFFilter
>(nullptr);
1024 return std::make_shared
<BPFFilter
>(maxV4
, maxV6
, maxQNames
);
1027 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)(const ComboAddress
& ca
)>("block", [](std::shared_ptr
<BPFFilter
> bpf
, const ComboAddress
& ca
) {
1029 return bpf
->block(ca
);
1033 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)(const DNSName
& qname
, boost::optional
<uint16_t> qtype
)>("blockQName", [](std::shared_ptr
<BPFFilter
> bpf
, const DNSName
& qname
, boost::optional
<uint16_t> qtype
) {
1035 return bpf
->block(qname
, qtype
? *qtype
: 255);
1039 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)(const ComboAddress
& ca
)>("unblock", [](std::shared_ptr
<BPFFilter
> bpf
, const ComboAddress
& ca
) {
1041 return bpf
->unblock(ca
);
1045 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)(const DNSName
& qname
, boost::optional
<uint16_t> qtype
)>("unblockQName", [](std::shared_ptr
<BPFFilter
> bpf
, const DNSName
& qname
, boost::optional
<uint16_t> qtype
) {
1047 return bpf
->unblock(qname
, qtype
? *qtype
: 255);
1051 g_lua
.registerFunction
<std::string(std::shared_ptr
<BPFFilter
>::*)()>("getStats", [](const std::shared_ptr
<BPFFilter
> bpf
) {
1052 setLuaNoSideEffect();
1055 std::vector
<std::pair
<ComboAddress
, uint64_t> > stats
= bpf
->getAddrStats();
1056 for (const auto& value
: stats
) {
1057 if (value
.first
.sin4
.sin_family
== AF_INET
) {
1058 res
+= value
.first
.toString() + ": " + std::to_string(value
.second
) + "\n";
1060 else if (value
.first
.sin4
.sin_family
== AF_INET6
) {
1061 res
+= "[" + value
.first
.toString() + "]: " + std::to_string(value
.second
) + "\n";
1064 std::vector
<std::tuple
<DNSName
, uint16_t, uint64_t> > qstats
= bpf
->getQNameStats();
1065 for (const auto& value
: qstats
) {
1066 res
+= std::get
<0>(value
).toString() + " " + std::to_string(std::get
<1>(value
)) + ": " + std::to_string(std::get
<2>(value
)) + "\n";
1072 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)()>("attachToAllBinds", [](std::shared_ptr
<BPFFilter
> bpf
) {
1075 for (const auto& frontend
: g_frontends
) {
1076 frontend
->attachFilter(bpf
);
1081 g_lua
.registerFunction
<void(ClientState::*)()>("detachFilter", [](ClientState
& frontend
) {
1082 frontend
.detachFilter();
1085 g_lua
.registerFunction
<void(ClientState::*)(std::shared_ptr
<BPFFilter
>)>("attachFilter", [](ClientState
& frontend
, std::shared_ptr
<BPFFilter
> bpf
) {
1087 frontend
.attachFilter(bpf
);
1091 g_lua
.writeFunction("setDefaultBPFFilter", [](std::shared_ptr
<BPFFilter
> bpf
) {
1092 if (g_configurationDone
) {
1093 g_outputBuffer
="setDefaultBPFFilter() cannot be used at runtime!\n";
1096 g_defaultBPFFilter
= bpf
;
1099 g_lua
.writeFunction("newDynBPFFilter", [client
](std::shared_ptr
<BPFFilter
> bpf
) {
1101 return std::shared_ptr
<DynBPFFilter
>(nullptr);
1103 return std::make_shared
<DynBPFFilter
>(bpf
);
1106 g_lua
.writeFunction("registerDynBPFFilter", [](std::shared_ptr
<DynBPFFilter
> dbpf
) {
1108 g_dynBPFFilters
.push_back(dbpf
);
1112 g_lua
.writeFunction("unregisterDynBPFFilter", [](std::shared_ptr
<DynBPFFilter
> dbpf
) {
1114 for (auto it
= g_dynBPFFilters
.begin(); it
!= g_dynBPFFilters
.end(); it
++) {
1116 g_dynBPFFilters
.erase(it
);
1123 g_lua
.registerFunction
<void(std::shared_ptr
<DynBPFFilter
>::*)(const ComboAddress
& addr
, boost::optional
<int> seconds
)>("block", [](std::shared_ptr
<DynBPFFilter
> dbpf
, const ComboAddress
& addr
, boost::optional
<int> seconds
) {
1125 struct timespec until
;
1126 clock_gettime(CLOCK_MONOTONIC
, &until
);
1127 until
.tv_sec
+= seconds
? *seconds
: 10;
1128 dbpf
->block(addr
, until
);
1132 g_lua
.registerFunction
<void(std::shared_ptr
<DynBPFFilter
>::*)()>("purgeExpired", [](std::shared_ptr
<DynBPFFilter
> dbpf
) {
1134 struct timespec now
;
1135 clock_gettime(CLOCK_MONOTONIC
, &now
);
1136 dbpf
->purgeExpired(now
);
1140 g_lua
.writeFunction("addBPFFilterDynBlocks", [](const map
<ComboAddress
,int>& m
, std::shared_ptr
<DynBPFFilter
> dynbpf
, boost::optional
<int> seconds
) {
1142 struct timespec until
, now
;
1143 clock_gettime(CLOCK_MONOTONIC
, &now
);
1145 int actualSeconds
= seconds
? *seconds
: 10;
1146 until
.tv_sec
+= actualSeconds
;
1147 for(const auto& capair
: m
) {
1148 dynbpf
->block(capair
.first
, until
);
1152 #endif /* HAVE_EBPF */
1154 g_lua
.writeFunction
<std::unordered_map
<string
,uint64_t>()>("getStatisticsCounters", []() {
1155 setLuaNoSideEffect();
1156 std::unordered_map
<string
,uint64_t> res
;
1157 for(const auto& entry
: g_stats
.entries
) {
1158 if(const auto& val
= boost::get
<DNSDistStats::stat_t
*>(&entry
.second
))
1159 res
[entry
.first
] = (*val
)->load();
1164 g_lua
.writeFunction("includeDirectory", [](const std::string
& dirname
) {
1165 if (g_configurationDone
) {
1166 errlog("includeDirectory() cannot be used at runtime!");
1167 g_outputBuffer
="includeDirectory() cannot be used at runtime!\n";
1172 errlog("includeDirectory() cannot be used recursively!");
1173 g_outputBuffer
="includeDirectory() cannot be used recursively!\n";
1180 if (stat(dirname
.c_str(), &st
)) {
1181 errlog("The included directory %s does not exist!", dirname
.c_str());
1182 g_outputBuffer
="The included directory " + dirname
+ " does not exist!";
1186 if (!S_ISDIR(st
.st_mode
)) {
1187 errlog("The included directory %s is not a directory!", dirname
.c_str());
1188 g_outputBuffer
="The included directory " + dirname
+ " is not a directory!";
1194 std::list
<std::string
> files
;
1195 if (!(dirp
= opendir(dirname
.c_str()))) {
1196 errlog("Error opening the included directory %s!", dirname
.c_str());
1197 g_outputBuffer
="Error opening the included directory " + dirname
+ "!";
1201 while((ent
= readdir(dirp
)) != NULL
) {
1202 if (ent
->d_name
[0] == '.') {
1206 if (boost::ends_with(ent
->d_name
, ".conf")) {
1207 std::ostringstream namebuf
;
1208 namebuf
<< dirname
.c_str() << "/" << ent
->d_name
;
1210 if (stat(namebuf
.str().c_str(), &st
) || !S_ISREG(st
.st_mode
)) {
1214 files
.push_back(namebuf
.str());
1221 for (auto file
= files
.begin(); file
!= files
.end(); ++file
) {
1222 std::ifstream
ifs(*file
);
1224 warnlog("Unable to read configuration from '%s'", *file
);
1226 vinfolog("Read configuration from '%s'", *file
);
1229 g_lua
.executeCode(ifs
);
1235 g_lua
.writeFunction("setAPIWritable", [](bool writable
, boost::optional
<std::string
> apiConfigDir
) {
1237 g_apiReadWrite
= writable
;
1239 if (!(*apiConfigDir
).empty()) {
1240 g_apiConfigDirectory
= *apiConfigDir
;
1243 errlog("The API configuration directory value cannot be empty!");
1244 g_outputBuffer
="The API configuration directory value cannot be empty!";
1249 g_lua
.writeFunction("setServFailWhenNoServer", [](bool servfail
) {
1251 g_servFailOnNoPolicy
= servfail
;
1254 g_lua
.writeFunction("setRingBuffersSize", [](size_t capacity
) {
1256 if (g_configurationDone
) {
1257 errlog("setRingBuffersSize() cannot be used at runtime!");
1258 g_outputBuffer
="setRingBuffersSize() cannot be used at runtime!\n";
1261 g_rings
.setCapacity(capacity
);
1264 g_lua
.writeFunction("RDRule", []() {
1265 return std::shared_ptr
<DNSRule
>(new RDRule());
1268 g_lua
.writeFunction("TimedIPSetRule", []() {
1269 return std::shared_ptr
<TimedIPSetRule
>(new TimedIPSetRule());
1272 g_lua
.registerFunction
<void(std::shared_ptr
<TimedIPSetRule
>::*)()>("clear", [](std::shared_ptr
<TimedIPSetRule
> tisr
) {
1276 g_lua
.registerFunction
<void(std::shared_ptr
<TimedIPSetRule
>::*)()>("cleanup", [](std::shared_ptr
<TimedIPSetRule
> tisr
) {
1280 g_lua
.registerFunction
<void(std::shared_ptr
<TimedIPSetRule
>::*)(const ComboAddress
& ca
, int t
)>("add", [](std::shared_ptr
<TimedIPSetRule
> tisr
, const ComboAddress
& ca
, int t
) {
1281 tisr
->add(ca
, time(0)+t
);
1284 g_lua
.registerFunction
<std::shared_ptr
<DNSRule
>(std::shared_ptr
<TimedIPSetRule
>::*)()>("slice", [](std::shared_ptr
<TimedIPSetRule
> tisr
) {
1285 return std::dynamic_pointer_cast
<DNSRule
>(tisr
);
1288 g_lua
.writeFunction("setWHashedPertubation", [](uint32_t pertub
) {
1290 g_hashperturb
= pertub
;
1293 g_lua
.writeFunction("setTCPUseSinglePipe", [](bool flag
) {
1294 if (g_configurationDone
) {
1295 g_outputBuffer
="setTCPUseSinglePipe() cannot be used at runtime!\n";
1299 g_useTCPSinglePipe
= flag
;
1302 g_lua
.writeFunction("snmpAgent", [](bool enableTraps
, boost::optional
<std::string
> masterSocket
) {
1303 #ifdef HAVE_NET_SNMP
1304 if (g_configurationDone
) {
1305 errlog("snmpAgent() cannot be used at runtime!");
1306 g_outputBuffer
="snmpAgent() cannot be used at runtime!\n";
1310 if (g_snmpEnabled
) {
1311 errlog("snmpAgent() cannot be used twice!");
1312 g_outputBuffer
="snmpAgent() cannot be used twice!\n";
1316 g_snmpEnabled
= true;
1317 g_snmpTrapsEnabled
= enableTraps
;
1318 g_snmpAgent
= new DNSDistSNMPAgent("dnsdist", masterSocket
? *masterSocket
: std::string());
1320 errlog("NET SNMP support is required to use snmpAgent()");
1321 g_outputBuffer
="NET SNMP support is required to use snmpAgent()\n";
1322 #endif /* HAVE_NET_SNMP */
1325 g_lua
.writeFunction("SNMPTrapAction", [](boost::optional
<std::string
> reason
) {
1326 #ifdef HAVE_NET_SNMP
1327 return std::shared_ptr
<DNSAction
>(new SNMPTrapAction(reason
? *reason
: ""));
1329 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1330 #endif /* HAVE_NET_SNMP */
1333 g_lua
.writeFunction("SNMPTrapResponseAction", [](boost::optional
<std::string
> reason
) {
1334 #ifdef HAVE_NET_SNMP
1335 return std::shared_ptr
<DNSResponseAction
>(new SNMPTrapResponseAction(reason
? *reason
: ""));
1337 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1338 #endif /* HAVE_NET_SNMP */
1341 g_lua
.writeFunction("sendCustomTrap", [](const std::string
& str
) {
1342 #ifdef HAVE_NET_SNMP
1343 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
1344 g_snmpAgent
->sendCustomTrap(str
);
1346 #endif /* HAVE_NET_SNMP */
1349 g_lua
.writeFunction("setPoolServerPolicy", [](ServerPolicy policy
, string pool
) {
1351 auto localPools
= g_pools
.getCopy();
1352 setPoolPolicy(localPools
, pool
, std::make_shared
<ServerPolicy
>(policy
));
1353 g_pools
.setState(localPools
);
1356 g_lua
.writeFunction("setPoolServerPolicyLua", [](string name
, policyfunc_t policy
, string pool
) {
1358 auto localPools
= g_pools
.getCopy();
1359 setPoolPolicy(localPools
, pool
, std::make_shared
<ServerPolicy
>(ServerPolicy
{name
, policy
}));
1360 g_pools
.setState(localPools
);
1363 g_lua
.writeFunction("showPoolServerPolicy", [](string pool
) {
1365 auto localPools
= g_pools
.getCopy();
1366 auto poolObj
= getPool(localPools
, pool
);
1367 if (poolObj
->policy
== nullptr) {
1368 g_outputBuffer
=g_policy
.getLocal()->name
+"\n";
1370 g_outputBuffer
=poolObj
->policy
->name
+"\n";
1374 g_lua
.writeFunction("setTCPDownstreamCleanupInterval", [](uint16_t interval
) {
1376 g_downstreamTCPCleanupInterval
= interval
;