]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lua-recursor4.cc
Merge pull request #8923 from atoomic/daemon-reload
[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 getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
38 {
39 int rcode=directResolve(qname, QType(QType::A), 1, ret);
40
41 ComboAddress prefixAddress(prefix);
42
43 // Remove double CNAME records
44 std::set<DNSName> seenCNAMEs;
45 ret.erase(std::remove_if(
46 ret.begin(),
47 ret.end(),
48 [&seenCNAMEs](DNSRecord& rr) {
49 if (rr.d_type == QType::CNAME) {
50 auto target = getRR<CNAMERecordContent>(rr);
51 if (target == nullptr) {
52 return false;
53 }
54 if (seenCNAMEs.count(target->getTarget()) > 0) {
55 // We've had this CNAME before, remove it
56 return true;
57 }
58 seenCNAMEs.insert(target->getTarget());
59 }
60 return false;
61 }),
62 ret.end());
63
64 bool seenA = false;
65 for(DNSRecord& rr : ret)
66 {
67 if(rr.d_type == QType::A && rr.d_place==DNSResourceRecord::ANSWER) {
68 if(auto rec = getRR<ARecordContent>(rr)) {
69 ComboAddress ipv4(rec->getCA());
70 uint32_t tmp;
71 memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4);
72 // tmp=htonl(tmp);
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;
76 }
77 seenA = true;
78 }
79 }
80
81 if (seenA) {
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(
85 ret.begin(),
86 ret.end(),
87 [](DNSRecord& rr) {
88 return (rr.d_type == QType::SOA && rr.d_place==DNSResourceRecord::AUTHORITY);
89 }),
90 ret.end());
91 }
92 return rcode;
93 }
94
95 static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
96 {
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 */
99 ret.clear();
100 vector<string> parts = qname.getRawLabels();
101
102 if(parts.size() < 8)
103 return -1;
104
105 string newquery;
106 for(int n = 0; n < 4; ++n) {
107 newquery +=
108 std::to_string(stoll(parts[n*2], 0, 16) + 16*stoll(parts[n*2+1], 0, 16));
109 newquery.append(1,'.');
110 }
111 newquery += "in-addr.arpa.";
112
113
114 DNSRecord rr;
115 rr.d_name = qname;
116 rr.d_type = QType::CNAME;
117 rr.d_content = std::make_shared<CNAMERecordContent>(newquery);
118 ret.push_back(rr);
119
120 int rcode = directResolve(DNSName(newquery), QType(QType::PTR), 1, ret);
121
122 return rcode;
123
124 }
125
126 boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const
127 {
128 if (dh)
129 return *dh;
130 return boost::optional<dnsheader>();
131 }
132
133 vector<string> RecursorLua4::DNSQuestion::getEDNSFlags() const
134 {
135 vector<string> ret;
136 if (ednsFlags) {
137 if (*ednsFlags & EDNSOpts::DNSSECOK)
138 ret.push_back("DO");
139 }
140 return ret;
141 }
142
143 bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag) const
144 {
145 if (ednsFlags) {
146 if (flag == "DO" && (*ednsFlags & EDNSOpts::DNSSECOK))
147 return true;
148 }
149 return false;
150 }
151
152 vector<pair<uint16_t, string> > RecursorLua4::DNSQuestion::getEDNSOptions() const
153 {
154 if(ednsOptions)
155 return *ednsOptions;
156 else
157 return vector<pair<uint16_t,string>>();
158 }
159
160 boost::optional<string> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const
161 {
162 if(ednsOptions)
163 for(const auto& o : *ednsOptions)
164 if(o.first==code)
165 return o.second;
166
167 return boost::optional<string>();
168 }
169
170 boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() const
171 {
172 if(ednsOptions) {
173 for(const auto& o : *ednsOptions) {
174 if(o.first==EDNSOptionCode::ECS) {
175 EDNSSubnetOpts eso;
176 if(getEDNSSubnetOptsFromString(o.second, &eso))
177 return eso.source;
178 else
179 break;
180 }
181 }
182 }
183 return boost::optional<Netmask>();
184 }
185
186 std::vector<std::pair<int, ProxyProtocolValue>> RecursorLua4::DNSQuestion::getProxyProtocolValues() const
187 {
188 std::vector<std::pair<int, ProxyProtocolValue>> result;
189 if (proxyProtocolValues) {
190 result.reserve(proxyProtocolValues->size());
191
192 int idx = 1;
193 for (const auto& value: *proxyProtocolValues) {
194 result.push_back({ idx++, value });
195 }
196 }
197
198 return result;
199 }
200
201 vector<pair<int, DNSRecord> > RecursorLua4::DNSQuestion::getRecords() const
202 {
203 vector<pair<int, DNSRecord> > ret;
204 int num=1;
205 for(const auto& r : records) {
206 ret.push_back({num++, r});
207 }
208 return ret;
209 }
210 void RecursorLua4::DNSQuestion::setRecords(const vector<pair<int, DNSRecord> >& recs)
211 {
212 records.clear();
213 for(const auto& p : recs) {
214 records.push_back(p.second);
215 }
216 }
217
218 void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name)
219 {
220 DNSRecord dr;
221 dr.d_name=name ? DNSName(*name) : qname;
222 dr.d_ttl=ttl.get_value_or(3600);
223 dr.d_type = type;
224 dr.d_place = place;
225 dr.d_content = DNSRecordContent::mastermake(type, 1, content);
226 records.push_back(dr);
227 }
228
229 void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name)
230 {
231 addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name);
232 }
233
234 struct DynMetric
235 {
236 std::atomic<unsigned long>* ptr;
237 void inc() { (*ptr)++; }
238 void incBy(unsigned int by) { (*ptr)+= by; }
239 unsigned long get() { return *ptr; }
240 void set(unsigned long val) { *ptr =val; }
241 };
242
243 void RecursorLua4::postPrepareContext()
244 {
245 d_lw->registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName& { return dq.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; });
246 d_lw->registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
247 d_lw->registerMember<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion& dq) -> bool { return dq.isTcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
248 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.local; }, [](DNSQuestion& dq, const ComboAddress& newLocal) { (void) newLocal; });
249 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.remote; }, [](DNSQuestion& dq, const ComboAddress& newRemote) { (void) newRemote; });
250 d_lw->registerMember<vState (DNSQuestion::*)>("validationState", [](const DNSQuestion& dq) -> vState { return dq.validationState; }, [](DNSQuestion& dq, vState newState) { (void) newState; });
251
252 d_lw->registerMember<bool (DNSQuestion::*)>("variable", [](const DNSQuestion& dq) -> bool { return dq.variable; }, [](DNSQuestion& dq, bool newVariable) { dq.variable = newVariable; });
253 d_lw->registerMember<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion& dq) -> bool { return dq.wantsRPZ; }, [](DNSQuestion& dq, bool newWantsRPZ) { dq.wantsRPZ = newWantsRPZ; });
254 d_lw->registerMember<bool (DNSQuestion::*)>("logResponse", [](const DNSQuestion& dq) -> bool { return dq.logResponse; }, [](DNSQuestion& dq, bool newLogResponse) { dq.logResponse = newLogResponse; });
255
256 d_lw->registerMember("rcode", &DNSQuestion::rcode);
257 d_lw->registerMember("tag", &DNSQuestion::tag);
258 d_lw->registerMember("requestorId", &DNSQuestion::requestorId);
259 d_lw->registerMember("deviceId", &DNSQuestion::deviceId);
260 d_lw->registerMember("deviceName", &DNSQuestion::deviceName);
261 d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction);
262 d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix);
263 d_lw->registerMember("followupName", &DNSQuestion::followupName);
264 d_lw->registerMember("data", &DNSQuestion::data);
265 d_lw->registerMember("udpQuery", &DNSQuestion::udpQuery);
266 d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer);
267 d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest);
268 d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback);
269 d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy);
270 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyName",
271 [](const DNSFilterEngine::Policy& pol) -> std::string {
272 return pol.getName();
273 },
274 [](DNSFilterEngine::Policy& pol, const std::string& name) {
275 pol.setName(name);
276 });
277 d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind);
278 d_lw->registerMember("policyType", &DNSFilterEngine::Policy::d_type);
279 d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl);
280 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyCustom",
281 [](const DNSFilterEngine::Policy& pol) -> std::string {
282 std::string result;
283 if (pol.d_kind != DNSFilterEngine::PolicyKind::Custom) {
284 return result;
285 }
286
287 for (const auto& dr : pol.d_custom) {
288 if (!result.empty()) {
289 result += "\n";
290 }
291 result += dr->getZoneRepresentation();
292 }
293
294 return result;
295 },
296 [](DNSFilterEngine::Policy& pol, const std::string& content) {
297 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
298 pol.d_custom.clear();
299 pol.d_custom.push_back(DNSRecordContent::mastermake(QType::CNAME, QClass::IN, content));
300 }
301 );
302 d_lw->registerFunction("getDH", &DNSQuestion::getDH);
303 d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions);
304 d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption);
305 d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet);
306 d_lw->registerFunction("getProxyProtocolValues", &DNSQuestion::getProxyProtocolValues);
307 d_lw->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags);
308 d_lw->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag);
309 d_lw->registerMember("name", &DNSRecord::d_name);
310 d_lw->registerMember("type", &DNSRecord::d_type);
311 d_lw->registerMember("ttl", &DNSRecord::d_ttl);
312 d_lw->registerMember("place", &DNSRecord::d_place);
313
314 d_lw->registerMember("size", &EDNSOptionViewValue::size);
315 d_lw->registerFunction<std::string(EDNSOptionViewValue::*)()>("getContent", [](const EDNSOptionViewValue& value) { return std::string(value.content, value.size); });
316 d_lw->registerFunction<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView& option) { return option.values.size(); });
317 d_lw->registerFunction<std::vector<string>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView& option) {
318 std::vector<string> values;
319 for (const auto& value : option.values) {
320 values.push_back(std::string(value.content, value.size));
321 }
322 return values;
323 });
324
325 /* pre 4.2 API compatibility, when we had only one value for a given EDNS option */
326 d_lw->registerMember<uint16_t(EDNSOptionView::*)>("size", [](const EDNSOptionView& option) -> uint16_t {
327 uint16_t result = 0;
328
329 if (!option.values.empty()) {
330 result = option.values.at(0).size;
331 }
332 return result;
333 },
334 [](EDNSOptionView& option, uint16_t newSize) { (void) newSize; });
335 d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) {
336 if (option.values.empty()) {
337 return std::string();
338 }
339 return std::string(option.values.at(0).content, option.values.at(0).size); });
340
341 d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); });
342 d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
343 boost::optional<ComboAddress> ret;
344
345 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content))
346 ret=rec->getCA(53);
347 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content))
348 ret=aaaarec->getCA(53);
349 return ret;
350 });
351
352 d_lw->registerFunction<const ProxyProtocolValue, std::string()>("getContent", [](const ProxyProtocolValue& value) { return value.content; });
353 d_lw->registerFunction<const ProxyProtocolValue, uint8_t()>("getType", [](const ProxyProtocolValue& value) { return value.type; });
354
355 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); });
356 d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer);
357 d_lw->registerFunction("addRecord", &DNSQuestion::addRecord);
358 d_lw->registerFunction("getRecords", &DNSQuestion::getRecords);
359 d_lw->registerFunction("setRecords", &DNSQuestion::setRecords);
360
361 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->insert(tag); } });
362 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) {
363 if (dq.policyTags) {
364 dq.policyTags->clear();
365 dq.policyTags->reserve(tags.size());
366 for (const auto& tag : tags) {
367 dq.policyTags->insert(tag.second);
368 }
369 }
370 });
371 d_lw->registerFunction<std::vector<std::pair<int, std::string> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) {
372 std::vector<std::pair<int, std::string> > ret;
373 if (dq.policyTags) {
374 int count = 1;
375 ret.reserve(dq.policyTags->size());
376 for (const auto& tag : *dq.policyTags) {
377 ret.push_back({count++, tag});
378 }
379 }
380 return ret;
381 });
382
383 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("discardPolicy", [](DNSQuestion& dq, const std::string& policy) {
384 if (dq.discardedPolicies) {
385 (*dq.discardedPolicies)[policy] = true;
386 }
387 });
388
389 d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); });
390 d_lw->registerFunction<void(SuffixMatchNode::*)(boost::variant<string,DNSName, vector<pair<unsigned int,string> > >)>(
391 "add",
392 [](SuffixMatchNode&smn, const boost::variant<string,DNSName,vector<pair<unsigned int,string> > >& in){
393 try {
394 if(auto s = boost::get<string>(&in)) {
395 smn.add(DNSName(*s));
396 }
397 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
398 for(const auto& entry : *v)
399 smn.add(DNSName(entry.second));
400 }
401 else {
402 smn.add(boost::get<DNSName>(in));
403 }
404 }
405 catch(std::exception& e) {
406 g_log <<Logger::Error<<e.what()<<endl;
407 }
408 }
409 );
410
411 d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
412 d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString);
413
414 d_pd.push_back({"policykinds", in_t {
415 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction},
416 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop },
417 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN},
418 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA },
419 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate},
420 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom }
421 }});
422
423 for(const auto& n : QType::names)
424 d_pd.push_back({n.first, n.second});
425
426 d_pd.push_back({"validationstates", in_t{
427 {"Indeterminate", Indeterminate },
428 {"Bogus", Bogus },
429 {"Insecure", Insecure },
430 {"Secure", Secure },
431 }});
432
433 d_pd.push_back({"now", &g_now});
434
435 d_lw->writeFunction("getMetric", [](const std::string& str) {
436 return DynMetric{getDynMetric(str)};
437 });
438
439 d_lw->registerFunction("inc", &DynMetric::inc);
440 d_lw->registerFunction("incBy", &DynMetric::incBy);
441 d_lw->registerFunction("set", &DynMetric::set);
442 d_lw->registerFunction("get", &DynMetric::get);
443
444 d_lw->writeFunction("getStat", [](const std::string& str) {
445 uint64_t result = 0;
446 optional<uint64_t> value = getStatByName(str);
447 if (value) {
448 result = *value;
449 }
450 return result;
451 });
452
453 d_lw->writeFunction("getRecursorThreadId", []() {
454 return getRecursorThreadId();
455 });
456
457 d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) {
458 if (g_snmpAgent) {
459 g_snmpAgent->sendCustomTrap(str);
460 }
461 });
462
463 d_lw->writeFunction("getregisteredname", [](const DNSName &dname) {
464 return getRegisteredName(dname);
465 });
466 }
467
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);
476
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);
480 }
481
482 void RecursorLua4::getFeatures(Features & features) {
483 // Add key-values pairs below.
484 // Make sure you add string values explicity converted to string.
485 // e.g. features.push_back(make_pair("somekey", string("stringvalue"));
486 // Both int and double end up as a lua number type.
487 features.push_back(make_pair("PR8001_devicename", true));
488 }
489
490 void RecursorLua4::maintenance() const
491 {
492 if (d_maintenance) {
493 d_maintenance();
494 }
495 }
496
497 bool RecursorLua4::prerpz(DNSQuestion& dq, int& ret) const
498 {
499 return genhook(d_prerpz, dq, ret);
500 }
501
502 bool RecursorLua4::preresolve(DNSQuestion& dq, int& ret) const
503 {
504 return genhook(d_preresolve, dq, ret);
505 }
506
507 bool RecursorLua4::nxdomain(DNSQuestion& dq, int& ret) const
508 {
509 return genhook(d_nxdomain, dq, ret);
510 }
511
512 bool RecursorLua4::nodata(DNSQuestion& dq, int& ret) const
513 {
514 return genhook(d_nodata, dq, ret);
515 }
516
517 bool RecursorLua4::postresolve(DNSQuestion& dq, int& ret) const
518 {
519 return genhook(d_postresolve, dq, ret);
520 }
521
522 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
523 {
524 bool variableAnswer = false;
525 bool wantsRPZ = false;
526 bool logQuery = false;
527 RecursorLua4::DNSQuestion dq(ns, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ, logQuery);
528 dq.currentRecords = &res;
529
530 return genhook(d_preoutquery, dq, ret);
531 }
532
533 bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) const
534 {
535 if(d_ipfilter)
536 return d_ipfilter(remote, local, dh);
537 return false; // don't block
538 }
539
540 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, const std::vector<ProxyProtocolValue>& proxyProtocolValues) const
541 {
542 if(d_gettag) {
543 std::vector<std::pair<int, const ProxyProtocolValue*>> proxyProtocolValuesMap;
544 proxyProtocolValuesMap.reserve(proxyProtocolValues.size());
545 int num = 1;
546 for (const auto& value : proxyProtocolValues) {
547 proxyProtocolValuesMap.emplace_back(num++, &value);
548 }
549
550 auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp, proxyProtocolValuesMap);
551
552 if (policyTags) {
553 const auto& tags = std::get<1>(ret);
554 if (tags) {
555 policyTags->reserve(policyTags->size() + tags->size());
556 for (const auto& tag : *tags) {
557 policyTags->insert(tag.second);
558 }
559 }
560 }
561 const auto dataret = std::get<2>(ret);
562 if (dataret) {
563 data = *dataret;
564 }
565 const auto reqIdret = std::get<3>(ret);
566 if (reqIdret) {
567 requestorId = *reqIdret;
568 }
569 const auto deviceIdret = std::get<4>(ret);
570 if (deviceIdret) {
571 deviceId = *deviceIdret;
572 }
573
574 const auto deviceNameret = std::get<5>(ret);
575 if (deviceNameret) {
576 deviceName = *deviceNameret;
577 }
578 return std::get<0>(ret);
579 }
580 return 0;
581 }
582
583 struct pdns_ffi_param
584 {
585 public:
586 pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::unordered_set<std::string>& policyTags_, std::vector<DNSRecord>& records_, const EDNSOptionViewMap& ednsOptions_, const std::vector<ProxyProtocolValue>& proxyProtocolValues_, 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_), proxyProtocolValues(proxyProtocolValues_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), rcode(rcode_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), logResponse(logResponse_), followCNAMERecords(followCNAMERecords_), qtype(qtype_), tcp(tcp_)
587 {
588 }
589
590 std::unique_ptr<std::string> qnameStr{nullptr};
591 std::unique_ptr<std::string> localStr{nullptr};
592 std::unique_ptr<std::string> remoteStr{nullptr};
593 std::unique_ptr<std::string> ednssubnetStr{nullptr};
594 std::vector<pdns_ednsoption_t> ednsOptionsVect;
595 std::vector<pdns_proxyprotocol_value_t> proxyProtocolValuesVect;
596
597 const DNSName& qname;
598 const ComboAddress& local;
599 const ComboAddress& remote;
600 const Netmask& ednssubnet;
601 std::unordered_set<std::string>& policyTags;
602 std::vector<DNSRecord>& records;
603 const EDNSOptionViewMap& ednsOptions;
604 const std::vector<ProxyProtocolValue>& proxyProtocolValues;
605 std::string& requestorId;
606 std::string& deviceId;
607 std::string& deviceName;
608 boost::optional<int>& rcode;
609 uint32_t& ttlCap;
610 bool& variable;
611 bool& logQuery;
612 bool& logResponse;
613 bool& followCNAMERecords;
614
615 unsigned int tag{0};
616 uint16_t qtype;
617 bool tcp;
618 };
619
620 unsigned int RecursorLua4::gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::unordered_set<std::string>* policyTags, std::vector<DNSRecord>& records, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, const std::vector<ProxyProtocolValue>& proxyProtocolValues, 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
621 {
622 if (d_gettag_ffi) {
623 pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, records, ednsOptions, proxyProtocolValues, requestorId, deviceId, deviceName, rcode, ttlCap, variable, tcp, logQuery, logResponse, followCNAMERecords);
624
625 auto ret = d_gettag_ffi(&param);
626 if (ret) {
627 data = *ret;
628 }
629
630 return param.tag;
631 }
632 return 0;
633 }
634
635 bool RecursorLua4::genhook(const luacall_t& func, DNSQuestion& dq, int& ret) const
636 {
637 if(!func)
638 return false;
639
640 if (dq.currentRecords) {
641 dq.records = *dq.currentRecords;
642 } else {
643 dq.records.clear();
644 }
645
646 dq.followupFunction.clear();
647 dq.followupPrefix.clear();
648 dq.followupName.clear();
649 dq.udpQuery.clear();
650 dq.udpAnswer.clear();
651 dq.udpCallback.clear();
652
653 dq.rcode = ret;
654 bool handled=func(&dq);
655
656 if(handled) {
657 loop:;
658 ret=dq.rcode;
659
660 if(!dq.followupFunction.empty()) {
661 if(dq.followupFunction=="followCNAMERecords") {
662 ret = followCNAMERecords(dq.records, QType(dq.qtype));
663 }
664 else if(dq.followupFunction=="getFakeAAAARecords") {
665 ret=getFakeAAAARecords(dq.followupName, dq.followupPrefix, dq.records);
666 }
667 else if(dq.followupFunction=="getFakePTRRecords") {
668 ret=getFakePTRRecords(dq.followupName, dq.followupPrefix, dq.records);
669 }
670 else if(dq.followupFunction=="udpQueryResponse") {
671 dq.udpAnswer = GenUDPQueryResponse(dq.udpQueryDest, dq.udpQuery);
672 auto cbFunc = d_lw->readVariable<boost::optional<luacall_t>>(dq.udpCallback).get_value_or(0);
673 if(!cbFunc) {
674 g_log<<Logger::Error<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl;
675 return false;
676 }
677 bool result=cbFunc(&dq);
678 if(!result) {
679 return false;
680 }
681 goto loop;
682 }
683 }
684 if (dq.currentRecords) {
685 *dq.currentRecords = dq.records;
686 }
687 }
688
689 // see if they added followup work for us too
690 return handled;
691 }
692
693 RecursorLua4::~RecursorLua4(){}
694
695 const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref)
696 {
697 if (!ref->qnameStr) {
698 ref->qnameStr = std::unique_ptr<std::string>(new std::string(ref->qname.toStringNoDot()));
699 }
700
701 return ref->qnameStr->c_str();
702 }
703
704 void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t* ref, const char** qname, size_t* qnameSize)
705 {
706 const auto& storage = ref->qname.getStorage();
707 *qname = storage.data();
708 *qnameSize = storage.size();
709 }
710
711 uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref)
712 {
713 return ref->qtype;
714 }
715
716 const char* pdns_ffi_param_get_remote(pdns_ffi_param_t* ref)
717 {
718 if (!ref->remoteStr) {
719 ref->remoteStr = std::unique_ptr<std::string>(new std::string(ref->remote.toString()));
720 }
721
722 return ref->remoteStr->c_str();
723 }
724
725 static void pdns_ffi_comboaddress_to_raw(const ComboAddress& ca, const void** addr, size_t* addrSize)
726 {
727 if (ca.isIPv4()) {
728 *addr = &ca.sin4.sin_addr.s_addr;
729 *addrSize = sizeof(ca.sin4.sin_addr.s_addr);
730 }
731 else {
732 *addr = &ca.sin6.sin6_addr.s6_addr;
733 *addrSize = sizeof(ca.sin6.sin6_addr.s6_addr);
734 }
735 }
736
737 void pdns_ffi_param_get_remote_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize)
738 {
739 pdns_ffi_comboaddress_to_raw(ref->remote, addr, addrSize);
740 }
741
742 uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t* ref)
743 {
744 return ref->remote.getPort();
745 }
746
747 const char* pdns_ffi_param_get_local(pdns_ffi_param_t* ref)
748 {
749 if (!ref->localStr) {
750 ref->localStr = std::unique_ptr<std::string>(new std::string(ref->local.toString()));
751 }
752
753 return ref->localStr->c_str();
754 }
755
756 void pdns_ffi_param_get_local_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize)
757 {
758 pdns_ffi_comboaddress_to_raw(ref->local, addr, addrSize);
759 }
760
761 uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t* ref)
762 {
763 return ref->local.getPort();
764 }
765
766 const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t* ref)
767 {
768 if (ref->ednssubnet.empty()) {
769 return nullptr;
770 }
771
772 if (!ref->ednssubnetStr) {
773 ref->ednssubnetStr = std::unique_ptr<std::string>(new std::string(ref->ednssubnet.toStringNoMask()));
774 }
775
776 return ref->ednssubnetStr->c_str();
777 }
778
779 void pdns_ffi_param_get_edns_cs_raw(pdns_ffi_param_t* ref, const void** net, size_t* netSize)
780 {
781 if (ref->ednssubnet.empty()) {
782 *net = nullptr;
783 *netSize = 0;
784 return;
785 }
786
787 pdns_ffi_comboaddress_to_raw(ref->ednssubnet.getNetwork(), net, netSize);
788 }
789
790 uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t* ref)
791 {
792 return ref->ednssubnet.getBits();
793 }
794
795 static void fill_edns_option(const EDNSOptionViewValue& value, pdns_ednsoption_t& option)
796 {
797 option.len = value.size;
798 option.data = nullptr;
799
800 if (value.size > 0) {
801 option.data = value.content;
802 }
803 }
804
805 size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t* ref, const pdns_ednsoption_t** out)
806 {
807 if (ref->ednsOptions.empty()) {
808 return 0;
809 }
810
811 size_t totalCount = 0;
812 for (const auto& option : ref->ednsOptions) {
813 totalCount += option.second.values.size();
814 }
815
816 ref->ednsOptionsVect.resize(totalCount);
817
818 size_t pos = 0;
819 for (const auto& option : ref->ednsOptions) {
820 for (const auto& entry : option.second.values) {
821 fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
822 ref->ednsOptionsVect.at(pos).optionCode = option.first;
823 pos++;
824 }
825 }
826
827 *out = ref->ednsOptionsVect.data();
828
829 return totalCount;
830 }
831
832 size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out)
833 {
834 const auto& it = ref->ednsOptions.find(optionCode);
835 if (it == ref->ednsOptions.cend() || it->second.values.empty()) {
836 return 0;
837 }
838
839 ref->ednsOptionsVect.resize(it->second.values.size());
840
841 size_t pos = 0;
842 for (const auto& entry : it->second.values) {
843 fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
844 ref->ednsOptionsVect.at(pos).optionCode = optionCode;
845 pos++;
846 }
847
848 *out = ref->ednsOptionsVect.data();
849
850 return pos;
851 }
852
853 size_t pdns_ffi_param_get_proxy_protocol_values(pdns_ffi_param_t* ref, const pdns_proxyprotocol_value_t** out)
854 {
855 if (ref->proxyProtocolValues.empty()) {
856 return 0;
857 }
858
859 ref->proxyProtocolValuesVect.resize(ref->proxyProtocolValues.size());
860
861 size_t pos = 0;
862 for (const auto& value : ref->proxyProtocolValues) {
863 auto& dest = ref->proxyProtocolValuesVect.at(pos);
864 dest.type = value.type;
865 dest.len = value.content.size();
866 if (dest.len > 0) {
867 dest.data = value.content.data();
868 }
869 pos++;
870 }
871
872 *out = ref->proxyProtocolValuesVect.data();
873
874 return ref->proxyProtocolValuesVect.size();
875 }
876
877 void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag)
878 {
879 ref->tag = tag;
880 }
881
882 void pdns_ffi_param_add_policytag(pdns_ffi_param_t *ref, const char* name)
883 {
884 ref->policyTags.insert(std::string(name));
885 }
886
887 void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name)
888 {
889 ref->requestorId = std::string(name);
890 }
891
892 void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name)
893 {
894 ref->deviceName = std::string(name);
895 }
896
897 void pdns_ffi_param_set_deviceid(pdns_ffi_param_t* ref, size_t len, const void* name)
898 {
899 ref->deviceId = std::string(reinterpret_cast<const char*>(name), len);
900 }
901
902 void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable)
903 {
904 ref->variable = variable;
905 }
906
907 void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl)
908 {
909 ref->ttlCap = ttl;
910 }
911
912 void pdns_ffi_param_set_log_query(pdns_ffi_param_t* ref, bool logQuery)
913 {
914 ref->logQuery = logQuery;
915 }
916
917 void pdns_ffi_param_set_log_response(pdns_ffi_param_t* ref, bool logResponse)
918 {
919 ref->logResponse = logResponse;
920 }
921
922 void pdns_ffi_param_set_rcode(pdns_ffi_param_t* ref, int rcode)
923 {
924 ref->rcode = rcode;
925 }
926
927 void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t* ref, bool follow)
928 {
929 ref->followCNAMERecords = follow;
930 }
931
932 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)
933 {
934 try {
935 DNSRecord dr;
936 dr.d_name = name != nullptr ? DNSName(name) : ref->qname;
937 dr.d_ttl = ttl;
938 dr.d_type = type;
939 dr.d_class = QClass::IN;
940 dr.d_place = DNSResourceRecord::Place(place);
941 dr.d_content = DNSRecordContent::mastermake(type, QClass::IN, std::string(content, contentSize));
942 ref->records.push_back(std::move(dr));
943
944 return true;
945 }
946 catch (const std::exception& e) {
947 g_log<<Logger::Error<<"Error attempting to add a record from Lua via pdns_ffi_param_add_record(): "<<e.what()<<endl;
948 return false;
949 }
950 }