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