]>
Commit | Line | Data |
---|---|---|
6bb38cd6 RG |
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 | */ | |
af7afecf | 22 | #include "config.h" |
519f5484 | 23 | #include "threadname.hh" |
6bb38cd6 RG |
24 | #include "dnsdist.hh" |
25 | #include "dnsdist-ecs.hh" | |
26 | #include "dnsdist-lua.hh" | |
27 | #include "dnsdist-protobuf.hh" | |
f441962a | 28 | #include "dnsdist-kvs.hh" |
6bb38cd6 RG |
29 | |
30 | #include "dolog.hh" | |
82a91ddf | 31 | #include "dnstap.hh" |
6bb38cd6 | 32 | #include "ednsoptions.hh" |
82a91ddf | 33 | #include "fstrm_logger.hh" |
6bb38cd6 | 34 | #include "remote_logger.hh" |
af7afecf RG |
35 | |
36 | #include <boost/optional/optional_io.hpp> | |
37 | ||
38 | #ifdef HAVE_LIBCRYPTO | |
39 | #include "ipcipher.hh" | |
40 | #endif /* HAVE_LIBCRYPTO */ | |
6bb38cd6 RG |
41 | |
42 | class DropAction : public DNSAction | |
43 | { | |
44 | public: | |
d67c1cbe | 45 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
46 | { |
47 | return Action::Drop; | |
48 | } | |
d67c1cbe | 49 | std::string toString() const override |
6bb38cd6 RG |
50 | { |
51 | return "drop"; | |
52 | } | |
53 | }; | |
54 | ||
55 | class AllowAction : public DNSAction | |
56 | { | |
57 | public: | |
d67c1cbe | 58 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
59 | { |
60 | return Action::Allow; | |
61 | } | |
d67c1cbe | 62 | std::string toString() const override |
6bb38cd6 RG |
63 | { |
64 | return "allow"; | |
65 | } | |
66 | }; | |
67 | ||
bc084a31 RG |
68 | class NoneAction : public DNSAction |
69 | { | |
70 | public: | |
d67c1cbe | 71 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
bc084a31 RG |
72 | { |
73 | return Action::None; | |
74 | } | |
d67c1cbe | 75 | std::string toString() const override |
bc084a31 RG |
76 | { |
77 | return "no op"; | |
78 | } | |
79 | }; | |
6bb38cd6 RG |
80 | |
81 | class QPSAction : public DNSAction | |
82 | { | |
83 | public: | |
84 | QPSAction(int limit) : d_qps(limit, limit) | |
85 | {} | |
d67c1cbe | 86 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
87 | { |
88 | if(d_qps.check()) | |
89 | return Action::None; | |
90 | else | |
91 | return Action::Drop; | |
92 | } | |
d67c1cbe | 93 | std::string toString() const override |
6bb38cd6 RG |
94 | { |
95 | return "qps limit to "+std::to_string(d_qps.getRate()); | |
96 | } | |
97 | private: | |
98 | QPSLimiter d_qps; | |
99 | }; | |
100 | ||
101 | class DelayAction : public DNSAction | |
102 | { | |
103 | public: | |
104 | DelayAction(int msec) : d_msec(msec) | |
105 | {} | |
d67c1cbe | 106 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
107 | { |
108 | *ruleresult=std::to_string(d_msec); | |
109 | return Action::Delay; | |
110 | } | |
d67c1cbe | 111 | std::string toString() const override |
6bb38cd6 RG |
112 | { |
113 | return "delay by "+std::to_string(d_msec)+ " msec"; | |
114 | } | |
115 | private: | |
116 | int d_msec; | |
117 | }; | |
118 | ||
119 | ||
120 | class TeeAction : public DNSAction | |
121 | { | |
122 | public: | |
123 | TeeAction(const ComboAddress& ca, bool addECS=false); | |
124 | ~TeeAction() override; | |
d67c1cbe SK |
125 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override; |
126 | std::string toString() const override; | |
127 | std::map<std::string, double> getStats() const override; | |
6bb38cd6 RG |
128 | |
129 | private: | |
130 | ComboAddress d_remote; | |
131 | std::thread d_worker; | |
132 | void worker(); | |
133 | ||
134 | int d_fd; | |
135 | mutable std::atomic<unsigned long> d_senderrors{0}; | |
136 | unsigned long d_recverrors{0}; | |
137 | mutable std::atomic<unsigned long> d_queries{0}; | |
138 | unsigned long d_responses{0}; | |
139 | unsigned long d_nxdomains{0}; | |
140 | unsigned long d_servfails{0}; | |
141 | unsigned long d_refuseds{0}; | |
142 | unsigned long d_formerrs{0}; | |
143 | unsigned long d_notimps{0}; | |
144 | unsigned long d_noerrors{0}; | |
145 | mutable unsigned long d_tcpdrops{0}; | |
146 | unsigned long d_otherrcode{0}; | |
147 | std::atomic<bool> d_pleaseQuit{false}; | |
148 | bool d_addECS{false}; | |
149 | }; | |
150 | ||
151 | TeeAction::TeeAction(const ComboAddress& ca, bool addECS) : d_remote(ca), d_addECS(addECS) | |
152 | { | |
153 | d_fd=SSocket(d_remote.sin4.sin_family, SOCK_DGRAM, 0); | |
154 | SConnect(d_fd, d_remote); | |
155 | setNonBlocking(d_fd); | |
156 | d_worker=std::thread(std::bind(&TeeAction::worker, this)); | |
157 | } | |
158 | ||
159 | TeeAction::~TeeAction() | |
160 | { | |
161 | d_pleaseQuit=true; | |
162 | close(d_fd); | |
163 | d_worker.join(); | |
164 | } | |
165 | ||
d67c1cbe | 166 | DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult) const |
6bb38cd6 RG |
167 | { |
168 | if(dq->tcp) { | |
169 | d_tcpdrops++; | |
170 | } | |
171 | else { | |
172 | ssize_t res; | |
173 | d_queries++; | |
174 | ||
175 | if(d_addECS) { | |
176 | std::string query; | |
177 | uint16_t len = dq->len; | |
178 | bool ednsAdded = false; | |
179 | bool ecsAdded = false; | |
180 | query.reserve(dq->size); | |
181 | query.assign((char*) dq->dh, len); | |
182 | ||
d67c1cbe | 183 | std::string newECSOption; |
cbf4e13a RG |
184 | generateECSOption(dq->ecsSet ? dq->ecs.getNetwork() : *dq->remote, newECSOption, dq->ecsSet ? dq->ecs.getBits() : dq->ecsPrefixLength); |
185 | ||
be90d6bd | 186 | if (!handleEDNSClientSubnet(const_cast<char*>(query.c_str()), query.capacity(), dq->qname->wirelength(), &len, ednsAdded, ecsAdded, dq->ecsOverride, newECSOption, g_preserveTrailingData)) { |
6bb38cd6 RG |
187 | return DNSAction::Action::None; |
188 | } | |
189 | ||
190 | res = send(d_fd, query.c_str(), len, 0); | |
191 | } | |
192 | else { | |
193 | res = send(d_fd, (char*)dq->dh, dq->len, 0); | |
194 | } | |
195 | ||
196 | if (res <= 0) | |
197 | d_senderrors++; | |
198 | } | |
199 | return DNSAction::Action::None; | |
200 | } | |
201 | ||
d67c1cbe | 202 | std::string TeeAction::toString() const |
6bb38cd6 RG |
203 | { |
204 | return "tee to "+d_remote.toStringWithPort(); | |
205 | } | |
206 | ||
d67c1cbe | 207 | std::map<std::string,double> TeeAction::getStats() const |
6bb38cd6 RG |
208 | { |
209 | return {{"queries", d_queries}, | |
210 | {"responses", d_responses}, | |
211 | {"recv-errors", d_recverrors}, | |
212 | {"send-errors", d_senderrors}, | |
213 | {"noerrors", d_noerrors}, | |
214 | {"nxdomains", d_nxdomains}, | |
215 | {"refuseds", d_refuseds}, | |
216 | {"servfails", d_servfails}, | |
217 | {"other-rcode", d_otherrcode}, | |
218 | {"tcp-drops", d_tcpdrops} | |
219 | }; | |
220 | } | |
221 | ||
222 | void TeeAction::worker() | |
223 | { | |
519f5484 | 224 | setThreadName("dnsdist/TeeWork"); |
6bb38cd6 RG |
225 | char packet[1500]; |
226 | int res=0; | |
227 | struct dnsheader* dh=(struct dnsheader*)packet; | |
228 | for(;;) { | |
229 | res=waitForData(d_fd, 0, 250000); | |
230 | if(d_pleaseQuit) | |
231 | break; | |
232 | if(res < 0) { | |
233 | usleep(250000); | |
234 | continue; | |
235 | } | |
236 | if(res==0) | |
237 | continue; | |
238 | res=recv(d_fd, packet, sizeof(packet), 0); | |
239 | if(res <= (int)sizeof(struct dnsheader)) | |
240 | d_recverrors++; | |
241 | else if(res > 0) | |
242 | d_responses++; | |
243 | ||
244 | if(dh->rcode == RCode::NoError) | |
245 | d_noerrors++; | |
246 | else if(dh->rcode == RCode::ServFail) | |
247 | d_servfails++; | |
248 | else if(dh->rcode == RCode::NXDomain) | |
249 | d_nxdomains++; | |
250 | else if(dh->rcode == RCode::Refused) | |
251 | d_refuseds++; | |
252 | else if(dh->rcode == RCode::FormErr) | |
253 | d_formerrs++; | |
254 | else if(dh->rcode == RCode::NotImp) | |
255 | d_notimps++; | |
256 | } | |
257 | } | |
258 | ||
259 | class PoolAction : public DNSAction | |
260 | { | |
261 | public: | |
262 | PoolAction(const std::string& pool) : d_pool(pool) {} | |
d67c1cbe | 263 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
264 | { |
265 | *ruleresult=d_pool; | |
266 | return Action::Pool; | |
267 | } | |
d67c1cbe | 268 | std::string toString() const override |
6bb38cd6 RG |
269 | { |
270 | return "to pool "+d_pool; | |
271 | } | |
272 | ||
273 | private: | |
d67c1cbe | 274 | std::string d_pool; |
6bb38cd6 RG |
275 | }; |
276 | ||
277 | ||
278 | class QPSPoolAction : public DNSAction | |
279 | { | |
280 | public: | |
281 | QPSPoolAction(unsigned int limit, const std::string& pool) : d_qps(limit, limit), d_pool(pool) {} | |
d67c1cbe | 282 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
283 | { |
284 | if(d_qps.check()) { | |
285 | *ruleresult=d_pool; | |
286 | return Action::Pool; | |
287 | } | |
288 | else | |
289 | return Action::None; | |
290 | } | |
d67c1cbe | 291 | std::string toString() const override |
6bb38cd6 RG |
292 | { |
293 | return "max " +std::to_string(d_qps.getRate())+" to pool "+d_pool; | |
294 | } | |
295 | ||
296 | private: | |
297 | QPSLimiter d_qps; | |
d67c1cbe | 298 | std::string d_pool; |
6bb38cd6 RG |
299 | }; |
300 | ||
301 | class RCodeAction : public DNSAction | |
302 | { | |
303 | public: | |
f6007449 | 304 | RCodeAction(uint8_t rcode) : d_rcode(rcode) {} |
d67c1cbe | 305 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
306 | { |
307 | dq->dh->rcode = d_rcode; | |
308 | dq->dh->qr = true; // for good measure | |
d545a872 | 309 | setResponseHeadersFromConfig(*dq->dh, d_responseConfig); |
6bb38cd6 RG |
310 | return Action::HeaderModify; |
311 | } | |
d67c1cbe | 312 | std::string toString() const override |
6bb38cd6 RG |
313 | { |
314 | return "set rcode "+std::to_string(d_rcode); | |
315 | } | |
316 | ||
d545a872 | 317 | ResponseConfig d_responseConfig; |
6bb38cd6 | 318 | private: |
f6007449 | 319 | uint8_t d_rcode; |
6bb38cd6 RG |
320 | }; |
321 | ||
a9613dfe DA |
322 | class ERCodeAction : public DNSAction |
323 | { | |
324 | public: | |
325 | ERCodeAction(uint8_t rcode) : d_rcode(rcode) {} | |
d67c1cbe | 326 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
a9613dfe DA |
327 | { |
328 | dq->dh->rcode = (d_rcode & 0xF); | |
329 | dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4); | |
330 | dq->dh->qr = true; // for good measure | |
d545a872 | 331 | setResponseHeadersFromConfig(*dq->dh, d_responseConfig); |
a9613dfe DA |
332 | return Action::HeaderModify; |
333 | } | |
d67c1cbe | 334 | std::string toString() const override |
a9613dfe DA |
335 | { |
336 | return "set ercode "+ERCode::to_s(d_rcode); | |
337 | } | |
338 | ||
d545a872 | 339 | ResponseConfig d_responseConfig; |
a9613dfe DA |
340 | private: |
341 | uint8_t d_rcode; | |
342 | }; | |
343 | ||
6bb38cd6 RG |
344 | class TCAction : public DNSAction |
345 | { | |
346 | public: | |
d67c1cbe | 347 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
348 | { |
349 | return Action::Truncate; | |
350 | } | |
d67c1cbe | 351 | std::string toString() const override |
6bb38cd6 RG |
352 | { |
353 | return "tc=1 answer"; | |
354 | } | |
355 | }; | |
356 | ||
d67c1cbe | 357 | DNSAction::Action LuaAction::operator()(DNSQuestion* dq, std::string* ruleresult) const |
ac2ccb4e CH |
358 | { |
359 | std::lock_guard<std::mutex> lock(g_luamutex); | |
360 | try { | |
361 | auto ret = d_func(dq); | |
c134cbaa | 362 | if (ruleresult) { |
d67c1cbe | 363 | if (boost::optional<std::string> rule = std::get<1>(ret)) { |
c134cbaa CHB |
364 | *ruleresult = *rule; |
365 | } | |
366 | else { | |
367 | // default to empty string | |
368 | ruleresult->clear(); | |
369 | } | |
370 | } | |
ac2ccb4e CH |
371 | return (Action)std::get<0>(ret); |
372 | } catch (std::exception &e) { | |
373 | warnlog("LuaAction failed inside lua, returning ServFail: %s", e.what()); | |
374 | } catch (...) { | |
375 | warnlog("LuaAction failed inside lua, returning ServFail: [unknown exception]"); | |
376 | } | |
377 | return DNSAction::Action::ServFail; | |
378 | } | |
379 | ||
d67c1cbe | 380 | DNSResponseAction::Action LuaResponseAction::operator()(DNSResponse* dr, std::string* ruleresult) const |
ac2ccb4e CH |
381 | { |
382 | std::lock_guard<std::mutex> lock(g_luamutex); | |
383 | try { | |
384 | auto ret = d_func(dr); | |
c134cbaa | 385 | if(ruleresult) { |
d67c1cbe | 386 | if (boost::optional<std::string> rule = std::get<1>(ret)) { |
c134cbaa CHB |
387 | *ruleresult = *rule; |
388 | } | |
389 | else { | |
390 | // default to empty string | |
391 | ruleresult->clear(); | |
392 | } | |
393 | } | |
ac2ccb4e CH |
394 | return (Action)std::get<0>(ret); |
395 | } catch (std::exception &e) { | |
396 | warnlog("LuaResponseAction failed inside lua, returning ServFail: %s", e.what()); | |
397 | } catch (...) { | |
398 | warnlog("LuaResponseAction failed inside lua, returning ServFail: [unknown exception]"); | |
399 | } | |
400 | return DNSResponseAction::Action::ServFail; | |
401 | } | |
402 | ||
d67c1cbe | 403 | DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresult) const |
6bb38cd6 RG |
404 | { |
405 | uint16_t qtype = dq->qtype; | |
406 | // do we even have a response? | |
202c4ab9 RG |
407 | if (d_cname.empty() && |
408 | d_rawResponse.empty() && | |
409 | d_types.count(qtype) == 0) { | |
6bb38cd6 | 410 | return Action::None; |
202c4ab9 | 411 | } |
6bb38cd6 RG |
412 | |
413 | vector<ComboAddress> addrs; | |
202c4ab9 RG |
414 | unsigned int totrdatalen = 0; |
415 | uint16_t numberOfRecords = 0; | |
6bb38cd6 RG |
416 | if (!d_cname.empty()) { |
417 | qtype = QType::CNAME; | |
418 | totrdatalen += d_cname.toDNSString().size(); | |
202c4ab9 RG |
419 | numberOfRecords = 1; |
420 | } else if (!d_rawResponse.empty()) { | |
421 | totrdatalen += d_rawResponse.size(); | |
422 | numberOfRecords = 1; | |
423 | } | |
424 | else { | |
6bb38cd6 RG |
425 | for(const auto& addr : d_addrs) { |
426 | if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) || | |
427 | (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) { | |
428 | continue; | |
429 | } | |
430 | totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr); | |
431 | addrs.push_back(addr); | |
202c4ab9 | 432 | ++numberOfRecords; |
6bb38cd6 RG |
433 | } |
434 | } | |
435 | ||
436 | if(addrs.size() > 1) | |
437 | random_shuffle(addrs.begin(), addrs.end()); | |
438 | ||
439 | unsigned int consumed=0; | |
440 | DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed); | |
441 | ||
202c4ab9 | 442 | if (dq->size < (sizeof(dnsheader) + consumed + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen)) { |
6bb38cd6 RG |
443 | return Action::None; |
444 | } | |
445 | ||
e7c732b8 RG |
446 | bool dnssecOK = false; |
447 | bool hadEDNS = false; | |
448 | if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) { | |
449 | hadEDNS = true; | |
450 | dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO; | |
451 | } | |
452 | ||
6bb38cd6 RG |
453 | dq->len = sizeof(dnsheader) + consumed + 4; // there goes your EDNS |
454 | char* dest = ((char*)dq->dh) + dq->len; | |
455 | ||
456 | dq->dh->qr = true; // for good measure | |
d545a872 | 457 | setResponseHeadersFromConfig(*dq->dh, d_responseConfig); |
6bb38cd6 RG |
458 | dq->dh->ancount = 0; |
459 | dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it | |
460 | ||
202c4ab9 RG |
461 | uint32_t ttl = htonl(d_responseConfig.ttl); |
462 | unsigned char recordstart[] = {0xc0, 0x0c, // compressed name | |
463 | 0, 0, // QTYPE | |
464 | 0, QClass::IN, | |
465 | 0, 0, 0, 0, // TTL | |
466 | 0, 0 }; // rdata length | |
467 | static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid"); | |
468 | memcpy(&recordstart[6], &ttl, sizeof(ttl)); | |
469 | ||
470 | if (qtype == QType::CNAME) { | |
471 | const std::string wireData = d_cname.toDNSString(); // Note! This doesn't do compression! | |
472 | uint16_t rdataLen = htons(wireData.length()); | |
473 | qtype = htons(qtype); | |
474 | memcpy(&recordstart[2], &qtype, sizeof(qtype)); | |
475 | memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen)); | |
6bb38cd6 RG |
476 | |
477 | memcpy(dest, recordstart, sizeof(recordstart)); | |
478 | dest += sizeof(recordstart); | |
479 | memcpy(dest, wireData.c_str(), wireData.length()); | |
480 | dq->len += wireData.length() + sizeof(recordstart); | |
481 | dq->dh->ancount++; | |
482 | } | |
202c4ab9 RG |
483 | else if (!d_rawResponse.empty()) { |
484 | uint16_t rdataLen = htons(d_rawResponse.size()); | |
485 | qtype = htons(qtype); | |
486 | memcpy(&recordstart[2], &qtype, sizeof(qtype)); | |
487 | memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen)); | |
488 | ||
489 | memcpy(dest, recordstart, sizeof(recordstart)); | |
490 | dest += sizeof(recordstart); | |
491 | memcpy(dest, d_rawResponse.c_str(), d_rawResponse.size()); | |
492 | dq->len += d_rawResponse.size() + sizeof(recordstart); | |
493 | dq->dh->ancount++; | |
494 | } | |
6bb38cd6 RG |
495 | else { |
496 | for(const auto& addr : addrs) { | |
202c4ab9 RG |
497 | uint16_t rdataLen = htons(addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr)); |
498 | qtype = htons(addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA); | |
499 | memcpy(&recordstart[2], &qtype, sizeof(qtype)); | |
500 | memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen)); | |
6bb38cd6 RG |
501 | |
502 | memcpy(dest, recordstart, sizeof(recordstart)); | |
503 | dest += sizeof(recordstart); | |
504 | ||
505 | memcpy(dest, | |
506 | addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr, | |
202c4ab9 RG |
507 | addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr)); |
508 | dest += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr)); | |
509 | dq->len += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr)) + sizeof(recordstart); | |
6bb38cd6 RG |
510 | dq->dh->ancount++; |
511 | } | |
512 | } | |
513 | ||
514 | dq->dh->ancount = htons(dq->dh->ancount); | |
515 | ||
8d72bcdd | 516 | if (hadEDNS) { |
5e98ccfa | 517 | addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers, 0); |
e7c732b8 RG |
518 | } |
519 | ||
6bb38cd6 RG |
520 | return Action::HeaderModify; |
521 | } | |
522 | ||
523 | class MacAddrAction : public DNSAction | |
524 | { | |
525 | public: | |
526 | MacAddrAction(uint16_t code) : d_code(code) | |
527 | {} | |
d67c1cbe | 528 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
529 | { |
530 | if(dq->dh->arcount) | |
531 | return Action::None; | |
532 | ||
d67c1cbe | 533 | std::string mac = getMACAddress(*dq->remote); |
6bb38cd6 RG |
534 | if(mac.empty()) |
535 | return Action::None; | |
536 | ||
d67c1cbe | 537 | std::string optRData; |
6bb38cd6 RG |
538 | generateEDNSOption(d_code, mac, optRData); |
539 | ||
d67c1cbe | 540 | std::string res; |
5e98ccfa | 541 | generateOptRR(optRData, res, g_EdnsUDPPayloadSize, 0, false); |
6bb38cd6 RG |
542 | |
543 | if ((dq->size - dq->len) < res.length()) | |
544 | return Action::None; | |
545 | ||
546 | dq->dh->arcount = htons(1); | |
547 | char* dest = ((char*)dq->dh) + dq->len; | |
548 | memcpy(dest, res.c_str(), res.length()); | |
549 | dq->len += res.length(); | |
550 | ||
551 | return Action::None; | |
552 | } | |
d67c1cbe | 553 | std::string toString() const override |
6bb38cd6 RG |
554 | { |
555 | return "add EDNS MAC (code="+std::to_string(d_code)+")"; | |
556 | } | |
557 | private: | |
558 | uint16_t d_code{3}; | |
559 | }; | |
560 | ||
561 | class NoRecurseAction : public DNSAction | |
562 | { | |
563 | public: | |
d67c1cbe | 564 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
565 | { |
566 | dq->dh->rd = false; | |
567 | return Action::None; | |
568 | } | |
d67c1cbe | 569 | std::string toString() const override |
6bb38cd6 RG |
570 | { |
571 | return "set rd=0"; | |
572 | } | |
573 | }; | |
574 | ||
575 | class LogAction : public DNSAction, public boost::noncopyable | |
576 | { | |
577 | public: | |
320b20cd | 578 | LogAction(): d_fp(nullptr, fclose) |
6bb38cd6 RG |
579 | { |
580 | } | |
320b20cd RG |
581 | |
582 | LogAction(const std::string& str, bool binary=true, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_binary(binary), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp) | |
6bb38cd6 RG |
583 | { |
584 | if(str.empty()) | |
585 | return; | |
586 | if(append) | |
320b20cd | 587 | d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "a+"), fclose); |
6bb38cd6 | 588 | else |
320b20cd | 589 | d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "w"), fclose); |
6bb38cd6 | 590 | if(!d_fp) |
a2a81d42 | 591 | throw std::runtime_error("Unable to open file '"+str+"' for logging: "+stringerror()); |
6bb38cd6 | 592 | if(!buffered) |
320b20cd | 593 | setbuf(d_fp.get(), 0); |
6bb38cd6 | 594 | } |
320b20cd | 595 | |
d67c1cbe | 596 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 | 597 | { |
320b20cd RG |
598 | if (!d_fp) { |
599 | if (!d_verboseOnly || g_verbose) { | |
600 | if (d_includeTimestamp) { | |
601 | infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id); | |
602 | } | |
603 | else { | |
604 | infolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id); | |
605 | } | |
606 | } | |
6bb38cd6 RG |
607 | } |
608 | else { | |
320b20cd | 609 | if (d_binary) { |
d67c1cbe | 610 | std::string out = dq->qname->toDNSString(); |
320b20cd RG |
611 | if (d_includeTimestamp) { |
612 | uint64_t tv_sec = static_cast<uint64_t>(dq->queryTime->tv_sec); | |
613 | uint32_t tv_nsec = static_cast<uint32_t>(dq->queryTime->tv_nsec); | |
614 | fwrite(&tv_sec, sizeof(tv_sec), 1, d_fp.get()); | |
615 | fwrite(&tv_nsec, sizeof(tv_nsec), 1, d_fp.get()); | |
616 | } | |
617 | uint16_t id = dq->dh->id; | |
618 | fwrite(&id, sizeof(id), 1, d_fp.get()); | |
619 | fwrite(out.c_str(), 1, out.size(), d_fp.get()); | |
620 | fwrite(&dq->qtype, sizeof(dq->qtype), 1, d_fp.get()); | |
621 | fwrite(&dq->remote->sin4.sin_family, sizeof(dq->remote->sin4.sin_family), 1, d_fp.get()); | |
622 | if (dq->remote->sin4.sin_family == AF_INET) { | |
623 | fwrite(&dq->remote->sin4.sin_addr.s_addr, sizeof(dq->remote->sin4.sin_addr.s_addr), 1, d_fp.get()); | |
624 | } | |
625 | else if (dq->remote->sin4.sin_family == AF_INET6) { | |
626 | fwrite(&dq->remote->sin6.sin6_addr.s6_addr, sizeof(dq->remote->sin6.sin6_addr.s6_addr), 1, d_fp.get()); | |
627 | } | |
628 | fwrite(&dq->remote->sin4.sin_port, sizeof(dq->remote->sin4.sin_port), 1, d_fp.get()); | |
6bb38cd6 RG |
629 | } |
630 | else { | |
320b20cd RG |
631 | if (d_includeTimestamp) { |
632 | fprintf(d_fp.get(), "[%llu.%lu] Packet from %s for %s %s with id %d\n", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->dh->id); | |
633 | } | |
634 | else { | |
635 | fprintf(d_fp.get(), "Packet from %s for %s %s with id %d\n", dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->dh->id); | |
636 | } | |
6bb38cd6 RG |
637 | } |
638 | } | |
639 | return Action::None; | |
640 | } | |
320b20cd | 641 | |
d67c1cbe | 642 | std::string toString() const override |
6bb38cd6 RG |
643 | { |
644 | if (!d_fname.empty()) { | |
645 | return "log to " + d_fname; | |
646 | } | |
647 | return "log"; | |
648 | } | |
649 | private: | |
d67c1cbe | 650 | std::string d_fname; |
320b20cd | 651 | std::unique_ptr<FILE, int(*)(FILE*)> d_fp{nullptr, fclose}; |
6bb38cd6 | 652 | bool d_binary{true}; |
320b20cd RG |
653 | bool d_verboseOnly{true}; |
654 | bool d_includeTimestamp{false}; | |
6bb38cd6 RG |
655 | }; |
656 | ||
b62c160b | 657 | class LogResponseAction : public DNSResponseAction, public boost::noncopyable |
658 | { | |
659 | public: | |
660 | LogResponseAction(): d_fp(nullptr, fclose) | |
661 | { | |
662 | } | |
663 | ||
664 | LogResponseAction(const std::string& str, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp) | |
665 | { | |
666 | if(str.empty()) | |
667 | return; | |
668 | if(append) | |
669 | d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "a+"), fclose); | |
670 | else | |
671 | d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "w"), fclose); | |
672 | if(!d_fp) | |
673 | throw std::runtime_error("Unable to open file '"+str+"' for logging: "+stringerror()); | |
674 | if(!buffered) | |
675 | setbuf(d_fp.get(), 0); | |
676 | } | |
677 | ||
678 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override | |
679 | { | |
680 | if (!d_fp) { | |
681 | if (!d_verboseOnly || g_verbose) { | |
682 | if (d_includeTimestamp) { | |
683 | infolog("[%u.%u] Answer to %s for %s %s (%s) with id %d", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id); | |
684 | } | |
685 | else { | |
686 | infolog("Answer to %s for %s %s (%s) with id %d", dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id); | |
687 | } | |
688 | } | |
689 | } | |
690 | else { | |
691 | if (d_includeTimestamp) { | |
692 | fprintf(d_fp.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %d\n", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id); | |
693 | } | |
694 | else { | |
695 | fprintf(d_fp.get(), "Answer to %s for %s %s (%s) with id %d\n", dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id); | |
696 | } | |
697 | } | |
698 | return Action::None; | |
699 | } | |
700 | ||
701 | std::string toString() const override | |
702 | { | |
703 | if (!d_fname.empty()) { | |
704 | return "log to " + d_fname; | |
705 | } | |
706 | return "log"; | |
707 | } | |
708 | private: | |
709 | std::string d_fname; | |
710 | std::unique_ptr<FILE, int(*)(FILE*)> d_fp{nullptr, fclose}; | |
711 | bool d_verboseOnly{true}; | |
712 | bool d_includeTimestamp{false}; | |
713 | }; | |
714 | ||
6bb38cd6 RG |
715 | |
716 | class DisableValidationAction : public DNSAction | |
717 | { | |
718 | public: | |
d67c1cbe | 719 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
720 | { |
721 | dq->dh->cd = true; | |
722 | return Action::None; | |
723 | } | |
d67c1cbe | 724 | std::string toString() const override |
6bb38cd6 RG |
725 | { |
726 | return "set cd=1"; | |
727 | } | |
728 | }; | |
729 | ||
730 | class SkipCacheAction : public DNSAction | |
731 | { | |
732 | public: | |
d67c1cbe | 733 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
734 | { |
735 | dq->skipCache = true; | |
736 | return Action::None; | |
737 | } | |
d67c1cbe | 738 | std::string toString() const override |
6bb38cd6 RG |
739 | { |
740 | return "skip cache"; | |
741 | } | |
742 | }; | |
743 | ||
acb8f5d5 CH |
744 | class TempFailureCacheTTLAction : public DNSAction |
745 | { | |
746 | public: | |
747 | TempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl) | |
748 | {} | |
d67c1cbe | 749 | TempFailureCacheTTLAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
acb8f5d5 CH |
750 | { |
751 | dq->tempFailureTTL = d_ttl; | |
752 | return Action::None; | |
753 | } | |
d67c1cbe | 754 | std::string toString() const override |
acb8f5d5 CH |
755 | { |
756 | return "set tempfailure cache ttl to "+std::to_string(d_ttl); | |
757 | } | |
758 | private: | |
759 | uint32_t d_ttl; | |
760 | }; | |
761 | ||
6bb38cd6 RG |
762 | class ECSPrefixLengthAction : public DNSAction |
763 | { | |
764 | public: | |
765 | ECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length) | |
766 | { | |
767 | } | |
d67c1cbe | 768 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
769 | { |
770 | dq->ecsPrefixLength = dq->remote->sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength; | |
771 | return Action::None; | |
772 | } | |
d67c1cbe | 773 | std::string toString() const override |
6bb38cd6 RG |
774 | { |
775 | return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength); | |
776 | } | |
777 | private: | |
778 | uint16_t d_v4PrefixLength; | |
779 | uint16_t d_v6PrefixLength; | |
780 | }; | |
781 | ||
782 | class ECSOverrideAction : public DNSAction | |
783 | { | |
784 | public: | |
785 | ECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride) | |
786 | { | |
787 | } | |
d67c1cbe | 788 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
789 | { |
790 | dq->ecsOverride = d_ecsOverride; | |
791 | return Action::None; | |
792 | } | |
d67c1cbe | 793 | std::string toString() const override |
6bb38cd6 RG |
794 | { |
795 | return "set ECS override to " + std::to_string(d_ecsOverride); | |
796 | } | |
797 | private: | |
798 | bool d_ecsOverride; | |
799 | }; | |
800 | ||
801 | ||
802 | class DisableECSAction : public DNSAction | |
803 | { | |
804 | public: | |
d67c1cbe | 805 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
806 | { |
807 | dq->useECS = false; | |
808 | return Action::None; | |
809 | } | |
d67c1cbe | 810 | std::string toString() const override |
6bb38cd6 RG |
811 | { |
812 | return "disable ECS"; | |
813 | } | |
814 | }; | |
815 | ||
bd14f087 RG |
816 | class SetECSAction : public DNSAction |
817 | { | |
818 | public: | |
4bd24482 | 819 | SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false) |
bd14f087 RG |
820 | { |
821 | } | |
822 | ||
4bd24482 | 823 | SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true) |
bd14f087 RG |
824 | { |
825 | } | |
826 | ||
d67c1cbe | 827 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
bd14f087 RG |
828 | { |
829 | dq->ecsSet = true; | |
830 | ||
831 | if (d_hasV6) { | |
832 | dq->ecs = dq->remote->isIPv4() ? d_v4 : d_v6; | |
833 | } | |
834 | else { | |
835 | dq->ecs = d_v4; | |
836 | } | |
837 | ||
838 | return Action::None; | |
839 | } | |
840 | ||
d67c1cbe | 841 | std::string toString() const override |
bd14f087 | 842 | { |
d67c1cbe | 843 | std::string result = "set ECS to " + d_v4.toString(); |
bd14f087 RG |
844 | if (d_hasV6) { |
845 | result += " / " + d_v6.toString(); | |
846 | } | |
847 | return result; | |
848 | } | |
849 | ||
850 | private: | |
851 | Netmask d_v4; | |
852 | Netmask d_v6; | |
853 | bool d_hasV6; | |
854 | }; | |
855 | ||
856 | ||
82a91ddf CH |
857 | class DnstapLogAction : public DNSAction, public boost::noncopyable |
858 | { | |
859 | public: | |
dd1a3034 | 860 | DnstapLogAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc) |
82a91ddf CH |
861 | { |
862 | } | |
d67c1cbe | 863 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
82a91ddf CH |
864 | { |
865 | #ifdef HAVE_PROTOBUF | |
866 | DnstapMessage message(d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr); | |
867 | { | |
868 | if (d_alterFunc) { | |
869 | std::lock_guard<std::mutex> lock(g_luamutex); | |
dd1a3034 | 870 | (*d_alterFunc)(dq, &message); |
82a91ddf CH |
871 | } |
872 | } | |
873 | std::string data; | |
874 | message.serialize(data); | |
875 | d_logger->queueData(data); | |
876 | #endif /* HAVE_PROTOBUF */ | |
877 | return Action::None; | |
878 | } | |
d67c1cbe | 879 | std::string toString() const override |
82a91ddf CH |
880 | { |
881 | return "remote log as dnstap to " + (d_logger ? d_logger->toString() : ""); | |
882 | } | |
883 | private: | |
884 | std::string d_identity; | |
885 | std::shared_ptr<RemoteLoggerInterface> d_logger; | |
dd1a3034 | 886 | boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > d_alterFunc; |
82a91ddf CH |
887 | }; |
888 | ||
6bb38cd6 RG |
889 | class RemoteLogAction : public DNSAction, public boost::noncopyable |
890 | { | |
891 | public: | |
dd1a3034 | 892 | RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey) |
6bb38cd6 RG |
893 | { |
894 | } | |
d67c1cbe | 895 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
896 | { |
897 | #ifdef HAVE_PROTOBUF | |
898 | if (!dq->uniqueId) { | |
d61aa945 | 899 | dq->uniqueId = getUniqueID(); |
6bb38cd6 RG |
900 | } |
901 | ||
902 | DNSDistProtoBufMessage message(*dq); | |
312a09a6 RG |
903 | if (!d_serverID.empty()) { |
904 | message.setServerIdentity(d_serverID); | |
6bb38cd6 | 905 | } |
312a09a6 | 906 | |
af7afecf RG |
907 | #if HAVE_LIBCRYPTO |
908 | if (!d_ipEncryptKey.empty()) | |
909 | { | |
910 | message.setRequestor(encryptCA(*dq->remote, d_ipEncryptKey)); | |
911 | } | |
912 | #endif /* HAVE_LIBCRYPTO */ | |
913 | ||
312a09a6 RG |
914 | if (d_alterFunc) { |
915 | std::lock_guard<std::mutex> lock(g_luamutex); | |
dd1a3034 | 916 | (*d_alterFunc)(dq, &message); |
312a09a6 RG |
917 | } |
918 | ||
6bb38cd6 RG |
919 | std::string data; |
920 | message.serialize(data); | |
921 | d_logger->queueData(data); | |
922 | #endif /* HAVE_PROTOBUF */ | |
923 | return Action::None; | |
924 | } | |
d67c1cbe | 925 | std::string toString() const override |
6bb38cd6 RG |
926 | { |
927 | return "remote log to " + (d_logger ? d_logger->toString() : ""); | |
928 | } | |
929 | private: | |
82a91ddf | 930 | std::shared_ptr<RemoteLoggerInterface> d_logger; |
dd1a3034 | 931 | boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc; |
312a09a6 | 932 | std::string d_serverID; |
af7afecf | 933 | std::string d_ipEncryptKey; |
6bb38cd6 RG |
934 | }; |
935 | ||
936 | class SNMPTrapAction : public DNSAction | |
937 | { | |
938 | public: | |
939 | SNMPTrapAction(const std::string& reason): d_reason(reason) | |
940 | { | |
941 | } | |
d67c1cbe | 942 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 RG |
943 | { |
944 | if (g_snmpAgent && g_snmpTrapsEnabled) { | |
945 | g_snmpAgent->sendDNSTrap(*dq, d_reason); | |
946 | } | |
947 | ||
948 | return Action::None; | |
949 | } | |
d67c1cbe | 950 | std::string toString() const override |
6bb38cd6 RG |
951 | { |
952 | return "send SNMP trap"; | |
953 | } | |
954 | private: | |
955 | std::string d_reason; | |
956 | }; | |
957 | ||
958 | class TagAction : public DNSAction | |
959 | { | |
960 | public: | |
f3b1a1ef | 961 | TagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value) |
6bb38cd6 RG |
962 | { |
963 | } | |
d67c1cbe | 964 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override |
6bb38cd6 | 965 | { |
15fac047 | 966 | if (!dq->qTag) { |
6bb38cd6 RG |
967 | dq->qTag = std::make_shared<QTag>(); |
968 | } | |
969 | ||
15fac047 | 970 | dq->qTag->insert({d_tag, d_value}); |
6bb38cd6 RG |
971 | |
972 | return Action::None; | |
973 | } | |
d67c1cbe | 974 | std::string toString() const override |
6bb38cd6 RG |
975 | { |
976 | return "set tag '" + d_tag + "' to value '" + d_value + "'"; | |
977 | } | |
978 | private: | |
979 | std::string d_tag; | |
980 | std::string d_value; | |
981 | }; | |
982 | ||
82a91ddf CH |
983 | class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable |
984 | { | |
985 | public: | |
dd1a3034 | 986 | DnstapLogResponseAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc) |
82a91ddf CH |
987 | { |
988 | } | |
d67c1cbe | 989 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override |
82a91ddf CH |
990 | { |
991 | #ifdef HAVE_PROTOBUF | |
992 | struct timespec now; | |
993 | gettime(&now, true); | |
994 | DnstapMessage message(d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now); | |
995 | { | |
996 | if (d_alterFunc) { | |
997 | std::lock_guard<std::mutex> lock(g_luamutex); | |
dd1a3034 | 998 | (*d_alterFunc)(dr, &message); |
82a91ddf CH |
999 | } |
1000 | } | |
1001 | std::string data; | |
1002 | message.serialize(data); | |
1003 | d_logger->queueData(data); | |
1004 | #endif /* HAVE_PROTOBUF */ | |
1005 | return Action::None; | |
1006 | } | |
d67c1cbe | 1007 | std::string toString() const override |
82a91ddf CH |
1008 | { |
1009 | return "log response as dnstap to " + (d_logger ? d_logger->toString() : ""); | |
1010 | } | |
1011 | private: | |
1012 | std::string d_identity; | |
1013 | std::shared_ptr<RemoteLoggerInterface> d_logger; | |
dd1a3034 | 1014 | boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > d_alterFunc; |
82a91ddf CH |
1015 | }; |
1016 | ||
6bb38cd6 RG |
1017 | class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable |
1018 | { | |
1019 | public: | |
dd1a3034 | 1020 | RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, bool includeCNAME): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey), d_includeCNAME(includeCNAME) |
6bb38cd6 RG |
1021 | { |
1022 | } | |
d67c1cbe | 1023 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override |
6bb38cd6 RG |
1024 | { |
1025 | #ifdef HAVE_PROTOBUF | |
1026 | if (!dr->uniqueId) { | |
d61aa945 | 1027 | dr->uniqueId = getUniqueID(); |
6bb38cd6 RG |
1028 | } |
1029 | ||
1030 | DNSDistProtoBufMessage message(*dr, d_includeCNAME); | |
312a09a6 RG |
1031 | if (!d_serverID.empty()) { |
1032 | message.setServerIdentity(d_serverID); | |
1033 | } | |
1034 | ||
af7afecf RG |
1035 | #if HAVE_LIBCRYPTO |
1036 | if (!d_ipEncryptKey.empty()) | |
1037 | { | |
1038 | message.setRequestor(encryptCA(*dr->remote, d_ipEncryptKey)); | |
1039 | } | |
1040 | #endif /* HAVE_LIBCRYPTO */ | |
1041 | ||
312a09a6 RG |
1042 | if (d_alterFunc) { |
1043 | std::lock_guard<std::mutex> lock(g_luamutex); | |
dd1a3034 | 1044 | (*d_alterFunc)(dr, &message); |
6bb38cd6 | 1045 | } |
312a09a6 | 1046 | |
6bb38cd6 RG |
1047 | std::string data; |
1048 | message.serialize(data); | |
1049 | d_logger->queueData(data); | |
1050 | #endif /* HAVE_PROTOBUF */ | |
1051 | return Action::None; | |
1052 | } | |
d67c1cbe | 1053 | std::string toString() const override |
6bb38cd6 RG |
1054 | { |
1055 | return "remote log response to " + (d_logger ? d_logger->toString() : ""); | |
1056 | } | |
1057 | private: | |
82a91ddf | 1058 | std::shared_ptr<RemoteLoggerInterface> d_logger; |
dd1a3034 | 1059 | boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc; |
312a09a6 | 1060 | std::string d_serverID; |
af7afecf | 1061 | std::string d_ipEncryptKey; |
6bb38cd6 RG |
1062 | bool d_includeCNAME; |
1063 | }; | |
1064 | ||
1065 | class DropResponseAction : public DNSResponseAction | |
1066 | { | |
1067 | public: | |
d67c1cbe | 1068 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override |
6bb38cd6 RG |
1069 | { |
1070 | return Action::Drop; | |
1071 | } | |
d67c1cbe | 1072 | std::string toString() const override |
6bb38cd6 RG |
1073 | { |
1074 | return "drop"; | |
1075 | } | |
1076 | }; | |
1077 | ||
1078 | class AllowResponseAction : public DNSResponseAction | |
1079 | { | |
1080 | public: | |
d67c1cbe | 1081 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override |
6bb38cd6 RG |
1082 | { |
1083 | return Action::Allow; | |
1084 | } | |
d67c1cbe | 1085 | std::string toString() const override |
6bb38cd6 RG |
1086 | { |
1087 | return "allow"; | |
1088 | } | |
1089 | }; | |
1090 | ||
1091 | class DelayResponseAction : public DNSResponseAction | |
1092 | { | |
1093 | public: | |
1094 | DelayResponseAction(int msec) : d_msec(msec) | |
1095 | {} | |
d67c1cbe | 1096 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override |
6bb38cd6 RG |
1097 | { |
1098 | *ruleresult=std::to_string(d_msec); | |
1099 | return Action::Delay; | |
1100 | } | |
d67c1cbe | 1101 | std::string toString() const override |
6bb38cd6 RG |
1102 | { |
1103 | return "delay by "+std::to_string(d_msec)+ " msec"; | |
1104 | } | |
1105 | private: | |
1106 | int d_msec; | |
1107 | }; | |
1108 | ||
1109 | class SNMPTrapResponseAction : public DNSResponseAction | |
1110 | { | |
1111 | public: | |
1112 | SNMPTrapResponseAction(const std::string& reason): d_reason(reason) | |
1113 | { | |
1114 | } | |
d67c1cbe | 1115 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override |
6bb38cd6 RG |
1116 | { |
1117 | if (g_snmpAgent && g_snmpTrapsEnabled) { | |
1118 | g_snmpAgent->sendDNSTrap(*dr, d_reason); | |
1119 | } | |
1120 | ||
1121 | return Action::None; | |
1122 | } | |
d67c1cbe | 1123 | std::string toString() const override |
6bb38cd6 RG |
1124 | { |
1125 | return "send SNMP trap"; | |
1126 | } | |
1127 | private: | |
1128 | std::string d_reason; | |
1129 | }; | |
1130 | ||
1131 | class TagResponseAction : public DNSResponseAction | |
1132 | { | |
1133 | public: | |
f3b1a1ef | 1134 | TagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value) |
6bb38cd6 RG |
1135 | { |
1136 | } | |
d67c1cbe | 1137 | DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override |
6bb38cd6 | 1138 | { |
15fac047 | 1139 | if (!dr->qTag) { |
6bb38cd6 RG |
1140 | dr->qTag = std::make_shared<QTag>(); |
1141 | } | |
1142 | ||
15fac047 | 1143 | dr->qTag->insert({d_tag, d_value}); |
6bb38cd6 RG |
1144 | |
1145 | return Action::None; | |
1146 | } | |
d67c1cbe | 1147 | std::string toString() const override |
6bb38cd6 RG |
1148 | { |
1149 | return "set tag '" + d_tag + "' to value '" + d_value + "'"; | |
1150 | } | |
1151 | private: | |
1152 | std::string d_tag; | |
1153 | std::string d_value; | |
1154 | }; | |
1155 | ||
2a28db86 RG |
1156 | class ContinueAction : public DNSAction |
1157 | { | |
1158 | public: | |
1159 | ContinueAction(std::shared_ptr<DNSAction>& action): d_action(action) | |
1160 | { | |
1161 | } | |
1162 | ||
1163 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override | |
1164 | { | |
1165 | if (d_action) { | |
1166 | /* call the action */ | |
1167 | auto action = (*d_action)(dq, ruleresult); | |
1168 | bool drop = false; | |
1169 | /* apply the changes if needed (pool selection, flags, etc */ | |
1170 | processRulesResult(action, *dq, *ruleresult, drop); | |
1171 | } | |
1172 | ||
1173 | /* but ignore the resulting action no matter what */ | |
1174 | return Action::None; | |
1175 | } | |
1176 | ||
1177 | std::string toString() const override | |
1178 | { | |
1179 | if (d_action) { | |
1180 | return "continue after: " + (d_action ? d_action->toString() : ""); | |
1181 | } | |
1182 | else { | |
1183 | return "no op"; | |
1184 | } | |
1185 | } | |
1186 | ||
1187 | private: | |
1188 | std::shared_ptr<DNSAction> d_action; | |
1189 | }; | |
1190 | ||
13c1fc12 RG |
1191 | #ifdef HAVE_DNS_OVER_HTTPS |
1192 | class HTTPStatusAction: public DNSAction | |
1193 | { | |
1194 | public: | |
9676d2a9 | 1195 | HTTPStatusAction(int code, const std::string& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code) |
13c1fc12 RG |
1196 | { |
1197 | } | |
1198 | ||
1199 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override | |
1200 | { | |
1201 | if (!dq->du) { | |
1202 | return Action::None; | |
1203 | } | |
1204 | ||
9676d2a9 | 1205 | dq->du->setHTTPResponse(d_code, d_body, d_contentType); |
13c1fc12 | 1206 | dq->dh->qr = true; // for good measure |
d545a872 | 1207 | setResponseHeadersFromConfig(*dq->dh, d_responseConfig); |
13c1fc12 RG |
1208 | return Action::HeaderModify; |
1209 | } | |
1210 | ||
1211 | std::string toString() const override | |
1212 | { | |
1213 | return "return an HTTP status of " + std::to_string(d_code); | |
1214 | } | |
d545a872 RG |
1215 | |
1216 | ResponseConfig d_responseConfig; | |
13c1fc12 | 1217 | private: |
13c1fc12 | 1218 | std::string d_body; |
9676d2a9 | 1219 | std::string d_contentType; |
13c1fc12 RG |
1220 | int d_code; |
1221 | }; | |
1222 | #endif /* HAVE_DNS_OVER_HTTPS */ | |
1223 | ||
f441962a RG |
1224 | class KeyValueStoreLookupAction : public DNSAction |
1225 | { | |
1226 | public: | |
1227 | KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag) | |
1228 | { | |
1229 | } | |
1230 | ||
1231 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override | |
1232 | { | |
77eebb37 | 1233 | std::vector<std::string> keys = d_key->getKeys(*dq); |
90fe8ae6 | 1234 | std::string result; |
77eebb37 RG |
1235 | for (const auto& key : keys) { |
1236 | if (d_kvs->getValue(key, result) == true) { | |
1237 | break; | |
1238 | } | |
1239 | } | |
f441962a RG |
1240 | |
1241 | if (!dq->qTag) { | |
1242 | dq->qTag = std::make_shared<QTag>(); | |
1243 | } | |
1244 | ||
1245 | dq->qTag->insert({d_tag, std::move(result)}); | |
1246 | ||
1247 | return Action::None; | |
1248 | } | |
1249 | ||
1250 | std::string toString() const override | |
1251 | { | |
1252 | return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'"; | |
1253 | } | |
1254 | ||
1255 | private: | |
1256 | std::shared_ptr<KeyValueStore> d_kvs; | |
1257 | std::shared_ptr<KeyValueLookupKey> d_key; | |
1258 | std::string d_tag; | |
1259 | }; | |
1260 | ||
af9f750c RG |
1261 | class SetNegativeAndSOAAction: public DNSAction |
1262 | { | |
1263 | public: | |
1264 | SetNegativeAndSOAAction(bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum): d_zone(zone), d_mname(mname), d_rname(rname), d_ttl(ttl), d_serial(serial), d_refresh(refresh), d_retry(retry), d_expire(expire), d_minimum(minimum), d_nxd(nxd) | |
1265 | { | |
1266 | } | |
1267 | ||
1268 | DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override | |
1269 | { | |
1270 | if (!setNegativeAndAdditionalSOA(*dq, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_serial, d_refresh, d_retry, d_expire, d_minimum)) { | |
1271 | return Action::None; | |
1272 | } | |
1273 | ||
1274 | return Action::Allow; | |
1275 | } | |
1276 | ||
1277 | std::string toString() const override | |
1278 | { | |
1279 | return std::string(d_nxd ? "NXD " : "NODATA") + " with SOA"; | |
1280 | } | |
1281 | ||
1282 | private: | |
1283 | DNSName d_zone; | |
1284 | DNSName d_mname; | |
1285 | DNSName d_rname; | |
1286 | uint32_t d_ttl; | |
1287 | uint32_t d_serial; | |
1288 | uint32_t d_refresh; | |
1289 | uint32_t d_retry; | |
1290 | uint32_t d_expire; | |
1291 | uint32_t d_minimum; | |
1292 | bool d_nxd; | |
1293 | }; | |
1294 | ||
d18eab67 | 1295 | template<typename T, typename ActionT> |
3ebf2998 | 1296 | static void addAction(GlobalStateHolder<vector<T> > *someRulActions, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params) { |
d18eab67 CH |
1297 | setLuaSideEffect(); |
1298 | ||
1299 | boost::uuids::uuid uuid; | |
f8a222ac RG |
1300 | uint64_t creationOrder; |
1301 | parseRuleParams(params, uuid, creationOrder); | |
d18eab67 CH |
1302 | |
1303 | auto rule=makeRule(var); | |
bccee370 RG |
1304 | someRulActions->modify([&rule, &action, &uuid, creationOrder](vector<T>& rulactions){ |
1305 | rulactions.push_back({std::move(rule), std::move(action), std::move(uuid), creationOrder}); | |
d18eab67 CH |
1306 | }); |
1307 | } | |
1308 | ||
202c4ab9 | 1309 | typedef std::unordered_map<std::string, boost::variant<bool, uint32_t> > responseParams_t; |
955b9377 | 1310 | |
d545a872 | 1311 | static void parseResponseConfig(boost::optional<responseParams_t> vars, ResponseConfig& config) |
955b9377 RG |
1312 | { |
1313 | if (vars) { | |
202c4ab9 RG |
1314 | if (vars->count("ttl")) { |
1315 | config.ttl = boost::get<uint32_t>((*vars)["ttl"]); | |
1316 | } | |
955b9377 | 1317 | if (vars->count("aa")) { |
d545a872 | 1318 | config.setAA = boost::get<bool>((*vars)["aa"]); |
955b9377 RG |
1319 | } |
1320 | if (vars->count("ad")) { | |
d545a872 | 1321 | config.setAD = boost::get<bool>((*vars)["ad"]); |
955b9377 RG |
1322 | } |
1323 | if (vars->count("ra")) { | |
d545a872 | 1324 | config.setRA = boost::get<bool>((*vars)["ra"]); |
955b9377 RG |
1325 | } |
1326 | } | |
1327 | } | |
1328 | ||
d545a872 RG |
1329 | void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config) |
1330 | { | |
1331 | if (config.setAA) { | |
1332 | dh.aa = *config.setAA; | |
1333 | } | |
1334 | if (config.setAD) { | |
1335 | dh.ad = *config.setAD; | |
1336 | } | |
1337 | else { | |
1338 | dh.ad = false; | |
1339 | } | |
1340 | if (config.setRA) { | |
1341 | dh.ra = *config.setRA; | |
1342 | } | |
1343 | else { | |
1344 | dh.ra = dh.rd; // for good measure | |
1345 | } | |
1346 | } | |
1347 | ||
6bb38cd6 RG |
1348 | void setupLuaActions() |
1349 | { | |
4d5959e6 RG |
1350 | g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) { |
1351 | boost::uuids::uuid uuid; | |
f8a222ac RG |
1352 | uint64_t creationOrder; |
1353 | parseRuleParams(params, uuid, creationOrder); | |
4d5959e6 | 1354 | |
6bb38cd6 | 1355 | auto rule=makeRule(dnsrule); |
bccee370 | 1356 | DNSDistRuleAction ra({std::move(rule), action, uuid, creationOrder}); |
4d5959e6 | 1357 | return std::make_shared<DNSDistRuleAction>(ra); |
6bb38cd6 RG |
1358 | }); |
1359 | ||
4d5959e6 | 1360 | g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) { |
d18eab67 | 1361 | if (era.type() != typeid(std::shared_ptr<DNSAction>)) { |
6bb38cd6 RG |
1362 | throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); |
1363 | } | |
1364 | ||
d18eab67 | 1365 | addAction(&g_rulactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params); |
6bb38cd6 RG |
1366 | }); |
1367 | ||
4d5959e6 | 1368 | g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) { |
d18eab67 | 1369 | if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) { |
6bb38cd6 RG |
1370 | throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); |
1371 | } | |
1372 | ||
d18eab67 | 1373 | addAction(&g_resprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params); |
6bb38cd6 RG |
1374 | }); |
1375 | ||
4d5959e6 | 1376 | g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) { |
d18eab67 | 1377 | if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) { |
4d5959e6 RG |
1378 | throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); |
1379 | } | |
1380 | ||
d18eab67 | 1381 | addAction(&g_cachehitresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params); |
6bb38cd6 RG |
1382 | }); |
1383 | ||
2d4783a8 CH |
1384 | g_lua.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) { |
1385 | if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) { | |
1386 | throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); | |
1387 | } | |
1388 | ||
1389 | addAction(&g_selfansweredresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params); | |
1390 | }); | |
1391 | ||
6bb38cd6 RG |
1392 | g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) { |
1393 | setLuaNoSideEffect(); | |
1394 | auto stats = ta.getStats(); | |
1395 | for(const auto& s : stats) { | |
1396 | g_outputBuffer+=s.first+"\t"; | |
1397 | if((uint64_t)s.second == s.second) | |
1398 | g_outputBuffer += std::to_string((uint64_t)s.second)+"\n"; | |
1399 | else | |
1400 | g_outputBuffer += std::to_string(s.second)+"\n"; | |
1401 | } | |
1402 | }); | |
1403 | ||
1404 | g_lua.writeFunction("getAction", [](unsigned int num) { | |
1405 | setLuaNoSideEffect(); | |
1406 | boost::optional<std::shared_ptr<DNSAction>> ret; | |
1407 | auto rulactions = g_rulactions.getCopy(); | |
1408 | if(num < rulactions.size()) | |
4d5959e6 | 1409 | ret=rulactions[num].d_action; |
6bb38cd6 RG |
1410 | return ret; |
1411 | }); | |
1412 | ||
1413 | g_lua.registerFunction("getStats", &DNSAction::getStats); | |
1414 | ||
1415 | g_lua.writeFunction("LuaAction", [](LuaAction::func_t func) { | |
1416 | setLuaSideEffect(); | |
1417 | return std::shared_ptr<DNSAction>(new LuaAction(func)); | |
1418 | }); | |
1419 | ||
1420 | g_lua.writeFunction("NoRecurseAction", []() { | |
1421 | return std::shared_ptr<DNSAction>(new NoRecurseAction); | |
1422 | }); | |
1423 | ||
1424 | g_lua.writeFunction("MacAddrAction", [](int code) { | |
1425 | return std::shared_ptr<DNSAction>(new MacAddrAction(code)); | |
1426 | }); | |
1427 | ||
d67c1cbe | 1428 | g_lua.writeFunction("PoolAction", [](const std::string& a) { |
6bb38cd6 RG |
1429 | return std::shared_ptr<DNSAction>(new PoolAction(a)); |
1430 | }); | |
1431 | ||
1432 | g_lua.writeFunction("QPSAction", [](int limit) { | |
1433 | return std::shared_ptr<DNSAction>(new QPSAction(limit)); | |
1434 | }); | |
1435 | ||
d67c1cbe | 1436 | g_lua.writeFunction("QPSPoolAction", [](int limit, const std::string& a) { |
6bb38cd6 RG |
1437 | return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a)); |
1438 | }); | |
1439 | ||
d545a872 | 1440 | g_lua.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b, boost::optional<responseParams_t> vars ) { |
6bb38cd6 | 1441 | vector<ComboAddress> addrs; |
d67c1cbe | 1442 | if(auto s = boost::get<std::string>(&inp)) |
6bb38cd6 RG |
1443 | addrs.push_back(ComboAddress(*s)); |
1444 | else { | |
d67c1cbe | 1445 | const auto& v = boost::get<vector<pair<int,std::string>>>(inp); |
6bb38cd6 RG |
1446 | for(const auto& a: v) |
1447 | addrs.push_back(ComboAddress(a.second)); | |
1448 | } | |
955b9377 | 1449 | if(b) { |
6bb38cd6 | 1450 | addrs.push_back(ComboAddress(*b)); |
955b9377 RG |
1451 | } |
1452 | ||
1453 | auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs)); | |
955b9377 | 1454 | auto sa = std::dynamic_pointer_cast<SpoofAction>(ret); |
d545a872 | 1455 | parseResponseConfig(vars, sa->d_responseConfig); |
955b9377 | 1456 | return ret; |
6bb38cd6 RG |
1457 | }); |
1458 | ||
d545a872 | 1459 | g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<responseParams_t> vars) { |
202c4ab9 | 1460 | auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(a))); |
955b9377 | 1461 | auto sa = std::dynamic_pointer_cast<SpoofAction>(ret); |
202c4ab9 RG |
1462 | parseResponseConfig(vars, sa->d_responseConfig); |
1463 | return ret; | |
1464 | }); | |
1465 | ||
1466 | g_lua.writeFunction("SpoofRawAction", [](const std::string& raw, boost::optional<responseParams_t> vars) { | |
1467 | auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raw)); | |
1468 | auto sa = std::dynamic_pointer_cast<SpoofAction>(ret); | |
1469 | parseResponseConfig(vars, sa->d_responseConfig); | |
955b9377 | 1470 | return ret; |
6bb38cd6 RG |
1471 | }); |
1472 | ||
1473 | g_lua.writeFunction("DropAction", []() { | |
1474 | return std::shared_ptr<DNSAction>(new DropAction); | |
1475 | }); | |
1476 | ||
1477 | g_lua.writeFunction("AllowAction", []() { | |
1478 | return std::shared_ptr<DNSAction>(new AllowAction); | |
1479 | }); | |
1480 | ||
bc084a31 RG |
1481 | g_lua.writeFunction("NoneAction", []() { |
1482 | return std::shared_ptr<DNSAction>(new NoneAction); | |
1483 | }); | |
1484 | ||
6bb38cd6 RG |
1485 | g_lua.writeFunction("DelayAction", [](int msec) { |
1486 | return std::shared_ptr<DNSAction>(new DelayAction(msec)); | |
1487 | }); | |
1488 | ||
1489 | g_lua.writeFunction("TCAction", []() { | |
1490 | return std::shared_ptr<DNSAction>(new TCAction); | |
1491 | }); | |
1492 | ||
1493 | g_lua.writeFunction("DisableValidationAction", []() { | |
1494 | return std::shared_ptr<DNSAction>(new DisableValidationAction); | |
1495 | }); | |
1496 | ||
320b20cd RG |
1497 | g_lua.writeFunction("LogAction", [](boost::optional<std::string> fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) { |
1498 | return std::shared_ptr<DNSAction>(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); | |
6bb38cd6 RG |
1499 | }); |
1500 | ||
b62c160b | 1501 | g_lua.writeFunction("LogResponseAction", [](boost::optional<std::string> fname, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) { |
1502 | return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); | |
1503 | }); | |
1504 | ||
d545a872 RG |
1505 | g_lua.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) { |
1506 | auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode)); | |
1507 | auto rca = std::dynamic_pointer_cast<RCodeAction>(ret); | |
1508 | parseResponseConfig(vars, rca->d_responseConfig); | |
1509 | return ret; | |
6bb38cd6 RG |
1510 | }); |
1511 | ||
d545a872 RG |
1512 | g_lua.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) { |
1513 | auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode)); | |
1514 | auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret); | |
1515 | parseResponseConfig(vars, erca->d_responseConfig); | |
1516 | return ret; | |
a9613dfe DA |
1517 | }); |
1518 | ||
6bb38cd6 RG |
1519 | g_lua.writeFunction("SkipCacheAction", []() { |
1520 | return std::shared_ptr<DNSAction>(new SkipCacheAction); | |
1521 | }); | |
1522 | ||
acb8f5d5 CH |
1523 | g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) { |
1524 | return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL)); | |
1525 | }); | |
1526 | ||
6bb38cd6 RG |
1527 | g_lua.writeFunction("DropResponseAction", []() { |
1528 | return std::shared_ptr<DNSResponseAction>(new DropResponseAction); | |
1529 | }); | |
1530 | ||
1531 | g_lua.writeFunction("AllowResponseAction", []() { | |
1532 | return std::shared_ptr<DNSResponseAction>(new AllowResponseAction); | |
1533 | }); | |
1534 | ||
1535 | g_lua.writeFunction("DelayResponseAction", [](int msec) { | |
1536 | return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec)); | |
1537 | }); | |
1538 | ||
1539 | g_lua.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) { | |
1540 | setLuaSideEffect(); | |
1541 | return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func)); | |
1542 | }); | |
1543 | ||
dd1a3034 | 1544 | g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<std::unordered_map<std::string, std::string>> vars) { |
7f29529f RG |
1545 | if (logger) { |
1546 | // avoids potentially-evaluated-expression warning with clang. | |
1547 | RemoteLoggerInterface& rl = *logger.get(); | |
1548 | if (typeid(rl) != typeid(RemoteLogger)) { | |
1549 | // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong. | |
1550 | throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction.")); | |
1551 | } | |
82a91ddf | 1552 | } |
312a09a6 RG |
1553 | |
1554 | std::string serverID; | |
af7afecf | 1555 | std::string ipEncryptKey; |
312a09a6 RG |
1556 | if (vars) { |
1557 | if (vars->count("serverID")) { | |
1558 | serverID = boost::get<std::string>((*vars)["serverID"]); | |
1559 | } | |
af7afecf RG |
1560 | if (vars->count("ipEncryptKey")) { |
1561 | ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]); | |
1562 | } | |
312a09a6 RG |
1563 | } |
1564 | ||
6bb38cd6 | 1565 | #ifdef HAVE_PROTOBUF |
af7afecf | 1566 | return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey)); |
6bb38cd6 RG |
1567 | #else |
1568 | throw std::runtime_error("Protobuf support is required to use RemoteLogAction"); | |
1569 | #endif | |
1570 | }); | |
1571 | ||
dd1a3034 | 1572 | g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<std::unordered_map<std::string, std::string>> vars) { |
7f29529f RG |
1573 | if (logger) { |
1574 | // avoids potentially-evaluated-expression warning with clang. | |
1575 | RemoteLoggerInterface& rl = *logger.get(); | |
1576 | if (typeid(rl) != typeid(RemoteLogger)) { | |
1577 | // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong. | |
1578 | throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction."); | |
1579 | } | |
82a91ddf | 1580 | } |
312a09a6 RG |
1581 | |
1582 | std::string serverID; | |
af7afecf | 1583 | std::string ipEncryptKey; |
312a09a6 RG |
1584 | if (vars) { |
1585 | if (vars->count("serverID")) { | |
1586 | serverID = boost::get<std::string>((*vars)["serverID"]); | |
1587 | } | |
af7afecf RG |
1588 | if (vars->count("ipEncryptKey")) { |
1589 | ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]); | |
1590 | } | |
312a09a6 RG |
1591 | } |
1592 | ||
6bb38cd6 | 1593 | #ifdef HAVE_PROTOBUF |
af7afecf | 1594 | return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false)); |
6bb38cd6 RG |
1595 | #else |
1596 | throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction"); | |
1597 | #endif | |
1598 | }); | |
1599 | ||
dd1a3034 | 1600 | g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) { |
82a91ddf CH |
1601 | #ifdef HAVE_PROTOBUF |
1602 | return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc)); | |
1603 | #else | |
1604 | throw std::runtime_error("Protobuf support is required to use DnstapLogAction"); | |
1605 | #endif | |
1606 | }); | |
1607 | ||
dd1a3034 | 1608 | g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) { |
82a91ddf CH |
1609 | #ifdef HAVE_PROTOBUF |
1610 | return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc)); | |
1611 | #else | |
1612 | throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction"); | |
1613 | #endif | |
1614 | }); | |
1615 | ||
6bb38cd6 RG |
1616 | g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) { |
1617 | return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false)); | |
1618 | }); | |
1619 | ||
1620 | g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) { | |
1621 | return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength)); | |
1622 | }); | |
1623 | ||
1624 | g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) { | |
1625 | return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride)); | |
1626 | }); | |
1627 | ||
1628 | g_lua.writeFunction("DisableECSAction", []() { | |
1629 | return std::shared_ptr<DNSAction>(new DisableECSAction()); | |
1630 | }); | |
1631 | ||
bd14f087 RG |
1632 | g_lua.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) { |
1633 | if (v6) { | |
1634 | return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6))); | |
1635 | } | |
1636 | return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4))); | |
1637 | }); | |
1638 | ||
6bb38cd6 RG |
1639 | g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) { |
1640 | #ifdef HAVE_NET_SNMP | |
1641 | return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : "")); | |
1642 | #else | |
1643 | throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()"); | |
1644 | #endif /* HAVE_NET_SNMP */ | |
1645 | }); | |
1646 | ||
1647 | g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) { | |
1648 | #ifdef HAVE_NET_SNMP | |
1649 | return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : "")); | |
1650 | #else | |
1651 | throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()"); | |
1652 | #endif /* HAVE_NET_SNMP */ | |
1653 | }); | |
1654 | ||
1655 | g_lua.writeFunction("TagAction", [](std::string tag, std::string value) { | |
1656 | return std::shared_ptr<DNSAction>(new TagAction(tag, value)); | |
1657 | }); | |
1658 | ||
1659 | g_lua.writeFunction("TagResponseAction", [](std::string tag, std::string value) { | |
1660 | return std::shared_ptr<DNSResponseAction>(new TagResponseAction(tag, value)); | |
1661 | }); | |
2a28db86 RG |
1662 | |
1663 | g_lua.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) { | |
1664 | return std::shared_ptr<DNSAction>(new ContinueAction(action)); | |
1665 | }); | |
13c1fc12 RG |
1666 | |
1667 | #ifdef HAVE_DNS_OVER_HTTPS | |
d545a872 RG |
1668 | g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) { |
1669 | auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : "")); | |
1670 | auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret); | |
1671 | parseResponseConfig(vars, hsa->d_responseConfig); | |
1672 | return ret; | |
13c1fc12 RG |
1673 | }); |
1674 | #endif /* HAVE_DNS_OVER_HTTPS */ | |
f441962a RG |
1675 | |
1676 | g_lua.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) { | |
1677 | return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag)); | |
1678 | }); | |
af9f750c RG |
1679 | |
1680 | g_lua.writeFunction("SetNegativeAndSOAAction", [](bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) { | |
1681 | return std::shared_ptr<DNSAction>(new SetNegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum)); | |
1682 | }); | |
6bb38cd6 | 1683 | } |