]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-lua-bindings.cc
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.
24 #include "dnsdist-lua.hh"
28 void setupLuaBindings(bool client
)
30 g_lua
.writeFunction("infolog", [](const string
& arg
) {
33 g_lua
.writeFunction("errlog", [](const string
& arg
) {
36 g_lua
.writeFunction("warnlog", [](const string
& arg
) {
39 g_lua
.writeFunction("show", [](const string
& arg
) {
45 g_lua
.registerFunction
<string(std::exception_ptr::*)()>("__tostring", [](const std::exception_ptr
& eptr
) {
48 std::rethrow_exception(eptr
);
50 } catch(const std::exception
& e
) {
51 return string(e
.what());
52 } catch(const PDNSException
& e
) {
55 return string("Unknown exception");
57 return string("No exception");
60 g_lua
.writeFunction("newServerPolicy", [](string name
, policyfunc_t policy
) { return ServerPolicy
{name
, policy
, true};});
61 g_lua
.registerMember("name", &ServerPolicy::name
);
62 g_lua
.registerMember("policy", &ServerPolicy::policy
);
63 g_lua
.registerMember("isLua", &ServerPolicy::isLua
);
64 g_lua
.registerFunction("toString", &ServerPolicy::toString
);
66 g_lua
.writeVariable("firstAvailable", ServerPolicy
{"firstAvailable", firstAvailable
, false});
67 g_lua
.writeVariable("roundrobin", ServerPolicy
{"roundrobin", roundrobin
, false});
68 g_lua
.writeVariable("wrandom", ServerPolicy
{"wrandom", wrandom
, false});
69 g_lua
.writeVariable("whashed", ServerPolicy
{"whashed", whashed
, false});
70 g_lua
.writeVariable("chashed", ServerPolicy
{"chashed", chashed
, false});
71 g_lua
.writeVariable("leastOutstanding", ServerPolicy
{"leastOutstanding", leastOutstanding
, false});
74 g_lua
.registerFunction
<void(std::shared_ptr
<ServerPool
>::*)(std::shared_ptr
<DNSDistPacketCache
>)>("setCache", [](std::shared_ptr
<ServerPool
> pool
, std::shared_ptr
<DNSDistPacketCache
> cache
) {
76 pool
->packetCache
= cache
;
79 g_lua
.registerFunction("getCache", &ServerPool::getCache
);
80 g_lua
.registerFunction
<void(std::shared_ptr
<ServerPool
>::*)()>("unsetCache", [](std::shared_ptr
<ServerPool
> pool
) {
82 pool
->packetCache
= nullptr;
85 g_lua
.registerFunction("getECS", &ServerPool::getECS
);
86 g_lua
.registerFunction("setECS", &ServerPool::setECS
);
89 g_lua
.registerFunction
<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState
& s
, int lim
) { s
.qps
= lim
? QPSLimiter(lim
, lim
) : QPSLimiter(); });
90 g_lua
.registerFunction
<void(std::shared_ptr
<DownstreamState
>::*)(string
)>("addPool", [](std::shared_ptr
<DownstreamState
> s
, string pool
) {
91 auto localPools
= g_pools
.getCopy();
92 addServerToPool(localPools
, pool
, s
);
93 g_pools
.setState(localPools
);
94 s
->pools
.insert(pool
);
96 g_lua
.registerFunction
<void(std::shared_ptr
<DownstreamState
>::*)(string
)>("rmPool", [](std::shared_ptr
<DownstreamState
> s
, string pool
) {
97 auto localPools
= g_pools
.getCopy();
98 removeServerFromPool(localPools
, pool
, s
);
99 g_pools
.setState(localPools
);
100 s
->pools
.erase(pool
);
102 g_lua
.registerFunction
<uint64_t(DownstreamState::*)()>("getOutstanding", [](const DownstreamState
& s
) { return s
.outstanding
.load(); });
103 g_lua
.registerFunction("isUp", &DownstreamState::isUp
);
104 g_lua
.registerFunction("setDown", &DownstreamState::setDown
);
105 g_lua
.registerFunction("setUp", &DownstreamState::setUp
);
106 g_lua
.registerFunction
<void(DownstreamState::*)(boost::optional
<bool> newStatus
)>("setAuto", [](DownstreamState
& s
, boost::optional
<bool> newStatus
) {
108 s
.upStatus
= *newStatus
;
112 g_lua
.registerFunction("getName", &DownstreamState::getName
);
113 g_lua
.registerFunction("getNameWithAddr", &DownstreamState::getNameWithAddr
);
114 g_lua
.registerMember("upStatus", &DownstreamState::upStatus
);
115 g_lua
.registerMember
<int (DownstreamState::*)>("weight",
116 [](const DownstreamState
& s
) -> int {return s
.weight
;},
117 [](DownstreamState
& s
, int newWeight
) {s
.setWeight(newWeight
);}
119 g_lua
.registerMember("order", &DownstreamState::order
);
120 g_lua
.registerMember("name", &DownstreamState::name
);
121 g_lua
.registerFunction
<std::string(DownstreamState::*)()>("getID", [](const DownstreamState
& s
) { return boost::uuids::to_string(s
.id
); });
124 g_lua
.registerFunction
<void(dnsheader::*)(bool)>("setRD", [](dnsheader
& dh
, bool v
) {
128 g_lua
.registerFunction
<bool(dnsheader::*)()>("getRD", [](dnsheader
& dh
) {
132 g_lua
.registerFunction
<void(dnsheader::*)(bool)>("setRA", [](dnsheader
& dh
, bool v
) {
136 g_lua
.registerFunction
<bool(dnsheader::*)()>("getRA", [](dnsheader
& dh
) {
140 g_lua
.registerFunction
<void(dnsheader::*)(bool)>("setAD", [](dnsheader
& dh
, bool v
) {
144 g_lua
.registerFunction
<bool(dnsheader::*)()>("getAD", [](dnsheader
& dh
) {
148 g_lua
.registerFunction
<void(dnsheader::*)(bool)>("setAA", [](dnsheader
& dh
, bool v
) {
152 g_lua
.registerFunction
<bool(dnsheader::*)()>("getAA", [](dnsheader
& dh
) {
156 g_lua
.registerFunction
<void(dnsheader::*)(bool)>("setCD", [](dnsheader
& dh
, bool v
) {
160 g_lua
.registerFunction
<bool(dnsheader::*)()>("getCD", [](dnsheader
& dh
) {
164 g_lua
.registerFunction
<void(dnsheader::*)(bool)>("setTC", [](dnsheader
& dh
, bool v
) {
166 if(v
) dh
.ra
= dh
.rd
; // you'll always need this, otherwise TC=1 gets ignored
169 g_lua
.registerFunction
<void(dnsheader::*)(bool)>("setQR", [](dnsheader
& dh
, bool v
) {
174 g_lua
.writeFunction("newCA", [](const std::string
& name
) { return ComboAddress(name
); });
175 g_lua
.registerFunction
<string(ComboAddress::*)()>("tostring", [](const ComboAddress
& ca
) { return ca
.toString(); });
176 g_lua
.registerFunction
<string(ComboAddress::*)()>("tostringWithPort", [](const ComboAddress
& ca
) { return ca
.toStringWithPort(); });
177 g_lua
.registerFunction
<string(ComboAddress::*)()>("toString", [](const ComboAddress
& ca
) { return ca
.toString(); });
178 g_lua
.registerFunction
<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress
& ca
) { return ca
.toStringWithPort(); });
179 g_lua
.registerFunction
<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress
& ca
) { return ntohs(ca
.sin4
.sin_port
); } );
180 g_lua
.registerFunction
<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress
& ca
, unsigned int bits
) { ca
.truncate(bits
); });
181 g_lua
.registerFunction
<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress
& ca
) { return ca
.sin4
.sin_family
== AF_INET
; });
182 g_lua
.registerFunction
<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress
& ca
) { return ca
.sin4
.sin_family
== AF_INET6
; });
183 g_lua
.registerFunction
<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress
& ca
) { return ca
.isMappedIPv4(); });
184 g_lua
.registerFunction
<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress
& ca
) { return ca
.mapToIPv4(); });
185 g_lua
.registerFunction
<bool(nmts_t::*)(const ComboAddress
&)>("match", [](nmts_t
& s
, const ComboAddress
& ca
) { return s
.match(ca
); });
188 g_lua
.registerFunction("isPartOf", &DNSName::isPartOf
);
189 g_lua
.registerFunction
<bool(DNSName::*)()>("chopOff", [](DNSName
&dn
) { return dn
.chopOff(); });
190 g_lua
.registerFunction
<unsigned int(DNSName::*)()>("countLabels", [](const DNSName
& name
) { return name
.countLabels(); });
191 g_lua
.registerFunction
<size_t(DNSName::*)()>("wirelength", [](const DNSName
& name
) { return name
.wirelength(); });
192 g_lua
.registerFunction
<string(DNSName::*)()>("tostring", [](const DNSName
&dn
) { return dn
.toString(); });
193 g_lua
.registerFunction
<string(DNSName::*)()>("toString", [](const DNSName
&dn
) { return dn
.toString(); });
194 g_lua
.writeFunction("newDNSName", [](const std::string
& name
) { return DNSName(name
); });
195 g_lua
.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); });
196 g_lua
.writeFunction("newDNSNameSet", []() { return DNSNameSet(); });
199 g_lua
.registerFunction
<string(DNSNameSet::*)()>("toString", [](const DNSNameSet
&dns
) { return dns
.toString(); });
200 g_lua
.registerFunction
<void(DNSNameSet::*)(DNSName
&)>("add", [](DNSNameSet
& dns
, DNSName
& dn
) { dns
.insert(dn
); });
201 g_lua
.registerFunction
<bool(DNSNameSet::*)(DNSName
&)>("check", [](DNSNameSet
& dns
, DNSName
& dn
) { return dns
.find(dn
) != dns
.end(); });
202 g_lua
.registerFunction("delete",(size_t (DNSNameSet::*)(const DNSName
&)) &DNSNameSet::erase
);
203 g_lua
.registerFunction("size",(size_t (DNSNameSet::*)() const) &DNSNameSet::size
);
204 g_lua
.registerFunction("clear",(void (DNSNameSet::*)()) &DNSNameSet::clear
);
205 g_lua
.registerFunction("empty",(bool (DNSNameSet::*)()) &DNSNameSet::empty
);
207 /* SuffixMatchNode */
208 g_lua
.registerFunction
<void (SuffixMatchNode::*)(const boost::variant
<DNSName
, string
, vector
<pair
<int, DNSName
>>, vector
<pair
<int, string
>>> &name
)>("add", [](SuffixMatchNode
&smn
, const boost::variant
<DNSName
, string
, vector
<pair
<int, DNSName
>>, vector
<pair
<int, string
>>> &name
) {
209 if (name
.type() == typeid(DNSName
)) {
210 auto n
= boost::get
<DNSName
>(name
);
214 if (name
.type() == typeid(string
)) {
215 auto n
= boost::get
<string
>(name
);
219 if (name
.type() == typeid(vector
<pair
<int, DNSName
>>)) {
220 auto names
= boost::get
<vector
<pair
<int, DNSName
>>>(name
);
221 for (auto const n
: names
) {
226 if (name
.type() == typeid(vector
<pair
<int, string
>>)) {
227 auto names
= boost::get
<vector
<pair
<int, string
>>>(name
);
228 for (auto const n
: names
) {
234 g_lua
.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName
&) const) &SuffixMatchNode::check
);
237 g_lua
.writeFunction("newNMG", []() { return NetmaskGroup(); });
238 g_lua
.registerFunction
<void(NetmaskGroup::*)(const std::string
&mask
)>("addMask", [](NetmaskGroup
&nmg
, const std::string
& mask
)
242 g_lua
.registerFunction
<void(NetmaskGroup::*)(const std::map
<ComboAddress
,int>& map
)>("addMasks", [](NetmaskGroup
&nmg
, const std::map
<ComboAddress
,int>& map
)
244 for (const auto& entry
: map
) {
245 nmg
.addMask(Netmask(entry
.first
));
249 g_lua
.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress
&) const)&NetmaskGroup::match
);
250 g_lua
.registerFunction("size", &NetmaskGroup::size
);
251 g_lua
.registerFunction("clear", &NetmaskGroup::clear
);
252 g_lua
.registerFunction
<string(NetmaskGroup::*)()>("toString", [](const NetmaskGroup
& nmg
) { return "NetmaskGroup " + nmg
.toString(); });
255 g_lua
.writeFunction("newQPSLimiter", [](int rate
, int burst
) { return QPSLimiter(rate
, burst
); });
256 g_lua
.registerFunction("check", &QPSLimiter::check
);
259 g_lua
.registerFunction
<std::string(ClientState::*)()>("toString", [](const ClientState
& fe
) {
260 setLuaNoSideEffect();
261 return fe
.local
.toStringWithPort();
263 g_lua
.registerMember("muted", &ClientState::muted
);
265 g_lua
.registerFunction
<void(ClientState::*)(std::shared_ptr
<BPFFilter
>)>("attachFilter", [](ClientState
& frontend
, std::shared_ptr
<BPFFilter
> bpf
) {
267 frontend
.attachFilter(bpf
);
270 g_lua
.registerFunction
<void(ClientState::*)()>("detachFilter", [](ClientState
& frontend
) {
271 frontend
.detachFilter();
273 #endif /* HAVE_EBPF */
277 g_lua
.writeFunction("newBPFFilter", [client
](uint32_t maxV4
, uint32_t maxV6
, uint32_t maxQNames
) {
279 return std::shared_ptr
<BPFFilter
>(nullptr);
281 return std::make_shared
<BPFFilter
>(maxV4
, maxV6
, maxQNames
);
284 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)(const ComboAddress
& ca
)>("block", [](std::shared_ptr
<BPFFilter
> bpf
, const ComboAddress
& ca
) {
286 return bpf
->block(ca
);
290 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
) {
292 return bpf
->block(qname
, qtype
? *qtype
: 255);
296 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)(const ComboAddress
& ca
)>("unblock", [](std::shared_ptr
<BPFFilter
> bpf
, const ComboAddress
& ca
) {
298 return bpf
->unblock(ca
);
302 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
) {
304 return bpf
->unblock(qname
, qtype
? *qtype
: 255);
308 g_lua
.registerFunction
<std::string(std::shared_ptr
<BPFFilter
>::*)()>("getStats", [](const std::shared_ptr
<BPFFilter
> bpf
) {
309 setLuaNoSideEffect();
312 std::vector
<std::pair
<ComboAddress
, uint64_t> > stats
= bpf
->getAddrStats();
313 for (const auto& value
: stats
) {
314 if (value
.first
.sin4
.sin_family
== AF_INET
) {
315 res
+= value
.first
.toString() + ": " + std::to_string(value
.second
) + "\n";
317 else if (value
.first
.sin4
.sin_family
== AF_INET6
) {
318 res
+= "[" + value
.first
.toString() + "]: " + std::to_string(value
.second
) + "\n";
321 std::vector
<std::tuple
<DNSName
, uint16_t, uint64_t> > qstats
= bpf
->getQNameStats();
322 for (const auto& value
: qstats
) {
323 res
+= std::get
<0>(value
).toString() + " " + std::to_string(std::get
<1>(value
)) + ": " + std::to_string(std::get
<2>(value
)) + "\n";
329 g_lua
.registerFunction
<void(std::shared_ptr
<BPFFilter
>::*)()>("attachToAllBinds", [](std::shared_ptr
<BPFFilter
> bpf
) {
332 for (const auto& frontend
: g_frontends
) {
333 frontend
->attachFilter(bpf
);
338 g_lua
.writeFunction("newDynBPFFilter", [client
](std::shared_ptr
<BPFFilter
> bpf
) {
340 return std::shared_ptr
<DynBPFFilter
>(nullptr);
342 return std::make_shared
<DynBPFFilter
>(bpf
);
345 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
) {
347 struct timespec until
;
348 clock_gettime(CLOCK_MONOTONIC
, &until
);
349 until
.tv_sec
+= seconds
? *seconds
: 10;
350 dbpf
->block(addr
, until
);
354 g_lua
.registerFunction
<void(std::shared_ptr
<DynBPFFilter
>::*)()>("purgeExpired", [](std::shared_ptr
<DynBPFFilter
> dbpf
) {
357 clock_gettime(CLOCK_MONOTONIC
, &now
);
358 dbpf
->purgeExpired(now
);
362 g_lua
.registerFunction
<void(std::shared_ptr
<DynBPFFilter
>::*)(boost::variant
<std::string
, std::vector
<std::pair
<int, std::string
>>>)>("excludeRange", [](std::shared_ptr
<DynBPFFilter
> dbpf
, boost::variant
<std::string
, std::vector
<std::pair
<int, std::string
>>> ranges
) {
363 if (ranges
.type() == typeid(std::vector
<std::pair
<int, std::string
>>)) {
364 for (const auto& range
: *boost::get
<std::vector
<std::pair
<int, std::string
>>>(&ranges
)) {
365 dbpf
->excludeRange(Netmask(range
.second
));
369 dbpf
->excludeRange(Netmask(*boost::get
<std::string
>(&ranges
)));
373 g_lua
.registerFunction
<void(std::shared_ptr
<DynBPFFilter
>::*)(boost::variant
<std::string
, std::vector
<std::pair
<int, std::string
>>>)>("includeRange", [](std::shared_ptr
<DynBPFFilter
> dbpf
, boost::variant
<std::string
, std::vector
<std::pair
<int, std::string
>>> ranges
) {
374 if (ranges
.type() == typeid(std::vector
<std::pair
<int, std::string
>>)) {
375 for (const auto& range
: *boost::get
<std::vector
<std::pair
<int, std::string
>>>(&ranges
)) {
376 dbpf
->includeRange(Netmask(range
.second
));
380 dbpf
->includeRange(Netmask(*boost::get
<std::string
>(&ranges
)));
383 #endif /* HAVE_EBPF */
386 g_lua
.registerFunction
<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView
& option
) {
387 return option
.values
.size();
389 g_lua
.registerFunction
<std::vector
<string
>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView
& option
) {
390 std::vector
<string
> values
;
391 for (const auto& value
: option
.values
) {
392 values
.push_back(std::string(value
.content
, value
.size
));
397 g_lua
.writeFunction("newDOHResponseMapEntry", [](const std::string
& regex
, uint16_t status
, const std::string
& content
, boost::optional
<std::map
<std::string
, std::string
>> customHeaders
) {
398 boost::optional
<std::vector
<std::pair
<std::string
, std::string
>>> headers
{boost::none
};
400 headers
= std::vector
<std::pair
<std::string
, std::string
>>();
401 for (const auto& header
: *customHeaders
) {
402 headers
->push_back({ boost::to_lower_copy(header
.first
), header
.second
});
405 return std::make_shared
<DOHResponseMapEntry
>(regex
, status
, content
, headers
);