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-protobuf.hh"
31 #include "ednsoptions.hh"
32 #include "fstrm_logger.hh"
33 #include "remote_logger.hh"
35 #include <boost/optional/optional_io.hpp>
38 #include "ipcipher.hh"
39 #endif /* HAVE_LIBCRYPTO */
41 class DropAction
: public DNSAction
44 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
48 std::string
toString() const override
54 class AllowAction
: public DNSAction
57 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
61 std::string
toString() const override
67 class NoneAction
: public DNSAction
70 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
74 std::string
toString() const override
80 class QPSAction
: public DNSAction
83 QPSAction(int limit
) : d_qps(limit
, limit
)
85 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
92 std::string
toString() const override
94 return "qps limit to "+std::to_string(d_qps
.getRate());
100 class DelayAction
: public DNSAction
103 DelayAction(int msec
) : d_msec(msec
)
105 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
107 *ruleresult
=std::to_string(d_msec
);
108 return Action::Delay
;
110 std::string
toString() const override
112 return "delay by "+std::to_string(d_msec
)+ " msec";
119 class TeeAction
: public DNSAction
122 TeeAction(const ComboAddress
& ca
, bool addECS
=false);
123 ~TeeAction() override
;
124 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
;
125 std::string
toString() const override
;
126 std::map
<std::string
, double> getStats() const override
;
129 ComboAddress d_remote
;
130 std::thread d_worker
;
134 mutable std::atomic
<unsigned long> d_senderrors
{0};
135 unsigned long d_recverrors
{0};
136 mutable std::atomic
<unsigned long> d_queries
{0};
137 unsigned long d_responses
{0};
138 unsigned long d_nxdomains
{0};
139 unsigned long d_servfails
{0};
140 unsigned long d_refuseds
{0};
141 unsigned long d_formerrs
{0};
142 unsigned long d_notimps
{0};
143 unsigned long d_noerrors
{0};
144 mutable unsigned long d_tcpdrops
{0};
145 unsigned long d_otherrcode
{0};
146 std::atomic
<bool> d_pleaseQuit
{false};
147 bool d_addECS
{false};
150 TeeAction::TeeAction(const ComboAddress
& ca
, bool addECS
) : d_remote(ca
), d_addECS(addECS
)
152 d_fd
=SSocket(d_remote
.sin4
.sin_family
, SOCK_DGRAM
, 0);
153 SConnect(d_fd
, d_remote
);
154 setNonBlocking(d_fd
);
155 d_worker
=std::thread(std::bind(&TeeAction::worker
, this));
158 TeeAction::~TeeAction()
165 DNSAction::Action
TeeAction::operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const
176 uint16_t len
= dq
->len
;
177 bool ednsAdded
= false;
178 bool ecsAdded
= false;
179 query
.reserve(dq
->size
);
180 query
.assign((char*) dq
->dh
, len
);
182 std::string newECSOption
;
183 generateECSOption(dq
->ecsSet
? dq
->ecs
.getNetwork() : *dq
->remote
, newECSOption
, dq
->ecsSet
? dq
->ecs
.getBits() : dq
->ecsPrefixLength
);
185 if (!handleEDNSClientSubnet(const_cast<char*>(query
.c_str()), query
.capacity(), dq
->qname
->wirelength(), &len
, &ednsAdded
, &ecsAdded
, dq
->ecsOverride
, newECSOption
, g_preserveTrailingData
)) {
186 return DNSAction::Action::None
;
189 res
= send(d_fd
, query
.c_str(), len
, 0);
192 res
= send(d_fd
, (char*)dq
->dh
, dq
->len
, 0);
198 return DNSAction::Action::None
;
201 std::string
TeeAction::toString() const
203 return "tee to "+d_remote
.toStringWithPort();
206 std::map
<std::string
,double> TeeAction::getStats() const
208 return {{"queries", d_queries
},
209 {"responses", d_responses
},
210 {"recv-errors", d_recverrors
},
211 {"send-errors", d_senderrors
},
212 {"noerrors", d_noerrors
},
213 {"nxdomains", d_nxdomains
},
214 {"refuseds", d_refuseds
},
215 {"servfails", d_servfails
},
216 {"other-rcode", d_otherrcode
},
217 {"tcp-drops", d_tcpdrops
}
221 void TeeAction::worker()
223 setThreadName("dnsdist/TeeWork");
226 struct dnsheader
* dh
=(struct dnsheader
*)packet
;
228 res
=waitForData(d_fd
, 0, 250000);
237 res
=recv(d_fd
, packet
, sizeof(packet
), 0);
238 if(res
<= (int)sizeof(struct dnsheader
))
243 if(dh
->rcode
== RCode::NoError
)
245 else if(dh
->rcode
== RCode::ServFail
)
247 else if(dh
->rcode
== RCode::NXDomain
)
249 else if(dh
->rcode
== RCode::Refused
)
251 else if(dh
->rcode
== RCode::FormErr
)
253 else if(dh
->rcode
== RCode::NotImp
)
258 class PoolAction
: public DNSAction
261 PoolAction(const std::string
& pool
) : d_pool(pool
) {}
262 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
267 std::string
toString() const override
269 return "to pool "+d_pool
;
277 class QPSPoolAction
: public DNSAction
280 QPSPoolAction(unsigned int limit
, const std::string
& pool
) : d_qps(limit
, limit
), d_pool(pool
) {}
281 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
290 std::string
toString() const override
292 return "max " +std::to_string(d_qps
.getRate())+" to pool "+d_pool
;
300 class RCodeAction
: public DNSAction
303 RCodeAction(uint8_t rcode
) : d_rcode(rcode
) {}
304 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
306 dq
->dh
->rcode
= d_rcode
;
307 dq
->dh
->qr
= true; // for good measure
308 return Action::HeaderModify
;
310 std::string
toString() const override
312 return "set rcode "+std::to_string(d_rcode
);
319 class ERCodeAction
: public DNSAction
322 ERCodeAction(uint8_t rcode
) : d_rcode(rcode
) {}
323 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
325 dq
->dh
->rcode
= (d_rcode
& 0xF);
326 dq
->ednsRCode
= ((d_rcode
& 0xFFF0) >> 4);
327 dq
->dh
->qr
= true; // for good measure
328 return Action::HeaderModify
;
330 std::string
toString() const override
332 return "set ercode "+ERCode::to_s(d_rcode
);
339 class TCAction
: public DNSAction
342 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
344 return Action::Truncate
;
346 std::string
toString() const override
348 return "tc=1 answer";
352 DNSAction::Action
LuaAction::operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const
354 std::lock_guard
<std::mutex
> lock(g_luamutex
);
356 auto ret
= d_func(dq
);
358 if (boost::optional
<std::string
> rule
= std::get
<1>(ret
)) {
362 // default to empty string
366 return (Action
)std::get
<0>(ret
);
367 } catch (std::exception
&e
) {
368 warnlog("LuaAction failed inside lua, returning ServFail: %s", e
.what());
370 warnlog("LuaAction failed inside lua, returning ServFail: [unknown exception]");
372 return DNSAction::Action::ServFail
;
375 DNSResponseAction::Action
LuaResponseAction::operator()(DNSResponse
* dr
, std::string
* ruleresult
) const
377 std::lock_guard
<std::mutex
> lock(g_luamutex
);
379 auto ret
= d_func(dr
);
381 if (boost::optional
<std::string
> rule
= std::get
<1>(ret
)) {
385 // default to empty string
389 return (Action
)std::get
<0>(ret
);
390 } catch (std::exception
&e
) {
391 warnlog("LuaResponseAction failed inside lua, returning ServFail: %s", e
.what());
393 warnlog("LuaResponseAction failed inside lua, returning ServFail: [unknown exception]");
395 return DNSResponseAction::Action::ServFail
;
398 DNSAction::Action
SpoofAction::operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const
400 uint16_t qtype
= dq
->qtype
;
401 // do we even have a response?
402 if(d_cname
.empty() && !std::count_if(d_addrs
.begin(), d_addrs
.end(), [qtype
](const ComboAddress
& a
)
404 return (qtype
== QType::ANY
|| ((a
.sin4
.sin_family
== AF_INET
&& qtype
== QType::A
) ||
405 (a
.sin4
.sin_family
== AF_INET6
&& qtype
== QType::AAAA
)));
409 vector
<ComboAddress
> addrs
;
410 unsigned int totrdatalen
=0;
411 if (!d_cname
.empty()) {
412 qtype
= QType::CNAME
;
413 totrdatalen
+= d_cname
.toDNSString().size();
415 for(const auto& addr
: d_addrs
) {
416 if(qtype
!= QType::ANY
&& ((addr
.sin4
.sin_family
== AF_INET
&& qtype
!= QType::A
) ||
417 (addr
.sin4
.sin_family
== AF_INET6
&& qtype
!= QType::AAAA
))) {
420 totrdatalen
+= addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
);
421 addrs
.push_back(addr
);
426 random_shuffle(addrs
.begin(), addrs
.end());
428 unsigned int consumed
=0;
429 DNSName
ignore((char*)dq
->dh
, dq
->len
, sizeof(dnsheader
), false, 0, 0, &consumed
);
431 if (dq
->size
< (sizeof(dnsheader
) + consumed
+ 4 + ((d_cname
.empty() ? 0 : 1) + addrs
.size())*12 /* recordstart */ + totrdatalen
)) {
435 bool dnssecOK
= false;
436 bool hadEDNS
= false;
437 if (g_addEDNSToSelfGeneratedResponses
&& queryHasEDNS(*dq
)) {
439 dnssecOK
= getEDNSZ(*dq
) & EDNS_HEADER_FLAG_DO
;
442 dq
->len
= sizeof(dnsheader
) + consumed
+ 4; // there goes your EDNS
443 char* dest
= ((char*)dq
->dh
) + dq
->len
;
445 dq
->dh
->qr
= true; // for good measure
446 dq
->dh
->ra
= dq
->dh
->rd
; // for good measure
449 dq
->dh
->arcount
= 0; // for now, forget about your EDNS, we're marching over it
451 if(qtype
== QType::CNAME
) {
452 std::string wireData
= d_cname
.toDNSString(); // Note! This doesn't do compression!
453 const unsigned char recordstart
[]={0xc0, 0x0c, // compressed name
454 0, (unsigned char) qtype
,
457 0, (unsigned char)wireData
.length()};
458 static_assert(sizeof(recordstart
) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
460 memcpy(dest
, recordstart
, sizeof(recordstart
));
461 dest
+= sizeof(recordstart
);
462 memcpy(dest
, wireData
.c_str(), wireData
.length());
463 dq
->len
+= wireData
.length() + sizeof(recordstart
);
467 for(const auto& addr
: addrs
) {
468 unsigned char rdatalen
= addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
);
469 const unsigned char recordstart
[]={0xc0, 0x0c, // compressed name
470 0, (unsigned char) (addr
.sin4
.sin_family
== AF_INET
? QType::A
: QType::AAAA
),
474 static_assert(sizeof(recordstart
) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
476 memcpy(dest
, recordstart
, sizeof(recordstart
));
477 dest
+= sizeof(recordstart
);
480 addr
.sin4
.sin_family
== AF_INET
? (void*)&addr
.sin4
.sin_addr
.s_addr
: (void*)&addr
.sin6
.sin6_addr
.s6_addr
,
483 dq
->len
+= rdatalen
+ sizeof(recordstart
);
488 dq
->dh
->ancount
= htons(dq
->dh
->ancount
);
491 addEDNS(dq
->dh
, dq
->len
, dq
->size
, dnssecOK
, g_PayloadSizeSelfGenAnswers
, 0);
494 return Action::HeaderModify
;
497 class MacAddrAction
: public DNSAction
500 MacAddrAction(uint16_t code
) : d_code(code
)
502 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
507 std::string mac
= getMACAddress(*dq
->remote
);
511 std::string optRData
;
512 generateEDNSOption(d_code
, mac
, optRData
);
515 generateOptRR(optRData
, res
, g_EdnsUDPPayloadSize
, 0, false);
517 if ((dq
->size
- dq
->len
) < res
.length())
520 dq
->dh
->arcount
= htons(1);
521 char* dest
= ((char*)dq
->dh
) + dq
->len
;
522 memcpy(dest
, res
.c_str(), res
.length());
523 dq
->len
+= res
.length();
527 std::string
toString() const override
529 return "add EDNS MAC (code="+std::to_string(d_code
)+")";
535 class NoRecurseAction
: public DNSAction
538 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
543 std::string
toString() const override
549 class LogAction
: public DNSAction
, public boost::noncopyable
552 LogAction() : d_fp(0)
555 LogAction(const std::string
& str
, bool binary
=true, bool append
=false, bool buffered
=true) : d_fname(str
), d_binary(binary
)
560 d_fp
= fopen(str
.c_str(), "a+");
562 d_fp
= fopen(str
.c_str(), "w");
564 throw std::runtime_error("Unable to open file '"+str
+"' for logging: "+std::string(strerror(errno
)));
568 ~LogAction() override
573 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
576 vinfolog("Packet from %s for %s %s with id %d", dq
->remote
->toStringWithPort(), dq
->qname
->toString(), QType(dq
->qtype
).getName(), dq
->dh
->id
);
580 std::string out
= dq
->qname
->toDNSString();
581 fwrite(out
.c_str(), 1, out
.size(), d_fp
);
582 fwrite((void*)&dq
->qtype
, 1, 2, d_fp
);
585 fprintf(d_fp
, "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
);
590 std::string
toString() const override
592 if (!d_fname
.empty()) {
593 return "log to " + d_fname
;
604 class DisableValidationAction
: public DNSAction
607 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
612 std::string
toString() const override
618 class SkipCacheAction
: public DNSAction
621 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
623 dq
->skipCache
= true;
626 std::string
toString() const override
632 class TempFailureCacheTTLAction
: public DNSAction
635 TempFailureCacheTTLAction(uint32_t ttl
) : d_ttl(ttl
)
637 TempFailureCacheTTLAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
639 dq
->tempFailureTTL
= d_ttl
;
642 std::string
toString() const override
644 return "set tempfailure cache ttl to "+std::to_string(d_ttl
);
650 class ECSPrefixLengthAction
: public DNSAction
653 ECSPrefixLengthAction(uint16_t v4Length
, uint16_t v6Length
) : d_v4PrefixLength(v4Length
), d_v6PrefixLength(v6Length
)
656 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
658 dq
->ecsPrefixLength
= dq
->remote
->sin4
.sin_family
== AF_INET
? d_v4PrefixLength
: d_v6PrefixLength
;
661 std::string
toString() const override
663 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength
) + "/" + std::to_string(d_v6PrefixLength
);
666 uint16_t d_v4PrefixLength
;
667 uint16_t d_v6PrefixLength
;
670 class ECSOverrideAction
: public DNSAction
673 ECSOverrideAction(bool ecsOverride
) : d_ecsOverride(ecsOverride
)
676 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
678 dq
->ecsOverride
= d_ecsOverride
;
681 std::string
toString() const override
683 return "set ECS override to " + std::to_string(d_ecsOverride
);
690 class DisableECSAction
: public DNSAction
693 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
698 std::string
toString() const override
700 return "disable ECS";
704 class SetECSAction
: public DNSAction
707 SetECSAction(const Netmask
& v4
): d_v4(v4
), d_hasV6(false)
711 SetECSAction(const Netmask
& v4
, const Netmask
& v6
): d_v4(v4
), d_v6(v6
), d_hasV6(true)
715 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
720 dq
->ecs
= dq
->remote
->isIPv4() ? d_v4
: d_v6
;
729 std::string
toString() const override
731 std::string result
= "set ECS to " + d_v4
.toString();
733 result
+= " / " + d_v6
.toString();
745 class DnstapLogAction
: public DNSAction
, public boost::noncopyable
748 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
)
751 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
754 DnstapMessage
message(d_identity
, dq
->remote
, dq
->local
, dq
->tcp
, reinterpret_cast<const char*>(dq
->dh
), dq
->len
, dq
->queryTime
, nullptr);
757 std::lock_guard
<std::mutex
> lock(g_luamutex
);
758 (*d_alterFunc
)(dq
, &message
);
762 message
.serialize(data
);
763 d_logger
->queueData(data
);
764 #endif /* HAVE_PROTOBUF */
767 std::string
toString() const override
769 return "remote log as dnstap to " + (d_logger
? d_logger
->toString() : "");
772 std::string d_identity
;
773 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
774 boost::optional
<std::function
<void(DNSQuestion
*, DnstapMessage
*)> > d_alterFunc
;
777 class RemoteLogAction
: public DNSAction
, public boost::noncopyable
780 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
)
783 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
787 dq
->uniqueId
= getUniqueID();
790 DNSDistProtoBufMessage
message(*dq
);
791 if (!d_serverID
.empty()) {
792 message
.setServerIdentity(d_serverID
);
796 if (!d_ipEncryptKey
.empty())
798 message
.setRequestor(encryptCA(*dq
->remote
, d_ipEncryptKey
));
800 #endif /* HAVE_LIBCRYPTO */
803 std::lock_guard
<std::mutex
> lock(g_luamutex
);
804 (*d_alterFunc
)(dq
, &message
);
808 message
.serialize(data
);
809 d_logger
->queueData(data
);
810 #endif /* HAVE_PROTOBUF */
813 std::string
toString() const override
815 return "remote log to " + (d_logger
? d_logger
->toString() : "");
818 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
819 boost::optional
<std::function
<void(DNSQuestion
*, DNSDistProtoBufMessage
*)> > d_alterFunc
;
820 std::string d_serverID
;
821 std::string d_ipEncryptKey
;
824 class SNMPTrapAction
: public DNSAction
827 SNMPTrapAction(const std::string
& reason
): d_reason(reason
)
830 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
832 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
833 g_snmpAgent
->sendDNSTrap(*dq
, d_reason
);
838 std::string
toString() const override
840 return "send SNMP trap";
843 std::string d_reason
;
846 class TagAction
: public DNSAction
849 TagAction(const std::string
& tag
, const std::string
& value
): d_tag(tag
), d_value(value
)
852 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
855 dq
->qTag
= std::make_shared
<QTag
>();
858 dq
->qTag
->insert({d_tag
, d_value
});
862 std::string
toString() const override
864 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
871 class DnstapLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
874 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
)
877 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
882 DnstapMessage
message(d_identity
, dr
->remote
, dr
->local
, dr
->tcp
, reinterpret_cast<const char*>(dr
->dh
), dr
->len
, dr
->queryTime
, &now
);
885 std::lock_guard
<std::mutex
> lock(g_luamutex
);
886 (*d_alterFunc
)(dr
, &message
);
890 message
.serialize(data
);
891 d_logger
->queueData(data
);
892 #endif /* HAVE_PROTOBUF */
895 std::string
toString() const override
897 return "log response as dnstap to " + (d_logger
? d_logger
->toString() : "");
900 std::string d_identity
;
901 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
902 boost::optional
<std::function
<void(DNSResponse
*, DnstapMessage
*)> > d_alterFunc
;
905 class RemoteLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
908 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
)
911 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
915 dr
->uniqueId
= getUniqueID();
918 DNSDistProtoBufMessage
message(*dr
, d_includeCNAME
);
919 if (!d_serverID
.empty()) {
920 message
.setServerIdentity(d_serverID
);
924 if (!d_ipEncryptKey
.empty())
926 message
.setRequestor(encryptCA(*dr
->remote
, d_ipEncryptKey
));
928 #endif /* HAVE_LIBCRYPTO */
931 std::lock_guard
<std::mutex
> lock(g_luamutex
);
932 (*d_alterFunc
)(dr
, &message
);
936 message
.serialize(data
);
937 d_logger
->queueData(data
);
938 #endif /* HAVE_PROTOBUF */
941 std::string
toString() const override
943 return "remote log response to " + (d_logger
? d_logger
->toString() : "");
946 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
947 boost::optional
<std::function
<void(DNSResponse
*, DNSDistProtoBufMessage
*)> > d_alterFunc
;
948 std::string d_serverID
;
949 std::string d_ipEncryptKey
;
953 class DropResponseAction
: public DNSResponseAction
956 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
960 std::string
toString() const override
966 class AllowResponseAction
: public DNSResponseAction
969 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
971 return Action::Allow
;
973 std::string
toString() const override
979 class DelayResponseAction
: public DNSResponseAction
982 DelayResponseAction(int msec
) : d_msec(msec
)
984 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
986 *ruleresult
=std::to_string(d_msec
);
987 return Action::Delay
;
989 std::string
toString() const override
991 return "delay by "+std::to_string(d_msec
)+ " msec";
997 class SNMPTrapResponseAction
: public DNSResponseAction
1000 SNMPTrapResponseAction(const std::string
& reason
): d_reason(reason
)
1003 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1005 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
1006 g_snmpAgent
->sendDNSTrap(*dr
, d_reason
);
1009 return Action::None
;
1011 std::string
toString() const override
1013 return "send SNMP trap";
1016 std::string d_reason
;
1019 class TagResponseAction
: public DNSResponseAction
1022 TagResponseAction(const std::string
& tag
, const std::string
& value
): d_tag(tag
), d_value(value
)
1025 DNSResponseAction::Action
operator()(DNSResponse
* dr
, std::string
* ruleresult
) const override
1028 dr
->qTag
= std::make_shared
<QTag
>();
1031 dr
->qTag
->insert({d_tag
, d_value
});
1033 return Action::None
;
1035 std::string
toString() const override
1037 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
1041 std::string d_value
;
1044 class ContinueAction
: public DNSAction
1047 ContinueAction(std::shared_ptr
<DNSAction
>& action
): d_action(action
)
1051 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1054 /* call the action */
1055 auto action
= (*d_action
)(dq
, ruleresult
);
1057 /* apply the changes if needed (pool selection, flags, etc */
1058 processRulesResult(action
, *dq
, *ruleresult
, drop
);
1061 /* but ignore the resulting action no matter what */
1062 return Action::None
;
1065 std::string
toString() const override
1068 return "continue after: " + (d_action
? d_action
->toString() : "");
1076 std::shared_ptr
<DNSAction
> d_action
;
1080 #ifdef HAVE_DNS_OVER_HTTPS
1081 class HTTPStatusAction
: public DNSAction
1084 HTTPStatusAction(int code
, const std::string
& reason
, const std::string
& body
): d_reason(reason
), d_body(body
), d_code(code
)
1088 DNSAction::Action
operator()(DNSQuestion
* dq
, std::string
* ruleresult
) const override
1091 return Action::None
;
1094 dq
->du
->setHTTPResponse(d_code
, d_reason
, d_body
);
1095 dq
->dh
->qr
= true; // for good measure
1096 return Action::HeaderModify
;
1099 std::string
toString() const override
1101 return "return an HTTP status of " + std::to_string(d_code
);
1104 std::string d_reason
;
1108 #endif /* HAVE_DNS_OVER_HTTPS */
1110 template<typename T
, typename ActionT
>
1111 static void addAction(GlobalStateHolder
<vector
<T
> > *someRulActions
, luadnsrule_t var
, std::shared_ptr
<ActionT
> action
, boost::optional
<luaruleparams_t
> params
) {
1114 boost::uuids::uuid uuid
;
1115 uint64_t creationOrder
;
1116 parseRuleParams(params
, uuid
, creationOrder
);
1118 auto rule
=makeRule(var
);
1119 someRulActions
->modify([rule
, action
, uuid
, creationOrder
](vector
<T
>& rulactions
){
1120 rulactions
.push_back({rule
, action
, uuid
, creationOrder
});
1124 void setupLuaActions()
1126 g_lua
.writeFunction("newRuleAction", [](luadnsrule_t dnsrule
, std::shared_ptr
<DNSAction
> action
, boost::optional
<luaruleparams_t
> params
) {
1127 boost::uuids::uuid uuid
;
1128 uint64_t creationOrder
;
1129 parseRuleParams(params
, uuid
, creationOrder
);
1131 auto rule
=makeRule(dnsrule
);
1132 DNSDistRuleAction
ra({rule
, action
, uuid
, creationOrder
});
1133 return std::make_shared
<DNSDistRuleAction
>(ra
);
1136 g_lua
.writeFunction("addAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
> > era
, boost::optional
<luaruleparams_t
> params
) {
1137 if (era
.type() != typeid(std::shared_ptr
<DNSAction
>)) {
1138 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
1141 addAction(&g_rulactions
, var
, boost::get
<std::shared_ptr
<DNSAction
> >(era
), params
);
1144 g_lua
.writeFunction("addResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
> > era
, boost::optional
<luaruleparams_t
> params
) {
1145 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
1146 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1149 addAction(&g_resprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
1152 g_lua
.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
>> era
, boost::optional
<luaruleparams_t
> params
) {
1153 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
1154 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1157 addAction(&g_cachehitresprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
1160 g_lua
.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
>> era
, boost::optional
<luaruleparams_t
> params
) {
1161 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
1162 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1165 addAction(&g_selfansweredresprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
1168 g_lua
.registerFunction
<void(DNSAction::*)()>("printStats", [](const DNSAction
& ta
) {
1169 setLuaNoSideEffect();
1170 auto stats
= ta
.getStats();
1171 for(const auto& s
: stats
) {
1172 g_outputBuffer
+=s
.first
+"\t";
1173 if((uint64_t)s
.second
== s
.second
)
1174 g_outputBuffer
+= std::to_string((uint64_t)s
.second
)+"\n";
1176 g_outputBuffer
+= std::to_string(s
.second
)+"\n";
1180 g_lua
.writeFunction("getAction", [](unsigned int num
) {
1181 setLuaNoSideEffect();
1182 boost::optional
<std::shared_ptr
<DNSAction
>> ret
;
1183 auto rulactions
= g_rulactions
.getCopy();
1184 if(num
< rulactions
.size())
1185 ret
=rulactions
[num
].d_action
;
1189 g_lua
.registerFunction("getStats", &DNSAction::getStats
);
1191 g_lua
.writeFunction("LuaAction", [](LuaAction::func_t func
) {
1193 return std::shared_ptr
<DNSAction
>(new LuaAction(func
));
1196 g_lua
.writeFunction("NoRecurseAction", []() {
1197 return std::shared_ptr
<DNSAction
>(new NoRecurseAction
);
1200 g_lua
.writeFunction("MacAddrAction", [](int code
) {
1201 return std::shared_ptr
<DNSAction
>(new MacAddrAction(code
));
1204 g_lua
.writeFunction("PoolAction", [](const std::string
& a
) {
1205 return std::shared_ptr
<DNSAction
>(new PoolAction(a
));
1208 g_lua
.writeFunction("QPSAction", [](int limit
) {
1209 return std::shared_ptr
<DNSAction
>(new QPSAction(limit
));
1212 g_lua
.writeFunction("QPSPoolAction", [](int limit
, const std::string
& a
) {
1213 return std::shared_ptr
<DNSAction
>(new QPSPoolAction(limit
, a
));
1216 g_lua
.writeFunction("SpoofAction", [](boost::variant
<std::string
,vector
<pair
<int, std::string
>>> inp
, boost::optional
<std::string
> b
) {
1217 vector
<ComboAddress
> addrs
;
1218 if(auto s
= boost::get
<std::string
>(&inp
))
1219 addrs
.push_back(ComboAddress(*s
));
1221 const auto& v
= boost::get
<vector
<pair
<int,std::string
>>>(inp
);
1222 for(const auto& a
: v
)
1223 addrs
.push_back(ComboAddress(a
.second
));
1226 addrs
.push_back(ComboAddress(*b
));
1227 return std::shared_ptr
<DNSAction
>(new SpoofAction(addrs
));
1230 g_lua
.writeFunction("SpoofCNAMEAction", [](const std::string
& a
) {
1231 return std::shared_ptr
<DNSAction
>(new SpoofAction(a
));
1234 g_lua
.writeFunction("DropAction", []() {
1235 return std::shared_ptr
<DNSAction
>(new DropAction
);
1238 g_lua
.writeFunction("AllowAction", []() {
1239 return std::shared_ptr
<DNSAction
>(new AllowAction
);
1242 g_lua
.writeFunction("NoneAction", []() {
1243 return std::shared_ptr
<DNSAction
>(new NoneAction
);
1246 g_lua
.writeFunction("DelayAction", [](int msec
) {
1247 return std::shared_ptr
<DNSAction
>(new DelayAction(msec
));
1250 g_lua
.writeFunction("TCAction", []() {
1251 return std::shared_ptr
<DNSAction
>(new TCAction
);
1254 g_lua
.writeFunction("DisableValidationAction", []() {
1255 return std::shared_ptr
<DNSAction
>(new DisableValidationAction
);
1258 g_lua
.writeFunction("LogAction", [](const std::string
& fname
, boost::optional
<bool> binary
, boost::optional
<bool> append
, boost::optional
<bool> buffered
) {
1259 return std::shared_ptr
<DNSAction
>(new LogAction(fname
, binary
? *binary
: true, append
? *append
: false, buffered
? *buffered
: false));
1262 g_lua
.writeFunction("RCodeAction", [](uint8_t rcode
) {
1263 return std::shared_ptr
<DNSAction
>(new RCodeAction(rcode
));
1266 g_lua
.writeFunction("ERCodeAction", [](uint8_t rcode
) {
1267 return std::shared_ptr
<DNSAction
>(new ERCodeAction(rcode
));
1270 g_lua
.writeFunction("SkipCacheAction", []() {
1271 return std::shared_ptr
<DNSAction
>(new SkipCacheAction
);
1274 g_lua
.writeFunction("TempFailureCacheTTLAction", [](int maxTTL
) {
1275 return std::shared_ptr
<DNSAction
>(new TempFailureCacheTTLAction(maxTTL
));
1278 g_lua
.writeFunction("DropResponseAction", []() {
1279 return std::shared_ptr
<DNSResponseAction
>(new DropResponseAction
);
1282 g_lua
.writeFunction("AllowResponseAction", []() {
1283 return std::shared_ptr
<DNSResponseAction
>(new AllowResponseAction
);
1286 g_lua
.writeFunction("DelayResponseAction", [](int msec
) {
1287 return std::shared_ptr
<DNSResponseAction
>(new DelayResponseAction(msec
));
1290 g_lua
.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func
) {
1292 return std::shared_ptr
<DNSResponseAction
>(new LuaResponseAction(func
));
1295 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
) {
1296 // avoids potentially-evaluated-expression warning with clang.
1297 RemoteLoggerInterface
& rl
= *logger
.get();
1298 if (typeid(rl
) != typeid(RemoteLogger
)) {
1299 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1300 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1303 std::string serverID
;
1304 std::string ipEncryptKey
;
1306 if (vars
->count("serverID")) {
1307 serverID
= boost::get
<std::string
>((*vars
)["serverID"]);
1309 if (vars
->count("ipEncryptKey")) {
1310 ipEncryptKey
= boost::get
<std::string
>((*vars
)["ipEncryptKey"]);
1314 #ifdef HAVE_PROTOBUF
1315 return std::shared_ptr
<DNSAction
>(new RemoteLogAction(logger
, alterFunc
, serverID
, ipEncryptKey
));
1317 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1321 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
) {
1322 // avoids potentially-evaluated-expression warning with clang.
1323 RemoteLoggerInterface
& rl
= *logger
.get();
1324 if (typeid(rl
) != typeid(RemoteLogger
)) {
1325 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1326 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
1329 std::string serverID
;
1330 std::string ipEncryptKey
;
1332 if (vars
->count("serverID")) {
1333 serverID
= boost::get
<std::string
>((*vars
)["serverID"]);
1335 if (vars
->count("ipEncryptKey")) {
1336 ipEncryptKey
= boost::get
<std::string
>((*vars
)["ipEncryptKey"]);
1340 #ifdef HAVE_PROTOBUF
1341 return std::shared_ptr
<DNSResponseAction
>(new RemoteLogResponseAction(logger
, alterFunc
, serverID
, ipEncryptKey
, includeCNAME
? *includeCNAME
: false));
1343 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1347 g_lua
.writeFunction("DnstapLogAction", [](const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(DNSQuestion
*, DnstapMessage
*)> > alterFunc
) {
1348 #ifdef HAVE_PROTOBUF
1349 return std::shared_ptr
<DNSAction
>(new DnstapLogAction(identity
, logger
, alterFunc
));
1351 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1355 g_lua
.writeFunction("DnstapLogResponseAction", [](const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(DNSResponse
*, DnstapMessage
*)> > alterFunc
) {
1356 #ifdef HAVE_PROTOBUF
1357 return std::shared_ptr
<DNSResponseAction
>(new DnstapLogResponseAction(identity
, logger
, alterFunc
));
1359 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1363 g_lua
.writeFunction("TeeAction", [](const std::string
& remote
, boost::optional
<bool> addECS
) {
1364 return std::shared_ptr
<DNSAction
>(new TeeAction(ComboAddress(remote
, 53), addECS
? *addECS
: false));
1367 g_lua
.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength
, uint16_t v6PrefixLength
) {
1368 return std::shared_ptr
<DNSAction
>(new ECSPrefixLengthAction(v4PrefixLength
, v6PrefixLength
));
1371 g_lua
.writeFunction("ECSOverrideAction", [](bool ecsOverride
) {
1372 return std::shared_ptr
<DNSAction
>(new ECSOverrideAction(ecsOverride
));
1375 g_lua
.writeFunction("DisableECSAction", []() {
1376 return std::shared_ptr
<DNSAction
>(new DisableECSAction());
1379 g_lua
.writeFunction("SetECSAction", [](const std::string v4
, boost::optional
<std::string
> v6
) {
1381 return std::shared_ptr
<DNSAction
>(new SetECSAction(Netmask(v4
), Netmask(*v6
)));
1383 return std::shared_ptr
<DNSAction
>(new SetECSAction(Netmask(v4
)));
1386 g_lua
.writeFunction("SNMPTrapAction", [](boost::optional
<std::string
> reason
) {
1387 #ifdef HAVE_NET_SNMP
1388 return std::shared_ptr
<DNSAction
>(new SNMPTrapAction(reason
? *reason
: ""));
1390 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1391 #endif /* HAVE_NET_SNMP */
1394 g_lua
.writeFunction("SNMPTrapResponseAction", [](boost::optional
<std::string
> reason
) {
1395 #ifdef HAVE_NET_SNMP
1396 return std::shared_ptr
<DNSResponseAction
>(new SNMPTrapResponseAction(reason
? *reason
: ""));
1398 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1399 #endif /* HAVE_NET_SNMP */
1402 g_lua
.writeFunction("TagAction", [](std::string tag
, std::string value
) {
1403 return std::shared_ptr
<DNSAction
>(new TagAction(tag
, value
));
1406 g_lua
.writeFunction("TagResponseAction", [](std::string tag
, std::string value
) {
1407 return std::shared_ptr
<DNSResponseAction
>(new TagResponseAction(tag
, value
));
1410 g_lua
.writeFunction("ContinueAction", [](std::shared_ptr
<DNSAction
> action
) {
1411 return std::shared_ptr
<DNSAction
>(new ContinueAction(action
));
1414 #ifdef HAVE_DNS_OVER_HTTPS
1415 g_lua
.writeFunction("HTTPStatusAction", [](uint16_t status
, std::string reason
, std::string body
) {
1416 return std::shared_ptr
<DNSAction
>(new HTTPStatusAction(status
, reason
, body
));
1418 #endif /* HAVE_DNS_OVER_HTTPS */