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