]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lua-auth4.cc
wip
[thirdparty/pdns.git] / pdns / lua-auth4.cc
1 #include "config.h"
2 #if defined(HAVE_LUA)
3 #include "ext/luawrapper/include/LuaContext.hpp"
4 #endif
5 #include "lua-auth4.hh"
6 #include "stubresolver.hh"
7 #include <fstream>
8 #include "logger.hh"
9 #include "dnsparser.hh"
10 #include "namespaces.hh"
11 #include "ednssubnet.hh"
12 #include <unordered_set>
13 #include "sstuff.hh"
14 #include <thread>
15 #include <mutex>
16
17 #include "ueberbackend.hh"
18
19 #if !defined(HAVE_LUA)
20
21 AuthLua4::AuthLua4(const std::string& fname) { }
22 bool AuthLua4::updatePolicy(const DNSName &qname, QType qtype, const DNSName &zonename, DNSPacket *packet) { return false; }
23 bool AuthLua4::axfrfilter(const ComboAddress& remote, const DNSName& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out) { return false; }
24 LuaContext* AuthLua4::getLua() { return 0; }
25 AuthLua4::~AuthLua4() { }
26
27 #else
28
29 LuaContext* AuthLua4::getLua()
30 {
31 return d_lw.get();
32 }
33
34 AuthLua4::AuthLua4(const std::string& fname) {
35 d_lw = std::unique_ptr<LuaContext>(new LuaContext);
36 stubParseResolveConf();
37 d_lw->registerFunction<int(dnsheader::*)()>("getID", [](dnsheader& dh) { return dh.id; });
38 d_lw->registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) { return dh.cd; });
39 d_lw->registerFunction<bool(dnsheader::*)()>("getTC", [](dnsheader& dh) { return dh.tc; });
40 d_lw->registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) { return dh.ra; });
41 d_lw->registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) { return dh.ad; });
42 d_lw->registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) { return dh.aa; });
43 d_lw->registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) { return dh.rd; });
44 d_lw->registerFunction<int(dnsheader::*)()>("getRCODE", [](dnsheader& dh) { return dh.rcode; });
45 d_lw->registerFunction<int(dnsheader::*)()>("getOPCODE", [](dnsheader& dh) { return dh.opcode; });
46 d_lw->registerFunction<int(dnsheader::*)()>("getQDCOUNT", [](dnsheader& dh) { return ntohs(dh.qdcount); });
47 d_lw->registerFunction<int(dnsheader::*)()>("getANCOUNT", [](dnsheader& dh) { return ntohs(dh.ancount); });
48 d_lw->registerFunction<int(dnsheader::*)()>("getNSCOUNT", [](dnsheader& dh) { return ntohs(dh.nscount); });
49 d_lw->registerFunction<int(dnsheader::*)()>("getARCOUNT", [](dnsheader& dh) { return ntohs(dh.arcount); });
50
51 d_lw->writeFunction("newDN", [](const std::string& dom){ return DNSName(dom); });
52 d_lw->registerFunction("isPartOf", &DNSName::isPartOf);
53 d_lw->registerFunction<bool(DNSName::*)(const std::string&)>("equal",
54 [](const DNSName& lhs, const std::string& rhs) { return lhs==DNSName(rhs); });
55 d_lw->registerFunction("__eq", &DNSName::operator==);
56
57 d_lw->registerFunction("__eq", &DNSResourceRecord::operator==);
58 d_lw->registerFunction("__lt", &DNSResourceRecord::operator<);
59
60 d_lw->registerFunction<string(DNSResourceRecord::*)()>("toString", [](const DNSResourceRecord& rec) { return rec.getZoneRepresentation();} );
61
62 d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("qname", [](DNSResourceRecord& rec) { return rec.qname; });
63 d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("wildcardname", [](DNSResourceRecord& rec) { return rec.wildcardname; });
64 d_lw->registerFunction<string(DNSResourceRecord::*)()>("content", [](DNSResourceRecord& rec) { return rec.content; });
65 d_lw->registerFunction<time_t(DNSResourceRecord::*)()>("last_modified", [](DNSResourceRecord& rec) { return rec.last_modified; });
66 d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("ttl", [](DNSResourceRecord& rec) { return rec.ttl; });
67 d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("signttl", [](DNSResourceRecord& rec) { return rec.signttl; });
68 d_lw->registerFunction<int(DNSResourceRecord::*)()>("domain_id", [](DNSResourceRecord& rec) { return rec.domain_id; });
69 d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qtype", [](DNSResourceRecord& rec) { return rec.qtype.getCode(); });
70 d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qclass", [](DNSResourceRecord& rec) { return rec.qclass; });
71 d_lw->registerFunction<uint8_t(DNSResourceRecord::*)()>("scopeMask", [](DNSResourceRecord& rec) { return rec.scopeMask; });
72 d_lw->registerFunction<bool(DNSResourceRecord::*)()>("auth", [](DNSResourceRecord& rec) { return rec.auth; });
73 d_lw->registerFunction<bool(DNSResourceRecord::*)()>("disabled", [](DNSResourceRecord& rec) { return rec.disabled; });
74
75 d_lw->registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
76 d_lw->registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
77 d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
78 d_lw->registerFunction<string(ComboAddress::*)()>("getRaw", [](const ComboAddress& ca) {
79 if(ca.sin4.sin_family == AF_INET) {
80 auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4);
81 }
82 else
83 return string((const char*)&ca.sin6.sin6_addr.s6_addr, 16);
84 } );
85
86 d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); });
87 typedef std::unordered_set<ComboAddress,ComboAddress::addressOnlyHash,ComboAddress::addressOnlyEqual> cas_t;
88 d_lw->writeFunction("newCAS", []{ return cas_t(); });
89
90
91 d_lw->registerFunction<void(cas_t::*)(boost::variant<string,ComboAddress, vector<pair<unsigned int,string> > >)>("add",
92 [](cas_t& cas, const boost::variant<string,ComboAddress,vector<pair<unsigned int,string> > >& in)
93 {
94 try {
95 if(auto s = boost::get<string>(&in)) {
96 cas.insert(ComboAddress(*s));
97 }
98 else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
99 for(const auto& str : *v)
100 cas.insert(ComboAddress(str.second));
101 }
102 else
103 cas.insert(boost::get<ComboAddress>(in));
104 }
105 catch(std::exception& e) { theL() <<Logger::Error<<e.what()<<endl; }
106 });
107
108 d_lw->registerFunction<bool(cas_t::*)(const ComboAddress&)>("check",[](const cas_t& cas, const ComboAddress&ca) {
109 return (bool)cas.count(ca);
110 });
111
112
113
114 d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) {
115 return ComboAddress::addressOnlyEqual()(lhs, rhs);
116 });
117
118
119 d_lw->registerFunction<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary
120 d_lw->registerFunction("toString", &Netmask::toString);
121 d_lw->registerFunction("empty", &Netmask::empty);
122
123 d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
124 d_lw->registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
125 {
126 nmg.addMask(mask);
127 });
128
129 d_lw->registerFunction<void(NetmaskGroup::*)(const vector<pair<unsigned int, std::string>>&)>("addMasks", [](NetmaskGroup&nmg, const vector<pair<unsigned int, std::string>>& masks)
130 {
131 for(const auto& mask: masks)
132 nmg.addMask(mask.second);
133 });
134
135
136 d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
137 d_lw->registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
138 d_lw->registerFunction<string(DNSName::*)()>("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); });
139 d_lw->registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
140 d_lw->registerMember("name", &DNSRecord::d_name);
141 d_lw->registerMember("type", &DNSRecord::d_type);
142 d_lw->registerMember("ttl", &DNSRecord::d_ttl);
143
144
145 d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); });
146 d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
147 boost::optional<ComboAddress> ret;
148
149 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content))
150 ret=rec->getCA(53);
151 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content))
152 ret=aaaarec->getCA(53);
153 return ret;
154 });
155
156
157 d_lw->registerFunction<void(DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.d_content = DNSRecordContent::mastermake(dr.d_type, 1, newContent); });
158
159 d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) {
160 theL() << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl;
161 });
162 typedef vector<pair<string, int> > in_t;
163 vector<pair<string, boost::variant<int, in_t, struct timeval* > > > pd{
164 {"PASS", (int)PolicyDecision::PASS}, {"DROP", (int)PolicyDecision::DROP},
165 {"TRUNCATE", (int)PolicyDecision::TRUNCATE}
166 };
167
168 vector<pair<string, int> > rcodes = {{"NOERROR", RCode::NoError },
169 {"FORMERR", RCode::FormErr },
170 {"SERVFAIL", RCode::ServFail },
171 {"NXDOMAIN", RCode::NXDomain },
172 {"NOTIMP", RCode::NotImp },
173 {"REFUSED", RCode::Refused },
174 {"YXDOMAIN", RCode::YXDomain },
175 {"YXRRSET", RCode::YXRRSet },
176 {"NXRRSET", RCode::NXRRSet },
177 {"NOTAUTH", RCode::NotAuth },
178 {"NOTZONE", RCode::NotZone }};
179 for(const auto& rcode : rcodes)
180 pd.push_back({rcode.first, rcode.second});
181
182 pd.push_back({"place", in_t{
183 {"QUESTION", 0},
184 {"ANSWER", 1},
185 {"AUTHORITY", 2},
186 {"ADDITIONAL", 3}
187 }});
188
189 pd.push_back({"loglevels", in_t{
190 {"Alert", LOG_ALERT},
191 {"Critical", LOG_CRIT},
192 {"Debug", LOG_DEBUG},
193 {"Emergency", LOG_EMERG},
194 {"Info", LOG_INFO},
195 {"Notice", LOG_NOTICE},
196 {"Warning", LOG_WARNING},
197 {"Error", LOG_ERR}
198 }});
199
200 for(const auto& n : QType::names)
201 pd.push_back({n.first, n.second});
202 d_lw->registerMember("tv_sec", &timeval::tv_sec);
203 d_lw->registerMember("tv_usec", &timeval::tv_usec);
204
205 d_lw->writeVariable("pdns", pd);
206
207 d_lw->writeFunction("resolve", [](const std::string& qname, uint16_t qtype) {
208 std::vector<DNSZoneRecord> ret;
209 std::unordered_map<int, DNSResourceRecord> luaResult;
210 stubDoResolve(DNSName(qname), qtype, ret);
211 int i = 0;
212 for(const auto &row: ret) {
213 luaResult[++i] = DNSResourceRecord::fromWire(row.dr);
214 luaResult[i].auth = row.auth;
215 }
216 return luaResult;
217 });
218
219
220 /* update policy */
221 d_lw->registerFunction<DNSName(UpdatePolicyQuery::*)()>("getQName", [](UpdatePolicyQuery& upq) { return upq.qname; });
222 d_lw->registerFunction<DNSName(UpdatePolicyQuery::*)()>("getZoneName", [](UpdatePolicyQuery& upq) { return upq.zonename; });
223 d_lw->registerFunction<uint16_t(UpdatePolicyQuery::*)()>("getQType", [](UpdatePolicyQuery& upq) { return upq.qtype; });
224 d_lw->registerFunction<ComboAddress(UpdatePolicyQuery::*)()>("getLocal", [](UpdatePolicyQuery& upq) { return upq.local; });
225 d_lw->registerFunction<ComboAddress(UpdatePolicyQuery::*)()>("getRemote", [](UpdatePolicyQuery& upq) { return upq.remote; });
226 d_lw->registerFunction<Netmask(UpdatePolicyQuery::*)()>("getRealRemote", [](UpdatePolicyQuery& upq) { return upq.realRemote; });
227 d_lw->registerFunction<DNSName(UpdatePolicyQuery::*)()>("getTsigName", [](UpdatePolicyQuery& upq) { return upq.tsigName; });
228 d_lw->registerFunction<std::string(UpdatePolicyQuery::*)()>("getPeerPrincipal", [](UpdatePolicyQuery& upq) { return upq.peerPrincipal; });
229 /* end of update policy */
230
231 if(!fname.empty()) {
232 ifstream ifs(fname);
233 if(!ifs) {
234 theL()<<Logger::Error<<"Unable to read configuration file from '"<<fname<<"': "<<strerror(errno)<<endl;
235 return;
236 }
237 d_lw->executeCode(ifs);
238
239 d_update_policy = d_lw->readVariable<boost::optional<luacall_update_policy_t>>("updatepolicy").get_value_or(0);
240 d_axfr_filter = d_lw->readVariable<boost::optional<luacall_axfr_filter_t>>("axfrfilter").get_value_or(0);
241 }
242
243 }
244
245 bool AuthLua4::axfrfilter(const ComboAddress& remote, const DNSName& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out) {
246 luacall_axfr_filter_t::result_type ret;
247 int rcode;
248
249 if (d_axfr_filter == NULL) return false;
250
251 ret = d_axfr_filter(remote, zone, in);
252 rcode = std::get<0>(ret);
253 if (rcode < 0)
254 return false;
255 else if (rcode == 1)
256 out.push_back(in);
257 else
258 throw PDNSException("Cannot understand return code "+std::to_string(rcode)+" in axfr filter response");
259
260 const auto& rows = std::get<1>(ret);
261
262 for(const auto& row: rows) {
263 DNSResourceRecord rec;
264 for(const auto& col: row.second) {
265 if (col.first == "qtype")
266 rec.qtype = QType(boost::get<unsigned int>(col.second));
267 else if (col.first == "qname")
268 rec.qname = DNSName(boost::get<std::string>(col.second)).makeLowerCase();
269 else if (col.first == "ttl")
270 rec.ttl = boost::get<unsigned int>(col.second);
271 else if (col.first == "content")
272 rec.setContent(boost::get<std::string>(col.second));
273 else
274 throw PDNSException("Cannot understand "+col.first+" in axfr filter response on row "+std::to_string(row.first));
275 }
276 out.push_back(rec);
277 }
278
279 return true;
280 }
281
282
283 bool AuthLua4::updatePolicy(const DNSName &qname, QType qtype, const DNSName &zonename, DNSPacket *packet) {
284 UpdatePolicyQuery upq;
285 upq.qname = qname;
286 upq.qtype = qtype.getCode();
287 upq.zonename = zonename;
288 upq.local = packet->getLocal();
289 upq.remote = packet->getRemote();
290 upq.realRemote = packet->getRealRemote();
291 upq.tsigName = packet->getTSIGKeyname();
292 upq.peerPrincipal = packet->d_peer_principal;
293
294 return d_update_policy(upq);
295 }
296
297 AuthLua4::~AuthLua4() { }
298
299
300 #endif