]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lua-recursor4.cc
Merge pull request #6412 from rgacogne/dnsdist-gnutls-memset
[thirdparty/pdns.git] / pdns / lua-recursor4.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
808c5ef7 22#include "lua-recursor4.hh"
23#include <fstream>
808c5ef7 24#include "logger.hh"
a3e7b735 25#include "dnsparser.hh"
26#include "syncres.hh"
dd39e2dc 27#include "namespaces.hh"
b40562da
RG
28#include "rec_channel.hh"
29#include "ednsoptions.hh"
5ecf1d7e 30#include "ednssubnet.hh"
db486de5 31#include "filterpo.hh"
d705aad9 32#include "rec-snmp.hh"
08dcccd6 33#include <unordered_set>
410d750c 34
9694e14f 35RecursorLua4::RecursorLua4() { prepareContext(); }
70c21c40 36
a3e7b735 37static int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype)
38{
39 vector<DNSRecord> resolved;
40 DNSName target;
41 for(const DNSRecord& rr : ret) {
42 if(rr.d_type == QType::CNAME) {
ba3c54cb
RG
43 auto rec = getRR<CNAMERecordContent>(rr);
44 if(rec) {
45 target=rec->getTarget();
46 break;
47 }
a3e7b735 48 }
49 }
50 if(target.empty())
51 return 0;
52
53 int rcode=directResolve(target, qtype, 1, resolved); // 1 == class
54
55 for(const DNSRecord& rr : resolved) {
56 ret.push_back(rr);
57 }
58 return rcode;
59
60}
61
62static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
63{
64 int rcode=directResolve(qname, QType(QType::A), 1, ret);
65
66 ComboAddress prefixAddress(prefix);
67
68 for(DNSRecord& rr : ret)
69 {
70 if(rr.d_type == QType::A && rr.d_place==DNSResourceRecord::ANSWER) {
ba3c54cb
RG
71 if(auto rec = getRR<ARecordContent>(rr)) {
72 ComboAddress ipv4(rec->getCA());
73 uint32_t tmp;
74 memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4);
75 // tmp=htonl(tmp);
76 memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4);
77 rr.d_content = std::make_shared<AAAARecordContent>(prefixAddress);
78 rr.d_type = QType::AAAA;
79 }
a3e7b735 80 }
81 }
82 return rcode;
83}
84
85static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
86{
87 /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it
88 and turn it into an IPv4 in-addr.arpa query */
89 ret.clear();
90 vector<string> parts = qname.getRawLabels();
91
92 if(parts.size() < 8)
93 return -1;
94
95 string newquery;
96 for(int n = 0; n < 4; ++n) {
97 newquery +=
926ccaca 98 std::to_string(stoll(parts[n*2], 0, 16) + 16*stoll(parts[n*2+1], 0, 16));
a3e7b735 99 newquery.append(1,'.');
100 }
101 newquery += "in-addr.arpa.";
102
103
104 int rcode = directResolve(DNSName(newquery), QType(QType::PTR), 1, ret);
105 for(DNSRecord& rr : ret)
106 {
107 if(rr.d_type == QType::PTR && rr.d_place==DNSResourceRecord::ANSWER) {
108 rr.d_name = qname;
109 }
110 }
111 return rcode;
112
113}
114
621e4e59
PL
115boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const
116{
117 if (dh)
118 return *dh;
119 return boost::optional<dnsheader>();
120}
121
e2fb3504
PL
122vector<string> RecursorLua4::DNSQuestion::getEDNSFlags() const
123{
124 vector<string> ret;
125 if (ednsFlags) {
126 if (*ednsFlags & EDNSOpts::DNSSECOK)
127 ret.push_back("DO");
128 }
129 return ret;
130}
131
132bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag) const
133{
134 if (ednsFlags) {
135 if (flag == "DO" && (*ednsFlags & EDNSOpts::DNSSECOK))
136 return true;
137 }
138 return false;
139}
140
ba21fcfe 141vector<pair<uint16_t, string> > RecursorLua4::DNSQuestion::getEDNSOptions() const
e8340d27 142{
143 if(ednsOptions)
144 return *ednsOptions;
145 else
146 return vector<pair<uint16_t,string>>();
147}
148
ba21fcfe 149boost::optional<string> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const
e8340d27 150{
151 if(ednsOptions)
152 for(const auto& o : *ednsOptions)
153 if(o.first==code)
154 return o.second;
155
156 return boost::optional<string>();
157}
158
ba21fcfe 159boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() const
5ecf1d7e 160{
161
162 if(ednsOptions) {
163 for(const auto& o : *ednsOptions) {
b40562da 164 if(o.first==EDNSOptionCode::ECS) {
5ecf1d7e 165 EDNSSubnetOpts eso;
166 if(getEDNSSubnetOptsFromString(o.second, &eso))
167 return eso.source;
168 else
169 break;
170 }
171 }
172 }
173 return boost::optional<Netmask>();
174}
175
e8340d27 176
ba21fcfe 177vector<pair<int, DNSRecord> > RecursorLua4::DNSQuestion::getRecords() const
a3e7b735 178{
179 vector<pair<int, DNSRecord> > ret;
180 int num=1;
181 for(const auto& r : records) {
182 ret.push_back({num++, r});
183 }
184 return ret;
185}
186void RecursorLua4::DNSQuestion::setRecords(const vector<pair<int, DNSRecord> >& recs)
187{
188 records.clear();
189 for(const auto& p : recs) {
190 records.push_back(p.second);
a3e7b735 191 }
192}
193
aee72a7b 194void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name)
a3e7b735 195{
196 DNSRecord dr;
aee72a7b 197 dr.d_name=name ? DNSName(*name) : qname;
a3e7b735 198 dr.d_ttl=ttl.get_value_or(3600);
199 dr.d_type = type;
200 dr.d_place = place;
6177a176 201 dr.d_content = DNSRecordContent::mastermake(type, 1, content);
a3e7b735 202 records.push_back(dr);
203}
204
aee72a7b 205void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name)
a3e7b735 206{
aee72a7b 207 addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name);
a3e7b735 208}
9f89a5f1 209
210struct DynMetric
211{
212 std::atomic<unsigned long>* ptr;
213 void inc() { (*ptr)++; }
214 void incBy(unsigned int by) { (*ptr)+= by; }
215 unsigned long get() { return *ptr; }
216 void set(unsigned long val) { *ptr =val; }
217};
218
70c21c40 219void RecursorLua4::postPrepareContext()
808c5ef7 220{
ba21fcfe
RG
221 d_lw->registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName& { return dq.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; });
222 d_lw->registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
223 d_lw->registerMember<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion& dq) -> bool { return dq.isTcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
224 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.local; }, [](DNSQuestion& dq, const ComboAddress& newLocal) { (void) newLocal; });
225 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.remote; }, [](DNSQuestion& dq, const ComboAddress& newRemote) { (void) newRemote; });
1921a4c2 226 d_lw->registerMember<vState (DNSQuestion::*)>("validationState", [](const DNSQuestion& dq) -> vState { return dq.validationState; }, [](DNSQuestion& dq, vState newState) { (void) newState; });
ba21fcfe
RG
227
228 d_lw->registerMember<bool (DNSQuestion::*)>("variable", [](const DNSQuestion& dq) -> bool { return dq.variable; }, [](DNSQuestion& dq, bool newVariable) { dq.variable = newVariable; });
229 d_lw->registerMember<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion& dq) -> bool { return dq.wantsRPZ; }, [](DNSQuestion& dq, bool newWantsRPZ) { dq.wantsRPZ = newWantsRPZ; });
230
a3e7b735 231 d_lw->registerMember("rcode", &DNSQuestion::rcode);
ba461517 232 d_lw->registerMember("tag", &DNSQuestion::tag);
67e31ebe 233 d_lw->registerMember("requestorId", &DNSQuestion::requestorId);
a3e7b735 234 d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction);
235 d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix);
236 d_lw->registerMember("followupName", &DNSQuestion::followupName);
6b8b26c8 237 d_lw->registerMember("data", &DNSQuestion::data);
238 d_lw->registerMember("udpQuery", &DNSQuestion::udpQuery);
239 d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer);
240 d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest);
241 d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback);
667f6c7c 242 d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy);
98c28a68
RG
243 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyName",
244 [](const DNSFilterEngine::Policy& pol) -> std::string {
245 if(pol.d_name)
246 return *pol.d_name;
247 return std::string();
248 },
249 [](DNSFilterEngine::Policy& pol, const std::string& name) {
250 pol.d_name = std::make_shared<std::string>(name);
251 });
db486de5
PL
252 d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind);
253 d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl);
98c28a68
RG
254 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyCustom",
255 [](const DNSFilterEngine::Policy& pol) -> std::string {
256 if(pol.d_custom)
257 return pol.d_custom->getZoneRepresentation();
258 return std::string();
db486de5 259 },
98c28a68 260 [](DNSFilterEngine::Policy& pol, const std::string& content) {
db486de5 261 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
6177a176 262 pol.d_custom = DNSRecordContent::mastermake(QType::CNAME, 1, content);
db486de5
PL
263 }
264 );
621e4e59 265 d_lw->registerFunction("getDH", &DNSQuestion::getDH);
e8340d27 266 d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions);
267 d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption);
5ecf1d7e 268 d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet);
e2fb3504
PL
269 d_lw->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags);
270 d_lw->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag);
a3e7b735 271 d_lw->registerMember("name", &DNSRecord::d_name);
272 d_lw->registerMember("type", &DNSRecord::d_type);
273 d_lw->registerMember("ttl", &DNSRecord::d_ttl);
57d0c73b 274 d_lw->registerMember("place", &DNSRecord::d_place);
00b8cadc
RG
275
276 d_lw->registerMember("size", &EDNSOptionView::size);
277 d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) { return std::string(option.content, option.size); });
278
a3e7b735 279 d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); });
7d5f094a 280 d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
281 boost::optional<ComboAddress> ret;
282
283 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content))
284 ret=rec->getCA(53);
dd079764
RG
285 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content))
286 ret=aaaarec->getCA(53);
7d5f094a 287 return ret;
288 });
a3e7b735 289
290
6177a176 291 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); });
a3e7b735 292 d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer);
08dcccd6 293 d_lw->registerFunction("addRecord", &DNSQuestion::addRecord);
a3e7b735 294 d_lw->registerFunction("getRecords", &DNSQuestion::getRecords);
295 d_lw->registerFunction("setRecords", &DNSQuestion::setRecords);
296
48096cf0 297 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->push_back(tag); } });
667f6c7c 298 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) {
48096cf0
RG
299 if (dq.policyTags) {
300 dq.policyTags->clear();
301 for (const auto& tag : tags) {
302 dq.policyTags->push_back(tag.second);
303 }
667f6c7c
RG
304 }
305 });
306 d_lw->registerFunction<std::vector<std::pair<int, std::string> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) {
307 std::vector<std::pair<int, std::string> > ret;
48096cf0
RG
308 if (dq.policyTags) {
309 int count = 1;
310 for (const auto& tag : *dq.policyTags) {
311 ret.push_back({count++, tag});
312 }
667f6c7c
RG
313 }
314 return ret;
315 });
316
0a273054
RG
317 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("discardPolicy", [](DNSQuestion& dq, const std::string& policy) {
318 if (dq.discardedPolicies) {
319 (*dq.discardedPolicies)[policy] = true;
320 }
321 });
322
a3e7b735 323 d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); });
805f3e03
PL
324 d_lw->registerFunction<void(SuffixMatchNode::*)(boost::variant<string,DNSName, vector<pair<unsigned int,string> > >)>(
325 "add",
326 [](SuffixMatchNode&smn, const boost::variant<string,DNSName,vector<pair<unsigned int,string> > >& in){
327 try {
328 if(auto s = boost::get<string>(&in)) {
329 smn.add(DNSName(*s));
330 }
331 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
dd079764
RG
332 for(const auto& entry : *v)
333 smn.add(DNSName(entry.second));
805f3e03
PL
334 }
335 else {
336 smn.add(boost::get<DNSName>(in));
337 }
338 }
339 catch(std::exception& e) {
340 theL() <<Logger::Error<<e.what()<<endl;
341 }
342 }
343 );
344
a3e7b735 345 d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
c6b99fc1 346 d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString);
a3e7b735 347
70c21c40 348 d_pd.push_back({"policykinds", in_t {
db486de5
PL
349 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction},
350 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop },
351 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN},
352 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA },
353 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate},
354 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom }
355 }});
356
a3e7b735 357 for(const auto& n : QType::names)
70c21c40 358 d_pd.push_back({n.first, n.second});
1921a4c2 359
70c21c40 360 d_pd.push_back({"validationstates", in_t{
1921a4c2
RG
361 {"Indeterminate", Indeterminate },
362 {"Bogus", Bogus },
363 {"Insecure", Insecure },
364 {"Secure", Secure },
365 }});
366
70c21c40 367 d_pd.push_back({"now", &g_now});
9f89a5f1 368
369 d_lw->writeFunction("getMetric", [](const std::string& str) {
370 return DynMetric{getDynMetric(str)};
371 });
372
373 d_lw->registerFunction("inc", &DynMetric::inc);
374 d_lw->registerFunction("incBy", &DynMetric::incBy);
375 d_lw->registerFunction("set", &DynMetric::set);
376 d_lw->registerFunction("get", &DynMetric::get);
b4015453 377
b0b37121
RG
378 d_lw->writeFunction("getStat", [](const std::string& str) {
379 uint64_t result = 0;
380 optional<uint64_t> value = getStatByName(str);
381 if (value) {
382 result = *value;
383 }
384 return result;
385 });
386
b4015453
RG
387 d_lw->writeFunction("getRecursorThreadId", []() {
388 return getRecursorThreadId();
389 });
390
d705aad9
RG
391 d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) {
392 if (g_snmpAgent) {
393 g_snmpAgent->sendCustomTrap(str);
394 }
395 });
70c21c40 396}
a3e7b735 397
70c21c40 398void RecursorLua4::postLoad() {
0a273054 399 d_prerpz = d_lw->readVariable<boost::optional<luacall_t>>("prerpz").get_value_or(0);
a3e7b735 400 d_preresolve = d_lw->readVariable<boost::optional<luacall_t>>("preresolve").get_value_or(0);
401 d_nodata = d_lw->readVariable<boost::optional<luacall_t>>("nodata").get_value_or(0);
402 d_nxdomain = d_lw->readVariable<boost::optional<luacall_t>>("nxdomain").get_value_or(0);
403 d_postresolve = d_lw->readVariable<boost::optional<luacall_t>>("postresolve").get_value_or(0);
f90c7544 404 d_preoutquery = d_lw->readVariable<boost::optional<luacall_t>>("preoutquery").get_value_or(0);
405
406 d_ipfilter = d_lw->readVariable<boost::optional<ipfilter_t>>("ipfilter").get_value_or(0);
81c0afd8 407 d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0);
70fb28d9 408 d_gettag_ffi = d_lw->readVariable<boost::optional<gettag_ffi_t>>("gettag_ffi").get_value_or(0);
808c5ef7 409}
410
5899ee54 411bool RecursorLua4::prerpz(DNSQuestion& dq, int& ret) const
0a273054 412{
ba21fcfe 413 return genhook(d_prerpz, dq, ret);
0a273054
RG
414}
415
5899ee54 416bool RecursorLua4::preresolve(DNSQuestion& dq, int& ret) const
808c5ef7 417{
ba21fcfe 418 return genhook(d_preresolve, dq, ret);
a3e7b735 419}
420
5899ee54 421bool RecursorLua4::nxdomain(DNSQuestion& dq, int& ret) const
a3e7b735 422{
ba21fcfe 423 return genhook(d_nxdomain, dq, ret);
a3e7b735 424}
425
5899ee54 426bool RecursorLua4::nodata(DNSQuestion& dq, int& ret) const
a3e7b735 427{
ba21fcfe 428 return genhook(d_nodata, dq, ret);
a3e7b735 429}
430
5899ee54 431bool RecursorLua4::postresolve(DNSQuestion& dq, int& ret) const
a3e7b735 432{
ba21fcfe 433 return genhook(d_postresolve, dq, ret);
a3e7b735 434}
435
5899ee54 436bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
a3e7b735 437{
ba21fcfe
RG
438 bool variableAnswer = false;
439 bool wantsRPZ = false;
2377be3b 440 RecursorLua4::DNSQuestion dq(ns, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ);
6e505c5e 441 dq.currentRecords = &res;
ba21fcfe
RG
442
443 return genhook(d_preoutquery, dq, ret);
a3e7b735 444}
445
5899ee54 446bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) const
a3e7b735 447{
448 if(d_ipfilter)
f5062066 449 return d_ipfilter(remote, local, dh);
f90c7544 450 return false; // don't block
a3e7b735 451}
452
5899ee54 453unsigned 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, std::string& deviceId) const
81c0afd8 454{
02b47f43 455 if(d_gettag) {
dff843b2 456 auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp);
02b47f43
RG
457
458 if (policyTags) {
459 const auto& tags = std::get<1>(ret);
460 if (tags) {
461 for (const auto& tag : *tags) {
462 policyTags->push_back(tag.second);
463 }
464 }
465 }
5fd2577f 466 const auto dataret = std::get<2>(ret);
05c74122
RG
467 if (dataret) {
468 data = *dataret;
469 }
67e31ebe
RG
470 const auto reqIdret = std::get<3>(ret);
471 if (reqIdret) {
472 requestorId = *reqIdret;
473 }
590388d2
NC
474 const auto deviceIdret = std::get<4>(ret);
475 if (deviceIdret) {
476 deviceId = *deviceIdret;
477 }
02b47f43
RG
478 return std::get<0>(ret);
479 }
81c0afd8 480 return 0;
481}
482
70fb28d9
RG
483struct pdns_ffi_param
484{
485public:
486 pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector<std::string>& policyTags_, const std::map<uint16_t, EDNSOptionView>& ednsOptions_, std::string& requestorId_, std::string& deviceId_, uint32_t& ttlCap_, bool& variable_, bool tcp_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), ttlCap(ttlCap_), variable(variable_), qtype(qtype_), tcp(tcp_)
487 {
488 }
489
490 std::unique_ptr<std::string> qnameStr{nullptr};
491 std::unique_ptr<std::string> localStr{nullptr};
492 std::unique_ptr<std::string> remoteStr{nullptr};
493 std::unique_ptr<std::string> ednssubnetStr{nullptr};
494 std::vector<pdns_ednsoption_t> ednsOptionsVect;
495
496 const DNSName& qname;
497 const ComboAddress& local;
498 const ComboAddress& remote;
499 const Netmask& ednssubnet;
500 std::vector<std::string>& policyTags;
501 const std::map<uint16_t, EDNSOptionView>& ednsOptions;
502 std::string& requestorId;
503 std::string& deviceId;
504 uint32_t& ttlCap;
505 bool& variable;
506
507 unsigned int tag{0};
508 uint16_t qtype;
509 bool tcp;
510};
511
5899ee54 512unsigned int RecursorLua4::gettag_ffi(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, std::string& deviceId, uint32_t& ttlCap, bool& variable) const
70fb28d9
RG
513{
514 if (d_gettag_ffi) {
515 pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, ednsOptions, requestorId, deviceId, ttlCap, variable, tcp);
516
517 auto ret = d_gettag_ffi(&param);
518 if (ret) {
519 data = *ret;
520 }
521
522 return param.tag;
523 }
524 return 0;
525}
526
5899ee54 527bool RecursorLua4::genhook(const luacall_t& func, DNSQuestion& dq, int& ret) const
a3e7b735 528{
529 if(!func)
808c5ef7 530 return false;
a3e7b735 531
6e505c5e
RG
532 if (dq.currentRecords) {
533 dq.records = *dq.currentRecords;
ba21fcfe 534 } else {
6e505c5e 535 dq.records.clear();
ba21fcfe
RG
536 }
537
6e505c5e
RG
538 dq.followupFunction.clear();
539 dq.followupPrefix.clear();
540 dq.followupName.clear();
541 dq.udpQuery.clear();
542 dq.udpAnswer.clear();
543 dq.udpCallback.clear();
ba21fcfe 544
6e505c5e 545 dq.rcode = ret;
1c567515 546 bool handled=func(&dq);
2205c52b 547
a3e7b735 548 if(handled) {
f9e5e573 549loop:;
6e505c5e 550 ret=dq.rcode;
d2f97f2a 551
6e505c5e
RG
552 if(!dq.followupFunction.empty()) {
553 if(dq.followupFunction=="followCNAMERecords") {
554 ret = followCNAMERecords(dq.records, QType(dq.qtype));
a3e7b735 555 }
6e505c5e
RG
556 else if(dq.followupFunction=="getFakeAAAARecords") {
557 ret=getFakeAAAARecords(dq.followupName, dq.followupPrefix, dq.records);
a3e7b735 558 }
6e505c5e
RG
559 else if(dq.followupFunction=="getFakePTRRecords") {
560 ret=getFakePTRRecords(dq.followupName, dq.followupPrefix, dq.records);
a3e7b735 561 }
6e505c5e
RG
562 else if(dq.followupFunction=="udpQueryResponse") {
563 dq.udpAnswer = GenUDPQueryResponse(dq.udpQueryDest, dq.udpQuery);
dd079764
RG
564 auto cbFunc = d_lw->readVariable<boost::optional<luacall_t>>(dq.udpCallback).get_value_or(0);
565 if(!cbFunc) {
d2f97f2a 566 theL()<<Logger::Error<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl;
6b8b26c8 567 return false;
d2f97f2a 568 }
dd079764 569 bool result=cbFunc(&dq);
ba21fcfe 570 if(!result) {
d2f97f2a 571 return false;
572 }
573 goto loop;
f90c7544 574 }
a3e7b735 575 }
6e505c5e
RG
576 if (dq.currentRecords) {
577 *dq.currentRecords = dq.records;
ba21fcfe 578 }
a3e7b735 579 }
580
a3e7b735 581 // see if they added followup work for us too
582 return handled;
583}
3dcc3fde 584
3dcc3fde 585RecursorLua4::~RecursorLua4(){}
70fb28d9
RG
586
587const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref)
588{
589 if (!ref->qnameStr) {
590 ref->qnameStr = std::unique_ptr<std::string>(new std::string(ref->qname.toStringNoDot()));
591 }
592
593 return ref->qnameStr->c_str();
594}
595
596uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref)
597{
598 return ref->qtype;
599}
600
601const char* pdns_ffi_param_get_remote(pdns_ffi_param_t* ref)
602{
603 if (!ref->remoteStr) {
604 ref->remoteStr = std::unique_ptr<std::string>(new std::string(ref->remote.toString()));
605 }
606
607 return ref->remoteStr->c_str();
608}
609
610uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t* ref)
611{
612 return ref->remote.getPort();
613}
614
615const char* pdns_ffi_param_get_local(pdns_ffi_param_t* ref)
616{
617 if (!ref->localStr) {
618 ref->localStr = std::unique_ptr<std::string>(new std::string(ref->local.toString()));
619 }
620
621 return ref->localStr->c_str();
622}
623
624uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t* ref)
625{
626 return ref->local.getPort();
627}
628
629const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t* ref)
630{
631 if (ref->ednssubnet.empty()) {
632 return nullptr;
633 }
634
635 if (!ref->ednssubnetStr) {
636 ref->ednssubnetStr = std::unique_ptr<std::string>(new std::string(ref->ednssubnet.toStringNoMask()));
637 }
638
639 return ref->ednssubnetStr->c_str();
640}
641
642uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t* ref)
643{
644 return ref->ednssubnet.getBits();
645}
646
647static void fill_edns_option(const EDNSOptionView& view, pdns_ednsoption_t& option)
648{
649 option.len = view.size;
650 option.data = nullptr;
651
652 if (view.size > 0) {
653 option.data = view.content;
654 }
655}
656
657size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t* ref, const pdns_ednsoption_t** out)
658{
659 if (ref->ednsOptions.empty()) {
660 return 0;
661 }
662
663 size_t count = ref->ednsOptions.size();
664 ref->ednsOptionsVect.resize(count);
665
666 size_t pos = 0;
667 for (const auto& entry : ref->ednsOptions) {
668 fill_edns_option(entry.second, ref->ednsOptionsVect.at(pos));
669 ref->ednsOptionsVect.at(pos).optionCode = entry.first;
670 pos++;
671 }
672
673 *out = ref->ednsOptionsVect.data();
674
675 return count;
676}
677
678size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out)
679{
680 const auto& it = ref->ednsOptions.find(optionCode);
681 if (it == ref->ednsOptions.cend()) {
682 return 0;
683 }
684
685 /* the current code deals with only one entry per code, but we will fix that */
686 ref->ednsOptionsVect.resize(1);
687 fill_edns_option(it->second, ref->ednsOptionsVect.at(0));
688 ref->ednsOptionsVect.at(0).optionCode = it->first;
689
690 *out = ref->ednsOptionsVect.data();
691
692 return 1;
693}
694
695void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag)
696{
697 ref->tag = tag;
698}
699
700void pdns_ffi_param_add_policytag(pdns_ffi_param_t *ref, const char* name)
701{
702 ref->policyTags.push_back(std::string(name));
703}
704
705void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name)
706{
707 ref->requestorId = std::string(name);
708}
709
710void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name)
711{
712 ref->deviceId = std::string(name);
713}
714
715void pdns_ffi_param_set_deviceid(pdns_ffi_param_t* ref, size_t len, const void* name)
716{
717 ref->deviceId = std::string(reinterpret_cast<const char*>(name), len);
718}
719
720void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable)
721{
722 ref->variable = variable;
723}
724
725void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl)
726{
727 ref->ttlCap = ttl;
728}