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