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