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 static int getFakeAAAARecords(const DNSName
& qname
, const std::string
& prefix
, vector
<DNSRecord
>& ret
)
39 int rcode
=directResolve(qname
, QType(QType::A
), 1, ret
);
41 ComboAddress
prefixAddress(prefix
);
43 // Remove double CNAME records
44 std::set
<DNSName
> seenCNAMEs
;
45 ret
.erase(std::remove_if(
48 [&seenCNAMEs
](DNSRecord
& rr
) {
49 if (rr
.d_type
== QType::CNAME
) {
50 auto target
= getRR
<CNAMERecordContent
>(rr
);
51 if (target
== nullptr) {
54 if (seenCNAMEs
.count(target
->getTarget()) > 0) {
55 // We've had this CNAME before, remove it
58 seenCNAMEs
.insert(target
->getTarget());
65 for(DNSRecord
& rr
: ret
)
67 if(rr
.d_type
== QType::A
&& rr
.d_place
==DNSResourceRecord::ANSWER
) {
68 if(auto rec
= getRR
<ARecordContent
>(rr
)) {
69 ComboAddress
ipv4(rec
->getCA());
71 memcpy((void*)&tmp
, &ipv4
.sin4
.sin_addr
.s_addr
, 4);
73 memcpy(((char*)&prefixAddress
.sin6
.sin6_addr
.s6_addr
)+12, &tmp
, 4);
74 rr
.d_content
= std::make_shared
<AAAARecordContent
>(prefixAddress
);
75 rr
.d_type
= QType::AAAA
;
82 // We've seen an A in the ANSWER section, so there is no need to keep any
83 // SOA in the AUTHORITY section as this is not a NODATA response.
84 ret
.erase(std::remove_if(
88 return (rr
.d_type
== QType::SOA
&& rr
.d_place
==DNSResourceRecord::AUTHORITY
);
95 static int getFakePTRRecords(const DNSName
& qname
, const std::string
& prefix
, vector
<DNSRecord
>& ret
)
97 /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it
98 and turn it into an IPv4 in-addr.arpa query */
100 vector
<string
> parts
= qname
.getRawLabels();
106 for(int n
= 0; n
< 4; ++n
) {
108 std::to_string(stoll(parts
[n
*2], 0, 16) + 16*stoll(parts
[n
*2+1], 0, 16));
109 newquery
.append(1,'.');
111 newquery
+= "in-addr.arpa.";
116 rr
.d_type
= QType::CNAME
;
117 rr
.d_content
= std::make_shared
<CNAMERecordContent
>(newquery
);
120 int rcode
= directResolve(DNSName(newquery
), QType(QType::PTR
), 1, ret
);
126 boost::optional
<dnsheader
> RecursorLua4::DNSQuestion::getDH() const
130 return boost::optional
<dnsheader
>();
133 vector
<string
> RecursorLua4::DNSQuestion::getEDNSFlags() const
137 if (*ednsFlags
& EDNSOpts::DNSSECOK
)
143 bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag
) const
146 if (flag
== "DO" && (*ednsFlags
& EDNSOpts::DNSSECOK
))
152 vector
<pair
<uint16_t, string
> > RecursorLua4::DNSQuestion::getEDNSOptions() const
157 return vector
<pair
<uint16_t,string
>>();
160 boost::optional
<string
> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code
) const
163 for(const auto& o
: *ednsOptions
)
167 return boost::optional
<string
>();
170 boost::optional
<Netmask
> RecursorLua4::DNSQuestion::getEDNSSubnet() const
173 for(const auto& o
: *ednsOptions
) {
174 if(o
.first
==EDNSOptionCode::ECS
) {
176 if(getEDNSSubnetOptsFromString(o
.second
, &eso
))
183 return boost::optional
<Netmask
>();
187 vector
<pair
<int, DNSRecord
> > RecursorLua4::DNSQuestion::getRecords() const
189 vector
<pair
<int, DNSRecord
> > ret
;
191 for(const auto& r
: records
) {
192 ret
.push_back({num
++, r
});
196 void RecursorLua4::DNSQuestion::setRecords(const vector
<pair
<int, DNSRecord
> >& recs
)
199 for(const auto& p
: recs
) {
200 records
.push_back(p
.second
);
204 void RecursorLua4::DNSQuestion::addRecord(uint16_t type
, const std::string
& content
, DNSResourceRecord::Place place
, boost::optional
<int> ttl
, boost::optional
<string
> name
)
207 dr
.d_name
=name
? DNSName(*name
) : qname
;
208 dr
.d_ttl
=ttl
.get_value_or(3600);
211 dr
.d_content
= DNSRecordContent::mastermake(type
, 1, content
);
212 records
.push_back(dr
);
215 void RecursorLua4::DNSQuestion::addAnswer(uint16_t type
, const std::string
& content
, boost::optional
<int> ttl
, boost::optional
<string
> name
)
217 addRecord(type
, content
, DNSResourceRecord::ANSWER
, ttl
, name
);
222 std::atomic
<unsigned long>* ptr
;
223 void inc() { (*ptr
)++; }
224 void incBy(unsigned int by
) { (*ptr
)+= by
; }
225 unsigned long get() { return *ptr
; }
226 void set(unsigned long val
) { *ptr
=val
; }
229 void RecursorLua4::postPrepareContext()
231 d_lw
->registerMember
<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion
& dq
) -> const DNSName
& { return dq
.qname
; }, [](DNSQuestion
& dq
, const DNSName
& newName
) { (void) newName
; });
232 d_lw
->registerMember
<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion
& dq
) -> uint16_t { return dq
.qtype
; }, [](DNSQuestion
& dq
, uint16_t newType
) { (void) newType
; });
233 d_lw
->registerMember
<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion
& dq
) -> bool { return dq
.isTcp
; }, [](DNSQuestion
& dq
, bool newTcp
) { (void) newTcp
; });
234 d_lw
->registerMember
<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion
& dq
) -> const ComboAddress
& { return dq
.local
; }, [](DNSQuestion
& dq
, const ComboAddress
& newLocal
) { (void) newLocal
; });
235 d_lw
->registerMember
<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion
& dq
) -> const ComboAddress
& { return dq
.remote
; }, [](DNSQuestion
& dq
, const ComboAddress
& newRemote
) { (void) newRemote
; });
236 d_lw
->registerMember
<vState (DNSQuestion::*)>("validationState", [](const DNSQuestion
& dq
) -> vState
{ return dq
.validationState
; }, [](DNSQuestion
& dq
, vState newState
) { (void) newState
; });
238 d_lw
->registerMember
<bool (DNSQuestion::*)>("variable", [](const DNSQuestion
& dq
) -> bool { return dq
.variable
; }, [](DNSQuestion
& dq
, bool newVariable
) { dq
.variable
= newVariable
; });
239 d_lw
->registerMember
<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion
& dq
) -> bool { return dq
.wantsRPZ
; }, [](DNSQuestion
& dq
, bool newWantsRPZ
) { dq
.wantsRPZ
= newWantsRPZ
; });
240 d_lw
->registerMember
<bool (DNSQuestion::*)>("logResponse", [](const DNSQuestion
& dq
) -> bool { return dq
.logResponse
; }, [](DNSQuestion
& dq
, bool newLogResponse
) { dq
.logResponse
= newLogResponse
; });
242 d_lw
->registerMember("rcode", &DNSQuestion::rcode
);
243 d_lw
->registerMember("tag", &DNSQuestion::tag
);
244 d_lw
->registerMember("requestorId", &DNSQuestion::requestorId
);
245 d_lw
->registerMember("deviceId", &DNSQuestion::deviceId
);
246 d_lw
->registerMember("deviceName", &DNSQuestion::deviceName
);
247 d_lw
->registerMember("followupFunction", &DNSQuestion::followupFunction
);
248 d_lw
->registerMember("followupPrefix", &DNSQuestion::followupPrefix
);
249 d_lw
->registerMember("followupName", &DNSQuestion::followupName
);
250 d_lw
->registerMember("data", &DNSQuestion::data
);
251 d_lw
->registerMember("udpQuery", &DNSQuestion::udpQuery
);
252 d_lw
->registerMember("udpAnswer", &DNSQuestion::udpAnswer
);
253 d_lw
->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest
);
254 d_lw
->registerMember("udpCallback", &DNSQuestion::udpCallback
);
255 d_lw
->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy
);
256 d_lw
->registerMember
<DNSFilterEngine::Policy
, std::string
>("policyName",
257 [](const DNSFilterEngine::Policy
& pol
) -> std::string
{
260 return std::string();
262 [](DNSFilterEngine::Policy
& pol
, const std::string
& name
) {
263 pol
.d_name
= std::make_shared
<std::string
>(name
);
265 d_lw
->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind
);
266 d_lw
->registerMember("policyType", &DNSFilterEngine::Policy::d_type
);
267 d_lw
->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl
);
268 d_lw
->registerMember
<DNSFilterEngine::Policy
, std::string
>("policyCustom",
269 [](const DNSFilterEngine::Policy
& pol
) -> std::string
{
271 if (pol
.d_kind
!= DNSFilterEngine::PolicyKind::Custom
) {
275 for (const auto& dr
: pol
.d_custom
) {
276 if (!result
.empty()) {
279 result
+= dr
->getZoneRepresentation();
284 [](DNSFilterEngine::Policy
& pol
, const std::string
& content
) {
285 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
286 pol
.d_custom
.clear();
287 pol
.d_custom
.push_back(DNSRecordContent::mastermake(QType::CNAME
, QClass::IN
, content
));
290 d_lw
->registerFunction("getDH", &DNSQuestion::getDH
);
291 d_lw
->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions
);
292 d_lw
->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption
);
293 d_lw
->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet
);
294 d_lw
->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags
);
295 d_lw
->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag
);
296 d_lw
->registerMember("name", &DNSRecord::d_name
);
297 d_lw
->registerMember("type", &DNSRecord::d_type
);
298 d_lw
->registerMember("ttl", &DNSRecord::d_ttl
);
299 d_lw
->registerMember("place", &DNSRecord::d_place
);
301 d_lw
->registerMember("size", &EDNSOptionViewValue::size
);
302 d_lw
->registerFunction
<std::string(EDNSOptionViewValue::*)()>("getContent", [](const EDNSOptionViewValue
& value
) { return std::string(value
.content
, value
.size
); });
303 d_lw
->registerFunction
<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView
& option
) { return option
.values
.size(); });
304 d_lw
->registerFunction
<std::vector
<string
>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView
& option
) {
305 std::vector
<string
> values
;
306 for (const auto& value
: option
.values
) {
307 values
.push_back(std::string(value
.content
, value
.size
));
312 /* pre 4.2 API compatibility, when we had only one value for a given EDNS option */
313 d_lw
->registerMember
<uint16_t(EDNSOptionView::*)>("size", [](const EDNSOptionView
& option
) -> uint16_t {
316 if (!option
.values
.empty()) {
317 result
= option
.values
.at(0).size
;
321 [](EDNSOptionView
& option
, uint16_t newSize
) { (void) newSize
; });
322 d_lw
->registerFunction
<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView
& option
) {
323 if (option
.values
.empty()) {
324 return std::string();
326 return std::string(option
.values
.at(0).content
, option
.values
.at(0).size
); });
328 d_lw
->registerFunction
<string(DNSRecord::*)()>("getContent", [](const DNSRecord
& dr
) { return dr
.d_content
->getZoneRepresentation(); });
329 d_lw
->registerFunction
<boost::optional
<ComboAddress
>(DNSRecord::*)()>("getCA", [](const DNSRecord
& dr
) {
330 boost::optional
<ComboAddress
> ret
;
332 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(dr
.d_content
))
334 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(dr
.d_content
))
335 ret
=aaaarec
->getCA(53);
340 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
); });
341 d_lw
->registerFunction("addAnswer", &DNSQuestion::addAnswer
);
342 d_lw
->registerFunction("addRecord", &DNSQuestion::addRecord
);
343 d_lw
->registerFunction("getRecords", &DNSQuestion::getRecords
);
344 d_lw
->registerFunction("setRecords", &DNSQuestion::setRecords
);
346 d_lw
->registerFunction
<void(DNSQuestion::*)(const std::string
&)>("addPolicyTag", [](DNSQuestion
& dq
, const std::string
& tag
) { if (dq
.policyTags
) { dq
.policyTags
->push_back(tag
); } });
347 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
) {
349 dq
.policyTags
->clear();
350 for (const auto& tag
: tags
) {
351 dq
.policyTags
->push_back(tag
.second
);
355 d_lw
->registerFunction
<std::vector
<std::pair
<int, std::string
> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion
& dq
) {
356 std::vector
<std::pair
<int, std::string
> > ret
;
359 for (const auto& tag
: *dq
.policyTags
) {
360 ret
.push_back({count
++, tag
});
366 d_lw
->registerFunction
<void(DNSQuestion::*)(const std::string
&)>("discardPolicy", [](DNSQuestion
& dq
, const std::string
& policy
) {
367 if (dq
.discardedPolicies
) {
368 (*dq
.discardedPolicies
)[policy
] = true;
372 d_lw
->writeFunction("newDS", []() { return SuffixMatchNode(); });
373 d_lw
->registerFunction
<void(SuffixMatchNode::*)(boost::variant
<string
,DNSName
, vector
<pair
<unsigned int,string
> > >)>(
375 [](SuffixMatchNode
&smn
, const boost::variant
<string
,DNSName
,vector
<pair
<unsigned int,string
> > >& in
){
377 if(auto s
= boost::get
<string
>(&in
)) {
378 smn
.add(DNSName(*s
));
380 else if(auto v
= boost::get
<vector
<pair
<unsigned int, string
> > >(&in
)) {
381 for(const auto& entry
: *v
)
382 smn
.add(DNSName(entry
.second
));
385 smn
.add(boost::get
<DNSName
>(in
));
388 catch(std::exception
& e
) {
389 g_log
<<Logger::Error
<<e
.what()<<endl
;
394 d_lw
->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName
&) const) &SuffixMatchNode::check
);
395 d_lw
->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString
);
397 d_pd
.push_back({"policykinds", in_t
{
398 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction
},
399 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop
},
400 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN
},
401 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA
},
402 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate
},
403 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom
}
406 for(const auto& n
: QType::names
)
407 d_pd
.push_back({n
.first
, n
.second
});
409 d_pd
.push_back({"validationstates", in_t
{
410 {"Indeterminate", Indeterminate
},
412 {"Insecure", Insecure
},
416 d_pd
.push_back({"now", &g_now
});
418 d_lw
->writeFunction("getMetric", [](const std::string
& str
) {
419 return DynMetric
{getDynMetric(str
)};
422 d_lw
->registerFunction("inc", &DynMetric::inc
);
423 d_lw
->registerFunction("incBy", &DynMetric::incBy
);
424 d_lw
->registerFunction("set", &DynMetric::set
);
425 d_lw
->registerFunction("get", &DynMetric::get
);
427 d_lw
->writeFunction("getStat", [](const std::string
& str
) {
429 optional
<uint64_t> value
= getStatByName(str
);
436 d_lw
->writeFunction("getRecursorThreadId", []() {
437 return getRecursorThreadId();
440 d_lw
->writeFunction("sendCustomSNMPTrap", [](const std::string
& str
) {
442 g_snmpAgent
->sendCustomTrap(str
);
446 d_lw
->writeFunction("getregisteredname", [](const DNSName
&dname
) {
447 return getRegisteredName(dname
);
451 void RecursorLua4::postLoad() {
452 d_prerpz
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("prerpz").get_value_or(0);
453 d_preresolve
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("preresolve").get_value_or(0);
454 d_nodata
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("nodata").get_value_or(0);
455 d_nxdomain
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("nxdomain").get_value_or(0);
456 d_postresolve
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("postresolve").get_value_or(0);
457 d_preoutquery
= d_lw
->readVariable
<boost::optional
<luacall_t
>>("preoutquery").get_value_or(0);
458 d_maintenance
= d_lw
->readVariable
<boost::optional
<luamaintenance_t
>>("maintenance").get_value_or(0);
460 d_ipfilter
= d_lw
->readVariable
<boost::optional
<ipfilter_t
>>("ipfilter").get_value_or(0);
461 d_gettag
= d_lw
->readVariable
<boost::optional
<gettag_t
>>("gettag").get_value_or(0);
462 d_gettag_ffi
= d_lw
->readVariable
<boost::optional
<gettag_ffi_t
>>("gettag_ffi").get_value_or(0);
465 void RecursorLua4::getFeatures(Features
& features
) {
466 // Add key-values pairs below.
467 // Make sure you add string values explicity converted to string.
468 // e.g. features.push_back(make_pair("somekey", string("stringvalue"));
469 // Both int and double end up as a lua number type.
470 features
.push_back(make_pair("PR8001_devicename", true));
473 void RecursorLua4::maintenance() const
480 bool RecursorLua4::prerpz(DNSQuestion
& dq
, int& ret
) const
482 return genhook(d_prerpz
, dq
, ret
);
485 bool RecursorLua4::preresolve(DNSQuestion
& dq
, int& ret
) const
487 return genhook(d_preresolve
, dq
, ret
);
490 bool RecursorLua4::nxdomain(DNSQuestion
& dq
, int& ret
) const
492 return genhook(d_nxdomain
, dq
, ret
);
495 bool RecursorLua4::nodata(DNSQuestion
& dq
, int& ret
) const
497 return genhook(d_nodata
, dq
, ret
);
500 bool RecursorLua4::postresolve(DNSQuestion
& dq
, int& ret
) const
502 return genhook(d_postresolve
, dq
, ret
);
505 bool RecursorLua4::preoutquery(const ComboAddress
& ns
, const ComboAddress
& requestor
, const DNSName
& query
, const QType
& qtype
, bool isTcp
, vector
<DNSRecord
>& res
, int& ret
) const
507 bool variableAnswer
= false;
508 bool wantsRPZ
= false;
509 bool logQuery
= false;
510 RecursorLua4::DNSQuestion
dq(ns
, requestor
, query
, qtype
.getCode(), isTcp
, variableAnswer
, wantsRPZ
, logQuery
);
511 dq
.currentRecords
= &res
;
513 return genhook(d_preoutquery
, dq
, ret
);
516 bool RecursorLua4::ipfilter(const ComboAddress
& remote
, const ComboAddress
& local
, const struct dnsheader
& dh
) const
519 return d_ipfilter(remote
, local
, dh
);
520 return false; // don't block
523 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 EDNSOptionViewMap
& ednsOptions
, bool tcp
, std::string
& requestorId
, std::string
& deviceId
, std::string
& deviceName
) const
526 auto ret
= d_gettag(remote
, ednssubnet
, local
, qname
, qtype
, ednsOptions
, tcp
);
529 const auto& tags
= std::get
<1>(ret
);
531 for (const auto& tag
: *tags
) {
532 policyTags
->push_back(tag
.second
);
536 const auto dataret
= std::get
<2>(ret
);
540 const auto reqIdret
= std::get
<3>(ret
);
542 requestorId
= *reqIdret
;
544 const auto deviceIdret
= std::get
<4>(ret
);
546 deviceId
= *deviceIdret
;
549 const auto deviceNameret
= std::get
<5>(ret
);
551 deviceName
= *deviceNameret
;
553 return std::get
<0>(ret
);
558 struct pdns_ffi_param
561 pdns_ffi_param(const DNSName
& qname_
, uint16_t qtype_
, const ComboAddress
& local_
, const ComboAddress
& remote_
, const Netmask
& ednssubnet_
, std::vector
<std::string
>& policyTags_
, std::vector
<DNSRecord
>& records_
, const EDNSOptionViewMap
& ednsOptions_
, std::string
& requestorId_
, std::string
& deviceId_
, std::string
& deviceName_
, boost::optional
<int>& rcode_
, uint32_t& ttlCap_
, bool& variable_
, bool tcp_
, bool& logQuery_
, bool& logResponse_
, bool& followCNAMERecords_
): qname(qname_
), local(local_
), remote(remote_
), ednssubnet(ednssubnet_
), policyTags(policyTags_
), records(records_
), ednsOptions(ednsOptions_
), requestorId(requestorId_
), deviceId(deviceId_
), deviceName(deviceName_
), rcode(rcode_
), ttlCap(ttlCap_
), variable(variable_
), logQuery(logQuery_
), logResponse(logResponse_
), followCNAMERecords(followCNAMERecords_
), qtype(qtype_
), tcp(tcp_
)
565 std::unique_ptr
<std::string
> qnameStr
{nullptr};
566 std::unique_ptr
<std::string
> localStr
{nullptr};
567 std::unique_ptr
<std::string
> remoteStr
{nullptr};
568 std::unique_ptr
<std::string
> ednssubnetStr
{nullptr};
569 std::vector
<pdns_ednsoption_t
> ednsOptionsVect
;
571 const DNSName
& qname
;
572 const ComboAddress
& local
;
573 const ComboAddress
& remote
;
574 const Netmask
& ednssubnet
;
575 std::vector
<std::string
>& policyTags
;
576 std::vector
<DNSRecord
>& records
;
577 const EDNSOptionViewMap
& ednsOptions
;
578 std::string
& requestorId
;
579 std::string
& deviceId
;
580 std::string
& deviceName
;
581 boost::optional
<int>& rcode
;
586 bool& followCNAMERecords
;
593 unsigned int RecursorLua4::gettag_ffi(const ComboAddress
& remote
, const Netmask
& ednssubnet
, const ComboAddress
& local
, const DNSName
& qname
, uint16_t qtype
, std::vector
<std::string
>* policyTags
, std::vector
<DNSRecord
>& records
, LuaContext::LuaObject
& data
, const EDNSOptionViewMap
& ednsOptions
, bool tcp
, std::string
& requestorId
, std::string
& deviceId
, std::string
& deviceName
, boost::optional
<int>& rcode
, uint32_t& ttlCap
, bool& variable
, bool& logQuery
, bool& logResponse
, bool& followCNAMERecords
) const
596 pdns_ffi_param_t
param(qname
, qtype
, local
, remote
, ednssubnet
, *policyTags
, records
, ednsOptions
, requestorId
, deviceId
, deviceName
, rcode
, ttlCap
, variable
, tcp
, logQuery
, logResponse
, followCNAMERecords
);
598 auto ret
= d_gettag_ffi(¶m
);
608 bool RecursorLua4::genhook(const luacall_t
& func
, DNSQuestion
& dq
, int& ret
) const
613 if (dq
.currentRecords
) {
614 dq
.records
= *dq
.currentRecords
;
619 dq
.followupFunction
.clear();
620 dq
.followupPrefix
.clear();
621 dq
.followupName
.clear();
623 dq
.udpAnswer
.clear();
624 dq
.udpCallback
.clear();
627 bool handled
=func(&dq
);
633 if(!dq
.followupFunction
.empty()) {
634 if(dq
.followupFunction
=="followCNAMERecords") {
635 ret
= followCNAMERecords(dq
.records
, QType(dq
.qtype
));
637 else if(dq
.followupFunction
=="getFakeAAAARecords") {
638 ret
=getFakeAAAARecords(dq
.followupName
, dq
.followupPrefix
, dq
.records
);
640 else if(dq
.followupFunction
=="getFakePTRRecords") {
641 ret
=getFakePTRRecords(dq
.followupName
, dq
.followupPrefix
, dq
.records
);
643 else if(dq
.followupFunction
=="udpQueryResponse") {
644 dq
.udpAnswer
= GenUDPQueryResponse(dq
.udpQueryDest
, dq
.udpQuery
);
645 auto cbFunc
= d_lw
->readVariable
<boost::optional
<luacall_t
>>(dq
.udpCallback
).get_value_or(0);
647 g_log
<<Logger::Error
<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl
;
650 bool result
=cbFunc(&dq
);
657 if (dq
.currentRecords
) {
658 *dq
.currentRecords
= dq
.records
;
662 // see if they added followup work for us too
666 RecursorLua4::~RecursorLua4(){}
668 const char* pdns_ffi_param_get_qname(pdns_ffi_param_t
* ref
)
670 if (!ref
->qnameStr
) {
671 ref
->qnameStr
= std::unique_ptr
<std::string
>(new std::string(ref
->qname
.toStringNoDot()));
674 return ref
->qnameStr
->c_str();
677 void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t
* ref
, const char** qname
, size_t* qnameSize
)
679 const auto& storage
= ref
->qname
.getStorage();
680 *qname
= storage
.data();
681 *qnameSize
= storage
.size();
684 uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t
* ref
)
689 const char* pdns_ffi_param_get_remote(pdns_ffi_param_t
* ref
)
691 if (!ref
->remoteStr
) {
692 ref
->remoteStr
= std::unique_ptr
<std::string
>(new std::string(ref
->remote
.toString()));
695 return ref
->remoteStr
->c_str();
698 static void pdns_ffi_comboaddress_to_raw(const ComboAddress
& ca
, const void** addr
, size_t* addrSize
)
701 *addr
= &ca
.sin4
.sin_addr
.s_addr
;
702 *addrSize
= sizeof(ca
.sin4
.sin_addr
.s_addr
);
705 *addr
= &ca
.sin6
.sin6_addr
.s6_addr
;
706 *addrSize
= sizeof(ca
.sin6
.sin6_addr
.s6_addr
);
710 void pdns_ffi_param_get_remote_raw(pdns_ffi_param_t
* ref
, const void** addr
, size_t* addrSize
)
712 pdns_ffi_comboaddress_to_raw(ref
->remote
, addr
, addrSize
);
715 uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t
* ref
)
717 return ref
->remote
.getPort();
720 const char* pdns_ffi_param_get_local(pdns_ffi_param_t
* ref
)
722 if (!ref
->localStr
) {
723 ref
->localStr
= std::unique_ptr
<std::string
>(new std::string(ref
->local
.toString()));
726 return ref
->localStr
->c_str();
729 void pdns_ffi_param_get_local_raw(pdns_ffi_param_t
* ref
, const void** addr
, size_t* addrSize
)
731 pdns_ffi_comboaddress_to_raw(ref
->local
, addr
, addrSize
);
734 uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t
* ref
)
736 return ref
->local
.getPort();
739 const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t
* ref
)
741 if (ref
->ednssubnet
.empty()) {
745 if (!ref
->ednssubnetStr
) {
746 ref
->ednssubnetStr
= std::unique_ptr
<std::string
>(new std::string(ref
->ednssubnet
.toStringNoMask()));
749 return ref
->ednssubnetStr
->c_str();
752 void pdns_ffi_param_get_edns_cs_raw(pdns_ffi_param_t
* ref
, const void** net
, size_t* netSize
)
754 if (ref
->ednssubnet
.empty()) {
760 pdns_ffi_comboaddress_to_raw(ref
->ednssubnet
.getNetwork(), net
, netSize
);
763 uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t
* ref
)
765 return ref
->ednssubnet
.getBits();
768 static void fill_edns_option(const EDNSOptionViewValue
& value
, pdns_ednsoption_t
& option
)
770 option
.len
= value
.size
;
771 option
.data
= nullptr;
773 if (value
.size
> 0) {
774 option
.data
= value
.content
;
778 size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t
* ref
, const pdns_ednsoption_t
** out
)
780 if (ref
->ednsOptions
.empty()) {
784 size_t totalCount
= 0;
785 for (const auto& option
: ref
->ednsOptions
) {
786 totalCount
+= option
.second
.values
.size();
789 ref
->ednsOptionsVect
.resize(totalCount
);
792 for (const auto& option
: ref
->ednsOptions
) {
793 for (const auto& entry
: option
.second
.values
) {
794 fill_edns_option(entry
, ref
->ednsOptionsVect
.at(pos
));
795 ref
->ednsOptionsVect
.at(pos
).optionCode
= option
.first
;
800 *out
= ref
->ednsOptionsVect
.data();
805 size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t
* ref
, uint16_t optionCode
, const pdns_ednsoption_t
** out
)
807 const auto& it
= ref
->ednsOptions
.find(optionCode
);
808 if (it
== ref
->ednsOptions
.cend() || it
->second
.values
.empty()) {
812 ref
->ednsOptionsVect
.resize(it
->second
.values
.size());
815 for (const auto& entry
: it
->second
.values
) {
816 fill_edns_option(entry
, ref
->ednsOptionsVect
.at(pos
));
817 ref
->ednsOptionsVect
.at(pos
).optionCode
= optionCode
;
821 *out
= ref
->ednsOptionsVect
.data();
826 void pdns_ffi_param_set_tag(pdns_ffi_param_t
* ref
, unsigned int tag
)
831 void pdns_ffi_param_add_policytag(pdns_ffi_param_t
*ref
, const char* name
)
833 ref
->policyTags
.push_back(std::string(name
));
836 void pdns_ffi_param_set_requestorid(pdns_ffi_param_t
* ref
, const char* name
)
838 ref
->requestorId
= std::string(name
);
841 void pdns_ffi_param_set_devicename(pdns_ffi_param_t
* ref
, const char* name
)
843 ref
->deviceName
= std::string(name
);
846 void pdns_ffi_param_set_deviceid(pdns_ffi_param_t
* ref
, size_t len
, const void* name
)
848 ref
->deviceId
= std::string(reinterpret_cast<const char*>(name
), len
);
851 void pdns_ffi_param_set_variable(pdns_ffi_param_t
* ref
, bool variable
)
853 ref
->variable
= variable
;
856 void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t
* ref
, uint32_t ttl
)
861 void pdns_ffi_param_set_log_query(pdns_ffi_param_t
* ref
, bool logQuery
)
863 ref
->logQuery
= logQuery
;
866 void pdns_ffi_param_set_log_response(pdns_ffi_param_t
* ref
, bool logResponse
)
868 ref
->logResponse
= logResponse
;
871 void pdns_ffi_param_set_rcode(pdns_ffi_param_t
* ref
, int rcode
)
876 void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t
* ref
, bool follow
)
878 ref
->followCNAMERecords
= follow
;
881 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
)
885 dr
.d_name
= name
!= nullptr ? DNSName(name
) : ref
->qname
;
888 dr
.d_class
= QClass::IN
;
889 dr
.d_place
= DNSResourceRecord::Place(place
);
890 dr
.d_content
= DNSRecordContent::mastermake(type
, QClass::IN
, std::string(content
, contentSize
));
891 ref
->records
.push_back(std::move(dr
));
895 catch (const std::exception
& e
) {
896 g_log
<<Logger::Error
<<"Error attempting to add a record from Lua via pdns_ffi_param_add_record(): "<<e
.what()<<endl
;