]>
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" |
b40562da RG |
28 | #include "rec_channel.hh" |
29 | #include "ednsoptions.hh" | |
5ecf1d7e | 30 | #include "ednssubnet.hh" |
db486de5 | 31 | #include "filterpo.hh" |
d705aad9 | 32 | #include "rec-snmp.hh" |
08dcccd6 | 33 | #include <unordered_set> |
410d750c | 34 | |
9694e14f | 35 | RecursorLua4::RecursorLua4() { prepareContext(); } |
70c21c40 | 36 | |
a3e7b735 | 37 | static int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype) |
38 | { | |
39 | vector<DNSRecord> resolved; | |
40 | DNSName target; | |
41 | for(const DNSRecord& rr : ret) { | |
42 | if(rr.d_type == QType::CNAME) { | |
ba3c54cb RG |
43 | auto rec = getRR<CNAMERecordContent>(rr); |
44 | if(rec) { | |
45 | target=rec->getTarget(); | |
46 | break; | |
47 | } | |
a3e7b735 | 48 | } |
49 | } | |
50 | if(target.empty()) | |
51 | return 0; | |
52 | ||
53 | int rcode=directResolve(target, qtype, 1, resolved); // 1 == class | |
54 | ||
55 | for(const DNSRecord& rr : resolved) { | |
56 | ret.push_back(rr); | |
57 | } | |
58 | return rcode; | |
59 | ||
60 | } | |
61 | ||
62 | static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret) | |
63 | { | |
64 | int rcode=directResolve(qname, QType(QType::A), 1, ret); | |
65 | ||
66 | ComboAddress prefixAddress(prefix); | |
67 | ||
68 | for(DNSRecord& rr : ret) | |
69 | { | |
70 | if(rr.d_type == QType::A && rr.d_place==DNSResourceRecord::ANSWER) { | |
ba3c54cb RG |
71 | if(auto rec = getRR<ARecordContent>(rr)) { |
72 | ComboAddress ipv4(rec->getCA()); | |
73 | uint32_t tmp; | |
74 | memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4); | |
75 | // tmp=htonl(tmp); | |
76 | memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4); | |
77 | rr.d_content = std::make_shared<AAAARecordContent>(prefixAddress); | |
78 | rr.d_type = QType::AAAA; | |
79 | } | |
a3e7b735 | 80 | } |
81 | } | |
82 | return rcode; | |
83 | } | |
84 | ||
85 | static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret) | |
86 | { | |
87 | /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it | |
88 | and turn it into an IPv4 in-addr.arpa query */ | |
89 | ret.clear(); | |
90 | vector<string> parts = qname.getRawLabels(); | |
91 | ||
92 | if(parts.size() < 8) | |
93 | return -1; | |
94 | ||
95 | string newquery; | |
96 | for(int n = 0; n < 4; ++n) { | |
97 | newquery += | |
926ccaca | 98 | std::to_string(stoll(parts[n*2], 0, 16) + 16*stoll(parts[n*2+1], 0, 16)); |
a3e7b735 | 99 | newquery.append(1,'.'); |
100 | } | |
101 | newquery += "in-addr.arpa."; | |
102 | ||
103 | ||
104 | int rcode = directResolve(DNSName(newquery), QType(QType::PTR), 1, ret); | |
105 | for(DNSRecord& rr : ret) | |
106 | { | |
107 | if(rr.d_type == QType::PTR && rr.d_place==DNSResourceRecord::ANSWER) { | |
108 | rr.d_name = qname; | |
109 | } | |
110 | } | |
111 | return rcode; | |
112 | ||
113 | } | |
114 | ||
621e4e59 PL |
115 | boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const |
116 | { | |
117 | if (dh) | |
118 | return *dh; | |
119 | return boost::optional<dnsheader>(); | |
120 | } | |
121 | ||
e2fb3504 PL |
122 | vector<string> RecursorLua4::DNSQuestion::getEDNSFlags() const |
123 | { | |
124 | vector<string> ret; | |
125 | if (ednsFlags) { | |
126 | if (*ednsFlags & EDNSOpts::DNSSECOK) | |
127 | ret.push_back("DO"); | |
128 | } | |
129 | return ret; | |
130 | } | |
131 | ||
132 | bool RecursorLua4::DNSQuestion::getEDNSFlag(string flag) const | |
133 | { | |
134 | if (ednsFlags) { | |
135 | if (flag == "DO" && (*ednsFlags & EDNSOpts::DNSSECOK)) | |
136 | return true; | |
137 | } | |
138 | return false; | |
139 | } | |
140 | ||
ba21fcfe | 141 | vector<pair<uint16_t, string> > RecursorLua4::DNSQuestion::getEDNSOptions() const |
e8340d27 | 142 | { |
143 | if(ednsOptions) | |
144 | return *ednsOptions; | |
145 | else | |
146 | return vector<pair<uint16_t,string>>(); | |
147 | } | |
148 | ||
ba21fcfe | 149 | boost::optional<string> RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const |
e8340d27 | 150 | { |
151 | if(ednsOptions) | |
152 | for(const auto& o : *ednsOptions) | |
153 | if(o.first==code) | |
154 | return o.second; | |
155 | ||
156 | return boost::optional<string>(); | |
157 | } | |
158 | ||
ba21fcfe | 159 | boost::optional<Netmask> RecursorLua4::DNSQuestion::getEDNSSubnet() const |
5ecf1d7e | 160 | { |
161 | ||
162 | if(ednsOptions) { | |
163 | for(const auto& o : *ednsOptions) { | |
b40562da | 164 | if(o.first==EDNSOptionCode::ECS) { |
5ecf1d7e | 165 | EDNSSubnetOpts eso; |
166 | if(getEDNSSubnetOptsFromString(o.second, &eso)) | |
167 | return eso.source; | |
168 | else | |
169 | break; | |
170 | } | |
171 | } | |
172 | } | |
173 | return boost::optional<Netmask>(); | |
174 | } | |
175 | ||
e8340d27 | 176 | |
ba21fcfe | 177 | vector<pair<int, DNSRecord> > RecursorLua4::DNSQuestion::getRecords() const |
a3e7b735 | 178 | { |
179 | vector<pair<int, DNSRecord> > ret; | |
180 | int num=1; | |
181 | for(const auto& r : records) { | |
182 | ret.push_back({num++, r}); | |
183 | } | |
184 | return ret; | |
185 | } | |
186 | void RecursorLua4::DNSQuestion::setRecords(const vector<pair<int, DNSRecord> >& recs) | |
187 | { | |
188 | records.clear(); | |
189 | for(const auto& p : recs) { | |
190 | records.push_back(p.second); | |
a3e7b735 | 191 | } |
192 | } | |
193 | ||
aee72a7b | 194 | void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name) |
a3e7b735 | 195 | { |
196 | DNSRecord dr; | |
aee72a7b | 197 | dr.d_name=name ? DNSName(*name) : qname; |
a3e7b735 | 198 | dr.d_ttl=ttl.get_value_or(3600); |
199 | dr.d_type = type; | |
200 | dr.d_place = place; | |
6177a176 | 201 | dr.d_content = DNSRecordContent::mastermake(type, 1, content); |
a3e7b735 | 202 | records.push_back(dr); |
203 | } | |
204 | ||
aee72a7b | 205 | void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name) |
a3e7b735 | 206 | { |
aee72a7b | 207 | addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name); |
a3e7b735 | 208 | } |
9f89a5f1 | 209 | |
210 | struct DynMetric | |
211 | { | |
212 | std::atomic<unsigned long>* ptr; | |
213 | void inc() { (*ptr)++; } | |
214 | void incBy(unsigned int by) { (*ptr)+= by; } | |
215 | unsigned long get() { return *ptr; } | |
216 | void set(unsigned long val) { *ptr =val; } | |
217 | }; | |
218 | ||
70c21c40 | 219 | void RecursorLua4::postPrepareContext() |
808c5ef7 | 220 | { |
ba21fcfe RG |
221 | d_lw->registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName& { return dq.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; }); |
222 | d_lw->registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; }); | |
223 | d_lw->registerMember<bool (DNSQuestion::*)>("isTcp", [](const DNSQuestion& dq) -> bool { return dq.isTcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; }); | |
224 | d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.local; }, [](DNSQuestion& dq, const ComboAddress& newLocal) { (void) newLocal; }); | |
225 | d_lw->registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress& { return dq.remote; }, [](DNSQuestion& dq, const ComboAddress& newRemote) { (void) newRemote; }); | |
1921a4c2 | 226 | d_lw->registerMember<vState (DNSQuestion::*)>("validationState", [](const DNSQuestion& dq) -> vState { return dq.validationState; }, [](DNSQuestion& dq, vState newState) { (void) newState; }); |
ba21fcfe RG |
227 | |
228 | d_lw->registerMember<bool (DNSQuestion::*)>("variable", [](const DNSQuestion& dq) -> bool { return dq.variable; }, [](DNSQuestion& dq, bool newVariable) { dq.variable = newVariable; }); | |
229 | d_lw->registerMember<bool (DNSQuestion::*)>("wantsRPZ", [](const DNSQuestion& dq) -> bool { return dq.wantsRPZ; }, [](DNSQuestion& dq, bool newWantsRPZ) { dq.wantsRPZ = newWantsRPZ; }); | |
230 | ||
a3e7b735 | 231 | d_lw->registerMember("rcode", &DNSQuestion::rcode); |
ba461517 | 232 | d_lw->registerMember("tag", &DNSQuestion::tag); |
67e31ebe | 233 | d_lw->registerMember("requestorId", &DNSQuestion::requestorId); |
a3e7b735 | 234 | d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction); |
235 | d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix); | |
236 | d_lw->registerMember("followupName", &DNSQuestion::followupName); | |
6b8b26c8 | 237 | d_lw->registerMember("data", &DNSQuestion::data); |
238 | d_lw->registerMember("udpQuery", &DNSQuestion::udpQuery); | |
239 | d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer); | |
240 | d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest); | |
241 | d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback); | |
667f6c7c | 242 | d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy); |
98c28a68 RG |
243 | d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyName", |
244 | [](const DNSFilterEngine::Policy& pol) -> std::string { | |
245 | if(pol.d_name) | |
246 | return *pol.d_name; | |
247 | return std::string(); | |
248 | }, | |
249 | [](DNSFilterEngine::Policy& pol, const std::string& name) { | |
250 | pol.d_name = std::make_shared<std::string>(name); | |
251 | }); | |
db486de5 PL |
252 | d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind); |
253 | d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl); | |
98c28a68 RG |
254 | d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyCustom", |
255 | [](const DNSFilterEngine::Policy& pol) -> std::string { | |
256 | if(pol.d_custom) | |
257 | return pol.d_custom->getZoneRepresentation(); | |
258 | return std::string(); | |
db486de5 | 259 | }, |
98c28a68 | 260 | [](DNSFilterEngine::Policy& pol, const std::string& content) { |
db486de5 | 261 | // Only CNAMES for now, when we ever add a d_custom_type, there will be pain |
6177a176 | 262 | pol.d_custom = DNSRecordContent::mastermake(QType::CNAME, 1, content); |
db486de5 PL |
263 | } |
264 | ); | |
621e4e59 | 265 | d_lw->registerFunction("getDH", &DNSQuestion::getDH); |
e8340d27 | 266 | d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions); |
267 | d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption); | |
5ecf1d7e | 268 | d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet); |
e2fb3504 PL |
269 | d_lw->registerFunction("getEDNSFlags", &DNSQuestion::getEDNSFlags); |
270 | d_lw->registerFunction("getEDNSFlag", &DNSQuestion::getEDNSFlag); | |
a3e7b735 | 271 | d_lw->registerMember("name", &DNSRecord::d_name); |
272 | d_lw->registerMember("type", &DNSRecord::d_type); | |
273 | d_lw->registerMember("ttl", &DNSRecord::d_ttl); | |
57d0c73b | 274 | d_lw->registerMember("place", &DNSRecord::d_place); |
00b8cadc RG |
275 | |
276 | d_lw->registerMember("size", &EDNSOptionView::size); | |
277 | d_lw->registerFunction<std::string(EDNSOptionView::*)()>("getContent", [](const EDNSOptionView& option) { return std::string(option.content, option.size); }); | |
278 | ||
a3e7b735 | 279 | d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); }); |
7d5f094a | 280 | d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) { |
281 | boost::optional<ComboAddress> ret; | |
282 | ||
283 | if(auto rec = std::dynamic_pointer_cast<ARecordContent>(dr.d_content)) | |
284 | ret=rec->getCA(53); | |
dd079764 RG |
285 | else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(dr.d_content)) |
286 | ret=aaaarec->getCA(53); | |
7d5f094a | 287 | return ret; |
288 | }); | |
a3e7b735 | 289 | |
290 | ||
6177a176 | 291 | 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); }); |
a3e7b735 | 292 | d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer); |
08dcccd6 | 293 | d_lw->registerFunction("addRecord", &DNSQuestion::addRecord); |
a3e7b735 | 294 | d_lw->registerFunction("getRecords", &DNSQuestion::getRecords); |
295 | d_lw->registerFunction("setRecords", &DNSQuestion::setRecords); | |
296 | ||
48096cf0 | 297 | d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("addPolicyTag", [](DNSQuestion& dq, const std::string& tag) { if (dq.policyTags) { dq.policyTags->push_back(tag); } }); |
667f6c7c | 298 | 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 |
299 | if (dq.policyTags) { |
300 | dq.policyTags->clear(); | |
301 | for (const auto& tag : tags) { | |
302 | dq.policyTags->push_back(tag.second); | |
303 | } | |
667f6c7c RG |
304 | } |
305 | }); | |
306 | d_lw->registerFunction<std::vector<std::pair<int, std::string> >(DNSQuestion::*)()>("getPolicyTags", [](const DNSQuestion& dq) { | |
307 | std::vector<std::pair<int, std::string> > ret; | |
48096cf0 RG |
308 | if (dq.policyTags) { |
309 | int count = 1; | |
310 | for (const auto& tag : *dq.policyTags) { | |
311 | ret.push_back({count++, tag}); | |
312 | } | |
667f6c7c RG |
313 | } |
314 | return ret; | |
315 | }); | |
316 | ||
0a273054 RG |
317 | d_lw->registerFunction<void(DNSQuestion::*)(const std::string&)>("discardPolicy", [](DNSQuestion& dq, const std::string& policy) { |
318 | if (dq.discardedPolicies) { | |
319 | (*dq.discardedPolicies)[policy] = true; | |
320 | } | |
321 | }); | |
322 | ||
a3e7b735 | 323 | d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); }); |
805f3e03 PL |
324 | d_lw->registerFunction<void(SuffixMatchNode::*)(boost::variant<string,DNSName, vector<pair<unsigned int,string> > >)>( |
325 | "add", | |
326 | [](SuffixMatchNode&smn, const boost::variant<string,DNSName,vector<pair<unsigned int,string> > >& in){ | |
327 | try { | |
328 | if(auto s = boost::get<string>(&in)) { | |
329 | smn.add(DNSName(*s)); | |
330 | } | |
331 | else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) { | |
dd079764 RG |
332 | for(const auto& entry : *v) |
333 | smn.add(DNSName(entry.second)); | |
805f3e03 PL |
334 | } |
335 | else { | |
336 | smn.add(boost::get<DNSName>(in)); | |
337 | } | |
338 | } | |
339 | catch(std::exception& e) { | |
340 | theL() <<Logger::Error<<e.what()<<endl; | |
341 | } | |
342 | } | |
343 | ); | |
344 | ||
a3e7b735 | 345 | d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); |
c6b99fc1 | 346 | d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString); |
a3e7b735 | 347 | |
70c21c40 | 348 | d_pd.push_back({"policykinds", in_t { |
db486de5 PL |
349 | {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction}, |
350 | {"Drop", (int)DNSFilterEngine::PolicyKind::Drop }, | |
351 | {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN}, | |
352 | {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA }, | |
353 | {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate}, | |
354 | {"Custom", (int)DNSFilterEngine::PolicyKind::Custom } | |
355 | }}); | |
356 | ||
a3e7b735 | 357 | for(const auto& n : QType::names) |
70c21c40 | 358 | d_pd.push_back({n.first, n.second}); |
1921a4c2 | 359 | |
70c21c40 | 360 | d_pd.push_back({"validationstates", in_t{ |
1921a4c2 RG |
361 | {"Indeterminate", Indeterminate }, |
362 | {"Bogus", Bogus }, | |
363 | {"Insecure", Insecure }, | |
364 | {"Secure", Secure }, | |
365 | }}); | |
366 | ||
70c21c40 | 367 | d_pd.push_back({"now", &g_now}); |
9f89a5f1 | 368 | |
369 | d_lw->writeFunction("getMetric", [](const std::string& str) { | |
370 | return DynMetric{getDynMetric(str)}; | |
371 | }); | |
372 | ||
373 | d_lw->registerFunction("inc", &DynMetric::inc); | |
374 | d_lw->registerFunction("incBy", &DynMetric::incBy); | |
375 | d_lw->registerFunction("set", &DynMetric::set); | |
376 | d_lw->registerFunction("get", &DynMetric::get); | |
b4015453 | 377 | |
b0b37121 RG |
378 | d_lw->writeFunction("getStat", [](const std::string& str) { |
379 | uint64_t result = 0; | |
380 | optional<uint64_t> value = getStatByName(str); | |
381 | if (value) { | |
382 | result = *value; | |
383 | } | |
384 | return result; | |
385 | }); | |
386 | ||
b4015453 RG |
387 | d_lw->writeFunction("getRecursorThreadId", []() { |
388 | return getRecursorThreadId(); | |
389 | }); | |
390 | ||
d705aad9 RG |
391 | d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) { |
392 | if (g_snmpAgent) { | |
393 | g_snmpAgent->sendCustomTrap(str); | |
394 | } | |
395 | }); | |
70c21c40 | 396 | } |
a3e7b735 | 397 | |
70c21c40 | 398 | void RecursorLua4::postLoad() { |
0a273054 | 399 | d_prerpz = d_lw->readVariable<boost::optional<luacall_t>>("prerpz").get_value_or(0); |
a3e7b735 | 400 | d_preresolve = d_lw->readVariable<boost::optional<luacall_t>>("preresolve").get_value_or(0); |
401 | d_nodata = d_lw->readVariable<boost::optional<luacall_t>>("nodata").get_value_or(0); | |
402 | d_nxdomain = d_lw->readVariable<boost::optional<luacall_t>>("nxdomain").get_value_or(0); | |
403 | d_postresolve = d_lw->readVariable<boost::optional<luacall_t>>("postresolve").get_value_or(0); | |
f90c7544 | 404 | d_preoutquery = d_lw->readVariable<boost::optional<luacall_t>>("preoutquery").get_value_or(0); |
405 | ||
406 | d_ipfilter = d_lw->readVariable<boost::optional<ipfilter_t>>("ipfilter").get_value_or(0); | |
81c0afd8 | 407 | d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0); |
70fb28d9 | 408 | d_gettag_ffi = d_lw->readVariable<boost::optional<gettag_ffi_t>>("gettag_ffi").get_value_or(0); |
808c5ef7 | 409 | } |
410 | ||
5899ee54 | 411 | bool RecursorLua4::prerpz(DNSQuestion& dq, int& ret) const |
0a273054 | 412 | { |
ba21fcfe | 413 | return genhook(d_prerpz, dq, ret); |
0a273054 RG |
414 | } |
415 | ||
5899ee54 | 416 | bool RecursorLua4::preresolve(DNSQuestion& dq, int& ret) const |
808c5ef7 | 417 | { |
ba21fcfe | 418 | return genhook(d_preresolve, dq, ret); |
a3e7b735 | 419 | } |
420 | ||
5899ee54 | 421 | bool RecursorLua4::nxdomain(DNSQuestion& dq, int& ret) const |
a3e7b735 | 422 | { |
ba21fcfe | 423 | return genhook(d_nxdomain, dq, ret); |
a3e7b735 | 424 | } |
425 | ||
5899ee54 | 426 | bool RecursorLua4::nodata(DNSQuestion& dq, int& ret) const |
a3e7b735 | 427 | { |
ba21fcfe | 428 | return genhook(d_nodata, dq, ret); |
a3e7b735 | 429 | } |
430 | ||
5899ee54 | 431 | bool RecursorLua4::postresolve(DNSQuestion& dq, int& ret) const |
a3e7b735 | 432 | { |
ba21fcfe | 433 | return genhook(d_postresolve, dq, ret); |
a3e7b735 | 434 | } |
435 | ||
5899ee54 | 436 | bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const |
a3e7b735 | 437 | { |
ba21fcfe RG |
438 | bool variableAnswer = false; |
439 | bool wantsRPZ = false; | |
2377be3b | 440 | RecursorLua4::DNSQuestion dq(ns, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ); |
6e505c5e | 441 | dq.currentRecords = &res; |
ba21fcfe RG |
442 | |
443 | return genhook(d_preoutquery, dq, ret); | |
a3e7b735 | 444 | } |
445 | ||
5899ee54 | 446 | bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) const |
a3e7b735 | 447 | { |
448 | if(d_ipfilter) | |
f5062066 | 449 | return d_ipfilter(remote, local, dh); |
f90c7544 | 450 | return false; // don't block |
a3e7b735 | 451 | } |
452 | ||
5899ee54 | 453 | unsigned int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const std::map<uint16_t, EDNSOptionView>& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId) const |
81c0afd8 | 454 | { |
02b47f43 | 455 | if(d_gettag) { |
dff843b2 | 456 | auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp); |
02b47f43 RG |
457 | |
458 | if (policyTags) { | |
459 | const auto& tags = std::get<1>(ret); | |
460 | if (tags) { | |
461 | for (const auto& tag : *tags) { | |
462 | policyTags->push_back(tag.second); | |
463 | } | |
464 | } | |
465 | } | |
5fd2577f | 466 | const auto dataret = std::get<2>(ret); |
05c74122 RG |
467 | if (dataret) { |
468 | data = *dataret; | |
469 | } | |
67e31ebe RG |
470 | const auto reqIdret = std::get<3>(ret); |
471 | if (reqIdret) { | |
472 | requestorId = *reqIdret; | |
473 | } | |
590388d2 NC |
474 | const auto deviceIdret = std::get<4>(ret); |
475 | if (deviceIdret) { | |
476 | deviceId = *deviceIdret; | |
477 | } | |
02b47f43 RG |
478 | return std::get<0>(ret); |
479 | } | |
81c0afd8 | 480 | return 0; |
481 | } | |
482 | ||
70fb28d9 RG |
483 | struct pdns_ffi_param |
484 | { | |
485 | public: | |
486 | pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector<std::string>& policyTags_, const std::map<uint16_t, EDNSOptionView>& ednsOptions_, std::string& requestorId_, std::string& deviceId_, uint32_t& ttlCap_, bool& variable_, bool tcp_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), ttlCap(ttlCap_), variable(variable_), qtype(qtype_), tcp(tcp_) | |
487 | { | |
488 | } | |
489 | ||
490 | std::unique_ptr<std::string> qnameStr{nullptr}; | |
491 | std::unique_ptr<std::string> localStr{nullptr}; | |
492 | std::unique_ptr<std::string> remoteStr{nullptr}; | |
493 | std::unique_ptr<std::string> ednssubnetStr{nullptr}; | |
494 | std::vector<pdns_ednsoption_t> ednsOptionsVect; | |
495 | ||
496 | const DNSName& qname; | |
497 | const ComboAddress& local; | |
498 | const ComboAddress& remote; | |
499 | const Netmask& ednssubnet; | |
500 | std::vector<std::string>& policyTags; | |
501 | const std::map<uint16_t, EDNSOptionView>& ednsOptions; | |
502 | std::string& requestorId; | |
503 | std::string& deviceId; | |
504 | uint32_t& ttlCap; | |
505 | bool& variable; | |
506 | ||
507 | unsigned int tag{0}; | |
508 | uint16_t qtype; | |
509 | bool tcp; | |
510 | }; | |
511 | ||
5899ee54 | 512 | unsigned int RecursorLua4::gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const std::map<uint16_t, EDNSOptionView>& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, uint32_t& ttlCap, bool& variable) const |
70fb28d9 RG |
513 | { |
514 | if (d_gettag_ffi) { | |
515 | pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, ednsOptions, requestorId, deviceId, ttlCap, variable, tcp); | |
516 | ||
517 | auto ret = d_gettag_ffi(¶m); | |
518 | if (ret) { | |
519 | data = *ret; | |
520 | } | |
521 | ||
522 | return param.tag; | |
523 | } | |
524 | return 0; | |
525 | } | |
526 | ||
5899ee54 | 527 | bool RecursorLua4::genhook(const luacall_t& func, DNSQuestion& dq, int& ret) const |
a3e7b735 | 528 | { |
529 | if(!func) | |
808c5ef7 | 530 | return false; |
a3e7b735 | 531 | |
6e505c5e RG |
532 | if (dq.currentRecords) { |
533 | dq.records = *dq.currentRecords; | |
ba21fcfe | 534 | } else { |
6e505c5e | 535 | dq.records.clear(); |
ba21fcfe RG |
536 | } |
537 | ||
6e505c5e RG |
538 | dq.followupFunction.clear(); |
539 | dq.followupPrefix.clear(); | |
540 | dq.followupName.clear(); | |
541 | dq.udpQuery.clear(); | |
542 | dq.udpAnswer.clear(); | |
543 | dq.udpCallback.clear(); | |
ba21fcfe | 544 | |
6e505c5e | 545 | dq.rcode = ret; |
1c567515 | 546 | bool handled=func(&dq); |
2205c52b | 547 | |
a3e7b735 | 548 | if(handled) { |
f9e5e573 | 549 | loop:; |
6e505c5e | 550 | ret=dq.rcode; |
d2f97f2a | 551 | |
6e505c5e RG |
552 | if(!dq.followupFunction.empty()) { |
553 | if(dq.followupFunction=="followCNAMERecords") { | |
554 | ret = followCNAMERecords(dq.records, QType(dq.qtype)); | |
a3e7b735 | 555 | } |
6e505c5e RG |
556 | else if(dq.followupFunction=="getFakeAAAARecords") { |
557 | ret=getFakeAAAARecords(dq.followupName, dq.followupPrefix, dq.records); | |
a3e7b735 | 558 | } |
6e505c5e RG |
559 | else if(dq.followupFunction=="getFakePTRRecords") { |
560 | ret=getFakePTRRecords(dq.followupName, dq.followupPrefix, dq.records); | |
a3e7b735 | 561 | } |
6e505c5e RG |
562 | else if(dq.followupFunction=="udpQueryResponse") { |
563 | dq.udpAnswer = GenUDPQueryResponse(dq.udpQueryDest, dq.udpQuery); | |
dd079764 RG |
564 | auto cbFunc = d_lw->readVariable<boost::optional<luacall_t>>(dq.udpCallback).get_value_or(0); |
565 | if(!cbFunc) { | |
d2f97f2a | 566 | theL()<<Logger::Error<<"Attempted callback for Lua UDP Query/Response which could not be found"<<endl; |
6b8b26c8 | 567 | return false; |
d2f97f2a | 568 | } |
dd079764 | 569 | bool result=cbFunc(&dq); |
ba21fcfe | 570 | if(!result) { |
d2f97f2a | 571 | return false; |
572 | } | |
573 | goto loop; | |
f90c7544 | 574 | } |
a3e7b735 | 575 | } |
6e505c5e RG |
576 | if (dq.currentRecords) { |
577 | *dq.currentRecords = dq.records; | |
ba21fcfe | 578 | } |
a3e7b735 | 579 | } |
580 | ||
a3e7b735 | 581 | // see if they added followup work for us too |
582 | return handled; | |
583 | } | |
3dcc3fde | 584 | |
3dcc3fde | 585 | RecursorLua4::~RecursorLua4(){} |
70fb28d9 RG |
586 | |
587 | const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref) | |
588 | { | |
589 | if (!ref->qnameStr) { | |
590 | ref->qnameStr = std::unique_ptr<std::string>(new std::string(ref->qname.toStringNoDot())); | |
591 | } | |
592 | ||
593 | return ref->qnameStr->c_str(); | |
594 | } | |
595 | ||
596 | uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref) | |
597 | { | |
598 | return ref->qtype; | |
599 | } | |
600 | ||
601 | const char* pdns_ffi_param_get_remote(pdns_ffi_param_t* ref) | |
602 | { | |
603 | if (!ref->remoteStr) { | |
604 | ref->remoteStr = std::unique_ptr<std::string>(new std::string(ref->remote.toString())); | |
605 | } | |
606 | ||
607 | return ref->remoteStr->c_str(); | |
608 | } | |
609 | ||
610 | uint16_t pdns_ffi_param_get_remote_port(const pdns_ffi_param_t* ref) | |
611 | { | |
612 | return ref->remote.getPort(); | |
613 | } | |
614 | ||
615 | const char* pdns_ffi_param_get_local(pdns_ffi_param_t* ref) | |
616 | { | |
617 | if (!ref->localStr) { | |
618 | ref->localStr = std::unique_ptr<std::string>(new std::string(ref->local.toString())); | |
619 | } | |
620 | ||
621 | return ref->localStr->c_str(); | |
622 | } | |
623 | ||
624 | uint16_t pdns_ffi_param_get_local_port(const pdns_ffi_param_t* ref) | |
625 | { | |
626 | return ref->local.getPort(); | |
627 | } | |
628 | ||
629 | const char* pdns_ffi_param_get_edns_cs(pdns_ffi_param_t* ref) | |
630 | { | |
631 | if (ref->ednssubnet.empty()) { | |
632 | return nullptr; | |
633 | } | |
634 | ||
635 | if (!ref->ednssubnetStr) { | |
636 | ref->ednssubnetStr = std::unique_ptr<std::string>(new std::string(ref->ednssubnet.toStringNoMask())); | |
637 | } | |
638 | ||
639 | return ref->ednssubnetStr->c_str(); | |
640 | } | |
641 | ||
642 | uint8_t pdns_ffi_param_get_edns_cs_source_mask(const pdns_ffi_param_t* ref) | |
643 | { | |
644 | return ref->ednssubnet.getBits(); | |
645 | } | |
646 | ||
647 | static void fill_edns_option(const EDNSOptionView& view, pdns_ednsoption_t& option) | |
648 | { | |
649 | option.len = view.size; | |
650 | option.data = nullptr; | |
651 | ||
652 | if (view.size > 0) { | |
653 | option.data = view.content; | |
654 | } | |
655 | } | |
656 | ||
657 | size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t* ref, const pdns_ednsoption_t** out) | |
658 | { | |
659 | if (ref->ednsOptions.empty()) { | |
660 | return 0; | |
661 | } | |
662 | ||
663 | size_t count = ref->ednsOptions.size(); | |
664 | ref->ednsOptionsVect.resize(count); | |
665 | ||
666 | size_t pos = 0; | |
667 | for (const auto& entry : ref->ednsOptions) { | |
668 | fill_edns_option(entry.second, ref->ednsOptionsVect.at(pos)); | |
669 | ref->ednsOptionsVect.at(pos).optionCode = entry.first; | |
670 | pos++; | |
671 | } | |
672 | ||
673 | *out = ref->ednsOptionsVect.data(); | |
674 | ||
675 | return count; | |
676 | } | |
677 | ||
678 | size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out) | |
679 | { | |
680 | const auto& it = ref->ednsOptions.find(optionCode); | |
681 | if (it == ref->ednsOptions.cend()) { | |
682 | return 0; | |
683 | } | |
684 | ||
685 | /* the current code deals with only one entry per code, but we will fix that */ | |
686 | ref->ednsOptionsVect.resize(1); | |
687 | fill_edns_option(it->second, ref->ednsOptionsVect.at(0)); | |
688 | ref->ednsOptionsVect.at(0).optionCode = it->first; | |
689 | ||
690 | *out = ref->ednsOptionsVect.data(); | |
691 | ||
692 | return 1; | |
693 | } | |
694 | ||
695 | void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag) | |
696 | { | |
697 | ref->tag = tag; | |
698 | } | |
699 | ||
700 | void pdns_ffi_param_add_policytag(pdns_ffi_param_t *ref, const char* name) | |
701 | { | |
702 | ref->policyTags.push_back(std::string(name)); | |
703 | } | |
704 | ||
705 | void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name) | |
706 | { | |
707 | ref->requestorId = std::string(name); | |
708 | } | |
709 | ||
710 | void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name) | |
711 | { | |
712 | ref->deviceId = std::string(name); | |
713 | } | |
714 | ||
715 | void pdns_ffi_param_set_deviceid(pdns_ffi_param_t* ref, size_t len, const void* name) | |
716 | { | |
717 | ref->deviceId = std::string(reinterpret_cast<const char*>(name), len); | |
718 | } | |
719 | ||
720 | void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable) | |
721 | { | |
722 | ref->variable = variable; | |
723 | } | |
724 | ||
725 | void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl) | |
726 | { | |
727 | ref->ttlCap = ttl; | |
728 | } |