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 "dnsdist-ecs.hh"
24 #include "dnsdist-lua.hh"
25 #include "dnsdist-protobuf.hh"
29 #include "ednsoptions.hh"
30 #include "fstrm_logger.hh"
31 #include "remote_logger.hh"
33 class DropAction
: public DNSAction
36 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
40 string
toString() const override
46 class AllowAction
: public DNSAction
49 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
53 string
toString() const override
60 class QPSAction
: public DNSAction
63 QPSAction(int limit
) : d_qps(limit
, limit
)
65 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
72 string
toString() const override
74 return "qps limit to "+std::to_string(d_qps
.getRate());
80 class DelayAction
: public DNSAction
83 DelayAction(int msec
) : d_msec(msec
)
85 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
87 *ruleresult
=std::to_string(d_msec
);
90 string
toString() const override
92 return "delay by "+std::to_string(d_msec
)+ " msec";
99 class TeeAction
: public DNSAction
102 TeeAction(const ComboAddress
& ca
, bool addECS
=false);
103 ~TeeAction() override
;
104 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
;
105 string
toString() const override
;
106 std::map
<string
, double> getStats() const override
;
109 ComboAddress d_remote
;
110 std::thread d_worker
;
114 mutable std::atomic
<unsigned long> d_senderrors
{0};
115 unsigned long d_recverrors
{0};
116 mutable std::atomic
<unsigned long> d_queries
{0};
117 unsigned long d_responses
{0};
118 unsigned long d_nxdomains
{0};
119 unsigned long d_servfails
{0};
120 unsigned long d_refuseds
{0};
121 unsigned long d_formerrs
{0};
122 unsigned long d_notimps
{0};
123 unsigned long d_noerrors
{0};
124 mutable unsigned long d_tcpdrops
{0};
125 unsigned long d_otherrcode
{0};
126 std::atomic
<bool> d_pleaseQuit
{false};
127 bool d_addECS
{false};
130 TeeAction::TeeAction(const ComboAddress
& ca
, bool addECS
) : d_remote(ca
), d_addECS(addECS
)
132 d_fd
=SSocket(d_remote
.sin4
.sin_family
, SOCK_DGRAM
, 0);
133 SConnect(d_fd
, d_remote
);
134 setNonBlocking(d_fd
);
135 d_worker
=std::thread(std::bind(&TeeAction::worker
, this));
138 TeeAction::~TeeAction()
146 DNSAction::Action
TeeAction::operator()(DNSQuestion
* dq
, string
* ruleresult
) const
157 uint16_t len
= dq
->len
;
158 bool ednsAdded
= false;
159 bool ecsAdded
= false;
160 query
.reserve(dq
->size
);
161 query
.assign((char*) dq
->dh
, len
);
163 if (!handleEDNSClientSubnet((char*) query
.c_str(), query
.capacity(), dq
->qname
->wirelength(), &len
, &ednsAdded
, &ecsAdded
, *dq
->remote
, dq
->ecsOverride
, dq
->ecsPrefixLength
)) {
164 return DNSAction::Action::None
;
167 res
= send(d_fd
, query
.c_str(), len
, 0);
170 res
= send(d_fd
, (char*)dq
->dh
, dq
->len
, 0);
176 return DNSAction::Action::None
;
179 string
TeeAction::toString() const
181 return "tee to "+d_remote
.toStringWithPort();
184 std::map
<string
,double> TeeAction::getStats() const
186 return {{"queries", d_queries
},
187 {"responses", d_responses
},
188 {"recv-errors", d_recverrors
},
189 {"send-errors", d_senderrors
},
190 {"noerrors", d_noerrors
},
191 {"nxdomains", d_nxdomains
},
192 {"refuseds", d_refuseds
},
193 {"servfails", d_servfails
},
194 {"other-rcode", d_otherrcode
},
195 {"tcp-drops", d_tcpdrops
}
199 void TeeAction::worker()
203 struct dnsheader
* dh
=(struct dnsheader
*)packet
;
205 res
=waitForData(d_fd
, 0, 250000);
214 res
=recv(d_fd
, packet
, sizeof(packet
), 0);
215 if(res
<= (int)sizeof(struct dnsheader
))
220 if(dh
->rcode
== RCode::NoError
)
222 else if(dh
->rcode
== RCode::ServFail
)
224 else if(dh
->rcode
== RCode::NXDomain
)
226 else if(dh
->rcode
== RCode::Refused
)
228 else if(dh
->rcode
== RCode::FormErr
)
230 else if(dh
->rcode
== RCode::NotImp
)
235 class PoolAction
: public DNSAction
238 PoolAction(const std::string
& pool
) : d_pool(pool
) {}
239 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
244 string
toString() const override
246 return "to pool "+d_pool
;
254 class QPSPoolAction
: public DNSAction
257 QPSPoolAction(unsigned int limit
, const std::string
& pool
) : d_qps(limit
, limit
), d_pool(pool
) {}
258 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
267 string
toString() const override
269 return "max " +std::to_string(d_qps
.getRate())+" to pool "+d_pool
;
277 class RCodeAction
: public DNSAction
280 RCodeAction(uint8_t rcode
) : d_rcode(rcode
) {}
281 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
283 dq
->dh
->rcode
= d_rcode
;
284 dq
->dh
->qr
= true; // for good measure
285 return Action::HeaderModify
;
287 string
toString() const override
289 return "set rcode "+std::to_string(d_rcode
);
296 class TCAction
: public DNSAction
299 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
301 return Action::Truncate
;
303 string
toString() const override
305 return "tc=1 answer";
309 DNSAction::Action
LuaAction::operator()(DNSQuestion
* dq
, string
* ruleresult
) const
311 std::lock_guard
<std::mutex
> lock(g_luamutex
);
313 auto ret
= d_func(dq
);
315 *ruleresult
=std::get
<1>(ret
);
316 return (Action
)std::get
<0>(ret
);
317 } catch (std::exception
&e
) {
318 warnlog("LuaAction failed inside lua, returning ServFail: %s", e
.what());
320 warnlog("LuaAction failed inside lua, returning ServFail: [unknown exception]");
322 return DNSAction::Action::ServFail
;
325 DNSResponseAction::Action
LuaResponseAction::operator()(DNSResponse
* dr
, string
* ruleresult
) const
327 std::lock_guard
<std::mutex
> lock(g_luamutex
);
329 auto ret
= d_func(dr
);
331 *ruleresult
=std::get
<1>(ret
);
332 return (Action
)std::get
<0>(ret
);
333 } catch (std::exception
&e
) {
334 warnlog("LuaResponseAction failed inside lua, returning ServFail: %s", e
.what());
336 warnlog("LuaResponseAction failed inside lua, returning ServFail: [unknown exception]");
338 return DNSResponseAction::Action::ServFail
;
341 DNSAction::Action
SpoofAction::operator()(DNSQuestion
* dq
, string
* ruleresult
) const
343 uint16_t qtype
= dq
->qtype
;
344 // do we even have a response?
345 if(d_cname
.empty() && !std::count_if(d_addrs
.begin(), d_addrs
.end(), [qtype
](const ComboAddress
& a
)
347 return (qtype
== QType::ANY
|| ((a
.sin4
.sin_family
== AF_INET
&& qtype
== QType::A
) ||
348 (a
.sin4
.sin_family
== AF_INET6
&& qtype
== QType::AAAA
)));
352 vector
<ComboAddress
> addrs
;
353 unsigned int totrdatalen
=0;
354 if (!d_cname
.empty()) {
355 qtype
= QType::CNAME
;
356 totrdatalen
+= d_cname
.toDNSString().size();
358 for(const auto& addr
: d_addrs
) {
359 if(qtype
!= QType::ANY
&& ((addr
.sin4
.sin_family
== AF_INET
&& qtype
!= QType::A
) ||
360 (addr
.sin4
.sin_family
== AF_INET6
&& qtype
!= QType::AAAA
))) {
363 totrdatalen
+= addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
);
364 addrs
.push_back(addr
);
369 random_shuffle(addrs
.begin(), addrs
.end());
371 unsigned int consumed
=0;
372 DNSName
ignore((char*)dq
->dh
, dq
->len
, sizeof(dnsheader
), false, 0, 0, &consumed
);
374 if (dq
->size
< (sizeof(dnsheader
) + consumed
+ 4 + ((d_cname
.empty() ? 0 : 1) + addrs
.size())*12 /* recordstart */ + totrdatalen
)) {
378 dq
->len
= sizeof(dnsheader
) + consumed
+ 4; // there goes your EDNS
379 char* dest
= ((char*)dq
->dh
) + dq
->len
;
381 dq
->dh
->qr
= true; // for good measure
382 dq
->dh
->ra
= dq
->dh
->rd
; // for good measure
385 dq
->dh
->arcount
= 0; // for now, forget about your EDNS, we're marching over it
387 if(qtype
== QType::CNAME
) {
388 string wireData
= d_cname
.toDNSString(); // Note! This doesn't do compression!
389 const unsigned char recordstart
[]={0xc0, 0x0c, // compressed name
390 0, (unsigned char) qtype
,
393 0, (unsigned char)wireData
.length()};
394 static_assert(sizeof(recordstart
) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
396 memcpy(dest
, recordstart
, sizeof(recordstart
));
397 dest
+= sizeof(recordstart
);
398 memcpy(dest
, wireData
.c_str(), wireData
.length());
399 dq
->len
+= wireData
.length() + sizeof(recordstart
);
403 for(const auto& addr
: addrs
) {
404 unsigned char rdatalen
= addr
.sin4
.sin_family
== AF_INET
? sizeof(addr
.sin4
.sin_addr
.s_addr
) : sizeof(addr
.sin6
.sin6_addr
.s6_addr
);
405 const unsigned char recordstart
[]={0xc0, 0x0c, // compressed name
406 0, (unsigned char) (addr
.sin4
.sin_family
== AF_INET
? QType::A
: QType::AAAA
),
410 static_assert(sizeof(recordstart
) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
412 memcpy(dest
, recordstart
, sizeof(recordstart
));
413 dest
+= sizeof(recordstart
);
416 addr
.sin4
.sin_family
== AF_INET
? (void*)&addr
.sin4
.sin_addr
.s_addr
: (void*)&addr
.sin6
.sin6_addr
.s6_addr
,
419 dq
->len
+= rdatalen
+ sizeof(recordstart
);
424 dq
->dh
->ancount
= htons(dq
->dh
->ancount
);
426 return Action::HeaderModify
;
429 class MacAddrAction
: public DNSAction
432 MacAddrAction(uint16_t code
) : d_code(code
)
434 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
439 string mac
= getMACAddress(*dq
->remote
);
444 generateEDNSOption(d_code
, mac
, optRData
);
447 generateOptRR(optRData
, res
);
449 if ((dq
->size
- dq
->len
) < res
.length())
452 dq
->dh
->arcount
= htons(1);
453 char* dest
= ((char*)dq
->dh
) + dq
->len
;
454 memcpy(dest
, res
.c_str(), res
.length());
455 dq
->len
+= res
.length();
459 string
toString() const override
461 return "add EDNS MAC (code="+std::to_string(d_code
)+")";
467 class NoRecurseAction
: public DNSAction
470 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
475 string
toString() const override
481 class LogAction
: public DNSAction
, public boost::noncopyable
484 LogAction() : d_fp(0)
487 LogAction(const std::string
& str
, bool binary
=true, bool append
=false, bool buffered
=true) : d_fname(str
), d_binary(binary
)
492 d_fp
= fopen(str
.c_str(), "a+");
494 d_fp
= fopen(str
.c_str(), "w");
496 throw std::runtime_error("Unable to open file '"+str
+"' for logging: "+string(strerror(errno
)));
500 ~LogAction() override
505 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
508 vinfolog("Packet from %s for %s %s with id %d", dq
->remote
->toStringWithPort(), dq
->qname
->toString(), QType(dq
->qtype
).getName(), dq
->dh
->id
);
512 string out
= dq
->qname
->toDNSString();
513 fwrite(out
.c_str(), 1, out
.size(), d_fp
);
514 fwrite((void*)&dq
->qtype
, 1, 2, d_fp
);
517 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
);
522 string
toString() const override
524 if (!d_fname
.empty()) {
525 return "log to " + d_fname
;
536 class DisableValidationAction
: public DNSAction
539 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
544 string
toString() const override
550 class SkipCacheAction
: public DNSAction
553 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
555 dq
->skipCache
= true;
558 string
toString() const override
564 class TempFailureCacheTTLAction
: public DNSAction
567 TempFailureCacheTTLAction(uint32_t ttl
) : d_ttl(ttl
)
569 TempFailureCacheTTLAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
571 dq
->tempFailureTTL
= d_ttl
;
574 string
toString() const override
576 return "set tempfailure cache ttl to "+std::to_string(d_ttl
);
582 class ECSPrefixLengthAction
: public DNSAction
585 ECSPrefixLengthAction(uint16_t v4Length
, uint16_t v6Length
) : d_v4PrefixLength(v4Length
), d_v6PrefixLength(v6Length
)
588 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
590 dq
->ecsPrefixLength
= dq
->remote
->sin4
.sin_family
== AF_INET
? d_v4PrefixLength
: d_v6PrefixLength
;
593 string
toString() const override
595 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength
) + "/" + std::to_string(d_v6PrefixLength
);
598 uint16_t d_v4PrefixLength
;
599 uint16_t d_v6PrefixLength
;
602 class ECSOverrideAction
: public DNSAction
605 ECSOverrideAction(bool ecsOverride
) : d_ecsOverride(ecsOverride
)
608 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
610 dq
->ecsOverride
= d_ecsOverride
;
613 string
toString() const override
615 return "set ECS override to " + std::to_string(d_ecsOverride
);
622 class DisableECSAction
: public DNSAction
625 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
630 string
toString() const override
632 return "disable ECS";
636 class DnstapLogAction
: public DNSAction
, public boost::noncopyable
639 DnstapLogAction(const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSQuestion
&, DnstapMessage
*)> > alterFunc
): d_identity(identity
), d_logger(logger
), d_alterFunc(alterFunc
)
642 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
645 DnstapMessage
message(d_identity
, dq
->remote
, dq
->local
, dq
->tcp
, reinterpret_cast<const char*>(dq
->dh
), dq
->len
, dq
->queryTime
, nullptr);
648 std::lock_guard
<std::mutex
> lock(g_luamutex
);
649 (*d_alterFunc
)(*dq
, &message
);
653 message
.serialize(data
);
654 d_logger
->queueData(data
);
655 #endif /* HAVE_PROTOBUF */
658 string
toString() const override
660 return "remote log as dnstap to " + (d_logger
? d_logger
->toString() : "");
663 std::string d_identity
;
664 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
665 boost::optional
<std::function
<void(const DNSQuestion
&, DnstapMessage
*)> > d_alterFunc
;
668 class RemoteLogAction
: public DNSAction
, public boost::noncopyable
671 RemoteLogAction(std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSQuestion
&, DNSDistProtoBufMessage
*)> > alterFunc
): d_logger(logger
), d_alterFunc(alterFunc
)
674 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
678 dq
->uniqueId
= t_uuidGenerator();
681 DNSDistProtoBufMessage
message(*dq
);
684 std::lock_guard
<std::mutex
> lock(g_luamutex
);
685 (*d_alterFunc
)(*dq
, &message
);
689 message
.serialize(data
);
690 d_logger
->queueData(data
);
691 #endif /* HAVE_PROTOBUF */
694 string
toString() const override
696 return "remote log to " + (d_logger
? d_logger
->toString() : "");
699 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
700 boost::optional
<std::function
<void(const DNSQuestion
&, DNSDistProtoBufMessage
*)> > d_alterFunc
;
703 class SNMPTrapAction
: public DNSAction
706 SNMPTrapAction(const std::string
& reason
): d_reason(reason
)
709 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
711 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
712 g_snmpAgent
->sendDNSTrap(*dq
, d_reason
);
717 string
toString() const override
719 return "send SNMP trap";
722 std::string d_reason
;
725 class TagAction
: public DNSAction
728 TagAction(const std::string tag
, const std::string value
): d_tag(tag
), d_value(value
)
731 DNSAction::Action
operator()(DNSQuestion
* dq
, string
* ruleresult
) const override
734 dq
->qTag
= std::make_shared
<QTag
>();
737 dq
->qTag
->insert({d_tag
, d_value
});
741 string
toString() const override
743 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
750 class DnstapLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
753 DnstapLogResponseAction(const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSResponse
&, DnstapMessage
*)> > alterFunc
): d_identity(identity
), d_logger(logger
), d_alterFunc(alterFunc
)
756 DNSResponseAction::Action
operator()(DNSResponse
* dr
, string
* ruleresult
) const override
761 DnstapMessage
message(d_identity
, dr
->remote
, dr
->local
, dr
->tcp
, reinterpret_cast<const char*>(dr
->dh
), dr
->len
, dr
->queryTime
, &now
);
764 std::lock_guard
<std::mutex
> lock(g_luamutex
);
765 (*d_alterFunc
)(*dr
, &message
);
769 message
.serialize(data
);
770 d_logger
->queueData(data
);
771 #endif /* HAVE_PROTOBUF */
774 string
toString() const override
776 return "log response as dnstap to " + (d_logger
? d_logger
->toString() : "");
779 std::string d_identity
;
780 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
781 boost::optional
<std::function
<void(const DNSResponse
&, DnstapMessage
*)> > d_alterFunc
;
784 class RemoteLogResponseAction
: public DNSResponseAction
, public boost::noncopyable
787 RemoteLogResponseAction(std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSResponse
&, DNSDistProtoBufMessage
*)> > alterFunc
, bool includeCNAME
): d_logger(logger
), d_alterFunc(alterFunc
), d_includeCNAME(includeCNAME
)
790 DNSResponseAction::Action
operator()(DNSResponse
* dr
, string
* ruleresult
) const override
794 dr
->uniqueId
= t_uuidGenerator();
797 DNSDistProtoBufMessage
message(*dr
, d_includeCNAME
);
800 std::lock_guard
<std::mutex
> lock(g_luamutex
);
801 (*d_alterFunc
)(*dr
, &message
);
805 message
.serialize(data
);
806 d_logger
->queueData(data
);
807 #endif /* HAVE_PROTOBUF */
810 string
toString() const override
812 return "remote log response to " + (d_logger
? d_logger
->toString() : "");
815 std::shared_ptr
<RemoteLoggerInterface
> d_logger
;
816 boost::optional
<std::function
<void(const DNSResponse
&, DNSDistProtoBufMessage
*)> > d_alterFunc
;
820 class DropResponseAction
: public DNSResponseAction
823 DNSResponseAction::Action
operator()(DNSResponse
* dr
, string
* ruleresult
) const override
827 string
toString() const override
833 class AllowResponseAction
: public DNSResponseAction
836 DNSResponseAction::Action
operator()(DNSResponse
* dr
, string
* ruleresult
) const override
838 return Action::Allow
;
840 string
toString() const override
846 class DelayResponseAction
: public DNSResponseAction
849 DelayResponseAction(int msec
) : d_msec(msec
)
851 DNSResponseAction::Action
operator()(DNSResponse
* dr
, string
* ruleresult
) const override
853 *ruleresult
=std::to_string(d_msec
);
854 return Action::Delay
;
856 string
toString() const override
858 return "delay by "+std::to_string(d_msec
)+ " msec";
864 class SNMPTrapResponseAction
: public DNSResponseAction
867 SNMPTrapResponseAction(const std::string
& reason
): d_reason(reason
)
870 DNSResponseAction::Action
operator()(DNSResponse
* dr
, string
* ruleresult
) const override
872 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
873 g_snmpAgent
->sendDNSTrap(*dr
, d_reason
);
878 string
toString() const override
880 return "send SNMP trap";
883 std::string d_reason
;
886 class TagResponseAction
: public DNSResponseAction
889 TagResponseAction(const std::string tag
, const std::string value
): d_tag(tag
), d_value(value
)
892 DNSResponseAction::Action
operator()(DNSResponse
* dr
, string
* ruleresult
) const override
895 dr
->qTag
= std::make_shared
<QTag
>();
898 dr
->qTag
->insert({d_tag
, d_value
});
902 string
toString() const override
904 return "set tag '" + d_tag
+ "' to value '" + d_value
+ "'";
911 template<typename T
, typename ActionT
>
912 static void addAction(GlobalStateHolder
<vector
<T
> > *someRulActions
, luadnsrule_t var
, std::shared_ptr
<ActionT
> action
, boost::optional
<luaruleparams_t
> params
) {
915 boost::uuids::uuid uuid
;
916 parseRuleParams(params
, uuid
);
918 auto rule
=makeRule(var
);
919 someRulActions
->modify([rule
, action
, uuid
](vector
<T
>& rulactions
){
920 rulactions
.push_back({rule
, action
, uuid
});
924 void setupLuaActions()
926 g_lua
.writeFunction("newRuleAction", [](luadnsrule_t dnsrule
, std::shared_ptr
<DNSAction
> action
, boost::optional
<luaruleparams_t
> params
) {
927 boost::uuids::uuid uuid
;
928 parseRuleParams(params
, uuid
);
930 auto rule
=makeRule(dnsrule
);
931 DNSDistRuleAction
ra({rule
, action
, uuid
});
932 return std::make_shared
<DNSDistRuleAction
>(ra
);
935 g_lua
.writeFunction("addAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
> > era
, boost::optional
<luaruleparams_t
> params
) {
936 if (era
.type() != typeid(std::shared_ptr
<DNSAction
>)) {
937 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
940 addAction(&g_rulactions
, var
, boost::get
<std::shared_ptr
<DNSAction
> >(era
), params
);
943 g_lua
.writeFunction("addLuaAction", [](luadnsrule_t var
, LuaAction::func_t func
, boost::optional
<luaruleparams_t
> params
) {
944 addAction(&g_rulactions
, var
, std::make_shared
<LuaAction
>(func
), params
);
947 g_lua
.writeFunction("addLuaResponseAction", [](luadnsrule_t var
, LuaResponseAction::func_t func
, boost::optional
<luaruleparams_t
> params
) {
948 addAction(&g_resprulactions
, var
, std::make_shared
<LuaResponseAction
>(func
), params
);
951 g_lua
.writeFunction("addResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
> > era
, boost::optional
<luaruleparams_t
> params
) {
952 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
953 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
956 addAction(&g_resprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
959 g_lua
.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
>> era
, boost::optional
<luaruleparams_t
> params
) {
960 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
961 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
964 addAction(&g_cachehitresprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
967 g_lua
.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var
, boost::variant
<std::shared_ptr
<DNSAction
>, std::shared_ptr
<DNSResponseAction
>> era
, boost::optional
<luaruleparams_t
> params
) {
968 if (era
.type() != typeid(std::shared_ptr
<DNSResponseAction
>)) {
969 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
972 addAction(&g_selfansweredresprulactions
, var
, boost::get
<std::shared_ptr
<DNSResponseAction
> >(era
), params
);
975 g_lua
.registerFunction
<void(DNSAction::*)()>("printStats", [](const DNSAction
& ta
) {
976 setLuaNoSideEffect();
977 auto stats
= ta
.getStats();
978 for(const auto& s
: stats
) {
979 g_outputBuffer
+=s
.first
+"\t";
980 if((uint64_t)s
.second
== s
.second
)
981 g_outputBuffer
+= std::to_string((uint64_t)s
.second
)+"\n";
983 g_outputBuffer
+= std::to_string(s
.second
)+"\n";
987 g_lua
.writeFunction("getAction", [](unsigned int num
) {
988 setLuaNoSideEffect();
989 boost::optional
<std::shared_ptr
<DNSAction
>> ret
;
990 auto rulactions
= g_rulactions
.getCopy();
991 if(num
< rulactions
.size())
992 ret
=rulactions
[num
].d_action
;
996 g_lua
.registerFunction("getStats", &DNSAction::getStats
);
998 g_lua
.writeFunction("LuaAction", [](LuaAction::func_t func
) {
1000 return std::shared_ptr
<DNSAction
>(new LuaAction(func
));
1003 g_lua
.writeFunction("NoRecurseAction", []() {
1004 return std::shared_ptr
<DNSAction
>(new NoRecurseAction
);
1007 g_lua
.writeFunction("MacAddrAction", [](int code
) {
1008 return std::shared_ptr
<DNSAction
>(new MacAddrAction(code
));
1011 g_lua
.writeFunction("PoolAction", [](const string
& a
) {
1012 return std::shared_ptr
<DNSAction
>(new PoolAction(a
));
1015 g_lua
.writeFunction("QPSAction", [](int limit
) {
1016 return std::shared_ptr
<DNSAction
>(new QPSAction(limit
));
1019 g_lua
.writeFunction("QPSPoolAction", [](int limit
, const string
& a
) {
1020 return std::shared_ptr
<DNSAction
>(new QPSPoolAction(limit
, a
));
1023 g_lua
.writeFunction("SpoofAction", [](boost::variant
<string
,vector
<pair
<int, string
>>> inp
, boost::optional
<string
> b
) {
1024 vector
<ComboAddress
> addrs
;
1025 if(auto s
= boost::get
<string
>(&inp
))
1026 addrs
.push_back(ComboAddress(*s
));
1028 const auto& v
= boost::get
<vector
<pair
<int,string
>>>(inp
);
1029 for(const auto& a
: v
)
1030 addrs
.push_back(ComboAddress(a
.second
));
1033 addrs
.push_back(ComboAddress(*b
));
1034 return std::shared_ptr
<DNSAction
>(new SpoofAction(addrs
));
1037 g_lua
.writeFunction("SpoofCNAMEAction", [](const string
& a
) {
1038 return std::shared_ptr
<DNSAction
>(new SpoofAction(a
));
1041 g_lua
.writeFunction("DropAction", []() {
1042 return std::shared_ptr
<DNSAction
>(new DropAction
);
1045 g_lua
.writeFunction("AllowAction", []() {
1046 return std::shared_ptr
<DNSAction
>(new AllowAction
);
1049 g_lua
.writeFunction("DelayAction", [](int msec
) {
1050 return std::shared_ptr
<DNSAction
>(new DelayAction(msec
));
1053 g_lua
.writeFunction("TCAction", []() {
1054 return std::shared_ptr
<DNSAction
>(new TCAction
);
1057 g_lua
.writeFunction("DisableValidationAction", []() {
1058 return std::shared_ptr
<DNSAction
>(new DisableValidationAction
);
1061 g_lua
.writeFunction("LogAction", [](const std::string
& fname
, boost::optional
<bool> binary
, boost::optional
<bool> append
, boost::optional
<bool> buffered
) {
1062 return std::shared_ptr
<DNSAction
>(new LogAction(fname
, binary
? *binary
: true, append
? *append
: false, buffered
? *buffered
: false));
1065 g_lua
.writeFunction("RCodeAction", [](uint8_t rcode
) {
1066 return std::shared_ptr
<DNSAction
>(new RCodeAction(rcode
));
1069 g_lua
.writeFunction("SkipCacheAction", []() {
1070 return std::shared_ptr
<DNSAction
>(new SkipCacheAction
);
1073 g_lua
.writeFunction("TempFailureCacheTTLAction", [](int maxTTL
) {
1074 return std::shared_ptr
<DNSAction
>(new TempFailureCacheTTLAction(maxTTL
));
1077 g_lua
.writeFunction("DropResponseAction", []() {
1078 return std::shared_ptr
<DNSResponseAction
>(new DropResponseAction
);
1081 g_lua
.writeFunction("AllowResponseAction", []() {
1082 return std::shared_ptr
<DNSResponseAction
>(new AllowResponseAction
);
1085 g_lua
.writeFunction("DelayResponseAction", [](int msec
) {
1086 return std::shared_ptr
<DNSResponseAction
>(new DelayResponseAction(msec
));
1089 g_lua
.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func
) {
1091 return std::shared_ptr
<DNSResponseAction
>(new LuaResponseAction(func
));
1094 g_lua
.writeFunction("RemoteLogAction", [](std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSQuestion
&, DNSDistProtoBufMessage
*)> > alterFunc
) {
1095 // avoids potentially-evaluated-expression warning with clang.
1096 RemoteLoggerInterface
& rl
= *logger
.get();
1097 if (typeid(rl
) != typeid(RemoteLogger
)) {
1098 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1099 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1101 #ifdef HAVE_PROTOBUF
1102 return std::shared_ptr
<DNSAction
>(new RemoteLogAction(logger
, alterFunc
));
1104 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1108 g_lua
.writeFunction("RemoteLogResponseAction", [](std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSResponse
&, DNSDistProtoBufMessage
*)> > alterFunc
, boost::optional
<bool> includeCNAME
) {
1109 // avoids potentially-evaluated-expression warning with clang.
1110 RemoteLoggerInterface
& rl
= *logger
.get();
1111 if (typeid(rl
) != typeid(RemoteLogger
)) {
1112 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1113 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
1115 #ifdef HAVE_PROTOBUF
1116 return std::shared_ptr
<DNSResponseAction
>(new RemoteLogResponseAction(logger
, alterFunc
, includeCNAME
? *includeCNAME
: false));
1118 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1122 g_lua
.writeFunction("DnstapLogAction", [](const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSQuestion
&, DnstapMessage
*)> > alterFunc
) {
1123 #ifdef HAVE_PROTOBUF
1124 return std::shared_ptr
<DNSAction
>(new DnstapLogAction(identity
, logger
, alterFunc
));
1126 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1130 g_lua
.writeFunction("DnstapLogResponseAction", [](const std::string
& identity
, std::shared_ptr
<RemoteLoggerInterface
> logger
, boost::optional
<std::function
<void(const DNSResponse
&, DnstapMessage
*)> > alterFunc
) {
1131 #ifdef HAVE_PROTOBUF
1132 return std::shared_ptr
<DNSResponseAction
>(new DnstapLogResponseAction(identity
, logger
, alterFunc
));
1134 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1138 g_lua
.writeFunction("TeeAction", [](const std::string
& remote
, boost::optional
<bool> addECS
) {
1139 return std::shared_ptr
<DNSAction
>(new TeeAction(ComboAddress(remote
, 53), addECS
? *addECS
: false));
1142 g_lua
.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength
, uint16_t v6PrefixLength
) {
1143 return std::shared_ptr
<DNSAction
>(new ECSPrefixLengthAction(v4PrefixLength
, v6PrefixLength
));
1146 g_lua
.writeFunction("ECSOverrideAction", [](bool ecsOverride
) {
1147 return std::shared_ptr
<DNSAction
>(new ECSOverrideAction(ecsOverride
));
1150 g_lua
.writeFunction("DisableECSAction", []() {
1151 return std::shared_ptr
<DNSAction
>(new DisableECSAction());
1154 g_lua
.writeFunction("SNMPTrapAction", [](boost::optional
<std::string
> reason
) {
1155 #ifdef HAVE_NET_SNMP
1156 return std::shared_ptr
<DNSAction
>(new SNMPTrapAction(reason
? *reason
: ""));
1158 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1159 #endif /* HAVE_NET_SNMP */
1162 g_lua
.writeFunction("SNMPTrapResponseAction", [](boost::optional
<std::string
> reason
) {
1163 #ifdef HAVE_NET_SNMP
1164 return std::shared_ptr
<DNSResponseAction
>(new SNMPTrapResponseAction(reason
? *reason
: ""));
1166 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1167 #endif /* HAVE_NET_SNMP */
1170 g_lua
.writeFunction("TagAction", [](std::string tag
, std::string value
) {
1171 return std::shared_ptr
<DNSAction
>(new TagAction(tag
, value
));
1174 g_lua
.writeFunction("TagResponseAction", [](std::string tag
, std::string value
) {
1175 return std::shared_ptr
<DNSResponseAction
>(new TagResponseAction(tag
, value
));