From ec469dd7cd943613397f5fac5aafbfba6e6664ff Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 13 Apr 2016 13:16:13 +0200 Subject: [PATCH] Protobuf: Encode UUID in binary. Add question to the response msg Also: - merge the dnsdist and recursor Remote Logger implementations. - fix the protobuf logging over TCP in dnsdist --- pdns/README-dnsdist.md | 2 +- pdns/dnsdist-lua2.cc | 4 +- pdns/dnsdist-protobuf.cc | 132 ++++++++++++ pdns/dnsdist-protobuf.hh | 9 + pdns/dnsdist-remotelogger.cc | 255 ----------------------- pdns/dnsdist-remotelogger.hh | 34 --- pdns/dnsdist-tcp.cc | 1 + pdns/dnsdistdist/Makefile.am | 3 +- pdns/dnsdistdist/dnsdist-protobuf.cc | 1 + pdns/dnsdistdist/dnsdist-protobuf.hh | 1 + pdns/dnsdistdist/dnsdist-remotelogger.cc | 1 - pdns/dnsdistdist/dnsdist-remotelogger.hh | 1 - pdns/dnsdistdist/remote_logger.cc | 1 + pdns/dnsdistdist/remote_logger.hh | 1 + pdns/dnspcap2protobuf.cc | 18 +- pdns/dnsrulactions.hh | 15 +- pdns/pdns_recursor.cc | 17 +- 17 files changed, 183 insertions(+), 313 deletions(-) create mode 100644 pdns/dnsdist-protobuf.cc create mode 100644 pdns/dnsdist-protobuf.hh delete mode 100644 pdns/dnsdist-remotelogger.cc delete mode 100644 pdns/dnsdist-remotelogger.hh create mode 120000 pdns/dnsdistdist/dnsdist-protobuf.cc create mode 120000 pdns/dnsdistdist/dnsdist-protobuf.hh delete mode 120000 pdns/dnsdistdist/dnsdist-remotelogger.cc delete mode 120000 pdns/dnsdistdist/dnsdist-remotelogger.hh create mode 120000 pdns/dnsdistdist/remote_logger.cc create mode 120000 pdns/dnsdistdist/remote_logger.hh diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md index fa322f84f5..2874d3acc1 100644 --- a/pdns/README-dnsdist.md +++ b/pdns/README-dnsdist.md @@ -1175,7 +1175,7 @@ instantiate a server with additional parameters * `printDNSCryptProviderFingerprint("/path/to/providerPublic.key")`: display the fingerprint of the provided resolver public key * `showDNSCryptBinds():`: display the currently configured DNSCrypt binds * RemoteLogger related: - * `newRemoteLogger(address:port)`: create a Remote Logger object, to use with `RemoteLogAction()` and `RemoteLogResponseAction()` + * `newRemoteLogger(address:port [, timeout=2, maxQueuedEntries=100, reconnectWaitTime=1])`: create a Remote Logger object, to use with `RemoteLogAction()` and `RemoteLogResponseAction()` All hooks --------- diff --git a/pdns/dnsdist-lua2.cc b/pdns/dnsdist-lua2.cc index 3718223cc1..18be93099a 100644 --- a/pdns/dnsdist-lua2.cc +++ b/pdns/dnsdist-lua2.cc @@ -582,8 +582,8 @@ void moreLua(bool client) g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr logger) { return std::shared_ptr(new RemoteLogResponseAction(logger)); }); - g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote) { - return std::make_shared(ComboAddress(remote)); + g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote, boost::optional timeout, boost::optional maxQueuedEntries, boost::optional reconnectWaitTime) { + return std::make_shared(ComboAddress(remote), timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1); }); } diff --git a/pdns/dnsdist-protobuf.cc b/pdns/dnsdist-protobuf.cc new file mode 100644 index 0000000000..d0a0d7aa9a --- /dev/null +++ b/pdns/dnsdist-protobuf.cc @@ -0,0 +1,132 @@ + +#include "config.h" + +#include "dnsdist.hh" + +#include "dnsparser.hh" +#include "dnsdist-protobuf.hh" + +#ifdef HAVE_PROTOBUF +#include "dnsmessage.pb.h" + +static void protobufFillMessage(PBDNSMessage& message, const DNSQuestion& dq) +{ + std::string* messageId = message.mutable_messageid(); + messageId->resize(dq.uniqueId.size()); + std::copy(dq.uniqueId.begin(), dq.uniqueId.end(), messageId->begin()); + + message.set_socketfamily(dq.remote->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6); + message.set_socketprotocol(dq.tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP); + if (dq.local->sin4.sin_family == AF_INET) { + message.set_to(&dq.local->sin4.sin_addr.s_addr, sizeof(dq.local->sin4.sin_addr.s_addr)); + } + else if (dq.local->sin4.sin_family == AF_INET6) { + message.set_to(&dq.local->sin6.sin6_addr.s6_addr, sizeof(dq.local->sin6.sin6_addr.s6_addr)); + } + if (dq.remote->sin4.sin_family == AF_INET) { + message.set_from(&dq.remote->sin4.sin_addr.s_addr, sizeof(dq.remote->sin4.sin_addr.s_addr)); + } + else if (dq.remote->sin4.sin_family == AF_INET6) { + message.set_from(&dq.remote->sin6.sin6_addr.s6_addr, sizeof(dq.remote->sin6.sin6_addr.s6_addr)); + } + + message.set_inbytes(dq.len); + + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + message.set_timesec(ts.tv_sec); + message.set_timeusec(ts.tv_nsec / 1000); + message.set_id(ntohs(dq.dh->id)); + + PBDNSMessage_DNSQuestion* question = message.mutable_question(); + question->set_qname(dq.qname->toString()); + question->set_qtype(dq.qtype); + question->set_qclass(dq.qclass); +} + +void protobufMessageFromQuestion(const DNSQuestion& dq, std::string& data) +{ + PBDNSMessage message; + message.set_type(PBDNSMessage_Type_DNSQueryType); + protobufFillMessage(message, dq); +// cerr <ancount) == 0) + return; + + if (ntohs(dh->qdcount) == 0) + return; + + vector content(len - sizeof(dnsheader)); + copy(packet + sizeof(dnsheader), packet + len, content.begin()); + PacketReader pr(content); + + size_t idx = 0; + DNSName rrname; + uint16_t qdcount = ntohs(dh->qdcount); + uint16_t ancount = ntohs(dh->ancount); + uint16_t rrtype; + uint16_t rrclass; + string blob; + struct dnsrecordheader ah; + + rrname = pr.getName(); + rrtype = pr.get16BitInt(); + rrclass = pr.get16BitInt(); + + /* consume remaining qd if any */ + if (qdcount > 1) { + for(idx = 1; idx < qdcount; idx++) { + rrname = pr.getName(); + rrtype = pr.get16BitInt(); + rrclass = pr.get16BitInt(); + (void) rrtype; + (void) rrclass; + } + } + + /* parse AN */ + for (idx = 0; idx < ancount; idx++) { + rrname = pr.getName(); + pr.getDnsrecordheader(ah); + + pr.xfrBlob(blob); + + if (ah.d_type == QType::A || ah.d_type == QType::AAAA) { + PBDNSMessage_DNSResponse_DNSRR* rr = response.add_rrs(); + if (rr) { + rr->set_name(rrname.toString()); + rr->set_type(ah.d_type); + rr->set_class_(ah.d_class); + rr->set_ttl(ah.d_ttl); + rr->set_rdata(blob.c_str(), blob.length()); + } + } + } +} + +void protobufMessageFromResponse(const DNSQuestion& dr, std::string& data) +{ + PBDNSMessage message; + message.set_type(PBDNSMessage_Type_DNSResponseType); + protobufFillMessage(message, dr); + + PBDNSMessage_DNSResponse response; + response.set_rcode(dr.dh->rcode); + addRRs((const char*) dr.dh, dr.len, response); + message.set_allocated_response(&response); + +// cerr < -#include "dnsmessage.pb.h" -#endif - -bool RemoteLogger::reconnect() -{ - if (d_socket >= 0) { - close(d_socket); - } - try { - //cerr<<"Connecting to " << d_remote.toStringWithPort()< lock(d_writeMutex); - d_queueCond.wait(lock, [this]{return !d_writeQueue.empty();}); - data = d_writeQueue.front(); - d_writeQueue.pop(); - } - - try { - uint16_t len = data.length(); - len = htons(len); - writen2WithTimeout(d_socket, &len, sizeof(len), (int) d_timeout); - writen2WithTimeout(d_socket, data.c_str(), data.length(), (int) d_timeout); - } - catch(const std::runtime_error& e) { - vinfolog("Error sending data to remote logger (%s): %s", d_remote.toStringWithPort(), e.what()); - - while (!reconnect()) { - sleep(d_reconnectWaitTime); - } - } - } -} - -void RemoteLogger::queueData(const std::string& data) -{ - { - std::unique_lock lock(d_writeMutex); - if (d_writeQueue.size() >= d_maxQueuedEntries) { - d_writeQueue.pop(); - } - d_writeQueue.push(data); - } - d_queueCond.notify_one(); -} - -RemoteLogger::RemoteLogger(const ComboAddress& remote, uint16_t timeout, uint64_t maxQueuedEntries, uint8_t reconnectWaitTime): d_remote(remote), d_maxQueuedEntries(maxQueuedEntries), d_timeout(timeout), d_reconnectWaitTime(reconnectWaitTime), d_thread(&RemoteLogger::worker, this) -{ -#ifdef HAVE_PROTOBUF - reconnect(); -#else - throw new std::runtime_error("Remote logging requires protobuf support, which is not enabled."); -#endif /* HAVE_PROTOBUF */ -} - -RemoteLogger::~RemoteLogger() -{ - if (d_socket >= 0) - close(d_socket); -} - -void RemoteLogger::logQuery(const DNSQuestion& dq) -{ -#ifdef HAVE_PROTOBUF - PBDNSMessage message; - message.set_type(PBDNSMessage_Type_DNSQueryType); - message.set_messageid(boost::uuids::to_string(dq.uniqueId)); - message.set_socketfamily(dq.remote->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6); - message.set_socketprotocol(dq.tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP); - if (dq.local->sin4.sin_family == AF_INET) { - message.set_to(&dq.local->sin4.sin_addr.s_addr, sizeof(dq.local->sin4.sin_addr.s_addr)); - } - else if (dq.local->sin4.sin_family == AF_INET6) { - message.set_to(&dq.local->sin6.sin6_addr.s6_addr, sizeof(dq.local->sin6.sin6_addr.s6_addr)); - } - if (dq.remote->sin4.sin_family == AF_INET) { - message.set_from(&dq.remote->sin4.sin_addr.s_addr, sizeof(dq.remote->sin4.sin_addr.s_addr)); - } - else if (dq.remote->sin4.sin_family == AF_INET6) { - message.set_from(&dq.remote->sin6.sin6_addr.s6_addr, sizeof(dq.remote->sin6.sin6_addr.s6_addr)); - } - message.set_inbytes(dq.len); - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - message.set_timesec(ts.tv_sec); - message.set_timeusec(ts.tv_nsec / 1000); - message.set_id(ntohs(dq.dh->id)); - - PBDNSMessage_DNSQuestion question; - question.set_qname(dq.qname->toString()); - question.set_qtype(dq.qtype); - question.set_qclass(dq.qclass); - message.set_allocated_question(&question); - - //cerr <ancount) == 0) - return; - - if (ntohs(dh->qdcount) == 0) - return; - - vector content(len - sizeof(dnsheader)); - copy(packet + sizeof(dnsheader), packet + len, content.begin()); - PacketReader pr(content); - - size_t idx = 0; - DNSName rrname; - uint16_t qdcount = ntohs(dh->qdcount); - uint16_t ancount = ntohs(dh->ancount); - uint16_t rrtype; - uint16_t rrclass; - string blob; - struct dnsrecordheader ah; - - rrname = pr.getName(); - rrtype = pr.get16BitInt(); - rrclass = pr.get16BitInt(); - - /* consume remaining qd if any */ - if (qdcount > 1) { - for(idx = 1; idx < qdcount; idx++) { - rrname = pr.getName(); - rrtype = pr.get16BitInt(); - rrclass = pr.get16BitInt(); - (void) rrtype; - (void) rrclass; - } - } - - /* parse AN */ - for (idx = 0; idx < ancount; idx++) { - rrname = pr.getName(); - pr.getDnsrecordheader(ah); - - pr.xfrBlob(blob); - if (ah.d_type == QType::A || ah.d_type == QType::AAAA) { - PBDNSMessage_DNSResponse_DNSRR* rr = response.add_rrs(); - if (rr) { - rr->set_name(rrname.toString()); - rr->set_type(ah.d_type); - rr->set_class_(ah.d_class); - rr->set_ttl(ah.d_ttl); - rr->set_rdata(blob.c_str(), blob.length()); - } - } - } -} -#endif /* HAVE_PROTOBUF */ - -void RemoteLogger::logResponse(const DNSQuestion& dr) -{ -#ifdef HAVE_PROTOBUF - PBDNSMessage message; - message.set_type(PBDNSMessage_Type_DNSResponseType); - message.set_messageid(boost::uuids::to_string(dr.uniqueId)); - message.set_socketfamily(dr.remote->sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6); - message.set_socketprotocol(dr.tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP); - if (dr.local->sin4.sin_family == AF_INET) { - message.set_from(&dr.local->sin4.sin_addr.s_addr, sizeof(dr.local->sin4.sin_addr.s_addr)); - } - else if (dr.local->sin4.sin_family == AF_INET6) { - message.set_from(&dr.local->sin6.sin6_addr.s6_addr, sizeof(dr.local->sin6.sin6_addr.s6_addr)); - } - if (dr.remote->sin4.sin_family == AF_INET) { - message.set_to(&dr.remote->sin4.sin_addr.s_addr, sizeof(dr.remote->sin4.sin_addr.s_addr)); - } - else if (dr.remote->sin4.sin_family == AF_INET6) { - message.set_to(&dr.remote->sin6.sin6_addr.s6_addr, sizeof(dr.remote->sin6.sin6_addr.s6_addr)); - } - message.set_inbytes(dr.len); - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - message.set_timesec(ts.tv_sec); - message.set_timeusec(ts.tv_nsec / 1000); - message.set_id(ntohs(dr.dh->id)); - - PBDNSMessage_DNSResponse response; - response.set_rcode(dr.dh->rcode); - addRRs((const char*) dr.dh, dr.len, response); - message.set_allocated_response(&response); - - - //cerr < -#include - -class RemoteLogger -{ -public: - RemoteLogger(const ComboAddress& remote, uint16_t timeout=2, uint64_t maxQueuedEntries=100, uint8_t reconnectWaitTime=1); - ~RemoteLogger(); - void logQuery(const DNSQuestion& dq); - void logResponse(const DNSQuestion& dr); - std::string toString() - { - return d_remote.toStringWithPort(); - } -private: - bool reconnect(); - bool sendData(const char* buffer, size_t bufferSize); - void worker(); - void queueData(const std::string& data); - - std::queue d_writeQueue; - std::mutex d_writeMutex; - std::condition_variable d_queueCond; - ComboAddress d_remote; - uint64_t d_maxQueuedEntries; - int d_socket{-1}; - uint16_t d_timeout; - uint8_t d_reconnectWaitTime; - std::thread d_thread; -}; - diff --git a/pdns/dnsdist-tcp.cc b/pdns/dnsdist-tcp.cc index eaeb974317..ebebb35069 100644 --- a/pdns/dnsdist-tcp.cc +++ b/pdns/dnsdist-tcp.cc @@ -420,6 +420,7 @@ void* tcpClientThread(int pipefd) break; } + dh = (struct dnsheader*) response; DNSQuestion dr(&qname, qtype, qclass, &ci.cs->local, &ci.remote, dh, responseSize, responseLen, true); #ifdef HAVE_PROTOBUF dr.uniqueId = dq.uniqueId; diff --git a/pdns/dnsdistdist/Makefile.am b/pdns/dnsdistdist/Makefile.am index 9d96068f38..8fe289a089 100644 --- a/pdns/dnsdistdist/Makefile.am +++ b/pdns/dnsdistdist/Makefile.am @@ -62,7 +62,7 @@ dnsdist_SOURCES = \ dnsdist-ecs.cc dnsdist-ecs.hh \ dnsdist-lua.cc \ dnsdist-lua2.cc \ - dnsdist-remotelogger.cc dnsdist-remotelogger.hh \ + dnsdist-protobuf.cc dnsdist-protobuf.hh \ dnsdist-rings.cc \ dnsdist-tcp.cc \ dnsdist-web.cc \ @@ -82,6 +82,7 @@ dnsdist_SOURCES = \ namespaces.hh \ pdnsexception.hh \ qtype.cc qtype.hh \ + remote_logger.cc remote_logger.hh \ sholder.hh \ sodcrypto.cc sodcrypto.hh \ sstuff.hh \ diff --git a/pdns/dnsdistdist/dnsdist-protobuf.cc b/pdns/dnsdistdist/dnsdist-protobuf.cc new file mode 120000 index 0000000000..a10089548e --- /dev/null +++ b/pdns/dnsdistdist/dnsdist-protobuf.cc @@ -0,0 +1 @@ +../dnsdist-protobuf.cc \ No newline at end of file diff --git a/pdns/dnsdistdist/dnsdist-protobuf.hh b/pdns/dnsdistdist/dnsdist-protobuf.hh new file mode 120000 index 0000000000..dd11fbf3db --- /dev/null +++ b/pdns/dnsdistdist/dnsdist-protobuf.hh @@ -0,0 +1 @@ +../dnsdist-protobuf.hh \ No newline at end of file diff --git a/pdns/dnsdistdist/dnsdist-remotelogger.cc b/pdns/dnsdistdist/dnsdist-remotelogger.cc deleted file mode 120000 index 9a5d9ea340..0000000000 --- a/pdns/dnsdistdist/dnsdist-remotelogger.cc +++ /dev/null @@ -1 +0,0 @@ -../dnsdist-remotelogger.cc \ No newline at end of file diff --git a/pdns/dnsdistdist/dnsdist-remotelogger.hh b/pdns/dnsdistdist/dnsdist-remotelogger.hh deleted file mode 120000 index e9f13069f0..0000000000 --- a/pdns/dnsdistdist/dnsdist-remotelogger.hh +++ /dev/null @@ -1 +0,0 @@ -../dnsdist-remotelogger.hh \ No newline at end of file diff --git a/pdns/dnsdistdist/remote_logger.cc b/pdns/dnsdistdist/remote_logger.cc new file mode 120000 index 0000000000..d1bf076c75 --- /dev/null +++ b/pdns/dnsdistdist/remote_logger.cc @@ -0,0 +1 @@ +../remote_logger.cc \ No newline at end of file diff --git a/pdns/dnsdistdist/remote_logger.hh b/pdns/dnsdistdist/remote_logger.hh new file mode 120000 index 0000000000..a6051d1def --- /dev/null +++ b/pdns/dnsdistdist/remote_logger.hh @@ -0,0 +1 @@ +../remote_logger.hh \ No newline at end of file diff --git a/pdns/dnspcap2protobuf.cc b/pdns/dnspcap2protobuf.cc index 62cd5ffaab..1a1e8d1ec6 100644 --- a/pdns/dnspcap2protobuf.cc +++ b/pdns/dnspcap2protobuf.cc @@ -1,6 +1,5 @@ #include #include -#include #include "dnsmessage.pb.h" #include "iputils.hh" @@ -151,22 +150,27 @@ int main(int argc, char **argv) if (!dh->qr) { boost::uuids::uuid uniqueId = uuidGenerator(); ids[dh->id] = uniqueId; - message.set_messageid(boost::uuids::to_string(uniqueId)); - question.set_qname(qname.toString()); - question.set_qtype(qtype); - question.set_qclass(qclass); - message.set_allocated_question(&question); + std::string* messageId = message.mutable_messageid(); + messageId->resize(uniqueId.size()); + std::copy(uniqueId.begin(), uniqueId.end(), messageId->begin()); } else { const auto& it = ids.find(dh->id); if (it != ids.end()) { - message.set_messageid(boost::uuids::to_string(it->second)); + std::string* messageId = message.mutable_messageid(); + messageId->resize(it->second.size()); + std::copy(it->second.begin(), it->second.end(), messageId->begin()); } + response.set_rcode(dh->rcode); addRRs((const char*) dh, pr.d_len, response); message.set_allocated_response(&response); } + question.set_qname(qname.toString()); + question.set_qtype(qtype); + question.set_qclass(qclass); + message.set_allocated_question(&question); std::string str; //cerr<logQuery(*dq); +#ifdef HAVE_PROTOBUF + std::string data; + protobufMessageFromQuestion(*dq, data); + d_logger->queueData(data); +#endif /* HAVE_PROTOBUF */ return Action::None; } string toString() const override @@ -753,7 +758,11 @@ public: } DNSResponseAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override { - d_logger->logResponse(*dq); +#ifdef HAVE_PROTOBUF + std::string data; + protobufMessageFromResponse(*dq, data); + d_logger->queueData(data); +#endif /* HAVE_PROTOBUF */ return Action::None; } string toString() const override diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 0aaf769e4c..39363bc1e1 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -85,7 +85,6 @@ extern SortList g_sortlist; #ifdef HAVE_PROTOBUF #include #include -#include #include "dnsmessage.pb.h" #endif @@ -616,7 +615,10 @@ catch(...) #ifdef HAVE_PROTOBUF static void protobufFillMessageFromDC(PBDNSMessage& message, const DNSComboWriter* dc) { - message.set_messageid(boost::uuids::to_string(dc->d_uuid)); + std::string* messageId = message.mutable_messageid(); + messageId->resize(dc->d_uuid.size()); + std::copy(dc->d_uuid.begin(), dc->d_uuid.end(), messageId->begin()); + message.set_socketfamily(dc->d_remote.sin4.sin_family == AF_INET ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6); message.set_socketprotocol(dc->d_tcp ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP); if (dc->d_local.sin4.sin_family == AF_INET) { @@ -646,6 +648,11 @@ static void protobufFillMessageFromDC(PBDNSMessage& message, const DNSComboWrite message.set_timesec(ts.tv_sec); message.set_timeusec(ts.tv_nsec / 1000); message.set_id(ntohs(dc->d_mdp.d_header.id)); + + PBDNSMessage_DNSQuestion* question = message.mutable_question(); + question->set_qname(dc->d_mdp.d_qname.toString()); + question->set_qtype(dc->d_mdp.d_qtype); + question->set_qclass(dc->d_mdp.d_qclass); } static void protobufLogQuery(const std::shared_ptr& logger, const DNSComboWriter* dc) @@ -655,12 +662,6 @@ static void protobufLogQuery(const std::shared_ptr& logger, const message.set_inbytes(dc->d_query.length()); protobufFillMessageFromDC(message, dc); - PBDNSMessage_DNSQuestion question; - question.set_qname(dc->d_mdp.d_qname.toString()); - question.set_qtype(dc->d_mdp.d_qtype); - question.set_qclass(dc->d_mdp.d_qclass); - message.set_allocated_question(&question); - // cerr <