]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lua-recursor4.cc
Merge pull request #5523 from rubenk/fix-typos-in-logmessage
[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 static int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype)
36 {
37 vector<DNSRecord> resolved;
38 DNSName target;
39 for(const DNSRecord& rr : ret) {
40 if(rr.d_type == QType::CNAME) {
41 auto rec = getRR<CNAMERecordContent>(rr);
42 if(rec) {
43 target=rec->getTarget();
44 break;
45 }
46 }
47 }
48 if(target.empty())
49 return 0;
50
51 int rcode=directResolve(target, qtype, 1, resolved); // 1 == class
52
53 for(const DNSRecord& rr : resolved) {
54 ret.push_back(rr);
55 }
56 return rcode;
57
58 }
59
60 static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
61 {
62 int rcode=directResolve(qname, QType(QType::A), 1, ret);
63
64 ComboAddress prefixAddress(prefix);
65
66 for(DNSRecord& rr : ret)
67 {
68 if(rr.d_type == QType::A && rr.d_place==DNSResourceRecord::ANSWER) {
69 if(auto rec = getRR<ARecordContent>(rr)) {
70 ComboAddress ipv4(rec->getCA());
71 uint32_t tmp;
72 memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4);
73 // tmp=htonl(tmp);
74 memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4);
75 rr.d_content = std::make_shared<AAAARecordContent>(prefixAddress);
76 rr.d_type = QType::AAAA;
77 }
78 }
79 }
80 return rcode;
81 }
82
83 static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
84 {
85 /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it
86 and turn it into an IPv4 in-addr.arpa query */
87 ret.clear();
88 vector<string> parts = qname.getRawLabels();
89
90 if(parts.size() < 8)
91 return -1;
92
93 string newquery;
94 for(int n = 0; n < 4; ++n) {
95 newquery +=
96 std::to_string(stoll(parts[n*2], 0, 16) + 16*stoll(parts[n*2+1], 0, 16));
97 newquery.append(1,'.');
98 }
99 newquery += "in-addr.arpa.";
100
101
102 int rcode = directResolve(DNSName(newquery), QType(QType::PTR), 1, ret);
103 for(DNSRecord& rr : ret)
104 {
105 if(rr.d_type == QType::PTR && rr.d_place==DNSResourceRecord::ANSWER) {
106 rr.d_name = qname;
107 }
108 }
109 return rcode;
110
111 }
112
113 boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const
114 {
115 if (dh)
116 return *dh;
117 return boost::optional<dnsheader>();
118 }
119
120 vector<string> RecursorLua4::DNSQuestion::getEDNSFlags() const
121 {
122 vector<string> ret;
123 if (ednsFlags) {
124 if (*ednsFlags & EDNSOpts::DNSSECOK)
125 ret.push_back("DO");
126 }
127 return ret;
128 }
129
130 bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag) const
131 {
132 if (ednsFlags) {
133 if (flag == "DO" && (*ednsFlags & EDNSOpts::DNSSECOK))
134 return true;
135 }
136 return false;
137 }
138
139 vector<pair<uint16_t, string> > RecursorLua4::DNSQuestion::getEDNSOptions() const
140 {
141 if(ednsOptions)
142 return *ednsOptions;
143 else
144 return vector<pair<uint16_t,string>>();
145 }
146
147 boost::optional<string> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const
148 {
149 if(ednsOptions)
150 for(const auto& o : *ednsOptions)
151 if(o.first==code)
152 return o.second;
153
154 return boost::optional<string>();
155 }
156
157 boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() const
158 {
159
160 if(ednsOptions) {
161 for(const auto& o : *ednsOptions) {
162 if(o.first==EDNSOptionCode::ECS) {
163 EDNSSubnetOpts eso;
164 if(getEDNSSubnetOptsFromString(o.second, &eso))
165 return eso.source;
166 else
167 break;
168 }
169 }
170 }
171 return boost::optional<Netmask>();
172 }
173
174
175 vector<pair<int, DNSRecord> > RecursorLua4::DNSQuestion::getRecords() const
176 {
177 vector<pair<int, DNSRecord> > ret;
178 int num=1;
179 for(const auto& r : records) {
180 ret.push_back({num++, r});
181 }
182 return ret;
183 }
184 void RecursorLua4::DNSQuestion::setRecords(const vector<pair<int, DNSRecord> >& recs)
185 {
186 records.clear();
187 for(const auto& p : recs) {
188 records.push_back(p.second);
189 }
190 }
191
192 void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name)
193 {
194 DNSRecord dr;
195 dr.d_name=name ? DNSName(*name) : qname;
196 dr.d_ttl=ttl.get_value_or(3600);
197 dr.d_type = type;
198 dr.d_place = place;
199 dr.d_content = DNSRecordContent::mastermake(type, 1, content);
200 records.push_back(dr);
201 }
202
203 void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name)
204 {
205 addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name);
206 }
207
208 struct DynMetric
209 {
210 std::atomic<unsigned long>* ptr;
211 void inc() { (*ptr)++; }
212 void incBy(unsigned int by) { (*ptr)+= by; }
213 unsigned long get() { return *ptr; }
214 void set(unsigned long val) { *ptr =val; }
215 };
216
217 RecursorLua4::RecursorLua4(const std::string& fname)
218 {
219 d_lw = std::unique_ptr<LuaContext>(new LuaContext);
220
221 d_lw->registerFunction<int(dnsheader::*)()>("getID", [](dnsheader& dh) { return dh.id; });
222 d_lw->registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) { return dh.cd; });
223 d_lw->registerFunction<bool(dnsheader::*)()>("getTC", [](dnsheader& dh) { return dh.tc; });
224 d_lw->registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) { return dh.ra; });
225 d_lw->registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) { return dh.ad; });
226 d_lw->registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) { return dh.aa; });
227 d_lw->registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) { return dh.rd; });
228 d_lw->registerFunction<int(dnsheader::*)()>("getRCODE", [](dnsheader& dh) { return dh.rcode; });
229 d_lw->registerFunction<int(dnsheader::*)()>("getOPCODE", [](dnsheader& dh) { return dh.opcode; });
230 d_lw->registerFunction<int(dnsheader::*)()>("getQDCOUNT", [](dnsheader& dh) { return ntohs(dh.qdcount); });
231 d_lw->registerFunction<int(dnsheader::*)()>("getANCOUNT", [](dnsheader& dh) { return ntohs(dh.ancount); });
232 d_lw->registerFunction<int(dnsheader::*)()>("getNSCOUNT", [](dnsheader& dh) { return ntohs(dh.nscount); });
233 d_lw->registerFunction<int(dnsheader::*)()>("getARCOUNT", [](dnsheader& dh) { return ntohs(dh.arcount); });
234
235 d_lw->writeFunction("newDN", [](boost::variant<const std::string, const DNSName> dom){
236 if(dom.which() == 0)
237 return DNSName(boost::get<const std::string>(dom));
238 else
239 return DNSName(boost::get<const DNSName>(dom));
240 });
241 d_lw->registerFunction("isPartOf", &DNSName::isPartOf);
242 d_lw->registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
243 d_lw->registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
244 d_lw->registerFunction<bool(DNSName::*)(const std::string&)>(
245 "equal",
246 [](const DNSName& lhs, const std::string& rhs) {
247 return lhs==DNSName(rhs);
248 }
249 );
250 d_lw->registerFunction("__eq", &DNSName::operator==);
251
252 d_lw->registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
253 d_lw->registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
254 d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
255 d_lw->registerFunction<string(ComboAddress::*)()>("getRaw", [](const ComboAddress& ca) {
256 if(ca.sin4.sin_family == AF_INET) {
257 auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4);
258 }
259 else
260 return string((const char*)&ca.sin6.sin6_addr.s6_addr, 16);
261 } );
262 d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
263 d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
264 d_lw->registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
265 d_lw->registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
266 d_lw->registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
267
268 d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); });
269 typedef std::unordered_set<ComboAddress,ComboAddress::addressOnlyHash,ComboAddress::addressOnlyEqual> cas_t;
270 d_lw->writeFunction("newCAS", []{ return cas_t(); });
271
272
273 d_lw->registerFunction<void(cas_t::*)(boost::variant<string,ComboAddress, vector<pair<unsigned int,string> > >)>(
274 "add",
275 [](cas_t& cas, const boost::variant<string,ComboAddress,vector<pair<unsigned int,string> > >& in)
276 {
277 try {
278 if(auto s = boost::get<string>(&in)) {
279 cas.insert(ComboAddress(*s));
280 }
281 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
282 for(const auto&entry : *v)
283 cas.insert(ComboAddress(entry.second));
284 }
285 else {
286 cas.insert(boost::get<ComboAddress>(in));
287 }
288 }
289 catch(std::exception& e) { theL() <<Logger::Error<<e.what()<<endl; }
290 });
291
292 d_lw->registerFunction<bool(cas_t::*)(const ComboAddress&)>("check",[](const cas_t& cas, const ComboAddress&ca) {
293 return (bool)cas.count(ca);
294 });
295
296 d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>(
297 "equal",
298 [](const ComboAddress& lhs, const ComboAddress& rhs) {
299 return ComboAddress::addressOnlyEqual()(lhs, rhs);
300 }
301 );
302
303 d_lw->writeFunction("newNetmask", [](const string& s) { return Netmask(s); });
304 d_lw->registerFunction<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary
305 d_lw->registerFunction<ComboAddress(Netmask::*)()>("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } );
306 d_lw->registerFunction("isIpv4", &Netmask::isIpv4);
307 d_lw->registerFunction("isIpv6", &Netmask::isIpv6);
308 d_lw->registerFunction("getBits", &Netmask::getBits);
309 d_lw->registerFunction("toString", &Netmask::toString);
310 d_lw->registerFunction("empty", &Netmask::empty);
311 d_lw->registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match);
312 d_lw->registerFunction("__eq", &Netmask::operator==);
313
314 d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
315 d_lw->registerFunction<void(NetmaskGroup::*)(const std::string&mask)>(
316 "addMask", [](NetmaskGroup&nmg, const std::string& mask){
317 nmg.addMask(mask);
318 }
319 );
320
321 d_lw->registerFunction<void(NetmaskGroup::*)(const vector<pair<unsigned int, std::string>>&)>(
322 "addMasks",
323 [](NetmaskGroup&nmg, const vector<pair<unsigned int, std::string>>& masks){
324 for(const auto& mask: masks)
325 nmg.addMask(mask.second);
326 }
327 );
328
329
330 d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
331 d_lw->registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
332 d_lw->registerFunction<string(DNSName::*)()>("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); });
333 d_lw->registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
334
335 d_lw->registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName& { return dq.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; });
336 d_lw->registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
337 d_lw->registerMember<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion& dq) -> bool { return dq.isTcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
338 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.local; }, [](DNSQuestion& dq, const ComboAddress& newLocal) { (void) newLocal; });
339 d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.remote; }, [](DNSQuestion& dq, const ComboAddress& newRemote) { (void) newRemote; });
340
341 d_lw->registerMember<bool (DNSQuestion::*)>("variable", [](const DNSQuestion& dq) -> bool { return dq.variable; }, [](DNSQuestion& dq, bool newVariable) { dq.variable = newVariable; });
342 d_lw->registerMember<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion& dq) -> bool { return dq.wantsRPZ; }, [](DNSQuestion& dq, bool newWantsRPZ) { dq.wantsRPZ = newWantsRPZ; });
343
344 d_lw->registerMember("rcode", &DNSQuestion::rcode);
345 d_lw->registerMember("tag", &DNSQuestion::tag);
346 d_lw->registerMember("requestorId", &DNSQuestion::requestorId);
347 d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction);
348 d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix);
349 d_lw->registerMember("followupName", &DNSQuestion::followupName);
350 d_lw->registerMember("data", &DNSQuestion::data);
351 d_lw->registerMember("udpQuery", &DNSQuestion::udpQuery);
352 d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer);
353 d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest);
354 d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback);
355 d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy);
356 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyName",
357 [](const DNSFilterEngine::Policy& pol) -> std::string {
358 if(pol.d_name)
359 return *pol.d_name;
360 return std::string();
361 },
362 [](DNSFilterEngine::Policy& pol, const std::string& name) {
363 pol.d_name = std::make_shared<std::string>(name);
364 });
365 d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind);
366 d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl);
367 d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyCustom",
368 [](const DNSFilterEngine::Policy& pol) -> std::string {
369 if(pol.d_custom)
370 return pol.d_custom->getZoneRepresentation();
371 return std::string();
372 },
373 [](DNSFilterEngine::Policy& pol, const std::string& content) {
374 // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
375 pol.d_custom = DNSRecordContent::mastermake(QType::CNAME, 1, content);
376 }
377 );
378 d_lw->registerFunction("getDH", &DNSQuestion::getDH);
379 d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions);
380 d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption);
381 d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet);
382 d_lw->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags);
383 d_lw->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag);
384 d_lw->registerMember("name", &DNSRecord::d_name);
385 d_lw->registerMember("type", &DNSRecord::d_type);
386 d_lw->registerMember("ttl", &DNSRecord::d_ttl);
387 d_lw->registerMember("place", &DNSRecord::d_place);
388
389 d_lw->registerMember("size", &EDNSOptionView::size);
390 d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) { return std::string(option.content, option.size); });
391
392 d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); });
393 d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
394 boost::optional<ComboAddress> ret;
395
396 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content))
397 ret=rec->getCA(53);
398 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content))
399 ret=aaaarec->getCA(53);
400 return ret;
401 });
402
403
404 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); });
405 d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer);
406 d_lw->registerFunction("addRecord", &DNSQuestion::addRecord);
407 d_lw->registerFunction("getRecords", &DNSQuestion::getRecords);
408 d_lw->registerFunction("setRecords", &DNSQuestion::setRecords);
409
410 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->push_back(tag); } });
411 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) {
412 if (dq.policyTags) {
413 dq.policyTags->clear();
414 for (const auto& tag : tags) {
415 dq.policyTags->push_back(tag.second);
416 }
417 }
418 });
419 d_lw->registerFunction<std::vector<std::pair<int, std::string> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) {
420 std::vector<std::pair<int, std::string> > ret;
421 if (dq.policyTags) {
422 int count = 1;
423 for (const auto& tag : *dq.policyTags) {
424 ret.push_back({count++, tag});
425 }
426 }
427 return ret;
428 });
429
430 d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("discardPolicy", [](DNSQuestion& dq, const std::string& policy) {
431 if (dq.discardedPolicies) {
432 (*dq.discardedPolicies)[policy] = true;
433 }
434 });
435
436 d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); });
437 d_lw->registerFunction<void(SuffixMatchNode::*)(boost::variant<string,DNSName, vector<pair<unsigned int,string> > >)>(
438 "add",
439 [](SuffixMatchNode&smn, const boost::variant<string,DNSName,vector<pair<unsigned int,string> > >& in){
440 try {
441 if(auto s = boost::get<string>(&in)) {
442 smn.add(DNSName(*s));
443 }
444 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
445 for(const auto& entry : *v)
446 smn.add(DNSName(entry.second));
447 }
448 else {
449 smn.add(boost::get<DNSName>(in));
450 }
451 }
452 catch(std::exception& e) {
453 theL() <<Logger::Error<<e.what()<<endl;
454 }
455 }
456 );
457
458 d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
459 d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString);
460
461
462 d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) {
463 theL() << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl;
464 });
465 typedef vector<pair<string, int> > in_t;
466 vector<pair<string, boost::variant<int, in_t, struct timeval* > > > pd{
467 {"PASS", (int)PolicyDecision::PASS}, {"DROP", (int)PolicyDecision::DROP},
468 {"TRUNCATE", (int)PolicyDecision::TRUNCATE}
469 };
470
471 vector<pair<string, int> > rcodes = {{"NOERROR", RCode::NoError },
472 {"FORMERR", RCode::FormErr },
473 {"SERVFAIL", RCode::ServFail },
474 {"NXDOMAIN", RCode::NXDomain },
475 {"NOTIMP", RCode::NotImp },
476 {"REFUSED", RCode::Refused },
477 {"YXDOMAIN", RCode::YXDomain },
478 {"YXRRSET", RCode::YXRRSet },
479 {"NXRRSET", RCode::NXRRSet },
480 {"NOTAUTH", RCode::NotAuth },
481 {"NOTZONE", RCode::NotZone }};
482 for(const auto& rcode : rcodes)
483 pd.push_back({rcode.first, rcode.second});
484
485 pd.push_back({"loglevels", in_t{
486 {"Alert", LOG_ALERT},
487 {"Critical", LOG_CRIT},
488 {"Debug", LOG_DEBUG},
489 {"Emergency", LOG_EMERG},
490 {"Info", LOG_INFO},
491 {"Notice", LOG_NOTICE},
492 {"Warning", LOG_WARNING},
493 {"Error", LOG_ERR}
494 }});
495
496 pd.push_back({"policykinds", in_t {
497 {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction},
498 {"Drop", (int)DNSFilterEngine::PolicyKind::Drop },
499 {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN},
500 {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA },
501 {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate},
502 {"Custom", (int)DNSFilterEngine::PolicyKind::Custom }
503 }});
504
505 for(const auto& n : QType::names)
506 pd.push_back({n.first, n.second});
507 pd.push_back({"now", &g_now});
508 d_lw->registerMember("tv_sec", &timeval::tv_sec);
509 d_lw->registerMember("tv_usec", &timeval::tv_usec);
510
511 d_lw->writeVariable("pdns", pd);
512
513 d_lw->writeFunction("getMetric", [](const std::string& str) {
514 return DynMetric{getDynMetric(str)};
515 });
516
517 d_lw->registerFunction("inc", &DynMetric::inc);
518 d_lw->registerFunction("incBy", &DynMetric::incBy);
519 d_lw->registerFunction("set", &DynMetric::set);
520 d_lw->registerFunction("get", &DynMetric::get);
521
522 d_lw->writeFunction("getStat", [](const std::string& str) {
523 uint64_t result = 0;
524 optional<uint64_t> value = getStatByName(str);
525 if (value) {
526 result = *value;
527 }
528 return result;
529 });
530
531 d_lw->writeFunction("getRecursorThreadId", []() {
532 return getRecursorThreadId();
533 });
534
535 d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) {
536 if (g_snmpAgent) {
537 g_snmpAgent->sendCustomTrap(str);
538 }
539 });
540
541 ifstream ifs(fname);
542 if(!ifs) {
543 throw std::runtime_error("Unable to read configuration file from '"+fname+"': "+strerror(errno));
544 }
545 d_lw->executeCode(ifs);
546
547 d_prerpz = d_lw->readVariable<boost::optional<luacall_t>>("prerpz").get_value_or(0);
548 d_preresolve = d_lw->readVariable<boost::optional<luacall_t>>("preresolve").get_value_or(0);
549 d_nodata = d_lw->readVariable<boost::optional<luacall_t>>("nodata").get_value_or(0);
550 d_nxdomain = d_lw->readVariable<boost::optional<luacall_t>>("nxdomain").get_value_or(0);
551 d_postresolve = d_lw->readVariable<boost::optional<luacall_t>>("postresolve").get_value_or(0);
552 d_preoutquery = d_lw->readVariable<boost::optional<luacall_t>>("preoutquery").get_value_or(0);
553
554 d_ipfilter = d_lw->readVariable<boost::optional<ipfilter_t>>("ipfilter").get_value_or(0);
555 d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0);
556 }
557
558 bool RecursorLua4::prerpz(DNSQuestion& dq, int& ret)
559 {
560 return genhook(d_prerpz, dq, ret);
561 }
562
563 bool RecursorLua4::preresolve(DNSQuestion& dq, int& ret)
564 {
565 return genhook(d_preresolve, dq, ret);
566 }
567
568 bool RecursorLua4::nxdomain(DNSQuestion& dq, int& ret)
569 {
570 return genhook(d_nxdomain, dq, ret);
571 }
572
573 bool RecursorLua4::nodata(DNSQuestion& dq, int& ret)
574 {
575 return genhook(d_nodata, dq, ret);
576 }
577
578 bool RecursorLua4::postresolve(DNSQuestion& dq, int& ret)
579 {
580 return genhook(d_postresolve, dq, ret);
581 }
582
583 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret)
584 {
585 bool variableAnswer = false;
586 bool wantsRPZ = false;
587 RecursorLua4::DNSQuestion dq(ns, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ);
588 dq.currentRecords = &res;
589
590 return genhook(d_preoutquery, dq, ret);
591 }
592
593 bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh)
594 {
595 if(d_ipfilter)
596 return d_ipfilter(remote, local, dh);
597 return false; // don't block
598 }
599
600 unsigned 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 std::map<uint16_t, EDNSOptionView>& ednsOptions, bool tcp, std::string& requestorId)
601 {
602 if(d_gettag) {
603 auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp);
604
605 if (policyTags) {
606 const auto& tags = std::get<1>(ret);
607 if (tags) {
608 for (const auto& tag : *tags) {
609 policyTags->push_back(tag.second);
610 }
611 }
612 }
613 const auto dataret = std::get<2>(ret);
614 if (dataret) {
615 data = *dataret;
616 }
617 const auto reqIdret = std::get<3>(ret);
618 if (reqIdret) {
619 requestorId = *reqIdret;
620 }
621 return std::get<0>(ret);
622 }
623 return 0;
624 }
625
626 bool RecursorLua4::genhook(luacall_t& func, DNSQuestion& dq, int& ret)
627 {
628 if(!func)
629 return false;
630
631 if (dq.currentRecords) {
632 dq.records = *dq.currentRecords;
633 } else {
634 dq.records.clear();
635 }
636
637 dq.followupFunction.clear();
638 dq.followupPrefix.clear();
639 dq.followupName.clear();
640 dq.udpQuery.clear();
641 dq.udpAnswer.clear();
642 dq.udpCallback.clear();
643
644 dq.rcode = ret;
645 bool handled=func(&dq);
646
647 if(handled) {
648 loop:;
649 ret=dq.rcode;
650
651 if(!dq.followupFunction.empty()) {
652 if(dq.followupFunction=="followCNAMERecords") {
653 ret = followCNAMERecords(dq.records, QType(dq.qtype));
654 }
655 else if(dq.followupFunction=="getFakeAAAARecords") {
656 ret=getFakeAAAARecords(dq.followupName, dq.followupPrefix, dq.records);
657 }
658 else if(dq.followupFunction=="getFakePTRRecords") {
659 ret=getFakePTRRecords(dq.followupName, dq.followupPrefix, dq.records);
660 }
661 else if(dq.followupFunction=="udpQueryResponse") {
662 dq.udpAnswer = GenUDPQueryResponse(dq.udpQueryDest, dq.udpQuery);
663 auto cbFunc = d_lw->readVariable<boost::optional<luacall_t>>(dq.udpCallback).get_value_or(0);
664 if(!cbFunc) {
665 theL()<<Logger::Error<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl;
666 return false;
667 }
668 bool result=cbFunc(&dq);
669 if(!result) {
670 return false;
671 }
672 goto loop;
673 }
674 }
675 if (dq.currentRecords) {
676 *dq.currentRecords = dq.records;
677 }
678 }
679
680 // see if they added followup work for us too
681 return handled;
682 }
683
684 RecursorLua4::~RecursorLua4(){}