For anonymization purposes, for example.
* `QPSPoolAction(maxqps, poolname)`: set the packet into the specified pool only if it **does not** exceed the specified QPS limits, letting the subsequent rules apply otherwise
* `QPSAction(rule, maxqps)`: drop these packets if the QPS limits are exceeded
* `RCodeAction(rcode)`: reply immediatly by turning the query into a response with the specified rcode
- * `RemoteLogAction(RemoteLogger)`: send the content of this query to a remote logger via Protocol Buffer
- * `RemoteLogResponseAction(RemoteLogger)`: send the content of this response to a remote logger via Protocol Buffer
+ * `RemoteLogAction(RemoteLogger [, alterFunction])`: send the content of this query to a remote logger via Protocol Buffer. `alterFunction` is a callback, receiving a DNSQuestion and a DNSDistProtoBufMessage, that can be used to modify the Protocol Buffer content, for example for anonymization purposes
+ * `RemoteLogResponseAction(RemoteLogger [,alterFunction])`: send the content of this response to a remote logger via Protocol Buffer. `alterFunction` is the same callback than the one in `RemoteLogAction`
* `SkipCacheAction()`: don't lookup the cache for this query, don't store the answer
* `SpoofAction(ip[, ip])` or `SpoofAction({ip, ip, ..}): forge a response with the specified IPv4 (for an A query) or IPv6 (for an AAAA). If you specify multiple addresses, all that match the query type (A, AAAA or ANY) will get spoofed in
* `SpoofCNAMEAction(cname)`: forge a response with the specified CNAME value
* ComboAddress related:
* `newCA(address)`: return a new ComboAddress
* `getPort()`: return the port number
+ * `isIPv4()`: return true if the address is an IPv4, false otherwise
+ * `isIPv6()`: return true if the address is an IPv6, false otherwise
+ * `isMappedIPv4()`: return true if the address is an IPv4 mapped into an IPv6, false otherwise
+ * `mapToIPv4()`: convert an IPv4 address mapped in a v6 one into an IPv4
* `tostring()`: return in human-friendly format
* `toString()`: alias for `tostring()`
* `tostringWithPort()`: return in human-friendly format, with port number
* `toStringWithPort()`: alias for `tostringWithPort()`
+ * `truncate(bits)`: truncate the address to the specified number of bits
* DNSName related:
* `newDNSName(name)`: make a DNSName based on this .-terminated name
* member `countLabels()`: return the number of labels
* member `getStats()`: print the block tables
* member `unblock(ComboAddress)`: unblock this address
* member `unblockQName(DNSName [, qtype=255])`: remove this qname from the block list
+ * DNSDistProtoBufMessage related:
+ * member `setBytes(bytes)`: set the size of the query
+ * member `setEDNSSubnet(Netmask)`: set the EDNS Subnet
+ * member `setQueryTime(sec, usec)`: in a response message, set the time at which the query has been received
+ * member `setQuestion(DNSName, qtype, qclass)`: set the question
+ * member `setRequestor(ComboAddress)`: set the requestor
+ * member `setRequestorFromString(string)`: set the requestor
+ * member `setResponder(ComboAddress)`: set the responder
+ * member `setResponderFromString(string)`: set the responder
+ * member `setResponseCode(rcode)`: set the response code
+ * member `setTime(sec, usec)`: set the time at which the query or response has been received
+ * member `toDebugString()`: return an string containing the content of the message
* DynBPFFilter related:
* function `newDynBPFFilter(BPFFilter)`: return a new DynBPFFilter object using this BPF Filter
* member `block(ComboAddress[, seconds]): add this address to the underlying BPF Filter for `seconds` seconds (default to 10 seconds)
g_lua.registerFunction("toString", &ComboAddress::toString);
g_lua.registerFunction("toStringWithPort", &ComboAddress::toStringWithPort);
g_lua.registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
+ g_lua.registerFunction("truncate", &ComboAddress::truncate);
+ g_lua.registerFunction("isIPv4", &ComboAddress::isIPv4);
+ g_lua.registerFunction("isIPv6", &ComboAddress::isIPv6);
+ g_lua.registerFunction("isMappedIPv4", &ComboAddress::isMappedIPv4);
+ g_lua.registerFunction("mapToIPv4", &ComboAddress::mapToIPv4);
+
g_lua.registerFunction("isPartOf", &DNSName::isPartOf);
g_lua.registerFunction("countLabels", &DNSName::countLabels);
g_lua.registerFunction("wirelength", &DNSName::wirelength);
typedef NetmaskTree<DynBlock> nmts_t;
g_lua.writeFunction("newCA", [](const std::string& name) { return ComboAddress(name); });
-
g_lua.writeFunction("newNMG", []() { return NetmaskGroup(); });
g_lua.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
{
return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
});
- g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLogger> logger) {
+ g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLogger> logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc) {
#ifdef HAVE_PROTOBUF
- return std::shared_ptr<DNSAction>(new RemoteLogAction(logger));
+ return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc));
#else
throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
#endif
});
- g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLogger> logger) {
+ g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLogger> logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc) {
#ifdef HAVE_PROTOBUF
- return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger));
+ return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc));
#else
throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
#endif
});
+
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const Netmask&)>("setEDNSSubnet", [](DNSDistProtoBufMessage& message, const Netmask& subnet) { message.setEDNSSubnet(subnet); });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const DNSName&, uint16_t, uint16_t)>("setQuestion", [](DNSDistProtoBufMessage& message, const DNSName& qname, uint16_t qtype, uint16_t qclass) { message.setQuestion(qname, qtype, qclass); });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(size_t)>("setBytes", [](DNSDistProtoBufMessage& message, size_t bytes) { message.setBytes(bytes); });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setTime(sec, usec); });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setQueryTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setQueryTime(sec, usec); });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(uint8_t)>("setResponseCode", [](DNSDistProtoBufMessage& message, uint8_t rcode) { message.setResponseCode(rcode); });
+ g_lua.registerFunction<std::string(DNSDistProtoBufMessage::*)()>("toDebugString", [](const DNSDistProtoBufMessage& message) { return message.toDebugString(); });
+
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&)>("setRequestor", [](DNSDistProtoBufMessage& message, const ComboAddress& addr) {
+ message.setRequestor(addr);
+ });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setRequestorFromString", [](DNSDistProtoBufMessage& message, const std::string& str) {
+ message.setRequestor(str);
+ });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&)>("setResponder", [](DNSDistProtoBufMessage& message, const ComboAddress& addr) {
+ message.setResponder(addr);
+ });
+ g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setResponderFromString", [](DNSDistProtoBufMessage& message, const std::string& str) {
+ message.setResponder(str);
+ });
+
g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) {
return std::make_shared<RemoteLogger>(ComboAddress(remote), timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1);
});
addLuaAction("luaspoof2.powerdns.com.", spoof2rule)
--]]
+
+-- alter a protobuf response for anonymization purposes
+--[[
+function alterProtobuf(dq, protobuf)
+ requestor = newCA(dq.remoteaddr:toString())
+ if requestor:isIPv4() then
+ requestor:truncate(24)
+ else
+ requestor:truncate(56)
+ end
+ protobuf:setRequestor(requestor)
+end
+
+rl = newRemoteLogger("127.0.0.1:4242")
+addAction(AllRule(), RemoteLogAction(rl, alterProtobuf))
+--]]
class RemoteLogAction : public DNSAction, public boost::noncopyable
{
public:
- RemoteLogAction(std::shared_ptr<RemoteLogger> logger): d_logger(logger)
+ RemoteLogAction(std::shared_ptr<RemoteLogger> logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc): d_logger(logger), d_alterFunc(alterFunc)
{
}
DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
#ifdef HAVE_PROTOBUF
DNSDistProtoBufMessage message(DNSDistProtoBufMessage::Query, *dq);
+ {
+ if (d_alterFunc) {
+ std::lock_guard<std::mutex> lock(g_luamutex);
+ (*d_alterFunc)(*dq, &message);
+ }
+ }
std::string data;
message.serialize(data);
d_logger->queueData(data);
}
private:
std::shared_ptr<RemoteLogger> d_logger;
+ boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > d_alterFunc;
};
class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
{
public:
- RemoteLogResponseAction(std::shared_ptr<RemoteLogger> logger): d_logger(logger)
+ RemoteLogResponseAction(std::shared_ptr<RemoteLogger> logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc): d_logger(logger), d_alterFunc(alterFunc)
{
}
DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
{
#ifdef HAVE_PROTOBUF
DNSDistProtoBufMessage message(*dr);
+ {
+ if (d_alterFunc) {
+ std::lock_guard<std::mutex> lock(g_luamutex);
+ (*d_alterFunc)(*dr, &message);
+ }
+ }
std::string data;
message.serialize(data);
d_logger->queueData(data);
}
private:
std::shared_ptr<RemoteLogger> d_logger;
+ boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > d_alterFunc;
};
class DropResponseAction : public DNSResponseAction
sin4.sin_port=htons(port);
}
+ bool isIPv6() const
+ {
+ return sin4.sin_family == AF_INET6;
+ }
+ bool isIPv4() const
+ {
+ return sin4.sin_family == AF_INET;
+ }
+
bool isMappedIPv4() const
{
if(sin4.sin_family!=AF_INET6)
#endif /* HAVE_PROTOBUF */
}
+void DNSProtoBufMessage::setRequestor(const std::string& requestor)
+{
+#ifdef HAVE_PROTOBUF
+ d_message.set_from(requestor);
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setRequestor(const ComboAddress& requestor)
+{
+#ifdef HAVE_PROTOBUF
+ if (requestor.sin4.sin_family == AF_INET) {
+ d_message.set_from(&requestor.sin4.sin_addr.s_addr, sizeof(requestor.sin4.sin_addr.s_addr));
+ }
+ else if (requestor.sin4.sin_family == AF_INET6) {
+ d_message.set_from(&requestor.sin6.sin6_addr.s6_addr, sizeof(requestor.sin6.sin6_addr.s6_addr));
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setResponder(const std::string& responder)
+{
+#ifdef HAVE_PROTOBUF
+ d_message.set_from(responder);
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setResponder(const ComboAddress& responder)
+{
+#ifdef HAVE_PROTOBUF
+ if (responder.sin4.sin_family == AF_INET) {
+ d_message.set_from(&responder.sin4.sin_addr.s_addr, sizeof(responder.sin4.sin_addr.s_addr));
+ }
+ else if (responder.sin4.sin_family == AF_INET6) {
+ d_message.set_from(&responder.sin6.sin6_addr.s6_addr, sizeof(responder.sin6.sin6_addr.s6_addr));
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
void DNSProtoBufMessage::serialize(std::string& data) const
{
#ifdef HAVE_PROTOBUF
d_message.set_socketprotocol(isTCP ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
if (responder) {
- if (responder->sin4.sin_family == AF_INET) {
- d_message.set_to(&responder->sin4.sin_addr.s_addr, sizeof(responder->sin4.sin_addr.s_addr));
- }
- else if (responder->sin4.sin_family == AF_INET6) {
- d_message.set_to(&responder->sin6.sin6_addr.s6_addr, sizeof(responder->sin6.sin6_addr.s6_addr));
- }
+ setResponder(*responder);
}
if (requestor) {
- if (requestor->sin4.sin_family == AF_INET) {
- d_message.set_from(&requestor->sin4.sin_addr.s_addr, sizeof(requestor->sin4.sin_addr.s_addr));
- }
- else if (requestor->sin4.sin_family == AF_INET6) {
- d_message.set_from(&requestor->sin6.sin6_addr.s6_addr, sizeof(requestor->sin6.sin6_addr.s6_addr));
- }
+ setRequestor(*requestor);
}
}
void setResponseCode(uint8_t rcode);
void addRRsFromPacket(const char* packet, const size_t len);
void serialize(std::string& data) const;
+ void setRequestor(const std::string& requestor);
+ void setRequestor(const ComboAddress& requestor);
+ void setResponder(const std::string& responder);
+ void setResponder(const ComboAddress& responder);
std::string toDebugString() const;
#ifdef HAVE_PROTOBUF