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