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