]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist-lua-actions.cc
Move UUID generators to a common function, fix boost 1.69.0 warning
[thirdparty/pdns.git] / pdns / dnsdist-lua-actions.cc
CommitLineData
6bb38cd6
RG
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
519f5484 22#include "threadname.hh"
6bb38cd6
RG
23#include "dnsdist.hh"
24#include "dnsdist-ecs.hh"
25#include "dnsdist-lua.hh"
26#include "dnsdist-protobuf.hh"
27
28#include "dolog.hh"
82a91ddf 29#include "dnstap.hh"
6bb38cd6 30#include "ednsoptions.hh"
82a91ddf 31#include "fstrm_logger.hh"
6bb38cd6 32#include "remote_logger.hh"
c134cbaa 33#include "boost/optional/optional_io.hpp"
6bb38cd6
RG
34
35class DropAction : public DNSAction
36{
37public:
38 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
39 {
40 return Action::Drop;
41 }
42 string toString() const override
43 {
44 return "drop";
45 }
46};
47
48class AllowAction : public DNSAction
49{
50public:
51 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
52 {
53 return Action::Allow;
54 }
55 string toString() const override
56 {
57 return "allow";
58 }
59};
60
bc084a31
RG
61class NoneAction : public DNSAction
62{
63public:
64 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
65 {
66 return Action::None;
67 }
68 string toString() const override
69 {
70 return "no op";
71 }
72};
6bb38cd6
RG
73
74class QPSAction : public DNSAction
75{
76public:
77 QPSAction(int limit) : d_qps(limit, limit)
78 {}
79 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
80 {
81 if(d_qps.check())
82 return Action::None;
83 else
84 return Action::Drop;
85 }
86 string toString() const override
87 {
88 return "qps limit to "+std::to_string(d_qps.getRate());
89 }
90private:
91 QPSLimiter d_qps;
92};
93
94class DelayAction : public DNSAction
95{
96public:
97 DelayAction(int msec) : d_msec(msec)
98 {}
99 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
100 {
101 *ruleresult=std::to_string(d_msec);
102 return Action::Delay;
103 }
104 string toString() const override
105 {
106 return "delay by "+std::to_string(d_msec)+ " msec";
107 }
108private:
109 int d_msec;
110};
111
112
113class TeeAction : public DNSAction
114{
115public:
116 TeeAction(const ComboAddress& ca, bool addECS=false);
117 ~TeeAction() override;
118 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override;
119 string toString() const override;
b8019cf7 120 std::map<string, double> getStats() const override;
6bb38cd6
RG
121
122private:
123 ComboAddress d_remote;
124 std::thread d_worker;
125 void worker();
126
127 int d_fd;
128 mutable std::atomic<unsigned long> d_senderrors{0};
129 unsigned long d_recverrors{0};
130 mutable std::atomic<unsigned long> d_queries{0};
131 unsigned long d_responses{0};
132 unsigned long d_nxdomains{0};
133 unsigned long d_servfails{0};
134 unsigned long d_refuseds{0};
135 unsigned long d_formerrs{0};
136 unsigned long d_notimps{0};
137 unsigned long d_noerrors{0};
138 mutable unsigned long d_tcpdrops{0};
139 unsigned long d_otherrcode{0};
140 std::atomic<bool> d_pleaseQuit{false};
141 bool d_addECS{false};
142};
143
144TeeAction::TeeAction(const ComboAddress& ca, bool addECS) : d_remote(ca), d_addECS(addECS)
145{
146 d_fd=SSocket(d_remote.sin4.sin_family, SOCK_DGRAM, 0);
147 SConnect(d_fd, d_remote);
148 setNonBlocking(d_fd);
149 d_worker=std::thread(std::bind(&TeeAction::worker, this));
150}
151
152TeeAction::~TeeAction()
153{
154 d_pleaseQuit=true;
155 close(d_fd);
156 d_worker.join();
157}
158
6bb38cd6
RG
159DNSAction::Action TeeAction::operator()(DNSQuestion* dq, string* ruleresult) const
160{
161 if(dq->tcp) {
162 d_tcpdrops++;
163 }
164 else {
165 ssize_t res;
166 d_queries++;
167
168 if(d_addECS) {
169 std::string query;
170 uint16_t len = dq->len;
171 bool ednsAdded = false;
172 bool ecsAdded = false;
173 query.reserve(dq->size);
174 query.assign((char*) dq->dh, len);
175
cbf4e13a
RG
176 string newECSOption;
177 generateECSOption(dq->ecsSet ? dq->ecs.getNetwork() : *dq->remote, newECSOption, dq->ecsSet ? dq->ecs.getBits() : dq->ecsPrefixLength);
178
53c57da7 179 if (!handleEDNSClientSubnet(const_cast<char*>(query.c_str()), query.capacity(), dq->qname->wirelength(), &len, &ednsAdded, &ecsAdded, dq->ecsOverride, newECSOption, g_preserveTrailingData)) {
6bb38cd6
RG
180 return DNSAction::Action::None;
181 }
182
183 res = send(d_fd, query.c_str(), len, 0);
184 }
185 else {
186 res = send(d_fd, (char*)dq->dh, dq->len, 0);
187 }
188
189 if (res <= 0)
190 d_senderrors++;
191 }
192 return DNSAction::Action::None;
193}
194
195string TeeAction::toString() const
196{
197 return "tee to "+d_remote.toStringWithPort();
198}
199
b8019cf7 200std::map<string,double> TeeAction::getStats() const
6bb38cd6
RG
201{
202 return {{"queries", d_queries},
203 {"responses", d_responses},
204 {"recv-errors", d_recverrors},
205 {"send-errors", d_senderrors},
206 {"noerrors", d_noerrors},
207 {"nxdomains", d_nxdomains},
208 {"refuseds", d_refuseds},
209 {"servfails", d_servfails},
210 {"other-rcode", d_otherrcode},
211 {"tcp-drops", d_tcpdrops}
212 };
213}
214
215void TeeAction::worker()
216{
519f5484 217 setThreadName("dnsdist/TeeWork");
6bb38cd6
RG
218 char packet[1500];
219 int res=0;
220 struct dnsheader* dh=(struct dnsheader*)packet;
221 for(;;) {
222 res=waitForData(d_fd, 0, 250000);
223 if(d_pleaseQuit)
224 break;
225 if(res < 0) {
226 usleep(250000);
227 continue;
228 }
229 if(res==0)
230 continue;
231 res=recv(d_fd, packet, sizeof(packet), 0);
232 if(res <= (int)sizeof(struct dnsheader))
233 d_recverrors++;
234 else if(res > 0)
235 d_responses++;
236
237 if(dh->rcode == RCode::NoError)
238 d_noerrors++;
239 else if(dh->rcode == RCode::ServFail)
240 d_servfails++;
241 else if(dh->rcode == RCode::NXDomain)
242 d_nxdomains++;
243 else if(dh->rcode == RCode::Refused)
244 d_refuseds++;
245 else if(dh->rcode == RCode::FormErr)
246 d_formerrs++;
247 else if(dh->rcode == RCode::NotImp)
248 d_notimps++;
249 }
250}
251
252class PoolAction : public DNSAction
253{
254public:
255 PoolAction(const std::string& pool) : d_pool(pool) {}
256 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
257 {
258 *ruleresult=d_pool;
259 return Action::Pool;
260 }
261 string toString() const override
262 {
263 return "to pool "+d_pool;
264 }
265
266private:
267 string d_pool;
268};
269
270
271class QPSPoolAction : public DNSAction
272{
273public:
274 QPSPoolAction(unsigned int limit, const std::string& pool) : d_qps(limit, limit), d_pool(pool) {}
275 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
276 {
277 if(d_qps.check()) {
278 *ruleresult=d_pool;
279 return Action::Pool;
280 }
281 else
282 return Action::None;
283 }
284 string toString() const override
285 {
286 return "max " +std::to_string(d_qps.getRate())+" to pool "+d_pool;
287 }
288
289private:
290 QPSLimiter d_qps;
291 string d_pool;
292};
293
294class RCodeAction : public DNSAction
295{
296public:
f6007449 297 RCodeAction(uint8_t rcode) : d_rcode(rcode) {}
6bb38cd6
RG
298 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
299 {
300 dq->dh->rcode = d_rcode;
301 dq->dh->qr = true; // for good measure
302 return Action::HeaderModify;
303 }
304 string toString() const override
305 {
306 return "set rcode "+std::to_string(d_rcode);
307 }
308
309private:
f6007449 310 uint8_t d_rcode;
6bb38cd6
RG
311};
312
313class TCAction : public DNSAction
314{
315public:
316 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
317 {
318 return Action::Truncate;
319 }
320 string toString() const override
321 {
322 return "tc=1 answer";
323 }
324};
325
ac2ccb4e
CH
326DNSAction::Action LuaAction::operator()(DNSQuestion* dq, string* ruleresult) const
327{
328 std::lock_guard<std::mutex> lock(g_luamutex);
329 try {
330 auto ret = d_func(dq);
c134cbaa
CHB
331 if (ruleresult) {
332 if (boost::optional<string> rule = std::get<1>(ret)) {
333 *ruleresult = *rule;
334 }
335 else {
336 // default to empty string
337 ruleresult->clear();
338 }
339 }
ac2ccb4e
CH
340 return (Action)std::get<0>(ret);
341 } catch (std::exception &e) {
342 warnlog("LuaAction failed inside lua, returning ServFail: %s", e.what());
343 } catch (...) {
344 warnlog("LuaAction failed inside lua, returning ServFail: [unknown exception]");
345 }
346 return DNSAction::Action::ServFail;
347}
348
349DNSResponseAction::Action LuaResponseAction::operator()(DNSResponse* dr, string* ruleresult) const
350{
351 std::lock_guard<std::mutex> lock(g_luamutex);
352 try {
353 auto ret = d_func(dr);
c134cbaa
CHB
354 if(ruleresult) {
355 if (boost::optional<string> rule = std::get<1>(ret)) {
356 *ruleresult = *rule;
357 }
358 else {
359 // default to empty string
360 ruleresult->clear();
361 }
362 }
ac2ccb4e
CH
363 return (Action)std::get<0>(ret);
364 } catch (std::exception &e) {
365 warnlog("LuaResponseAction failed inside lua, returning ServFail: %s", e.what());
366 } catch (...) {
367 warnlog("LuaResponseAction failed inside lua, returning ServFail: [unknown exception]");
368 }
369 return DNSResponseAction::Action::ServFail;
370}
371
6bb38cd6
RG
372DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, string* ruleresult) const
373{
374 uint16_t qtype = dq->qtype;
375 // do we even have a response?
376 if(d_cname.empty() && !std::count_if(d_addrs.begin(), d_addrs.end(), [qtype](const ComboAddress& a)
377 {
378 return (qtype == QType::ANY || ((a.sin4.sin_family == AF_INET && qtype == QType::A) ||
379 (a.sin4.sin_family == AF_INET6 && qtype == QType::AAAA)));
380 }))
381 return Action::None;
382
383 vector<ComboAddress> addrs;
384 unsigned int totrdatalen=0;
385 if (!d_cname.empty()) {
386 qtype = QType::CNAME;
387 totrdatalen += d_cname.toDNSString().size();
388 } else {
389 for(const auto& addr : d_addrs) {
390 if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) ||
391 (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
392 continue;
393 }
394 totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
395 addrs.push_back(addr);
396 }
397 }
398
399 if(addrs.size() > 1)
400 random_shuffle(addrs.begin(), addrs.end());
401
402 unsigned int consumed=0;
403 DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed);
404
405 if (dq->size < (sizeof(dnsheader) + consumed + 4 + ((d_cname.empty() ? 0 : 1) + addrs.size())*12 /* recordstart */ + totrdatalen)) {
406 return Action::None;
407 }
408
e7c732b8
RG
409 bool dnssecOK = false;
410 bool hadEDNS = false;
411 if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) {
412 hadEDNS = true;
413 dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO;
414 }
415
6bb38cd6
RG
416 dq->len = sizeof(dnsheader) + consumed + 4; // there goes your EDNS
417 char* dest = ((char*)dq->dh) + dq->len;
418
419 dq->dh->qr = true; // for good measure
420 dq->dh->ra = dq->dh->rd; // for good measure
421 dq->dh->ad = false;
422 dq->dh->ancount = 0;
423 dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
424
425 if(qtype == QType::CNAME) {
426 string wireData = d_cname.toDNSString(); // Note! This doesn't do compression!
427 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
428 0, (unsigned char) qtype,
429 0, QClass::IN, // IN
430 0, 0, 0, 60, // TTL
431 0, (unsigned char)wireData.length()};
432 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
433
434 memcpy(dest, recordstart, sizeof(recordstart));
435 dest += sizeof(recordstart);
436 memcpy(dest, wireData.c_str(), wireData.length());
437 dq->len += wireData.length() + sizeof(recordstart);
438 dq->dh->ancount++;
439 }
440 else {
441 for(const auto& addr : addrs) {
442 unsigned char rdatalen = addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
443 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
444 0, (unsigned char) (addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA),
445 0, QClass::IN, // IN
446 0, 0, 0, 60, // TTL
447 0, rdatalen};
448 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
449
450 memcpy(dest, recordstart, sizeof(recordstart));
451 dest += sizeof(recordstart);
452
453 memcpy(dest,
454 addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr,
455 rdatalen);
456 dest += rdatalen;
457 dq->len += rdatalen + sizeof(recordstart);
458 dq->dh->ancount++;
459 }
460 }
461
462 dq->dh->ancount = htons(dq->dh->ancount);
463
8d72bcdd 464 if (hadEDNS) {
e0fd37ec 465 addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers);
e7c732b8
RG
466 }
467
6bb38cd6
RG
468 return Action::HeaderModify;
469}
470
471class MacAddrAction : public DNSAction
472{
473public:
474 MacAddrAction(uint16_t code) : d_code(code)
475 {}
476 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
477 {
478 if(dq->dh->arcount)
479 return Action::None;
480
481 string mac = getMACAddress(*dq->remote);
482 if(mac.empty())
483 return Action::None;
484
485 string optRData;
486 generateEDNSOption(d_code, mac, optRData);
487
488 string res;
e7c732b8 489 generateOptRR(optRData, res, g_EdnsUDPPayloadSize, false);
6bb38cd6
RG
490
491 if ((dq->size - dq->len) < res.length())
492 return Action::None;
493
494 dq->dh->arcount = htons(1);
495 char* dest = ((char*)dq->dh) + dq->len;
496 memcpy(dest, res.c_str(), res.length());
497 dq->len += res.length();
498
499 return Action::None;
500 }
501 string toString() const override
502 {
503 return "add EDNS MAC (code="+std::to_string(d_code)+")";
504 }
505private:
506 uint16_t d_code{3};
507};
508
509class NoRecurseAction : public DNSAction
510{
511public:
512 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
513 {
514 dq->dh->rd = false;
515 return Action::None;
516 }
517 string toString() const override
518 {
519 return "set rd=0";
520 }
521};
522
523class LogAction : public DNSAction, public boost::noncopyable
524{
525public:
526 LogAction() : d_fp(0)
527 {
528 }
529 LogAction(const std::string& str, bool binary=true, bool append=false, bool buffered=true) : d_fname(str), d_binary(binary)
530 {
531 if(str.empty())
532 return;
533 if(append)
534 d_fp = fopen(str.c_str(), "a+");
535 else
536 d_fp = fopen(str.c_str(), "w");
537 if(!d_fp)
538 throw std::runtime_error("Unable to open file '"+str+"' for logging: "+string(strerror(errno)));
539 if(!buffered)
540 setbuf(d_fp, 0);
541 }
542 ~LogAction() override
543 {
544 if(d_fp)
545 fclose(d_fp);
546 }
547 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
548 {
549 if(!d_fp) {
550 vinfolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
551 }
552 else {
553 if(d_binary) {
554 string out = dq->qname->toDNSString();
555 fwrite(out.c_str(), 1, out.size(), d_fp);
556 fwrite((void*)&dq->qtype, 1, 2, d_fp);
557 }
558 else {
559 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);
560 }
561 }
562 return Action::None;
563 }
564 string toString() const override
565 {
566 if (!d_fname.empty()) {
567 return "log to " + d_fname;
568 }
569 return "log";
570 }
571private:
572 string d_fname;
573 FILE* d_fp{0};
574 bool d_binary{true};
575};
576
577
578class DisableValidationAction : public DNSAction
579{
580public:
581 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
582 {
583 dq->dh->cd = true;
584 return Action::None;
585 }
586 string toString() const override
587 {
588 return "set cd=1";
589 }
590};
591
592class SkipCacheAction : public DNSAction
593{
594public:
595 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
596 {
597 dq->skipCache = true;
598 return Action::None;
599 }
600 string toString() const override
601 {
602 return "skip cache";
603 }
604};
605
acb8f5d5
CH
606class TempFailureCacheTTLAction : public DNSAction
607{
608public:
609 TempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl)
610 {}
611 TempFailureCacheTTLAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
612 {
613 dq->tempFailureTTL = d_ttl;
614 return Action::None;
615 }
616 string toString() const override
617 {
618 return "set tempfailure cache ttl to "+std::to_string(d_ttl);
619 }
620private:
621 uint32_t d_ttl;
622};
623
6bb38cd6
RG
624class ECSPrefixLengthAction : public DNSAction
625{
626public:
627 ECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
628 {
629 }
630 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
631 {
632 dq->ecsPrefixLength = dq->remote->sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
633 return Action::None;
634 }
635 string toString() const override
636 {
637 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength);
638 }
639private:
640 uint16_t d_v4PrefixLength;
641 uint16_t d_v6PrefixLength;
642};
643
644class ECSOverrideAction : public DNSAction
645{
646public:
647 ECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride)
648 {
649 }
650 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
651 {
652 dq->ecsOverride = d_ecsOverride;
653 return Action::None;
654 }
655 string toString() const override
656 {
657 return "set ECS override to " + std::to_string(d_ecsOverride);
658 }
659private:
660 bool d_ecsOverride;
661};
662
663
664class DisableECSAction : public DNSAction
665{
666public:
667 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
668 {
669 dq->useECS = false;
670 return Action::None;
671 }
672 string toString() const override
673 {
674 return "disable ECS";
675 }
676};
677
bd14f087
RG
678class SetECSAction : public DNSAction
679{
680public:
4bd24482 681 SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false)
bd14f087
RG
682 {
683 }
684
4bd24482 685 SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true)
bd14f087
RG
686 {
687 }
688
689 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
690 {
691 dq->ecsSet = true;
692
693 if (d_hasV6) {
694 dq->ecs = dq->remote->isIPv4() ? d_v4 : d_v6;
695 }
696 else {
697 dq->ecs = d_v4;
698 }
699
700 return Action::None;
701 }
702
703 string toString() const override
704 {
705 string result = "set ECS to " + d_v4.toString();
706 if (d_hasV6) {
707 result += " / " + d_v6.toString();
708 }
709 return result;
710 }
711
712private:
713 Netmask d_v4;
714 Netmask d_v6;
715 bool d_hasV6;
716};
717
718
82a91ddf
CH
719class DnstapLogAction : public DNSAction, public boost::noncopyable
720{
721public:
f3b1a1ef 722 DnstapLogAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
82a91ddf
CH
723 {
724 }
725 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
726 {
727#ifdef HAVE_PROTOBUF
728 DnstapMessage message(d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
729 {
730 if (d_alterFunc) {
731 std::lock_guard<std::mutex> lock(g_luamutex);
732 (*d_alterFunc)(*dq, &message);
733 }
734 }
735 std::string data;
736 message.serialize(data);
737 d_logger->queueData(data);
738#endif /* HAVE_PROTOBUF */
739 return Action::None;
740 }
741 string toString() const override
742 {
743 return "remote log as dnstap to " + (d_logger ? d_logger->toString() : "");
744 }
745private:
746 std::string d_identity;
747 std::shared_ptr<RemoteLoggerInterface> d_logger;
748 boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > d_alterFunc;
749};
750
6bb38cd6
RG
751class RemoteLogAction : public DNSAction, public boost::noncopyable
752{
753public:
312a09a6 754 RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID)
6bb38cd6
RG
755 {
756 }
757 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
758 {
759#ifdef HAVE_PROTOBUF
760 if (!dq->uniqueId) {
d61aa945 761 dq->uniqueId = getUniqueID();
6bb38cd6
RG
762 }
763
764 DNSDistProtoBufMessage message(*dq);
312a09a6
RG
765 if (!d_serverID.empty()) {
766 message.setServerIdentity(d_serverID);
6bb38cd6 767 }
312a09a6
RG
768
769 if (d_alterFunc) {
770 std::lock_guard<std::mutex> lock(g_luamutex);
771 (*d_alterFunc)(*dq, &message);
772 }
773
6bb38cd6
RG
774 std::string data;
775 message.serialize(data);
776 d_logger->queueData(data);
777#endif /* HAVE_PROTOBUF */
778 return Action::None;
779 }
780 string toString() const override
781 {
782 return "remote log to " + (d_logger ? d_logger->toString() : "");
783 }
784private:
82a91ddf 785 std::shared_ptr<RemoteLoggerInterface> d_logger;
6bb38cd6 786 boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > d_alterFunc;
312a09a6 787 std::string d_serverID;
6bb38cd6
RG
788};
789
790class SNMPTrapAction : public DNSAction
791{
792public:
793 SNMPTrapAction(const std::string& reason): d_reason(reason)
794 {
795 }
796 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
797 {
798 if (g_snmpAgent && g_snmpTrapsEnabled) {
799 g_snmpAgent->sendDNSTrap(*dq, d_reason);
800 }
801
802 return Action::None;
803 }
804 string toString() const override
805 {
806 return "send SNMP trap";
807 }
808private:
809 std::string d_reason;
810};
811
812class TagAction : public DNSAction
813{
814public:
f3b1a1ef 815 TagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
6bb38cd6
RG
816 {
817 }
818 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
819 {
15fac047 820 if (!dq->qTag) {
6bb38cd6
RG
821 dq->qTag = std::make_shared<QTag>();
822 }
823
15fac047 824 dq->qTag->insert({d_tag, d_value});
6bb38cd6
RG
825
826 return Action::None;
827 }
828 string toString() const override
829 {
830 return "set tag '" + d_tag + "' to value '" + d_value + "'";
831 }
832private:
833 std::string d_tag;
834 std::string d_value;
835};
836
82a91ddf
CH
837class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable
838{
839public:
f3b1a1ef 840 DnstapLogResponseAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
82a91ddf
CH
841 {
842 }
843 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
844 {
845#ifdef HAVE_PROTOBUF
846 struct timespec now;
847 gettime(&now, true);
848 DnstapMessage message(d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
849 {
850 if (d_alterFunc) {
851 std::lock_guard<std::mutex> lock(g_luamutex);
852 (*d_alterFunc)(*dr, &message);
853 }
854 }
855 std::string data;
856 message.serialize(data);
857 d_logger->queueData(data);
858#endif /* HAVE_PROTOBUF */
859 return Action::None;
860 }
861 string toString() const override
862 {
863 return "log response as dnstap to " + (d_logger ? d_logger->toString() : "");
864 }
865private:
866 std::string d_identity;
867 std::shared_ptr<RemoteLoggerInterface> d_logger;
868 boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > d_alterFunc;
869};
870
6bb38cd6
RG
871class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
872{
873public:
312a09a6 874 RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, bool includeCNAME): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_includeCNAME(includeCNAME)
6bb38cd6
RG
875 {
876 }
877 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
878 {
879#ifdef HAVE_PROTOBUF
880 if (!dr->uniqueId) {
d61aa945 881 dr->uniqueId = getUniqueID();
6bb38cd6
RG
882 }
883
884 DNSDistProtoBufMessage message(*dr, d_includeCNAME);
312a09a6
RG
885 if (!d_serverID.empty()) {
886 message.setServerIdentity(d_serverID);
887 }
888
889 if (d_alterFunc) {
890 std::lock_guard<std::mutex> lock(g_luamutex);
891 (*d_alterFunc)(*dr, &message);
6bb38cd6 892 }
312a09a6 893
6bb38cd6
RG
894 std::string data;
895 message.serialize(data);
896 d_logger->queueData(data);
897#endif /* HAVE_PROTOBUF */
898 return Action::None;
899 }
900 string toString() const override
901 {
902 return "remote log response to " + (d_logger ? d_logger->toString() : "");
903 }
904private:
82a91ddf 905 std::shared_ptr<RemoteLoggerInterface> d_logger;
6bb38cd6 906 boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > d_alterFunc;
312a09a6 907 std::string d_serverID;
6bb38cd6
RG
908 bool d_includeCNAME;
909};
910
911class DropResponseAction : public DNSResponseAction
912{
913public:
914 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
915 {
916 return Action::Drop;
917 }
918 string toString() const override
919 {
920 return "drop";
921 }
922};
923
924class AllowResponseAction : public DNSResponseAction
925{
926public:
927 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
928 {
929 return Action::Allow;
930 }
931 string toString() const override
932 {
933 return "allow";
934 }
935};
936
937class DelayResponseAction : public DNSResponseAction
938{
939public:
940 DelayResponseAction(int msec) : d_msec(msec)
941 {}
942 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
943 {
944 *ruleresult=std::to_string(d_msec);
945 return Action::Delay;
946 }
947 string toString() const override
948 {
949 return "delay by "+std::to_string(d_msec)+ " msec";
950 }
951private:
952 int d_msec;
953};
954
955class SNMPTrapResponseAction : public DNSResponseAction
956{
957public:
958 SNMPTrapResponseAction(const std::string& reason): d_reason(reason)
959 {
960 }
961 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
962 {
963 if (g_snmpAgent && g_snmpTrapsEnabled) {
964 g_snmpAgent->sendDNSTrap(*dr, d_reason);
965 }
966
967 return Action::None;
968 }
969 string toString() const override
970 {
971 return "send SNMP trap";
972 }
973private:
974 std::string d_reason;
975};
976
977class TagResponseAction : public DNSResponseAction
978{
979public:
f3b1a1ef 980 TagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
6bb38cd6
RG
981 {
982 }
983 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
984 {
15fac047 985 if (!dr->qTag) {
6bb38cd6
RG
986 dr->qTag = std::make_shared<QTag>();
987 }
988
15fac047 989 dr->qTag->insert({d_tag, d_value});
6bb38cd6
RG
990
991 return Action::None;
992 }
993 string toString() const override
994 {
995 return "set tag '" + d_tag + "' to value '" + d_value + "'";
996 }
997private:
998 std::string d_tag;
999 std::string d_value;
1000};
1001
d18eab67
CH
1002template<typename T, typename ActionT>
1003static void addAction(GlobalStateHolder<vector<T> > *someRulActions, luadnsrule_t var, std::shared_ptr<ActionT> action, boost::optional<luaruleparams_t> params) {
1004 setLuaSideEffect();
1005
1006 boost::uuids::uuid uuid;
f8a222ac
RG
1007 uint64_t creationOrder;
1008 parseRuleParams(params, uuid, creationOrder);
d18eab67
CH
1009
1010 auto rule=makeRule(var);
f8a222ac
RG
1011 someRulActions->modify([rule, action, uuid, creationOrder](vector<T>& rulactions){
1012 rulactions.push_back({rule, action, uuid, creationOrder});
d18eab67
CH
1013 });
1014}
1015
6bb38cd6
RG
1016void setupLuaActions()
1017{
4d5959e6
RG
1018 g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
1019 boost::uuids::uuid uuid;
f8a222ac
RG
1020 uint64_t creationOrder;
1021 parseRuleParams(params, uuid, creationOrder);
4d5959e6 1022
6bb38cd6 1023 auto rule=makeRule(dnsrule);
f8a222ac 1024 DNSDistRuleAction ra({rule, action, uuid, creationOrder});
4d5959e6 1025 return std::make_shared<DNSDistRuleAction>(ra);
6bb38cd6
RG
1026 });
1027
4d5959e6 1028 g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
d18eab67 1029 if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
6bb38cd6
RG
1030 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
1031 }
1032
d18eab67 1033 addAction(&g_rulactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
6bb38cd6
RG
1034 });
1035
e33e53fc 1036 g_lua.writeFunction("addLuaAction", [](luadnsrule_t var, LuaAction::func_t func, boost::optional<luaruleparams_t> params) {
d18eab67 1037 addAction(&g_rulactions, var, std::make_shared<LuaAction>(func), params);
4d5959e6 1038 });
6bb38cd6 1039
e33e53fc 1040 g_lua.writeFunction("addLuaResponseAction", [](luadnsrule_t var, LuaResponseAction::func_t func, boost::optional<luaruleparams_t> params) {
d18eab67 1041 addAction(&g_resprulactions, var, std::make_shared<LuaResponseAction>(func), params);
6bb38cd6
RG
1042 });
1043
4d5959e6 1044 g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
d18eab67 1045 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
6bb38cd6
RG
1046 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1047 }
1048
d18eab67 1049 addAction(&g_resprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
6bb38cd6
RG
1050 });
1051
4d5959e6 1052 g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
d18eab67 1053 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
4d5959e6
RG
1054 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1055 }
1056
d18eab67 1057 addAction(&g_cachehitresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
6bb38cd6
RG
1058 });
1059
2d4783a8
CH
1060 g_lua.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1061 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1062 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1063 }
1064
1065 addAction(&g_selfansweredresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1066 });
1067
6bb38cd6
RG
1068 g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) {
1069 setLuaNoSideEffect();
1070 auto stats = ta.getStats();
1071 for(const auto& s : stats) {
1072 g_outputBuffer+=s.first+"\t";
1073 if((uint64_t)s.second == s.second)
1074 g_outputBuffer += std::to_string((uint64_t)s.second)+"\n";
1075 else
1076 g_outputBuffer += std::to_string(s.second)+"\n";
1077 }
1078 });
1079
1080 g_lua.writeFunction("getAction", [](unsigned int num) {
1081 setLuaNoSideEffect();
1082 boost::optional<std::shared_ptr<DNSAction>> ret;
1083 auto rulactions = g_rulactions.getCopy();
1084 if(num < rulactions.size())
4d5959e6 1085 ret=rulactions[num].d_action;
6bb38cd6
RG
1086 return ret;
1087 });
1088
1089 g_lua.registerFunction("getStats", &DNSAction::getStats);
1090
1091 g_lua.writeFunction("LuaAction", [](LuaAction::func_t func) {
1092 setLuaSideEffect();
1093 return std::shared_ptr<DNSAction>(new LuaAction(func));
1094 });
1095
1096 g_lua.writeFunction("NoRecurseAction", []() {
1097 return std::shared_ptr<DNSAction>(new NoRecurseAction);
1098 });
1099
1100 g_lua.writeFunction("MacAddrAction", [](int code) {
1101 return std::shared_ptr<DNSAction>(new MacAddrAction(code));
1102 });
1103
1104 g_lua.writeFunction("PoolAction", [](const string& a) {
1105 return std::shared_ptr<DNSAction>(new PoolAction(a));
1106 });
1107
1108 g_lua.writeFunction("QPSAction", [](int limit) {
1109 return std::shared_ptr<DNSAction>(new QPSAction(limit));
1110 });
1111
1112 g_lua.writeFunction("QPSPoolAction", [](int limit, const string& a) {
1113 return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
1114 });
1115
1116 g_lua.writeFunction("SpoofAction", [](boost::variant<string,vector<pair<int, string>>> inp, boost::optional<string> b ) {
1117 vector<ComboAddress> addrs;
1118 if(auto s = boost::get<string>(&inp))
1119 addrs.push_back(ComboAddress(*s));
1120 else {
1121 const auto& v = boost::get<vector<pair<int,string>>>(inp);
1122 for(const auto& a: v)
1123 addrs.push_back(ComboAddress(a.second));
1124 }
1125 if(b)
1126 addrs.push_back(ComboAddress(*b));
1127 return std::shared_ptr<DNSAction>(new SpoofAction(addrs));
1128 });
1129
1130 g_lua.writeFunction("SpoofCNAMEAction", [](const string& a) {
1131 return std::shared_ptr<DNSAction>(new SpoofAction(a));
1132 });
1133
1134 g_lua.writeFunction("DropAction", []() {
1135 return std::shared_ptr<DNSAction>(new DropAction);
1136 });
1137
1138 g_lua.writeFunction("AllowAction", []() {
1139 return std::shared_ptr<DNSAction>(new AllowAction);
1140 });
1141
bc084a31
RG
1142 g_lua.writeFunction("NoneAction", []() {
1143 return std::shared_ptr<DNSAction>(new NoneAction);
1144 });
1145
6bb38cd6
RG
1146 g_lua.writeFunction("DelayAction", [](int msec) {
1147 return std::shared_ptr<DNSAction>(new DelayAction(msec));
1148 });
1149
1150 g_lua.writeFunction("TCAction", []() {
1151 return std::shared_ptr<DNSAction>(new TCAction);
1152 });
1153
1154 g_lua.writeFunction("DisableValidationAction", []() {
1155 return std::shared_ptr<DNSAction>(new DisableValidationAction);
1156 });
1157
1158 g_lua.writeFunction("LogAction", [](const std::string& fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered) {
1159 return std::shared_ptr<DNSAction>(new LogAction(fname, binary ? *binary : true, append ? *append : false, buffered ? *buffered : false));
1160 });
1161
f6007449 1162 g_lua.writeFunction("RCodeAction", [](uint8_t rcode) {
6bb38cd6
RG
1163 return std::shared_ptr<DNSAction>(new RCodeAction(rcode));
1164 });
1165
1166 g_lua.writeFunction("SkipCacheAction", []() {
1167 return std::shared_ptr<DNSAction>(new SkipCacheAction);
1168 });
1169
acb8f5d5
CH
1170 g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
1171 return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
1172 });
1173
6bb38cd6
RG
1174 g_lua.writeFunction("DropResponseAction", []() {
1175 return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
1176 });
1177
1178 g_lua.writeFunction("AllowResponseAction", []() {
1179 return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
1180 });
1181
1182 g_lua.writeFunction("DelayResponseAction", [](int msec) {
1183 return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
1184 });
1185
1186 g_lua.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
1187 setLuaSideEffect();
1188 return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
1189 });
1190
312a09a6 1191 g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<std::unordered_map<std::string, std::string>> vars) {
82a91ddf
CH
1192 // avoids potentially-evaluated-expression warning with clang.
1193 RemoteLoggerInterface& rl = *logger.get();
1194 if (typeid(rl) != typeid(RemoteLogger)) {
1195 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1196 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1197 }
312a09a6
RG
1198
1199 std::string serverID;
1200 if (vars) {
1201 if (vars->count("serverID")) {
1202 serverID = boost::get<std::string>((*vars)["serverID"]);
1203 }
1204 }
1205
6bb38cd6 1206#ifdef HAVE_PROTOBUF
312a09a6 1207 return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID));
6bb38cd6
RG
1208#else
1209 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1210#endif
1211 });
1212
312a09a6 1213 g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<std::unordered_map<std::string, std::string>> vars) {
82a91ddf
CH
1214 // avoids potentially-evaluated-expression warning with clang.
1215 RemoteLoggerInterface& rl = *logger.get();
1216 if (typeid(rl) != typeid(RemoteLogger)) {
1217 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1218 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
1219 }
312a09a6
RG
1220
1221 std::string serverID;
1222 if (vars) {
1223 if (vars->count("serverID")) {
1224 serverID = boost::get<std::string>((*vars)["serverID"]);
1225 }
1226 }
1227
6bb38cd6 1228#ifdef HAVE_PROTOBUF
312a09a6 1229 return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, includeCNAME ? *includeCNAME : false));
6bb38cd6
RG
1230#else
1231 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1232#endif
1233 });
1234
82a91ddf
CH
1235 g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > alterFunc) {
1236#ifdef HAVE_PROTOBUF
1237 return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
1238#else
1239 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1240#endif
1241 });
1242
1243 g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > alterFunc) {
1244#ifdef HAVE_PROTOBUF
1245 return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
1246#else
1247 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1248#endif
1249 });
1250
6bb38cd6
RG
1251 g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
1252 return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false));
1253 });
1254
1255 g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
1256 return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
1257 });
1258
1259 g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
1260 return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride));
1261 });
1262
1263 g_lua.writeFunction("DisableECSAction", []() {
1264 return std::shared_ptr<DNSAction>(new DisableECSAction());
1265 });
1266
bd14f087
RG
1267 g_lua.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) {
1268 if (v6) {
1269 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6)));
1270 }
1271 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4)));
1272 });
1273
6bb38cd6
RG
1274 g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
1275#ifdef HAVE_NET_SNMP
1276 return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
1277#else
1278 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1279#endif /* HAVE_NET_SNMP */
1280 });
1281
1282 g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
1283#ifdef HAVE_NET_SNMP
1284 return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
1285#else
1286 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1287#endif /* HAVE_NET_SNMP */
1288 });
1289
1290 g_lua.writeFunction("TagAction", [](std::string tag, std::string value) {
1291 return std::shared_ptr<DNSAction>(new TagAction(tag, value));
1292 });
1293
1294 g_lua.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
1295 return std::shared_ptr<DNSResponseAction>(new TagResponseAction(tag, value));
1296 });
1297}