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