]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-lua-actions.cc
Merge pull request #10501 from rgacogne/ddist-per-thread-lua-ffi
[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 class LuaFFIPerThreadAction: public DNSAction
493 {
494 public:
495 typedef std::function<int(dnsdist_ffi_dnsquestion_t* dq)> func_t;
496
497 LuaFFIPerThreadAction(const std::string& code): d_functionCode(code), d_functionID(s_functionsCounter++)
498 {
499 }
500
501 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
502 {
503 try {
504 auto& state = t_perThreadStates[d_functionID];
505 if (!state.d_initialized) {
506 setupLuaFFIPerThreadContext(state.d_luaContext);
507 /* mark the state as initialized first so if there is a syntax error
508 we only try to execute the code once */
509 state.d_initialized = true;
510 state.d_func = state.d_luaContext.executeCode<func_t>(d_functionCode);
511 }
512
513 if (!state.d_func) {
514 /* the function was not properly initialized */
515 return DNSAction::Action::None;
516 }
517
518 dnsdist_ffi_dnsquestion_t dqffi(dq);
519 auto ret = state.d_func(&dqffi);
520 if (ruleresult) {
521 if (dqffi.result) {
522 *ruleresult = *dqffi.result;
523 }
524 else {
525 // default to empty string
526 ruleresult->clear();
527 }
528 }
529 return static_cast<DNSAction::Action>(ret);
530 }
531 catch (const std::exception &e) {
532 warnlog("LuaFFIPerThreadAction failed inside Lua, returning ServFail: %s", e.what());
533 }
534 catch (...) {
535 warnlog("LuaFFIPerthreadAction failed inside Lua, returning ServFail: [unknown exception]");
536 }
537 return DNSAction::Action::ServFail;
538 }
539
540 string toString() const override
541 {
542 return "Lua FFI per-thread script";
543 }
544
545 private:
546 struct PerThreadState
547 {
548 LuaContext d_luaContext;
549 func_t d_func;
550 bool d_initialized{false};
551 };
552 static std::atomic<uint64_t> s_functionsCounter;
553 static thread_local std::map<uint64_t, PerThreadState> t_perThreadStates;
554 const std::string d_functionCode;
555 const uint64_t d_functionID;
556 };
557
558 std::atomic<uint64_t> LuaFFIPerThreadAction::s_functionsCounter = 0;
559 thread_local std::map<uint64_t, LuaFFIPerThreadAction::PerThreadState> LuaFFIPerThreadAction::t_perThreadStates;
560
561 class LuaFFIResponseAction: public DNSResponseAction
562 {
563 public:
564 typedef std::function<int(dnsdist_ffi_dnsquestion_t* dq)> func_t;
565
566 LuaFFIResponseAction(const LuaFFIResponseAction::func_t& func): d_func(func)
567 {
568 }
569
570 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
571 {
572 DNSQuestion* dq = dynamic_cast<DNSQuestion*>(dr);
573 if (dq == nullptr) {
574 return DNSResponseAction::Action::ServFail;
575 }
576
577 dnsdist_ffi_dnsquestion_t dqffi(dq);
578 try {
579 std::lock_guard<std::mutex> lock(g_luamutex);
580
581 auto ret = d_func(&dqffi);
582 if (ruleresult) {
583 if (dqffi.result) {
584 *ruleresult = *dqffi.result;
585 }
586 else {
587 // default to empty string
588 ruleresult->clear();
589 }
590 }
591 return static_cast<DNSResponseAction::Action>(ret);
592 } catch (const std::exception &e) {
593 warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: %s", e.what());
594 } catch (...) {
595 warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: [unknown exception]");
596 }
597 return DNSResponseAction::Action::ServFail;
598 }
599
600 string toString() const override
601 {
602 return "Lua FFI script";
603 }
604 private:
605 func_t d_func;
606 };
607
608 class LuaFFIPerThreadResponseAction: public DNSResponseAction
609 {
610 public:
611 typedef std::function<int(dnsdist_ffi_dnsquestion_t* dq)> func_t;
612
613 LuaFFIPerThreadResponseAction(const std::string& code): d_functionCode(code), d_functionID(s_functionsCounter++)
614 {
615 }
616
617 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
618 {
619 DNSQuestion* dq = dynamic_cast<DNSQuestion*>(dr);
620 if (dq == nullptr) {
621 return DNSResponseAction::Action::ServFail;
622 }
623
624 try {
625 auto& state = t_perThreadStates[d_functionID];
626 if (!state.d_initialized) {
627 setupLuaFFIPerThreadContext(state.d_luaContext);
628 /* mark the state as initialized first so if there is a syntax error
629 we only try to execute the code once */
630 state.d_initialized = true;
631 state.d_func = state.d_luaContext.executeCode<func_t>(d_functionCode);
632 }
633
634 if (!state.d_func) {
635 /* the function was not properly initialized */
636 return DNSResponseAction::Action::None;
637 }
638
639 dnsdist_ffi_dnsquestion_t dqffi(dq);
640 auto ret = state.d_func(&dqffi);
641 if (ruleresult) {
642 if (dqffi.result) {
643 *ruleresult = *dqffi.result;
644 }
645 else {
646 // default to empty string
647 ruleresult->clear();
648 }
649 }
650 return static_cast<DNSResponseAction::Action>(ret);
651 }
652 catch (const std::exception &e) {
653 warnlog("LuaFFIPerThreadResponseAction failed inside Lua, returning ServFail: %s", e.what());
654 }
655 catch (...) {
656 warnlog("LuaFFIPerthreadResponseAction failed inside Lua, returning ServFail: [unknown exception]");
657 }
658 return DNSResponseAction::Action::ServFail;
659 }
660
661 string toString() const override
662 {
663 return "Lua FFI per-thread script";
664 }
665
666 private:
667 struct PerThreadState
668 {
669 LuaContext d_luaContext;
670 func_t d_func;
671 bool d_initialized{false};
672 };
673
674 static std::atomic<uint64_t> s_functionsCounter;
675 static thread_local std::map<uint64_t, PerThreadState> t_perThreadStates;
676 const std::string d_functionCode;
677 const uint64_t d_functionID;
678 };
679
680 std::atomic<uint64_t> LuaFFIPerThreadResponseAction::s_functionsCounter = 0;
681 thread_local std::map<uint64_t, LuaFFIPerThreadResponseAction::PerThreadState> LuaFFIPerThreadResponseAction::t_perThreadStates;
682
683 thread_local std::default_random_engine SpoofAction::t_randomEngine;
684
685 DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
686 {
687 uint16_t qtype = dq->qtype;
688 // do we even have a response?
689 if (d_cname.empty() &&
690 d_rawResponses.empty() &&
691 d_types.count(qtype) == 0) {
692 return Action::None;
693 }
694
695 vector<ComboAddress> addrs;
696 vector<std::string> rawResponses;
697 unsigned int totrdatalen = 0;
698 uint16_t numberOfRecords = 0;
699 if (!d_cname.empty()) {
700 qtype = QType::CNAME;
701 totrdatalen += d_cname.getStorage().size();
702 numberOfRecords = 1;
703 } else if (!d_rawResponses.empty()) {
704 rawResponses.reserve(d_rawResponses.size());
705 for(const auto& rawResponse : d_rawResponses){
706 totrdatalen += rawResponse.size();
707 rawResponses.push_back(rawResponse);
708 ++numberOfRecords;
709 }
710 if (rawResponses.size() > 1) {
711 shuffle(rawResponses.begin(), rawResponses.end(), t_randomEngine);
712 }
713 }
714 else {
715 for(const auto& addr : d_addrs) {
716 if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) ||
717 (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
718 continue;
719 }
720 totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
721 addrs.push_back(addr);
722 ++numberOfRecords;
723 }
724 }
725
726 if (addrs.size() > 1) {
727 shuffle(addrs.begin(), addrs.end(), t_randomEngine);
728 }
729
730 unsigned int qnameWireLength=0;
731 DNSName ignore((char*)dq->getData().data(), dq->getData().size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength);
732
733 if (dq->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen)) {
734 return Action::None;
735 }
736
737 bool dnssecOK = false;
738 bool hadEDNS = false;
739 if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) {
740 hadEDNS = true;
741 dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO;
742 }
743
744 auto& data = dq->getMutableData();
745 data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen); // there goes your EDNS
746 uint8_t* dest = &(data.at(sizeof(dnsheader) + qnameWireLength + 4));
747
748 dq->getHeader()->qr = true; // for good measure
749 setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
750 dq->getHeader()->ancount = 0;
751 dq->getHeader()->arcount = 0; // for now, forget about your EDNS, we're marching over it
752
753 uint32_t ttl = htonl(d_responseConfig.ttl);
754 unsigned char recordstart[] = {0xc0, 0x0c, // compressed name
755 0, 0, // QTYPE
756 0, QClass::IN,
757 0, 0, 0, 0, // TTL
758 0, 0 }; // rdata length
759 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
760 memcpy(&recordstart[6], &ttl, sizeof(ttl));
761 bool raw = false;
762
763 if (qtype == QType::CNAME) {
764 const auto& wireData = d_cname.getStorage(); // Note! This doesn't do compression!
765 uint16_t rdataLen = htons(wireData.length());
766 qtype = htons(qtype);
767 memcpy(&recordstart[2], &qtype, sizeof(qtype));
768 memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
769
770 memcpy(dest, recordstart, sizeof(recordstart));
771 dest += sizeof(recordstart);
772 memcpy(dest, wireData.c_str(), wireData.length());
773 dq->getHeader()->ancount++;
774 }
775 else if (!rawResponses.empty()) {
776 qtype = htons(qtype);
777 for(const auto& rawResponse : rawResponses){
778 uint16_t rdataLen = htons(rawResponse.size());
779 memcpy(&recordstart[2], &qtype, sizeof(qtype));
780 memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
781
782 memcpy(dest, recordstart, sizeof(recordstart));
783 dest += sizeof(recordstart);
784
785 memcpy(dest, rawResponse.c_str(), rawResponse.size());
786 dest += rawResponse.size();
787
788 dq->getHeader()->ancount++;
789 }
790 raw = true;
791 }
792 else {
793 for(const auto& addr : addrs) {
794 uint16_t rdataLen = htons(addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
795 qtype = htons(addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA);
796 memcpy(&recordstart[2], &qtype, sizeof(qtype));
797 memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
798
799 memcpy(dest, recordstart, sizeof(recordstart));
800 dest += sizeof(recordstart);
801
802 memcpy(dest,
803 addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr,
804 addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
805 dest += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
806 dq->getHeader()->ancount++;
807 }
808 }
809
810 dq->getHeader()->ancount = htons(dq->getHeader()->ancount);
811
812 if (hadEDNS && raw == false) {
813 addEDNS(dq->getMutableData(), dq->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
814 }
815
816 return Action::HeaderModify;
817 }
818
819 class SetMacAddrAction : public DNSAction
820 {
821 public:
822 // this action does not stop the processing
823 SetMacAddrAction(uint16_t code) : d_code(code)
824 {}
825 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
826 {
827 if (dq->getHeader()->arcount) {
828 return Action::None;
829 }
830
831 std::string mac = getMACAddress(*dq->remote);
832 if (mac.empty()) {
833 return Action::None;
834 }
835
836 std::string optRData;
837 generateEDNSOption(d_code, mac, optRData);
838
839 auto& data = dq->getMutableData();
840 if (generateOptRR(optRData, data, dq->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
841 dq->getHeader()->arcount = htons(1);
842 }
843
844 return Action::None;
845 }
846 std::string toString() const override
847 {
848 return "add EDNS MAC (code="+std::to_string(d_code)+")";
849 }
850 private:
851 uint16_t d_code{3};
852 };
853
854 class SetNoRecurseAction : public DNSAction
855 {
856 public:
857 // this action does not stop the processing
858 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
859 {
860 dq->getHeader()->rd = false;
861 return Action::None;
862 }
863 std::string toString() const override
864 {
865 return "set rd=0";
866 }
867 };
868
869 class LogAction : public DNSAction, public boost::noncopyable
870 {
871 public:
872 // this action does not stop the processing
873 LogAction()
874 {
875 }
876
877 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)
878 {
879 if (str.empty()) {
880 return;
881 }
882
883 if (!reopenLogFile()) {
884 throw std::runtime_error("Unable to open file '" + str + "' for logging: " + stringerror());
885 }
886 }
887
888 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
889 {
890 auto fp = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
891 if (!fp) {
892 if (!d_verboseOnly || g_verbose) {
893 if (d_includeTimestamp) {
894 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);
895 }
896 else {
897 infolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).toString(), dq->getHeader()->id);
898 }
899 }
900 }
901 else {
902 if (d_binary) {
903 const auto& out = dq->qname->getStorage();
904 if (d_includeTimestamp) {
905 uint64_t tv_sec = static_cast<uint64_t>(dq->queryTime->tv_sec);
906 uint32_t tv_nsec = static_cast<uint32_t>(dq->queryTime->tv_nsec);
907 fwrite(&tv_sec, sizeof(tv_sec), 1, fp.get());
908 fwrite(&tv_nsec, sizeof(tv_nsec), 1, fp.get());
909 }
910 uint16_t id = dq->getHeader()->id;
911 fwrite(&id, sizeof(id), 1, fp.get());
912 fwrite(out.c_str(), 1, out.size(), fp.get());
913 fwrite(&dq->qtype, sizeof(dq->qtype), 1, fp.get());
914 fwrite(&dq->remote->sin4.sin_family, sizeof(dq->remote->sin4.sin_family), 1, fp.get());
915 if (dq->remote->sin4.sin_family == AF_INET) {
916 fwrite(&dq->remote->sin4.sin_addr.s_addr, sizeof(dq->remote->sin4.sin_addr.s_addr), 1, fp.get());
917 }
918 else if (dq->remote->sin4.sin_family == AF_INET6) {
919 fwrite(&dq->remote->sin6.sin6_addr.s6_addr, sizeof(dq->remote->sin6.sin6_addr.s6_addr), 1, fp.get());
920 }
921 fwrite(&dq->remote->sin4.sin_port, sizeof(dq->remote->sin4.sin_port), 1, fp.get());
922 }
923 else {
924 if (d_includeTimestamp) {
925 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);
926 }
927 else {
928 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);
929 }
930 }
931 }
932 return Action::None;
933 }
934
935 std::string toString() const override
936 {
937 if (!d_fname.empty()) {
938 return "log to " + d_fname;
939 }
940 return "log";
941 }
942
943 void reload() override
944 {
945 if (!reopenLogFile()) {
946 warnlog("Unable to open file '%s' for logging: %s", d_fname, stringerror());
947 }
948 }
949
950 private:
951 bool reopenLogFile()
952 {
953 // we are using a naked pointer here because we don't want fclose to be called
954 // with a nullptr, which would happen if we constructor a shared_ptr with fclose
955 // as a custom deleter and nullptr as a FILE*
956 auto nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w");
957 if (!nfp) {
958 /* don't fall on our sword when reopening */
959 return false;
960 }
961
962 auto fp = std::shared_ptr<FILE>(nfp, fclose);
963 nfp = nullptr;
964
965 if (!d_buffered) {
966 setbuf(fp.get(), 0);
967 }
968
969 std::atomic_store_explicit(&d_fp, fp, std::memory_order_release);
970 return true;
971 }
972
973 std::string d_fname;
974 std::shared_ptr<FILE> d_fp{nullptr};
975 bool d_binary{true};
976 bool d_verboseOnly{true};
977 bool d_includeTimestamp{false};
978 bool d_append{false};
979 bool d_buffered{true};
980 };
981
982 class LogResponseAction : public DNSResponseAction, public boost::noncopyable
983 {
984 public:
985 LogResponseAction()
986 {
987 }
988
989 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)
990 {
991 if (str.empty()) {
992 return;
993 }
994
995 if (!reopenLogFile()) {
996 throw std::runtime_error("Unable to open file '" + str + "' for logging: " + stringerror());
997 }
998 }
999
1000 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1001 {
1002 auto fp = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
1003 if (!fp) {
1004 if (!d_verboseOnly || g_verbose) {
1005 if (d_includeTimestamp) {
1006 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);
1007 }
1008 else {
1009 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);
1010 }
1011 }
1012 }
1013 else {
1014 if (d_includeTimestamp) {
1015 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);
1016 }
1017 else {
1018 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);
1019 }
1020 }
1021 return Action::None;
1022 }
1023
1024 std::string toString() const override
1025 {
1026 if (!d_fname.empty()) {
1027 return "log to " + d_fname;
1028 }
1029 return "log";
1030 }
1031
1032 void reload() override
1033 {
1034 if (!reopenLogFile()) {
1035 warnlog("Unable to open file '%s' for logging: %s", d_fname, stringerror());
1036 }
1037 }
1038
1039 private:
1040 bool reopenLogFile()
1041 {
1042 // we are using a naked pointer here because we don't want fclose to be called
1043 // with a nullptr, which would happen if we constructor a shared_ptr with fclose
1044 // as a custom deleter and nullptr as a FILE*
1045 auto nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w");
1046 if (!nfp) {
1047 /* don't fall on our sword when reopening */
1048 return false;
1049 }
1050
1051 auto fp = std::shared_ptr<FILE>(nfp, fclose);
1052 nfp = nullptr;
1053
1054 if (!d_buffered) {
1055 setbuf(fp.get(), 0);
1056 }
1057
1058 std::atomic_store_explicit(&d_fp, fp, std::memory_order_release);
1059 return true;
1060 }
1061
1062 std::string d_fname;
1063 std::shared_ptr<FILE> d_fp{nullptr};
1064 bool d_verboseOnly{true};
1065 bool d_includeTimestamp{false};
1066 bool d_append{false};
1067 bool d_buffered{true};
1068 };
1069
1070
1071 class SetDisableValidationAction : public DNSAction
1072 {
1073 public:
1074 // this action does not stop the processing
1075 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1076 {
1077 dq->getHeader()->cd = true;
1078 return Action::None;
1079 }
1080 std::string toString() const override
1081 {
1082 return "set cd=1";
1083 }
1084 };
1085
1086 class SetSkipCacheAction : public DNSAction
1087 {
1088 public:
1089 // this action does not stop the processing
1090 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1091 {
1092 dq->skipCache = true;
1093 return Action::None;
1094 }
1095 std::string toString() const override
1096 {
1097 return "skip cache";
1098 }
1099 };
1100
1101 class SetSkipCacheResponseAction : public DNSResponseAction
1102 {
1103 public:
1104 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1105 {
1106 dr->skipCache = true;
1107 return Action::None;
1108 }
1109 std::string toString() const override
1110 {
1111 return "skip cache";
1112 }
1113 };
1114
1115 class SetTempFailureCacheTTLAction : public DNSAction
1116 {
1117 public:
1118 // this action does not stop the processing
1119 SetTempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl)
1120 {
1121 }
1122 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1123 {
1124 dq->tempFailureTTL = d_ttl;
1125 return Action::None;
1126 }
1127 std::string toString() const override
1128 {
1129 return "set tempfailure cache ttl to "+std::to_string(d_ttl);
1130 }
1131 private:
1132 uint32_t d_ttl;
1133 };
1134
1135 class SetECSPrefixLengthAction : public DNSAction
1136 {
1137 public:
1138 // this action does not stop the processing
1139 SetECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
1140 {
1141 }
1142 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1143 {
1144 dq->ecsPrefixLength = dq->remote->sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
1145 return Action::None;
1146 }
1147 std::string toString() const override
1148 {
1149 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength);
1150 }
1151 private:
1152 uint16_t d_v4PrefixLength;
1153 uint16_t d_v6PrefixLength;
1154 };
1155
1156 class SetECSOverrideAction : public DNSAction
1157 {
1158 public:
1159 // this action does not stop the processing
1160 SetECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride)
1161 {
1162 }
1163 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1164 {
1165 dq->ecsOverride = d_ecsOverride;
1166 return Action::None;
1167 }
1168 std::string toString() const override
1169 {
1170 return "set ECS override to " + std::to_string(d_ecsOverride);
1171 }
1172 private:
1173 bool d_ecsOverride;
1174 };
1175
1176
1177 class SetDisableECSAction : public DNSAction
1178 {
1179 public:
1180 // this action does not stop the processing
1181 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1182 {
1183 dq->useECS = false;
1184 return Action::None;
1185 }
1186 std::string toString() const override
1187 {
1188 return "disable ECS";
1189 }
1190 };
1191
1192 class SetECSAction : public DNSAction
1193 {
1194 public:
1195 // this action does not stop the processing
1196 SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false)
1197 {
1198 }
1199
1200 SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true)
1201 {
1202 }
1203
1204 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1205 {
1206 dq->ecsSet = true;
1207
1208 if (d_hasV6) {
1209 dq->ecs = dq->remote->isIPv4() ? d_v4 : d_v6;
1210 }
1211 else {
1212 dq->ecs = d_v4;
1213 }
1214
1215 return Action::None;
1216 }
1217
1218 std::string toString() const override
1219 {
1220 std::string result = "set ECS to " + d_v4.toString();
1221 if (d_hasV6) {
1222 result += " / " + d_v6.toString();
1223 }
1224 return result;
1225 }
1226
1227 private:
1228 Netmask d_v4;
1229 Netmask d_v6;
1230 bool d_hasV6;
1231 };
1232
1233 static DnstapMessage::ProtocolType ProtocolToDNSTap(DNSQuestion::Protocol protocol)
1234 {
1235 DnstapMessage::ProtocolType result;
1236 switch (protocol) {
1237 default:
1238 case DNSQuestion::Protocol::DoUDP:
1239 case DNSQuestion::Protocol::DNSCryptUDP:
1240 result = DnstapMessage::ProtocolType::DoUDP;
1241 break;
1242 case DNSQuestion::Protocol::DoTCP:
1243 case DNSQuestion::Protocol::DNSCryptTCP:
1244 result = DnstapMessage::ProtocolType::DoTCP;
1245 break;
1246 case DNSQuestion::Protocol::DoT:
1247 result = DnstapMessage::ProtocolType::DoT;
1248 break;
1249 case DNSQuestion::Protocol::DoH:
1250 result = DnstapMessage::ProtocolType::DoH;
1251 break;
1252 }
1253 return result;
1254 }
1255
1256 class DnstapLogAction : public DNSAction, public boost::noncopyable
1257 {
1258 public:
1259 // this action does not stop the processing
1260 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)
1261 {
1262 }
1263 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1264 {
1265 static thread_local std::string data;
1266 data.clear();
1267
1268 DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dq->getProtocol());
1269 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);
1270 {
1271 if (d_alterFunc) {
1272 std::lock_guard<std::mutex> lock(g_luamutex);
1273 (*d_alterFunc)(dq, &message);
1274 }
1275 }
1276
1277 d_logger->queueData(data);
1278
1279 return Action::None;
1280 }
1281 std::string toString() const override
1282 {
1283 return "remote log as dnstap to " + (d_logger ? d_logger->toString() : "");
1284 }
1285 private:
1286 std::string d_identity;
1287 std::shared_ptr<RemoteLoggerInterface> d_logger;
1288 boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > d_alterFunc;
1289 };
1290
1291 class RemoteLogAction : public DNSAction, public boost::noncopyable
1292 {
1293 public:
1294 // this action does not stop the processing
1295 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)
1296 {
1297 }
1298 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1299 {
1300 if (!dq->uniqueId) {
1301 dq->uniqueId = getUniqueID();
1302 }
1303
1304 DNSDistProtoBufMessage message(*dq);
1305 if (!d_serverID.empty()) {
1306 message.setServerIdentity(d_serverID);
1307 }
1308
1309 #if HAVE_LIBCRYPTO
1310 if (!d_ipEncryptKey.empty())
1311 {
1312 message.setRequestor(encryptCA(*dq->remote, d_ipEncryptKey));
1313 }
1314 #endif /* HAVE_LIBCRYPTO */
1315
1316 if (d_alterFunc) {
1317 std::lock_guard<std::mutex> lock(g_luamutex);
1318 (*d_alterFunc)(dq, &message);
1319 }
1320
1321 static thread_local std::string data;
1322 data.clear();
1323 message.serialize(data);
1324 d_logger->queueData(data);
1325
1326 return Action::None;
1327 }
1328 std::string toString() const override
1329 {
1330 return "remote log to " + (d_logger ? d_logger->toString() : "");
1331 }
1332 private:
1333 std::shared_ptr<RemoteLoggerInterface> d_logger;
1334 boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc;
1335 std::string d_serverID;
1336 std::string d_ipEncryptKey;
1337 };
1338
1339 class SNMPTrapAction : public DNSAction
1340 {
1341 public:
1342 // this action does not stop the processing
1343 SNMPTrapAction(const std::string& reason): d_reason(reason)
1344 {
1345 }
1346 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1347 {
1348 if (g_snmpAgent && g_snmpTrapsEnabled) {
1349 g_snmpAgent->sendDNSTrap(*dq, d_reason);
1350 }
1351
1352 return Action::None;
1353 }
1354 std::string toString() const override
1355 {
1356 return "send SNMP trap";
1357 }
1358 private:
1359 std::string d_reason;
1360 };
1361
1362 class SetTagAction : public DNSAction
1363 {
1364 public:
1365 // this action does not stop the processing
1366 SetTagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
1367 {
1368 }
1369 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1370 {
1371 if (!dq->qTag) {
1372 dq->qTag = std::make_shared<QTag>();
1373 }
1374
1375 dq->qTag->insert({d_tag, d_value});
1376
1377 return Action::None;
1378 }
1379 std::string toString() const override
1380 {
1381 return "set tag '" + d_tag + "' to value '" + d_value + "'";
1382 }
1383 private:
1384 std::string d_tag;
1385 std::string d_value;
1386 };
1387
1388 class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable
1389 {
1390 public:
1391 // this action does not stop the processing
1392 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)
1393 {
1394 }
1395 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1396 {
1397 static thread_local std::string data;
1398 struct timespec now;
1399 gettime(&now, true);
1400 data.clear();
1401
1402 DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dr->getProtocol());
1403 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);
1404 {
1405 if (d_alterFunc) {
1406 std::lock_guard<std::mutex> lock(g_luamutex);
1407 (*d_alterFunc)(dr, &message);
1408 }
1409 }
1410
1411 d_logger->queueData(data);
1412
1413 return Action::None;
1414 }
1415 std::string toString() const override
1416 {
1417 return "log response as dnstap to " + (d_logger ? d_logger->toString() : "");
1418 }
1419 private:
1420 std::string d_identity;
1421 std::shared_ptr<RemoteLoggerInterface> d_logger;
1422 boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > d_alterFunc;
1423 };
1424
1425 class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
1426 {
1427 public:
1428 // this action does not stop the processing
1429 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)
1430 {
1431 }
1432 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1433 {
1434 if (!dr->uniqueId) {
1435 dr->uniqueId = getUniqueID();
1436 }
1437
1438 DNSDistProtoBufMessage message(*dr, d_includeCNAME);
1439 if (!d_serverID.empty()) {
1440 message.setServerIdentity(d_serverID);
1441 }
1442
1443 #if HAVE_LIBCRYPTO
1444 if (!d_ipEncryptKey.empty())
1445 {
1446 message.setRequestor(encryptCA(*dr->remote, d_ipEncryptKey));
1447 }
1448 #endif /* HAVE_LIBCRYPTO */
1449
1450 if (d_alterFunc) {
1451 std::lock_guard<std::mutex> lock(g_luamutex);
1452 (*d_alterFunc)(dr, &message);
1453 }
1454
1455 static thread_local std::string data;
1456 data.clear();
1457 message.serialize(data);
1458 d_logger->queueData(data);
1459
1460 return Action::None;
1461 }
1462 std::string toString() const override
1463 {
1464 return "remote log response to " + (d_logger ? d_logger->toString() : "");
1465 }
1466 private:
1467 std::shared_ptr<RemoteLoggerInterface> d_logger;
1468 boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc;
1469 std::string d_serverID;
1470 std::string d_ipEncryptKey;
1471 bool d_includeCNAME;
1472 };
1473
1474 class DropResponseAction : public DNSResponseAction
1475 {
1476 public:
1477 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1478 {
1479 return Action::Drop;
1480 }
1481 std::string toString() const override
1482 {
1483 return "drop";
1484 }
1485 };
1486
1487 class AllowResponseAction : public DNSResponseAction
1488 {
1489 public:
1490 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1491 {
1492 return Action::Allow;
1493 }
1494 std::string toString() const override
1495 {
1496 return "allow";
1497 }
1498 };
1499
1500 class DelayResponseAction : public DNSResponseAction
1501 {
1502 public:
1503 DelayResponseAction(int msec) : d_msec(msec)
1504 {
1505 }
1506 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1507 {
1508 *ruleresult = std::to_string(d_msec);
1509 return Action::Delay;
1510 }
1511 std::string toString() const override
1512 {
1513 return "delay by "+std::to_string(d_msec)+ " msec";
1514 }
1515 private:
1516 int d_msec;
1517 };
1518
1519 class SNMPTrapResponseAction : public DNSResponseAction
1520 {
1521 public:
1522 // this action does not stop the processing
1523 SNMPTrapResponseAction(const std::string& reason): d_reason(reason)
1524 {
1525 }
1526 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1527 {
1528 if (g_snmpAgent && g_snmpTrapsEnabled) {
1529 g_snmpAgent->sendDNSTrap(*dr, d_reason);
1530 }
1531
1532 return Action::None;
1533 }
1534 std::string toString() const override
1535 {
1536 return "send SNMP trap";
1537 }
1538 private:
1539 std::string d_reason;
1540 };
1541
1542 class SetTagResponseAction : public DNSResponseAction
1543 {
1544 public:
1545 // this action does not stop the processing
1546 SetTagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
1547 {
1548 }
1549 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1550 {
1551 if (!dr->qTag) {
1552 dr->qTag = std::make_shared<QTag>();
1553 }
1554
1555 dr->qTag->insert({d_tag, d_value});
1556
1557 return Action::None;
1558 }
1559 std::string toString() const override
1560 {
1561 return "set tag '" + d_tag + "' to value '" + d_value + "'";
1562 }
1563 private:
1564 std::string d_tag;
1565 std::string d_value;
1566 };
1567
1568 class ContinueAction : public DNSAction
1569 {
1570 public:
1571 // this action does not stop the processing
1572 ContinueAction(std::shared_ptr<DNSAction>& action): d_action(action)
1573 {
1574 }
1575
1576 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1577 {
1578 if (d_action) {
1579 /* call the action */
1580 auto action = (*d_action)(dq, ruleresult);
1581 bool drop = false;
1582 /* apply the changes if needed (pool selection, flags, etc */
1583 processRulesResult(action, *dq, *ruleresult, drop);
1584 }
1585
1586 /* but ignore the resulting action no matter what */
1587 return Action::None;
1588 }
1589
1590 std::string toString() const override
1591 {
1592 if (d_action) {
1593 return "continue after: " + (d_action ? d_action->toString() : "");
1594 }
1595 else {
1596 return "no op";
1597 }
1598 }
1599
1600 private:
1601 std::shared_ptr<DNSAction> d_action;
1602 };
1603
1604 #ifdef HAVE_DNS_OVER_HTTPS
1605 class HTTPStatusAction: public DNSAction
1606 {
1607 public:
1608 HTTPStatusAction(int code, const PacketBuffer& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
1609 {
1610 }
1611
1612 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1613 {
1614 if (!dq->du) {
1615 return Action::None;
1616 }
1617
1618 dq->du->setHTTPResponse(d_code, PacketBuffer(d_body), d_contentType);
1619 dq->getHeader()->qr = true; // for good measure
1620 setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
1621 return Action::HeaderModify;
1622 }
1623
1624 std::string toString() const override
1625 {
1626 return "return an HTTP status of " + std::to_string(d_code);
1627 }
1628
1629 ResponseConfig d_responseConfig;
1630 private:
1631 PacketBuffer d_body;
1632 std::string d_contentType;
1633 int d_code;
1634 };
1635 #endif /* HAVE_DNS_OVER_HTTPS */
1636
1637 class KeyValueStoreLookupAction : public DNSAction
1638 {
1639 public:
1640 // this action does not stop the processing
1641 KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag)
1642 {
1643 }
1644
1645 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1646 {
1647 std::vector<std::string> keys = d_key->getKeys(*dq);
1648 std::string result;
1649 for (const auto& key : keys) {
1650 if (d_kvs->getValue(key, result) == true) {
1651 break;
1652 }
1653 }
1654
1655 if (!dq->qTag) {
1656 dq->qTag = std::make_shared<QTag>();
1657 }
1658
1659 dq->qTag->insert({d_tag, std::move(result)});
1660
1661 return Action::None;
1662 }
1663
1664 std::string toString() const override
1665 {
1666 return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'";
1667 }
1668
1669 private:
1670 std::shared_ptr<KeyValueStore> d_kvs;
1671 std::shared_ptr<KeyValueLookupKey> d_key;
1672 std::string d_tag;
1673 };
1674
1675 class NegativeAndSOAAction: public DNSAction
1676 {
1677 public:
1678 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)
1679 {
1680 }
1681
1682 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1683 {
1684 if (!setNegativeAndAdditionalSOA(*dq, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_serial, d_refresh, d_retry, d_expire, d_minimum)) {
1685 return Action::None;
1686 }
1687
1688 setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
1689
1690 return Action::Allow;
1691 }
1692
1693 std::string toString() const override
1694 {
1695 return std::string(d_nxd ? "NXD " : "NODATA") + " with SOA";
1696 }
1697
1698 ResponseConfig d_responseConfig;
1699
1700 private:
1701 DNSName d_zone;
1702 DNSName d_mname;
1703 DNSName d_rname;
1704 uint32_t d_ttl;
1705 uint32_t d_serial;
1706 uint32_t d_refresh;
1707 uint32_t d_retry;
1708 uint32_t d_expire;
1709 uint32_t d_minimum;
1710 bool d_nxd;
1711 };
1712
1713 class SetProxyProtocolValuesAction : public DNSAction
1714 {
1715 public:
1716 // this action does not stop the processing
1717 SetProxyProtocolValuesAction(const std::vector<std::pair<uint8_t, std::string>>& values)
1718 {
1719 d_values.reserve(values.size());
1720 for (const auto& value : values) {
1721 d_values.push_back({value.second, value.first});
1722 }
1723 }
1724
1725 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1726 {
1727 if (!dq->proxyProtocolValues) {
1728 dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
1729 }
1730
1731 *(dq->proxyProtocolValues) = d_values;
1732
1733 return Action::None;
1734 }
1735
1736 std::string toString() const override
1737 {
1738 return "set Proxy-Protocol values";
1739 }
1740
1741 private:
1742 std::vector<ProxyProtocolValue> d_values;
1743 };
1744
1745 class SetAdditionalProxyProtocolValueAction : public DNSAction
1746 {
1747 public:
1748 // this action does not stop the processing
1749 SetAdditionalProxyProtocolValueAction(uint8_t type, const std::string& value): d_value(value), d_type(type)
1750 {
1751 }
1752
1753 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1754 {
1755 if (!dq->proxyProtocolValues) {
1756 dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
1757 }
1758
1759 dq->proxyProtocolValues->push_back({ d_value, d_type });
1760
1761 return Action::None;
1762 }
1763
1764 std::string toString() const override
1765 {
1766 return "add a Proxy-Protocol value of type " + std::to_string(d_type);
1767 }
1768
1769 private:
1770 std::string d_value;
1771 uint8_t d_type;
1772 };
1773
1774 template<typename T, typename ActionT>
1775 static void addAction(GlobalStateHolder<vector<T> > *someRuleActions, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params) {
1776 setLuaSideEffect();
1777
1778 std::string name;
1779 boost::uuids::uuid uuid;
1780 uint64_t creationOrder;
1781 parseRuleParams(params, uuid, name, creationOrder);
1782
1783 auto rule = makeRule(var);
1784 someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector<T>& ruleactions){
1785 ruleactions.push_back({std::move(rule), std::move(action), std::move(name), std::move(uuid), creationOrder});
1786 });
1787 }
1788
1789 typedef std::unordered_map<std::string, boost::variant<bool, uint32_t> > responseParams_t;
1790
1791 static void parseResponseConfig(boost::optional<responseParams_t> vars, ResponseConfig& config)
1792 {
1793 if (vars) {
1794 if (vars->count("ttl")) {
1795 config.ttl = boost::get<uint32_t>((*vars)["ttl"]);
1796 }
1797 if (vars->count("aa")) {
1798 config.setAA = boost::get<bool>((*vars)["aa"]);
1799 }
1800 if (vars->count("ad")) {
1801 config.setAD = boost::get<bool>((*vars)["ad"]);
1802 }
1803 if (vars->count("ra")) {
1804 config.setRA = boost::get<bool>((*vars)["ra"]);
1805 }
1806 }
1807 }
1808
1809 void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config)
1810 {
1811 if (config.setAA) {
1812 dh.aa = *config.setAA;
1813 }
1814 if (config.setAD) {
1815 dh.ad = *config.setAD;
1816 }
1817 else {
1818 dh.ad = false;
1819 }
1820 if (config.setRA) {
1821 dh.ra = *config.setRA;
1822 }
1823 else {
1824 dh.ra = dh.rd; // for good measure
1825 }
1826 }
1827
1828 void setupLuaActions(LuaContext& luaCtx)
1829 {
1830 luaCtx.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
1831 boost::uuids::uuid uuid;
1832 uint64_t creationOrder;
1833 std::string name;
1834 parseRuleParams(params, uuid, name, creationOrder);
1835
1836 auto rule = makeRule(dnsrule);
1837 DNSDistRuleAction ra({std::move(rule), action, std::move(name), uuid, creationOrder});
1838 return std::make_shared<DNSDistRuleAction>(ra);
1839 });
1840
1841 luaCtx.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1842 if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
1843 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
1844 }
1845
1846 addAction(&g_ruleactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
1847 });
1848
1849 luaCtx.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1850 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1851 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1852 }
1853
1854 addAction(&g_respruleactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1855 });
1856
1857 luaCtx.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1858 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1859 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1860 }
1861
1862 addAction(&g_cachehitrespruleactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1863 });
1864
1865 luaCtx.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1866 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1867 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1868 }
1869
1870 addAction(&g_selfansweredrespruleactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1871 });
1872
1873 luaCtx.registerFunction<void(DNSAction::*)()const>("printStats", [](const DNSAction& ta) {
1874 setLuaNoSideEffect();
1875 auto stats = ta.getStats();
1876 for(const auto& s : stats) {
1877 g_outputBuffer+=s.first+"\t";
1878 if((uint64_t)s.second == s.second)
1879 g_outputBuffer += std::to_string((uint64_t)s.second)+"\n";
1880 else
1881 g_outputBuffer += std::to_string(s.second)+"\n";
1882 }
1883 });
1884
1885 luaCtx.writeFunction("getAction", [](unsigned int num) {
1886 setLuaNoSideEffect();
1887 boost::optional<std::shared_ptr<DNSAction>> ret;
1888 auto ruleactions = g_ruleactions.getCopy();
1889 if(num < ruleactions.size())
1890 ret=ruleactions[num].d_action;
1891 return ret;
1892 });
1893
1894 luaCtx.registerFunction("getStats", &DNSAction::getStats);
1895 luaCtx.registerFunction("reload", &DNSAction::reload);
1896 luaCtx.registerFunction("reload", &DNSResponseAction::reload);
1897
1898 luaCtx.writeFunction("LuaAction", [](LuaAction::func_t func) {
1899 setLuaSideEffect();
1900 return std::shared_ptr<DNSAction>(new LuaAction(func));
1901 });
1902
1903 luaCtx.writeFunction("LuaFFIAction", [](LuaFFIAction::func_t func) {
1904 setLuaSideEffect();
1905 return std::shared_ptr<DNSAction>(new LuaFFIAction(func));
1906 });
1907
1908 luaCtx.writeFunction("LuaFFIPerThreadAction", [](std::string code) {
1909 setLuaSideEffect();
1910 return std::shared_ptr<DNSAction>(new LuaFFIPerThreadAction(code));
1911 });
1912
1913 luaCtx.writeFunction("SetNoRecurseAction", []() {
1914 return std::shared_ptr<DNSAction>(new SetNoRecurseAction);
1915 });
1916
1917 luaCtx.writeFunction("NoRecurseAction", []() {
1918 warnlog("access to NoRecurseAction is deprecated and will be removed in a future version, please use SetNoRecurseAction instead");
1919 return std::shared_ptr<DNSAction>(new SetNoRecurseAction);
1920 });
1921
1922 luaCtx.writeFunction("SetMacAddrAction", [](int code) {
1923 return std::shared_ptr<DNSAction>(new SetMacAddrAction(code));
1924 });
1925
1926 luaCtx.writeFunction("MacAddrAction", [](int code) {
1927 warnlog("access to MacAddrAction is deprecated and will be removed in a future version, please use SetMacAddrAction instead");
1928 return std::shared_ptr<DNSAction>(new SetMacAddrAction(code));
1929 });
1930
1931 luaCtx.writeFunction("PoolAction", [](const std::string& a) {
1932 return std::shared_ptr<DNSAction>(new PoolAction(a));
1933 });
1934
1935 luaCtx.writeFunction("QPSAction", [](int limit) {
1936 return std::shared_ptr<DNSAction>(new QPSAction(limit));
1937 });
1938
1939 luaCtx.writeFunction("QPSPoolAction", [](int limit, const std::string& a) {
1940 return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
1941 });
1942
1943 luaCtx.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<responseParams_t> vars) {
1944 vector<ComboAddress> addrs;
1945 if(auto s = boost::get<std::string>(&inp)) {
1946 addrs.push_back(ComboAddress(*s));
1947 } else {
1948 const auto& v = boost::get<vector<pair<int,std::string>>>(inp);
1949 for(const auto& a: v) {
1950 addrs.push_back(ComboAddress(a.second));
1951 }
1952 }
1953
1954 auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs));
1955 auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
1956 parseResponseConfig(vars, sa->d_responseConfig);
1957 return ret;
1958 });
1959
1960 luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<responseParams_t> vars) {
1961 auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(a)));
1962 auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
1963 parseResponseConfig(vars, sa->d_responseConfig);
1964 return ret;
1965 });
1966
1967 luaCtx.writeFunction("SpoofRawAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<responseParams_t> vars) {
1968 vector<string> raws;
1969 if(auto s = boost::get<std::string>(&inp)) {
1970 raws.push_back(*s);
1971 } else {
1972 const auto& v = boost::get<vector<pair<int,std::string>>>(inp);
1973 for(const auto& raw: v) {
1974 raws.push_back(raw.second);
1975 }
1976 }
1977
1978 auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raws));
1979 auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
1980 parseResponseConfig(vars, sa->d_responseConfig);
1981 return ret;
1982 });
1983
1984 luaCtx.writeFunction("DropAction", []() {
1985 return std::shared_ptr<DNSAction>(new DropAction);
1986 });
1987
1988 luaCtx.writeFunction("AllowAction", []() {
1989 return std::shared_ptr<DNSAction>(new AllowAction);
1990 });
1991
1992 luaCtx.writeFunction("NoneAction", []() {
1993 return std::shared_ptr<DNSAction>(new NoneAction);
1994 });
1995
1996 luaCtx.writeFunction("DelayAction", [](int msec) {
1997 return std::shared_ptr<DNSAction>(new DelayAction(msec));
1998 });
1999
2000 luaCtx.writeFunction("TCAction", []() {
2001 return std::shared_ptr<DNSAction>(new TCAction);
2002 });
2003
2004 luaCtx.writeFunction("SetDisableValidationAction", []() {
2005 return std::shared_ptr<DNSAction>(new SetDisableValidationAction);
2006 });
2007
2008 luaCtx.writeFunction("DisableValidationAction", []() {
2009 warnlog("access to DisableValidationAction is deprecated and will be removed in a future version, please use SetDisableValidationAction instead");
2010 return std::shared_ptr<DNSAction>(new SetDisableValidationAction);
2011 });
2012
2013 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) {
2014 return std::shared_ptr<DNSAction>(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
2015 });
2016
2017 luaCtx.writeFunction("LogResponseAction", [](boost::optional<std::string> fname, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
2018 return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
2019 });
2020
2021 luaCtx.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
2022 auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode));
2023 auto rca = std::dynamic_pointer_cast<RCodeAction>(ret);
2024 parseResponseConfig(vars, rca->d_responseConfig);
2025 return ret;
2026 });
2027
2028 luaCtx.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
2029 auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
2030 auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret);
2031 parseResponseConfig(vars, erca->d_responseConfig);
2032 return ret;
2033 });
2034
2035 luaCtx.writeFunction("SetSkipCacheAction", []() {
2036 return std::shared_ptr<DNSAction>(new SetSkipCacheAction);
2037 });
2038
2039 luaCtx.writeFunction("SkipCacheAction", []() {
2040 warnlog("access to SkipCacheAction is deprecated and will be removed in a future version, please use SetSkipCacheAction instead");
2041 return std::shared_ptr<DNSAction>(new SetSkipCacheAction);
2042 });
2043
2044 luaCtx.writeFunction("SetSkipCacheResponseAction", []() {
2045 return std::shared_ptr<DNSResponseAction>(new SetSkipCacheResponseAction);
2046 });
2047
2048 luaCtx.writeFunction("SetTempFailureCacheTTLAction", [](int maxTTL) {
2049 return std::shared_ptr<DNSAction>(new SetTempFailureCacheTTLAction(maxTTL));
2050 });
2051
2052 luaCtx.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
2053 warnlog("access to TempFailureCacheTTLAction is deprecated and will be removed in a future version, please use SetTempFailureCacheTTLAction instead");
2054 return std::shared_ptr<DNSAction>(new SetTempFailureCacheTTLAction(maxTTL));
2055 });
2056
2057 luaCtx.writeFunction("DropResponseAction", []() {
2058 return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
2059 });
2060
2061 luaCtx.writeFunction("AllowResponseAction", []() {
2062 return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
2063 });
2064
2065 luaCtx.writeFunction("DelayResponseAction", [](int msec) {
2066 return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
2067 });
2068
2069 luaCtx.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
2070 setLuaSideEffect();
2071 return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
2072 });
2073
2074 luaCtx.writeFunction("LuaFFIResponseAction", [](LuaFFIResponseAction::func_t func) {
2075 setLuaSideEffect();
2076 return std::shared_ptr<DNSResponseAction>(new LuaFFIResponseAction(func));
2077 });
2078
2079 luaCtx.writeFunction("LuaFFIPerThreadResponseAction", [](std::string code) {
2080 setLuaSideEffect();
2081 return std::shared_ptr<DNSResponseAction>(new LuaFFIPerThreadResponseAction(code));
2082 });
2083
2084 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) {
2085 if (logger) {
2086 // avoids potentially-evaluated-expression warning with clang.
2087 RemoteLoggerInterface& rl = *logger.get();
2088 if (typeid(rl) != typeid(RemoteLogger)) {
2089 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
2090 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
2091 }
2092 }
2093
2094 std::string serverID;
2095 std::string ipEncryptKey;
2096 if (vars) {
2097 if (vars->count("serverID")) {
2098 serverID = boost::get<std::string>((*vars)["serverID"]);
2099 }
2100 if (vars->count("ipEncryptKey")) {
2101 ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]);
2102 }
2103 }
2104
2105 return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey));
2106 });
2107
2108 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) {
2109 if (logger) {
2110 // avoids potentially-evaluated-expression warning with clang.
2111 RemoteLoggerInterface& rl = *logger.get();
2112 if (typeid(rl) != typeid(RemoteLogger)) {
2113 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
2114 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
2115 }
2116 }
2117
2118 std::string serverID;
2119 std::string ipEncryptKey;
2120 if (vars) {
2121 if (vars->count("serverID")) {
2122 serverID = boost::get<std::string>((*vars)["serverID"]);
2123 }
2124 if (vars->count("ipEncryptKey")) {
2125 ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]);
2126 }
2127 }
2128
2129 return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false));
2130 });
2131
2132 luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
2133 return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
2134 });
2135
2136 luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
2137 return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
2138 });
2139
2140 luaCtx.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
2141 return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false));
2142 });
2143
2144 luaCtx.writeFunction("SetECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
2145 return std::shared_ptr<DNSAction>(new SetECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
2146 });
2147
2148 luaCtx.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
2149 warnlog("access to ECSPrefixLengthAction is deprecated and will be removed in a future version, please use SetECSPrefixLengthAction instead");
2150 return std::shared_ptr<DNSAction>(new SetECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
2151 });
2152
2153 luaCtx.writeFunction("SetECSOverrideAction", [](bool ecsOverride) {
2154 return std::shared_ptr<DNSAction>(new SetECSOverrideAction(ecsOverride));
2155 });
2156
2157 luaCtx.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
2158 warnlog("access to ECSOverrideAction is deprecated and will be removed in a future version, please use SetECSOverrideAction instead");
2159 return std::shared_ptr<DNSAction>(new SetECSOverrideAction(ecsOverride));
2160 });
2161
2162 luaCtx.writeFunction("SetDisableECSAction", []() {
2163 return std::shared_ptr<DNSAction>(new SetDisableECSAction());
2164 });
2165
2166 luaCtx.writeFunction("DisableECSAction", []() {
2167 warnlog("access to DisableECSAction is deprecated and will be removed in a future version, please use SetDisableECSAction instead");
2168 return std::shared_ptr<DNSAction>(new SetDisableECSAction());
2169 });
2170
2171 luaCtx.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) {
2172 if (v6) {
2173 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6)));
2174 }
2175 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4)));
2176 });
2177
2178 luaCtx.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
2179 #ifdef HAVE_NET_SNMP
2180 return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
2181 #else
2182 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
2183 #endif /* HAVE_NET_SNMP */
2184 });
2185
2186 luaCtx.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
2187 #ifdef HAVE_NET_SNMP
2188 return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
2189 #else
2190 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
2191 #endif /* HAVE_NET_SNMP */
2192 });
2193
2194 luaCtx.writeFunction("SetTagAction", [](std::string tag, std::string value) {
2195 return std::shared_ptr<DNSAction>(new SetTagAction(tag, value));
2196 });
2197
2198 luaCtx.writeFunction("TagAction", [](std::string tag, std::string value) {
2199 warnlog("access to TagAction is deprecated and will be removed in a future version, please use SetTagAction instead");
2200 return std::shared_ptr<DNSAction>(new SetTagAction(tag, value));
2201 });
2202
2203 luaCtx.writeFunction("SetTagResponseAction", [](std::string tag, std::string value) {
2204 return std::shared_ptr<DNSResponseAction>(new SetTagResponseAction(tag, value));
2205 });
2206
2207 luaCtx.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
2208 warnlog("access to TagResponseAction is deprecated and will be removed in a future version, please use SetTagResponseAction instead");
2209 return std::shared_ptr<DNSResponseAction>(new SetTagResponseAction(tag, value));
2210 });
2211
2212 luaCtx.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
2213 return std::shared_ptr<DNSAction>(new ContinueAction(action));
2214 });
2215
2216 #ifdef HAVE_DNS_OVER_HTTPS
2217 luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
2218 auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : ""));
2219 auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
2220 parseResponseConfig(vars, hsa->d_responseConfig);
2221 return ret;
2222 });
2223 #endif /* HAVE_DNS_OVER_HTTPS */
2224
2225 luaCtx.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
2226 return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
2227 });
2228
2229 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) {
2230 auto ret = std::shared_ptr<DNSAction>(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum));
2231 auto action = std::dynamic_pointer_cast<NegativeAndSOAAction>(ret);
2232 parseResponseConfig(vars, action->d_responseConfig);
2233 return ret;
2234 });
2235
2236 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) {
2237 warnlog("access to SetNegativeAndSOAAction is deprecated and will be removed in a future version, please use NegativeAndSOAAction instead");
2238 auto ret = std::shared_ptr<DNSAction>(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum));
2239 auto action = std::dynamic_pointer_cast<NegativeAndSOAAction>(ret);
2240 parseResponseConfig(vars, action->d_responseConfig);
2241 return ret;
2242 });
2243
2244 luaCtx.writeFunction("SetProxyProtocolValuesAction", [](const std::vector<std::pair<uint8_t, std::string>>& values) {
2245 return std::shared_ptr<DNSAction>(new SetProxyProtocolValuesAction(values));
2246 });
2247
2248 luaCtx.writeFunction("SetAdditionalProxyProtocolValueAction", [](uint8_t type, const std::string& value) {
2249 return std::shared_ptr<DNSAction>(new SetAdditionalProxyProtocolValueAction(type, value));
2250 });
2251 }