]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lua-base4.cc
Merge pull request #14195 from rgacogne/ddist-no-assertions
[thirdparty/pdns.git] / pdns / lua-base4.cc
CommitLineData
cceacd60 1#include <cassert>
f03de9dc
AT
2#include <fstream>
3#include <unordered_set>
4#include <unordered_map>
5#include <typeinfo>
6#include "logger.hh"
adfe9b16 7#include "logging.hh"
f03de9dc
AT
8#include "iputils.hh"
9#include "dnsname.hh"
10#include "dnsparser.hh"
11#include "dnspacket.hh"
12#include "namespaces.hh"
13#include "ednssubnet.hh"
14#include "lua-base4.hh"
0c606b24 15#include "ext/luawrapper/include/LuaContext.hpp"
2c419831 16#include "dns_random.hh"
f03de9dc 17
abb11ca4 18BaseLua4::BaseLua4() = default;
9694e14f 19
cceacd60 20void BaseLua4::loadFile(const std::string& fname)
5bd17cb1 21{
9694e14f 22 std::ifstream ifs(fname);
2157aec4 23 if (!ifs) {
cceacd60
FM
24 auto ret = errno;
25 auto msg = stringerror(ret);
26 SLOG(g_log << Logger::Error << "Unable to read configuration file from '" << fname << "': " << msg << endl,
27 g_slog->withName("lua")->error(Logr::Error, ret, "Unable to read configuration file", "file", Logging::Loggable(fname), "msg", Logging::Loggable(msg)));
28 throw std::runtime_error(msg);
9694e14f
AT
29 }
30 loadStream(ifs);
31};
32
33void BaseLua4::loadString(const std::string &script) {
34 std::istringstream iss(script);
35 loadStream(iss);
36};
37
c4e71b7c
OM
38// By default no features
39void BaseLua4::getFeatures(Features &) { }
40
f03de9dc 41void BaseLua4::prepareContext() {
2bbc9eb0 42 d_lw = std::make_unique<LuaContext>();
f03de9dc 43
1b2c38ad 44 // lua features available
c4e71b7c
OM
45 Features features;
46 getFeatures(features);
47 d_lw->writeVariable("pdns_features", features);
5bd17cb1 48
f03de9dc 49 // dnsheader
7a95b864 50 d_lw->registerFunction<int(dnsheader::*)()>("getID", [](dnsheader& dh) { return ntohs(dh.id); });
f03de9dc
AT
51 d_lw->registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) { return dh.cd; });
52 d_lw->registerFunction<bool(dnsheader::*)()>("getTC", [](dnsheader& dh) { return dh.tc; });
53 d_lw->registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) { return dh.ra; });
54 d_lw->registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) { return dh.ad; });
55 d_lw->registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) { return dh.aa; });
56 d_lw->registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) { return dh.rd; });
57 d_lw->registerFunction<int(dnsheader::*)()>("getRCODE", [](dnsheader& dh) { return dh.rcode; });
58 d_lw->registerFunction<int(dnsheader::*)()>("getOPCODE", [](dnsheader& dh) { return dh.opcode; });
59 d_lw->registerFunction<int(dnsheader::*)()>("getQDCOUNT", [](dnsheader& dh) { return ntohs(dh.qdcount); });
60 d_lw->registerFunction<int(dnsheader::*)()>("getANCOUNT", [](dnsheader& dh) { return ntohs(dh.ancount); });
61 d_lw->registerFunction<int(dnsheader::*)()>("getNSCOUNT", [](dnsheader& dh) { return ntohs(dh.nscount); });
62 d_lw->registerFunction<int(dnsheader::*)()>("getARCOUNT", [](dnsheader& dh) { return ntohs(dh.arcount); });
63
64 // DNSName
65 d_lw->writeFunction("newDN", [](const std::string& dom){ return DNSName(dom); });
d45048a5
AT
66 d_lw->registerFunction("__lt", &DNSName::operator<);
67 d_lw->registerFunction("canonCompare", &DNSName::canonCompare);
68 d_lw->registerFunction("makeRelative", &DNSName::makeRelative);
f03de9dc 69 d_lw->registerFunction("isPartOf", &DNSName::isPartOf);
0be34c86 70 d_lw->registerFunction("getRawLabels", &DNSName::getRawLabels);
f03de9dc 71 d_lw->registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
c052aac7 72 d_lw->registerFunction<size_t(DNSName::*)()>("wireLength", [](const DNSName& name) { return name.wirelength(); });
8c5a204f 73 d_lw->registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
f03de9dc
AT
74 d_lw->registerFunction<bool(DNSName::*)(const std::string&)>("equal", [](const DNSName& lhs, const std::string& rhs) { return lhs==DNSName(rhs); });
75 d_lw->registerEqFunction(&DNSName::operator==);
f03de9dc
AT
76 d_lw->registerToStringFunction<string(DNSName::*)()>([](const DNSName&dn ) { return dn.toString(); });
77 d_lw->registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
78 d_lw->registerFunction<string(DNSName::*)()>("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); });
79 d_lw->registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
80
81 // DNSResourceRecord
27c44631
AT
82 d_lw->writeFunction("newDRR", [](const DNSName& qname, const string& qtype, const unsigned int ttl, const string& content, boost::optional<int> domain_id, boost::optional<int> auth){
83 auto drr = DNSResourceRecord();
84 drr.qname = qname;
85 drr.qtype = qtype;
86 drr.ttl = ttl;
87 drr.setContent(content);
88 if (domain_id)
89 drr.domain_id = *domain_id;
90 if (auth)
91 drr.auth = *auth;
92 return drr;
93 });
f03de9dc
AT
94 d_lw->registerEqFunction(&DNSResourceRecord::operator==);
95 d_lw->registerFunction("__lt", &DNSResourceRecord::operator<);
c052aac7 96 d_lw->registerToStringFunction<string(DNSResourceRecord::*)()>([](const DNSResourceRecord& rec) { return rec.getZoneRepresentation(); });
f03de9dc
AT
97 d_lw->registerFunction<string(DNSResourceRecord::*)()>("toString", [](const DNSResourceRecord& rec) { return rec.getZoneRepresentation();} );
98 d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("qname", [](DNSResourceRecord& rec) { return rec.qname; });
c052aac7 99 d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("wildcardName", [](DNSResourceRecord& rec) { return rec.wildcardname; });
f03de9dc 100 d_lw->registerFunction<string(DNSResourceRecord::*)()>("content", [](DNSResourceRecord& rec) { return rec.content; });
c052aac7 101 d_lw->registerFunction<time_t(DNSResourceRecord::*)()>("lastModified", [](DNSResourceRecord& rec) { return rec.last_modified; });
f03de9dc
AT
102 d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("ttl", [](DNSResourceRecord& rec) { return rec.ttl; });
103 d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("signttl", [](DNSResourceRecord& rec) { return rec.signttl; });
c052aac7 104 d_lw->registerFunction<int(DNSResourceRecord::*)()>("domainId", [](DNSResourceRecord& rec) { return rec.domain_id; });
f03de9dc
AT
105 d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qtype", [](DNSResourceRecord& rec) { return rec.qtype.getCode(); });
106 d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qclass", [](DNSResourceRecord& rec) { return rec.qclass; });
107 d_lw->registerFunction<uint8_t(DNSResourceRecord::*)()>("scopeMask", [](DNSResourceRecord& rec) { return rec.scopeMask; });
108 d_lw->registerFunction<bool(DNSResourceRecord::*)()>("auth", [](DNSResourceRecord& rec) { return rec.auth; });
109 d_lw->registerFunction<bool(DNSResourceRecord::*)()>("disabled", [](DNSResourceRecord& rec) { return rec.disabled; });
110
111 // ComboAddress
112 d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
113 d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
c052aac7 114 d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
f03de9dc
AT
115 d_lw->registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
116 d_lw->registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
117 d_lw->registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
118 d_lw->registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
119 d_lw->registerToStringFunction<string(ComboAddress::*)()>([](const ComboAddress& ca) { return ca.toString(); });
120 d_lw->registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
f03de9dc
AT
121 d_lw->registerFunction<string(ComboAddress::*)()>("getRaw", [](const ComboAddress& ca) {
122 if(ca.sin4.sin_family == AF_INET) {
123 auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4);
124 }
125 else
126 return string((const char*)&ca.sin6.sin6_addr.s6_addr, 16);
127 } );
128
129 d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); });
aec9c907
PD
130 d_lw->writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional<uint16_t> port) {
131 if (raw.size() == 4) {
132 struct sockaddr_in sin4;
133 memset(&sin4, 0, sizeof(sin4));
134 sin4.sin_family = AF_INET;
135 memcpy(&sin4.sin_addr.s_addr, raw.c_str(), raw.size());
136 if (port) {
137 sin4.sin_port = htons(*port);
138 }
139 return ComboAddress(&sin4);
140 }
141 else if (raw.size() == 16) {
142 struct sockaddr_in6 sin6;
143 memset(&sin6, 0, sizeof(sin6));
144 sin6.sin6_family = AF_INET6;
145 memcpy(&sin6.sin6_addr.s6_addr, raw.c_str(), raw.size());
146 if (port) {
147 sin6.sin6_port = htons(*port);
148 }
149 return ComboAddress(&sin6);
150 }
151 return ComboAddress();
152 });
f03de9dc 153 typedef std::unordered_set<ComboAddress,ComboAddress::addressOnlyHash,ComboAddress::addressOnlyEqual> cas_t;
c052aac7 154 d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) { return ComboAddress::addressOnlyEqual()(lhs, rhs); });
f03de9dc
AT
155
156 // cas_t
c052aac7 157 d_lw->writeFunction("newCAS", []{ return cas_t(); });
70c21c40
AT
158 d_lw->registerFunction<void(cas_t::*)(boost::variant<string,ComboAddress, vector<pair<unsigned int,string> > >)>("add",
159 [](cas_t& cas, const boost::variant<string,ComboAddress,vector<pair<unsigned int,string> > >& in)
f03de9dc
AT
160 {
161 try {
70c21c40
AT
162 if(auto s = boost::get<string>(&in)) {
163 cas.insert(ComboAddress(*s));
164 }
165 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
166 for(const auto& str : *v)
167 cas.insert(ComboAddress(str.second));
168 }
169 else
170 cas.insert(boost::get<ComboAddress>(in));
171 }
adfe9b16
OM
172 catch(std::exception& e) {
173 SLOG(g_log <<Logger::Error<<e.what()<<endl,
174 g_slog->withName("lua")->error(Logr::Error, e.what(), "Exception in newCAS", "exception", Logging::Loggable("std::exception")));
175 }
f03de9dc
AT
176 });
177 d_lw->registerFunction<bool(cas_t::*)(const ComboAddress&)>("check",[](const cas_t& cas, const ComboAddress&ca) { return cas.count(ca)>0; });
f03de9dc 178
49f44df3
AT
179 // QType
180 d_lw->writeFunction("newQType", [](const string& s) { QType q; q = s; return q; });
181 d_lw->registerFunction("getCode", &QType::getCode);
d5fcd583 182 d_lw->registerFunction("getName", &QType::toString);
49f44df3 183 d_lw->registerEqFunction<bool(QType::*)(const QType&)>([](const QType& a, const QType& b){ return a == b;}); // operator overloading confuses LuaContext
d5fcd583 184 d_lw->registerToStringFunction(&QType::toString);
49f44df3 185
f03de9dc
AT
186 // Netmask
187 d_lw->writeFunction("newNetmask", [](const string& s) { return Netmask(s); });
188 d_lw->registerFunction<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary
189 d_lw->registerFunction<ComboAddress(Netmask::*)()>("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } );
d14121a8
AT
190 d_lw->registerFunction("isIpv4", &Netmask::isIPv4);
191 d_lw->registerFunction("isIPv4", &Netmask::isIPv4);
37e35fbc
AT
192 d_lw->registerFunction("isIpv6", &Netmask::isIPv6);
193 d_lw->registerFunction("isIPv6", &Netmask::isIPv6);
f03de9dc
AT
194 d_lw->registerFunction("getBits", &Netmask::getBits);
195 d_lw->registerFunction("toString", &Netmask::toString);
196 d_lw->registerFunction("empty", &Netmask::empty);
197 d_lw->registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match);
198 d_lw->registerEqFunction(&Netmask::operator==);
70c21c40 199 d_lw->registerToStringFunction(&Netmask::toString);
f03de9dc
AT
200
201 // NetmaskGroup
223bfcad
PD
202 d_lw->writeFunction("newNMG", [](boost::optional<vector<pair<unsigned int, std::string>>> masks) {
203 auto nmg = NetmaskGroup();
204
205 if (masks) {
206 for(const auto& mask: *masks) {
207 nmg.addMask(mask.second);
208 }
209 }
210
211 return nmg;
212 });
213 // d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
f03de9dc
AT
214 d_lw->registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask) { nmg.addMask(mask); });
215 d_lw->registerFunction<void(NetmaskGroup::*)(const vector<pair<unsigned int, std::string>>&)>("addMasks", [](NetmaskGroup&nmg, const vector<pair<unsigned int, std::string>>& masks) { for(const auto& mask: masks) { nmg.addMask(mask.second); } });
216 d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
217
218 // DNSRecord
d525b58b 219 d_lw->writeFunction("newDR", [](const DNSName& name, const std::string& type, unsigned int ttl, const std::string& content, int place) { QType qtype; qtype = type; auto dr = DNSRecord(); dr.d_name = name; dr.d_type = qtype.getCode(); dr.d_ttl = ttl; dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::make(dr.d_type, QClass::IN, content))); dr.d_place = static_cast<DNSResourceRecord::Place>(place); return dr; });
f03de9dc
AT
220 d_lw->registerMember("name", &DNSRecord::d_name);
221 d_lw->registerMember("type", &DNSRecord::d_type);
222 d_lw->registerMember("ttl", &DNSRecord::d_ttl);
223 d_lw->registerMember("place", &DNSRecord::d_place);
d06dcda4 224 d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.getContent()->getZoneRepresentation(); });
f03de9dc
AT
225 d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
226 boost::optional<ComboAddress> ret;
227
d06dcda4 228 if(auto arec = getRR<ARecordContent>(dr))
dc058f65 229 ret=arec->getCA(53);
d06dcda4 230 else if(auto aaaarec = getRR<AAAARecordContent>(dr))
dc058f65 231 ret=aaaarec->getCA(53);
f03de9dc
AT
232 return ret;
233 });
d525b58b 234 d_lw->registerFunction<void (DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::make(dr.d_type, 1, newContent))); });
f03de9dc
AT
235
236 // pdnsload
adfe9b16
OM
237 d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) {
238 SLOG(g_log << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl,
239 g_slog->withName("lua")->info(static_cast<Logr::Priority>(loglevel.get_value_or(Logr::Warning)), msg));
240 });
e556776d
OM
241 d_lw->writeFunction("pdnsrandom", [](boost::optional<uint32_t> maximum) {
242 return maximum ? dns_random(*maximum) : dns_random_uint32();
243 });
f03de9dc
AT
244
245 // certain constants
f03de9dc
AT
246
247 vector<pair<string, int> > rcodes = {{"NOERROR", RCode::NoError },
248 {"FORMERR", RCode::FormErr },
249 {"SERVFAIL", RCode::ServFail },
250 {"NXDOMAIN", RCode::NXDomain },
251 {"NOTIMP", RCode::NotImp },
252 {"REFUSED", RCode::Refused },
253 {"YXDOMAIN", RCode::YXDomain },
254 {"YXRRSET", RCode::YXRRSet },
255 {"NXRRSET", RCode::NXRRSet },
256 {"NOTAUTH", RCode::NotAuth },
f3f042ef 257 {"NOTZONE", RCode::NotZone },
f7c973de 258 {"DROP", -2 }}; // To give backport-incompatibility warning
f03de9dc
AT
259 for(const auto& rcode : rcodes)
260 d_pd.push_back({rcode.first, rcode.second});
261
262 d_pd.push_back({"place", in_t{
263 {"QUESTION", 0},
264 {"ANSWER", 1},
265 {"AUTHORITY", 2},
266 {"ADDITIONAL", 3}
267 }});
268
269 d_pd.push_back({"loglevels", in_t{
270 {"Alert", LOG_ALERT},
271 {"Critical", LOG_CRIT},
272 {"Debug", LOG_DEBUG},
273 {"Emergency", LOG_EMERG},
274 {"Info", LOG_INFO},
275 {"Notice", LOG_NOTICE},
276 {"Warning", LOG_WARNING},
277 {"Error", LOG_ERR}
278 }});
279
280 for(const auto& n : QType::names)
281 d_pd.push_back({n.first, n.second});
282
283 d_lw->registerMember("tv_sec", &timeval::tv_sec);
284 d_lw->registerMember("tv_usec", &timeval::tv_usec);
285
286 postPrepareContext();
287
288 // so we can let postprepare do changes to this
289 d_lw->writeVariable("pdns", d_pd);
290}
291
9694e14f
AT
292void BaseLua4::loadStream(std::istream &is) {
293 d_lw->executeCode(is);
294
295 postLoad();
296}
297
abb11ca4 298BaseLua4::~BaseLua4() = default;