]>
Commit | Line | Data |
---|---|---|
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 | 34 | RecursorLua4::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 | 39 | bool 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 | 44 | bool 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 | 49 | bool 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 |
54 | bool 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 | 59 | bool 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 | 64 | bool 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 | ||
69 | bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) | |
70 | { | |
71 | return false; | |
72 | } | |
73 | ||
02b47f43 | 74 | int 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 | 84 | static 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 | ||
109 | static 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 | ||
132 | static 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 | 162 | vector<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 | ||
170 | boost::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 | 180 | boost::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 | 198 | vector<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 | } | |
207 | void 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 | 216 | void 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 | 227 | void 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 | |
232 | struct 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 | 241 | RecursorLua4::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 |
554 | bool 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 | 559 | bool 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 | 564 | bool 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 | 569 | bool 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 | 574 | bool 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 | 579 | bool 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 | ||
584 | bool 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 | 591 | int 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 | 609 | bool 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 | 633 | loop:; |
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 | 670 | RecursorLua4::~RecursorLua4(){} |