]>
Commit | Line | Data |
---|---|---|
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 | 18 | BaseLua4::BaseLua4() = default; |
9694e14f | 19 | |
cceacd60 | 20 | void 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 | ||
33 | void BaseLua4::loadString(const std::string &script) { | |
34 | std::istringstream iss(script); | |
35 | loadStream(iss); | |
36 | }; | |
37 | ||
c4e71b7c OM |
38 | // By default no features |
39 | void BaseLua4::getFeatures(Features &) { } | |
40 | ||
f03de9dc | 41 | void 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 |
292 | void BaseLua4::loadStream(std::istream &is) { |
293 | d_lw->executeCode(is); | |
294 | ||
295 | postLoad(); | |
296 | } | |
297 | ||
abb11ca4 | 298 | BaseLua4::~BaseLua4() = default; |