]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lua-recursor4.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.
22 #include "lua-recursor4.hh"
25 #include "dnsparser.hh"
27 #include "namespaces.hh"
28 #include "rec_channel.hh"
29 #include "ednsoptions.hh"
30 #include "ednssubnet.hh"
31 #include "filterpo.hh"
32 #include "rec-snmp.hh"
33 #include <unordered_set>
35 static int followCNAMERecords(vector
<DNSRecord
>& ret
, const QType
& qtype
)
37 vector
<DNSRecord
> resolved
;
39 for(const DNSRecord
& rr
: ret
) {
40 if(rr
.d_type
== QType::CNAME
) {
41 auto rec
= getRR
<CNAMERecordContent
>(rr
);
43 target
=rec
->getTarget();
51 int rcode
=directResolve(target
, qtype
, 1, resolved
); // 1 == class
53 for(const DNSRecord
& rr
: resolved
) {
60 static int getFakeAAAARecords(const DNSName
& qname
, const std::string
& prefix
, vector
<DNSRecord
>& ret
)
62 int rcode
=directResolve(qname
, QType(QType::A
), 1, ret
);
64 ComboAddress
prefixAddress(prefix
);
66 for(DNSRecord
& rr
: ret
)
68 if(rr
.d_type
== QType::A
&& rr
.d_place
==DNSResourceRecord::ANSWER
) {
69 if(auto rec
= getRR
<ARecordContent
>(rr
)) {
70 ComboAddress
ipv4(rec
->getCA());
72 memcpy((void*)&tmp
, &ipv4
.sin4
.sin_addr
.s_addr
, 4);
74 memcpy(((char*)&prefixAddress
.sin6
.sin6_addr
.s6_addr
)+12, &tmp
, 4);
75 rr
.d_content
= std::make_shared
<AAAARecordContent
>(prefixAddress
);
76 rr
.d_type
= QType::AAAA
;
83 static int getFakePTRRecords(const DNSName
& qname
, const std::string
& prefix
, vector
<DNSRecord
>& ret
)
85 /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it
86 and turn it into an IPv4 in-addr.arpa query */
88 vector
<string
> parts
= qname
.getRawLabels();
94 for(int n
= 0; n
< 4; ++n
) {
96 std::to_string(stoll(parts
[n
*2], 0, 16) + 16*stoll(parts
[n
*2+1], 0, 16));
97 newquery
.append(1,'.');
99 newquery
+= "in-addr.arpa.";
102 int rcode
= directResolve(DNSName(newquery
), QType(QType::PTR
), 1, ret
);
103 for(DNSRecord
& rr
: ret
)
105 if(rr
.d_type
== QType::PTR
&& rr
.d_place
==DNSResourceRecord::ANSWER
) {
113 boost::optional
<dnsheader
> RecursorLua4::DNSQuestion::getDH() const
117 return boost::optional
<dnsheader
>();
120 vector
<string
> RecursorLua4::DNSQuestion::getEDNSFlags() const
124 if (*ednsFlags
& EDNSOpts::DNSSECOK
)
130 bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag
) const
133 if (flag
== "DO" && (*ednsFlags
& EDNSOpts::DNSSECOK
))
139 vector
<pair
<uint16_t, string
> > RecursorLua4::DNSQuestion::getEDNSOptions() const
144 return vector
<pair
<uint16_t,string
>>();
147 boost::optional
<string
> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code
) const
150 for(const auto& o
: *ednsOptions
)
154 return boost::optional
<string
>();
157 boost::optional
<Netmask
> RecursorLua4::DNSQuestion::getEDNSSubnet() const
161 for(const auto& o
: *ednsOptions
) {
162 if(o
.first
==EDNSOptionCode::ECS
) {
164 if(getEDNSSubnetOptsFromString(o
.second
, &eso
))
171 return boost::optional
<Netmask
>();
175 vector
<pair
<int, DNSRecord
> > RecursorLua4::DNSQuestion::getRecords() const
177 vector
<pair
<int, DNSRecord
> > ret
;
179 for(const auto& r
: records
) {
180 ret
.push_back({num
++, r
});
184 void RecursorLua4::DNSQuestion::setRecords(const vector
<pair
<int, DNSRecord
> >& recs
)
187 for(const auto& p
: recs
) {
188 records
.push_back(p
.second
);
192 void RecursorLua4::DNSQuestion::addRecord(uint16_t type
, const std::string
& content
, DNSResourceRecord::Place place
, boost::optional
<int> ttl
, boost::optional
<string
> name
)
195 dr
.d_name
=name
? DNSName(*name
) : qname
;
196 dr
.d_ttl
=ttl
.get_value_or(3600);
199 dr
.d_content
= DNSRecordContent::mastermake(type
, 1, content
);
200 records
.push_back(dr
);
203 void RecursorLua4::DNSQuestion::addAnswer(uint16_t type
, const std::string
& content
, boost::optional
<int> ttl
, boost::optional
<string
> name
)
205 addRecord(type
, content
, DNSResourceRecord::ANSWER
, ttl
, name
);
210 std::atomic
<unsigned long>* ptr
;
211 void inc() { (*ptr
)++; }
212 void incBy(unsigned int by
) { (*ptr
)+= by
; }
213 unsigned long get() { return *ptr
; }
214 void set(unsigned long val
) { *ptr
=val
; }
217 RecursorLua4::RecursorLua4(const std::string
& fname
)
219 d_lw
= std::unique_ptr
<LuaContext
>(new LuaContext
);
221 d_lw
->registerFunction
<int(dnsheader::*)()>("getID", [](dnsheader
& dh
) { return dh
.id
; });
222 d_lw
->registerFunction
<bool(dnsheader::*)()>("getCD", [](dnsheader
& dh
) { return dh
.cd
; });
223 d_lw
->registerFunction
<bool(dnsheader::*)()>("getTC", [](dnsheader
& dh
) { return dh
.tc
; });
224 d_lw
->registerFunction
<bool(dnsheader::*)()>("getRA", [](dnsheader
& dh
) { return dh
.ra
; });
225 d_lw
->registerFunction
<bool(dnsheader::*)()>("getAD", [](dnsheader
& dh
) { return dh
.ad
; });
226 d_lw
->registerFunction
<bool(dnsheader::*)()>("getAA", [](dnsheader
& dh
) { return dh
.aa
; });
227 d_lw
->registerFunction
<bool(dnsheader::*)()>("getRD", [](dnsheader
& dh
) { return dh
.rd
; });
228 d_lw
->registerFunction
<int(dnsheader::*)()>("getRCODE", [](dnsheader
& dh
) { return dh
.rcode
; });
229 d_lw
->registerFunction
<int(dnsheader::*)()>("getOPCODE", [](dnsheader
& dh
) { return dh
.opcode
; });
230 d_lw
->registerFunction
<int(dnsheader::*)()>("getQDCOUNT", [](dnsheader
& dh
) { return ntohs(dh
.qdcount
); });
231 d_lw
->registerFunction
<int(dnsheader::*)()>("getANCOUNT", [](dnsheader
& dh
) { return ntohs(dh
.ancount
); });
232 d_lw
->registerFunction
<int(dnsheader::*)()>("getNSCOUNT", [](dnsheader
& dh
) { return ntohs(dh
.nscount
); });
233 d_lw
->registerFunction
<int(dnsheader::*)()>("getARCOUNT", [](dnsheader
& dh
) { return ntohs(dh
.arcount
); });
235 d_lw
->writeFunction("newDN", [](boost::variant
<const std::string
, const DNSName
> dom
){
237 return DNSName(boost::get
<const std::string
>(dom
));
239 return DNSName(boost::get
<const DNSName
>(dom
));
241 d_lw
->registerFunction("isPartOf", &DNSName::isPartOf
);
242 d_lw
->registerFunction
<unsigned int(DNSName::*)()>("countLabels", [](const DNSName
& name
) { return name
.countLabels(); });
243 d_lw
->registerFunction
<size_t(DNSName::*)()>("wirelength", [](const DNSName
& name
) { return name
.wirelength(); });
244 d_lw
->registerFunction
<bool(DNSName::*)(const std::string
&)>(
246 [](const DNSName
& lhs
, const std::string
& rhs
) {
247 return lhs
==DNSName(rhs
);
250 d_lw
->registerFunction("__eq", &DNSName::operator==);
252 d_lw
->registerFunction
<string(ComboAddress::*)()>("toString", [](const ComboAddress
& ca
) { return ca
.toString(); });
253 d_lw
->registerFunction
<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress
& ca
) { return ca
.toStringWithPort(); });
254 d_lw
->registerFunction
<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress
& ca
) { return ntohs(ca
.sin4
.sin_port
); } );
255 d_lw
->registerFunction
<string(ComboAddress::*)()>("getRaw", [](const ComboAddress
& ca
) {
256 if(ca
.sin4
.sin_family
== AF_INET
) {
257 auto t
=ca
.sin4
.sin_addr
.s_addr
; return string((const char*)&t
, 4);
260 return string((const char*)&ca
.sin6
.sin6_addr
.s6_addr
, 16);
262 d_lw
->registerFunction
<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress
& ca
) { return ca
.sin4
.sin_family
== AF_INET
; });
263 d_lw
->registerFunction
<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress
& ca
) { return ca
.sin4
.sin_family
== AF_INET6
; });
264 d_lw
->registerFunction
<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress
& ca
) { return ca
.isMappedIPv4(); });
265 d_lw
->registerFunction
<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress
& ca
) { return ca
.mapToIPv4(); });
266 d_lw
->registerFunction
<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress
& ca
, unsigned int bits
) { ca
.truncate(bits
); });
268 d_lw
->writeFunction("newCA", [](const std::string
& a
) { return ComboAddress(a
); });
269 typedef std::unordered_set
<ComboAddress
,ComboAddress::addressOnlyHash
,ComboAddress::addressOnlyEqual
> cas_t
;
270 d_lw
->writeFunction("newCAS", []{ return cas_t(); });
273 d_lw
->registerFunction
<void(cas_t::*)(boost::variant
<string
,ComboAddress
, vector
<pair
<unsigned int,string
> > >)>(
275 [](cas_t
& cas
, const boost::variant
<string
,ComboAddress
,vector
<pair
<unsigned int,string
> > >& in
)
278 if(auto s
= boost::get
<string
>(&in
)) {
279 cas
.insert(ComboAddress(*s
));
281 else if(auto v
= boost::get
<vector
<pair
<unsigned int, string
> > >(&in
)) {
282 for(const auto&entry
: *v
)
283 cas
.insert(ComboAddress(entry
.second
));
286 cas
.insert(boost::get
<ComboAddress
>(in
));
289 catch(std::exception
& e
) { theL() <<Logger::Error
<<e
.what()<<endl
; }
292 d_lw
->registerFunction
<bool(cas_t::*)(const ComboAddress
&)>("check",[](const cas_t
& cas
, const ComboAddress
&ca
) {
293 return (bool)cas
.count(ca
);
296 d_lw
->registerFunction
<bool(ComboAddress::*)(const ComboAddress
&)>(
298 [](const ComboAddress
& lhs
, const ComboAddress
& rhs
) {
299 return ComboAddress::addressOnlyEqual()(lhs
, rhs
);
303 d_lw
->writeFunction("newNetmask", [](const string
& s
) { return Netmask(s
); });
304 d_lw
->registerFunction
<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask
& nm
) { return nm
.getNetwork(); } ); // const reference makes this necessary
305 d_lw
->registerFunction
<ComboAddress(Netmask::*)()>("getMaskedNetwork", [](const Netmask
& nm
) { return nm
.getMaskedNetwork(); } );
306 d_lw
->registerFunction("isIpv4", &Netmask::isIpv4
);
307 d_lw
->registerFunction("isIpv6", &Netmask::isIpv6
);
308 d_lw
->registerFunction("getBits", &Netmask::getBits
);
309 d_lw
->registerFunction("toString", &Netmask::toString
);
310 d_lw
->registerFunction("empty", &Netmask::empty
);
311 d_lw
->registerFunction("match", (bool (Netmask::*)(const string
&) const)&Netmask::match
);
312 d_lw
->registerFunction("__eq", &Netmask::operator==);
314 d_lw
->writeFunction("newNMG", []() { return NetmaskGroup(); });
315 d_lw
->registerFunction
<void(NetmaskGroup::*)(const std::string
&mask
)>(
316 "addMask", [](NetmaskGroup
&nmg
, const std::string
& mask
){
321 d_lw
->registerFunction
<void(NetmaskGroup::*)(const vector
<pair
<unsigned int, std::string
>>&)>(
323 [](NetmaskGroup
&nmg
, const vector
<pair
<unsigned int, std::string
>>& masks
){
324 for(const auto& mask
: masks
)
325 nmg
.addMask(mask
.second
);
330 d_lw
->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress
&) const)&NetmaskGroup::match
);
331 d_lw
->registerFunction
<string(DNSName::*)()>("toString", [](const DNSName
&dn
) { return dn
.toString(); });
332 d_lw
->registerFunction
<string(DNSName::*)()>("toStringNoDot", [](const DNSName
&dn
) { return dn
.toStringNoDot(); });
333 d_lw
->registerFunction
<bool(DNSName::*)()>("chopOff", [](DNSName
&dn
) { return dn
.chopOff(); });
335 d_lw
->registerMember
<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion
& dq
) -> const DNSName
& { return dq
.qname
; }, [](DNSQuestion
& dq
, const DNSName
& newName
) { (void) newName
; });
336 d_lw
->registerMember
<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion
& dq
) -> uint16_t { return dq
.qtype
; }, [](DNSQuestion
& dq
, uint16_t newType
) { (void) newType
; });
337 d_lw
->registerMember
<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion
& dq
) -> bool { return dq
.isTcp
; }, [](DNSQuestion
& dq
, bool newTcp
) { (void) newTcp
; });
338 d_lw
->registerMember
<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion
& dq
) -> const ComboAddress
& { return dq
.local
; }, [](DNSQuestion
& dq
, const ComboAddress
& newLocal
) { (void) newLocal
; });
339 d_lw
->registerMember
<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion
& dq
) -> const ComboAddress
& { return dq
.remote
; }, [](DNSQuestion
& dq
, const ComboAddress
& newRemote
) { (void) newRemote
; });
341 d_lw
->registerMember
<bool (DNSQuestion::*)>("variable", [](const DNSQuestion
& dq
) -> bool { return dq
.variable
; }, [](DNSQuestion
& dq
, bool newVariable
) { dq
.variable
= newVariable
; });
342 d_lw
->registerMember
<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion
& dq
) -> bool { return dq
.wantsRPZ
; }, [](DNSQuestion
& dq
, bool newWantsRPZ
) { dq
.wantsRPZ
= newWantsRPZ
; });
344 d_lw
->registerMember("rcode", &DNSQuestion::rcode
);
345 d_lw
->registerMember("tag", &DNSQuestion::tag
);
346 d_lw
->registerMember("requestorId", &DNSQuestion::requestorId
);
347 d_lw
->registerMember("followupFunction", &DNSQuestion::followupFunction
);
348 d_lw
->registerMember("followupPrefix", &DNSQuestion::followupPrefix
);
349 d_lw
->registerMember("followupName", &DNSQuestion::followupName
);
350 d_lw
->registerMember("data", &DNSQuestion::data
);
351 d_lw
->registerMember("udpQuery", &DNSQuestion::udpQuery
);
352 d_lw
->registerMember("udpAnswer", &DNSQuestion::udpAnswer
);
353 d_lw
->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest
);
354 d_lw
->registerMember("udpCallback", &DNSQuestion::udpCallback
);
355 d_lw
->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy
);
356 d_lw
->registerMember
<DNSFilterEngine::Policy
, std::string
>("policyName",
357 [](const DNSFilterEngine::Policy
& pol
) -> std::string
{
360 return std::string();
362 [](DNSFilterEngine::Policy
& pol
, const std::string
& name
) {
363 pol
.d_name
= std::make_shared
<std::string
>(name
);
365 d_lw
->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind
);
366 d_lw
->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl
);
367 d_lw
->registerMember
<DNSFilterEngine::Policy
, std::string
>("policyCustom",
368 [](const DNSFilterEngine::Policy
& pol
) -> std::string
{
370 return pol
.d_custom
->getZoneRepresentation();
371 return std::string();
373 [](DNSFilterEngine::Policy
& pol
, const std::string
& content
) {
374 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
375 pol
.d_custom
= DNSRecordContent::mastermake(QType::CNAME
, 1, content
);
378 d_lw
->registerFunction("getDH", &DNSQuestion::getDH
);
379 d_lw
->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions
);
380 d_lw
->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption
);
381 d_lw
->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet
);
382 d_lw
->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags
);
383 d_lw
->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag
);
384 d_lw
->registerMember("name", &DNSRecord::d_name
);
385 d_lw
->registerMember("type", &DNSRecord::d_type
);
386 d_lw
->registerMember("ttl", &DNSRecord::d_ttl
);
387 d_lw
->registerMember("place", &DNSRecord::d_place
);
389 d_lw
->registerMember("size", &EDNSOptionView::size
);
390 d_lw
->registerFunction
<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView
& option
) { return std::string(option
.content
, option
.size
); });
392 d_lw
->registerFunction
<string(DNSRecord::*)()>("getContent", [](const DNSRecord
& dr
) { return dr
.d_content
->getZoneRepresentation(); });
393 d_lw
->registerFunction
<boost::optional
<ComboAddress
>(DNSRecord::*)()>("getCA", [](const DNSRecord
& dr
) {
394 boost::optional
<ComboAddress
> ret
;
396 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(dr
.d_content
))
398 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(dr
.d_content
))
399 ret
=aaaarec
->getCA(53);
404 d_lw
->registerFunction
<void(DNSRecord::*)(const std::string
&)>("changeContent", [](DNSRecord
& dr
, const std::string
& newContent
) { dr
.d_content
= DNSRecordContent::mastermake(dr
.d_type
, 1, newContent
); });
405 d_lw
->registerFunction("addAnswer", &DNSQuestion::addAnswer
);
406 d_lw
->registerFunction("addRecord", &DNSQuestion::addRecord
);
407 d_lw
->registerFunction("getRecords", &DNSQuestion::getRecords
);
408 d_lw
->registerFunction("setRecords", &DNSQuestion::setRecords
);
410 d_lw
->registerFunction
<void(DNSQuestion::*)(const std::string
&)>("addPolicyTag", [](DNSQuestion
& dq
, const std::string
& tag
) { if (dq
.policyTags
) { dq
.policyTags
->push_back(tag
); } });
411 d_lw
->registerFunction
<void(DNSQuestion::*)(const std::vector
<std::pair
<int, std::string
> >&)>("setPolicyTags", [](DNSQuestion
& dq
, const std::vector
<std::pair
<int, std::string
> >& tags
) {
413 dq
.policyTags
->clear();
414 for (const auto& tag
: tags
) {
415 dq
.policyTags
->push_back(tag
.second
);
419 d_lw
->registerFunction
<std::vector
<std::pair
<int, std::string
> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion
& dq
) {
420 std::vector
<std::pair
<int, std::string
> > ret
;
423 for (const auto& tag
: *dq
.policyTags
) {
424 ret
.push_back({count
++, tag
});
430 d_lw
->registerFunction
<void(DNSQuestion::*)(const std::string
&)>("discardPolicy", [](DNSQuestion
& dq
, const std::string
& policy
) {
431 if (dq
.discardedPolicies
) {
432 (*dq
.discardedPolicies
)[policy
] = true;
436 d_lw
->writeFunction("newDS", []() { return SuffixMatchNode(); });
437 d_lw
->registerFunction
<void(SuffixMatchNode::*)(boost::variant
<string
,DNSName
, vector
<pair
<unsigned int,string
> > >)>(
439 [](SuffixMatchNode
&smn
, const boost::variant
<string
,DNSName
,vector
<pair
<unsigned int,string
> > >& in
){
441 if(auto s
= boost::get
<string
>(&in
)) {
442 smn
.add(DNSName(*s
));
444 else if(auto v
= boost::get
<vector
<pair
<unsigned int, string
> > >(&in
)) {
445 for(const auto& entry
: *v
)
446 smn
.add(DNSName(entry
.second
));
449 smn
.add(boost::get
<DNSName
>(in
));
452 catch(std::exception
& e
) {
453 theL() <<Logger::Error
<<e
.what()<<endl
;
458 d_lw
->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName
&) const) &SuffixMatchNode::check
);
459 d_lw
->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString
);
462 d_lw
->writeFunction("pdnslog", [](const std::string
& msg
, boost::optional
<int> loglevel
) {
463 theL() << (Logger::Urgency
)loglevel
.get_value_or(Logger::Warning
) << msg
<<endl
;
465 typedef vector
<pair
<string
, int> > in_t
;
466 vector
<pair
<string
, boost::variant
<int, in_t
, struct timeval
* > > > pd
{
467 {"PASS", (int)PolicyDecision::PASS
}, {"DROP", (int)PolicyDecision::DROP
},
468 {"TRUNCATE", (int)PolicyDecision::TRUNCATE
}
471 vector
<pair
<string
, int> > rcodes
= {{"NOERROR", RCode::NoError
},
472 {"FORMERR", RCode::FormErr
},
473 {"SERVFAIL", RCode::ServFail
},
474 {"NXDOMAIN", RCode::NXDomain
},
475 {"NOTIMP", RCode::NotImp
},
476 {"REFUSED", RCode::Refused
},
477 {"YXDOMAIN", RCode::YXDomain
},
478 {"YXRRSET", RCode::YXRRSet
},
479 {"NXRRSET", RCode::NXRRSet
},
480 {"NOTAUTH", RCode::NotAuth
},
481 {"NOTZONE", RCode::NotZone
}};
482 for(const auto& rcode
: rcodes
)
483 pd
.push_back({rcode
.first
, rcode
.second
});
485 pd
.push_back({"loglevels", in_t
{
486 {"Alert", LOG_ALERT
},
487 {"Critical", LOG_CRIT
},
488 {"Debug", LOG_DEBUG
},
489 {"Emergency", LOG_EMERG
},
491 {"Notice", LOG_NOTICE
},
492 {"Warning", LOG_WARNING
},
496 pd
.push_back({"policykinds", in_t
{
497 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction
},
498 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop
},
499 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN
},
500 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA
},
501 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate
},
502 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom
}
505 for(const auto& n
: QType::names
)
506 pd
.push_back({n
.first
, n
.second
});
507 pd
.push_back({"now", &g_now
});
508 d_lw
->registerMember("tv_sec", &timeval::tv_sec
);
509 d_lw
->registerMember("tv_usec", &timeval::tv_usec
);
511 d_lw
->writeVariable("pdns", pd
);
513 d_lw
->writeFunction("getMetric", [](const std::string
& str
) {
514 return DynMetric
{getDynMetric(str
)};
517 d_lw
->registerFunction("inc", &DynMetric::inc
);
518 d_lw
->registerFunction("incBy", &DynMetric::incBy
);
519 d_lw
->registerFunction("set", &DynMetric::set
);
520 d_lw
->registerFunction("get", &DynMetric::get
);
522 d_lw
->writeFunction("getStat", [](const std::string
& str
) {
524 optional
<uint64_t> value
= getStatByName(str
);
531 d_lw
->writeFunction("getRecursorThreadId", []() {
532 return getRecursorThreadId();
535 d_lw
->writeFunction("sendCustomSNMPTrap", [](const std::string
& str
) {
537 g_snmpAgent
->sendCustomTrap(str
);
543 throw std::runtime_error("Unable to read configuration file from '"+fname
+"': "+strerror(errno
));
545 d_lw
->executeCode(ifs
);
547 d_prerpz
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("prerpz").get_value_or(0);
548 d_preresolve
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("preresolve").get_value_or(0);
549 d_nodata
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("nodata").get_value_or(0);
550 d_nxdomain
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("nxdomain").get_value_or(0);
551 d_postresolve
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("postresolve").get_value_or(0);
552 d_preoutquery
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("preoutquery").get_value_or(0);
554 d_ipfilter
= d_lw
->readVariable
<boost::optional
<ipfilter_t
>>("ipfilter").get_value_or(0);
555 d_gettag
= d_lw
->readVariable
<boost::optional
<gettag_t
>>("gettag").get_value_or(0);
558 bool RecursorLua4::prerpz(DNSQuestion
& dq
, int& ret
)
560 return genhook(d_prerpz
, dq
, ret
);
563 bool RecursorLua4::preresolve(DNSQuestion
& dq
, int& ret
)
565 return genhook(d_preresolve
, dq
, ret
);
568 bool RecursorLua4::nxdomain(DNSQuestion
& dq
, int& ret
)
570 return genhook(d_nxdomain
, dq
, ret
);
573 bool RecursorLua4::nodata(DNSQuestion
& dq
, int& ret
)
575 return genhook(d_nodata
, dq
, ret
);
578 bool RecursorLua4::postresolve(DNSQuestion
& dq
, int& ret
)
580 return genhook(d_postresolve
, dq
, ret
);
583 bool RecursorLua4::preoutquery(const ComboAddress
& ns
, const ComboAddress
& requestor
, const DNSName
& query
, const QType
& qtype
, bool isTcp
, vector
<DNSRecord
>& res
, int& ret
)
585 bool variableAnswer
= false;
586 bool wantsRPZ
= false;
587 RecursorLua4::DNSQuestion
dq(ns
, requestor
, query
, qtype
.getCode(), isTcp
, variableAnswer
, wantsRPZ
);
588 dq
.currentRecords
= &res
;
590 return genhook(d_preoutquery
, dq
, ret
);
593 bool RecursorLua4::ipfilter(const ComboAddress
& remote
, const ComboAddress
& local
, const struct dnsheader
& dh
)
596 return d_ipfilter(remote
, local
, dh
);
597 return false; // don't block
600 unsigned int RecursorLua4::gettag(const ComboAddress
& remote
, const Netmask
& ednssubnet
, const ComboAddress
& local
, const DNSName
& qname
, uint16_t qtype
, std::vector
<std::string
>* policyTags
, LuaContext::LuaObject
& data
, const std::map
<uint16_t, EDNSOptionView
>& ednsOptions
, bool tcp
, std::string
& requestorId
)
603 auto ret
= d_gettag(remote
, ednssubnet
, local
, qname
, qtype
, ednsOptions
, tcp
);
606 const auto& tags
= std::get
<1>(ret
);
608 for (const auto& tag
: *tags
) {
609 policyTags
->push_back(tag
.second
);
613 const auto dataret
= std::get
<2>(ret
);
617 const auto reqIdret
= std::get
<3>(ret
);
619 requestorId
= *reqIdret
;
621 return std::get
<0>(ret
);
626 bool RecursorLua4::genhook(luacall_t
& func
, DNSQuestion
& dq
, int& ret
)
631 if (dq
.currentRecords
) {
632 dq
.records
= *dq
.currentRecords
;
637 dq
.followupFunction
.clear();
638 dq
.followupPrefix
.clear();
639 dq
.followupName
.clear();
641 dq
.udpAnswer
.clear();
642 dq
.udpCallback
.clear();
645 bool handled
=func(&dq
);
651 if(!dq
.followupFunction
.empty()) {
652 if(dq
.followupFunction
=="followCNAMERecords") {
653 ret
= followCNAMERecords(dq
.records
, QType(dq
.qtype
));
655 else if(dq
.followupFunction
=="getFakeAAAARecords") {
656 ret
=getFakeAAAARecords(dq
.followupName
, dq
.followupPrefix
, dq
.records
);
658 else if(dq
.followupFunction
=="getFakePTRRecords") {
659 ret
=getFakePTRRecords(dq
.followupName
, dq
.followupPrefix
, dq
.records
);
661 else if(dq
.followupFunction
=="udpQueryResponse") {
662 dq
.udpAnswer
= GenUDPQueryResponse(dq
.udpQueryDest
, dq
.udpQuery
);
663 auto cbFunc
= d_lw
->readVariable
<boost::optional
<luacall_t
>>(dq
.udpCallback
).get_value_or(0);
665 theL()<<Logger::Error
<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl
;
668 bool result
=cbFunc(&dq
);
675 if (dq
.currentRecords
) {
676 *dq
.currentRecords
= dq
.records
;
680 // see if they added followup work for us too
684 RecursorLua4::~RecursorLua4(){}