]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lua-recursor4.cc
Merge pull request #8918 from rgacogne/rec-edns-padding-plus-tests
[thirdparty/pdns.git] / pdns / lua-recursor4.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #include "lua-recursor4.hh"
23 #include <fstream>
24 #include "logger.hh"
25 #include "dnsparser.hh"
26 #include "syncres.hh"
27 #include "namespaces.hh"
28 #include "rec_channel.hh"
29 #include "ednsoptions.hh"
30 #include "ednssubnet.hh"
31 #include "filterpo.hh"
32 #include "rec-snmp.hh"
33 #include <unordered_set>
34
35 RecursorLua4::RecursorLua4() { prepareContext(); }
36
37 boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const
38 {
39 if (dh)
40 return *dh;
41 return boost::optional<dnsheader>();
42 }
43
44 vector<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
54 bool 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
63 vector<pair<uint16_t, string> > RecursorLua4::DNSQuestion::getEDNSOptions() const
64 {
65 if(ednsOptions)
66 return *ednsOptions;
67 else
68 return vector<pair<uint16_t,string>>();
69 }
70
71 boost::optional<string> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const
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
81 boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() const
82 {
83 if(ednsOptions) {
84 for(const auto& o : *ednsOptions) {
85 if(o.first==EDNSOptionCode::ECS) {
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
97 std::vector<std::pair<int, ProxyProtocolValue>> RecursorLua4::DNSQuestion::getProxyProtocolValues() const
98 {
99 std::vector<std::pair<int, ProxyProtocolValue>> result;
100 if (proxyProtocolValues) {
101 result.reserve(proxyProtocolValues->size());
102
103 int idx = 1;
104 for (const auto& value: *proxyProtocolValues) {
105 result.push_back({ idx++, value });
106 }
107 }
108
109 return result;
110 }
111
112 vector<pair<int, DNSRecord> > RecursorLua4::DNSQuestion::getRecords() const
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 }
121 void 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);
126 }
127 }
128
129 void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name)
130 {
131 DNSRecord dr;
132 dr.d_name=name ? DNSName(*name) : qname;
133 dr.d_ttl=ttl.get_value_or(3600);
134 dr.d_type = type;
135 dr.d_place = place;
136 dr.d_content = DNSRecordContent::mastermake(type, QClass::IN, content);
137 records.push_back(dr);
138 }
139
140 void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name)
141 {
142 addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name);
143 }
144
145 struct 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
154 void RecursorLua4::postPrepareContext()
155 {
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; });
161 d_lw->registerMember<uint8_t (DNSQuestion::*)>("validationState", [](const DNSQuestion& dq) -> uint8_t { return (vStateIsBogus(dq.validationState) ? /* in order not to break older scripts */ static_cast<uint8_t>(255) : static_cast<uint8_t>(dq.validationState)); }, [](DNSQuestion& dq, uint8_t newState) { (void) newState; });
162 d_lw->registerMember<vState (DNSQuestion::*)>("detailedValidationState", [](const DNSQuestion& dq) -> vState { return dq.validationState; }, [](DNSQuestion& dq, vState newState) { (void) newState; });
163
164 d_lw->registerMember<bool (DNSQuestion::*)>("variable", [](const DNSQuestion& dq) -> bool { return dq.variable; }, [](DNSQuestion& dq, bool newVariable) { dq.variable = newVariable; });
165 d_lw->registerMember<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion& dq) -> bool { return dq.wantsRPZ; }, [](DNSQuestion& dq, bool newWantsRPZ) { dq.wantsRPZ = newWantsRPZ; });
166 d_lw->registerMember<bool (DNSQuestion::*)>("logResponse", [](const DNSQuestion& dq) -> bool { return dq.logResponse; }, [](DNSQuestion& dq, bool newLogResponse) { dq.logResponse = newLogResponse; });
167 d_lw->registerMember<bool (DNSQuestion::*)>("addPaddingToResponse", [](const DNSQuestion& dq) -> bool { return dq.addPaddingToResponse; }, [](DNSQuestion& dq, bool add) { dq.addPaddingToResponse = add; });
168
169 d_lw->registerMember("rcode", &DNSQuestion::rcode);
170 d_lw->registerMember("tag", &DNSQuestion::tag);
171 d_lw->registerMember("requestorId", &DNSQuestion::requestorId);
172 d_lw->registerMember("deviceId", &DNSQuestion::deviceId);
173 d_lw->registerMember("deviceName", &DNSQuestion::deviceName);
174 d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction);
175 d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix);
176 d_lw->registerMember("followupName", &DNSQuestion::followupName);
177 d_lw->registerMember("data", &DNSQuestion::data);
178 d_lw->registerMember<uint16_t (DNSQuestion::*)>("extendedErrorCode", [](const DNSQuestion& dq) -> uint16_t {
179 if (dq.extendedErrorCode && *dq.extendedErrorCode) {
180 return *(*dq.extendedErrorCode);
181 }
182 return 0;
183 },
184 [](DNSQuestion& dq, uint16_t newCode) {
185 if (dq.extendedErrorCode) {
186 *dq.extendedErrorCode = newCode;
187 }
188 });
189 d_lw->registerMember<std::string (DNSQuestion::*)>("extendedErrorExtra", [](const DNSQuestion& dq) -> std::string {
190 if (dq.extendedErrorExtra) {
191 return *dq.extendedErrorExtra;
192 }
193 return "";
194 },
195 [](DNSQuestion& dq, const std::string& newExtra) {
196 if (dq.extendedErrorExtra) {
197 *dq.extendedErrorExtra = newExtra;
198 }
199 });
200 d_lw->registerMember("udpQuery", &DNSQuestion::udpQuery);
201 d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer);
202 d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest);
203 d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback);
204 d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy);
205
206 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyName",
207 [](const DNSFilterEngine::Policy& pol) -> std::string {
208 return pol.getName();
209 },
210 [](DNSFilterEngine::Policy& pol, const std::string& name) {
211 pol.setName(name);
212 });
213 d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind);
214 d_lw->registerMember("policyType", &DNSFilterEngine::Policy::d_type);
215 d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl);
216 d_lw->registerMember("policyTrigger", &DNSFilterEngine::Policy::d_trigger);
217 d_lw->registerMember("policyHit", &DNSFilterEngine::Policy::d_hit);
218 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyCustom",
219 [](const DNSFilterEngine::Policy& pol) -> std::string {
220 std::string result;
221 if (pol.d_kind != DNSFilterEngine::PolicyKind::Custom) {
222 return result;
223 }
224
225 for (const auto& dr : pol.d_custom) {
226 if (!result.empty()) {
227 result += "\n";
228 }
229 result += dr->getZoneRepresentation();
230 }
231
232 return result;
233 },
234 [](DNSFilterEngine::Policy& pol, const std::string& content) {
235 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
236 pol.d_custom.clear();
237 pol.d_custom.push_back(DNSRecordContent::mastermake(QType::CNAME, QClass::IN, content));
238 }
239 );
240 d_lw->registerFunction("getDH", &DNSQuestion::getDH);
241 d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions);
242 d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption);
243 d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet);
244 d_lw->registerFunction("getProxyProtocolValues", &DNSQuestion::getProxyProtocolValues);
245 d_lw->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags);
246 d_lw->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag);
247
248 d_lw->registerMember("name", &DNSRecord::d_name);
249 d_lw->registerMember("type", &DNSRecord::d_type);
250 d_lw->registerMember("ttl", &DNSRecord::d_ttl);
251 d_lw->registerMember("place", &DNSRecord::d_place);
252
253 d_lw->registerMember("size", &EDNSOptionViewValue::size);
254 d_lw->registerFunction<std::string(EDNSOptionViewValue::*)()>("getContent", [](const EDNSOptionViewValue& value) { return std::string(value.content, value.size); });
255 d_lw->registerFunction<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView& option) { return option.values.size(); });
256 d_lw->registerFunction<std::vector<string>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView& option) {
257 std::vector<string> values;
258 for (const auto& value : option.values) {
259 values.push_back(std::string(value.content, value.size));
260 }
261 return values;
262 });
263
264 /* pre 4.2 API compatibility, when we had only one value for a given EDNS option */
265 d_lw->registerMember<uint16_t(EDNSOptionView::*)>("size", [](const EDNSOptionView& option) -> uint16_t {
266 uint16_t result = 0;
267
268 if (!option.values.empty()) {
269 result = option.values.at(0).size;
270 }
271 return result;
272 },
273 [](EDNSOptionView& option, uint16_t newSize) { (void) newSize; });
274 d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) {
275 if (option.values.empty()) {
276 return std::string();
277 }
278 return std::string(option.values.at(0).content, option.values.at(0).size); });
279
280 d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); });
281 d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
282 boost::optional<ComboAddress> ret;
283
284 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content))
285 ret=rec->getCA(53);
286 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content))
287 ret=aaaarec->getCA(53);
288 return ret;
289 });
290
291 d_lw->registerFunction<const ProxyProtocolValue, std::string()>("getContent", [](const ProxyProtocolValue& value) { return value.content; });
292 d_lw->registerFunction<const ProxyProtocolValue, uint8_t()>("getType", [](const ProxyProtocolValue& value) { return value.type; });
293
294 d_lw->registerFunction<void(DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.d_content = DNSRecordContent::mastermake(dr.d_type, QClass::IN, newContent); });
295 d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer);
296 d_lw->registerFunction("addRecord", &DNSQuestion::addRecord);
297 d_lw->registerFunction("getRecords", &DNSQuestion::getRecords);
298 d_lw->registerFunction("setRecords", &DNSQuestion::setRecords);
299
300 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->insert(tag); } });
301 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) {
302 if (dq.policyTags) {
303 dq.policyTags->clear();
304 dq.policyTags->reserve(tags.size());
305 for (const auto& tag : tags) {
306 dq.policyTags->insert(tag.second);
307 }
308 }
309 });
310 d_lw->registerFunction<std::vector<std::pair<int, std::string> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) {
311 std::vector<std::pair<int, std::string> > ret;
312 if (dq.policyTags) {
313 int count = 1;
314 ret.reserve(dq.policyTags->size());
315 for (const auto& tag : *dq.policyTags) {
316 ret.push_back({count++, tag});
317 }
318 }
319 return ret;
320 });
321
322 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("discardPolicy", [](DNSQuestion& dq, const std::string& policy) {
323 if (dq.discardedPolicies) {
324 (*dq.discardedPolicies)[policy] = true;
325 }
326 });
327
328 d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); });
329 d_lw->registerFunction<void(SuffixMatchNode::*)(boost::variant<string,DNSName, vector<pair<unsigned int,string> > >)>(
330 "add",
331 [](SuffixMatchNode&smn, const boost::variant<string,DNSName,vector<pair<unsigned int,string> > >& in){
332 try {
333 if(auto s = boost::get<string>(&in)) {
334 smn.add(DNSName(*s));
335 }
336 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
337 for(const auto& entry : *v)
338 smn.add(DNSName(entry.second));
339 }
340 else {
341 smn.add(boost::get<DNSName>(in));
342 }
343 }
344 catch(std::exception& e) {
345 g_log <<Logger::Error<<e.what()<<endl;
346 }
347 }
348 );
349
350 d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
351 d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString);
352
353 d_pd.push_back({"policykinds", in_t {
354 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction},
355 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop },
356 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN},
357 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA },
358 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate},
359 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom }
360 }});
361
362 d_pd.push_back({"policytypes", in_t {
363 {"None", (int)DNSFilterEngine::PolicyType::None },
364 {"QName", (int)DNSFilterEngine::PolicyType::QName },
365 {"ClientIP", (int)DNSFilterEngine::PolicyType::ClientIP },
366 {"ResponseIP", (int)DNSFilterEngine::PolicyType::ResponseIP },
367 {"NSDName", (int)DNSFilterEngine::PolicyType::NSDName },
368 {"NSIP", (int)DNSFilterEngine::PolicyType::NSIP }
369 }});
370
371 for(const auto& n : QType::names)
372 d_pd.push_back({n.first, n.second});
373
374 d_pd.push_back({"validationstates", in_t{
375 {"Indeterminate", static_cast<unsigned int>(vState::Indeterminate) },
376 {"BogusNoValidDNSKEY", static_cast<unsigned int>(vState::BogusNoValidDNSKEY) },
377 {"BogusInvalidDenial", static_cast<unsigned int>(vState::BogusInvalidDenial) },
378 {"BogusUnableToGetDSs", static_cast<unsigned int>(vState::BogusUnableToGetDSs) },
379 {"BogusUnableToGetDNSKEYs", static_cast<unsigned int>(vState::BogusUnableToGetDNSKEYs) },
380 {"BogusSelfSignedDS", static_cast<unsigned int>(vState::BogusSelfSignedDS) },
381 {"BogusNoRRSIG", static_cast<unsigned int>(vState::BogusNoRRSIG) },
382 {"BogusNoValidRRSIG", static_cast<unsigned int>(vState::BogusNoValidRRSIG) },
383 {"BogusMissingNegativeIndication", static_cast<unsigned int>(vState::BogusMissingNegativeIndication) },
384 {"BogusSignatureNotYetValid", static_cast<unsigned int>(vState::BogusSignatureNotYetValid)},
385 {"BogusSignatureExpired", static_cast<unsigned int>(vState::BogusSignatureExpired)},
386 {"BogusUnsupportedDNSKEYAlgo", static_cast<unsigned int>(vState::BogusUnsupportedDNSKEYAlgo)},
387 {"BogusUnsupportedDSDigestType", static_cast<unsigned int>(vState::BogusUnsupportedDSDigestType)},
388 {"BogusNoZoneKeyBitSet", static_cast<unsigned int>(vState::BogusNoZoneKeyBitSet)},
389 {"BogusRevokedDNSKEY", static_cast<unsigned int>(vState::BogusRevokedDNSKEY)},
390 {"BogusInvalidDNSKEYProtocol", static_cast<unsigned int>(vState::BogusInvalidDNSKEYProtocol)},
391 {"Insecure", static_cast<unsigned int>(vState::Insecure) },
392 {"Secure", static_cast<unsigned int>(vState::Secure) },
393 /* in order not to break compatibility with older scripts: */
394 {"Bogus", static_cast<unsigned int>(255) },
395 }});
396
397 d_lw->writeFunction("isValidationStateBogus", [](vState state) {
398 return vStateIsBogus(state);
399 });
400
401 d_pd.push_back({"now", &g_now});
402
403 d_lw->writeFunction("getMetric", [](const std::string& str, boost::optional<std::string> prometheusName) {
404 return DynMetric{getDynMetric(str, prometheusName ? *prometheusName : "")};
405 });
406
407 d_lw->registerFunction("inc", &DynMetric::inc);
408 d_lw->registerFunction("incBy", &DynMetric::incBy);
409 d_lw->registerFunction("set", &DynMetric::set);
410 d_lw->registerFunction("get", &DynMetric::get);
411
412 d_lw->writeFunction("getStat", [](const std::string& str) {
413 uint64_t result = 0;
414 boost::optional<uint64_t> value = getStatByName(str);
415 if (value) {
416 result = *value;
417 }
418 return result;
419 });
420
421 d_lw->writeFunction("getRecursorThreadId", []() {
422 return getRecursorThreadId();
423 });
424
425 d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) {
426 if (g_snmpAgent) {
427 g_snmpAgent->sendCustomTrap(str);
428 }
429 });
430
431 d_lw->writeFunction("getregisteredname", [](const DNSName &dname) {
432 return getRegisteredName(dname);
433 });
434
435 d_lw->registerMember<const DNSName (PolicyEvent::*)>("qname", [](const PolicyEvent& event) -> const DNSName& { return event.qname; }, [](PolicyEvent& event, const DNSName& newName) { (void) newName; });
436 d_lw->registerMember<uint16_t (PolicyEvent::*)>("qtype", [](const PolicyEvent& event) -> uint16_t { return event.qtype.getCode(); }, [](PolicyEvent& event, uint16_t newType) { (void) newType; });
437 d_lw->registerMember<bool (PolicyEvent::*)>("isTcp", [](const PolicyEvent& event) -> bool { return event.isTcp; }, [](PolicyEvent& event, bool newTcp) { (void) newTcp; });
438 d_lw->registerMember<const ComboAddress (PolicyEvent::*)>("remote", [](const PolicyEvent& event) -> const ComboAddress& { return event.remote; }, [](PolicyEvent& event, const ComboAddress& newRemote) { (void) newRemote; });
439 d_lw->registerMember("appliedPolicy", &PolicyEvent::appliedPolicy);
440 d_lw->registerFunction<void(PolicyEvent::*)(const std::string&)>("addPolicyTag", [](PolicyEvent& event, const std::string& tag) { if (event.policyTags) { event.policyTags->insert(tag); } });
441 d_lw->registerFunction<void(PolicyEvent::*)(const std::vector<std::pair<int, std::string> >&)>("setPolicyTags", [](PolicyEvent& event, const std::vector<std::pair<int, std::string> >& tags) {
442 if (event.policyTags) {
443 event.policyTags->clear();
444 event.policyTags->reserve(tags.size());
445 for (const auto& tag : tags) {
446 event.policyTags->insert(tag.second);
447 }
448 }
449 });
450 d_lw->registerFunction<std::vector<std::pair<int, std::string> >(PolicyEvent::*)()>("getPolicyTags", [](const PolicyEvent& event) {
451 std::vector<std::pair<int, std::string> > ret;
452 if (event.policyTags) {
453 int count = 1;
454 ret.reserve(event.policyTags->size());
455 for (const auto& tag : *event.policyTags) {
456 ret.push_back({count++, tag});
457 }
458 }
459 return ret;
460 });
461 d_lw->registerFunction<void(PolicyEvent::*)(const std::string&)>("discardPolicy", [](PolicyEvent& event, const std::string& policy) {
462 if (event.discardedPolicies) {
463 (*event.discardedPolicies)[policy] = true;
464 }
465 });
466 }
467
468 void RecursorLua4::postLoad() {
469 d_prerpz = d_lw->readVariable<boost::optional<luacall_t>>("prerpz").get_value_or(0);
470 d_preresolve = d_lw->readVariable<boost::optional<luacall_t>>("preresolve").get_value_or(0);
471 d_nodata = d_lw->readVariable<boost::optional<luacall_t>>("nodata").get_value_or(0);
472 d_nxdomain = d_lw->readVariable<boost::optional<luacall_t>>("nxdomain").get_value_or(0);
473 d_postresolve = d_lw->readVariable<boost::optional<luacall_t>>("postresolve").get_value_or(0);
474 d_preoutquery = d_lw->readVariable<boost::optional<luacall_t>>("preoutquery").get_value_or(0);
475 d_maintenance = d_lw->readVariable<boost::optional<luamaintenance_t>>("maintenance").get_value_or(0);
476
477 d_ipfilter = d_lw->readVariable<boost::optional<ipfilter_t>>("ipfilter").get_value_or(0);
478 d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0);
479 d_gettag_ffi = d_lw->readVariable<boost::optional<gettag_ffi_t>>("gettag_ffi").get_value_or(0);
480
481 d_policyHitEventFilter = d_lw->readVariable<boost::optional<policyEventFilter_t>>("policyEventFilter").get_value_or(0);
482 }
483
484 void RecursorLua4::getFeatures(Features & features) {
485 // Add key-values pairs below.
486 // Make sure you add string values explicitly converted to string.
487 // e.g. features.push_back(make_pair("somekey", string("stringvalue"));
488 // Both int and double end up as a lua number type.
489 features.push_back(make_pair("PR8001_devicename", true));
490 }
491
492 void RecursorLua4::maintenance() const
493 {
494 if (d_maintenance) {
495 d_maintenance();
496 }
497 }
498
499 bool RecursorLua4::prerpz(DNSQuestion& dq, int& ret) const
500 {
501 return genhook(d_prerpz, dq, ret);
502 }
503
504 bool RecursorLua4::preresolve(DNSQuestion& dq, int& ret) const
505 {
506 return genhook(d_preresolve, dq, ret);
507 }
508
509 bool RecursorLua4::nxdomain(DNSQuestion& dq, int& ret) const
510 {
511 return genhook(d_nxdomain, dq, ret);
512 }
513
514 bool RecursorLua4::nodata(DNSQuestion& dq, int& ret) const
515 {
516 return genhook(d_nodata, dq, ret);
517 }
518
519 bool RecursorLua4::postresolve(DNSQuestion& dq, int& ret) const
520 {
521 return genhook(d_postresolve, dq, ret);
522 }
523
524 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
525 {
526 bool variableAnswer = false;
527 bool wantsRPZ = false;
528 bool logQuery = false;
529 bool addPaddingToResponse = false;
530 RecursorLua4::DNSQuestion dq(ns, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ, logQuery, addPaddingToResponse);
531 dq.currentRecords = &res;
532
533 return genhook(d_preoutquery, dq, ret);
534 }
535
536 bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) const
537 {
538 if(d_ipfilter)
539 return d_ipfilter(remote, local, dh);
540 return false; // don't block
541 }
542
543 bool RecursorLua4::policyHitEventFilter(const ComboAddress& remote, const DNSName& qname, const QType& qtype, bool tcp, DNSFilterEngine::Policy& policy, std::unordered_set<std::string>& tags, std::unordered_map<std::string, bool>& discardedPolicies) const
544 {
545 if (!d_policyHitEventFilter) {
546 return false;
547 }
548
549 PolicyEvent event(remote, qname, qtype, tcp);
550 event.appliedPolicy = &policy;
551 event.policyTags = &tags;
552 event.discardedPolicies = &discardedPolicies;
553
554 if (d_policyHitEventFilter(event)) {
555 return true;
556 }
557 else {
558 return false;
559 }
560 }
561
562 unsigned int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::unordered_set<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, std::string& routingTag, const std::vector<ProxyProtocolValue>& proxyProtocolValues) const
563 {
564 if(d_gettag) {
565 std::vector<std::pair<int, const ProxyProtocolValue*>> proxyProtocolValuesMap;
566 proxyProtocolValuesMap.reserve(proxyProtocolValues.size());
567 int num = 1;
568 for (const auto& value : proxyProtocolValues) {
569 proxyProtocolValuesMap.emplace_back(num++, &value);
570 }
571
572 auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp, proxyProtocolValuesMap);
573
574 if (policyTags) {
575 const auto& tags = std::get<1>(ret);
576 if (tags) {
577 policyTags->reserve(policyTags->size() + tags->size());
578 for (const auto& tag : *tags) {
579 policyTags->insert(tag.second);
580 }
581 }
582 }
583 const auto dataret = std::get<2>(ret);
584 if (dataret) {
585 data = *dataret;
586 }
587 const auto reqIdret = std::get<3>(ret);
588 if (reqIdret) {
589 requestorId = *reqIdret;
590 }
591 const auto deviceIdret = std::get<4>(ret);
592 if (deviceIdret) {
593 deviceId = *deviceIdret;
594 }
595
596 const auto deviceNameret = std::get<5>(ret);
597 if (deviceNameret) {
598 deviceName = *deviceNameret;
599 }
600
601 const auto routingTarget = std::get<6>(ret);
602 if (routingTarget) {
603 routingTag = *routingTarget;
604 }
605
606 return std::get<0>(ret);
607 }
608 return 0;
609 }
610
611 struct pdns_ffi_param
612 {
613 public:
614 pdns_ffi_param(RecursorLua4::FFIParams& params_): params(params_)
615 {
616 }
617
618 RecursorLua4::FFIParams& params;
619 std::unique_ptr<std::string> qnameStr{nullptr};
620 std::unique_ptr<std::string> localStr{nullptr};
621 std::unique_ptr<std::string> remoteStr{nullptr};
622 std::unique_ptr<std::string> ednssubnetStr{nullptr};
623 std::vector<pdns_ednsoption_t> ednsOptionsVect;
624 std::vector<pdns_proxyprotocol_value_t> proxyProtocolValuesVect;
625 };
626
627 unsigned int RecursorLua4::gettag_ffi(RecursorLua4::FFIParams& params) const
628 {
629 if (d_gettag_ffi) {
630 pdns_ffi_param_t param(params);
631
632 auto ret = d_gettag_ffi(&param);
633 if (ret) {
634 params.data = *ret;
635 }
636
637 return param.params.tag;
638 }
639 return 0;
640 }
641
642 bool RecursorLua4::genhook(const luacall_t& func, DNSQuestion& dq, int& ret) const
643 {
644 if(!func)
645 return false;
646
647 if (dq.currentRecords) {
648 dq.records = *dq.currentRecords;
649 } else {
650 dq.records.clear();
651 }
652
653 dq.followupFunction.clear();
654 dq.followupPrefix.clear();
655 dq.followupName.clear();
656 dq.udpQuery.clear();
657 dq.udpAnswer.clear();
658 dq.udpCallback.clear();
659
660 dq.rcode = ret;
661 bool handled=func(&dq);
662
663 if(handled) {
664 loop:;
665 ret=dq.rcode;
666
667 if(!dq.followupFunction.empty()) {
668 if(dq.followupFunction=="followCNAMERecords") {
669 ret = followCNAMERecords(dq.records, QType(dq.qtype), ret);
670 }
671 else if(dq.followupFunction=="getFakeAAAARecords") {
672 ret=getFakeAAAARecords(dq.followupName, ComboAddress(dq.followupPrefix), dq.records);
673 }
674 else if(dq.followupFunction=="getFakePTRRecords") {
675 ret=getFakePTRRecords(dq.followupName, dq.records);
676 }
677 else if(dq.followupFunction=="udpQueryResponse") {
678 dq.udpAnswer = GenUDPQueryResponse(dq.udpQueryDest, dq.udpQuery);
679 auto cbFunc = d_lw->readVariable<boost::optional<luacall_t>>(dq.udpCallback).get_value_or(0);
680 if(!cbFunc) {
681 g_log<<Logger::Error<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl;
682 return false;
683 }
684 bool result=cbFunc(&dq);
685 if(!result) {
686 return false;
687 }
688 goto loop;
689 }
690 }
691 if (dq.currentRecords) {
692 *dq.currentRecords = dq.records;
693 }
694 }
695
696 // see if they added followup work for us too
697 return handled;
698 }
699
700 RecursorLua4::~RecursorLua4(){}
701
702 const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref)
703 {
704 if (!ref->qnameStr) {
705 ref->qnameStr = std::unique_ptr<std::string>(new std::string(ref->params.qname.toStringNoDot()));
706 }
707
708 return ref->qnameStr->c_str();
709 }
710
711 void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t* ref, const char** qname, size_t* qnameSize)
712 {
713 const auto& storage = ref->params.qname.getStorage();
714 *qname = storage.data();
715 *qnameSize = storage.size();
716 }
717
718 uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref)
719 {
720 return ref->params.qtype;
721 }
722
723 const char* pdns_ffi_param_get_remote(pdns_ffi_param_t* ref)
724 {
725 if (!ref->remoteStr) {
726 ref->remoteStr = std::unique_ptr<std::string>(new std::string(ref->params.remote.toString()));
727 }
728
729 return ref->remoteStr->c_str();
730 }
731
732 static void pdns_ffi_comboaddress_to_raw(const ComboAddress& ca, const void** addr, size_t* addrSize)
733 {
734 if (ca.isIPv4()) {
735 *addr = &ca.sin4.sin_addr.s_addr;
736 *addrSize = sizeof(ca.sin4.sin_addr.s_addr);
737 }
738 else {
739 *addr = &ca.sin6.sin6_addr.s6_addr;
740 *addrSize = sizeof(ca.sin6.sin6_addr.s6_addr);
741 }
742 }
743
744 void pdns_ffi_param_get_remote_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize)
745 {
746 pdns_ffi_comboaddress_to_raw(ref->params.remote, addr, addrSize);
747 }
748
749 uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t* ref)
750 {
751 return ref->params.remote.getPort();
752 }
753
754 const char* pdns_ffi_param_get_local(pdns_ffi_param_t* ref)
755 {
756 if (!ref->localStr) {
757 ref->localStr = std::unique_ptr<std::string>(new std::string(ref->params.local.toString()));
758 }
759
760 return ref->localStr->c_str();
761 }
762
763 void pdns_ffi_param_get_local_raw(pdns_ffi_param_t* ref, const void** addr, size_t* addrSize)
764 {
765 pdns_ffi_comboaddress_to_raw(ref->params.local, addr, addrSize);
766 }
767
768 uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t* ref)
769 {
770 return ref->params.local.getPort();
771 }
772
773 const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t* ref)
774 {
775 if (ref->params.ednssubnet.empty()) {
776 return nullptr;
777 }
778
779 if (!ref->ednssubnetStr) {
780 ref->ednssubnetStr = std::unique_ptr<std::string>(new std::string(ref->params.ednssubnet.toStringNoMask()));
781 }
782
783 return ref->ednssubnetStr->c_str();
784 }
785
786 void pdns_ffi_param_get_edns_cs_raw(pdns_ffi_param_t* ref, const void** net, size_t* netSize)
787 {
788 if (ref->params.ednssubnet.empty()) {
789 *net = nullptr;
790 *netSize = 0;
791 return;
792 }
793
794 pdns_ffi_comboaddress_to_raw(ref->params.ednssubnet.getNetwork(), net, netSize);
795 }
796
797 uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t* ref)
798 {
799 return ref->params.ednssubnet.getBits();
800 }
801
802 static void fill_edns_option(const EDNSOptionViewValue& value, pdns_ednsoption_t& option)
803 {
804 option.len = value.size;
805 option.data = nullptr;
806
807 if (value.size > 0) {
808 option.data = value.content;
809 }
810 }
811
812 size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t* ref, const pdns_ednsoption_t** out)
813 {
814 if (ref->params.ednsOptions.empty()) {
815 return 0;
816 }
817
818 size_t totalCount = 0;
819 for (const auto& option : ref->params.ednsOptions) {
820 totalCount += option.second.values.size();
821 }
822
823 ref->ednsOptionsVect.resize(totalCount);
824
825 size_t pos = 0;
826 for (const auto& option : ref->params.ednsOptions) {
827 for (const auto& entry : option.second.values) {
828 fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
829 ref->ednsOptionsVect.at(pos).optionCode = option.first;
830 pos++;
831 }
832 }
833
834 *out = ref->ednsOptionsVect.data();
835
836 return totalCount;
837 }
838
839 size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out)
840 {
841 const auto& it = ref->params.ednsOptions.find(optionCode);
842 if (it == ref->params.ednsOptions.cend() || it->second.values.empty()) {
843 return 0;
844 }
845
846 ref->ednsOptionsVect.resize(it->second.values.size());
847
848 size_t pos = 0;
849 for (const auto& entry : it->second.values) {
850 fill_edns_option(entry, ref->ednsOptionsVect.at(pos));
851 ref->ednsOptionsVect.at(pos).optionCode = optionCode;
852 pos++;
853 }
854
855 *out = ref->ednsOptionsVect.data();
856
857 return pos;
858 }
859
860 size_t pdns_ffi_param_get_proxy_protocol_values(pdns_ffi_param_t* ref, const pdns_proxyprotocol_value_t** out)
861 {
862 if (ref->params.proxyProtocolValues.empty()) {
863 return 0;
864 }
865
866 ref->proxyProtocolValuesVect.resize(ref->params.proxyProtocolValues.size());
867
868 size_t pos = 0;
869 for (const auto& value : ref->params.proxyProtocolValues) {
870 auto& dest = ref->proxyProtocolValuesVect.at(pos);
871 dest.type = value.type;
872 dest.len = value.content.size();
873 if (dest.len > 0) {
874 dest.data = value.content.data();
875 }
876 pos++;
877 }
878
879 *out = ref->proxyProtocolValuesVect.data();
880
881 return ref->proxyProtocolValuesVect.size();
882 }
883
884 void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag)
885 {
886 ref->params.tag = tag;
887 }
888
889 void pdns_ffi_param_add_policytag(pdns_ffi_param_t *ref, const char* name)
890 {
891 ref->params.policyTags.insert(std::string(name));
892 }
893
894 void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name)
895 {
896 ref->params.requestorId = std::string(name);
897 }
898
899 void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name)
900 {
901 ref->params.deviceName = std::string(name);
902 }
903
904 void pdns_ffi_param_set_deviceid(pdns_ffi_param_t* ref, size_t len, const void* name)
905 {
906 ref->params.deviceId = std::string(reinterpret_cast<const char*>(name), len);
907 }
908
909 void pdns_ffi_param_set_routingtag(pdns_ffi_param_t* ref, const char* rtag)
910 {
911 ref->params.routingTag = std::string(rtag);
912 }
913
914 void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable)
915 {
916 ref->params.variable = variable;
917 }
918
919 void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl)
920 {
921 ref->params.ttlCap = ttl;
922 }
923
924 void pdns_ffi_param_set_log_query(pdns_ffi_param_t* ref, bool logQuery)
925 {
926 ref->params.logQuery = logQuery;
927 }
928
929 void pdns_ffi_param_set_log_response(pdns_ffi_param_t* ref, bool logResponse)
930 {
931 ref->params.logResponse = logResponse;
932 }
933
934 void pdns_ffi_param_set_rcode(pdns_ffi_param_t* ref, int rcode)
935 {
936 ref->params.rcode = rcode;
937 }
938
939 void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t* ref, bool follow)
940 {
941 ref->params.followCNAMERecords = follow;
942 }
943
944 void pdns_ffi_param_set_extended_error_code(pdns_ffi_param_t* ref, uint16_t code)
945 {
946 ref->params.extendedErrorCode = code;
947 }
948
949 void pdns_ffi_param_set_extended_error_extra(pdns_ffi_param_t* ref, size_t len, const char* extra)
950 {
951 ref->params.extendedErrorExtra = std::string(extra, len);
952 }
953
954 bool pdns_ffi_param_add_record(pdns_ffi_param_t *ref, const char* name, uint16_t type, uint32_t ttl, const char* content, size_t contentSize, pdns_record_place_t place)
955 {
956 try {
957 DNSRecord dr;
958 dr.d_name = name != nullptr ? DNSName(name) : ref->params.qname;
959 dr.d_ttl = ttl;
960 dr.d_type = type;
961 dr.d_class = QClass::IN;
962 dr.d_place = DNSResourceRecord::Place(place);
963 dr.d_content = DNSRecordContent::mastermake(type, QClass::IN, std::string(content, contentSize));
964 ref->params.records.push_back(std::move(dr));
965
966 return true;
967 }
968 catch (const std::exception& e) {
969 g_log<<Logger::Error<<"Error attempting to add a record from Lua via pdns_ffi_param_add_record(): "<<e.what()<<endl;
970 return false;
971 }
972 }
973
974 void pdns_ffi_param_set_padding_disabled(pdns_ffi_param_t* ref, bool disabled)
975 {
976 ref->params.disablePadding = disabled;
977 }