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