2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
23 #include "threadname.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"
33 #include "ednsoptions.hh"
34 #include "fstrm_logger.hh"
35 #include "remote_logger.hh"
37 #include <boost/optional/optional_io.hpp>
40 #include "ipcipher.hh"
41 #endif /* HAVE_LIBCRYPTO */
43 class DropAction
: public DNSAction
46 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
50 std::string
toString() const override
56 class AllowAction
: public DNSAction
59 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
63 std::string
toString() const override
69 class NoneAction
: public DNSAction
72 // this action does not stop the processing
73 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
77 std::string
toString() const override
83 class QPSAction
: public DNSAction
86 QPSAction(int limit
) : d_qps(limit
, limit
)
89 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
91 std::lock_guard
<decltype(d_lock
)> guard(d_lock
);
99 std::string
toString() const override
101 return "qps limit to "+std::to_string(d_qps
.getRate());
104 mutable std::mutex d_lock
;
108 class DelayAction
: public DNSAction
111 DelayAction(int msec
) : d_msec(msec
)
114 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
116 *ruleresult
= std::to_string(d_msec
);
117 return Action::Delay
;
119 std::string
toString() const override
121 return "delay by "+std::to_string(d_msec
)+ " msec";
127 class TeeAction
: public DNSAction
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
;
138 ComboAddress d_remote
;
139 std::thread d_worker
;
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};
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};
159 TeeAction::TeeAction(const ComboAddress
& ca
, bool addECS
) : d_remote(ca
), d_addECS(addECS
)
161 d_fd
=SSocket(d_remote
.sin4
.sin_family
, SOCK_DGRAM
, 0);
163 SConnect(d_fd
, d_remote
);
164 setNonBlocking(d_fd
);
165 d_worker
=std::thread([this](){worker();});
175 TeeAction::~TeeAction()
182 DNSAction::Action
TeeAction::operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const
192 PacketBuffer
query(dq
->getData());
193 bool ednsAdded
= false;
194 bool ecsAdded
= false;
196 std::string newECSOption
;
197 generateECSOption(dq
->ecsSet
? dq
->ecs
.getNetwork() : *dq
->remote
, newECSOption
, dq
->ecsSet
? dq
->ecs
.getBits() : dq
->ecsPrefixLength
);
199 if (!handleEDNSClientSubnet(query
, dq
->getMaximumSize(), dq
->qname
->wirelength(), ednsAdded
, ecsAdded
, dq
->ecsOverride
, newECSOption
)) {
200 return DNSAction::Action::None
;
203 res
= send(d_fd
, query
.data(), query
.size(), 0);
206 res
= send(d_fd
, dq
->getData().data(), dq
->getData().size(), 0);
214 return DNSAction::Action::None
;
217 std::string
TeeAction::toString() const
219 return "tee to "+d_remote
.toStringWithPort();
222 std::map
<std::string
,double> TeeAction::getStats() const
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
}
237 void TeeAction::worker()
239 setThreadName("dnsdist/TeeWork");
242 struct dnsheader
* dh
=(struct dnsheader
*)packet
;
244 res
=waitForData(d_fd
, 0, 250000);
253 res
=recv(d_fd
, packet
, sizeof(packet
), 0);
254 if(res
<= (int)sizeof(struct dnsheader
))
259 if(dh
->rcode
== RCode::NoError
)
261 else if(dh
->rcode
== RCode::ServFail
)
263 else if(dh
->rcode
== RCode::NXDomain
)
265 else if(dh
->rcode
== RCode::Refused
)
267 else if(dh
->rcode
== RCode::FormErr
)
269 else if(dh
->rcode
== RCode::NotImp
)
274 class PoolAction
: public DNSAction
277 PoolAction(const std::string
& pool
) : d_pool(pool
) {}
278 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
283 std::string
toString() const override
285 return "to pool "+d_pool
;
293 class QPSPoolAction
: public DNSAction
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
299 std::lock_guard
<decltype(d_lock
)> guard(d_lock
);
301 *ruleresult
= d_pool
;
308 std::string
toString() const override
310 return "max " +std::to_string(d_qps
.getRate())+" to pool "+d_pool
;
314 mutable std::mutex d_lock
;
319 class RCodeAction
: public DNSAction
322 RCodeAction(uint8_t rcode
) : d_rcode(rcode
) {}
323 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
325 dq
->getHeader()->rcode
= d_rcode
;
326 dq
->getHeader()->qr
= true; // for good measure
327 setResponseHeadersFromConfig(*dq
->getHeader(), d_responseConfig
);
328 return Action::HeaderModify
;
330 std::string
toString() const override
332 return "set rcode "+std::to_string(d_rcode
);
335 ResponseConfig d_responseConfig
;
340 class ERCodeAction
: public DNSAction
343 ERCodeAction(uint8_t rcode
) : d_rcode(rcode
) {}
344 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
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
;
352 std::string
toString() const override
354 return "set ercode "+ERCode::to_s(d_rcode
);
357 ResponseConfig d_responseConfig
;
362 class TCAction
: public DNSAction
365 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
367 return Action::Truncate
;
369 std::string
toString() const override
371 return "tc=1 answer";
375 class LuaAction
: public DNSAction
378 typedef std::function
<std::tuple
<int, boost::optional
<string
> >(DNSQuestion
* dq
)> func_t
;
379 LuaAction(const LuaAction::func_t
& func
) : d_func(func
)
382 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
384 std::lock_guard
<std::mutex
> lock(g_luamutex
);
386 auto ret
= d_func(dq
);
388 if (boost::optional
<std::string
> rule
= std::get
<1>(ret
)) {
392 // default to empty string
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());
400 warnlog("LuaAction failed inside Lua, returning ServFail: [unknown exception]");
402 return DNSAction::Action::ServFail
;
405 string
toString() const override
413 class LuaResponseAction
: public DNSResponseAction
416 typedef std::function
<std::tuple
<int, boost::optional
<string
> >(DNSResponse
* dr
)> func_t
;
417 LuaResponseAction(const LuaResponseAction::func_t
& func
) : d_func(func
)
419 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
421 std::lock_guard
<std::mutex
> lock(g_luamutex
);
423 auto ret
= d_func(dr
);
425 if (boost::optional
<std::string
> rule
= std::get
<1>(ret
)) {
429 // default to empty string
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());
437 warnlog("LuaResponseAction failed inside Lua, returning ServFail: [unknown exception]");
439 return DNSResponseAction::Action::ServFail
;
442 string
toString() const override
444 return "Lua response script";
450 class LuaFFIAction
: public DNSAction
453 typedef std::function
<int(dnsdist_ffi_dnsquestion_t
* dq
)> func_t
;
455 LuaFFIAction(const LuaFFIAction::func_t
& func
): d_func(func
)
459 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
461 dnsdist_ffi_dnsquestion_t
dqffi(dq
);
463 std::lock_guard
<std::mutex
> lock(g_luamutex
);
465 auto ret
= d_func(&dqffi
);
468 *ruleresult
= *dqffi
.result
;
471 // default to empty string
475 return static_cast<DNSAction::Action
>(ret
);
476 } catch (const std::exception
&e
) {
477 warnlog("LuaFFIAction failed inside Lua, returning ServFail: %s", e
.what());
479 warnlog("LuaFFIAction failed inside Lua, returning ServFail: [unknown exception]");
481 return DNSAction::Action::ServFail
;
484 string
toString() const override
486 return "Lua FFI script";
493 class LuaFFIResponseAction
: public DNSResponseAction
496 typedef std::function
<int(dnsdist_ffi_dnsquestion_t
* dq
)> func_t
;
498 LuaFFIResponseAction(const LuaFFIResponseAction::func_t
& func
): d_func(func
)
502 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
504 DNSQuestion
* dq
= dynamic_cast<DNSQuestion
*>(dr
);
506 return DNSResponseAction::Action::ServFail
;
509 dnsdist_ffi_dnsquestion_t
dqffi(dq
);
511 std::lock_guard
<std::mutex
> lock(g_luamutex
);
513 auto ret
= d_func(&dqffi
);
516 *ruleresult
= *dqffi
.result
;
519 // default to empty string
523 return static_cast<DNSResponseAction::Action
>(ret
);
524 } catch (const std::exception
&e
) {
525 warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: %s", e
.what());
527 warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: [unknown exception]");
529 return DNSResponseAction::Action::ServFail
;
532 string
toString() const override
534 return "Lua FFI script";
540 thread_local
std::default_random_engine
SpoofAction::t_randomEngine
;
542 DNSAction::Action
SpoofAction::operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const
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) {
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();
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
);
567 if (rawResponses
.size() > 1) {
568 shuffle(rawResponses
.begin(), rawResponses
.end(), t_randomEngine
);
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
))) {
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
);
583 if (addrs
.size() > 1) {
584 shuffle(addrs
.begin(), addrs
.end(), t_randomEngine
);
587 unsigned int qnameWireLength
=0;
588 DNSName
ignore((char*)dq
->getData().data(), dq
->getData().size(), sizeof(dnsheader
), false, 0, 0, &qnameWireLength
);
590 if (dq
->getMaximumSize() < (sizeof(dnsheader
) + qnameWireLength
+ 4 + numberOfRecords
*12 /* recordstart */ + totrdatalen
)) {
594 bool dnssecOK
= false;
595 bool hadEDNS
= false;
596 if (g_addEDNSToSelfGeneratedResponses
&& queryHasEDNS(*dq
)) {
598 dnssecOK
= getEDNSZ(*dq
) & EDNS_HEADER_FLAG_DO
;
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));
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
610 uint32_t ttl
= htonl(d_responseConfig
.ttl
);
611 unsigned char recordstart
[] = {0xc0, 0x0c, // compressed name
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
));
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
));
627 memcpy(dest
, recordstart
, sizeof(recordstart
));
628 dest
+= sizeof(recordstart
);
629 memcpy(dest
, wireData
.c_str(), wireData
.length());
630 dq
->getHeader()->ancount
++;
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
));
639 memcpy(dest
, recordstart
, sizeof(recordstart
));
640 dest
+= sizeof(recordstart
);
642 memcpy(dest
, rawResponse
.c_str(), rawResponse
.size());
643 dest
+= rawResponse
.size();
645 dq
->getHeader()->ancount
++;
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
));
656 memcpy(dest
, recordstart
, sizeof(recordstart
));
657 dest
+= sizeof(recordstart
);
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
++;
667 dq
->getHeader()->ancount
= htons(dq
->getHeader()->ancount
);
669 if (hadEDNS
&& raw
== false) {
670 addEDNS(dq
->getMutableData(), dq
->getMaximumSize(), dnssecOK
, g_PayloadSizeSelfGenAnswers
, 0);
673 return Action::HeaderModify
;
676 class SetMacAddrAction
: public DNSAction
679 // this action does not stop the processing
680 SetMacAddrAction(uint16_t code
) : d_code(code
)
682 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
684 if (dq
->getHeader()->arcount
) {
688 std::string mac
= getMACAddress(*dq
->remote
);
693 std::string optRData
;
694 generateEDNSOption(d_code
, mac
, optRData
);
696 auto& data
= dq
->getMutableData();
697 if (generateOptRR(optRData
, data
, dq
->getMaximumSize(), g_EdnsUDPPayloadSize
, 0, false)) {
698 dq
->getHeader()->arcount
= htons(1);
703 std::string
toString() const override
705 return "add EDNS MAC (code="+std::to_string(d_code
)+")";
711 class SetNoRecurseAction
: public DNSAction
714 // this action does not stop the processing
715 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
717 dq
->getHeader()->rd
= false;
720 std::string
toString() const override
726 class LogAction
: public DNSAction
, public boost::noncopyable
729 // this action does not stop the processing
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
)
740 if (!reopenLogFile()) {
741 throw std::runtime_error("Unable to open file '" + str
+ "' for logging: " + stringerror());
745 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
747 auto fp
= std::atomic_load_explicit(&d_fp
, std::memory_order_acquire
);
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
);
754 infolog("Packet from %s for %s %s with id %d", dq
->remote
->toStringWithPort(), dq
->qname
->toString(), QType(dq
->qtype
).toString(), dq
->getHeader()->id
);
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());
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());
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());
778 fwrite(&dq
->remote
->sin4
.sin_port
, sizeof(dq
->remote
->sin4
.sin_port
), 1, fp
.get());
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
);
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
);
792 std::string
toString() const override
794 if (!d_fname
.empty()) {
795 return "log to " + d_fname
;
800 void reload() override
802 if (!reopenLogFile()) {
803 warnlog("Unable to open file '%s' for logging: %s", d_fname
, stringerror());
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");
815 /* don't fall on our sword when reopening */
819 auto fp
= std::shared_ptr
<FILE>(nfp
, fclose
);
826 std::atomic_store_explicit(&d_fp
, fp
, std::memory_order_release
);
831 std::shared_ptr
<FILE> d_fp
{nullptr};
833 bool d_verboseOnly
{true};
834 bool d_includeTimestamp
{false};
835 bool d_append
{false};
836 bool d_buffered
{true};
839 class LogResponseAction
: public DNSResponseAction
, public boost::noncopyable
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
)
852 if (!reopenLogFile()) {
853 throw std::runtime_error("Unable to open file '" + str
+ "' for logging: " + stringerror());
857 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
859 auto fp
= std::atomic_load_explicit(&d_fp
, std::memory_order_acquire
);
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
);
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
);
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
);
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
);
881 std::string
toString() const override
883 if (!d_fname
.empty()) {
884 return "log to " + d_fname
;
889 void reload() override
891 if (!reopenLogFile()) {
892 warnlog("Unable to open file '%s' for logging: %s", d_fname
, stringerror());
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");
904 /* don't fall on our sword when reopening */
908 auto fp
= std::shared_ptr
<FILE>(nfp
, fclose
);
915 std::atomic_store_explicit(&d_fp
, fp
, std::memory_order_release
);
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};
928 class SetDisableValidationAction
: public DNSAction
931 // this action does not stop the processing
932 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
934 dq
->getHeader()->cd
= true;
937 std::string
toString() const override
943 class SetSkipCacheAction
: public DNSAction
946 // this action does not stop the processing
947 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
949 dq
->skipCache
= true;
952 std::string
toString() const override
958 class SetSkipCacheResponseAction
: public DNSResponseAction
961 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
963 dr
->skipCache
= true;
966 std::string
toString() const override
972 class SetTempFailureCacheTTLAction
: public DNSAction
975 // this action does not stop the processing
976 SetTempFailureCacheTTLAction(uint32_t ttl
) : d_ttl(ttl
)
979 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
981 dq
->tempFailureTTL
= d_ttl
;
984 std::string
toString() const override
986 return "set tempfailure cache ttl to "+std::to_string(d_ttl
);
992 class SetECSPrefixLengthAction
: public DNSAction
995 // this action does not stop the processing
996 SetECSPrefixLengthAction(uint16_t v4Length
, uint16_t v6Length
) : d_v4PrefixLength(v4Length
), d_v6PrefixLength(v6Length
)
999 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1001 dq
->ecsPrefixLength
= dq
->remote
->sin4
.sin_family
== AF_INET
? d_v4PrefixLength
: d_v6PrefixLength
;
1002 return Action::None
;
1004 std::string
toString() const override
1006 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength
) + "/" + std::to_string(d_v6PrefixLength
);
1009 uint16_t d_v4PrefixLength
;
1010 uint16_t d_v6PrefixLength
;
1013 class SetECSOverrideAction
: public DNSAction
1016 // this action does not stop the processing
1017 SetECSOverrideAction(bool ecsOverride
) : d_ecsOverride(ecsOverride
)
1020 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1022 dq
->ecsOverride
= d_ecsOverride
;
1023 return Action::None
;
1025 std::string
toString() const override
1027 return "set ECS override to " + std::to_string(d_ecsOverride
);
1034 class SetDisableECSAction
: public DNSAction
1037 // this action does not stop the processing
1038 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1041 return Action::None
;
1043 std::string
toString() const override
1045 return "disable ECS";
1049 class SetECSAction
: public DNSAction
1052 // this action does not stop the processing
1053 SetECSAction(const Netmask
& v4
): d_v4(v4
), d_hasV6(false)
1057 SetECSAction(const Netmask
& v4
, const Netmask
& v6
): d_v4(v4
), d_v6(v6
), d_hasV6(true)
1061 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1066 dq
->ecs
= dq
->remote
->isIPv4() ? d_v4
: d_v6
;
1072 return Action::None
;
1075 std::string
toString() const override
1077 std::string result
= "set ECS to " + d_v4
.toString();
1079 result
+= " / " + d_v6
.toString();
1090 static DnstapMessage::ProtocolType
ProtocolToDNSTap(DNSQuestion::Protocol protocol
)
1092 DnstapMessage::ProtocolType result
;
1095 case DNSQuestion::Protocol::DoUDP
:
1096 case DNSQuestion::Protocol::DNSCryptUDP
:
1097 result
= DnstapMessage::ProtocolType::DoUDP
;
1099 case DNSQuestion::Protocol::DoTCP
:
1100 case DNSQuestion::Protocol::DNSCryptTCP
:
1101 result
= DnstapMessage::ProtocolType::DoTCP
;
1103 case DNSQuestion::Protocol::DoT
:
1104 result
= DnstapMessage::ProtocolType::DoT
;
1106 case DNSQuestion::Protocol::DoH
:
1107 result
= DnstapMessage::ProtocolType::DoH
;
1113 class DnstapLogAction
: public DNSAction
, public boost::noncopyable
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
)
1120 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1122 static thread_local
std::string data
;
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);
1129 std::lock_guard
<std::mutex
> lock(g_luamutex
);
1130 (*d_alterFunc
)(dq
, &message
);
1134 d_logger
->queueData(data
);
1136 return Action::None
;
1138 std::string
toString() const override
1140 return "remote log as dnstap to " + (d_logger
? d_logger
->toString() : "");
1143 std::string d_identity
;
1144 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
1145 boost::optional
<std::function
<void(DNSQuestion
*, DnstapMessage
*)> > d_alterFunc
;
1148 class RemoteLogAction
: public DNSAction
, public boost::noncopyable
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
)
1155 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1157 if (!dq
->uniqueId
) {
1158 dq
->uniqueId
= getUniqueID();
1161 DNSDistProtoBufMessage
message(*dq
);
1162 if (!d_serverID
.empty()) {
1163 message
.setServerIdentity(d_serverID
);
1167 if (!d_ipEncryptKey
.empty())
1169 message
.setRequestor(encryptCA(*dq
->remote
, d_ipEncryptKey
));
1171 #endif /* HAVE_LIBCRYPTO */
1174 std::lock_guard
<std::mutex
> lock(g_luamutex
);
1175 (*d_alterFunc
)(dq
, &message
);
1178 static thread_local
std::string data
;
1180 message
.serialize(data
);
1181 d_logger
->queueData(data
);
1183 return Action::None
;
1185 std::string
toString() const override
1187 return "remote log to " + (d_logger
? d_logger
->toString() : "");
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
;
1196 class SNMPTrapAction
: public DNSAction
1199 // this action does not stop the processing
1200 SNMPTrapAction(const std::string
& reason
): d_reason(reason
)
1203 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1205 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
1206 g_snmpAgent
->sendDNSTrap(*dq
, d_reason
);
1209 return Action::None
;
1211 std::string
toString() const override
1213 return "send SNMP trap";
1216 std::string d_reason
;
1219 class SetTagAction
: public DNSAction
1222 // this action does not stop the processing
1223 SetTagAction(const std::string
& tag
, const std::string
& value
): d_tag(tag
), d_value(value
)
1226 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1229 dq
->qTag
= std::make_shared
<QTag
>();
1232 dq
->qTag
->insert({d_tag
, d_value
});
1234 return Action::None
;
1236 std::string
toString() const override
1238 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
1242 std::string d_value
;
1245 class DnstapLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
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
)
1252 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1254 static thread_local
std::string data
;
1255 struct timespec now
;
1256 gettime(&now
, true);
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
);
1263 std::lock_guard
<std::mutex
> lock(g_luamutex
);
1264 (*d_alterFunc
)(dr
, &message
);
1268 d_logger
->queueData(data
);
1270 return Action::None
;
1272 std::string
toString() const override
1274 return "log response as dnstap to " + (d_logger
? d_logger
->toString() : "");
1277 std::string d_identity
;
1278 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
1279 boost::optional
<std::function
<void(DNSResponse
*, DnstapMessage
*)> > d_alterFunc
;
1282 class RemoteLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
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
)
1289 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1291 if (!dr
->uniqueId
) {
1292 dr
->uniqueId
= getUniqueID();
1295 DNSDistProtoBufMessage
message(*dr
, d_includeCNAME
);
1296 if (!d_serverID
.empty()) {
1297 message
.setServerIdentity(d_serverID
);
1301 if (!d_ipEncryptKey
.empty())
1303 message
.setRequestor(encryptCA(*dr
->remote
, d_ipEncryptKey
));
1305 #endif /* HAVE_LIBCRYPTO */
1308 std::lock_guard
<std::mutex
> lock(g_luamutex
);
1309 (*d_alterFunc
)(dr
, &message
);
1312 static thread_local
std::string data
;
1314 message
.serialize(data
);
1315 d_logger
->queueData(data
);
1317 return Action::None
;
1319 std::string
toString() const override
1321 return "remote log response to " + (d_logger
? d_logger
->toString() : "");
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
;
1331 class DropResponseAction
: public DNSResponseAction
1334 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1336 return Action::Drop
;
1338 std::string
toString() const override
1344 class AllowResponseAction
: public DNSResponseAction
1347 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1349 return Action::Allow
;
1351 std::string
toString() const override
1357 class DelayResponseAction
: public DNSResponseAction
1360 DelayResponseAction(int msec
) : d_msec(msec
)
1363 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1365 *ruleresult
= std::to_string(d_msec
);
1366 return Action::Delay
;
1368 std::string
toString() const override
1370 return "delay by "+std::to_string(d_msec
)+ " msec";
1376 class SNMPTrapResponseAction
: public DNSResponseAction
1379 // this action does not stop the processing
1380 SNMPTrapResponseAction(const std::string
& reason
): d_reason(reason
)
1383 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1385 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
1386 g_snmpAgent
->sendDNSTrap(*dr
, d_reason
);
1389 return Action::None
;
1391 std::string
toString() const override
1393 return "send SNMP trap";
1396 std::string d_reason
;
1399 class SetTagResponseAction
: public DNSResponseAction
1402 // this action does not stop the processing
1403 SetTagResponseAction(const std::string
& tag
, const std::string
& value
): d_tag(tag
), d_value(value
)
1406 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1409 dr
->qTag
= std::make_shared
<QTag
>();
1412 dr
->qTag
->insert({d_tag
, d_value
});
1414 return Action::None
;
1416 std::string
toString() const override
1418 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
1422 std::string d_value
;
1425 class ContinueAction
: public DNSAction
1428 // this action does not stop the processing
1429 ContinueAction(std::shared_ptr
<DNSAction
>& action
): d_action(action
)
1433 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1436 /* call the action */
1437 auto action
= (*d_action
)(dq
, ruleresult
);
1439 /* apply the changes if needed (pool selection, flags, etc */
1440 processRulesResult(action
, *dq
, *ruleresult
, drop
);
1443 /* but ignore the resulting action no matter what */
1444 return Action::None
;
1447 std::string
toString() const override
1450 return "continue after: " + (d_action
? d_action
->toString() : "");
1458 std::shared_ptr
<DNSAction
> d_action
;
1461 #ifdef HAVE_DNS_OVER_HTTPS
1462 class HTTPStatusAction
: public DNSAction
1465 HTTPStatusAction(int code
, const PacketBuffer
& body
, const std::string
& contentType
): d_body(body
), d_contentType(contentType
), d_code(code
)
1469 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1472 return Action::None
;
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
;
1481 std::string
toString() const override
1483 return "return an HTTP status of " + std::to_string(d_code
);
1486 ResponseConfig d_responseConfig
;
1488 PacketBuffer d_body
;
1489 std::string d_contentType
;
1492 #endif /* HAVE_DNS_OVER_HTTPS */
1494 class KeyValueStoreLookupAction
: public DNSAction
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
)
1502 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1504 std::vector
<std::string
> keys
= d_key
->getKeys(*dq
);
1506 for (const auto& key
: keys
) {
1507 if (d_kvs
->getValue(key
, result
) == true) {
1513 dq
->qTag
= std::make_shared
<QTag
>();
1516 dq
->qTag
->insert({d_tag
, std::move(result
)});
1518 return Action::None
;
1521 std::string
toString() const override
1523 return "lookup key-value store based on '" + d_key
->toString() + "' and set the result in tag '" + d_tag
+ "'";
1527 std::shared_ptr
<KeyValueStore
> d_kvs
;
1528 std::shared_ptr
<KeyValueLookupKey
> d_key
;
1532 class NegativeAndSOAAction
: public DNSAction
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
)
1539 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
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
;
1545 setResponseHeadersFromConfig(*dq
->getHeader(), d_responseConfig
);
1547 return Action::Allow
;
1550 std::string
toString() const override
1552 return std::string(d_nxd
? "NXD " : "NODATA") + " with SOA";
1555 ResponseConfig d_responseConfig
;
1570 class SetProxyProtocolValuesAction
: public DNSAction
1573 // this action does not stop the processing
1574 SetProxyProtocolValuesAction(const std::vector
<std::pair
<uint8_t, std::string
>>& values
)
1576 d_values
.reserve(values
.size());
1577 for (const auto& value
: values
) {
1578 d_values
.push_back({value
.second
, value
.first
});
1582 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1584 if (!dq
->proxyProtocolValues
) {
1585 dq
->proxyProtocolValues
= make_unique
<std::vector
<ProxyProtocolValue
>>();
1588 *(dq
->proxyProtocolValues
) = d_values
;
1590 return Action::None
;
1593 std::string
toString() const override
1595 return "set Proxy-Protocol values";
1599 std::vector
<ProxyProtocolValue
> d_values
;
1602 class SetAdditionalProxyProtocolValueAction
: public DNSAction
1605 // this action does not stop the processing
1606 SetAdditionalProxyProtocolValueAction(uint8_t type
, const std::string
& value
): d_value(value
), d_type(type
)
1610 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1612 if (!dq
->proxyProtocolValues
) {
1613 dq
->proxyProtocolValues
= make_unique
<std::vector
<ProxyProtocolValue
>>();
1616 dq
->proxyProtocolValues
->push_back({ d_value
, d_type
});
1618 return Action::None
;
1621 std::string
toString() const override
1623 return "add a Proxy-Protocol value of type " + std::to_string(d_type
);
1627 std::string d_value
;
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
) {
1636 boost::uuids::uuid uuid
;
1637 uint64_t creationOrder
;
1638 parseRuleParams(params
, uuid
, name
, creationOrder
);
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
});
1646 typedef std::unordered_map
<std::string
, boost::variant
<bool, uint32_t> > responseParams_t
;
1648 static void parseResponseConfig(boost::optional
<responseParams_t
> vars
, ResponseConfig
& config
)
1651 if (vars
->count("ttl")) {
1652 config
.ttl
= boost::get
<uint32_t>((*vars
)["ttl"]);
1654 if (vars
->count("aa")) {
1655 config
.setAA
= boost::get
<bool>((*vars
)["aa"]);
1657 if (vars
->count("ad")) {
1658 config
.setAD
= boost::get
<bool>((*vars
)["ad"]);
1660 if (vars
->count("ra")) {
1661 config
.setRA
= boost::get
<bool>((*vars
)["ra"]);
1666 void setResponseHeadersFromConfig(dnsheader
& dh
, const ResponseConfig
& config
)
1669 dh
.aa
= *config
.setAA
;
1672 dh
.ad
= *config
.setAD
;
1678 dh
.ra
= *config
.setRA
;
1681 dh
.ra
= dh
.rd
; // for good measure
1685 void setupLuaActions(LuaContext
& luaCtx
)
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
;
1691 parseRuleParams(params
, uuid
, name
, creationOrder
);
1693 auto rule
= makeRule(dnsrule
);
1694 DNSDistRuleAction
ra({std::move(rule
), action
, std::move(name
), uuid
, creationOrder
});
1695 return std::make_shared
<DNSDistRuleAction
>(ra
);
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()?");
1703 addAction(&g_ruleactions
, var
, boost::get
<std::shared_ptr
<DNSAction
> >(era
), params
);
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()?");
1711 addAction(&g_respruleactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
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()?");
1719 addAction(&g_cachehitrespruleactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
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()?");
1727 addAction(&g_selfansweredrespruleactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
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";
1738 g_outputBuffer
+= std::to_string(s
.second
)+"\n";
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
;
1751 luaCtx
.registerFunction("getStats", &DNSAction::getStats
);
1752 luaCtx
.registerFunction("reload", &DNSAction::reload
);
1753 luaCtx
.registerFunction("reload", &DNSResponseAction::reload
);
1755 luaCtx
.writeFunction("LuaAction", [](LuaAction::func_t func
) {
1757 return std::shared_ptr
<DNSAction
>(new LuaAction(func
));
1760 luaCtx
.writeFunction("LuaFFIAction", [](LuaFFIAction::func_t func
) {
1762 return std::shared_ptr
<DNSAction
>(new LuaFFIAction(func
));
1765 luaCtx
.writeFunction("SetNoRecurseAction", []() {
1766 return std::shared_ptr
<DNSAction
>(new SetNoRecurseAction
);
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
);
1774 luaCtx
.writeFunction("SetMacAddrAction", [](int code
) {
1775 return std::shared_ptr
<DNSAction
>(new SetMacAddrAction(code
));
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
));
1783 luaCtx
.writeFunction("PoolAction", [](const std::string
& a
) {
1784 return std::shared_ptr
<DNSAction
>(new PoolAction(a
));
1787 luaCtx
.writeFunction("QPSAction", [](int limit
) {
1788 return std::shared_ptr
<DNSAction
>(new QPSAction(limit
));
1791 luaCtx
.writeFunction("QPSPoolAction", [](int limit
, const std::string
& a
) {
1792 return std::shared_ptr
<DNSAction
>(new QPSPoolAction(limit
, a
));
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
));
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
));
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
);
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
);
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
)) {
1824 const auto& v
= boost::get
<vector
<pair
<int,std::string
>>>(inp
);
1825 for(const auto& raw
: v
) {
1826 raws
.push_back(raw
.second
);
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
);
1836 luaCtx
.writeFunction("DropAction", []() {
1837 return std::shared_ptr
<DNSAction
>(new DropAction
);
1840 luaCtx
.writeFunction("AllowAction", []() {
1841 return std::shared_ptr
<DNSAction
>(new AllowAction
);
1844 luaCtx
.writeFunction("NoneAction", []() {
1845 return std::shared_ptr
<DNSAction
>(new NoneAction
);
1848 luaCtx
.writeFunction("DelayAction", [](int msec
) {
1849 return std::shared_ptr
<DNSAction
>(new DelayAction(msec
));
1852 luaCtx
.writeFunction("TCAction", []() {
1853 return std::shared_ptr
<DNSAction
>(new TCAction
);
1856 luaCtx
.writeFunction("SetDisableValidationAction", []() {
1857 return std::shared_ptr
<DNSAction
>(new SetDisableValidationAction
);
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
);
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));
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));
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
);
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
);
1887 luaCtx
.writeFunction("SetSkipCacheAction", []() {
1888 return std::shared_ptr
<DNSAction
>(new SetSkipCacheAction
);
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
);
1896 luaCtx
.writeFunction("SetSkipCacheResponseAction", []() {
1897 return std::shared_ptr
<DNSResponseAction
>(new SetSkipCacheResponseAction
);
1900 luaCtx
.writeFunction("SetTempFailureCacheTTLAction", [](int maxTTL
) {
1901 return std::shared_ptr
<DNSAction
>(new SetTempFailureCacheTTLAction(maxTTL
));
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
));
1909 luaCtx
.writeFunction("DropResponseAction", []() {
1910 return std::shared_ptr
<DNSResponseAction
>(new DropResponseAction
);
1913 luaCtx
.writeFunction("AllowResponseAction", []() {
1914 return std::shared_ptr
<DNSResponseAction
>(new AllowResponseAction
);
1917 luaCtx
.writeFunction("DelayResponseAction", [](int msec
) {
1918 return std::shared_ptr
<DNSResponseAction
>(new DelayResponseAction(msec
));
1921 luaCtx
.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func
) {
1923 return std::shared_ptr
<DNSResponseAction
>(new LuaResponseAction(func
));
1926 luaCtx
.writeFunction("LuaFFIResponseAction", [](LuaFFIResponseAction::func_t func
) {
1928 return std::shared_ptr
<DNSResponseAction
>(new LuaFFIResponseAction(func
));
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
) {
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."));
1941 std::string serverID
;
1942 std::string ipEncryptKey
;
1944 if (vars
->count("serverID")) {
1945 serverID
= boost::get
<std::string
>((*vars
)["serverID"]);
1947 if (vars
->count("ipEncryptKey")) {
1948 ipEncryptKey
= boost::get
<std::string
>((*vars
)["ipEncryptKey"]);
1952 return std::shared_ptr
<DNSAction
>(new RemoteLogAction(logger
, alterFunc
, serverID
, ipEncryptKey
));
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
) {
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.");
1965 std::string serverID
;
1966 std::string ipEncryptKey
;
1968 if (vars
->count("serverID")) {
1969 serverID
= boost::get
<std::string
>((*vars
)["serverID"]);
1971 if (vars
->count("ipEncryptKey")) {
1972 ipEncryptKey
= boost::get
<std::string
>((*vars
)["ipEncryptKey"]);
1976 return std::shared_ptr
<DNSResponseAction
>(new RemoteLogResponseAction(logger
, alterFunc
, serverID
, ipEncryptKey
, includeCNAME
? *includeCNAME
: false));
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
));
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
));
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));
1991 luaCtx
.writeFunction("SetECSPrefixLengthAction", [](uint16_t v4PrefixLength
, uint16_t v6PrefixLength
) {
1992 return std::shared_ptr
<DNSAction
>(new SetECSPrefixLengthAction(v4PrefixLength
, v6PrefixLength
));
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
));
2000 luaCtx
.writeFunction("SetECSOverrideAction", [](bool ecsOverride
) {
2001 return std::shared_ptr
<DNSAction
>(new SetECSOverrideAction(ecsOverride
));
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
));
2009 luaCtx
.writeFunction("SetDisableECSAction", []() {
2010 return std::shared_ptr
<DNSAction
>(new SetDisableECSAction());
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());
2018 luaCtx
.writeFunction("SetECSAction", [](const std::string v4
, boost::optional
<std::string
> v6
) {
2020 return std::shared_ptr
<DNSAction
>(new SetECSAction(Netmask(v4
), Netmask(*v6
)));
2022 return std::shared_ptr
<DNSAction
>(new SetECSAction(Netmask(v4
)));
2025 luaCtx
.writeFunction("SNMPTrapAction", [](boost::optional
<std::string
> reason
) {
2026 #ifdef HAVE_NET_SNMP
2027 return std::shared_ptr
<DNSAction
>(new SNMPTrapAction(reason
? *reason
: ""));
2029 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
2030 #endif /* HAVE_NET_SNMP */
2033 luaCtx
.writeFunction("SNMPTrapResponseAction", [](boost::optional
<std::string
> reason
) {
2034 #ifdef HAVE_NET_SNMP
2035 return std::shared_ptr
<DNSResponseAction
>(new SNMPTrapResponseAction(reason
? *reason
: ""));
2037 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
2038 #endif /* HAVE_NET_SNMP */
2041 luaCtx
.writeFunction("SetTagAction", [](std::string tag
, std::string value
) {
2042 return std::shared_ptr
<DNSAction
>(new SetTagAction(tag
, value
));
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
));
2050 luaCtx
.writeFunction("SetTagResponseAction", [](std::string tag
, std::string value
) {
2051 return std::shared_ptr
<DNSResponseAction
>(new SetTagResponseAction(tag
, value
));
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
));
2059 luaCtx
.writeFunction("ContinueAction", [](std::shared_ptr
<DNSAction
> action
) {
2060 return std::shared_ptr
<DNSAction
>(new ContinueAction(action
));
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
);
2070 #endif /* HAVE_DNS_OVER_HTTPS */
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
));
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
);
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
);
2091 luaCtx
.writeFunction("SetProxyProtocolValuesAction", [](const std::vector
<std::pair
<uint8_t, std::string
>>& values
) {
2092 return std::shared_ptr
<DNSAction
>(new SetProxyProtocolValuesAction(values
));
2095 luaCtx
.writeFunction("SetAdditionalProxyProtocolValueAction", [](uint8_t type
, const std::string
& value
) {
2096 return std::shared_ptr
<DNSAction
>(new SetAdditionalProxyProtocolValueAction(type
, value
));