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 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
76 std::string
toString() const override
82 class QPSAction
: public DNSAction
85 QPSAction(int limit
) : d_qps(limit
, limit
)
87 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
94 std::string
toString() const override
96 return "qps limit to "+std::to_string(d_qps
.getRate());
102 class DelayAction
: public DNSAction
105 DelayAction(int msec
) : d_msec(msec
)
107 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
109 *ruleresult
=std::to_string(d_msec
);
110 return Action::Delay
;
112 std::string
toString() const override
114 return "delay by "+std::to_string(d_msec
)+ " msec";
121 class TeeAction
: public DNSAction
124 TeeAction(const ComboAddress
& ca
, bool addECS
=false);
125 ~TeeAction() override
;
126 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
;
127 std::string
toString() const override
;
128 std::map
<std::string
, double> getStats() const override
;
131 ComboAddress d_remote
;
132 std::thread d_worker
;
136 mutable std::atomic
<unsigned long> d_senderrors
{0};
137 unsigned long d_recverrors
{0};
138 mutable std::atomic
<unsigned long> d_queries
{0};
139 unsigned long d_responses
{0};
140 unsigned long d_nxdomains
{0};
141 unsigned long d_servfails
{0};
142 unsigned long d_refuseds
{0};
143 unsigned long d_formerrs
{0};
144 unsigned long d_notimps
{0};
145 unsigned long d_noerrors
{0};
146 mutable unsigned long d_tcpdrops
{0};
147 unsigned long d_otherrcode
{0};
148 std::atomic
<bool> d_pleaseQuit
{false};
149 bool d_addECS
{false};
152 TeeAction::TeeAction(const ComboAddress
& ca
, bool addECS
) : d_remote(ca
), d_addECS(addECS
)
154 d_fd
=SSocket(d_remote
.sin4
.sin_family
, SOCK_DGRAM
, 0);
155 SConnect(d_fd
, d_remote
);
156 setNonBlocking(d_fd
);
157 d_worker
=std::thread(std::bind(&TeeAction::worker
, this));
160 TeeAction::~TeeAction()
167 DNSAction::Action
TeeAction::operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const
178 uint16_t len
= dq
->len
;
179 bool ednsAdded
= false;
180 bool ecsAdded
= false;
181 query
.reserve(dq
->size
);
182 query
.assign((char*) dq
->dh
, len
);
184 std::string newECSOption
;
185 generateECSOption(dq
->ecsSet
? dq
->ecs
.getNetwork() : *dq
->remote
, newECSOption
, dq
->ecsSet
? dq
->ecs
.getBits() : dq
->ecsPrefixLength
);
187 if (!handleEDNSClientSubnet(const_cast<char*>(query
.c_str()), query
.capacity(), dq
->qname
->wirelength(), &len
, ednsAdded
, ecsAdded
, dq
->ecsOverride
, newECSOption
, g_preserveTrailingData
)) {
188 return DNSAction::Action::None
;
191 res
= send(d_fd
, query
.c_str(), len
, 0);
194 res
= send(d_fd
, (char*)dq
->dh
, dq
->len
, 0);
200 return DNSAction::Action::None
;
203 std::string
TeeAction::toString() const
205 return "tee to "+d_remote
.toStringWithPort();
208 std::map
<std::string
,double> TeeAction::getStats() const
210 return {{"queries", d_queries
},
211 {"responses", d_responses
},
212 {"recv-errors", d_recverrors
},
213 {"send-errors", d_senderrors
},
214 {"noerrors", d_noerrors
},
215 {"nxdomains", d_nxdomains
},
216 {"refuseds", d_refuseds
},
217 {"servfails", d_servfails
},
218 {"other-rcode", d_otherrcode
},
219 {"tcp-drops", d_tcpdrops
}
223 void TeeAction::worker()
225 setThreadName("dnsdist/TeeWork");
228 struct dnsheader
* dh
=(struct dnsheader
*)packet
;
230 res
=waitForData(d_fd
, 0, 250000);
239 res
=recv(d_fd
, packet
, sizeof(packet
), 0);
240 if(res
<= (int)sizeof(struct dnsheader
))
245 if(dh
->rcode
== RCode::NoError
)
247 else if(dh
->rcode
== RCode::ServFail
)
249 else if(dh
->rcode
== RCode::NXDomain
)
251 else if(dh
->rcode
== RCode::Refused
)
253 else if(dh
->rcode
== RCode::FormErr
)
255 else if(dh
->rcode
== RCode::NotImp
)
260 class PoolAction
: public DNSAction
263 PoolAction(const std::string
& pool
) : d_pool(pool
) {}
264 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
269 std::string
toString() const override
271 return "to pool "+d_pool
;
279 class QPSPoolAction
: public DNSAction
282 QPSPoolAction(unsigned int limit
, const std::string
& pool
) : d_qps(limit
, limit
), d_pool(pool
) {}
283 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
292 std::string
toString() const override
294 return "max " +std::to_string(d_qps
.getRate())+" to pool "+d_pool
;
302 class RCodeAction
: public DNSAction
305 RCodeAction(uint8_t rcode
) : d_rcode(rcode
) {}
306 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
308 dq
->dh
->rcode
= d_rcode
;
309 dq
->dh
->qr
= true; // for good measure
310 setResponseHeadersFromConfig(*dq
->dh
, d_responseConfig
);
311 return Action::HeaderModify
;
313 std::string
toString() const override
315 return "set rcode "+std::to_string(d_rcode
);
318 ResponseConfig d_responseConfig
;
323 class ERCodeAction
: public DNSAction
326 ERCodeAction(uint8_t rcode
) : d_rcode(rcode
) {}
327 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
329 dq
->dh
->rcode
= (d_rcode
& 0xF);
330 dq
->ednsRCode
= ((d_rcode
& 0xFFF0) >> 4);
331 dq
->dh
->qr
= true; // for good measure
332 setResponseHeadersFromConfig(*dq
->dh
, d_responseConfig
);
333 return Action::HeaderModify
;
335 std::string
toString() const override
337 return "set ercode "+ERCode::to_s(d_rcode
);
340 ResponseConfig d_responseConfig
;
345 class TCAction
: public DNSAction
348 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
350 return Action::Truncate
;
352 std::string
toString() const override
354 return "tc=1 answer";
358 class LuaAction
: public DNSAction
361 typedef std::function
<std::tuple
<int, boost::optional
<string
> >(DNSQuestion
* dq
)> func_t
;
362 LuaAction(const LuaAction::func_t
& func
) : d_func(func
)
365 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
367 std::lock_guard
<std::mutex
> lock(g_luamutex
);
369 auto ret
= d_func(dq
);
371 if (boost::optional
<std::string
> rule
= std::get
<1>(ret
)) {
375 // default to empty string
379 return static_cast<Action
>(std::get
<0>(ret
));
380 } catch (const std::exception
&e
) {
381 warnlog("LuaAction failed inside Lua, returning ServFail: %s", e
.what());
383 warnlog("LuaAction failed inside Lua, returning ServFail: [unknown exception]");
385 return DNSAction::Action::ServFail
;
388 string
toString() const override
396 class LuaResponseAction
: public DNSResponseAction
399 typedef std::function
<std::tuple
<int, boost::optional
<string
> >(DNSResponse
* dr
)> func_t
;
400 LuaResponseAction(const LuaResponseAction::func_t
& func
) : d_func(func
)
402 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
404 std::lock_guard
<std::mutex
> lock(g_luamutex
);
406 auto ret
= d_func(dr
);
408 if (boost::optional
<std::string
> rule
= std::get
<1>(ret
)) {
412 // default to empty string
416 return static_cast<Action
>(std::get
<0>(ret
));
417 } catch (const std::exception
&e
) {
418 warnlog("LuaResponseAction failed inside Lua, returning ServFail: %s", e
.what());
420 warnlog("LuaResponseAction failed inside Lua, returning ServFail: [unknown exception]");
422 return DNSResponseAction::Action::ServFail
;
425 string
toString() const override
427 return "Lua response script";
433 class LuaFFIAction
: public DNSAction
436 typedef std::function
<int(dnsdist_ffi_dnsquestion_t
* dq
)> func_t
;
438 LuaFFIAction(const LuaFFIAction::func_t
& func
): d_func(func
)
442 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
444 dnsdist_ffi_dnsquestion_t
dqffi(dq
);
446 std::lock_guard
<std::mutex
> lock(g_luamutex
);
448 auto ret
= d_func(&dqffi
);
451 *ruleresult
= *dqffi
.result
;
454 // default to empty string
458 return static_cast<DNSAction::Action
>(ret
);
459 } catch (const std::exception
&e
) {
460 warnlog("LuaFFIAction failed inside Lua, returning ServFail: %s", e
.what());
462 warnlog("LuaFFIAction failed inside Lua, returning ServFail: [unknown exception]");
464 return DNSAction::Action::ServFail
;
467 string
toString() const override
469 return "Lua FFI script";
476 class LuaFFIResponseAction
: public DNSResponseAction
479 typedef std::function
<int(dnsdist_ffi_dnsquestion_t
* dq
)> func_t
;
481 LuaFFIResponseAction(const LuaFFIResponseAction::func_t
& func
): d_func(func
)
485 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
487 DNSQuestion
* dq
= dynamic_cast<DNSQuestion
*>(dr
);
489 return DNSResponseAction::Action::ServFail
;
492 dnsdist_ffi_dnsquestion_t
dqffi(dq
);
494 std::lock_guard
<std::mutex
> lock(g_luamutex
);
496 auto ret
= d_func(&dqffi
);
499 *ruleresult
= *dqffi
.result
;
502 // default to empty string
506 return static_cast<DNSResponseAction::Action
>(ret
);
507 } catch (const std::exception
&e
) {
508 warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: %s", e
.what());
510 warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: [unknown exception]");
512 return DNSResponseAction::Action::ServFail
;
515 string
toString() const override
517 return "Lua FFI script";
523 thread_local
std::default_random_engine
SpoofAction::t_randomEngine
;
525 DNSAction::Action
SpoofAction::operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const
527 uint16_t qtype
= dq
->qtype
;
528 // do we even have a response?
529 if (d_cname
.empty() &&
530 d_rawResponse
.empty() &&
531 d_types
.count(qtype
) == 0) {
535 vector
<ComboAddress
> addrs
;
536 unsigned int totrdatalen
= 0;
537 uint16_t numberOfRecords
= 0;
538 if (!d_cname
.empty()) {
539 qtype
= QType::CNAME
;
540 totrdatalen
+= d_cname
.toDNSString().size();
542 } else if (!d_rawResponse
.empty()) {
543 totrdatalen
+= d_rawResponse
.size();
547 for(const auto& addr
: d_addrs
) {
548 if(qtype
!= QType::ANY
&& ((addr
.sin4
.sin_family
== AF_INET
&& qtype
!= QType::A
) ||
549 (addr
.sin4
.sin_family
== AF_INET6
&& qtype
!= QType::AAAA
))) {
552 totrdatalen
+= addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
);
553 addrs
.push_back(addr
);
558 if (addrs
.size() > 1) {
559 shuffle(addrs
.begin(), addrs
.end(), t_randomEngine
);
562 unsigned int consumed
=0;
563 DNSName
ignore((char*)dq
->dh
, dq
->len
, sizeof(dnsheader
), false, 0, 0, &consumed
);
565 if (dq
->size
< (sizeof(dnsheader
) + consumed
+ 4 + numberOfRecords
*12 /* recordstart */ + totrdatalen
)) {
569 bool dnssecOK
= false;
570 bool hadEDNS
= false;
571 if (g_addEDNSToSelfGeneratedResponses
&& queryHasEDNS(*dq
)) {
573 dnssecOK
= getEDNSZ(*dq
) & EDNS_HEADER_FLAG_DO
;
576 dq
->len
= sizeof(dnsheader
) + consumed
+ 4; // there goes your EDNS
577 char* dest
= ((char*)dq
->dh
) + dq
->len
;
579 dq
->dh
->qr
= true; // for good measure
580 setResponseHeadersFromConfig(*dq
->dh
, d_responseConfig
);
582 dq
->dh
->arcount
= 0; // for now, forget about your EDNS, we're marching over it
584 uint32_t ttl
= htonl(d_responseConfig
.ttl
);
585 unsigned char recordstart
[] = {0xc0, 0x0c, // compressed name
589 0, 0 }; // rdata length
590 static_assert(sizeof(recordstart
) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
591 memcpy(&recordstart
[6], &ttl
, sizeof(ttl
));
594 if (qtype
== QType::CNAME
) {
595 const std::string wireData
= d_cname
.toDNSString(); // Note! This doesn't do compression!
596 uint16_t rdataLen
= htons(wireData
.length());
597 qtype
= htons(qtype
);
598 memcpy(&recordstart
[2], &qtype
, sizeof(qtype
));
599 memcpy(&recordstart
[10], &rdataLen
, sizeof(rdataLen
));
601 memcpy(dest
, recordstart
, sizeof(recordstart
));
602 dest
+= sizeof(recordstart
);
603 memcpy(dest
, wireData
.c_str(), wireData
.length());
604 dq
->len
+= wireData
.length() + sizeof(recordstart
);
607 else if (!d_rawResponse
.empty()) {
608 uint16_t rdataLen
= htons(d_rawResponse
.size());
609 qtype
= htons(qtype
);
610 memcpy(&recordstart
[2], &qtype
, sizeof(qtype
));
611 memcpy(&recordstart
[10], &rdataLen
, sizeof(rdataLen
));
613 memcpy(dest
, recordstart
, sizeof(recordstart
));
614 dest
+= sizeof(recordstart
);
615 memcpy(dest
, d_rawResponse
.c_str(), d_rawResponse
.size());
616 dq
->len
+= d_rawResponse
.size() + sizeof(recordstart
);
621 for(const auto& addr
: addrs
) {
622 uint16_t rdataLen
= htons(addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
));
623 qtype
= htons(addr
.sin4
.sin_family
== AF_INET
? QType::A
: QType::AAAA
);
624 memcpy(&recordstart
[2], &qtype
, sizeof(qtype
));
625 memcpy(&recordstart
[10], &rdataLen
, sizeof(rdataLen
));
627 memcpy(dest
, recordstart
, sizeof(recordstart
));
628 dest
+= sizeof(recordstart
);
631 addr
.sin4
.sin_family
== AF_INET
? (void*)&addr
.sin4
.sin_addr
.s_addr
: (void*)&addr
.sin6
.sin6_addr
.s6_addr
,
632 addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
));
633 dest
+= (addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
));
634 dq
->len
+= (addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
)) + sizeof(recordstart
);
639 dq
->dh
->ancount
= htons(dq
->dh
->ancount
);
641 if (hadEDNS
&& raw
== false) {
642 addEDNS(dq
->dh
, dq
->len
, dq
->size
, dnssecOK
, g_PayloadSizeSelfGenAnswers
, 0);
645 return Action::HeaderModify
;
648 class MacAddrAction
: public DNSAction
651 MacAddrAction(uint16_t code
) : d_code(code
)
653 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
658 std::string mac
= getMACAddress(*dq
->remote
);
662 std::string optRData
;
663 generateEDNSOption(d_code
, mac
, optRData
);
666 generateOptRR(optRData
, res
, g_EdnsUDPPayloadSize
, 0, false);
668 if ((dq
->size
- dq
->len
) < res
.length())
671 dq
->dh
->arcount
= htons(1);
672 char* dest
= ((char*)dq
->dh
) + dq
->len
;
673 memcpy(dest
, res
.c_str(), res
.length());
674 dq
->len
+= res
.length();
678 std::string
toString() const override
680 return "add EDNS MAC (code="+std::to_string(d_code
)+")";
686 class NoRecurseAction
: public DNSAction
689 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
694 std::string
toString() const override
700 class LogAction
: public DNSAction
, public boost::noncopyable
703 LogAction(): d_fp(nullptr, fclose
)
707 LogAction(const std::string
& str
, bool binary
=true, bool append
=false, bool buffered
=true, bool verboseOnly
=true, bool includeTimestamp
=false): d_fname(str
), d_binary(binary
), d_verboseOnly(verboseOnly
), d_includeTimestamp(includeTimestamp
)
712 d_fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fopen(str
.c_str(), "a+"), fclose
);
714 d_fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fopen(str
.c_str(), "w"), fclose
);
716 throw std::runtime_error("Unable to open file '"+str
+"' for logging: "+stringerror());
718 setbuf(d_fp
.get(), 0);
721 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
724 if (!d_verboseOnly
|| g_verbose
) {
725 if (d_includeTimestamp
) {
726 infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dq
->queryTime
->tv_sec
), static_cast<unsigned long>(dq
->queryTime
->tv_nsec
), dq
->remote
->toStringWithPort(), dq
->qname
->toString(), QType(dq
->qtype
).getName(), dq
->dh
->id
);
729 infolog("Packet from %s for %s %s with id %d", dq
->remote
->toStringWithPort(), dq
->qname
->toString(), QType(dq
->qtype
).getName(), dq
->dh
->id
);
735 std::string out
= dq
->qname
->toDNSString();
736 if (d_includeTimestamp
) {
737 uint64_t tv_sec
= static_cast<uint64_t>(dq
->queryTime
->tv_sec
);
738 uint32_t tv_nsec
= static_cast<uint32_t>(dq
->queryTime
->tv_nsec
);
739 fwrite(&tv_sec
, sizeof(tv_sec
), 1, d_fp
.get());
740 fwrite(&tv_nsec
, sizeof(tv_nsec
), 1, d_fp
.get());
742 uint16_t id
= dq
->dh
->id
;
743 fwrite(&id
, sizeof(id
), 1, d_fp
.get());
744 fwrite(out
.c_str(), 1, out
.size(), d_fp
.get());
745 fwrite(&dq
->qtype
, sizeof(dq
->qtype
), 1, d_fp
.get());
746 fwrite(&dq
->remote
->sin4
.sin_family
, sizeof(dq
->remote
->sin4
.sin_family
), 1, d_fp
.get());
747 if (dq
->remote
->sin4
.sin_family
== AF_INET
) {
748 fwrite(&dq
->remote
->sin4
.sin_addr
.s_addr
, sizeof(dq
->remote
->sin4
.sin_addr
.s_addr
), 1, d_fp
.get());
750 else if (dq
->remote
->sin4
.sin_family
== AF_INET6
) {
751 fwrite(&dq
->remote
->sin6
.sin6_addr
.s6_addr
, sizeof(dq
->remote
->sin6
.sin6_addr
.s6_addr
), 1, d_fp
.get());
753 fwrite(&dq
->remote
->sin4
.sin_port
, sizeof(dq
->remote
->sin4
.sin_port
), 1, d_fp
.get());
756 if (d_includeTimestamp
) {
757 fprintf(d_fp
.get(), "[%llu.%lu] Packet from %s for %s %s with id %d\n", static_cast<unsigned long long>(dq
->queryTime
->tv_sec
), static_cast<unsigned long>(dq
->queryTime
->tv_nsec
), dq
->remote
->toStringWithPort().c_str(), dq
->qname
->toString().c_str(), QType(dq
->qtype
).getName().c_str(), dq
->dh
->id
);
760 fprintf(d_fp
.get(), "Packet from %s for %s %s with id %d\n", dq
->remote
->toStringWithPort().c_str(), dq
->qname
->toString().c_str(), QType(dq
->qtype
).getName().c_str(), dq
->dh
->id
);
767 std::string
toString() const override
769 if (!d_fname
.empty()) {
770 return "log to " + d_fname
;
776 std::unique_ptr
<FILE, int(*)(FILE*)> d_fp
{nullptr, fclose
};
778 bool d_verboseOnly
{true};
779 bool d_includeTimestamp
{false};
782 class LogResponseAction
: public DNSResponseAction
, public boost::noncopyable
785 LogResponseAction(): d_fp(nullptr, fclose
)
789 LogResponseAction(const std::string
& str
, bool append
=false, bool buffered
=true, bool verboseOnly
=true, bool includeTimestamp
=false): d_fname(str
), d_verboseOnly(verboseOnly
), d_includeTimestamp(includeTimestamp
)
794 d_fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fopen(str
.c_str(), "a+"), fclose
);
796 d_fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fopen(str
.c_str(), "w"), fclose
);
798 throw std::runtime_error("Unable to open file '"+str
+"' for logging: "+stringerror());
800 setbuf(d_fp
.get(), 0);
803 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
806 if (!d_verboseOnly
|| g_verbose
) {
807 if (d_includeTimestamp
) {
808 infolog("[%u.%u] Answer to %s for %s %s (%s) with id %d", static_cast<unsigned long long>(dr
->queryTime
->tv_sec
), static_cast<unsigned long>(dr
->queryTime
->tv_nsec
), dr
->remote
->toStringWithPort(), dr
->qname
->toString(), QType(dr
->qtype
).getName(), RCode::to_s(dr
->dh
->rcode
), dr
->dh
->id
);
811 infolog("Answer to %s for %s %s (%s) with id %d", dr
->remote
->toStringWithPort(), dr
->qname
->toString(), QType(dr
->qtype
).getName(), RCode::to_s(dr
->dh
->rcode
), dr
->dh
->id
);
816 if (d_includeTimestamp
) {
817 fprintf(d_fp
.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %d\n", static_cast<unsigned long long>(dr
->queryTime
->tv_sec
), static_cast<unsigned long>(dr
->queryTime
->tv_nsec
), dr
->remote
->toStringWithPort().c_str(), dr
->qname
->toString().c_str(), QType(dr
->qtype
).getName().c_str(), RCode::to_s(dr
->dh
->rcode
).c_str(), dr
->dh
->id
);
820 fprintf(d_fp
.get(), "Answer to %s for %s %s (%s) with id %d\n", dr
->remote
->toStringWithPort().c_str(), dr
->qname
->toString().c_str(), QType(dr
->qtype
).getName().c_str(), RCode::to_s(dr
->dh
->rcode
).c_str(), dr
->dh
->id
);
826 std::string
toString() const override
828 if (!d_fname
.empty()) {
829 return "log to " + d_fname
;
835 std::unique_ptr
<FILE, int(*)(FILE*)> d_fp
{nullptr, fclose
};
836 bool d_verboseOnly
{true};
837 bool d_includeTimestamp
{false};
841 class DisableValidationAction
: public DNSAction
844 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
849 std::string
toString() const override
855 class SkipCacheAction
: public DNSAction
858 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
860 dq
->skipCache
= true;
863 std::string
toString() const override
869 class TempFailureCacheTTLAction
: public DNSAction
872 TempFailureCacheTTLAction(uint32_t ttl
) : d_ttl(ttl
)
874 TempFailureCacheTTLAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
876 dq
->tempFailureTTL
= d_ttl
;
879 std::string
toString() const override
881 return "set tempfailure cache ttl to "+std::to_string(d_ttl
);
887 class ECSPrefixLengthAction
: public DNSAction
890 ECSPrefixLengthAction(uint16_t v4Length
, uint16_t v6Length
) : d_v4PrefixLength(v4Length
), d_v6PrefixLength(v6Length
)
893 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
895 dq
->ecsPrefixLength
= dq
->remote
->sin4
.sin_family
== AF_INET
? d_v4PrefixLength
: d_v6PrefixLength
;
898 std::string
toString() const override
900 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength
) + "/" + std::to_string(d_v6PrefixLength
);
903 uint16_t d_v4PrefixLength
;
904 uint16_t d_v6PrefixLength
;
907 class ECSOverrideAction
: public DNSAction
910 ECSOverrideAction(bool ecsOverride
) : d_ecsOverride(ecsOverride
)
913 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
915 dq
->ecsOverride
= d_ecsOverride
;
918 std::string
toString() const override
920 return "set ECS override to " + std::to_string(d_ecsOverride
);
927 class DisableECSAction
: public DNSAction
930 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
935 std::string
toString() const override
937 return "disable ECS";
941 class SetECSAction
: public DNSAction
944 SetECSAction(const Netmask
& v4
): d_v4(v4
), d_hasV6(false)
948 SetECSAction(const Netmask
& v4
, const Netmask
& v6
): d_v4(v4
), d_v6(v6
), d_hasV6(true)
952 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
957 dq
->ecs
= dq
->remote
->isIPv4() ? d_v4
: d_v6
;
966 std::string
toString() const override
968 std::string result
= "set ECS to " + d_v4
.toString();
970 result
+= " / " + d_v6
.toString();
982 class DnstapLogAction
: public DNSAction
, public boost::noncopyable
985 DnstapLogAction(const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
>& logger
, boost::optional
<std::function
<void(DNSQuestion
*, DnstapMessage
*)> > alterFunc
): d_identity(identity
), d_logger(logger
), d_alterFunc(alterFunc
)
988 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
991 DnstapMessage
message(d_identity
, dq
->remote
, dq
->local
, dq
->tcp
, reinterpret_cast<const char*>(dq
->dh
), dq
->len
, dq
->queryTime
, nullptr);
994 std::lock_guard
<std::mutex
> lock(g_luamutex
);
995 (*d_alterFunc
)(dq
, &message
);
999 message
.serialize(data
);
1000 d_logger
->queueData(data
);
1001 #endif /* HAVE_PROTOBUF */
1002 return Action::None
;
1004 std::string
toString() const override
1006 return "remote log as dnstap to " + (d_logger
? d_logger
->toString() : "");
1009 std::string d_identity
;
1010 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
1011 boost::optional
<std::function
<void(DNSQuestion
*, DnstapMessage
*)> > d_alterFunc
;
1014 class RemoteLogAction
: public DNSAction
, public boost::noncopyable
1017 RemoteLogAction(std::shared_ptr
<RemoteLoggerInterface
>& logger
, boost::optional
<std::function
<void(DNSQuestion
*, DNSDistProtoBufMessage
*)> > alterFunc
, const std::string
& serverID
, const std::string
& ipEncryptKey
): d_logger(logger
), d_alterFunc(alterFunc
), d_serverID(serverID
), d_ipEncryptKey(ipEncryptKey
)
1020 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1022 #ifdef HAVE_PROTOBUF
1023 if (!dq
->uniqueId
) {
1024 dq
->uniqueId
= getUniqueID();
1027 DNSDistProtoBufMessage
message(*dq
);
1028 if (!d_serverID
.empty()) {
1029 message
.setServerIdentity(d_serverID
);
1033 if (!d_ipEncryptKey
.empty())
1035 message
.setRequestor(encryptCA(*dq
->remote
, d_ipEncryptKey
));
1037 #endif /* HAVE_LIBCRYPTO */
1040 std::lock_guard
<std::mutex
> lock(g_luamutex
);
1041 (*d_alterFunc
)(dq
, &message
);
1045 message
.serialize(data
);
1046 d_logger
->queueData(data
);
1047 #endif /* HAVE_PROTOBUF */
1048 return Action::None
;
1050 std::string
toString() const override
1052 return "remote log to " + (d_logger
? d_logger
->toString() : "");
1055 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
1056 boost::optional
<std::function
<void(DNSQuestion
*, DNSDistProtoBufMessage
*)> > d_alterFunc
;
1057 std::string d_serverID
;
1058 std::string d_ipEncryptKey
;
1061 class SNMPTrapAction
: public DNSAction
1064 SNMPTrapAction(const std::string
& reason
): d_reason(reason
)
1067 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1069 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
1070 g_snmpAgent
->sendDNSTrap(*dq
, d_reason
);
1073 return Action::None
;
1075 std::string
toString() const override
1077 return "send SNMP trap";
1080 std::string d_reason
;
1083 class TagAction
: public DNSAction
1086 TagAction(const std::string
& tag
, const std::string
& value
): d_tag(tag
), d_value(value
)
1089 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1092 dq
->qTag
= std::make_shared
<QTag
>();
1095 dq
->qTag
->insert({d_tag
, d_value
});
1097 return Action::None
;
1099 std::string
toString() const override
1101 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
1105 std::string d_value
;
1108 class DnstapLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
1111 DnstapLogResponseAction(const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
>& logger
, boost::optional
<std::function
<void(DNSResponse
*, DnstapMessage
*)> > alterFunc
): d_identity(identity
), d_logger(logger
), d_alterFunc(alterFunc
)
1114 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1116 #ifdef HAVE_PROTOBUF
1117 struct timespec now
;
1118 gettime(&now
, true);
1119 DnstapMessage
message(d_identity
, dr
->remote
, dr
->local
, dr
->tcp
, reinterpret_cast<const char*>(dr
->dh
), dr
->len
, dr
->queryTime
, &now
);
1122 std::lock_guard
<std::mutex
> lock(g_luamutex
);
1123 (*d_alterFunc
)(dr
, &message
);
1127 message
.serialize(data
);
1128 d_logger
->queueData(data
);
1129 #endif /* HAVE_PROTOBUF */
1130 return Action::None
;
1132 std::string
toString() const override
1134 return "log response as dnstap to " + (d_logger
? d_logger
->toString() : "");
1137 std::string d_identity
;
1138 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
1139 boost::optional
<std::function
<void(DNSResponse
*, DnstapMessage
*)> > d_alterFunc
;
1142 class RemoteLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
1145 RemoteLogResponseAction(std::shared_ptr
<RemoteLoggerInterface
>& logger
, boost::optional
<std::function
<void(DNSResponse
*, DNSDistProtoBufMessage
*)> > alterFunc
, const std::string
& serverID
, const std::string
& ipEncryptKey
, bool includeCNAME
): d_logger(logger
), d_alterFunc(alterFunc
), d_serverID(serverID
), d_ipEncryptKey(ipEncryptKey
), d_includeCNAME(includeCNAME
)
1148 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1150 #ifdef HAVE_PROTOBUF
1151 if (!dr
->uniqueId
) {
1152 dr
->uniqueId
= getUniqueID();
1155 DNSDistProtoBufMessage
message(*dr
, d_includeCNAME
);
1156 if (!d_serverID
.empty()) {
1157 message
.setServerIdentity(d_serverID
);
1161 if (!d_ipEncryptKey
.empty())
1163 message
.setRequestor(encryptCA(*dr
->remote
, d_ipEncryptKey
));
1165 #endif /* HAVE_LIBCRYPTO */
1168 std::lock_guard
<std::mutex
> lock(g_luamutex
);
1169 (*d_alterFunc
)(dr
, &message
);
1173 message
.serialize(data
);
1174 d_logger
->queueData(data
);
1175 #endif /* HAVE_PROTOBUF */
1176 return Action::None
;
1178 std::string
toString() const override
1180 return "remote log response to " + (d_logger
? d_logger
->toString() : "");
1183 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
1184 boost::optional
<std::function
<void(DNSResponse
*, DNSDistProtoBufMessage
*)> > d_alterFunc
;
1185 std::string d_serverID
;
1186 std::string d_ipEncryptKey
;
1187 bool d_includeCNAME
;
1190 class DropResponseAction
: public DNSResponseAction
1193 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1195 return Action::Drop
;
1197 std::string
toString() const override
1203 class AllowResponseAction
: public DNSResponseAction
1206 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1208 return Action::Allow
;
1210 std::string
toString() const override
1216 class DelayResponseAction
: public DNSResponseAction
1219 DelayResponseAction(int msec
) : d_msec(msec
)
1221 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1223 *ruleresult
=std::to_string(d_msec
);
1224 return Action::Delay
;
1226 std::string
toString() const override
1228 return "delay by "+std::to_string(d_msec
)+ " msec";
1234 class SNMPTrapResponseAction
: public DNSResponseAction
1237 SNMPTrapResponseAction(const std::string
& reason
): d_reason(reason
)
1240 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1242 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
1243 g_snmpAgent
->sendDNSTrap(*dr
, d_reason
);
1246 return Action::None
;
1248 std::string
toString() const override
1250 return "send SNMP trap";
1253 std::string d_reason
;
1256 class TagResponseAction
: public DNSResponseAction
1259 TagResponseAction(const std::string
& tag
, const std::string
& value
): d_tag(tag
), d_value(value
)
1262 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1265 dr
->qTag
= std::make_shared
<QTag
>();
1268 dr
->qTag
->insert({d_tag
, d_value
});
1270 return Action::None
;
1272 std::string
toString() const override
1274 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
1278 std::string d_value
;
1281 class ContinueAction
: public DNSAction
1284 ContinueAction(std::shared_ptr
<DNSAction
>& action
): d_action(action
)
1288 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1291 /* call the action */
1292 auto action
= (*d_action
)(dq
, ruleresult
);
1294 /* apply the changes if needed (pool selection, flags, etc */
1295 processRulesResult(action
, *dq
, *ruleresult
, drop
);
1298 /* but ignore the resulting action no matter what */
1299 return Action::None
;
1302 std::string
toString() const override
1305 return "continue after: " + (d_action
? d_action
->toString() : "");
1313 std::shared_ptr
<DNSAction
> d_action
;
1316 #ifdef HAVE_DNS_OVER_HTTPS
1317 class HTTPStatusAction
: public DNSAction
1320 HTTPStatusAction(int code
, const std::string
& body
, const std::string
& contentType
): d_body(body
), d_contentType(contentType
), d_code(code
)
1324 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1327 return Action::None
;
1330 dq
->du
->setHTTPResponse(d_code
, d_body
, d_contentType
);
1331 dq
->dh
->qr
= true; // for good measure
1332 setResponseHeadersFromConfig(*dq
->dh
, d_responseConfig
);
1333 return Action::HeaderModify
;
1336 std::string
toString() const override
1338 return "return an HTTP status of " + std::to_string(d_code
);
1341 ResponseConfig d_responseConfig
;
1344 std::string d_contentType
;
1347 #endif /* HAVE_DNS_OVER_HTTPS */
1349 class KeyValueStoreLookupAction
: public DNSAction
1352 KeyValueStoreLookupAction(std::shared_ptr
<KeyValueStore
>& kvs
, std::shared_ptr
<KeyValueLookupKey
>& lookupKey
, const std::string
& destinationTag
): d_kvs(kvs
), d_key(lookupKey
), d_tag(destinationTag
)
1356 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1358 std::vector
<std::string
> keys
= d_key
->getKeys(*dq
);
1360 for (const auto& key
: keys
) {
1361 if (d_kvs
->getValue(key
, result
) == true) {
1367 dq
->qTag
= std::make_shared
<QTag
>();
1370 dq
->qTag
->insert({d_tag
, std::move(result
)});
1372 return Action::None
;
1375 std::string
toString() const override
1377 return "lookup key-value store based on '" + d_key
->toString() + "' and set the result in tag '" + d_tag
+ "'";
1381 std::shared_ptr
<KeyValueStore
> d_kvs
;
1382 std::shared_ptr
<KeyValueLookupKey
> d_key
;
1386 class SetNegativeAndSOAAction
: public DNSAction
1389 SetNegativeAndSOAAction(bool nxd
, const DNSName
& zone
, uint32_t ttl
, const DNSName
& mname
, const DNSName
& rname
, uint32_t serial
, uint32_t refresh
, uint32_t retry
, uint32_t expire
, uint32_t minimum
): d_zone(zone
), d_mname(mname
), d_rname(rname
), d_ttl(ttl
), d_serial(serial
), d_refresh(refresh
), d_retry(retry
), d_expire(expire
), d_minimum(minimum
), d_nxd(nxd
)
1393 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1395 if (!setNegativeAndAdditionalSOA(*dq
, d_nxd
, d_zone
, d_ttl
, d_mname
, d_rname
, d_serial
, d_refresh
, d_retry
, d_expire
, d_minimum
)) {
1396 return Action::None
;
1399 setResponseHeadersFromConfig(*dq
->dh
, d_responseConfig
);
1401 return Action::Allow
;
1404 std::string
toString() const override
1406 return std::string(d_nxd
? "NXD " : "NODATA") + " with SOA";
1409 ResponseConfig d_responseConfig
;
1424 class SetProxyProtocolValuesAction
: public DNSAction
1427 SetProxyProtocolValuesAction(const std::vector
<std::pair
<uint8_t, std::string
>>& values
)
1429 d_values
.reserve(values
.size());
1430 for (const auto& value
: values
) {
1431 d_values
.push_back({value
.second
, value
.first
});
1435 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1437 if (!dq
->proxyProtocolValues
) {
1438 dq
->proxyProtocolValues
= make_unique
<std::vector
<ProxyProtocolValue
>>();
1441 *(dq
->proxyProtocolValues
) = d_values
;
1443 return Action::None
;
1446 std::string
toString() const override
1448 return "set Proxy-Protocol values";
1452 std::vector
<ProxyProtocolValue
> d_values
;
1455 template<typename T
, typename ActionT
>
1456 static void addAction(GlobalStateHolder
<vector
<T
> > *someRulActions
, const luadnsrule_t
& var
, const std::shared_ptr
<ActionT
>& action
, boost::optional
<luaruleparams_t
>& params
) {
1459 boost::uuids::uuid uuid
;
1460 uint64_t creationOrder
;
1461 parseRuleParams(params
, uuid
, creationOrder
);
1463 auto rule
=makeRule(var
);
1464 someRulActions
->modify([&rule
, &action
, &uuid
, creationOrder
](vector
<T
>& rulactions
){
1465 rulactions
.push_back({std::move(rule
), std::move(action
), std::move(uuid
), creationOrder
});
1469 typedef std::unordered_map
<std::string
, boost::variant
<bool, uint32_t> > responseParams_t
;
1471 static void parseResponseConfig(boost::optional
<responseParams_t
> vars
, ResponseConfig
& config
)
1474 if (vars
->count("ttl")) {
1475 config
.ttl
= boost::get
<uint32_t>((*vars
)["ttl"]);
1477 if (vars
->count("aa")) {
1478 config
.setAA
= boost::get
<bool>((*vars
)["aa"]);
1480 if (vars
->count("ad")) {
1481 config
.setAD
= boost::get
<bool>((*vars
)["ad"]);
1483 if (vars
->count("ra")) {
1484 config
.setRA
= boost::get
<bool>((*vars
)["ra"]);
1489 void setResponseHeadersFromConfig(dnsheader
& dh
, const ResponseConfig
& config
)
1492 dh
.aa
= *config
.setAA
;
1495 dh
.ad
= *config
.setAD
;
1501 dh
.ra
= *config
.setRA
;
1504 dh
.ra
= dh
.rd
; // for good measure
1508 void setupLuaActions()
1510 g_lua
.writeFunction("newRuleAction", [](luadnsrule_t dnsrule
, std::shared_ptr
<DNSAction
> action
, boost::optional
<luaruleparams_t
> params
) {
1511 boost::uuids::uuid uuid
;
1512 uint64_t creationOrder
;
1513 parseRuleParams(params
, uuid
, creationOrder
);
1515 auto rule
=makeRule(dnsrule
);
1516 DNSDistRuleAction
ra({std::move(rule
), action
, uuid
, creationOrder
});
1517 return std::make_shared
<DNSDistRuleAction
>(ra
);
1520 g_lua
.writeFunction("addAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
> > era
, boost::optional
<luaruleparams_t
> params
) {
1521 if (era
.type() != typeid(std::shared_ptr
<DNSAction
>)) {
1522 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
1525 addAction(&g_rulactions
, var
, boost::get
<std::shared_ptr
<DNSAction
> >(era
), params
);
1528 g_lua
.writeFunction("addResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
> > era
, boost::optional
<luaruleparams_t
> params
) {
1529 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
1530 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1533 addAction(&g_resprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
1536 g_lua
.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
>> era
, boost::optional
<luaruleparams_t
> params
) {
1537 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
1538 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1541 addAction(&g_cachehitresprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
1544 g_lua
.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
>> era
, boost::optional
<luaruleparams_t
> params
) {
1545 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
1546 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1549 addAction(&g_selfansweredresprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
1552 g_lua
.registerFunction
<void(DNSAction::*)()>("printStats", [](const DNSAction
& ta
) {
1553 setLuaNoSideEffect();
1554 auto stats
= ta
.getStats();
1555 for(const auto& s
: stats
) {
1556 g_outputBuffer
+=s
.first
+"\t";
1557 if((uint64_t)s
.second
== s
.second
)
1558 g_outputBuffer
+= std::to_string((uint64_t)s
.second
)+"\n";
1560 g_outputBuffer
+= std::to_string(s
.second
)+"\n";
1564 g_lua
.writeFunction("getAction", [](unsigned int num
) {
1565 setLuaNoSideEffect();
1566 boost::optional
<std::shared_ptr
<DNSAction
>> ret
;
1567 auto rulactions
= g_rulactions
.getCopy();
1568 if(num
< rulactions
.size())
1569 ret
=rulactions
[num
].d_action
;
1573 g_lua
.registerFunction("getStats", &DNSAction::getStats
);
1575 g_lua
.writeFunction("LuaAction", [](LuaAction::func_t func
) {
1577 return std::shared_ptr
<DNSAction
>(new LuaAction(func
));
1580 g_lua
.writeFunction("LuaFFIAction", [](LuaFFIAction::func_t func
) {
1582 return std::shared_ptr
<DNSAction
>(new LuaFFIAction(func
));
1585 g_lua
.writeFunction("NoRecurseAction", []() {
1586 return std::shared_ptr
<DNSAction
>(new NoRecurseAction
);
1589 g_lua
.writeFunction("MacAddrAction", [](int code
) {
1590 return std::shared_ptr
<DNSAction
>(new MacAddrAction(code
));
1593 g_lua
.writeFunction("PoolAction", [](const std::string
& a
) {
1594 return std::shared_ptr
<DNSAction
>(new PoolAction(a
));
1597 g_lua
.writeFunction("QPSAction", [](int limit
) {
1598 return std::shared_ptr
<DNSAction
>(new QPSAction(limit
));
1601 g_lua
.writeFunction("QPSPoolAction", [](int limit
, const std::string
& a
) {
1602 return std::shared_ptr
<DNSAction
>(new QPSPoolAction(limit
, a
));
1605 g_lua
.writeFunction("SpoofAction", [](boost::variant
<std::string
,vector
<pair
<int, std::string
>>> inp
, boost::optional
<std::string
> b
, boost::optional
<responseParams_t
> vars
) {
1606 vector
<ComboAddress
> addrs
;
1607 if(auto s
= boost::get
<std::string
>(&inp
))
1608 addrs
.push_back(ComboAddress(*s
));
1610 const auto& v
= boost::get
<vector
<pair
<int,std::string
>>>(inp
);
1611 for(const auto& a
: v
)
1612 addrs
.push_back(ComboAddress(a
.second
));
1615 addrs
.push_back(ComboAddress(*b
));
1618 auto ret
= std::shared_ptr
<DNSAction
>(new SpoofAction(addrs
));
1619 auto sa
= std::dynamic_pointer_cast
<SpoofAction
>(ret
);
1620 parseResponseConfig(vars
, sa
->d_responseConfig
);
1624 g_lua
.writeFunction("SpoofCNAMEAction", [](const std::string
& a
, boost::optional
<responseParams_t
> vars
) {
1625 auto ret
= std::shared_ptr
<DNSAction
>(new SpoofAction(DNSName(a
)));
1626 auto sa
= std::dynamic_pointer_cast
<SpoofAction
>(ret
);
1627 parseResponseConfig(vars
, sa
->d_responseConfig
);
1631 g_lua
.writeFunction("SpoofRawAction", [](const std::string
& raw
, boost::optional
<responseParams_t
> vars
) {
1632 auto ret
= std::shared_ptr
<DNSAction
>(new SpoofAction(raw
));
1633 auto sa
= std::dynamic_pointer_cast
<SpoofAction
>(ret
);
1634 parseResponseConfig(vars
, sa
->d_responseConfig
);
1638 g_lua
.writeFunction("DropAction", []() {
1639 return std::shared_ptr
<DNSAction
>(new DropAction
);
1642 g_lua
.writeFunction("AllowAction", []() {
1643 return std::shared_ptr
<DNSAction
>(new AllowAction
);
1646 g_lua
.writeFunction("NoneAction", []() {
1647 return std::shared_ptr
<DNSAction
>(new NoneAction
);
1650 g_lua
.writeFunction("DelayAction", [](int msec
) {
1651 return std::shared_ptr
<DNSAction
>(new DelayAction(msec
));
1654 g_lua
.writeFunction("TCAction", []() {
1655 return std::shared_ptr
<DNSAction
>(new TCAction
);
1658 g_lua
.writeFunction("DisableValidationAction", []() {
1659 return std::shared_ptr
<DNSAction
>(new DisableValidationAction
);
1662 g_lua
.writeFunction("LogAction", [](boost::optional
<std::string
> fname
, boost::optional
<bool> binary
, boost::optional
<bool> append
, boost::optional
<bool> buffered
, boost::optional
<bool> verboseOnly
, boost::optional
<bool> includeTimestamp
) {
1663 return std::shared_ptr
<DNSAction
>(new LogAction(fname
? *fname
: "", binary
? *binary
: true, append
? *append
: false, buffered
? *buffered
: false, verboseOnly
? *verboseOnly
: true, includeTimestamp
? *includeTimestamp
: false));
1666 g_lua
.writeFunction("LogResponseAction", [](boost::optional
<std::string
> fname
, boost::optional
<bool> append
, boost::optional
<bool> buffered
, boost::optional
<bool> verboseOnly
, boost::optional
<bool> includeTimestamp
) {
1667 return std::shared_ptr
<DNSResponseAction
>(new LogResponseAction(fname
? *fname
: "", append
? *append
: false, buffered
? *buffered
: false, verboseOnly
? *verboseOnly
: true, includeTimestamp
? *includeTimestamp
: false));
1670 g_lua
.writeFunction("RCodeAction", [](uint8_t rcode
, boost::optional
<responseParams_t
> vars
) {
1671 auto ret
= std::shared_ptr
<DNSAction
>(new RCodeAction(rcode
));
1672 auto rca
= std::dynamic_pointer_cast
<RCodeAction
>(ret
);
1673 parseResponseConfig(vars
, rca
->d_responseConfig
);
1677 g_lua
.writeFunction("ERCodeAction", [](uint8_t rcode
, boost::optional
<responseParams_t
> vars
) {
1678 auto ret
= std::shared_ptr
<DNSAction
>(new ERCodeAction(rcode
));
1679 auto erca
= std::dynamic_pointer_cast
<ERCodeAction
>(ret
);
1680 parseResponseConfig(vars
, erca
->d_responseConfig
);
1684 g_lua
.writeFunction("SkipCacheAction", []() {
1685 return std::shared_ptr
<DNSAction
>(new SkipCacheAction
);
1688 g_lua
.writeFunction("TempFailureCacheTTLAction", [](int maxTTL
) {
1689 return std::shared_ptr
<DNSAction
>(new TempFailureCacheTTLAction(maxTTL
));
1692 g_lua
.writeFunction("DropResponseAction", []() {
1693 return std::shared_ptr
<DNSResponseAction
>(new DropResponseAction
);
1696 g_lua
.writeFunction("AllowResponseAction", []() {
1697 return std::shared_ptr
<DNSResponseAction
>(new AllowResponseAction
);
1700 g_lua
.writeFunction("DelayResponseAction", [](int msec
) {
1701 return std::shared_ptr
<DNSResponseAction
>(new DelayResponseAction(msec
));
1704 g_lua
.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func
) {
1706 return std::shared_ptr
<DNSResponseAction
>(new LuaResponseAction(func
));
1709 g_lua
.writeFunction("LuaFFIResponseAction", [](LuaFFIResponseAction::func_t func
) {
1711 return std::shared_ptr
<DNSResponseAction
>(new LuaFFIResponseAction(func
));
1714 g_lua
.writeFunction("RemoteLogAction", [](std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(DNSQuestion
*, DNSDistProtoBufMessage
*)> > alterFunc
, boost::optional
<std::unordered_map
<std::string
, std::string
>> vars
) {
1716 // avoids potentially-evaluated-expression warning with clang.
1717 RemoteLoggerInterface
& rl
= *logger
.get();
1718 if (typeid(rl
) != typeid(RemoteLogger
)) {
1719 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1720 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1724 std::string serverID
;
1725 std::string ipEncryptKey
;
1727 if (vars
->count("serverID")) {
1728 serverID
= boost::get
<std::string
>((*vars
)["serverID"]);
1730 if (vars
->count("ipEncryptKey")) {
1731 ipEncryptKey
= boost::get
<std::string
>((*vars
)["ipEncryptKey"]);
1735 #ifdef HAVE_PROTOBUF
1736 return std::shared_ptr
<DNSAction
>(new RemoteLogAction(logger
, alterFunc
, serverID
, ipEncryptKey
));
1738 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1742 g_lua
.writeFunction("RemoteLogResponseAction", [](std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(DNSResponse
*, DNSDistProtoBufMessage
*)> > alterFunc
, boost::optional
<bool> includeCNAME
, boost::optional
<std::unordered_map
<std::string
, std::string
>> vars
) {
1744 // avoids potentially-evaluated-expression warning with clang.
1745 RemoteLoggerInterface
& rl
= *logger
.get();
1746 if (typeid(rl
) != typeid(RemoteLogger
)) {
1747 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1748 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
1752 std::string serverID
;
1753 std::string ipEncryptKey
;
1755 if (vars
->count("serverID")) {
1756 serverID
= boost::get
<std::string
>((*vars
)["serverID"]);
1758 if (vars
->count("ipEncryptKey")) {
1759 ipEncryptKey
= boost::get
<std::string
>((*vars
)["ipEncryptKey"]);
1763 #ifdef HAVE_PROTOBUF
1764 return std::shared_ptr
<DNSResponseAction
>(new RemoteLogResponseAction(logger
, alterFunc
, serverID
, ipEncryptKey
, includeCNAME
? *includeCNAME
: false));
1766 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1770 g_lua
.writeFunction("DnstapLogAction", [](const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(DNSQuestion
*, DnstapMessage
*)> > alterFunc
) {
1771 #ifdef HAVE_PROTOBUF
1772 return std::shared_ptr
<DNSAction
>(new DnstapLogAction(identity
, logger
, alterFunc
));
1774 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1778 g_lua
.writeFunction("DnstapLogResponseAction", [](const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(DNSResponse
*, DnstapMessage
*)> > alterFunc
) {
1779 #ifdef HAVE_PROTOBUF
1780 return std::shared_ptr
<DNSResponseAction
>(new DnstapLogResponseAction(identity
, logger
, alterFunc
));
1782 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1786 g_lua
.writeFunction("TeeAction", [](const std::string
& remote
, boost::optional
<bool> addECS
) {
1787 return std::shared_ptr
<DNSAction
>(new TeeAction(ComboAddress(remote
, 53), addECS
? *addECS
: false));
1790 g_lua
.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength
, uint16_t v6PrefixLength
) {
1791 return std::shared_ptr
<DNSAction
>(new ECSPrefixLengthAction(v4PrefixLength
, v6PrefixLength
));
1794 g_lua
.writeFunction("ECSOverrideAction", [](bool ecsOverride
) {
1795 return std::shared_ptr
<DNSAction
>(new ECSOverrideAction(ecsOverride
));
1798 g_lua
.writeFunction("DisableECSAction", []() {
1799 return std::shared_ptr
<DNSAction
>(new DisableECSAction());
1802 g_lua
.writeFunction("SetECSAction", [](const std::string v4
, boost::optional
<std::string
> v6
) {
1804 return std::shared_ptr
<DNSAction
>(new SetECSAction(Netmask(v4
), Netmask(*v6
)));
1806 return std::shared_ptr
<DNSAction
>(new SetECSAction(Netmask(v4
)));
1809 g_lua
.writeFunction("SNMPTrapAction", [](boost::optional
<std::string
> reason
) {
1810 #ifdef HAVE_NET_SNMP
1811 return std::shared_ptr
<DNSAction
>(new SNMPTrapAction(reason
? *reason
: ""));
1813 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1814 #endif /* HAVE_NET_SNMP */
1817 g_lua
.writeFunction("SNMPTrapResponseAction", [](boost::optional
<std::string
> reason
) {
1818 #ifdef HAVE_NET_SNMP
1819 return std::shared_ptr
<DNSResponseAction
>(new SNMPTrapResponseAction(reason
? *reason
: ""));
1821 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1822 #endif /* HAVE_NET_SNMP */
1825 g_lua
.writeFunction("TagAction", [](std::string tag
, std::string value
) {
1826 return std::shared_ptr
<DNSAction
>(new TagAction(tag
, value
));
1829 g_lua
.writeFunction("TagResponseAction", [](std::string tag
, std::string value
) {
1830 return std::shared_ptr
<DNSResponseAction
>(new TagResponseAction(tag
, value
));
1833 g_lua
.writeFunction("ContinueAction", [](std::shared_ptr
<DNSAction
> action
) {
1834 return std::shared_ptr
<DNSAction
>(new ContinueAction(action
));
1837 #ifdef HAVE_DNS_OVER_HTTPS
1838 g_lua
.writeFunction("HTTPStatusAction", [](uint16_t status
, std::string body
, boost::optional
<std::string
> contentType
, boost::optional
<responseParams_t
> vars
) {
1839 auto ret
= std::shared_ptr
<DNSAction
>(new HTTPStatusAction(status
, body
, contentType
? *contentType
: ""));
1840 auto hsa
= std::dynamic_pointer_cast
<HTTPStatusAction
>(ret
);
1841 parseResponseConfig(vars
, hsa
->d_responseConfig
);
1844 #endif /* HAVE_DNS_OVER_HTTPS */
1846 g_lua
.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr
<KeyValueStore
>& kvs
, std::shared_ptr
<KeyValueLookupKey
>& lookupKey
, const std::string
& destinationTag
) {
1847 return std::shared_ptr
<DNSAction
>(new KeyValueStoreLookupAction(kvs
, lookupKey
, destinationTag
));
1850 g_lua
.writeFunction("SetNegativeAndSOAAction", [](bool nxd
, const std::string
& zone
, uint32_t ttl
, const std::string
& mname
, const std::string
& rname
, uint32_t serial
, uint32_t refresh
, uint32_t retry
, uint32_t expire
, uint32_t minimum
, boost::optional
<responseParams_t
> vars
) {
1851 auto ret
= std::shared_ptr
<DNSAction
>(new SetNegativeAndSOAAction(nxd
, DNSName(zone
), ttl
, DNSName(mname
), DNSName(rname
), serial
, refresh
, retry
, expire
, minimum
));
1852 auto action
= std::dynamic_pointer_cast
<SetNegativeAndSOAAction
>(ret
);
1853 parseResponseConfig(vars
, action
->d_responseConfig
);
1857 g_lua
.writeFunction("SetProxyProtocolValuesAction", [](const std::vector
<std::pair
<uint8_t, std::string
>>& values
) {
1858 return std::shared_ptr
<DNSAction
>(new SetProxyProtocolValuesAction(values
));