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