]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lua-recursor4.cc
Merge pull request #6825 from klaus3000/disable-signed-NOTIFYs
[thirdparty/pdns.git] / pdns / lua-recursor4.cc
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 */
22 #include "lua-recursor4.hh"
23 #include <fstream>
24 #include "logger.hh"
25 #include "dnsparser.hh"
26 #include "syncres.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>
34
35 RecursorLua4::RecursorLua4() { prepareContext(); }
36
37 static 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) {
43 auto rec = getRR<CNAMERecordContent>(rr);
44 if(rec) {
45 target=rec->getTarget();
46 break;
47 }
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
62 static 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) {
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 }
80 }
81 }
82 return rcode;
83 }
84
85 static 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 +=
98 std::to_string(stoll(parts[n*2], 0, 16) + 16*stoll(parts[n*2+1], 0, 16));
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
115 boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const
116 {
117 if (dh)
118 return *dh;
119 return boost::optional<dnsheader>();
120 }
121
122 vector<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
132 bool 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
141 vector<pair<uint16_t, string> > RecursorLua4::DNSQuestion::getEDNSOptions() const
142 {
143 if(ednsOptions)
144 return *ednsOptions;
145 else
146 return vector<pair<uint16_t,string>>();
147 }
148
149 boost::optional<string> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const
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
159 boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() const
160 {
161 if(ednsOptions) {
162 for(const auto& o : *ednsOptions) {
163 if(o.first==EDNSOptionCode::ECS) {
164 EDNSSubnetOpts eso;
165 if(getEDNSSubnetOptsFromString(o.second, &eso))
166 return eso.source;
167 else
168 break;
169 }
170 }
171 }
172 return boost::optional<Netmask>();
173 }
174
175
176 vector<pair<int, DNSRecord> > RecursorLua4::DNSQuestion::getRecords() const
177 {
178 vector<pair<int, DNSRecord> > ret;
179 int num=1;
180 for(const auto& r : records) {
181 ret.push_back({num++, r});
182 }
183 return ret;
184 }
185 void RecursorLua4::DNSQuestion::setRecords(const vector<pair<int, DNSRecord> >& recs)
186 {
187 records.clear();
188 for(const auto& p : recs) {
189 records.push_back(p.second);
190 }
191 }
192
193 void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name)
194 {
195 DNSRecord dr;
196 dr.d_name=name ? DNSName(*name) : qname;
197 dr.d_ttl=ttl.get_value_or(3600);
198 dr.d_type = type;
199 dr.d_place = place;
200 dr.d_content = DNSRecordContent::mastermake(type, 1, content);
201 records.push_back(dr);
202 }
203
204 void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name)
205 {
206 addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name);
207 }
208
209 struct DynMetric
210 {
211 std::atomic<unsigned long>* ptr;
212 void inc() { (*ptr)++; }
213 void incBy(unsigned int by) { (*ptr)+= by; }
214 unsigned long get() { return *ptr; }
215 void set(unsigned long val) { *ptr =val; }
216 };
217
218 void RecursorLua4::postPrepareContext()
219 {
220 d_lw->registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName& { return dq.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; });
221 d_lw->registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
222 d_lw->registerMember<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion& dq) -> bool { return dq.isTcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
223 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.local; }, [](DNSQuestion& dq, const ComboAddress& newLocal) { (void) newLocal; });
224 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.remote; }, [](DNSQuestion& dq, const ComboAddress& newRemote) { (void) newRemote; });
225 d_lw->registerMember<vState (DNSQuestion::*)>("validationState", [](const DNSQuestion& dq) -> vState { return dq.validationState; }, [](DNSQuestion& dq, vState newState) { (void) newState; });
226
227 d_lw->registerMember<bool (DNSQuestion::*)>("variable", [](const DNSQuestion& dq) -> bool { return dq.variable; }, [](DNSQuestion& dq, bool newVariable) { dq.variable = newVariable; });
228 d_lw->registerMember<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion& dq) -> bool { return dq.wantsRPZ; }, [](DNSQuestion& dq, bool newWantsRPZ) { dq.wantsRPZ = newWantsRPZ; });
229 d_lw->registerMember<bool (DNSQuestion::*)>("logResponse", [](const DNSQuestion& dq) -> bool { return dq.logResponse; }, [](DNSQuestion& dq, bool newLogResponse) { dq.logResponse = newLogResponse; });
230
231 d_lw->registerMember("rcode", &DNSQuestion::rcode);
232 d_lw->registerMember("tag", &DNSQuestion::tag);
233 d_lw->registerMember("requestorId", &DNSQuestion::requestorId);
234 d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction);
235 d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix);
236 d_lw->registerMember("followupName", &DNSQuestion::followupName);
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);
242 d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy);
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 });
252 d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind);
253 d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl);
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();
259 },
260 [](DNSFilterEngine::Policy& pol, const std::string& content) {
261 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
262 pol.d_custom = DNSRecordContent::mastermake(QType::CNAME, 1, content);
263 }
264 );
265 d_lw->registerFunction("getDH", &DNSQuestion::getDH);
266 d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions);
267 d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption);
268 d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet);
269 d_lw->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags);
270 d_lw->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag);
271 d_lw->registerMember("name", &DNSRecord::d_name);
272 d_lw->registerMember("type", &DNSRecord::d_type);
273 d_lw->registerMember("ttl", &DNSRecord::d_ttl);
274 d_lw->registerMember("place", &DNSRecord::d_place);
275
276 d_lw->registerMember("size", &EDNSOptionViewValue::size);
277 d_lw->registerFunction<std::string(EDNSOptionViewValue::*)()>("getContent", [](const EDNSOptionViewValue& value) { return std::string(value.content, value.size); });
278 d_lw->registerFunction<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView& option) { return option.values.size(); });
279 d_lw->registerFunction<std::vector<std::pair<int, string>>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView& option) {
280 std::vector<std::pair<int, string> > values;
281 for (const auto& value : option.values) {
282 values.push_back(std::make_pair(values.size(), std::string(value.content, value.size)));
283 }
284 return values;
285 });
286
287 /* pre 4.2 API compatibility, when we had only one value for a given EDNS option */
288 d_lw->registerMember<uint16_t(EDNSOptionView::*)>("size", [](const EDNSOptionView& option) -> uint16_t {
289 uint16_t result = 0;
290
291 if (!option.values.empty()) {
292 result = option.values.at(0).size;
293 }
294 return result;
295 },
296 [](EDNSOptionView& option, uint16_t newSize) { (void) newSize; });
297 d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) {
298 if (option.values.empty()) {
299 return std::string();
300 }
301 return std::string(option.values.at(0).content, option.values.at(0).size); });
302
303 d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); });
304 d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
305 boost::optional<ComboAddress> ret;
306
307 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content))
308 ret=rec->getCA(53);
309 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content))
310 ret=aaaarec->getCA(53);
311 return ret;
312 });
313
314
315 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); });
316 d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer);
317 d_lw->registerFunction("addRecord", &DNSQuestion::addRecord);
318 d_lw->registerFunction("getRecords", &DNSQuestion::getRecords);
319 d_lw->registerFunction("setRecords", &DNSQuestion::setRecords);
320
321 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->push_back(tag); } });
322 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) {
323 if (dq.policyTags) {
324 dq.policyTags->clear();
325 for (const auto& tag : tags) {
326 dq.policyTags->push_back(tag.second);
327 }
328 }
329 });
330 d_lw->registerFunction<std::vector<std::pair<int, std::string> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) {
331 std::vector<std::pair<int, std::string> > ret;
332 if (dq.policyTags) {
333 int count = 1;
334 for (const auto& tag : *dq.policyTags) {
335 ret.push_back({count++, tag});
336 }
337 }
338 return ret;
339 });
340
341 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("discardPolicy", [](DNSQuestion& dq, const std::string& policy) {
342 if (dq.discardedPolicies) {
343 (*dq.discardedPolicies)[policy] = true;
344 }
345 });
346
347 d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); });
348 d_lw->registerFunction<void(SuffixMatchNode::*)(boost::variant<string,DNSName, vector<pair<unsigned int,string> > >)>(
349 "add",
350 [](SuffixMatchNode&smn, const boost::variant<string,DNSName,vector<pair<unsigned int,string> > >& in){
351 try {
352 if(auto s = boost::get<string>(&in)) {
353 smn.add(DNSName(*s));
354 }
355 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
356 for(const auto& entry : *v)
357 smn.add(DNSName(entry.second));
358 }
359 else {
360 smn.add(boost::get<DNSName>(in));
361 }
362 }
363 catch(std::exception& e) {
364 g_log <<Logger::Error<<e.what()<<endl;
365 }
366 }
367 );
368
369 d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
370 d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString);
371
372 d_pd.push_back({"policykinds", in_t {
373 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction},
374 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop },
375 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN},
376 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA },
377 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate},
378 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom }
379 }});
380
381 for(const auto& n : QType::names)
382 d_pd.push_back({n.first, n.second});
383
384 d_pd.push_back({"validationstates", in_t{
385 {"Indeterminate", Indeterminate },
386 {"Bogus", Bogus },
387 {"Insecure", Insecure },
388 {"Secure", Secure },
389 }});
390
391 d_pd.push_back({"now", &g_now});
392
393 d_lw->writeFunction("getMetric", [](const std::string& str) {
394 return DynMetric{getDynMetric(str)};
395 });
396
397 d_lw->registerFunction("inc", &DynMetric::inc);
398 d_lw->registerFunction("incBy", &DynMetric::incBy);
399 d_lw->registerFunction("set", &DynMetric::set);
400 d_lw->registerFunction("get", &DynMetric::get);
401
402 d_lw->writeFunction("getStat", [](const std::string& str) {
403 uint64_t result = 0;
404 optional<uint64_t> value = getStatByName(str);
405 if (value) {
406 result = *value;
407 }
408 return result;
409 });
410
411 d_lw->writeFunction("getRecursorThreadId", []() {
412 return getRecursorThreadId();
413 });
414
415 d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) {
416 if (g_snmpAgent) {
417 g_snmpAgent->sendCustomTrap(str);
418 }
419 });
420 }
421
422 void RecursorLua4::postLoad() {
423 d_prerpz = d_lw->readVariable<boost::optional<luacall_t>>("prerpz").get_value_or(0);
424 d_preresolve = d_lw->readVariable<boost::optional<luacall_t>>("preresolve").get_value_or(0);
425 d_nodata = d_lw->readVariable<boost::optional<luacall_t>>("nodata").get_value_or(0);
426 d_nxdomain = d_lw->readVariable<boost::optional<luacall_t>>("nxdomain").get_value_or(0);
427 d_postresolve = d_lw->readVariable<boost::optional<luacall_t>>("postresolve").get_value_or(0);
428 d_preoutquery = d_lw->readVariable<boost::optional<luacall_t>>("preoutquery").get_value_or(0);
429 d_maintenance = d_lw->readVariable<boost::optional<luamaintenance_t>>("maintenance").get_value_or(0);
430
431 d_ipfilter = d_lw->readVariable<boost::optional<ipfilter_t>>("ipfilter").get_value_or(0);
432 d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0);
433 d_gettag_ffi = d_lw->readVariable<boost::optional<gettag_ffi_t>>("gettag_ffi").get_value_or(0);
434 }
435
436 void RecursorLua4::maintenance() const
437 {
438 if (d_maintenance) {
439 d_maintenance();
440 }
441 }
442
443 bool RecursorLua4::prerpz(DNSQuestion& dq, int& ret) const
444 {
445 return genhook(d_prerpz, dq, ret);
446 }
447
448 bool RecursorLua4::preresolve(DNSQuestion& dq, int& ret) const
449 {
450 return genhook(d_preresolve, dq, ret);
451 }
452
453 bool RecursorLua4::nxdomain(DNSQuestion& dq, int& ret) const
454 {
455 return genhook(d_nxdomain, dq, ret);
456 }
457
458 bool RecursorLua4::nodata(DNSQuestion& dq, int& ret) const
459 {
460 return genhook(d_nodata, dq, ret);
461 }
462
463 bool RecursorLua4::postresolve(DNSQuestion& dq, int& ret) const
464 {
465 return genhook(d_postresolve, dq, ret);
466 }
467
468 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
469 {
470 bool variableAnswer = false;
471 bool wantsRPZ = false;
472 bool logQuery = false;
473 RecursorLua4::DNSQuestion dq(ns, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ, logQuery);
474 dq.currentRecords = &res;
475
476 return genhook(d_preoutquery, dq, ret);
477 }
478
479 bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) const
480 {
481 if(d_ipfilter)
482 return d_ipfilter(remote, local, dh);
483 return false; // don't block
484 }
485
486 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) const
487 {
488 if(d_gettag) {
489 auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp);
490
491 if (policyTags) {
492 const auto& tags = std::get<1>(ret);
493 if (tags) {
494 for (const auto& tag : *tags) {
495 policyTags->push_back(tag.second);
496 }
497 }
498 }
499 const auto dataret = std::get<2>(ret);
500 if (dataret) {
501 data = *dataret;
502 }
503 const auto reqIdret = std::get<3>(ret);
504 if (reqIdret) {
505 requestorId = *reqIdret;
506 }
507 const auto deviceIdret = std::get<4>(ret);
508 if (deviceIdret) {
509 deviceId = *deviceIdret;
510 }
511 return std::get<0>(ret);
512 }
513 return 0;
514 }
515
516 struct pdns_ffi_param
517 {
518 public:
519 pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector<std::string>& policyTags_, const EDNSOptionViewMap& ednsOptions_, std::string& requestorId_, std::string& deviceId_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), qtype(qtype_), tcp(tcp_)
520 {
521 }
522
523 std::unique_ptr<std::string> qnameStr{nullptr};
524 std::unique_ptr<std::string> localStr{nullptr};
525 std::unique_ptr<std::string> remoteStr{nullptr};
526 std::unique_ptr<std::string> ednssubnetStr{nullptr};
527 std::vector<pdns_ednsoption_t> ednsOptionsVect;
528
529 const DNSName& qname;
530 const ComboAddress& local;
531 const ComboAddress& remote;
532 const Netmask& ednssubnet;
533 std::vector<std::string>& policyTags;
534 const EDNSOptionViewMap& ednsOptions;
535 std::string& requestorId;
536 std::string& deviceId;
537 uint32_t& ttlCap;
538 bool& variable;
539 bool& logQuery;
540
541 unsigned int tag{0};
542 uint16_t qtype;
543 bool tcp;
544 };
545
546 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, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, uint32_t& ttlCap, bool& variable, bool& logQuery) const
547 {
548 if (d_gettag_ffi) {
549 pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, ednsOptions, requestorId, deviceId, ttlCap, variable, tcp, logQuery);
550
551 auto ret = d_gettag_ffi(&param);
552 if (ret) {
553 data = *ret;
554 }
555
556 return param.tag;
557 }
558 return 0;
559 }
560
561 bool RecursorLua4::genhook(const luacall_t& func, DNSQuestion& dq, int& ret) const
562 {
563 if(!func)
564 return false;
565
566 if (dq.currentRecords) {
567 dq.records = *dq.currentRecords;
568 } else {
569 dq.records.clear();
570 }
571
572 dq.followupFunction.clear();
573 dq.followupPrefix.clear();
574 dq.followupName.clear();
575 dq.udpQuery.clear();
576 dq.udpAnswer.clear();
577 dq.udpCallback.clear();
578
579 dq.rcode = ret;
580 bool handled=func(&dq);
581
582 if(handled) {
583 loop:;
584 ret=dq.rcode;
585
586 if(!dq.followupFunction.empty()) {
587 if(dq.followupFunction=="followCNAMERecords") {
588 ret = followCNAMERecords(dq.records, QType(dq.qtype));
589 }
590 else if(dq.followupFunction=="getFakeAAAARecords") {
591 ret=getFakeAAAARecords(dq.followupName, dq.followupPrefix, dq.records);
592 }
593 else if(dq.followupFunction=="getFakePTRRecords") {
594 ret=getFakePTRRecords(dq.followupName, dq.followupPrefix, dq.records);
595 }
596 else if(dq.followupFunction=="udpQueryResponse") {
597 dq.udpAnswer = GenUDPQueryResponse(dq.udpQueryDest, dq.udpQuery);
598 auto cbFunc = d_lw->readVariable<boost::optional<luacall_t>>(dq.udpCallback).get_value_or(0);
599 if(!cbFunc) {
600 g_log<<Logger::Error<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl;
601 return false;
602 }
603 bool result=cbFunc(&dq);
604 if(!result) {
605 return false;
606 }
607 goto loop;
608 }
609 }
610 if (dq.currentRecords) {
611 *dq.currentRecords = dq.records;
612 }
613 }
614
615 // see if they added followup work for us too
616 return handled;
617 }
618
619 RecursorLua4::~RecursorLua4(){}
620
621 const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref)
622 {
623 if (!ref->qnameStr) {
624 ref->qnameStr = std::unique_ptr<std::string>(new std::string(ref->qname.toStringNoDot()));
625 }
626
627 return ref->qnameStr->c_str();
628 }
629
630 void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t* ref, const char** qname, size_t* qnameSize)
631 {
632 const auto& storage = ref->qname.getStorage();
633 *qname = storage.data();
634 *qnameSize = storage.size();
635 }
636
637 uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref)
638 {
639 return ref->qtype;
640 }
641
642 const char* pdns_ffi_param_get_remote(pdns_ffi_param_t* ref)
643 {
644 if (!ref->remoteStr) {
645 ref->remoteStr = std::unique_ptr<std::string>(new std::string(ref->remote.toString()));
646 }
647
648 return ref->remoteStr->c_str();
649 }
650
651 static void pdns_ffi_comboaddress_to_raw(const ComboAddress& ca, const void** addr, size_t* addrSize)
652 {
653 if (ca.isIPv4()) {
654 *addr = &ca.sin4.sin_addr.s_addr;
655 *addrSize = sizeof(ca.sin4.sin_addr.s_addr);
656 }
657 else {
658 *addr = &ca.sin6.sin6_addr.s6_addr;
659 *addrSize = sizeof(ca.sin6.sin6_addr.s6_addr);
660 }
661 }
662
663 void pdns_ffi_param_get_remote_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize)
664 {
665 pdns_ffi_comboaddress_to_raw(ref->remote, addr, addrSize);
666 }
667
668 uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t* ref)
669 {
670 return ref->remote.getPort();
671 }
672
673 const char* pdns_ffi_param_get_local(pdns_ffi_param_t* ref)
674 {
675 if (!ref->localStr) {
676 ref->localStr = std::unique_ptr<std::string>(new std::string(ref->local.toString()));
677 }
678
679 return ref->localStr->c_str();
680 }
681
682 void pdns_ffi_param_get_local_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize)
683 {
684 pdns_ffi_comboaddress_to_raw(ref->local, addr, addrSize);
685 }
686
687 uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t* ref)
688 {
689 return ref->local.getPort();
690 }
691
692 const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t* ref)
693 {
694 if (ref->ednssubnet.empty()) {
695 return nullptr;
696 }
697
698 if (!ref->ednssubnetStr) {
699 ref->ednssubnetStr = std::unique_ptr<std::string>(new std::string(ref->ednssubnet.toStringNoMask()));
700 }
701
702 return ref->ednssubnetStr->c_str();
703 }
704
705 void pdns_ffi_param_get_edns_cs_raw(pdns_ffi_param_t* ref, const void** net, size_t* netSize)
706 {
707 if (ref->ednssubnet.empty()) {
708 *net = nullptr;
709 *netSize = 0;
710 return;
711 }
712
713 pdns_ffi_comboaddress_to_raw(ref->ednssubnet.getNetwork(), net, netSize);
714 }
715
716 uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t* ref)
717 {
718 return ref->ednssubnet.getBits();
719 }
720
721 static void fill_edns_option(const EDNSOptionViewValue& value, pdns_ednsoption_t& option)
722 {
723 option.len = value.size;
724 option.data = nullptr;
725
726 if (value.size > 0) {
727 option.data = value.content;
728 }
729 }
730
731 size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t* ref, const pdns_ednsoption_t** out)
732 {
733 if (ref->ednsOptions.empty()) {
734 return 0;
735 }
736
737 size_t totalCount = 0;
738 for (const auto& option : ref->ednsOptions) {
739 totalCount += option.second.values.size();
740 }
741
742 ref->ednsOptionsVect.resize(totalCount);
743
744 size_t pos = 0;
745 for (const auto& option : ref->ednsOptions) {
746 for (const auto& entry : option.second.values) {
747 fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
748 ref->ednsOptionsVect.at(pos).optionCode = option.first;
749 pos++;
750 }
751 }
752
753 *out = ref->ednsOptionsVect.data();
754
755 return totalCount;
756 }
757
758 size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out)
759 {
760 const auto& it = ref->ednsOptions.find(optionCode);
761 if (it == ref->ednsOptions.cend() || it->second.values.empty()) {
762 return 0;
763 }
764
765 ref->ednsOptionsVect.resize(it->second.values.size());
766
767 size_t pos = 0;
768 for (const auto& entry : it->second.values) {
769 fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
770 ref->ednsOptionsVect.at(pos).optionCode = optionCode;
771 pos++;
772 }
773
774 *out = ref->ednsOptionsVect.data();
775
776 return pos;
777 }
778
779 void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag)
780 {
781 ref->tag = tag;
782 }
783
784 void pdns_ffi_param_add_policytag(pdns_ffi_param_t *ref, const char* name)
785 {
786 ref->policyTags.push_back(std::string(name));
787 }
788
789 void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name)
790 {
791 ref->requestorId = std::string(name);
792 }
793
794 void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name)
795 {
796 ref->deviceId = std::string(name);
797 }
798
799 void pdns_ffi_param_set_deviceid(pdns_ffi_param_t* ref, size_t len, const void* name)
800 {
801 ref->deviceId = std::string(reinterpret_cast<const char*>(name), len);
802 }
803
804 void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable)
805 {
806 ref->variable = variable;
807 }
808
809 void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl)
810 {
811 ref->ttlCap = ttl;
812 }
813
814 void pdns_ffi_param_set_log_query(pdns_ffi_param_t* ref, bool logQuery)
815 {
816 ref->logQuery = logQuery;
817 }