]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-lua-actions.cc
Merge pull request #7956 from pieterlexis/auth-dont-start-as-root
[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(0)
554 {
555 }
556 LogAction(const std::string& str, bool binary=true, bool append=false, bool buffered=true) : d_fname(str), d_binary(binary)
557 {
558 if(str.empty())
559 return;
560 if(append)
561 d_fp = fopen(str.c_str(), "a+");
562 else
563 d_fp = fopen(str.c_str(), "w");
564 if(!d_fp)
565 throw std::runtime_error("Unable to open file '"+str+"' for logging: "+stringerror());
566 if(!buffered)
567 setbuf(d_fp, 0);
568 }
569 ~LogAction() override
570 {
571 if(d_fp)
572 fclose(d_fp);
573 }
574 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
575 {
576 if(!d_fp) {
577 vinfolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
578 }
579 else {
580 if(d_binary) {
581 std::string out = dq->qname->toDNSString();
582 fwrite(out.c_str(), 1, out.size(), d_fp);
583 fwrite((void*)&dq->qtype, 1, 2, d_fp);
584 }
585 else {
586 fprintf(d_fp, "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);
587 }
588 }
589 return Action::None;
590 }
591 std::string toString() const override
592 {
593 if (!d_fname.empty()) {
594 return "log to " + d_fname;
595 }
596 return "log";
597 }
598 private:
599 std::string d_fname;
600 FILE* d_fp{0};
601 bool d_binary{true};
602 };
603
604
605 class DisableValidationAction : public DNSAction
606 {
607 public:
608 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
609 {
610 dq->dh->cd = true;
611 return Action::None;
612 }
613 std::string toString() const override
614 {
615 return "set cd=1";
616 }
617 };
618
619 class SkipCacheAction : public DNSAction
620 {
621 public:
622 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
623 {
624 dq->skipCache = true;
625 return Action::None;
626 }
627 std::string toString() const override
628 {
629 return "skip cache";
630 }
631 };
632
633 class TempFailureCacheTTLAction : public DNSAction
634 {
635 public:
636 TempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl)
637 {}
638 TempFailureCacheTTLAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
639 {
640 dq->tempFailureTTL = d_ttl;
641 return Action::None;
642 }
643 std::string toString() const override
644 {
645 return "set tempfailure cache ttl to "+std::to_string(d_ttl);
646 }
647 private:
648 uint32_t d_ttl;
649 };
650
651 class ECSPrefixLengthAction : public DNSAction
652 {
653 public:
654 ECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
655 {
656 }
657 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
658 {
659 dq->ecsPrefixLength = dq->remote->sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
660 return Action::None;
661 }
662 std::string toString() const override
663 {
664 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength);
665 }
666 private:
667 uint16_t d_v4PrefixLength;
668 uint16_t d_v6PrefixLength;
669 };
670
671 class ECSOverrideAction : public DNSAction
672 {
673 public:
674 ECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride)
675 {
676 }
677 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
678 {
679 dq->ecsOverride = d_ecsOverride;
680 return Action::None;
681 }
682 std::string toString() const override
683 {
684 return "set ECS override to " + std::to_string(d_ecsOverride);
685 }
686 private:
687 bool d_ecsOverride;
688 };
689
690
691 class DisableECSAction : public DNSAction
692 {
693 public:
694 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
695 {
696 dq->useECS = false;
697 return Action::None;
698 }
699 std::string toString() const override
700 {
701 return "disable ECS";
702 }
703 };
704
705 class SetECSAction : public DNSAction
706 {
707 public:
708 SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false)
709 {
710 }
711
712 SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true)
713 {
714 }
715
716 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
717 {
718 dq->ecsSet = true;
719
720 if (d_hasV6) {
721 dq->ecs = dq->remote->isIPv4() ? d_v4 : d_v6;
722 }
723 else {
724 dq->ecs = d_v4;
725 }
726
727 return Action::None;
728 }
729
730 std::string toString() const override
731 {
732 std::string result = "set ECS to " + d_v4.toString();
733 if (d_hasV6) {
734 result += " / " + d_v6.toString();
735 }
736 return result;
737 }
738
739 private:
740 Netmask d_v4;
741 Netmask d_v6;
742 bool d_hasV6;
743 };
744
745
746 class DnstapLogAction : public DNSAction, public boost::noncopyable
747 {
748 public:
749 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)
750 {
751 }
752 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
753 {
754 #ifdef HAVE_PROTOBUF
755 DnstapMessage message(d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
756 {
757 if (d_alterFunc) {
758 std::lock_guard<std::mutex> lock(g_luamutex);
759 (*d_alterFunc)(dq, &message);
760 }
761 }
762 std::string data;
763 message.serialize(data);
764 d_logger->queueData(data);
765 #endif /* HAVE_PROTOBUF */
766 return Action::None;
767 }
768 std::string toString() const override
769 {
770 return "remote log as dnstap to " + (d_logger ? d_logger->toString() : "");
771 }
772 private:
773 std::string d_identity;
774 std::shared_ptr<RemoteLoggerInterface> d_logger;
775 boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > d_alterFunc;
776 };
777
778 class RemoteLogAction : public DNSAction, public boost::noncopyable
779 {
780 public:
781 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)
782 {
783 }
784 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
785 {
786 #ifdef HAVE_PROTOBUF
787 if (!dq->uniqueId) {
788 dq->uniqueId = getUniqueID();
789 }
790
791 DNSDistProtoBufMessage message(*dq);
792 if (!d_serverID.empty()) {
793 message.setServerIdentity(d_serverID);
794 }
795
796 #if HAVE_LIBCRYPTO
797 if (!d_ipEncryptKey.empty())
798 {
799 message.setRequestor(encryptCA(*dq->remote, d_ipEncryptKey));
800 }
801 #endif /* HAVE_LIBCRYPTO */
802
803 if (d_alterFunc) {
804 std::lock_guard<std::mutex> lock(g_luamutex);
805 (*d_alterFunc)(dq, &message);
806 }
807
808 std::string data;
809 message.serialize(data);
810 d_logger->queueData(data);
811 #endif /* HAVE_PROTOBUF */
812 return Action::None;
813 }
814 std::string toString() const override
815 {
816 return "remote log to " + (d_logger ? d_logger->toString() : "");
817 }
818 private:
819 std::shared_ptr<RemoteLoggerInterface> d_logger;
820 boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc;
821 std::string d_serverID;
822 std::string d_ipEncryptKey;
823 };
824
825 class SNMPTrapAction : public DNSAction
826 {
827 public:
828 SNMPTrapAction(const std::string& reason): d_reason(reason)
829 {
830 }
831 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
832 {
833 if (g_snmpAgent && g_snmpTrapsEnabled) {
834 g_snmpAgent->sendDNSTrap(*dq, d_reason);
835 }
836
837 return Action::None;
838 }
839 std::string toString() const override
840 {
841 return "send SNMP trap";
842 }
843 private:
844 std::string d_reason;
845 };
846
847 class TagAction : public DNSAction
848 {
849 public:
850 TagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
851 {
852 }
853 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
854 {
855 if (!dq->qTag) {
856 dq->qTag = std::make_shared<QTag>();
857 }
858
859 dq->qTag->insert({d_tag, d_value});
860
861 return Action::None;
862 }
863 std::string toString() const override
864 {
865 return "set tag '" + d_tag + "' to value '" + d_value + "'";
866 }
867 private:
868 std::string d_tag;
869 std::string d_value;
870 };
871
872 class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable
873 {
874 public:
875 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)
876 {
877 }
878 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
879 {
880 #ifdef HAVE_PROTOBUF
881 struct timespec now;
882 gettime(&now, true);
883 DnstapMessage message(d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
884 {
885 if (d_alterFunc) {
886 std::lock_guard<std::mutex> lock(g_luamutex);
887 (*d_alterFunc)(dr, &message);
888 }
889 }
890 std::string data;
891 message.serialize(data);
892 d_logger->queueData(data);
893 #endif /* HAVE_PROTOBUF */
894 return Action::None;
895 }
896 std::string toString() const override
897 {
898 return "log response as dnstap to " + (d_logger ? d_logger->toString() : "");
899 }
900 private:
901 std::string d_identity;
902 std::shared_ptr<RemoteLoggerInterface> d_logger;
903 boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > d_alterFunc;
904 };
905
906 class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
907 {
908 public:
909 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)
910 {
911 }
912 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
913 {
914 #ifdef HAVE_PROTOBUF
915 if (!dr->uniqueId) {
916 dr->uniqueId = getUniqueID();
917 }
918
919 DNSDistProtoBufMessage message(*dr, d_includeCNAME);
920 if (!d_serverID.empty()) {
921 message.setServerIdentity(d_serverID);
922 }
923
924 #if HAVE_LIBCRYPTO
925 if (!d_ipEncryptKey.empty())
926 {
927 message.setRequestor(encryptCA(*dr->remote, d_ipEncryptKey));
928 }
929 #endif /* HAVE_LIBCRYPTO */
930
931 if (d_alterFunc) {
932 std::lock_guard<std::mutex> lock(g_luamutex);
933 (*d_alterFunc)(dr, &message);
934 }
935
936 std::string data;
937 message.serialize(data);
938 d_logger->queueData(data);
939 #endif /* HAVE_PROTOBUF */
940 return Action::None;
941 }
942 std::string toString() const override
943 {
944 return "remote log response to " + (d_logger ? d_logger->toString() : "");
945 }
946 private:
947 std::shared_ptr<RemoteLoggerInterface> d_logger;
948 boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc;
949 std::string d_serverID;
950 std::string d_ipEncryptKey;
951 bool d_includeCNAME;
952 };
953
954 class DropResponseAction : public DNSResponseAction
955 {
956 public:
957 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
958 {
959 return Action::Drop;
960 }
961 std::string toString() const override
962 {
963 return "drop";
964 }
965 };
966
967 class AllowResponseAction : public DNSResponseAction
968 {
969 public:
970 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
971 {
972 return Action::Allow;
973 }
974 std::string toString() const override
975 {
976 return "allow";
977 }
978 };
979
980 class DelayResponseAction : public DNSResponseAction
981 {
982 public:
983 DelayResponseAction(int msec) : d_msec(msec)
984 {}
985 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
986 {
987 *ruleresult=std::to_string(d_msec);
988 return Action::Delay;
989 }
990 std::string toString() const override
991 {
992 return "delay by "+std::to_string(d_msec)+ " msec";
993 }
994 private:
995 int d_msec;
996 };
997
998 class SNMPTrapResponseAction : public DNSResponseAction
999 {
1000 public:
1001 SNMPTrapResponseAction(const std::string& reason): d_reason(reason)
1002 {
1003 }
1004 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1005 {
1006 if (g_snmpAgent && g_snmpTrapsEnabled) {
1007 g_snmpAgent->sendDNSTrap(*dr, d_reason);
1008 }
1009
1010 return Action::None;
1011 }
1012 std::string toString() const override
1013 {
1014 return "send SNMP trap";
1015 }
1016 private:
1017 std::string d_reason;
1018 };
1019
1020 class TagResponseAction : public DNSResponseAction
1021 {
1022 public:
1023 TagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
1024 {
1025 }
1026 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1027 {
1028 if (!dr->qTag) {
1029 dr->qTag = std::make_shared<QTag>();
1030 }
1031
1032 dr->qTag->insert({d_tag, d_value});
1033
1034 return Action::None;
1035 }
1036 std::string toString() const override
1037 {
1038 return "set tag '" + d_tag + "' to value '" + d_value + "'";
1039 }
1040 private:
1041 std::string d_tag;
1042 std::string d_value;
1043 };
1044
1045 class ContinueAction : public DNSAction
1046 {
1047 public:
1048 ContinueAction(std::shared_ptr<DNSAction>& action): d_action(action)
1049 {
1050 }
1051
1052 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1053 {
1054 if (d_action) {
1055 /* call the action */
1056 auto action = (*d_action)(dq, ruleresult);
1057 bool drop = false;
1058 /* apply the changes if needed (pool selection, flags, etc */
1059 processRulesResult(action, *dq, *ruleresult, drop);
1060 }
1061
1062 /* but ignore the resulting action no matter what */
1063 return Action::None;
1064 }
1065
1066 std::string toString() const override
1067 {
1068 if (d_action) {
1069 return "continue after: " + (d_action ? d_action->toString() : "");
1070 }
1071 else {
1072 return "no op";
1073 }
1074 }
1075
1076 private:
1077 std::shared_ptr<DNSAction> d_action;
1078 };
1079
1080 #ifdef HAVE_DNS_OVER_HTTPS
1081 class HTTPStatusAction: public DNSAction
1082 {
1083 public:
1084 HTTPStatusAction(int code, const std::string& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
1085 {
1086 }
1087
1088 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1089 {
1090 if (!dq->du) {
1091 return Action::None;
1092 }
1093
1094 dq->du->setHTTPResponse(d_code, d_body, d_contentType);
1095 dq->dh->qr = true; // for good measure
1096 return Action::HeaderModify;
1097 }
1098
1099 std::string toString() const override
1100 {
1101 return "return an HTTP status of " + std::to_string(d_code);
1102 }
1103 private:
1104 std::string d_body;
1105 std::string d_contentType;
1106 int d_code;
1107 };
1108 #endif /* HAVE_DNS_OVER_HTTPS */
1109
1110 class KeyValueStoreLookupAction : public DNSAction
1111 {
1112 public:
1113 KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag)
1114 {
1115 }
1116
1117 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1118 {
1119 std::vector<std::string> keys = d_key->getKeys(*dq);
1120 std::string result;
1121 for (const auto& key : keys) {
1122 if (d_kvs->getValue(key, result) == true) {
1123 break;
1124 }
1125 }
1126
1127 if (!dq->qTag) {
1128 dq->qTag = std::make_shared<QTag>();
1129 }
1130
1131 dq->qTag->insert({d_tag, std::move(result)});
1132
1133 return Action::None;
1134 }
1135
1136 std::string toString() const override
1137 {
1138 return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'";
1139 }
1140
1141 private:
1142 std::shared_ptr<KeyValueStore> d_kvs;
1143 std::shared_ptr<KeyValueLookupKey> d_key;
1144 std::string d_tag;
1145 };
1146
1147 template<typename T, typename ActionT>
1148 static void addAction(GlobalStateHolder<vector<T> > *someRulActions, luadnsrule_t var, std::shared_ptr<ActionT> action, boost::optional<luaruleparams_t> params) {
1149 setLuaSideEffect();
1150
1151 boost::uuids::uuid uuid;
1152 uint64_t creationOrder;
1153 parseRuleParams(params, uuid, creationOrder);
1154
1155 auto rule=makeRule(var);
1156 someRulActions->modify([rule, action, uuid, creationOrder](vector<T>& rulactions){
1157 rulactions.push_back({rule, action, uuid, creationOrder});
1158 });
1159 }
1160
1161 void setupLuaActions()
1162 {
1163 g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
1164 boost::uuids::uuid uuid;
1165 uint64_t creationOrder;
1166 parseRuleParams(params, uuid, creationOrder);
1167
1168 auto rule=makeRule(dnsrule);
1169 DNSDistRuleAction ra({rule, action, uuid, creationOrder});
1170 return std::make_shared<DNSDistRuleAction>(ra);
1171 });
1172
1173 g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1174 if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
1175 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
1176 }
1177
1178 addAction(&g_rulactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
1179 });
1180
1181 g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1182 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1183 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1184 }
1185
1186 addAction(&g_resprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1187 });
1188
1189 g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1190 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1191 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1192 }
1193
1194 addAction(&g_cachehitresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1195 });
1196
1197 g_lua.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1198 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1199 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1200 }
1201
1202 addAction(&g_selfansweredresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1203 });
1204
1205 g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) {
1206 setLuaNoSideEffect();
1207 auto stats = ta.getStats();
1208 for(const auto& s : stats) {
1209 g_outputBuffer+=s.first+"\t";
1210 if((uint64_t)s.second == s.second)
1211 g_outputBuffer += std::to_string((uint64_t)s.second)+"\n";
1212 else
1213 g_outputBuffer += std::to_string(s.second)+"\n";
1214 }
1215 });
1216
1217 g_lua.writeFunction("getAction", [](unsigned int num) {
1218 setLuaNoSideEffect();
1219 boost::optional<std::shared_ptr<DNSAction>> ret;
1220 auto rulactions = g_rulactions.getCopy();
1221 if(num < rulactions.size())
1222 ret=rulactions[num].d_action;
1223 return ret;
1224 });
1225
1226 g_lua.registerFunction("getStats", &DNSAction::getStats);
1227
1228 g_lua.writeFunction("LuaAction", [](LuaAction::func_t func) {
1229 setLuaSideEffect();
1230 return std::shared_ptr<DNSAction>(new LuaAction(func));
1231 });
1232
1233 g_lua.writeFunction("NoRecurseAction", []() {
1234 return std::shared_ptr<DNSAction>(new NoRecurseAction);
1235 });
1236
1237 g_lua.writeFunction("MacAddrAction", [](int code) {
1238 return std::shared_ptr<DNSAction>(new MacAddrAction(code));
1239 });
1240
1241 g_lua.writeFunction("PoolAction", [](const std::string& a) {
1242 return std::shared_ptr<DNSAction>(new PoolAction(a));
1243 });
1244
1245 g_lua.writeFunction("QPSAction", [](int limit) {
1246 return std::shared_ptr<DNSAction>(new QPSAction(limit));
1247 });
1248
1249 g_lua.writeFunction("QPSPoolAction", [](int limit, const std::string& a) {
1250 return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
1251 });
1252
1253 g_lua.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b ) {
1254 vector<ComboAddress> addrs;
1255 if(auto s = boost::get<std::string>(&inp))
1256 addrs.push_back(ComboAddress(*s));
1257 else {
1258 const auto& v = boost::get<vector<pair<int,std::string>>>(inp);
1259 for(const auto& a: v)
1260 addrs.push_back(ComboAddress(a.second));
1261 }
1262 if(b)
1263 addrs.push_back(ComboAddress(*b));
1264 return std::shared_ptr<DNSAction>(new SpoofAction(addrs));
1265 });
1266
1267 g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a) {
1268 return std::shared_ptr<DNSAction>(new SpoofAction(a));
1269 });
1270
1271 g_lua.writeFunction("DropAction", []() {
1272 return std::shared_ptr<DNSAction>(new DropAction);
1273 });
1274
1275 g_lua.writeFunction("AllowAction", []() {
1276 return std::shared_ptr<DNSAction>(new AllowAction);
1277 });
1278
1279 g_lua.writeFunction("NoneAction", []() {
1280 return std::shared_ptr<DNSAction>(new NoneAction);
1281 });
1282
1283 g_lua.writeFunction("DelayAction", [](int msec) {
1284 return std::shared_ptr<DNSAction>(new DelayAction(msec));
1285 });
1286
1287 g_lua.writeFunction("TCAction", []() {
1288 return std::shared_ptr<DNSAction>(new TCAction);
1289 });
1290
1291 g_lua.writeFunction("DisableValidationAction", []() {
1292 return std::shared_ptr<DNSAction>(new DisableValidationAction);
1293 });
1294
1295 g_lua.writeFunction("LogAction", [](const std::string& fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered) {
1296 return std::shared_ptr<DNSAction>(new LogAction(fname, binary ? *binary : true, append ? *append : false, buffered ? *buffered : false));
1297 });
1298
1299 g_lua.writeFunction("RCodeAction", [](uint8_t rcode) {
1300 return std::shared_ptr<DNSAction>(new RCodeAction(rcode));
1301 });
1302
1303 g_lua.writeFunction("ERCodeAction", [](uint8_t rcode) {
1304 return std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
1305 });
1306
1307 g_lua.writeFunction("SkipCacheAction", []() {
1308 return std::shared_ptr<DNSAction>(new SkipCacheAction);
1309 });
1310
1311 g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
1312 return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
1313 });
1314
1315 g_lua.writeFunction("DropResponseAction", []() {
1316 return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
1317 });
1318
1319 g_lua.writeFunction("AllowResponseAction", []() {
1320 return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
1321 });
1322
1323 g_lua.writeFunction("DelayResponseAction", [](int msec) {
1324 return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
1325 });
1326
1327 g_lua.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
1328 setLuaSideEffect();
1329 return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
1330 });
1331
1332 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) {
1333 if (logger) {
1334 // avoids potentially-evaluated-expression warning with clang.
1335 RemoteLoggerInterface& rl = *logger.get();
1336 if (typeid(rl) != typeid(RemoteLogger)) {
1337 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1338 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1339 }
1340 }
1341
1342 std::string serverID;
1343 std::string ipEncryptKey;
1344 if (vars) {
1345 if (vars->count("serverID")) {
1346 serverID = boost::get<std::string>((*vars)["serverID"]);
1347 }
1348 if (vars->count("ipEncryptKey")) {
1349 ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]);
1350 }
1351 }
1352
1353 #ifdef HAVE_PROTOBUF
1354 return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey));
1355 #else
1356 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1357 #endif
1358 });
1359
1360 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) {
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("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
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<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false));
1383 #else
1384 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1385 #endif
1386 });
1387
1388 g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
1389 #ifdef HAVE_PROTOBUF
1390 return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
1391 #else
1392 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1393 #endif
1394 });
1395
1396 g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
1397 #ifdef HAVE_PROTOBUF
1398 return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
1399 #else
1400 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1401 #endif
1402 });
1403
1404 g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
1405 return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false));
1406 });
1407
1408 g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
1409 return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
1410 });
1411
1412 g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
1413 return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride));
1414 });
1415
1416 g_lua.writeFunction("DisableECSAction", []() {
1417 return std::shared_ptr<DNSAction>(new DisableECSAction());
1418 });
1419
1420 g_lua.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) {
1421 if (v6) {
1422 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6)));
1423 }
1424 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4)));
1425 });
1426
1427 g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
1428 #ifdef HAVE_NET_SNMP
1429 return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
1430 #else
1431 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1432 #endif /* HAVE_NET_SNMP */
1433 });
1434
1435 g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
1436 #ifdef HAVE_NET_SNMP
1437 return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
1438 #else
1439 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1440 #endif /* HAVE_NET_SNMP */
1441 });
1442
1443 g_lua.writeFunction("TagAction", [](std::string tag, std::string value) {
1444 return std::shared_ptr<DNSAction>(new TagAction(tag, value));
1445 });
1446
1447 g_lua.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
1448 return std::shared_ptr<DNSResponseAction>(new TagResponseAction(tag, value));
1449 });
1450
1451 g_lua.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
1452 return std::shared_ptr<DNSAction>(new ContinueAction(action));
1453 });
1454
1455 #ifdef HAVE_DNS_OVER_HTTPS
1456 g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType) {
1457 return std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
1458 });
1459 #endif /* HAVE_DNS_OVER_HTTPS */
1460
1461 g_lua.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
1462 return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
1463 });
1464 }