]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-lua-actions.cc
Merge pull request #8411 from rgacogne/dnsdist-better-log-action
[thirdparty/pdns.git] / pdns / dnsdist-lua-actions.cc
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 */
22 #include "config.h"
23 #include "threadname.hh"
24 #include "dnsdist.hh"
25 #include "dnsdist-ecs.hh"
26 #include "dnsdist-lua.hh"
27 #include "dnsdist-protobuf.hh"
28 #include "dnsdist-kvs.hh"
29
30 #include "dolog.hh"
31 #include "dnstap.hh"
32 #include "ednsoptions.hh"
33 #include "fstrm_logger.hh"
34 #include "remote_logger.hh"
35
36 #include <boost/optional/optional_io.hpp>
37
38 #ifdef HAVE_LIBCRYPTO
39 #include "ipcipher.hh"
40 #endif /* HAVE_LIBCRYPTO */
41
42 class DropAction : public DNSAction
43 {
44 public:
45 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
46 {
47 return Action::Drop;
48 }
49 std::string toString() const override
50 {
51 return "drop";
52 }
53 };
54
55 class AllowAction : public DNSAction
56 {
57 public:
58 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
59 {
60 return Action::Allow;
61 }
62 std::string toString() const override
63 {
64 return "allow";
65 }
66 };
67
68 class NoneAction : public DNSAction
69 {
70 public:
71 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
72 {
73 return Action::None;
74 }
75 std::string toString() const override
76 {
77 return "no op";
78 }
79 };
80
81 class QPSAction : public DNSAction
82 {
83 public:
84 QPSAction(int limit) : d_qps(limit, limit)
85 {}
86 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
87 {
88 if(d_qps.check())
89 return Action::None;
90 else
91 return Action::Drop;
92 }
93 std::string toString() const override
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 {}
106 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
107 {
108 *ruleresult=std::to_string(d_msec);
109 return Action::Delay;
110 }
111 std::string toString() const override
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;
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;
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
166 DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
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
183 std::string newECSOption;
184 generateECSOption(dq->ecsSet ? dq->ecs.getNetwork() : *dq->remote, newECSOption, dq->ecsSet ? dq->ecs.getBits() : dq->ecsPrefixLength);
185
186 if (!handleEDNSClientSubnet(const_cast<char*>(query.c_str()), query.capacity(), dq->qname->wirelength(), &len, &ednsAdded, &ecsAdded, dq->ecsOverride, newECSOption, g_preserveTrailingData)) {
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
202 std::string TeeAction::toString() const
203 {
204 return "tee to "+d_remote.toStringWithPort();
205 }
206
207 std::map<std::string,double> TeeAction::getStats() const
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 {
224 setThreadName("dnsdist/TeeWork");
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) {}
263 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
264 {
265 *ruleresult=d_pool;
266 return Action::Pool;
267 }
268 std::string toString() const override
269 {
270 return "to pool "+d_pool;
271 }
272
273 private:
274 std::string d_pool;
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) {}
282 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
283 {
284 if(d_qps.check()) {
285 *ruleresult=d_pool;
286 return Action::Pool;
287 }
288 else
289 return Action::None;
290 }
291 std::string toString() const override
292 {
293 return "max " +std::to_string(d_qps.getRate())+" to pool "+d_pool;
294 }
295
296 private:
297 QPSLimiter d_qps;
298 std::string d_pool;
299 };
300
301 class RCodeAction : public DNSAction
302 {
303 public:
304 RCodeAction(uint8_t rcode) : d_rcode(rcode) {}
305 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
306 {
307 dq->dh->rcode = d_rcode;
308 dq->dh->qr = true; // for good measure
309 return Action::HeaderModify;
310 }
311 std::string toString() const override
312 {
313 return "set rcode "+std::to_string(d_rcode);
314 }
315
316 private:
317 uint8_t d_rcode;
318 };
319
320 class ERCodeAction : public DNSAction
321 {
322 public:
323 ERCodeAction(uint8_t rcode) : d_rcode(rcode) {}
324 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
325 {
326 dq->dh->rcode = (d_rcode & 0xF);
327 dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4);
328 dq->dh->qr = true; // for good measure
329 return Action::HeaderModify;
330 }
331 std::string toString() const override
332 {
333 return "set ercode "+ERCode::to_s(d_rcode);
334 }
335
336 private:
337 uint8_t d_rcode;
338 };
339
340 class TCAction : public DNSAction
341 {
342 public:
343 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
344 {
345 return Action::Truncate;
346 }
347 std::string toString() const override
348 {
349 return "tc=1 answer";
350 }
351 };
352
353 DNSAction::Action LuaAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
354 {
355 std::lock_guard<std::mutex> lock(g_luamutex);
356 try {
357 auto ret = d_func(dq);
358 if (ruleresult) {
359 if (boost::optional<std::string> rule = std::get<1>(ret)) {
360 *ruleresult = *rule;
361 }
362 else {
363 // default to empty string
364 ruleresult->clear();
365 }
366 }
367 return (Action)std::get<0>(ret);
368 } catch (std::exception &e) {
369 warnlog("LuaAction failed inside lua, returning ServFail: %s", e.what());
370 } catch (...) {
371 warnlog("LuaAction failed inside lua, returning ServFail: [unknown exception]");
372 }
373 return DNSAction::Action::ServFail;
374 }
375
376 DNSResponseAction::Action LuaResponseAction::operator()(DNSResponse* dr, std::string* ruleresult) const
377 {
378 std::lock_guard<std::mutex> lock(g_luamutex);
379 try {
380 auto ret = d_func(dr);
381 if(ruleresult) {
382 if (boost::optional<std::string> rule = std::get<1>(ret)) {
383 *ruleresult = *rule;
384 }
385 else {
386 // default to empty string
387 ruleresult->clear();
388 }
389 }
390 return (Action)std::get<0>(ret);
391 } catch (std::exception &e) {
392 warnlog("LuaResponseAction failed inside lua, returning ServFail: %s", e.what());
393 } catch (...) {
394 warnlog("LuaResponseAction failed inside lua, returning ServFail: [unknown exception]");
395 }
396 return DNSResponseAction::Action::ServFail;
397 }
398
399 DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
400 {
401 uint16_t qtype = dq->qtype;
402 // do we even have a response?
403 if(d_cname.empty() && !std::count_if(d_addrs.begin(), d_addrs.end(), [qtype](const ComboAddress& a)
404 {
405 return (qtype == QType::ANY || ((a.sin4.sin_family == AF_INET && qtype == QType::A) ||
406 (a.sin4.sin_family == AF_INET6 && qtype == QType::AAAA)));
407 }))
408 return Action::None;
409
410 vector<ComboAddress> addrs;
411 unsigned int totrdatalen=0;
412 if (!d_cname.empty()) {
413 qtype = QType::CNAME;
414 totrdatalen += d_cname.toDNSString().size();
415 } else {
416 for(const auto& addr : d_addrs) {
417 if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) ||
418 (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
419 continue;
420 }
421 totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
422 addrs.push_back(addr);
423 }
424 }
425
426 if(addrs.size() > 1)
427 random_shuffle(addrs.begin(), addrs.end());
428
429 unsigned int consumed=0;
430 DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed);
431
432 if (dq->size < (sizeof(dnsheader) + consumed + 4 + ((d_cname.empty() ? 0 : 1) + addrs.size())*12 /* recordstart */ + totrdatalen)) {
433 return Action::None;
434 }
435
436 bool dnssecOK = false;
437 bool hadEDNS = false;
438 if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) {
439 hadEDNS = true;
440 dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO;
441 }
442
443 dq->len = sizeof(dnsheader) + consumed + 4; // there goes your EDNS
444 char* dest = ((char*)dq->dh) + dq->len;
445
446 dq->dh->qr = true; // for good measure
447 dq->dh->ra = dq->dh->rd; // for good measure
448 dq->dh->ad = false;
449 dq->dh->ancount = 0;
450 dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
451
452 if(qtype == QType::CNAME) {
453 std::string wireData = d_cname.toDNSString(); // Note! This doesn't do compression!
454 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
455 0, (unsigned char) qtype,
456 0, QClass::IN, // IN
457 0, 0, 0, 60, // TTL
458 0, (unsigned char)wireData.length()};
459 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
460
461 memcpy(dest, recordstart, sizeof(recordstart));
462 dest += sizeof(recordstart);
463 memcpy(dest, wireData.c_str(), wireData.length());
464 dq->len += wireData.length() + sizeof(recordstart);
465 dq->dh->ancount++;
466 }
467 else {
468 for(const auto& addr : addrs) {
469 unsigned char rdatalen = addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
470 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
471 0, (unsigned char) (addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA),
472 0, QClass::IN, // IN
473 0, 0, 0, 60, // TTL
474 0, rdatalen};
475 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
476
477 memcpy(dest, recordstart, sizeof(recordstart));
478 dest += sizeof(recordstart);
479
480 memcpy(dest,
481 addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr,
482 rdatalen);
483 dest += rdatalen;
484 dq->len += rdatalen + sizeof(recordstart);
485 dq->dh->ancount++;
486 }
487 }
488
489 dq->dh->ancount = htons(dq->dh->ancount);
490
491 if (hadEDNS) {
492 addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
493 }
494
495 return Action::HeaderModify;
496 }
497
498 class MacAddrAction : public DNSAction
499 {
500 public:
501 MacAddrAction(uint16_t code) : d_code(code)
502 {}
503 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
504 {
505 if(dq->dh->arcount)
506 return Action::None;
507
508 std::string mac = getMACAddress(*dq->remote);
509 if(mac.empty())
510 return Action::None;
511
512 std::string optRData;
513 generateEDNSOption(d_code, mac, optRData);
514
515 std::string res;
516 generateOptRR(optRData, res, g_EdnsUDPPayloadSize, 0, false);
517
518 if ((dq->size - dq->len) < res.length())
519 return Action::None;
520
521 dq->dh->arcount = htons(1);
522 char* dest = ((char*)dq->dh) + dq->len;
523 memcpy(dest, res.c_str(), res.length());
524 dq->len += res.length();
525
526 return Action::None;
527 }
528 std::string toString() const override
529 {
530 return "add EDNS MAC (code="+std::to_string(d_code)+")";
531 }
532 private:
533 uint16_t d_code{3};
534 };
535
536 class NoRecurseAction : public DNSAction
537 {
538 public:
539 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
540 {
541 dq->dh->rd = false;
542 return Action::None;
543 }
544 std::string toString() const override
545 {
546 return "set rd=0";
547 }
548 };
549
550 class LogAction : public DNSAction, public boost::noncopyable
551 {
552 public:
553 LogAction(): d_fp(nullptr, fclose)
554 {
555 }
556
557 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)
558 {
559 if(str.empty())
560 return;
561 if(append)
562 d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "a+"), fclose);
563 else
564 d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "w"), fclose);
565 if(!d_fp)
566 throw std::runtime_error("Unable to open file '"+str+"' for logging: "+stringerror());
567 if(!buffered)
568 setbuf(d_fp.get(), 0);
569 }
570
571 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
572 {
573 if (!d_fp) {
574 if (!d_verboseOnly || g_verbose) {
575 if (d_includeTimestamp) {
576 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);
577 }
578 else {
579 infolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
580 }
581 }
582 }
583 else {
584 if (d_binary) {
585 std::string out = dq->qname->toDNSString();
586 if (d_includeTimestamp) {
587 uint64_t tv_sec = static_cast<uint64_t>(dq->queryTime->tv_sec);
588 uint32_t tv_nsec = static_cast<uint32_t>(dq->queryTime->tv_nsec);
589 fwrite(&tv_sec, sizeof(tv_sec), 1, d_fp.get());
590 fwrite(&tv_nsec, sizeof(tv_nsec), 1, d_fp.get());
591 }
592 uint16_t id = dq->dh->id;
593 fwrite(&id, sizeof(id), 1, d_fp.get());
594 fwrite(out.c_str(), 1, out.size(), d_fp.get());
595 fwrite(&dq->qtype, sizeof(dq->qtype), 1, d_fp.get());
596 fwrite(&dq->remote->sin4.sin_family, sizeof(dq->remote->sin4.sin_family), 1, d_fp.get());
597 if (dq->remote->sin4.sin_family == AF_INET) {
598 fwrite(&dq->remote->sin4.sin_addr.s_addr, sizeof(dq->remote->sin4.sin_addr.s_addr), 1, d_fp.get());
599 }
600 else if (dq->remote->sin4.sin_family == AF_INET6) {
601 fwrite(&dq->remote->sin6.sin6_addr.s6_addr, sizeof(dq->remote->sin6.sin6_addr.s6_addr), 1, d_fp.get());
602 }
603 fwrite(&dq->remote->sin4.sin_port, sizeof(dq->remote->sin4.sin_port), 1, d_fp.get());
604 }
605 else {
606 if (d_includeTimestamp) {
607 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);
608 }
609 else {
610 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);
611 }
612 }
613 }
614 return Action::None;
615 }
616
617 std::string toString() const override
618 {
619 if (!d_fname.empty()) {
620 return "log to " + d_fname;
621 }
622 return "log";
623 }
624 private:
625 std::string d_fname;
626 std::unique_ptr<FILE, int(*)(FILE*)> d_fp{nullptr, fclose};
627 bool d_binary{true};
628 bool d_verboseOnly{true};
629 bool d_includeTimestamp{false};
630 };
631
632
633 class DisableValidationAction : public DNSAction
634 {
635 public:
636 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
637 {
638 dq->dh->cd = true;
639 return Action::None;
640 }
641 std::string toString() const override
642 {
643 return "set cd=1";
644 }
645 };
646
647 class SkipCacheAction : public DNSAction
648 {
649 public:
650 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
651 {
652 dq->skipCache = true;
653 return Action::None;
654 }
655 std::string toString() const override
656 {
657 return "skip cache";
658 }
659 };
660
661 class TempFailureCacheTTLAction : public DNSAction
662 {
663 public:
664 TempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl)
665 {}
666 TempFailureCacheTTLAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
667 {
668 dq->tempFailureTTL = d_ttl;
669 return Action::None;
670 }
671 std::string toString() const override
672 {
673 return "set tempfailure cache ttl to "+std::to_string(d_ttl);
674 }
675 private:
676 uint32_t d_ttl;
677 };
678
679 class ECSPrefixLengthAction : public DNSAction
680 {
681 public:
682 ECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
683 {
684 }
685 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
686 {
687 dq->ecsPrefixLength = dq->remote->sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
688 return Action::None;
689 }
690 std::string toString() const override
691 {
692 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength);
693 }
694 private:
695 uint16_t d_v4PrefixLength;
696 uint16_t d_v6PrefixLength;
697 };
698
699 class ECSOverrideAction : public DNSAction
700 {
701 public:
702 ECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride)
703 {
704 }
705 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
706 {
707 dq->ecsOverride = d_ecsOverride;
708 return Action::None;
709 }
710 std::string toString() const override
711 {
712 return "set ECS override to " + std::to_string(d_ecsOverride);
713 }
714 private:
715 bool d_ecsOverride;
716 };
717
718
719 class DisableECSAction : public DNSAction
720 {
721 public:
722 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
723 {
724 dq->useECS = false;
725 return Action::None;
726 }
727 std::string toString() const override
728 {
729 return "disable ECS";
730 }
731 };
732
733 class SetECSAction : public DNSAction
734 {
735 public:
736 SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false)
737 {
738 }
739
740 SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true)
741 {
742 }
743
744 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
745 {
746 dq->ecsSet = true;
747
748 if (d_hasV6) {
749 dq->ecs = dq->remote->isIPv4() ? d_v4 : d_v6;
750 }
751 else {
752 dq->ecs = d_v4;
753 }
754
755 return Action::None;
756 }
757
758 std::string toString() const override
759 {
760 std::string result = "set ECS to " + d_v4.toString();
761 if (d_hasV6) {
762 result += " / " + d_v6.toString();
763 }
764 return result;
765 }
766
767 private:
768 Netmask d_v4;
769 Netmask d_v6;
770 bool d_hasV6;
771 };
772
773
774 class DnstapLogAction : public DNSAction, public boost::noncopyable
775 {
776 public:
777 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)
778 {
779 }
780 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
781 {
782 #ifdef HAVE_PROTOBUF
783 DnstapMessage message(d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
784 {
785 if (d_alterFunc) {
786 std::lock_guard<std::mutex> lock(g_luamutex);
787 (*d_alterFunc)(dq, &message);
788 }
789 }
790 std::string data;
791 message.serialize(data);
792 d_logger->queueData(data);
793 #endif /* HAVE_PROTOBUF */
794 return Action::None;
795 }
796 std::string toString() const override
797 {
798 return "remote log as dnstap to " + (d_logger ? d_logger->toString() : "");
799 }
800 private:
801 std::string d_identity;
802 std::shared_ptr<RemoteLoggerInterface> d_logger;
803 boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > d_alterFunc;
804 };
805
806 class RemoteLogAction : public DNSAction, public boost::noncopyable
807 {
808 public:
809 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)
810 {
811 }
812 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
813 {
814 #ifdef HAVE_PROTOBUF
815 if (!dq->uniqueId) {
816 dq->uniqueId = getUniqueID();
817 }
818
819 DNSDistProtoBufMessage message(*dq);
820 if (!d_serverID.empty()) {
821 message.setServerIdentity(d_serverID);
822 }
823
824 #if HAVE_LIBCRYPTO
825 if (!d_ipEncryptKey.empty())
826 {
827 message.setRequestor(encryptCA(*dq->remote, d_ipEncryptKey));
828 }
829 #endif /* HAVE_LIBCRYPTO */
830
831 if (d_alterFunc) {
832 std::lock_guard<std::mutex> lock(g_luamutex);
833 (*d_alterFunc)(dq, &message);
834 }
835
836 std::string data;
837 message.serialize(data);
838 d_logger->queueData(data);
839 #endif /* HAVE_PROTOBUF */
840 return Action::None;
841 }
842 std::string toString() const override
843 {
844 return "remote log to " + (d_logger ? d_logger->toString() : "");
845 }
846 private:
847 std::shared_ptr<RemoteLoggerInterface> d_logger;
848 boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc;
849 std::string d_serverID;
850 std::string d_ipEncryptKey;
851 };
852
853 class SNMPTrapAction : public DNSAction
854 {
855 public:
856 SNMPTrapAction(const std::string& reason): d_reason(reason)
857 {
858 }
859 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
860 {
861 if (g_snmpAgent && g_snmpTrapsEnabled) {
862 g_snmpAgent->sendDNSTrap(*dq, d_reason);
863 }
864
865 return Action::None;
866 }
867 std::string toString() const override
868 {
869 return "send SNMP trap";
870 }
871 private:
872 std::string d_reason;
873 };
874
875 class TagAction : public DNSAction
876 {
877 public:
878 TagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
879 {
880 }
881 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
882 {
883 if (!dq->qTag) {
884 dq->qTag = std::make_shared<QTag>();
885 }
886
887 dq->qTag->insert({d_tag, d_value});
888
889 return Action::None;
890 }
891 std::string toString() const override
892 {
893 return "set tag '" + d_tag + "' to value '" + d_value + "'";
894 }
895 private:
896 std::string d_tag;
897 std::string d_value;
898 };
899
900 class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable
901 {
902 public:
903 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)
904 {
905 }
906 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
907 {
908 #ifdef HAVE_PROTOBUF
909 struct timespec now;
910 gettime(&now, true);
911 DnstapMessage message(d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
912 {
913 if (d_alterFunc) {
914 std::lock_guard<std::mutex> lock(g_luamutex);
915 (*d_alterFunc)(dr, &message);
916 }
917 }
918 std::string data;
919 message.serialize(data);
920 d_logger->queueData(data);
921 #endif /* HAVE_PROTOBUF */
922 return Action::None;
923 }
924 std::string toString() const override
925 {
926 return "log response as dnstap to " + (d_logger ? d_logger->toString() : "");
927 }
928 private:
929 std::string d_identity;
930 std::shared_ptr<RemoteLoggerInterface> d_logger;
931 boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > d_alterFunc;
932 };
933
934 class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
935 {
936 public:
937 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)
938 {
939 }
940 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
941 {
942 #ifdef HAVE_PROTOBUF
943 if (!dr->uniqueId) {
944 dr->uniqueId = getUniqueID();
945 }
946
947 DNSDistProtoBufMessage message(*dr, d_includeCNAME);
948 if (!d_serverID.empty()) {
949 message.setServerIdentity(d_serverID);
950 }
951
952 #if HAVE_LIBCRYPTO
953 if (!d_ipEncryptKey.empty())
954 {
955 message.setRequestor(encryptCA(*dr->remote, d_ipEncryptKey));
956 }
957 #endif /* HAVE_LIBCRYPTO */
958
959 if (d_alterFunc) {
960 std::lock_guard<std::mutex> lock(g_luamutex);
961 (*d_alterFunc)(dr, &message);
962 }
963
964 std::string data;
965 message.serialize(data);
966 d_logger->queueData(data);
967 #endif /* HAVE_PROTOBUF */
968 return Action::None;
969 }
970 std::string toString() const override
971 {
972 return "remote log response to " + (d_logger ? d_logger->toString() : "");
973 }
974 private:
975 std::shared_ptr<RemoteLoggerInterface> d_logger;
976 boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc;
977 std::string d_serverID;
978 std::string d_ipEncryptKey;
979 bool d_includeCNAME;
980 };
981
982 class DropResponseAction : public DNSResponseAction
983 {
984 public:
985 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
986 {
987 return Action::Drop;
988 }
989 std::string toString() const override
990 {
991 return "drop";
992 }
993 };
994
995 class AllowResponseAction : public DNSResponseAction
996 {
997 public:
998 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
999 {
1000 return Action::Allow;
1001 }
1002 std::string toString() const override
1003 {
1004 return "allow";
1005 }
1006 };
1007
1008 class DelayResponseAction : public DNSResponseAction
1009 {
1010 public:
1011 DelayResponseAction(int msec) : d_msec(msec)
1012 {}
1013 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1014 {
1015 *ruleresult=std::to_string(d_msec);
1016 return Action::Delay;
1017 }
1018 std::string toString() const override
1019 {
1020 return "delay by "+std::to_string(d_msec)+ " msec";
1021 }
1022 private:
1023 int d_msec;
1024 };
1025
1026 class SNMPTrapResponseAction : public DNSResponseAction
1027 {
1028 public:
1029 SNMPTrapResponseAction(const std::string& reason): d_reason(reason)
1030 {
1031 }
1032 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1033 {
1034 if (g_snmpAgent && g_snmpTrapsEnabled) {
1035 g_snmpAgent->sendDNSTrap(*dr, d_reason);
1036 }
1037
1038 return Action::None;
1039 }
1040 std::string toString() const override
1041 {
1042 return "send SNMP trap";
1043 }
1044 private:
1045 std::string d_reason;
1046 };
1047
1048 class TagResponseAction : public DNSResponseAction
1049 {
1050 public:
1051 TagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
1052 {
1053 }
1054 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1055 {
1056 if (!dr->qTag) {
1057 dr->qTag = std::make_shared<QTag>();
1058 }
1059
1060 dr->qTag->insert({d_tag, d_value});
1061
1062 return Action::None;
1063 }
1064 std::string toString() const override
1065 {
1066 return "set tag '" + d_tag + "' to value '" + d_value + "'";
1067 }
1068 private:
1069 std::string d_tag;
1070 std::string d_value;
1071 };
1072
1073 class ContinueAction : public DNSAction
1074 {
1075 public:
1076 ContinueAction(std::shared_ptr<DNSAction>& action): d_action(action)
1077 {
1078 }
1079
1080 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1081 {
1082 if (d_action) {
1083 /* call the action */
1084 auto action = (*d_action)(dq, ruleresult);
1085 bool drop = false;
1086 /* apply the changes if needed (pool selection, flags, etc */
1087 processRulesResult(action, *dq, *ruleresult, drop);
1088 }
1089
1090 /* but ignore the resulting action no matter what */
1091 return Action::None;
1092 }
1093
1094 std::string toString() const override
1095 {
1096 if (d_action) {
1097 return "continue after: " + (d_action ? d_action->toString() : "");
1098 }
1099 else {
1100 return "no op";
1101 }
1102 }
1103
1104 private:
1105 std::shared_ptr<DNSAction> d_action;
1106 };
1107
1108 #ifdef HAVE_DNS_OVER_HTTPS
1109 class HTTPStatusAction: public DNSAction
1110 {
1111 public:
1112 HTTPStatusAction(int code, const std::string& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
1113 {
1114 }
1115
1116 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1117 {
1118 if (!dq->du) {
1119 return Action::None;
1120 }
1121
1122 dq->du->setHTTPResponse(d_code, d_body, d_contentType);
1123 dq->dh->qr = true; // for good measure
1124 return Action::HeaderModify;
1125 }
1126
1127 std::string toString() const override
1128 {
1129 return "return an HTTP status of " + std::to_string(d_code);
1130 }
1131 private:
1132 std::string d_body;
1133 std::string d_contentType;
1134 int d_code;
1135 };
1136 #endif /* HAVE_DNS_OVER_HTTPS */
1137
1138 class KeyValueStoreLookupAction : public DNSAction
1139 {
1140 public:
1141 KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag)
1142 {
1143 }
1144
1145 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1146 {
1147 std::vector<std::string> keys = d_key->getKeys(*dq);
1148 std::string result;
1149 for (const auto& key : keys) {
1150 if (d_kvs->getValue(key, result) == true) {
1151 break;
1152 }
1153 }
1154
1155 if (!dq->qTag) {
1156 dq->qTag = std::make_shared<QTag>();
1157 }
1158
1159 dq->qTag->insert({d_tag, std::move(result)});
1160
1161 return Action::None;
1162 }
1163
1164 std::string toString() const override
1165 {
1166 return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'";
1167 }
1168
1169 private:
1170 std::shared_ptr<KeyValueStore> d_kvs;
1171 std::shared_ptr<KeyValueLookupKey> d_key;
1172 std::string d_tag;
1173 };
1174
1175 template<typename T, typename ActionT>
1176 static void addAction(GlobalStateHolder<vector<T> > *someRulActions, luadnsrule_t var, std::shared_ptr<ActionT> action, boost::optional<luaruleparams_t> params) {
1177 setLuaSideEffect();
1178
1179 boost::uuids::uuid uuid;
1180 uint64_t creationOrder;
1181 parseRuleParams(params, uuid, creationOrder);
1182
1183 auto rule=makeRule(var);
1184 someRulActions->modify([rule, action, uuid, creationOrder](vector<T>& rulactions){
1185 rulactions.push_back({rule, action, uuid, creationOrder});
1186 });
1187 }
1188
1189 void setupLuaActions()
1190 {
1191 g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
1192 boost::uuids::uuid uuid;
1193 uint64_t creationOrder;
1194 parseRuleParams(params, uuid, creationOrder);
1195
1196 auto rule=makeRule(dnsrule);
1197 DNSDistRuleAction ra({rule, action, uuid, creationOrder});
1198 return std::make_shared<DNSDistRuleAction>(ra);
1199 });
1200
1201 g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1202 if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
1203 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
1204 }
1205
1206 addAction(&g_rulactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
1207 });
1208
1209 g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1210 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1211 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1212 }
1213
1214 addAction(&g_resprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1215 });
1216
1217 g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1218 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1219 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1220 }
1221
1222 addAction(&g_cachehitresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1223 });
1224
1225 g_lua.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1226 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1227 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1228 }
1229
1230 addAction(&g_selfansweredresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1231 });
1232
1233 g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) {
1234 setLuaNoSideEffect();
1235 auto stats = ta.getStats();
1236 for(const auto& s : stats) {
1237 g_outputBuffer+=s.first+"\t";
1238 if((uint64_t)s.second == s.second)
1239 g_outputBuffer += std::to_string((uint64_t)s.second)+"\n";
1240 else
1241 g_outputBuffer += std::to_string(s.second)+"\n";
1242 }
1243 });
1244
1245 g_lua.writeFunction("getAction", [](unsigned int num) {
1246 setLuaNoSideEffect();
1247 boost::optional<std::shared_ptr<DNSAction>> ret;
1248 auto rulactions = g_rulactions.getCopy();
1249 if(num < rulactions.size())
1250 ret=rulactions[num].d_action;
1251 return ret;
1252 });
1253
1254 g_lua.registerFunction("getStats", &DNSAction::getStats);
1255
1256 g_lua.writeFunction("LuaAction", [](LuaAction::func_t func) {
1257 setLuaSideEffect();
1258 return std::shared_ptr<DNSAction>(new LuaAction(func));
1259 });
1260
1261 g_lua.writeFunction("NoRecurseAction", []() {
1262 return std::shared_ptr<DNSAction>(new NoRecurseAction);
1263 });
1264
1265 g_lua.writeFunction("MacAddrAction", [](int code) {
1266 return std::shared_ptr<DNSAction>(new MacAddrAction(code));
1267 });
1268
1269 g_lua.writeFunction("PoolAction", [](const std::string& a) {
1270 return std::shared_ptr<DNSAction>(new PoolAction(a));
1271 });
1272
1273 g_lua.writeFunction("QPSAction", [](int limit) {
1274 return std::shared_ptr<DNSAction>(new QPSAction(limit));
1275 });
1276
1277 g_lua.writeFunction("QPSPoolAction", [](int limit, const std::string& a) {
1278 return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
1279 });
1280
1281 g_lua.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b ) {
1282 vector<ComboAddress> addrs;
1283 if(auto s = boost::get<std::string>(&inp))
1284 addrs.push_back(ComboAddress(*s));
1285 else {
1286 const auto& v = boost::get<vector<pair<int,std::string>>>(inp);
1287 for(const auto& a: v)
1288 addrs.push_back(ComboAddress(a.second));
1289 }
1290 if(b)
1291 addrs.push_back(ComboAddress(*b));
1292 return std::shared_ptr<DNSAction>(new SpoofAction(addrs));
1293 });
1294
1295 g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a) {
1296 return std::shared_ptr<DNSAction>(new SpoofAction(a));
1297 });
1298
1299 g_lua.writeFunction("DropAction", []() {
1300 return std::shared_ptr<DNSAction>(new DropAction);
1301 });
1302
1303 g_lua.writeFunction("AllowAction", []() {
1304 return std::shared_ptr<DNSAction>(new AllowAction);
1305 });
1306
1307 g_lua.writeFunction("NoneAction", []() {
1308 return std::shared_ptr<DNSAction>(new NoneAction);
1309 });
1310
1311 g_lua.writeFunction("DelayAction", [](int msec) {
1312 return std::shared_ptr<DNSAction>(new DelayAction(msec));
1313 });
1314
1315 g_lua.writeFunction("TCAction", []() {
1316 return std::shared_ptr<DNSAction>(new TCAction);
1317 });
1318
1319 g_lua.writeFunction("DisableValidationAction", []() {
1320 return std::shared_ptr<DNSAction>(new DisableValidationAction);
1321 });
1322
1323 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) {
1324 return std::shared_ptr<DNSAction>(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
1325 });
1326
1327 g_lua.writeFunction("RCodeAction", [](uint8_t rcode) {
1328 return std::shared_ptr<DNSAction>(new RCodeAction(rcode));
1329 });
1330
1331 g_lua.writeFunction("ERCodeAction", [](uint8_t rcode) {
1332 return std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
1333 });
1334
1335 g_lua.writeFunction("SkipCacheAction", []() {
1336 return std::shared_ptr<DNSAction>(new SkipCacheAction);
1337 });
1338
1339 g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
1340 return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
1341 });
1342
1343 g_lua.writeFunction("DropResponseAction", []() {
1344 return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
1345 });
1346
1347 g_lua.writeFunction("AllowResponseAction", []() {
1348 return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
1349 });
1350
1351 g_lua.writeFunction("DelayResponseAction", [](int msec) {
1352 return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
1353 });
1354
1355 g_lua.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
1356 setLuaSideEffect();
1357 return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
1358 });
1359
1360 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) {
1361 if (logger) {
1362 // avoids potentially-evaluated-expression warning with clang.
1363 RemoteLoggerInterface& rl = *logger.get();
1364 if (typeid(rl) != typeid(RemoteLogger)) {
1365 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1366 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1367 }
1368 }
1369
1370 std::string serverID;
1371 std::string ipEncryptKey;
1372 if (vars) {
1373 if (vars->count("serverID")) {
1374 serverID = boost::get<std::string>((*vars)["serverID"]);
1375 }
1376 if (vars->count("ipEncryptKey")) {
1377 ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]);
1378 }
1379 }
1380
1381 #ifdef HAVE_PROTOBUF
1382 return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey));
1383 #else
1384 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1385 #endif
1386 });
1387
1388 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) {
1389 if (logger) {
1390 // avoids potentially-evaluated-expression warning with clang.
1391 RemoteLoggerInterface& rl = *logger.get();
1392 if (typeid(rl) != typeid(RemoteLogger)) {
1393 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1394 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
1395 }
1396 }
1397
1398 std::string serverID;
1399 std::string ipEncryptKey;
1400 if (vars) {
1401 if (vars->count("serverID")) {
1402 serverID = boost::get<std::string>((*vars)["serverID"]);
1403 }
1404 if (vars->count("ipEncryptKey")) {
1405 ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]);
1406 }
1407 }
1408
1409 #ifdef HAVE_PROTOBUF
1410 return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false));
1411 #else
1412 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1413 #endif
1414 });
1415
1416 g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
1417 #ifdef HAVE_PROTOBUF
1418 return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
1419 #else
1420 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1421 #endif
1422 });
1423
1424 g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
1425 #ifdef HAVE_PROTOBUF
1426 return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
1427 #else
1428 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1429 #endif
1430 });
1431
1432 g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
1433 return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false));
1434 });
1435
1436 g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
1437 return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
1438 });
1439
1440 g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
1441 return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride));
1442 });
1443
1444 g_lua.writeFunction("DisableECSAction", []() {
1445 return std::shared_ptr<DNSAction>(new DisableECSAction());
1446 });
1447
1448 g_lua.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) {
1449 if (v6) {
1450 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6)));
1451 }
1452 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4)));
1453 });
1454
1455 g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
1456 #ifdef HAVE_NET_SNMP
1457 return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
1458 #else
1459 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1460 #endif /* HAVE_NET_SNMP */
1461 });
1462
1463 g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
1464 #ifdef HAVE_NET_SNMP
1465 return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
1466 #else
1467 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1468 #endif /* HAVE_NET_SNMP */
1469 });
1470
1471 g_lua.writeFunction("TagAction", [](std::string tag, std::string value) {
1472 return std::shared_ptr<DNSAction>(new TagAction(tag, value));
1473 });
1474
1475 g_lua.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
1476 return std::shared_ptr<DNSResponseAction>(new TagResponseAction(tag, value));
1477 });
1478
1479 g_lua.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
1480 return std::shared_ptr<DNSAction>(new ContinueAction(action));
1481 });
1482
1483 #ifdef HAVE_DNS_OVER_HTTPS
1484 g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType) {
1485 return std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
1486 });
1487 #endif /* HAVE_DNS_OVER_HTTPS */
1488
1489 g_lua.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
1490 return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
1491 });
1492 }