]>
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 | ||
b8470add | 54 | 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 | 55 | { |
56 | return false; | |
57 | } | |
58 | ||
c672b54a | 59 | bool RecursorLua4::preoutquery(const ComboAddress& remote, const ComboAddress& local,const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& ret, int& res) |
410d750c | 60 | { |
61 | return false; | |
62 | } | |
63 | ||
64 | bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) | |
65 | { | |
66 | return false; | |
67 | } | |
68 | ||
02b47f43 | 69 | int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags) |
81c0afd8 | 70 | { |
71 | return 0; | |
72 | } | |
73 | ||
410d750c | 74 | |
75 | #else | |
76 | #undef L | |
77 | #include "ext/luawrapper/include/LuaContext.hpp" | |
78 | ||
a3e7b735 | 79 | static int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype) |
80 | { | |
81 | vector<DNSRecord> resolved; | |
82 | DNSName target; | |
83 | for(const DNSRecord& rr : ret) { | |
84 | if(rr.d_type == QType::CNAME) { | |
ba3c54cb RG |
85 | auto rec = getRR<CNAMERecordContent>(rr); |
86 | if(rec) { | |
87 | target=rec->getTarget(); | |
88 | break; | |
89 | } | |
a3e7b735 | 90 | } |
91 | } | |
92 | if(target.empty()) | |
93 | return 0; | |
94 | ||
95 | int rcode=directResolve(target, qtype, 1, resolved); // 1 == class | |
96 | ||
97 | for(const DNSRecord& rr : resolved) { | |
98 | ret.push_back(rr); | |
99 | } | |
100 | return rcode; | |
101 | ||
102 | } | |
103 | ||
104 | static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret) | |
105 | { | |
106 | int rcode=directResolve(qname, QType(QType::A), 1, ret); | |
107 | ||
108 | ComboAddress prefixAddress(prefix); | |
109 | ||
110 | for(DNSRecord& rr : ret) | |
111 | { | |
112 | if(rr.d_type == QType::A && rr.d_place==DNSResourceRecord::ANSWER) { | |
ba3c54cb RG |
113 | if(auto rec = getRR<ARecordContent>(rr)) { |
114 | ComboAddress ipv4(rec->getCA()); | |
115 | uint32_t tmp; | |
116 | memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4); | |
117 | // tmp=htonl(tmp); | |
118 | memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4); | |
119 | rr.d_content = std::make_shared<AAAARecordContent>(prefixAddress); | |
120 | rr.d_type = QType::AAAA; | |
121 | } | |
a3e7b735 | 122 | } |
123 | } | |
124 | return rcode; | |
125 | } | |
126 | ||
127 | static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret) | |
128 | { | |
129 | /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it | |
130 | and turn it into an IPv4 in-addr.arpa query */ | |
131 | ret.clear(); | |
132 | vector<string> parts = qname.getRawLabels(); | |
133 | ||
134 | if(parts.size() < 8) | |
135 | return -1; | |
136 | ||
137 | string newquery; | |
138 | for(int n = 0; n < 4; ++n) { | |
139 | newquery += | |
926ccaca | 140 | std::to_string(stoll(parts[n*2], 0, 16) + 16*stoll(parts[n*2+1], 0, 16)); |
a3e7b735 | 141 | newquery.append(1,'.'); |
142 | } | |
143 | newquery += "in-addr.arpa."; | |
144 | ||
145 | ||
146 | int rcode = directResolve(DNSName(newquery), QType(QType::PTR), 1, ret); | |
147 | for(DNSRecord& rr : ret) | |
148 | { | |
149 | if(rr.d_type == QType::PTR && rr.d_place==DNSResourceRecord::ANSWER) { | |
150 | rr.d_name = qname; | |
151 | } | |
152 | } | |
153 | return rcode; | |
154 | ||
155 | } | |
156 | ||
e8340d27 | 157 | vector<pair<uint16_t, string> > RecursorLua4::DNSQuestion::getEDNSOptions() |
158 | { | |
159 | if(ednsOptions) | |
160 | return *ednsOptions; | |
161 | else | |
162 | return vector<pair<uint16_t,string>>(); | |
163 | } | |
164 | ||
165 | boost::optional<string> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) | |
166 | { | |
167 | if(ednsOptions) | |
168 | for(const auto& o : *ednsOptions) | |
169 | if(o.first==code) | |
170 | return o.second; | |
171 | ||
172 | return boost::optional<string>(); | |
173 | } | |
174 | ||
5ecf1d7e | 175 | boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() |
176 | { | |
177 | ||
178 | if(ednsOptions) { | |
179 | for(const auto& o : *ednsOptions) { | |
180 | if(o.first==8) { | |
181 | EDNSSubnetOpts eso; | |
182 | if(getEDNSSubnetOptsFromString(o.second, &eso)) | |
183 | return eso.source; | |
184 | else | |
185 | break; | |
186 | } | |
187 | } | |
188 | } | |
189 | return boost::optional<Netmask>(); | |
190 | } | |
191 | ||
e8340d27 | 192 | |
a3e7b735 | 193 | vector<pair<int, DNSRecord> > RecursorLua4::DNSQuestion::getRecords() |
194 | { | |
195 | vector<pair<int, DNSRecord> > ret; | |
196 | int num=1; | |
197 | for(const auto& r : records) { | |
198 | ret.push_back({num++, r}); | |
199 | } | |
200 | return ret; | |
201 | } | |
202 | void RecursorLua4::DNSQuestion::setRecords(const vector<pair<int, DNSRecord> >& recs) | |
203 | { | |
204 | records.clear(); | |
205 | for(const auto& p : recs) { | |
206 | records.push_back(p.second); | |
207 | cout<<"Setting: "<<p.second.d_content->getZoneRepresentation()<<endl; | |
208 | } | |
209 | } | |
210 | ||
aee72a7b | 211 | void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name) |
a3e7b735 | 212 | { |
213 | DNSRecord dr; | |
aee72a7b | 214 | dr.d_name=name ? DNSName(*name) : qname; |
a3e7b735 | 215 | dr.d_ttl=ttl.get_value_or(3600); |
216 | dr.d_type = type; | |
217 | dr.d_place = place; | |
218 | dr.d_content = shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(type, 1, content)); | |
219 | records.push_back(dr); | |
220 | } | |
221 | ||
aee72a7b | 222 | void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name) |
a3e7b735 | 223 | { |
aee72a7b | 224 | addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name); |
a3e7b735 | 225 | } |
9f89a5f1 | 226 | |
227 | struct DynMetric | |
228 | { | |
229 | std::atomic<unsigned long>* ptr; | |
230 | void inc() { (*ptr)++; } | |
231 | void incBy(unsigned int by) { (*ptr)+= by; } | |
232 | unsigned long get() { return *ptr; } | |
233 | void set(unsigned long val) { *ptr =val; } | |
234 | }; | |
235 | ||
808c5ef7 | 236 | RecursorLua4::RecursorLua4(const std::string& fname) |
237 | { | |
3dcc3fde | 238 | d_lw = std::unique_ptr<LuaContext>(new LuaContext); |
f5062066 | 239 | |
240 | d_lw->registerFunction<int(dnsheader::*)()>("getID", [](dnsheader& dh) { return dh.id; }); | |
241 | d_lw->registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) { return dh.cd; }); | |
242 | d_lw->registerFunction<bool(dnsheader::*)()>("getTC", [](dnsheader& dh) { return dh.tc; }); | |
243 | d_lw->registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) { return dh.ra; }); | |
244 | d_lw->registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) { return dh.ad; }); | |
245 | d_lw->registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) { return dh.aa; }); | |
246 | d_lw->registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) { return dh.rd; }); | |
247 | d_lw->registerFunction<int(dnsheader::*)()>("getRCODE", [](dnsheader& dh) { return dh.rcode; }); | |
248 | d_lw->registerFunction<int(dnsheader::*)()>("getOPCODE", [](dnsheader& dh) { return dh.opcode; }); | |
249 | d_lw->registerFunction<int(dnsheader::*)()>("getQDCOUNT", [](dnsheader& dh) { return ntohs(dh.qdcount); }); | |
250 | d_lw->registerFunction<int(dnsheader::*)()>("getANCOUNT", [](dnsheader& dh) { return ntohs(dh.ancount); }); | |
251 | d_lw->registerFunction<int(dnsheader::*)()>("getNSCOUNT", [](dnsheader& dh) { return ntohs(dh.nscount); }); | |
252 | d_lw->registerFunction<int(dnsheader::*)()>("getARCOUNT", [](dnsheader& dh) { return ntohs(dh.arcount); }); | |
253 | ||
0bfc199a PD |
254 | d_lw->writeFunction("newDN", [](boost::variant<const std::string, const DNSName> dom){ |
255 | if(dom.which() == 0) | |
256 | return DNSName(boost::get<const std::string>(dom)); | |
257 | else | |
258 | return DNSName(boost::get<const DNSName>(dom)); | |
259 | }); | |
e632cd29 | 260 | d_lw->registerFunction("isPartOf", &DNSName::isPartOf); |
805f3e03 PL |
261 | d_lw->registerFunction<bool(DNSName::*)(const std::string&)>( |
262 | "equal", | |
263 | [](const DNSName& lhs, const std::string& rhs) { | |
264 | return lhs==DNSName(rhs); | |
265 | } | |
266 | ); | |
e632cd29 | 267 | d_lw->registerFunction("__eq", &DNSName::operator==); |
268 | ||
f90c7544 | 269 | d_lw->registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); }); |
0a112365 | 270 | d_lw->registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); |
271 | d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } ); | |
6232ff13 | 272 | d_lw->registerFunction<string(ComboAddress::*)()>("getRaw", [](const ComboAddress& ca) { |
273 | if(ca.sin4.sin_family == AF_INET) { | |
274 | auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4); | |
275 | } | |
276 | else | |
277 | return string((const char*)&ca.sin6.sin6_addr.s6_addr, 16); | |
278 | } ); | |
0a112365 | 279 | |
f90c7544 | 280 | d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); }); |
08dcccd6 | 281 | typedef std::unordered_set<ComboAddress,ComboAddress::addressOnlyHash,ComboAddress::addressOnlyEqual> cas_t; |
282 | d_lw->writeFunction("newCAS", []{ return cas_t(); }); | |
283 | ||
284 | ||
805f3e03 PL |
285 | d_lw->registerFunction<void(cas_t::*)(boost::variant<string,ComboAddress, vector<pair<unsigned int,string> > >)>( |
286 | "add", | |
287 | [](cas_t& cas, const boost::variant<string,ComboAddress,vector<pair<unsigned int,string> > >& in) | |
288 | { | |
289 | try { | |
290 | if(auto s = boost::get<string>(&in)) { | |
291 | cas.insert(ComboAddress(*s)); | |
292 | } | |
293 | else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) { | |
294 | for(const auto& s : *v) | |
295 | cas.insert(ComboAddress(s.second)); | |
296 | } | |
297 | else { | |
298 | cas.insert(boost::get<ComboAddress>(in)); | |
299 | } | |
300 | } | |
301 | catch(std::exception& e) { theL() <<Logger::Error<<e.what()<<endl; } | |
302 | }); | |
08dcccd6 | 303 | |
304 | d_lw->registerFunction<bool(cas_t::*)(const ComboAddress&)>("check",[](const cas_t& cas, const ComboAddress&ca) { | |
305 | return (bool)cas.count(ca); | |
306 | }); | |
307 | ||
805f3e03 PL |
308 | d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>( |
309 | "equal", | |
310 | [](const ComboAddress& lhs, const ComboAddress& rhs) { | |
cab04622 | 311 | return ComboAddress::addressOnlyEqual()(lhs, rhs); |
805f3e03 PL |
312 | } |
313 | ); | |
cab04622 | 314 | |
5ecf1d7e | 315 | |
316 | d_lw->registerFunction<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary | |
9d4da043 AT |
317 | d_lw->registerFunction<ComboAddress(Netmask::*)()>("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } ); |
318 | d_lw->registerFunction("isIpv4", &Netmask::isIpv4); | |
319 | d_lw->registerFunction("isIpv6", &Netmask::isIpv6); | |
320 | d_lw->registerFunction("getBits", &Netmask::getBits); | |
5ecf1d7e | 321 | d_lw->registerFunction("toString", &Netmask::toString); |
dc5748ed | 322 | d_lw->registerFunction("empty", &Netmask::empty); |
9d4da043 AT |
323 | d_lw->registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match); |
324 | d_lw->registerFunction("__eq", &Netmask::operator==); | |
5ecf1d7e | 325 | |
f90c7544 | 326 | d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); }); |
805f3e03 PL |
327 | d_lw->registerFunction<void(NetmaskGroup::*)(const std::string&mask)>( |
328 | "addMask", [](NetmaskGroup&nmg, const std::string& mask){ | |
329 | nmg.addMask(mask); | |
330 | } | |
331 | ); | |
f90c7544 | 332 | |
805f3e03 PL |
333 | d_lw->registerFunction<void(NetmaskGroup::*)(const vector<pair<unsigned int, std::string>>&)>( |
334 | "addMasks", | |
335 | [](NetmaskGroup&nmg, const vector<pair<unsigned int, std::string>>& masks){ | |
336 | for(const auto& mask: masks) | |
337 | nmg.addMask(mask.second); | |
338 | } | |
339 | ); | |
7d5f094a | 340 | |
341 | ||
f90c7544 | 342 | d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match); |
a3e7b735 | 343 | d_lw->registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); }); |
f27783bf PD |
344 | d_lw->registerFunction<string(DNSName::*)()>("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); }); |
345 | d_lw->registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); }); | |
a3e7b735 | 346 | d_lw->registerMember("qname", &DNSQuestion::qname); |
347 | d_lw->registerMember("qtype", &DNSQuestion::qtype); | |
c672b54a | 348 | d_lw->registerMember("isTcp", &DNSQuestion::isTcp); |
8fb39a38 | 349 | d_lw->registerMember("localaddr", &DNSQuestion::local); |
350 | d_lw->registerMember("remoteaddr", &DNSQuestion::remote); | |
a3e7b735 | 351 | d_lw->registerMember("rcode", &DNSQuestion::rcode); |
ba461517 | 352 | d_lw->registerMember("tag", &DNSQuestion::tag); |
a3e7b735 | 353 | d_lw->registerMember("variable", &DNSQuestion::variable); |
354 | d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction); | |
355 | d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix); | |
356 | d_lw->registerMember("followupName", &DNSQuestion::followupName); | |
6b8b26c8 | 357 | d_lw->registerMember("data", &DNSQuestion::data); |
358 | d_lw->registerMember("udpQuery", &DNSQuestion::udpQuery); | |
359 | d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer); | |
360 | d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest); | |
361 | d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback); | |
b8470add | 362 | d_lw->registerMember("wantsRPZ", &DNSQuestion::wantsRPZ); |
667f6c7c | 363 | d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy); |
db486de5 PL |
364 | d_lw->registerMember("policyName", &DNSFilterEngine::Policy::d_name); |
365 | d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind); | |
366 | d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl); | |
367 | d_lw->registerMember<DNSFilterEngine::Policy, string>("policyCustom", | |
368 | [](const DNSFilterEngine::Policy& pol) -> string { | |
369 | return pol.d_custom->getZoneRepresentation(); | |
370 | }, | |
371 | [](DNSFilterEngine::Policy& pol, string content) { | |
372 | // Only CNAMES for now, when we ever add a d_custom_type, there will be pain | |
373 | pol.d_custom = shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(QType::CNAME, 1, content)); | |
374 | } | |
375 | ); | |
e8340d27 | 376 | d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions); |
377 | d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption); | |
5ecf1d7e | 378 | d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet); |
a3e7b735 | 379 | d_lw->registerMember("name", &DNSRecord::d_name); |
380 | d_lw->registerMember("type", &DNSRecord::d_type); | |
381 | d_lw->registerMember("ttl", &DNSRecord::d_ttl); | |
e8340d27 | 382 | |
a3e7b735 | 383 | |
384 | d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); }); | |
7d5f094a | 385 | d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) { |
386 | boost::optional<ComboAddress> ret; | |
387 | ||
388 | if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content)) | |
389 | ret=rec->getCA(53); | |
390 | else if(auto rec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content)) | |
391 | ret=rec->getCA(53); | |
392 | return ret; | |
393 | }); | |
a3e7b735 | 394 | |
395 | ||
396 | 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)); }); | |
397 | d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer); | |
08dcccd6 | 398 | d_lw->registerFunction("addRecord", &DNSQuestion::addRecord); |
a3e7b735 | 399 | d_lw->registerFunction("getRecords", &DNSQuestion::getRecords); |
400 | d_lw->registerFunction("setRecords", &DNSQuestion::setRecords); | |
401 | ||
48096cf0 | 402 | d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->push_back(tag); } }); |
667f6c7c | 403 | 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 |
404 | if (dq.policyTags) { |
405 | dq.policyTags->clear(); | |
406 | for (const auto& tag : tags) { | |
407 | dq.policyTags->push_back(tag.second); | |
408 | } | |
667f6c7c RG |
409 | } |
410 | }); | |
411 | d_lw->registerFunction<std::vector<std::pair<int, std::string> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) { | |
412 | std::vector<std::pair<int, std::string> > ret; | |
48096cf0 RG |
413 | if (dq.policyTags) { |
414 | int count = 1; | |
415 | for (const auto& tag : *dq.policyTags) { | |
416 | ret.push_back({count++, tag}); | |
417 | } | |
667f6c7c RG |
418 | } |
419 | return ret; | |
420 | }); | |
421 | ||
a3e7b735 | 422 | d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); }); |
805f3e03 PL |
423 | d_lw->registerFunction<void(SuffixMatchNode::*)(boost::variant<string,DNSName, vector<pair<unsigned int,string> > >)>( |
424 | "add", | |
425 | [](SuffixMatchNode&smn, const boost::variant<string,DNSName,vector<pair<unsigned int,string> > >& in){ | |
426 | try { | |
427 | if(auto s = boost::get<string>(&in)) { | |
428 | smn.add(DNSName(*s)); | |
429 | } | |
430 | else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) { | |
431 | for(const auto& s : *v) | |
432 | smn.add(DNSName(s.second)); | |
433 | } | |
434 | else { | |
435 | smn.add(boost::get<DNSName>(in)); | |
436 | } | |
437 | } | |
438 | catch(std::exception& e) { | |
439 | theL() <<Logger::Error<<e.what()<<endl; | |
440 | } | |
441 | } | |
442 | ); | |
443 | ||
a3e7b735 | 444 | d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); |
c6b99fc1 | 445 | d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString); |
a3e7b735 | 446 | |
01688965 | 447 | |
fceabffa | 448 | d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) { |
dc5748ed | 449 | theL() << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl; |
01688965 | 450 | }); |
451 | typedef vector<pair<string, int> > in_t; | |
f703f766 | 452 | vector<pair<string, boost::variant<int, in_t, struct timeval* > > > pd{ |
a3e7b735 | 453 | {"PASS", (int)PolicyDecision::PASS}, {"DROP", (int)PolicyDecision::DROP}, |
454 | {"TRUNCATE", (int)PolicyDecision::TRUNCATE} | |
455 | }; | |
456 | ||
71851d8c RG |
457 | vector<pair<string, int> > rcodes = {{"NOERROR", RCode::NoError }, |
458 | {"FORMERR", RCode::FormErr }, | |
459 | {"SERVFAIL", RCode::ServFail }, | |
460 | {"NXDOMAIN", RCode::NXDomain }, | |
461 | {"NOTIMP", RCode::NotImp }, | |
462 | {"REFUSED", RCode::Refused }, | |
463 | {"YXDOMAIN", RCode::YXDomain }, | |
464 | {"YXRRSET", RCode::YXRRSet }, | |
465 | {"NXRRSET", RCode::NXRRSet }, | |
466 | {"NOTAUTH", RCode::NotAuth }, | |
467 | {"NOTZONE", RCode::NotZone }}; | |
468 | for(const auto& rcode : rcodes) | |
469 | pd.push_back({rcode.first, rcode.second}); | |
470 | ||
01688965 | 471 | pd.push_back({"loglevels", in_t{ |
4e97e253 | 472 | {"Alert", LOG_ALERT}, |
01688965 | 473 | {"Critical", LOG_CRIT}, |
474 | {"Debug", LOG_DEBUG}, | |
4e97e253 | 475 | {"Emergency", LOG_EMERG}, |
01688965 | 476 | {"Info", LOG_INFO}, |
477 | {"Notice", LOG_NOTICE}, | |
478 | {"Warning", LOG_WARNING}, | |
479 | {"Error", LOG_ERR} | |
480 | }}); | |
fceabffa | 481 | |
db486de5 PL |
482 | pd.push_back({"policykinds", in_t { |
483 | {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction}, | |
484 | {"Drop", (int)DNSFilterEngine::PolicyKind::Drop }, | |
485 | {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN}, | |
486 | {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA }, | |
487 | {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate}, | |
488 | {"Custom", (int)DNSFilterEngine::PolicyKind::Custom } | |
489 | }}); | |
490 | ||
a3e7b735 | 491 | for(const auto& n : QType::names) |
492 | pd.push_back({n.first, n.second}); | |
f703f766 PD |
493 | pd.push_back({"now", &g_now}); |
494 | d_lw->registerMember("tv_sec", &timeval::tv_sec); | |
495 | d_lw->registerMember("tv_usec", &timeval::tv_usec); | |
496 | ||
01688965 | 497 | d_lw->writeVariable("pdns", pd); |
9f89a5f1 | 498 | |
499 | d_lw->writeFunction("getMetric", [](const std::string& str) { | |
500 | return DynMetric{getDynMetric(str)}; | |
501 | }); | |
502 | ||
503 | d_lw->registerFunction("inc", &DynMetric::inc); | |
504 | d_lw->registerFunction("incBy", &DynMetric::incBy); | |
505 | d_lw->registerFunction("set", &DynMetric::set); | |
506 | d_lw->registerFunction("get", &DynMetric::get); | |
507 | ||
808c5ef7 | 508 | |
509 | ifstream ifs(fname); | |
510 | if(!ifs) { | |
d82c6389 | 511 | throw std::runtime_error("Unable to read configuration file from '"+fname+"': "+strerror(errno)); |
808c5ef7 | 512 | } |
513 | d_lw->executeCode(ifs); | |
a3e7b735 | 514 | |
515 | d_preresolve = d_lw->readVariable<boost::optional<luacall_t>>("preresolve").get_value_or(0); | |
516 | d_nodata = d_lw->readVariable<boost::optional<luacall_t>>("nodata").get_value_or(0); | |
517 | d_nxdomain = d_lw->readVariable<boost::optional<luacall_t>>("nxdomain").get_value_or(0); | |
518 | d_postresolve = d_lw->readVariable<boost::optional<luacall_t>>("postresolve").get_value_or(0); | |
f90c7544 | 519 | d_preoutquery = d_lw->readVariable<boost::optional<luacall_t>>("preoutquery").get_value_or(0); |
520 | ||
521 | d_ipfilter = d_lw->readVariable<boost::optional<ipfilter_t>>("ipfilter").get_value_or(0); | |
81c0afd8 | 522 | d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0); |
808c5ef7 | 523 | } |
524 | ||
b8470add | 525 | 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 | 526 | { |
b8470add | 527 | return genhook(d_preresolve, remote, local, query, qtype, isTcp, res, ednsOpts, tag, appliedPolicy, policyTags, ret, variable, wantsRPZ); |
a3e7b735 | 528 | } |
529 | ||
c672b54a | 530 | 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 | 531 | { |
b8470add | 532 | return genhook(d_nxdomain, remote, local, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, variable, 0); |
a3e7b735 | 533 | } |
534 | ||
c672b54a | 535 | 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 | 536 | { |
b8470add | 537 | return genhook(d_nodata, remote, local, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, variable, 0); |
a3e7b735 | 538 | } |
539 | ||
db486de5 | 540 | 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 | 541 | { |
b8470add | 542 | return genhook(d_postresolve, remote, local, query, qtype, isTcp, res, 0, 0, appliedPolicy, policyTags, ret, variable, 0); |
a3e7b735 | 543 | } |
544 | ||
c672b54a | 545 | bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) |
a3e7b735 | 546 | { |
b8470add | 547 | return genhook(d_preoutquery, ns, requestor, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, 0, 0); |
a3e7b735 | 548 | } |
549 | ||
550 | bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) | |
551 | { | |
552 | if(d_ipfilter) | |
f5062066 | 553 | return d_ipfilter(remote, local, dh); |
f90c7544 | 554 | return false; // don't block |
a3e7b735 | 555 | } |
556 | ||
02b47f43 | 557 | int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags) |
81c0afd8 | 558 | { |
02b47f43 RG |
559 | if(d_gettag) { |
560 | auto ret = d_gettag(remote, ednssubnet, local, qname, qtype); | |
561 | ||
562 | if (policyTags) { | |
563 | const auto& tags = std::get<1>(ret); | |
564 | if (tags) { | |
565 | for (const auto& tag : *tags) { | |
566 | policyTags->push_back(tag.second); | |
567 | } | |
568 | } | |
569 | } | |
570 | return std::get<0>(ret); | |
571 | } | |
81c0afd8 | 572 | return 0; |
573 | } | |
574 | ||
b8470add | 575 | 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) |
a3e7b735 | 576 | { |
577 | if(!func) | |
808c5ef7 | 578 | return false; |
a3e7b735 | 579 | |
580 | auto dq = std::make_shared<DNSQuestion>(); | |
581 | dq->qname = query; | |
582 | dq->qtype = qtype.getCode(); | |
583 | dq->local=local; | |
584 | dq->remote=remote; | |
585 | dq->records = res; | |
ba461517 | 586 | dq->tag = tag; |
e8340d27 | 587 | dq->ednsOptions = ednsOpts; |
c672b54a | 588 | dq->isTcp = isTcp; |
574b95cd | 589 | dq->rcode = ret; |
48096cf0 | 590 | dq->policyTags = policyTags; |
db486de5 | 591 | dq->appliedPolicy = appliedPolicy; |
b8470add | 592 | dq->wantsRPZ = wantsRPZ; |
a3e7b735 | 593 | bool handled=func(dq); |
2205c52b | 594 | if(variable) *variable |= dq->variable; // could still be set to indicate this *name* is variable, even if not 'handled' |
b8470add | 595 | *wantsRPZ = dq->wantsRPZ; // Even if we did not handle the query, RPZ could be disabled |
2205c52b | 596 | |
a3e7b735 | 597 | if(handled) { |
f9e5e573 | 598 | loop:; |
a3e7b735 | 599 | ret=dq->rcode; |
d2f97f2a | 600 | |
a3e7b735 | 601 | if(!dq->followupFunction.empty()) { |
602 | if(dq->followupFunction=="followCNAMERecords") { | |
d2f97f2a | 603 | ret = followCNAMERecords(dq->records, qtype); |
a3e7b735 | 604 | } |
605 | else if(dq->followupFunction=="getFakeAAAARecords") { | |
d2f97f2a | 606 | ret=getFakeAAAARecords(dq->followupName, dq->followupPrefix, dq->records); |
a3e7b735 | 607 | } |
608 | else if(dq->followupFunction=="getFakePTRRecords") { | |
d2f97f2a | 609 | ret=getFakePTRRecords(dq->followupName, dq->followupPrefix, dq->records); |
a3e7b735 | 610 | } |
f90c7544 | 611 | else if(dq->followupFunction=="udpQueryResponse") { |
d2f97f2a | 612 | dq->udpAnswer = GenUDPQueryResponse(dq->udpQueryDest, dq->udpQuery); |
613 | auto func = d_lw->readVariable<boost::optional<luacall_t>>(dq->udpCallback).get_value_or(0); | |
614 | if(!func) { | |
615 | theL()<<Logger::Error<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl; | |
6b8b26c8 | 616 | return false; |
d2f97f2a | 617 | } |
618 | bool res=func(dq); | |
619 | if(variable) *variable |= dq->variable; // could still be set to indicate this *name* is variable | |
620 | if(!res) { | |
621 | return false; | |
622 | } | |
623 | goto loop; | |
f90c7544 | 624 | } |
a3e7b735 | 625 | } |
626 | res=dq->records; | |
a3e7b735 | 627 | } |
628 | ||
629 | ||
630 | // see if they added followup work for us too | |
631 | return handled; | |
632 | } | |
3dcc3fde | 633 | |
410d750c | 634 | #endif |
3dcc3fde | 635 | RecursorLua4::~RecursorLua4(){} |