Skip to content

Commit

Permalink
dnsdist: Add an optional Lua callback for altering a Protobuf message
Browse files Browse the repository at this point in the history
For anonymization purpose, for example.
  • Loading branch information
rgacogne committed Aug 19, 2016
1 parent ecbdd81 commit 5608b03
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 21 deletions.
21 changes: 19 additions & 2 deletions pdns/README-dnsdist.md
Expand Up @@ -1274,8 +1274,8 @@ instantiate a server with additional parameters
* `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 purpose
* `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
Expand Down Expand Up @@ -1355,10 +1355,15 @@ instantiate a server with additional parameters
* 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
Expand Down Expand Up @@ -1422,6 +1427,18 @@ instantiate a server with additional parameters
* 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)
Expand Down
6 changes: 6 additions & 0 deletions pdns/dnsdist-lua.cc
Expand Up @@ -1096,6 +1096,12 @@ vector<std::function<void(void)>> setupLua(bool client, const std::string& confi
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);
Expand Down
31 changes: 26 additions & 5 deletions pdns/dnsdist-lua2.cc
Expand Up @@ -163,7 +163,6 @@ void moreLua(bool client)
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)
{
Expand Down Expand Up @@ -679,20 +678,42 @@ void moreLua(bool client)
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);
});
Expand Down
16 changes: 16 additions & 0 deletions pdns/dnsdistconf.lua
Expand Up @@ -222,3 +222,19 @@ end
addLuaAction("luaspoof2.powerdns.com.", spoof2rule)
--]]
-- alter a protobuf response for anonymization purpose
--[[
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))
--]]
18 changes: 16 additions & 2 deletions pdns/dnsrulactions.hh
Expand Up @@ -983,13 +983,19 @@ public:
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);
Expand All @@ -1002,18 +1008,25 @@ public:
}
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);
Expand All @@ -1026,6 +1039,7 @@ public:
}
private:
std::shared_ptr<RemoteLogger> d_logger;
boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > d_alterFunc;
};

class DropResponseAction : public DNSResponseAction
Expand Down
9 changes: 9 additions & 0 deletions pdns/iputils.hh
Expand Up @@ -218,6 +218,15 @@ union ComboAddress {
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)
Expand Down
52 changes: 40 additions & 12 deletions pdns/protobuf.cc
Expand Up @@ -140,6 +140,44 @@ void DNSProtoBufMessage::addRRsFromPacket(const char* packet, const size_t len)
#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
Expand Down Expand Up @@ -178,20 +216,10 @@ void DNSProtoBufMessage::update(const boost::uuids::uuid& uuid, const ComboAddre
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);
}
}

Expand Down
4 changes: 4 additions & 0 deletions pdns/protobuf.hh
Expand Up @@ -41,6 +41,10 @@ public:
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
Expand Down

0 comments on commit 5608b03

Please sign in to comment.