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 RecursorLua4::RecursorLua4() { prepareContext(); }
37 boost::optional
<dnsheader
> RecursorLua4::DNSQuestion::getDH() const
41 return boost::optional
<dnsheader
>();
44 vector
<string
> RecursorLua4::DNSQuestion::getEDNSFlags() const
48 if (*ednsFlags
& EDNSOpts::DNSSECOK
)
54 bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag
) const
57 if (flag
== "DO" && (*ednsFlags
& EDNSOpts::DNSSECOK
))
63 vector
<pair
<uint16_t, string
> > RecursorLua4::DNSQuestion::getEDNSOptions() const
68 return vector
<pair
<uint16_t,string
>>();
71 boost::optional
<string
> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code
) const
74 for(const auto& o
: *ednsOptions
)
78 return boost::optional
<string
>();
81 boost::optional
<Netmask
> RecursorLua4::DNSQuestion::getEDNSSubnet() const
84 for(const auto& o
: *ednsOptions
) {
85 if(o
.first
==EDNSOptionCode::ECS
) {
87 if(getEDNSSubnetOptsFromString(o
.second
, &eso
))
94 return boost::optional
<Netmask
>();
97 std::vector
<std::pair
<int, ProxyProtocolValue
>> RecursorLua4::DNSQuestion::getProxyProtocolValues() const
99 std::vector
<std::pair
<int, ProxyProtocolValue
>> result
;
100 if (proxyProtocolValues
) {
101 result
.reserve(proxyProtocolValues
->size());
104 for (const auto& value
: *proxyProtocolValues
) {
105 result
.push_back({ idx
++, value
});
112 vector
<pair
<int, DNSRecord
> > RecursorLua4::DNSQuestion::getRecords() const
114 vector
<pair
<int, DNSRecord
> > ret
;
116 for(const auto& r
: records
) {
117 ret
.push_back({num
++, r
});
121 void RecursorLua4::DNSQuestion::setRecords(const vector
<pair
<int, DNSRecord
> >& recs
)
124 for(const auto& p
: recs
) {
125 records
.push_back(p
.second
);
129 void RecursorLua4::DNSQuestion::addRecord(uint16_t type
, const std::string
& content
, DNSResourceRecord::Place place
, boost::optional
<int> ttl
, boost::optional
<string
> name
)
132 dr
.d_name
=name
? DNSName(*name
) : qname
;
133 dr
.d_ttl
=ttl
.get_value_or(3600);
136 dr
.d_content
= DNSRecordContent::mastermake(type
, QClass::IN
, content
);
137 records
.push_back(dr
);
140 void RecursorLua4::DNSQuestion::addAnswer(uint16_t type
, const std::string
& content
, boost::optional
<int> ttl
, boost::optional
<string
> name
)
142 addRecord(type
, content
, DNSResourceRecord::ANSWER
, ttl
, name
);
147 std::atomic
<unsigned long>* ptr
;
148 void inc() { (*ptr
)++; }
149 void incBy(unsigned int by
) { (*ptr
)+= by
; }
150 unsigned long get() { return *ptr
; }
151 void set(unsigned long val
) { *ptr
=val
; }
154 void RecursorLua4::postPrepareContext()
156 d_lw
->registerMember
<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion
& dq
) -> const DNSName
& { return dq
.qname
; }, [](DNSQuestion
& dq
, const DNSName
& newName
) { (void) newName
; });
157 d_lw
->registerMember
<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion
& dq
) -> uint16_t { return dq
.qtype
; }, [](DNSQuestion
& dq
, uint16_t newType
) { (void) newType
; });
158 d_lw
->registerMember
<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion
& dq
) -> bool { return dq
.isTcp
; }, [](DNSQuestion
& dq
, bool newTcp
) { (void) newTcp
; });
159 d_lw
->registerMember
<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion
& dq
) -> const ComboAddress
& { return dq
.local
; }, [](DNSQuestion
& dq
, const ComboAddress
& newLocal
) { (void) newLocal
; });
160 d_lw
->registerMember
<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion
& dq
) -> const ComboAddress
& { return dq
.remote
; }, [](DNSQuestion
& dq
, const ComboAddress
& newRemote
) { (void) newRemote
; });
161 d_lw
->registerMember
<uint8_t (DNSQuestion::*)>("validationState", [](const DNSQuestion
& dq
) -> uint8_t { return (vStateIsBogus(dq
.validationState
) ? /* in order not to break older scripts */ static_cast<uint8_t>(255) : static_cast<uint8_t>(dq
.validationState
)); }, [](DNSQuestion
& dq
, uint8_t newState
) { (void) newState
; });
162 d_lw
->registerMember
<vState (DNSQuestion::*)>("detailedValidationState", [](const DNSQuestion
& dq
) -> vState
{ return dq
.validationState
; }, [](DNSQuestion
& dq
, vState newState
) { (void) newState
; });
164 d_lw
->registerMember
<bool (DNSQuestion::*)>("variable", [](const DNSQuestion
& dq
) -> bool { return dq
.variable
; }, [](DNSQuestion
& dq
, bool newVariable
) { dq
.variable
= newVariable
; });
165 d_lw
->registerMember
<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion
& dq
) -> bool { return dq
.wantsRPZ
; }, [](DNSQuestion
& dq
, bool newWantsRPZ
) { dq
.wantsRPZ
= newWantsRPZ
; });
166 d_lw
->registerMember
<bool (DNSQuestion::*)>("logResponse", [](const DNSQuestion
& dq
) -> bool { return dq
.logResponse
; }, [](DNSQuestion
& dq
, bool newLogResponse
) { dq
.logResponse
= newLogResponse
; });
167 d_lw
->registerMember
<bool (DNSQuestion::*)>("addPaddingToResponse", [](const DNSQuestion
& dq
) -> bool { return dq
.addPaddingToResponse
; }, [](DNSQuestion
& dq
, bool add
) { dq
.addPaddingToResponse
= add
; });
169 d_lw
->registerMember("rcode", &DNSQuestion::rcode
);
170 d_lw
->registerMember("tag", &DNSQuestion::tag
);
171 d_lw
->registerMember("requestorId", &DNSQuestion::requestorId
);
172 d_lw
->registerMember("deviceId", &DNSQuestion::deviceId
);
173 d_lw
->registerMember("deviceName", &DNSQuestion::deviceName
);
174 d_lw
->registerMember("followupFunction", &DNSQuestion::followupFunction
);
175 d_lw
->registerMember("followupPrefix", &DNSQuestion::followupPrefix
);
176 d_lw
->registerMember("followupName", &DNSQuestion::followupName
);
177 d_lw
->registerMember("data", &DNSQuestion::data
);
178 d_lw
->registerMember
<uint16_t (DNSQuestion::*)>("extendedErrorCode", [](const DNSQuestion
& dq
) -> uint16_t {
179 if (dq
.extendedErrorCode
&& *dq
.extendedErrorCode
) {
180 return *(*dq
.extendedErrorCode
);
184 [](DNSQuestion
& dq
, uint16_t newCode
) {
185 if (dq
.extendedErrorCode
) {
186 *dq
.extendedErrorCode
= newCode
;
189 d_lw
->registerMember
<std::string (DNSQuestion::*)>("extendedErrorExtra", [](const DNSQuestion
& dq
) -> std::string
{
190 if (dq
.extendedErrorExtra
) {
191 return *dq
.extendedErrorExtra
;
195 [](DNSQuestion
& dq
, const std::string
& newExtra
) {
196 if (dq
.extendedErrorExtra
) {
197 *dq
.extendedErrorExtra
= newExtra
;
200 d_lw
->registerMember("udpQuery", &DNSQuestion::udpQuery
);
201 d_lw
->registerMember("udpAnswer", &DNSQuestion::udpAnswer
);
202 d_lw
->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest
);
203 d_lw
->registerMember("udpCallback", &DNSQuestion::udpCallback
);
204 d_lw
->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy
);
206 d_lw
->registerMember
<DNSFilterEngine::Policy
, std::string
>("policyName",
207 [](const DNSFilterEngine::Policy
& pol
) -> std::string
{
208 return pol
.getName();
210 [](DNSFilterEngine::Policy
& pol
, const std::string
& name
) {
213 d_lw
->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind
);
214 d_lw
->registerMember("policyType", &DNSFilterEngine::Policy::d_type
);
215 d_lw
->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl
);
216 d_lw
->registerMember("policyTrigger", &DNSFilterEngine::Policy::d_trigger
);
217 d_lw
->registerMember("policyHit", &DNSFilterEngine::Policy::d_hit
);
218 d_lw
->registerMember
<DNSFilterEngine::Policy
, std::string
>("policyCustom",
219 [](const DNSFilterEngine::Policy
& pol
) -> std::string
{
221 if (pol
.d_kind
!= DNSFilterEngine::PolicyKind::Custom
) {
225 for (const auto& dr
: pol
.d_custom
) {
226 if (!result
.empty()) {
229 result
+= dr
->getZoneRepresentation();
234 [](DNSFilterEngine::Policy
& pol
, const std::string
& content
) {
235 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
236 pol
.d_custom
.clear();
237 pol
.d_custom
.push_back(DNSRecordContent::mastermake(QType::CNAME
, QClass::IN
, content
));
240 d_lw
->registerFunction("getDH", &DNSQuestion::getDH
);
241 d_lw
->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions
);
242 d_lw
->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption
);
243 d_lw
->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet
);
244 d_lw
->registerFunction("getProxyProtocolValues", &DNSQuestion::getProxyProtocolValues
);
245 d_lw
->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags
);
246 d_lw
->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag
);
248 d_lw
->registerMember("name", &DNSRecord::d_name
);
249 d_lw
->registerMember("type", &DNSRecord::d_type
);
250 d_lw
->registerMember("ttl", &DNSRecord::d_ttl
);
251 d_lw
->registerMember("place", &DNSRecord::d_place
);
253 d_lw
->registerMember("size", &EDNSOptionViewValue::size
);
254 d_lw
->registerFunction
<std::string(EDNSOptionViewValue::*)()>("getContent", [](const EDNSOptionViewValue
& value
) { return std::string(value
.content
, value
.size
); });
255 d_lw
->registerFunction
<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView
& option
) { return option
.values
.size(); });
256 d_lw
->registerFunction
<std::vector
<string
>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView
& option
) {
257 std::vector
<string
> values
;
258 for (const auto& value
: option
.values
) {
259 values
.push_back(std::string(value
.content
, value
.size
));
264 /* pre 4.2 API compatibility, when we had only one value for a given EDNS option */
265 d_lw
->registerMember
<uint16_t(EDNSOptionView::*)>("size", [](const EDNSOptionView
& option
) -> uint16_t {
268 if (!option
.values
.empty()) {
269 result
= option
.values
.at(0).size
;
273 [](EDNSOptionView
& option
, uint16_t newSize
) { (void) newSize
; });
274 d_lw
->registerFunction
<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView
& option
) {
275 if (option
.values
.empty()) {
276 return std::string();
278 return std::string(option
.values
.at(0).content
, option
.values
.at(0).size
); });
280 d_lw
->registerFunction
<string(DNSRecord::*)()>("getContent", [](const DNSRecord
& dr
) { return dr
.d_content
->getZoneRepresentation(); });
281 d_lw
->registerFunction
<boost::optional
<ComboAddress
>(DNSRecord::*)()>("getCA", [](const DNSRecord
& dr
) {
282 boost::optional
<ComboAddress
> ret
;
284 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(dr
.d_content
))
286 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(dr
.d_content
))
287 ret
=aaaarec
->getCA(53);
291 d_lw
->registerFunction
<const ProxyProtocolValue
, std::string()>("getContent", [](const ProxyProtocolValue
& value
) { return value
.content
; });
292 d_lw
->registerFunction
<const ProxyProtocolValue
, uint8_t()>("getType", [](const ProxyProtocolValue
& value
) { return value
.type
; });
294 d_lw
->registerFunction
<void(DNSRecord::*)(const std::string
&)>("changeContent", [](DNSRecord
& dr
, const std::string
& newContent
) { dr
.d_content
= DNSRecordContent::mastermake(dr
.d_type
, QClass::IN
, newContent
); });
295 d_lw
->registerFunction("addAnswer", &DNSQuestion::addAnswer
);
296 d_lw
->registerFunction("addRecord", &DNSQuestion::addRecord
);
297 d_lw
->registerFunction("getRecords", &DNSQuestion::getRecords
);
298 d_lw
->registerFunction("setRecords", &DNSQuestion::setRecords
);
300 d_lw
->registerFunction
<void(DNSQuestion::*)(const std::string
&)>("addPolicyTag", [](DNSQuestion
& dq
, const std::string
& tag
) { if (dq
.policyTags
) { dq
.policyTags
->insert(tag
); } });
301 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
) {
303 dq
.policyTags
->clear();
304 dq
.policyTags
->reserve(tags
.size());
305 for (const auto& tag
: tags
) {
306 dq
.policyTags
->insert(tag
.second
);
310 d_lw
->registerFunction
<std::vector
<std::pair
<int, std::string
> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion
& dq
) {
311 std::vector
<std::pair
<int, std::string
> > ret
;
314 ret
.reserve(dq
.policyTags
->size());
315 for (const auto& tag
: *dq
.policyTags
) {
316 ret
.push_back({count
++, tag
});
322 d_lw
->registerFunction
<void(DNSQuestion::*)(const std::string
&)>("discardPolicy", [](DNSQuestion
& dq
, const std::string
& policy
) {
323 if (dq
.discardedPolicies
) {
324 (*dq
.discardedPolicies
)[policy
] = true;
328 d_lw
->writeFunction("newDS", []() { return SuffixMatchNode(); });
329 d_lw
->registerFunction
<void(SuffixMatchNode::*)(boost::variant
<string
,DNSName
, vector
<pair
<unsigned int,string
> > >)>(
331 [](SuffixMatchNode
&smn
, const boost::variant
<string
,DNSName
,vector
<pair
<unsigned int,string
> > >& in
){
333 if(auto s
= boost::get
<string
>(&in
)) {
334 smn
.add(DNSName(*s
));
336 else if(auto v
= boost::get
<vector
<pair
<unsigned int, string
> > >(&in
)) {
337 for(const auto& entry
: *v
)
338 smn
.add(DNSName(entry
.second
));
341 smn
.add(boost::get
<DNSName
>(in
));
344 catch(std::exception
& e
) {
345 g_log
<<Logger::Error
<<e
.what()<<endl
;
350 d_lw
->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName
&) const) &SuffixMatchNode::check
);
351 d_lw
->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString
);
353 d_pd
.push_back({"policykinds", in_t
{
354 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction
},
355 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop
},
356 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN
},
357 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA
},
358 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate
},
359 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom
}
362 d_pd
.push_back({"policytypes", in_t
{
363 {"None", (int)DNSFilterEngine::PolicyType::None
},
364 {"QName", (int)DNSFilterEngine::PolicyType::QName
},
365 {"ClientIP", (int)DNSFilterEngine::PolicyType::ClientIP
},
366 {"ResponseIP", (int)DNSFilterEngine::PolicyType::ResponseIP
},
367 {"NSDName", (int)DNSFilterEngine::PolicyType::NSDName
},
368 {"NSIP", (int)DNSFilterEngine::PolicyType::NSIP
}
371 for(const auto& n
: QType::names
)
372 d_pd
.push_back({n
.first
, n
.second
});
374 d_pd
.push_back({"validationstates", in_t
{
375 {"Indeterminate", static_cast<unsigned int>(vState::Indeterminate
) },
376 {"BogusNoValidDNSKEY", static_cast<unsigned int>(vState::BogusNoValidDNSKEY
) },
377 {"BogusInvalidDenial", static_cast<unsigned int>(vState::BogusInvalidDenial
) },
378 {"BogusUnableToGetDSs", static_cast<unsigned int>(vState::BogusUnableToGetDSs
) },
379 {"BogusUnableToGetDNSKEYs", static_cast<unsigned int>(vState::BogusUnableToGetDNSKEYs
) },
380 {"BogusSelfSignedDS", static_cast<unsigned int>(vState::BogusSelfSignedDS
) },
381 {"BogusNoRRSIG", static_cast<unsigned int>(vState::BogusNoRRSIG
) },
382 {"BogusNoValidRRSIG", static_cast<unsigned int>(vState::BogusNoValidRRSIG
) },
383 {"BogusMissingNegativeIndication", static_cast<unsigned int>(vState::BogusMissingNegativeIndication
) },
384 {"BogusSignatureNotYetValid", static_cast<unsigned int>(vState::BogusSignatureNotYetValid
)},
385 {"BogusSignatureExpired", static_cast<unsigned int>(vState::BogusSignatureExpired
)},
386 {"BogusUnsupportedDNSKEYAlgo", static_cast<unsigned int>(vState::BogusUnsupportedDNSKEYAlgo
)},
387 {"BogusUnsupportedDSDigestType", static_cast<unsigned int>(vState::BogusUnsupportedDSDigestType
)},
388 {"BogusNoZoneKeyBitSet", static_cast<unsigned int>(vState::BogusNoZoneKeyBitSet
)},
389 {"BogusRevokedDNSKEY", static_cast<unsigned int>(vState::BogusRevokedDNSKEY
)},
390 {"BogusInvalidDNSKEYProtocol", static_cast<unsigned int>(vState::BogusInvalidDNSKEYProtocol
)},
391 {"Insecure", static_cast<unsigned int>(vState::Insecure
) },
392 {"Secure", static_cast<unsigned int>(vState::Secure
) },
393 /* in order not to break compatibility with older scripts: */
394 {"Bogus", static_cast<unsigned int>(255) },
397 d_lw
->writeFunction("isValidationStateBogus", [](vState state
) {
398 return vStateIsBogus(state
);
401 d_pd
.push_back({"now", &g_now
});
403 d_lw
->writeFunction("getMetric", [](const std::string
& str
, boost::optional
<std::string
> prometheusName
) {
404 return DynMetric
{getDynMetric(str
, prometheusName
? *prometheusName
: "")};
407 d_lw
->registerFunction("inc", &DynMetric::inc
);
408 d_lw
->registerFunction("incBy", &DynMetric::incBy
);
409 d_lw
->registerFunction("set", &DynMetric::set
);
410 d_lw
->registerFunction("get", &DynMetric::get
);
412 d_lw
->writeFunction("getStat", [](const std::string
& str
) {
414 boost::optional
<uint64_t> value
= getStatByName(str
);
421 d_lw
->writeFunction("getRecursorThreadId", []() {
422 return getRecursorThreadId();
425 d_lw
->writeFunction("sendCustomSNMPTrap", [](const std::string
& str
) {
427 g_snmpAgent
->sendCustomTrap(str
);
431 d_lw
->writeFunction("getregisteredname", [](const DNSName
&dname
) {
432 return getRegisteredName(dname
);
435 d_lw
->registerMember
<const DNSName (PolicyEvent::*)>("qname", [](const PolicyEvent
& event
) -> const DNSName
& { return event
.qname
; }, [](PolicyEvent
& event
, const DNSName
& newName
) { (void) newName
; });
436 d_lw
->registerMember
<uint16_t (PolicyEvent::*)>("qtype", [](const PolicyEvent
& event
) -> uint16_t { return event
.qtype
.getCode(); }, [](PolicyEvent
& event
, uint16_t newType
) { (void) newType
; });
437 d_lw
->registerMember
<bool (PolicyEvent::*)>("isTcp", [](const PolicyEvent
& event
) -> bool { return event
.isTcp
; }, [](PolicyEvent
& event
, bool newTcp
) { (void) newTcp
; });
438 d_lw
->registerMember
<const ComboAddress (PolicyEvent::*)>("remote", [](const PolicyEvent
& event
) -> const ComboAddress
& { return event
.remote
; }, [](PolicyEvent
& event
, const ComboAddress
& newRemote
) { (void) newRemote
; });
439 d_lw
->registerMember("appliedPolicy", &PolicyEvent::appliedPolicy
);
440 d_lw
->registerFunction
<void(PolicyEvent::*)(const std::string
&)>("addPolicyTag", [](PolicyEvent
& event
, const std::string
& tag
) { if (event
.policyTags
) { event
.policyTags
->insert(tag
); } });
441 d_lw
->registerFunction
<void(PolicyEvent::*)(const std::vector
<std::pair
<int, std::string
> >&)>("setPolicyTags", [](PolicyEvent
& event
, const std::vector
<std::pair
<int, std::string
> >& tags
) {
442 if (event
.policyTags
) {
443 event
.policyTags
->clear();
444 event
.policyTags
->reserve(tags
.size());
445 for (const auto& tag
: tags
) {
446 event
.policyTags
->insert(tag
.second
);
450 d_lw
->registerFunction
<std::vector
<std::pair
<int, std::string
> >(PolicyEvent::*)()>("getPolicyTags", [](const PolicyEvent
& event
) {
451 std::vector
<std::pair
<int, std::string
> > ret
;
452 if (event
.policyTags
) {
454 ret
.reserve(event
.policyTags
->size());
455 for (const auto& tag
: *event
.policyTags
) {
456 ret
.push_back({count
++, tag
});
461 d_lw
->registerFunction
<void(PolicyEvent::*)(const std::string
&)>("discardPolicy", [](PolicyEvent
& event
, const std::string
& policy
) {
462 if (event
.discardedPolicies
) {
463 (*event
.discardedPolicies
)[policy
] = true;
468 void RecursorLua4::postLoad() {
469 d_prerpz
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("prerpz").get_value_or(0);
470 d_preresolve
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("preresolve").get_value_or(0);
471 d_nodata
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("nodata").get_value_or(0);
472 d_nxdomain
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("nxdomain").get_value_or(0);
473 d_postresolve
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("postresolve").get_value_or(0);
474 d_preoutquery
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("preoutquery").get_value_or(0);
475 d_maintenance
= d_lw
->readVariable
<boost::optional
<luamaintenance_t
>>("maintenance").get_value_or(0);
477 d_ipfilter
= d_lw
->readVariable
<boost::optional
<ipfilter_t
>>("ipfilter").get_value_or(0);
478 d_gettag
= d_lw
->readVariable
<boost::optional
<gettag_t
>>("gettag").get_value_or(0);
479 d_gettag_ffi
= d_lw
->readVariable
<boost::optional
<gettag_ffi_t
>>("gettag_ffi").get_value_or(0);
481 d_policyHitEventFilter
= d_lw
->readVariable
<boost::optional
<policyEventFilter_t
>>("policyEventFilter").get_value_or(0);
484 void RecursorLua4::getFeatures(Features
& features
) {
485 // Add key-values pairs below.
486 // Make sure you add string values explicitly converted to string.
487 // e.g. features.push_back(make_pair("somekey", string("stringvalue"));
488 // Both int and double end up as a lua number type.
489 features
.push_back(make_pair("PR8001_devicename", true));
492 void RecursorLua4::maintenance() const
499 bool RecursorLua4::prerpz(DNSQuestion
& dq
, int& ret
) const
501 return genhook(d_prerpz
, dq
, ret
);
504 bool RecursorLua4::preresolve(DNSQuestion
& dq
, int& ret
) const
506 return genhook(d_preresolve
, dq
, ret
);
509 bool RecursorLua4::nxdomain(DNSQuestion
& dq
, int& ret
) const
511 return genhook(d_nxdomain
, dq
, ret
);
514 bool RecursorLua4::nodata(DNSQuestion
& dq
, int& ret
) const
516 return genhook(d_nodata
, dq
, ret
);
519 bool RecursorLua4::postresolve(DNSQuestion
& dq
, int& ret
) const
521 return genhook(d_postresolve
, dq
, ret
);
524 bool RecursorLua4::preoutquery(const ComboAddress
& ns
, const ComboAddress
& requestor
, const DNSName
& query
, const QType
& qtype
, bool isTcp
, vector
<DNSRecord
>& res
, int& ret
) const
526 bool variableAnswer
= false;
527 bool wantsRPZ
= false;
528 bool logQuery
= false;
529 bool addPaddingToResponse
= false;
530 RecursorLua4::DNSQuestion
dq(ns
, requestor
, query
, qtype
.getCode(), isTcp
, variableAnswer
, wantsRPZ
, logQuery
, addPaddingToResponse
);
531 dq
.currentRecords
= &res
;
533 return genhook(d_preoutquery
, dq
, ret
);
536 bool RecursorLua4::ipfilter(const ComboAddress
& remote
, const ComboAddress
& local
, const struct dnsheader
& dh
) const
539 return d_ipfilter(remote
, local
, dh
);
540 return false; // don't block
543 bool RecursorLua4::policyHitEventFilter(const ComboAddress
& remote
, const DNSName
& qname
, const QType
& qtype
, bool tcp
, DNSFilterEngine::Policy
& policy
, std::unordered_set
<std::string
>& tags
, std::unordered_map
<std::string
, bool>& discardedPolicies
) const
545 if (!d_policyHitEventFilter
) {
549 PolicyEvent
event(remote
, qname
, qtype
, tcp
);
550 event
.appliedPolicy
= &policy
;
551 event
.policyTags
= &tags
;
552 event
.discardedPolicies
= &discardedPolicies
;
554 if (d_policyHitEventFilter(event
)) {
562 unsigned int RecursorLua4::gettag(const ComboAddress
& remote
, const Netmask
& ednssubnet
, const ComboAddress
& local
, const DNSName
& qname
, uint16_t qtype
, std::unordered_set
<std::string
>* policyTags
, LuaContext::LuaObject
& data
, const EDNSOptionViewMap
& ednsOptions
, bool tcp
, std::string
& requestorId
, std::string
& deviceId
, std::string
& deviceName
, std::string
& routingTag
, const std::vector
<ProxyProtocolValue
>& proxyProtocolValues
) const
565 std::vector
<std::pair
<int, const ProxyProtocolValue
*>> proxyProtocolValuesMap
;
566 proxyProtocolValuesMap
.reserve(proxyProtocolValues
.size());
568 for (const auto& value
: proxyProtocolValues
) {
569 proxyProtocolValuesMap
.emplace_back(num
++, &value
);
572 auto ret
= d_gettag(remote
, ednssubnet
, local
, qname
, qtype
, ednsOptions
, tcp
, proxyProtocolValuesMap
);
575 const auto& tags
= std::get
<1>(ret
);
577 policyTags
->reserve(policyTags
->size() + tags
->size());
578 for (const auto& tag
: *tags
) {
579 policyTags
->insert(tag
.second
);
583 const auto dataret
= std::get
<2>(ret
);
587 const auto reqIdret
= std::get
<3>(ret
);
589 requestorId
= *reqIdret
;
591 const auto deviceIdret
= std::get
<4>(ret
);
593 deviceId
= *deviceIdret
;
596 const auto deviceNameret
= std::get
<5>(ret
);
598 deviceName
= *deviceNameret
;
601 const auto routingTarget
= std::get
<6>(ret
);
603 routingTag
= *routingTarget
;
606 return std::get
<0>(ret
);
611 struct pdns_ffi_param
614 pdns_ffi_param(RecursorLua4::FFIParams
& params_
): params(params_
)
618 RecursorLua4::FFIParams
& params
;
619 std::unique_ptr
<std::string
> qnameStr
{nullptr};
620 std::unique_ptr
<std::string
> localStr
{nullptr};
621 std::unique_ptr
<std::string
> remoteStr
{nullptr};
622 std::unique_ptr
<std::string
> ednssubnetStr
{nullptr};
623 std::vector
<pdns_ednsoption_t
> ednsOptionsVect
;
624 std::vector
<pdns_proxyprotocol_value_t
> proxyProtocolValuesVect
;
627 unsigned int RecursorLua4::gettag_ffi(RecursorLua4::FFIParams
& params
) const
630 pdns_ffi_param_t
param(params
);
632 auto ret
= d_gettag_ffi(¶m
);
637 return param
.params
.tag
;
642 bool RecursorLua4::genhook(const luacall_t
& func
, DNSQuestion
& dq
, int& ret
) const
647 if (dq
.currentRecords
) {
648 dq
.records
= *dq
.currentRecords
;
653 dq
.followupFunction
.clear();
654 dq
.followupPrefix
.clear();
655 dq
.followupName
.clear();
657 dq
.udpAnswer
.clear();
658 dq
.udpCallback
.clear();
661 bool handled
=func(&dq
);
667 if(!dq
.followupFunction
.empty()) {
668 if(dq
.followupFunction
=="followCNAMERecords") {
669 ret
= followCNAMERecords(dq
.records
, QType(dq
.qtype
), ret
);
671 else if(dq
.followupFunction
=="getFakeAAAARecords") {
672 ret
=getFakeAAAARecords(dq
.followupName
, ComboAddress(dq
.followupPrefix
), dq
.records
);
674 else if(dq
.followupFunction
=="getFakePTRRecords") {
675 ret
=getFakePTRRecords(dq
.followupName
, dq
.records
);
677 else if(dq
.followupFunction
=="udpQueryResponse") {
678 dq
.udpAnswer
= GenUDPQueryResponse(dq
.udpQueryDest
, dq
.udpQuery
);
679 auto cbFunc
= d_lw
->readVariable
<boost::optional
<luacall_t
>>(dq
.udpCallback
).get_value_or(0);
681 g_log
<<Logger::Error
<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl
;
684 bool result
=cbFunc(&dq
);
691 if (dq
.currentRecords
) {
692 *dq
.currentRecords
= dq
.records
;
696 // see if they added followup work for us too
700 RecursorLua4::~RecursorLua4(){}
702 const char* pdns_ffi_param_get_qname(pdns_ffi_param_t
* ref
)
704 if (!ref
->qnameStr
) {
705 ref
->qnameStr
= std::unique_ptr
<std::string
>(new std::string(ref
->params
.qname
.toStringNoDot()));
708 return ref
->qnameStr
->c_str();
711 void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t
* ref
, const char** qname
, size_t* qnameSize
)
713 const auto& storage
= ref
->params
.qname
.getStorage();
714 *qname
= storage
.data();
715 *qnameSize
= storage
.size();
718 uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t
* ref
)
720 return ref
->params
.qtype
;
723 const char* pdns_ffi_param_get_remote(pdns_ffi_param_t
* ref
)
725 if (!ref
->remoteStr
) {
726 ref
->remoteStr
= std::unique_ptr
<std::string
>(new std::string(ref
->params
.remote
.toString()));
729 return ref
->remoteStr
->c_str();
732 static void pdns_ffi_comboaddress_to_raw(const ComboAddress
& ca
, const void** addr
, size_t* addrSize
)
735 *addr
= &ca
.sin4
.sin_addr
.s_addr
;
736 *addrSize
= sizeof(ca
.sin4
.sin_addr
.s_addr
);
739 *addr
= &ca
.sin6
.sin6_addr
.s6_addr
;
740 *addrSize
= sizeof(ca
.sin6
.sin6_addr
.s6_addr
);
744 void pdns_ffi_param_get_remote_raw(pdns_ffi_param_t
* ref
, const void** addr
, size_t* addrSize
)
746 pdns_ffi_comboaddress_to_raw(ref
->params
.remote
, addr
, addrSize
);
749 uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t
* ref
)
751 return ref
->params
.remote
.getPort();
754 const char* pdns_ffi_param_get_local(pdns_ffi_param_t
* ref
)
756 if (!ref
->localStr
) {
757 ref
->localStr
= std::unique_ptr
<std::string
>(new std::string(ref
->params
.local
.toString()));
760 return ref
->localStr
->c_str();
763 void pdns_ffi_param_get_local_raw(pdns_ffi_param_t
* ref
, const void** addr
, size_t* addrSize
)
765 pdns_ffi_comboaddress_to_raw(ref
->params
.local
, addr
, addrSize
);
768 uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t
* ref
)
770 return ref
->params
.local
.getPort();
773 const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t
* ref
)
775 if (ref
->params
.ednssubnet
.empty()) {
779 if (!ref
->ednssubnetStr
) {
780 ref
->ednssubnetStr
= std::unique_ptr
<std::string
>(new std::string(ref
->params
.ednssubnet
.toStringNoMask()));
783 return ref
->ednssubnetStr
->c_str();
786 void pdns_ffi_param_get_edns_cs_raw(pdns_ffi_param_t
* ref
, const void** net
, size_t* netSize
)
788 if (ref
->params
.ednssubnet
.empty()) {
794 pdns_ffi_comboaddress_to_raw(ref
->params
.ednssubnet
.getNetwork(), net
, netSize
);
797 uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t
* ref
)
799 return ref
->params
.ednssubnet
.getBits();
802 static void fill_edns_option(const EDNSOptionViewValue
& value
, pdns_ednsoption_t
& option
)
804 option
.len
= value
.size
;
805 option
.data
= nullptr;
807 if (value
.size
> 0) {
808 option
.data
= value
.content
;
812 size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t
* ref
, const pdns_ednsoption_t
** out
)
814 if (ref
->params
.ednsOptions
.empty()) {
818 size_t totalCount
= 0;
819 for (const auto& option
: ref
->params
.ednsOptions
) {
820 totalCount
+= option
.second
.values
.size();
823 ref
->ednsOptionsVect
.resize(totalCount
);
826 for (const auto& option
: ref
->params
.ednsOptions
) {
827 for (const auto& entry
: option
.second
.values
) {
828 fill_edns_option(entry
, ref
->ednsOptionsVect
.at(pos
));
829 ref
->ednsOptionsVect
.at(pos
).optionCode
= option
.first
;
834 *out
= ref
->ednsOptionsVect
.data();
839 size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t
* ref
, uint16_t optionCode
, const pdns_ednsoption_t
** out
)
841 const auto& it
= ref
->params
.ednsOptions
.find(optionCode
);
842 if (it
== ref
->params
.ednsOptions
.cend() || it
->second
.values
.empty()) {
846 ref
->ednsOptionsVect
.resize(it
->second
.values
.size());
849 for (const auto& entry
: it
->second
.values
) {
850 fill_edns_option(entry
, ref
->ednsOptionsVect
.at(pos
));
851 ref
->ednsOptionsVect
.at(pos
).optionCode
= optionCode
;
855 *out
= ref
->ednsOptionsVect
.data();
860 size_t pdns_ffi_param_get_proxy_protocol_values(pdns_ffi_param_t
* ref
, const pdns_proxyprotocol_value_t
** out
)
862 if (ref
->params
.proxyProtocolValues
.empty()) {
866 ref
->proxyProtocolValuesVect
.resize(ref
->params
.proxyProtocolValues
.size());
869 for (const auto& value
: ref
->params
.proxyProtocolValues
) {
870 auto& dest
= ref
->proxyProtocolValuesVect
.at(pos
);
871 dest
.type
= value
.type
;
872 dest
.len
= value
.content
.size();
874 dest
.data
= value
.content
.data();
879 *out
= ref
->proxyProtocolValuesVect
.data();
881 return ref
->proxyProtocolValuesVect
.size();
884 void pdns_ffi_param_set_tag(pdns_ffi_param_t
* ref
, unsigned int tag
)
886 ref
->params
.tag
= tag
;
889 void pdns_ffi_param_add_policytag(pdns_ffi_param_t
*ref
, const char* name
)
891 ref
->params
.policyTags
.insert(std::string(name
));
894 void pdns_ffi_param_set_requestorid(pdns_ffi_param_t
* ref
, const char* name
)
896 ref
->params
.requestorId
= std::string(name
);
899 void pdns_ffi_param_set_devicename(pdns_ffi_param_t
* ref
, const char* name
)
901 ref
->params
.deviceName
= std::string(name
);
904 void pdns_ffi_param_set_deviceid(pdns_ffi_param_t
* ref
, size_t len
, const void* name
)
906 ref
->params
.deviceId
= std::string(reinterpret_cast<const char*>(name
), len
);
909 void pdns_ffi_param_set_routingtag(pdns_ffi_param_t
* ref
, const char* rtag
)
911 ref
->params
.routingTag
= std::string(rtag
);
914 void pdns_ffi_param_set_variable(pdns_ffi_param_t
* ref
, bool variable
)
916 ref
->params
.variable
= variable
;
919 void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t
* ref
, uint32_t ttl
)
921 ref
->params
.ttlCap
= ttl
;
924 void pdns_ffi_param_set_log_query(pdns_ffi_param_t
* ref
, bool logQuery
)
926 ref
->params
.logQuery
= logQuery
;
929 void pdns_ffi_param_set_log_response(pdns_ffi_param_t
* ref
, bool logResponse
)
931 ref
->params
.logResponse
= logResponse
;
934 void pdns_ffi_param_set_rcode(pdns_ffi_param_t
* ref
, int rcode
)
936 ref
->params
.rcode
= rcode
;
939 void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t
* ref
, bool follow
)
941 ref
->params
.followCNAMERecords
= follow
;
944 void pdns_ffi_param_set_extended_error_code(pdns_ffi_param_t
* ref
, uint16_t code
)
946 ref
->params
.extendedErrorCode
= code
;
949 void pdns_ffi_param_set_extended_error_extra(pdns_ffi_param_t
* ref
, size_t len
, const char* extra
)
951 ref
->params
.extendedErrorExtra
= std::string(extra
, len
);
954 bool pdns_ffi_param_add_record(pdns_ffi_param_t
*ref
, const char* name
, uint16_t type
, uint32_t ttl
, const char* content
, size_t contentSize
, pdns_record_place_t place
)
958 dr
.d_name
= name
!= nullptr ? DNSName(name
) : ref
->params
.qname
;
961 dr
.d_class
= QClass::IN
;
962 dr
.d_place
= DNSResourceRecord::Place(place
);
963 dr
.d_content
= DNSRecordContent::mastermake(type
, QClass::IN
, std::string(content
, contentSize
));
964 ref
->params
.records
.push_back(std::move(dr
));
968 catch (const std::exception
& e
) {
969 g_log
<<Logger::Error
<<"Error attempting to add a record from Lua via pdns_ffi_param_add_record(): "<<e
.what()<<endl
;
974 void pdns_ffi_param_set_padding_disabled(pdns_ffi_param_t
* ref
, bool disabled
)
976 ref
->params
.disablePadding
= disabled
;