]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Use protozero for Protocol Buffer operations
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 9 Dec 2020 10:26:37 +0000 (11:26 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 5 Jan 2021 09:25:06 +0000 (10:25 +0100)
33 files changed:
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-lua.cc
pdns/dnsdist-protobuf.cc
pdns/dnsdist-protobuf.hh
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/configure.ac
pdns/dnsdistdist/dnsdist-idstate.cc
pdns/dnsdistdist/dnsdist-lua-bindings-protobuf.cc
pdns/dnsdistdist/ext/protozero [new symlink]
pdns/dnsdistdist/m4/pdns_check_dnstap.m4 [changed from symlink to file mode: 0644]
pdns/dnsdistdist/m4/pdns_with_protobuf.m4 [deleted symlink]
pdns/dnsdistdist/protobuf.cc [deleted symlink]
pdns/dnsdistdist/protobuf.hh [deleted symlink]
pdns/dnsdistdist/protozero.cc [new symlink]
pdns/dnsdistdist/protozero.hh [new symlink]
pdns/dnsparser.hh
pdns/dnstap.cc
pdns/dnstap.hh
pdns/lwres.cc
pdns/pdns_recursor.cc
pdns/protozero.cc
pdns/protozero.hh
pdns/rec-dnstap.hh [deleted file]
pdns/recpacketcache.hh
pdns/recursordist/Makefile.am
pdns/recursordist/rec-dnstap.hh [deleted symlink]
pdns/recursordist/rec-protozero.cc [new file with mode: 0644]
pdns/recursordist/rec-protozero.hh [new file with mode: 0644]
pdns/remote_logger.cc
pdns/views.hh
regression-tests.dnsdist/test_Protobuf.py

index 29f1f2045a05dd1dbc1cb8db6abdf63a11b90773..b8da49f0eaa70fb31e83322057b9919ee8763329 100644 (file)
@@ -987,18 +987,20 @@ public:
   }
   DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
   {
-#ifdef HAVE_PROTOBUF
-    DnstapMessage message(d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
+    static thread_local std::string data;
+    data.clear();
+
+    const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(dq->dh);
+    DnstapMessage message(data, !dh->qr ? 5 : 6, d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
     {
       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);
-#endif /* HAVE_PROTOBUF */
+
     return Action::None;
   }
   std::string toString() const override
@@ -1019,7 +1021,6 @@ public:
   }
   DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
   {
-#ifdef HAVE_PROTOBUF
     if (!dq->uniqueId) {
       dq->uniqueId = getUniqueID();
     }
@@ -1041,10 +1042,11 @@ public:
       (*d_alterFunc)(dq, &message);
     }
 
-    std::string data;
+    static thread_local std::string data;
+    data.clear();
     message.serialize(data);
     d_logger->queueData(data);
-#endif /* HAVE_PROTOBUF */
+
     return Action::None;
   }
   std::string toString() const override
@@ -1113,20 +1115,21 @@ public:
   }
   DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
   {
-#ifdef HAVE_PROTOBUF
+    static thread_local std::string data;
     struct timespec now;
     gettime(&now, true);
-    DnstapMessage message(d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
+    data.clear();
+
+    DnstapMessage message(data, 6, d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
     {
       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);
-#endif /* HAVE_PROTOBUF */
+
     return Action::None;
   }
   std::string toString() const override
@@ -1147,7 +1150,6 @@ public:
   }
   DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
   {
-#ifdef HAVE_PROTOBUF
     if (!dr->uniqueId) {
       dr->uniqueId = getUniqueID();
     }
@@ -1169,10 +1171,11 @@ public:
       (*d_alterFunc)(dr, &message);
     }
 
-    std::string data;
+    static thread_local std::string data;
+    data.clear();
     message.serialize(data);
     d_logger->queueData(data);
-#endif /* HAVE_PROTOBUF */
+
     return Action::None;
   }
   std::string toString() const override
@@ -1731,11 +1734,7 @@ void setupLuaActions(LuaContext& luaCtx)
         }
       }
 
-#ifdef HAVE_PROTOBUF
       return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey));
-#else
-      throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
-#endif
     });
 
   luaCtx.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) {
@@ -1759,27 +1758,15 @@ void setupLuaActions(LuaContext& luaCtx)
         }
       }
 
-#ifdef HAVE_PROTOBUF
       return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false));
-#else
-      throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
-#endif
     });
 
   luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
-#ifdef HAVE_PROTOBUF
       return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
-#else
-      throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
-#endif
     });
 
   luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
-#ifdef HAVE_PROTOBUF
       return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
-#else
-      throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
-#endif
     });
 
   luaCtx.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
index e25b57dab8b2ffada1514eaac33bd5d4014c84e6..bca320fc79fffc68c64c40d54db2be7d7fa4dfde 100644 (file)
@@ -48,7 +48,6 @@
 #include "dnswriter.hh"
 #include "dolog.hh"
 #include "lock.hh"
-#include "protobuf.hh"
 #include "sodcrypto.hh"
 
 #ifdef HAVE_LIBSSL
@@ -722,9 +721,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         frontend->cleanup();
       }
       g_tlslocals.clear();
-#ifdef HAVE_PROTOBUF
-      google::protobuf::ShutdownProtobufLibrary();
-#endif /* HAVE_PROTOBUF */
 #endif /* 0 */
       _exit(0);
   } );
index fcf2fd6508b02efb7039aec57ec76d0455ed2cb1..01678d44aa4f986864986dcb259b1a0bcca93149 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 #include "config.h"
-
 #include "dnsdist.hh"
-
 #include "dnsdist-protobuf.hh"
+#include "protozero.hh"
+
+DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSQuestion& dq): d_dq(dq), d_type(1)
+{
+}
+
+DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSResponse& dr, bool includeCNAME): d_dq(dr), d_dr(&dr), d_type(2), d_includeCNAME(includeCNAME)
+{
+}
+
+void DNSDistProtoBufMessage::setServerIdentity(const std::string& serverId)
+{
+  d_serverIdentity = serverId;
+}
+
+void DNSDistProtoBufMessage::setRequestor(const ComboAddress& requestor)
+{
+  d_requestor = requestor;
+}
+
+void DNSDistProtoBufMessage::setResponder(const ComboAddress& responder)
+{
+  d_responder = responder;
+}
+
+void DNSDistProtoBufMessage::setRequestorPort(uint16_t port)
+{
+  if (d_requestor) {
+    d_requestor->setPort(port);
+  }
+}
+
+void DNSDistProtoBufMessage::setResponderPort(uint16_t port)
+{
+  if (d_responder) {
+    d_responder->setPort(port);
+  }
+}
+
+void DNSDistProtoBufMessage::setResponseCode(uint8_t rcode)
+{
+  d_rcode = rcode;
+}
+
+void DNSDistProtoBufMessage::setType(uint32_t type)
+{
+  d_type = type;
+}
 
-#ifdef HAVE_PROTOBUF
-#include "dnsmessage.pb.h"
+void DNSDistProtoBufMessage::setBytes(size_t bytes)
+{
+  d_bytes = bytes;
+}
+
+void DNSDistProtoBufMessage::setTime(time_t sec, uint32_t usec)
+{
+  d_time = std::make_pair(sec, usec);
+}
+
+void DNSDistProtoBufMessage::setQueryTime(time_t sec, uint32_t usec)
+{
+  d_queryTime = std::make_pair(sec, usec);
+}
+
+void DNSDistProtoBufMessage::setQuestion(const DNSName& name, uint16_t qtype, uint16_t qclass)
+{
+  d_question = DNSDistProtoBufMessage::PBQuestion(name, qtype, qclass);
+}
+
+void DNSDistProtoBufMessage::setEDNSSubnet(const Netmask& nm)
+{
+  d_ednsSubnet = nm;
+}
+
+void DNSDistProtoBufMessage::addTag(const std::string& strValue)
+{
+  d_additionalTags.push_back(strValue);
+}
 
-DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSQuestion& dq): DNSProtoBufMessage(Query, dq.uniqueId ? *dq.uniqueId : getUniqueID(), dq.remote, dq.local, *dq.qname, dq.qtype, dq.qclass, dq.dh->id, dq.tcp, dq.len)
+void DNSDistProtoBufMessage::addRR(DNSName&& qname, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob)
 {
-  setQueryTime(dq.queryTime->tv_sec, dq.queryTime->tv_nsec / 1000);
-};
+  d_additionalRRs.push_back({std::move(qname), strBlob, uTTL, uType, uClass});
+}
 
-DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSResponse& dr, bool includeCNAME): DNSProtoBufMessage(Response, dr.uniqueId ? *dr.uniqueId : getUniqueID(), dr.remote, dr.local, *dr.qname, dr.qtype, dr.qclass, dr.dh->id, dr.tcp, dr.len)
+void DNSDistProtoBufMessage::serialize(std::string& data) const
 {
-  setQueryTime(dr.queryTime->tv_sec, dr.queryTime->tv_nsec / 1000);
-  setResponseCode(dr.dh->rcode);
-  addRRsFromPacket((const char*) dr.dh, dr.len, includeCNAME);
-};
+  if ((data.capacity() - data.size()) < 128) {
+    data.reserve(data.size() + 128);
+  }
+  pdns::ProtoZero::Message m{data};
+
+  m.setType(d_type);
+
+  if (d_time) {
+    m.setTime(d_time->first, d_time->second);
+  }
+  else {
+    struct timespec ts;
+    gettime(&ts, true);
+    m.setTime(ts.tv_sec, ts.tv_nsec / 1000);
+  }
+
+  m.setRequest(d_dq.uniqueId ? *d_dq.uniqueId : getUniqueID(), d_requestor ? *d_requestor : *d_dq.remote, d_responder ? *d_responder : *d_dq.local, d_question ? d_question->d_name : *d_dq.qname, d_question ? d_question->d_type : d_dq.qtype, d_question ? d_question->d_class : d_dq.qclass, d_dq.dh->id, d_dq.tcp, d_bytes ? *d_bytes : d_dq.len);
+
+  if (d_serverIdentity) {
+    m.setServerIdentity(*d_serverIdentity);
+  }
+  else if (d_ServerIdentityRef != nullptr) {
+    m.setServerIdentity(*d_ServerIdentityRef);
+  }
+
+  if (d_ednsSubnet) {
+    m.setEDNSSubnet(*d_ednsSubnet, 128);
+  }
+
+  m.startResponse();
+  if (d_queryTime) {
+    m.setQueryTime(d_queryTime->first, d_queryTime->second);
+  }
+  else {
+    m.setQueryTime(d_dq.queryTime->tv_sec, d_dq.queryTime->tv_nsec / 1000);
+  }
+
+  if (d_dr != nullptr) {
+    m.setResponseCode(d_rcode ? *d_rcode : d_dr->dh->rcode);
+    m.addRRsFromPacket(reinterpret_cast<const char*>(d_dr->dh), d_dr->len, d_includeCNAME);
+  }
+  else {
+    if (d_rcode) {
+      m.setResponseCode(*d_rcode);
+    }
+  }
+
+  for (const auto& rr : d_additionalRRs) {
+    m.addRR(rr.d_name, rr.d_type, rr.d_class, rr.d_ttl, rr.d_data);
+  }
+
+  for (const auto& tag : d_additionalTags) {
+    m.addPolicyTag(tag);
+  }
 
-#endif /* HAVE_PROTOBUF */
+  m.commitResponse();
+}
index 670ea796db68c0f72e5bd736b1bb3ee26d25e6f9..e291dc385a382dce0ea5e23bd1c0526067419b05 100644 (file)
  */
 #pragma once
 
-#include "protobuf.hh"
+#include "dnsdist.hh"
+#include "dnsname.hh"
+#include "protozero.hh"
 
-class DNSDistProtoBufMessage: public DNSProtoBufMessage
+class DNSDistProtoBufMessage
 {
 public:
   DNSDistProtoBufMessage(const DNSQuestion& dq);
   DNSDistProtoBufMessage(const DNSResponse& dr, bool includeCNAME);
+
+  void setServerIdentity(const std::string& serverId);
+  void setRequestor(const ComboAddress& requestor);
+  void setResponder(const ComboAddress& responder);
+  void setRequestorPort(uint16_t port);
+  void setResponderPort(uint16_t port);
+  void setResponseCode(uint8_t rcode);
+  void setType(uint32_t type);
+  void setBytes(size_t bytes);
+  void setTime(time_t sec, uint32_t usec);
+  void setQueryTime(time_t sec, uint32_t usec);
+  void setQuestion(const DNSName& name, uint16_t qtype, uint16_t qclass);
+  void setEDNSSubnet(const Netmask& nm);
+
+  void addTag(const std::string& strValue);
+  void addRR(DNSName&& qame, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& data);
+
+  void serialize(std::string& data) const;
+
+  std::string toDebugString() const;
+
+private:
+  struct PBRecord
+  {
+    DNSName d_name;
+    std::string d_data;
+    uint32_t d_ttl;
+    uint16_t d_type;
+    uint16_t d_class;
+  };
+  struct PBQuestion
+  {
+    PBQuestion(const DNSName& name, uint16_t type, uint16_t class_): d_name(name), d_type(type), d_class(class_)
+    {
+    }
+
+    DNSName d_name;
+    uint16_t d_type;
+    uint16_t d_class;
+  };
+
+  std::vector<PBRecord> d_additionalRRs;
+  std::vector<std::string> d_additionalTags;
+
+  const DNSQuestion& d_dq;
+  const DNSResponse* d_dr{nullptr};
+  const std::string* d_ServerIdentityRef{nullptr};
+
+  boost::optional<PBQuestion> d_question{boost::none};
+  boost::optional<std::string> d_serverIdentity{boost::none};
+  boost::optional<ComboAddress> d_requestor{boost::none};
+  boost::optional<ComboAddress> d_responder{boost::none};
+  boost::optional<Netmask> d_ednsSubnet{boost::none};
+  boost::optional<std::pair<time_t, uint32_t>> d_time{boost::none};
+  boost::optional<std::pair<time_t, uint32_t>> d_queryTime{boost::none};
+  boost::optional<size_t> d_bytes{boost::none};
+  boost::optional<uint8_t> d_rcode{boost::none};
+
+  uint32_t d_type{1};
+  bool d_includeCNAME{false};
 };
index 39cb2e197e4170eb3b6a8396211933b5759c320d..5726b0395323258f1811d1a41df53f6d1e156516 100644 (file)
@@ -1127,9 +1127,7 @@ static bool prepareOutgoingResponse(LocalHolders& holders, ClientState& cs, DNSQ
 {
   DNSResponse dr(dq.qname, dq.qtype, dq.qclass, dq.consumed, dq.local, dq.remote, reinterpret_cast<dnsheader*>(dq.dh), dq.size, dq.len, dq.tcp, dq.queryTime);
 
-#ifdef HAVE_PROTOBUF
   dr.uniqueId = dq.uniqueId;
-#endif
   dr.qTag = dq.qTag;
   dr.delayMsec = dq.delayMsec;
 
@@ -2134,9 +2132,7 @@ try
 #ifdef HAVE_LMDB
       cout<<"lmdb ";
 #endif
-#ifdef HAVE_PROTOBUF
       cout<<"protobuf ";
-#endif
 #ifdef HAVE_RE2
       cout<<"re2 ";
 #endif
index 81c13458f6c440439ca812b3e8949339212a0d33..7d5a06a01f0c7c767d78a1cd42ca4df461742895 100644 (file)
@@ -74,9 +74,7 @@ struct DNSQuestion
   std::string getTrailingData() const;
   bool setTrailingData(const std::string&);
 
-#ifdef HAVE_PROTOBUF
   boost::optional<boost::uuids::uuid> uniqueId;
-#endif
   Netmask ecs;
   boost::optional<Netmask> subnet;
   std::string sni; /* Server Name Indication, if any (DoT or DoH) */
@@ -490,9 +488,7 @@ struct IDState
       throw std::runtime_error("Trying to move an in-use IDState");
     }
 
-#ifdef HAVE_PROTOBUF
     uniqueId = std::move(rhs.uniqueId);
-#endif
   }
 
   IDState& operator=(IDState&& rhs)
@@ -532,9 +528,7 @@ struct IDState
     dnssecOK = rhs.dnssecOK;
     useZeroScope = rhs.useZeroScope;
 
-#ifdef HAVE_PROTOBUF
     uniqueId = std::move(rhs.uniqueId);
-#endif
 
     return *this;
   }
@@ -612,9 +606,7 @@ struct IDState
   StopWatch sentTime;                                         // 16
   DNSName qname;                                              // 80
   std::shared_ptr<DNSCryptQuery> dnsCryptQuery{nullptr};
-#ifdef HAVE_PROTOBUF
   boost::optional<boost::uuids::uuid> uniqueId;
-#endif
   boost::optional<Netmask> subnet{boost::none};
   std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
   std::shared_ptr<QTag> qTag{nullptr};
index f6116851fed79571391d49418b645d829d8b19c3..13c80e85e717134e7de095b42397e5a3feeee32d 100644 (file)
@@ -1,4 +1,13 @@
-AM_CPPFLAGS += $(SYSTEMD_CFLAGS) $(LUA_CFLAGS) $(LIBEDIT_CFLAGS) $(LIBSODIUM_CFLAGS) $(FSTRM_CFLAGS) $(YAHTTP_CFLAGS) $(SANITIZER_FLAGS) $(NET_SNMP_CFLAGS) $(LIBCAP_CFLAGS) -DSYSCONFDIR=\"${sysconfdir}\"
+AM_CPPFLAGS += $(SYSTEMD_CFLAGS) \
+       $(LUA_CFLAGS) \
+       $(LIBEDIT_CFLAGS) \
+       $(LIBSODIUM_CFLAGS) \
+       $(FSTRM_CFLAGS) \
+       $(YAHTTP_CFLAGS) \
+       $(SANITIZER_FLAGS) \
+       $(NET_SNMP_CFLAGS) \
+       $(LIBCAP_CFLAGS) \
+       -DSYSCONFDIR=\"${sysconfdir}\"
 
 ACLOCAL_AMFLAGS = -I m4
 
@@ -6,13 +15,9 @@ SUBDIRS=ext/ipcrypt \
        ext/yahttp
 
 CLEANFILES = \
-       dnsmessage.pb.cc \
-       dnsmessage.pb.h \
        htmlfiles.h.tmp \
        htmlfiles.h \
-       dnsdist-lua-ffi-interface.inc \
-       dnstap.pb.cc \
-       dnstap.pb.h
+       dnsdist-lua-ffi-interface.inc
 
 dnslabeltext.cc: dnslabeltext.rl
        $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc
@@ -96,6 +101,7 @@ EXTRA_DIST=COPYING \
           portsmplexer.cc \
           cdb.cc cdb.hh \
           ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh \
+          ext/protozero/include/* \
           builder-support/gen-version
 
 bin_PROGRAMS = dnsdist
@@ -189,7 +195,7 @@ dnsdist_SOURCES = \
        packetcache.hh \
        pdnsexception.hh \
        pollmplexer.cc \
-       protobuf.cc protobuf.hh \
+       protozero.cc protozero.hh \
        proxy-protocol.cc proxy-protocol.hh \
        qtype.cc qtype.hh \
        remote_logger.cc remote_logger.hh \
@@ -351,23 +357,6 @@ endif
 
 CLEANFILES += lua.hpp
 
-if HAVE_PROTOBUF
-if HAVE_PROTOC
-dnsmessage.pb.cc: dnsmessage.proto
-       $(AM_V_GEN)$(PROTOC) -I$(srcdir) --cpp_out=./ $<
-
-dnstap.pb.cc: dnstap.proto
-       $(AM_V_GEN)$(PROTOC) -I$(srcdir) --cpp_out=./ $<
-
-BUILT_SOURCES += dnsmessage.pb.cc dnstap.pb.cc
-
-nodist_dnsdist_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h dnstap.pb.cc dnstap.pb.h
-dnsdist_LDADD += $(PROTOBUF_LIBS)
-
-dnsdist.$(OBJEXT): dnsmessage.pb.cc dnstap.pb.cc
-endif
-endif
-
 if HAVE_FREEBSD
 dnsdist_SOURCES += kqueuemplexer.cc
 testrunner_SOURCES += kqueuemplexer.cc
index 62850326e83a759b00909bfa308b64706ed5c2ac..ddc9d528e8552ab45ce63cb46f4de48f3f16c124 100644 (file)
@@ -32,9 +32,6 @@ PDNS_CHECK_NETWORK_LIBS
 PDNS_CHECK_PTHREAD_NP
 PDNS_CHECK_SECURE_MEMSET
 
-
-PDNS_WITH_PROTOBUF
-
 BOOST_REQUIRE([1.42])
 
 PDNS_ENABLE_UNIT_TESTS
@@ -177,10 +174,7 @@ AC_MSG_NOTICE([])
 AC_MSG_NOTICE([Features enabled])
 AC_MSG_NOTICE([----------------])
 AC_MSG_NOTICE([Lua: $LUAPC])
-AS_IF([test "x$PROTOBUF_LIBS" != "x" -a x"$PROTOC" != "x"],
-  [AC_MSG_NOTICE([Protobuf: yes])],
-  [AC_MSG_NOTICE([Protobuf: no])]
-)
+AC_MSG_NOTICE([Protobuf: yes])
 AS_IF([test "x$systemd" != "xn"],
   [AC_MSG_NOTICE([systemd: yes])],
   [AC_MSG_NOTICE([systemd: no])]
index 05fa48f7ff37ceaa307e7c2de959ecf4a5b66692..db22f3de0ade39b32150275ad88a73d0fcf6c1ff 100644 (file)
@@ -17,9 +17,8 @@ DNSResponse makeDNSResponseFromIDState(IDState& ids, struct dnsheader* dh, size_
   dr.tempFailureTTL = ids.tempFailureTTL;
   dr.qTag = std::move(ids.qTag);
   dr.subnet = std::move(ids.subnet);
-#ifdef HAVE_PROTOBUF
   dr.uniqueId = std::move(ids.uniqueId);
-#endif
+
   if (ids.dnsCryptQuery) {
     dr.dnsCryptQuery = std::move(ids.dnsCryptQuery);
   }
@@ -48,10 +47,7 @@ void setIDStateFromDNSQuestion(IDState& ids, DNSQuestion& dq, DNSName&& qname)
   ids.useZeroScope = dq.useZeroScope;
   ids.qTag = dq.qTag;
   ids.dnssecOK = dq.dnssecOK;
+  ids.uniqueId = std::move(dq.uniqueId);
 
   ids.dnsCryptQuery = std::move(dq.dnsCryptQuery);
-
-#ifdef HAVE_PROTOBUF
-  ids.uniqueId = std::move(dq.uniqueId);
-#endif
 }
index f834abf6a245515eba966c633e24cc296118ec10..3bf81f46c67d0003e5bc368a3f28a1ff65bd75e5 100644 (file)
@@ -73,11 +73,13 @@ void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck)
         message.addTag(tag.second);
       }
     });
+
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(boost::optional <time_t> sec, boost::optional <uint32_t> uSec)>("setProtobufResponseType",
                                         [](DNSDistProtoBufMessage& message, boost::optional <time_t> sec, boost::optional <uint32_t> uSec) {
-      message.setType(DNSProtoBufMessage::Response);
-      message.setQueryTime(sec?*sec:0, uSec?*uSec:0);
+      message.setType(2);
+      message.setQueryTime(sec ? *sec : 0, uSec ? *uSec : 0);
     });
+
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string& strQueryName, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob)>("addResponseRR", [](DNSDistProtoBufMessage& message,
                                                             const std::string& strQueryName, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob) {
       message.addRR(DNSName(strQueryName), uType, uClass, uTTL, strBlob);
@@ -88,7 +90,7 @@ void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck)
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setTime(sec, usec); });
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setQueryTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setQueryTime(sec, usec); });
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(uint8_t)>("setResponseCode", [](DNSDistProtoBufMessage& message, uint8_t rcode) { message.setResponseCode(rcode); });
-  luaCtx.registerFunction<std::string(DNSDistProtoBufMessage::*)()const>("toDebugString", [](const DNSDistProtoBufMessage& message) { return message.toDebugString(); });
+
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&, boost::optional<uint16_t>)>("setRequestor", [](DNSDistProtoBufMessage& message, const ComboAddress& addr, boost::optional<uint16_t> port) {
       message.setRequestor(addr);
       if (port) {
@@ -96,7 +98,7 @@ void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck)
       }
     });
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&, boost::optional<uint16_t>)>("setRequestorFromString", [](DNSDistProtoBufMessage& message, const std::string& str, boost::optional<uint16_t> port) {
-      message.setRequestor(str);
+      message.setRequestor(ComboAddress(str));
       if (port) {
         message.setRequestorPort(*port);
       }
@@ -108,7 +110,7 @@ void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck)
       }
     });
   luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&, boost::optional<uint16_t>)>("setResponderFromString", [](DNSDistProtoBufMessage& message, const std::string& str, boost::optional<uint16_t> port) {
-      message.setResponder(str);
+      message.setResponder(ComboAddress(str));
       if (port) {
         message.setResponderPort(*port);
       }
@@ -117,7 +119,6 @@ void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck)
       message.setServerIdentity(str);
     });
 
-  luaCtx.registerFunction<std::string(DnstapMessage::*)()const>("toDebugString", [](const DnstapMessage& message) { return message.toDebugString(); });
   luaCtx.registerFunction<void(DnstapMessage::*)(const std::string&)>("setExtra", [](DnstapMessage& message, const std::string& str) {
       message.setExtra(str);
     });
diff --git a/pdns/dnsdistdist/ext/protozero b/pdns/dnsdistdist/ext/protozero
new file mode 120000 (symlink)
index 0000000..9997350
--- /dev/null
@@ -0,0 +1 @@
+../../../ext/protozero
\ No newline at end of file
deleted file mode 120000 (symlink)
index ed71845d972625dbff6538fd5bb2509c472252a9..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../../../m4/pdns_check_dnstap.m4
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..1be83c676f1e7c6f89e0e54ed1193e51fc644bde
--- /dev/null
@@ -0,0 +1,31 @@
+AC_DEFUN([PDNS_CHECK_DNSTAP], [
+  AC_MSG_CHECKING([whether we will have dnstap])
+  AC_ARG_ENABLE([dnstap],
+    AS_HELP_STRING([--enable-dnstap],[enable dnstap support @<:@default=$1@:>@]),
+    [enable_dnstap=$enableval],
+    [enable_dnstap=$1],
+  )
+  AC_MSG_RESULT([$enable_dnstap])
+
+  AS_IF([test "x$enable_dnstap" != "xno"], [
+    AS_IF([test "x$enable_dnstap" = "xyes" -o "x$enable_dnstap" = "xauto"], [
+      PKG_CHECK_MODULES([FSTRM], [libfstrm], [
+        AC_DEFINE([HAVE_FSTRM], [1], [Define to 1 if you have libfstrm])
+        save_CFLAGS=$CFLAGS
+        save_LIBS=$LIBS
+        CFLAGS="$FSTRM_CFLAGS $CFLAGS"
+        LIBS="$FSTRM_LIBS $LIBS"
+        AC_CHECK_FUNCS([fstrm_tcp_writer_init])
+        CFLAGS=$save_CFLAGS
+        LIBS=$save_LIBS
+      ], [ : ])
+    ])
+  ])
+
+  AM_CONDITIONAL([FSTRM], [test "x$FSTRM_LIBS" != "x"])
+  AS_IF([test "x$enable_dnstap" = "xyes"], [
+    AS_IF([test x"$FSTRM_LIBS" = "x"], [
+      AC_MSG_ERROR([dnstap requested but libfstrm was not found])
+    ])
+  ])
+])
diff --git a/pdns/dnsdistdist/m4/pdns_with_protobuf.m4 b/pdns/dnsdistdist/m4/pdns_with_protobuf.m4
deleted file mode 120000 (symlink)
index bdfe381..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../../m4/pdns_with_protobuf.m4
\ No newline at end of file
diff --git a/pdns/dnsdistdist/protobuf.cc b/pdns/dnsdistdist/protobuf.cc
deleted file mode 120000 (symlink)
index 088ecc8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../protobuf.cc
\ No newline at end of file
diff --git a/pdns/dnsdistdist/protobuf.hh b/pdns/dnsdistdist/protobuf.hh
deleted file mode 120000 (symlink)
index c7def8e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../protobuf.hh
\ No newline at end of file
diff --git a/pdns/dnsdistdist/protozero.cc b/pdns/dnsdistdist/protozero.cc
new file mode 120000 (symlink)
index 0000000..b2f57f3
--- /dev/null
@@ -0,0 +1 @@
+../protozero.cc
\ No newline at end of file
diff --git a/pdns/dnsdistdist/protozero.hh b/pdns/dnsdistdist/protozero.hh
new file mode 120000 (symlink)
index 0000000..edbde5a
--- /dev/null
@@ -0,0 +1 @@
+../protozero.hh
\ No newline at end of file
index 48010f1d3e53f7a3e28b41461a97a9462762362a..02911952845829721847cb3dac51960a6619a4b2 100644 (file)
@@ -37,6 +37,7 @@
 #include "pdnsexception.hh"
 #include "iputils.hh"
 #include "svc-records.hh"
+#include "views.hh"
 
 /** DNS records have three representations:
     1) in the packet
@@ -66,7 +67,7 @@ class MOADNSParser;
 class PacketReader
 {
 public:
-  PacketReader(const std::string& content, uint16_t initialPos=sizeof(dnsheader))
+  PacketReader(const pdns_string_view& content, uint16_t initialPos=sizeof(dnsheader))
     : d_pos(initialPos), d_startrecordpos(initialPos), d_content(content)
   {
     if(content.size() > std::numeric_limits<uint16_t>::max())
@@ -183,7 +184,7 @@ private:
   uint16_t d_startrecordpos; // needed for getBlob later on
   uint16_t d_recordlen;      // ditto
   uint16_t not_used; // Aligns the whole class on 8-byte boundaries
-  const std::string& d_content;
+  const pdns_string_view d_content;
 };
 
 struct DNSRecord;
index f52ce2912b12f378139a97d92ec55fbdaed0d0bb..a8fa98b15f609e8a5e8e7011e1800b07dbdeefd5 100644 (file)
@@ -1,76 +1,68 @@
+#include <boost/uuid/uuid.hpp>
 #include "config.h"
 #include "gettime.hh"
 #include "dnstap.hh"
 
-DnstapMessage::DnstapMessage(const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime)
+#include "ext/protozero/include/protozero/pbf_writer.hpp"
+
+DnstapMessage::DnstapMessage(std::string& buffer, int32_t type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, boost::optional<const DNSName&> auth): d_buffer(buffer)
 {
-#ifdef HAVE_PROTOBUF
-  const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+  protozero::pbf_writer pbf{d_buffer};
 
-  proto_message.set_identity(identity);
-  proto_message.set_version(PACKAGE_STRING);
-  proto_message.set_type(dnstap::Dnstap::MESSAGE);
+  pbf.add_bytes(1, identity);
+  pbf.add_bytes(2, PACKAGE_STRING);
+  pbf.add_enum(15, 1);
 
-  dnstap::Message* message = proto_message.mutable_message();
+  const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+  protozero::pbf_writer pbf_message{pbf, 14};
 
-  message->set_type(!dh->qr ? dnstap::Message_Type_CLIENT_QUERY : dnstap::Message_Type_CLIENT_RESPONSE);
-  message->set_socket_protocol(isTCP ? dnstap::TCP : dnstap::UDP);
+  pbf_message.add_enum(1, type);
+  pbf_message.add_enum(3, isTCP ? 2 : 1);
 
   if (requestor != nullptr) {
-    message->set_socket_family(requestor->sin4.sin_family == AF_INET ? dnstap::INET : dnstap::INET6);
+    pbf_message.add_enum(2, requestor->sin4.sin_family == AF_INET ? 1 : 2);
     if (requestor->sin4.sin_family == AF_INET) {
-      message->set_query_address(&requestor->sin4.sin_addr.s_addr, sizeof(requestor->sin4.sin_addr.s_addr));
-    } else if (requestor->sin4.sin_family == AF_INET6) {
-      message->set_query_address(&requestor->sin6.sin6_addr.s6_addr, sizeof(requestor->sin6.sin6_addr.s6_addr));
+      pbf_message.add_bytes(4, reinterpret_cast<const char*>(&requestor->sin4.sin_addr.s_addr), sizeof(requestor->sin4.sin_addr.s_addr));
+    }
+    else if (requestor->sin4.sin_family == AF_INET6) {
+      pbf_message.add_bytes(4, reinterpret_cast<const char*>(&requestor->sin6.sin6_addr.s6_addr), sizeof(requestor->sin6.sin6_addr.s6_addr));
     }
-    message->set_query_port(ntohs(requestor->sin4.sin_port));
+    pbf_message.add_uint32(6, ntohs(requestor->sin4.sin_port));
   }
+
   if (responder != nullptr) {
-    message->set_socket_family(responder->sin4.sin_family == AF_INET ? dnstap::INET : dnstap::INET6);
     if (responder->sin4.sin_family == AF_INET) {
-      message->set_response_address(&responder->sin4.sin_addr.s_addr, sizeof(responder->sin4.sin_addr.s_addr));
-    } else if (responder->sin4.sin_family == AF_INET6) {
-      message->set_response_address(&responder->sin6.sin6_addr.s6_addr, sizeof(responder->sin6.sin6_addr.s6_addr));
+      pbf_message.add_bytes(5, reinterpret_cast<const char*>(&responder->sin4.sin_addr.s_addr), sizeof(responder->sin4.sin_addr.s_addr));
+    }
+    else if (responder->sin4.sin_family == AF_INET6) {
+      pbf_message.add_bytes(5, reinterpret_cast<const char*>(&responder->sin6.sin6_addr.s6_addr), sizeof(responder->sin6.sin6_addr.s6_addr));
     }
-    message->set_response_port(ntohs(responder->sin4.sin_port));
+    pbf_message.add_uint32(7, ntohs(responder->sin4.sin_port));
   }
+
   if (queryTime != nullptr) {
-    message->set_query_time_sec(queryTime->tv_sec);
-    message->set_query_time_nsec(queryTime->tv_nsec);
+    pbf_message.add_uint64(8, queryTime->tv_sec);
+    pbf_message.add_fixed32(9, queryTime->tv_nsec);
   }
+
   if (responseTime != nullptr) {
-    message->set_response_time_sec(responseTime->tv_sec);
-    message->set_response_time_nsec(responseTime->tv_nsec);
+    pbf_message.add_uint64(12, responseTime->tv_sec);
+    pbf_message.add_fixed32(13, responseTime->tv_nsec);
   }
 
   if (!dh->qr) {
-    message->set_query_message(packet, len);
+    pbf_message.add_bytes(10, packet, len);
   } else {
-    message->set_response_message(packet, len);
+    pbf_message.add_bytes(14, packet, len);
   }
-#endif /* HAVE_PROTOBUF */
-}
 
-void DnstapMessage::serialize(std::string& data) const
-{
-#ifdef HAVE_PROTOBUF
-  proto_message.SerializeToString(&data);
-#endif /* HAVE_PROTOBUF */
-}
-
-std::string DnstapMessage::toDebugString() const
-{
-  return
-#ifdef HAVE_PROTOBUF
-    proto_message.DebugString();
-#else
-    "";
-#endif /* HAVE_PROTOBUF */
+  if (auth) {
+    pbf_message.add_bytes(11, auth->toDNSString());
+  }
 }
 
 void DnstapMessage::setExtra(const std::string& extra)
 {
-#ifdef HAVE_PROTOBUF
-  proto_message.set_extra(extra);
-#endif /* HAVE_PROTOBUF */
+  protozero::pbf_writer pbf{d_buffer};
+  pbf.add_bytes(3, extra);
 }
index d00bd0bca81c5c74477a0b66858bab47d68295f3..2b1373ddfbcffcf3a00c48b720f8182cc1e43191 100644 (file)
 
 #include "dnsname.hh"
 #include "iputils.hh"
-
-#ifdef HAVE_PROTOBUF
-#include <boost/uuid/uuid.hpp>
-#include "dnstap.pb.h"
-#endif /* HAVE_PROTOBUF */
+#include "protozero.hh"
 
 class DnstapMessage
 {
 public:
-  DnstapMessage(const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime);
-  void serialize(std::string& data) const;
-  std::string toDebugString() const;
+  DnstapMessage(std::string& buffer, int32_t type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, boost::optional<const DNSName&> auth=boost::none);
 
   void setExtra(const std::string& extra);
 
-#ifdef HAVE_PROTOBUF
 protected:
-  dnstap::Dnstap proto_message;
-#endif /* HAVE_PROTOBUF */
+  std::string& d_buffer;
 };
index 9b56397c4831fa2a036f7c5298b528e5b528a418..fca41db91ac8c486713a8d53893410c270a92979 100644 (file)
@@ -54,7 +54,7 @@
 #include "uuid-utils.hh"
 
 #ifdef HAVE_FSTRM
-#include "rec-dnstap.hh"
+#include "dnstap.hh"
 #include "fstrm_logger.hh"
 
 
@@ -81,9 +81,8 @@ static void logFstreamQuery(const std::shared_ptr<std::vector<std::unique_ptr<Fr
 
   struct timespec ts;
   TIMEVAL_TO_TIMESPEC(&queryTime, &ts);
-  RecDnstapMessage message(SyncRes::s_serverID, nullptr, &ip, doTCP, auth, reinterpret_cast<const char*>(&*packet.begin()), packet.size(), &ts, nullptr);
   std::string str;
-  message.serialize(str);
+  DnstapMessage message(str, 4, SyncRes::s_serverID, nullptr, &ip, doTCP, reinterpret_cast<const char*>(&*packet.begin()), packet.size(), &ts, nullptr, auth);
 
   for (auto& logger : *fstreamLoggers) {
     logger->queueData(str);
@@ -112,9 +111,8 @@ static void logFstreamResponse(const std::shared_ptr<std::vector<std::unique_ptr
   struct timespec ts1, ts2;
   TIMEVAL_TO_TIMESPEC(&queryTime, &ts1);
   TIMEVAL_TO_TIMESPEC(&replyTime, &ts2);
-  RecDnstapMessage message(SyncRes::s_serverID, nullptr, &ip, doTCP, auth, static_cast<const char*>(&*packet.begin()), packet.size(), &ts1, &ts2);
   std::string str;
-  message.serialize(str);
+  DnstapMessage message(str, 3, SyncRes::s_serverID, nullptr, &ip, doTCP, static_cast<const char*>(&*packet.begin()), packet.size(), &ts1, &ts2, auth);
 
   for (auto& logger : *fstreamLoggers) {
     logger->queueData(str);
index 0f27ebe977ee48e2e02c1a07202a6b274ee47b6d..71b67b572dbc6b5ff1e349390fa18453f7eb0be1 100644 (file)
 
 #ifdef HAVE_PROTOBUF
 #include "uuid-utils.hh"
-#include "protozero.hh"
+#include "rec-protozero.hh"
 #endif /* HAVE_PROTOBUF */
 
 #include "xpf.hh"
@@ -894,7 +894,8 @@ static void protobufLogQuery(uint8_t maskV4, uint8_t maskV6, const boost::uuids:
   ComboAddress requestor = requestorNM.getMaskedNetwork();
   requestor.setPort(remote.getPort());
 
-  pdns::ProtoZero::Message m{128, std::string::size_type(policyTags.empty() ? 0 : 64)}; // It's a guess
+  pdns::ProtoZero::RecMessage m{128, std::string::size_type(policyTags.empty() ? 0 : 64)}; // It's a guess
+  m.setType(1);
   m.setRequest(uniqueId, requestor, local, qname, qtype, qclass, id, tcp, len);
   m.setServerIdentity(SyncRes::s_serverID);
   m.setEDNSSubnet(ednssubnet, ednssubnet.isIPv4() ? maskV4 : maskV6);
@@ -912,7 +913,7 @@ static void protobufLogQuery(uint8_t maskV4, uint8_t maskV6, const boost::uuids:
   }
 }
 
-static void protobufLogResponse(pdns::ProtoZero::Message& message)
+static void protobufLogResponse(pdns::ProtoZero::RecMessage& message)
 {
   if (!t_protobufServers) {
     return;
@@ -1434,7 +1435,7 @@ static void startDoResolve(void *p)
     bool wantsRPZ(true);
     RecursorPacketCache::OptPBData pbDataForCache;
 #ifdef HAVE_PROTOBUF
-    pdns::ProtoZero::Message pbMessage;
+    pdns::ProtoZero::RecMessage pbMessage;
     if (checkProtobufExport(luaconfsLocal)) {
       pbMessage.reserve(128, 128); // It's a bit of a guess...
       pbMessage.setResponse(dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
@@ -2824,7 +2825,7 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
 
 #ifdef HAVE_PROTOBUF
       if(t_protobufServers && logResponse && !(luaconfsLocal->protobufExportConfig.taggedOnly && pbData && !pbData->d_tagged)) { // XXX
-        pdns::ProtoZero::Message pbMessage(pbData ? pbData->d_message : "", pbData ? pbData->d_response : "", 64, 10); // The extra bytes we are going to add
+        pdns::ProtoZero::RecMessage pbMessage(pbData ? pbData->d_message : "", pbData ? pbData->d_response : "", 64, 10); // The extra bytes we are going to add
         if (pbData) {
           // We take the inmutable string from the cache and are appending a few values
         } else {
index 3a40b383470ec612c49d599f4a16e2bef0ae9359..4d9ddcb896a1d29a8b6ea5b1047020be8d0b321b 100644 (file)
@@ -21,8 +21,7 @@
  */
 
 #include "protozero.hh"
-#include "dnsrecords.hh"
-
+#include "dnsparser.hh"
 
 void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& ca)
 {
@@ -59,7 +58,6 @@ void pdns::ProtoZero::Message::encodeDNSName(protozero::pbf_writer& pbf, std::st
 
 void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, bool tcp, size_t len)
 {
-  setType(1);
   setMessageIdentity(uniqueId);
   setSocketFamily(requestor.sin4.sin_family);
   setSocketProtocol(tcp);
@@ -79,99 +77,81 @@ void pdns::ProtoZero::Message::setResponse(const DNSName& qname, uint16_t qtype,
   setQuestion(qname, qtype, qclass);
 }
 
-
-void pdns::ProtoZero::Message::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr)
+void pdns::ProtoZero::Message::addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME)
 {
-  if (record.d_place != DNSResourceRecord::ANSWER || record.d_class != QClass::IN) {
+  if (len < sizeof(struct dnsheader)) {
     return;
   }
 
-  if (exportTypes.count(record.d_type) == 0) {
+  const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+
+  if (ntohs(dh->ancount) == 0) {
     return;
   }
 
-  protozero::pbf_writer pbf_rr{d_response, 2};
-
-  encodeDNSName(pbf_rr, d_rspbuf, 1, record.d_name);
-  pbf_rr.add_uint32(2, record.d_type);
-  pbf_rr.add_uint32(3, record.d_class);
-  pbf_rr.add_uint32(4, record.d_ttl);
-
-  switch(record.d_type) {
-  case QType::A:
-  {
-    const auto& content = dynamic_cast<const ARecordContent&>(*(record.d_content));
-    ComboAddress data = content.getCA();
-    pbf_rr.add_bytes(5, reinterpret_cast<const char*>(&data.sin4.sin_addr.s_addr), sizeof(data.sin4.sin_addr.s_addr));
-    break;
-  }
-  case QType::AAAA:
-  {
-    const auto& content = dynamic_cast<const AAAARecordContent&>(*(record.d_content));
-    ComboAddress data = content.getCA();
-    pbf_rr.add_bytes(5, reinterpret_cast<const char*>(&data.sin6.sin6_addr.s6_addr), sizeof(data.sin6.sin6_addr.s6_addr));
-    break;
-  }
-  case QType::CNAME:
-  {
-    const auto& content = dynamic_cast<const CNAMERecordContent&>(*(record.d_content));
-    pbf_rr.add_string(5, content.getTarget().toString());
-    break;
-  }
-  case QType::TXT:
-  {
-    const auto& content = dynamic_cast<const TXTRecordContent&>(*(record.d_content));
-    pbf_rr.add_string(5, content.d_text);
-    break;
-  }
-  case QType::NS:
-  {
-    const auto& content = dynamic_cast<const NSRecordContent&>(*(record.d_content));
-    pbf_rr.add_string(5, content.getNS().toString());
-    break;
-  }
-  case QType::PTR:
-  {
-    const auto& content = dynamic_cast<const PTRRecordContent&>(*(record.d_content));
-    pbf_rr.add_string(5, content.getContent().toString());
-    break;
-  }
-  case QType::MX:
-  {
-    const auto& content = dynamic_cast<const MXRecordContent&>(*(record.d_content));
-    pbf_rr.add_string(5, content.d_mxname.toString());
-    break;
-  }
-  case QType::SPF:
-  {
-    const auto& content = dynamic_cast<const SPFRecordContent&>(*(record.d_content));
-    pbf_rr.add_string(5, content.getText());
-    break;
+  if (ntohs(dh->qdcount) == 0) {
+    return;
   }
-  case QType::SRV:
-  {
-    const auto& content = dynamic_cast<const SRVRecordContent&>(*(record.d_content));
-    pbf_rr.add_string(5, content.d_target.toString());
-    break;
+
+  PacketReader pr(pdns_string_view(packet, len));
+
+  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;
+    }
   }
-  default:
-    break;
+
+  /* parse AN */
+  for (idx = 0; idx < ancount; idx++) {
+    rrname = pr.getName();
+    pr.getDnsrecordheader(ah);
+
+    if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
+      pr.xfrBlob(blob);
+
+      addRR(rrname, ah.d_type, ah.d_class, ah.d_ttl, blob);
+
+    } else if (ah.d_type == QType::CNAME && includeCNAME) {
+      protozero::pbf_writer pbf_rr{d_response, 2};
+
+      encodeDNSName(pbf_rr, d_buffer, 1, rrname);
+      pbf_rr.add_uint32(2, ah.d_type);
+      pbf_rr.add_uint32(3, ah.d_class);
+      pbf_rr.add_uint32(4, ah.d_ttl);
+      DNSName target;
+      pr.xfrName(target, true);
+      encodeDNSName(pbf_rr, d_buffer, 5, target);
+    }
+    else {
+      pr.xfrBlob(blob);
+    }
   }
-#ifdef NOD_ENABLED
-  pbf_rr.add_bool(6, udr);
-  pbf_rr.commit();
-
-  // Save the offset of the byte containing the just added bool. We can do this since
-  // we know a bit about how protobuf's encoding works.
-  offsets.push_back(d_rspbuf.length() - 1);
-#endif
 }
 
-#ifdef NOD_ENABLED
-void pdns::ProtoZero::Message::clearUDR(std::string& str)
+void pdns::ProtoZero::Message::addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob)
 {
-  for (auto i : offsets) {
-    str.at(i) = 0;
-  }
+  protozero::pbf_writer pbf_rr{d_response, 2};
+  encodeDNSName(pbf_rr, d_buffer, 1, name);
+  pbf_rr.add_uint32(2, uType);
+  pbf_rr.add_uint32(3, uClass);
+  pbf_rr.add_uint32(4, uTTL);
+  pbf_rr.add_string(5, blob);
 }
-#endif
index c151f075b89a5c86ccc3c854e40058f6d4f08de8..7a767af1be93c5b45d3b38616777f90769f78169 100644 (file)
  */
 #pragma once
 
-#include <protozero/pbf_writer.hpp>
-#include <string>
+#include "ext/protozero/include/protozero/pbf_writer.hpp"
 
 #include "config.h"
 #include "iputils.hh"
-#include "filterpo.hh"
 #include "gettime.hh"
 #include "uuid-utils.hh"
 
@@ -34,233 +32,186 @@ namespace pdns {
   namespace ProtoZero {
     class Message {
     public:
-      Message() : d_message{d_msgbuf}, d_response{d_rspbuf}
+      Message(std::string& buffer): d_buffer(buffer), d_message{d_buffer}
       {
       }
-      // Start a new messagebuf, containing separate data for the response part
-      Message(std::string::size_type sz1, std::string::size_type sz2) : d_message{d_msgbuf}, d_response{d_rspbuf}
-      {
-        reserve(sz1, sz2);
-      }
 
-      // Construct a Message with (partially) constructed content
-      Message(const std::string& buf1, const std::string& buf2, std::string::size_type sz1, std::string::size_type sz2) :
-        d_msgbuf{buf1}, d_rspbuf{buf2}, d_message{d_msgbuf}, d_response{d_rspbuf}
-      {
-        reserve(sz1, sz2);
-      }
       Message(const Message&) = delete;
       Message(Message&&) = delete;
       Message& operator=(const Message&) = delete;
       Message& operator=(Message&&) = delete;
 
-      void reserve(std::string::size_type sz1, std::string::size_type sz2)
-      {
-        // We expect to grow the buffers, in the end the d_message will contains the (grown) d_response
-        // This is extra space in addition to what's already there
-        // Different from what string.reserve() does
-        std::string::size_type extra = sz1 + d_rspbuf.length() + sz2;
-        if (d_msgbuf.capacity() < d_msgbuf.size() + extra) {
-          d_message.reserve(extra);
-        }
-        if (d_rspbuf.capacity() < d_rspbuf.size() + sz2) {
-          d_response.reserve(sz2);
-        }
-      }
-      const std::string& getMessageBuf() const
-      {
-        return d_msgbuf;
-      }
-      const std::string& getResponseBuf() const
-      {
-        return d_rspbuf;
-      }
-      std::string&& finishAndMoveBuf()
-      {
-        if (!d_rspbuf.empty()) {
-          d_message.add_message(13, d_rspbuf);
-        }
-        return std::move(d_msgbuf);
-      }
-      void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& ca);
-      void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
-      void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
       void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, bool tcp, size_t len);
       void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass);
 
-      void setType(int mtype)
+      void setType(uint32_t mtype)
       {
-       d_message.add_enum(1, mtype);
+        d_message.add_enum(1, mtype);
       }
+
       void setMessageIdentity(const boost::uuids::uuid& uniqueId)
       {
-       d_message.add_bytes(2, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
+        d_message.add_bytes(2, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
       }
+
       void setServerIdentity(const std::string& serverIdentity)
       {
-       d_message.add_bytes(3, serverIdentity.data(), serverIdentity.length());
+        d_message.add_bytes(3, serverIdentity.data(), serverIdentity.length());
       }
+
       void setSocketFamily(int family)
       {
-       d_message.add_enum(4, family == AF_INET ? 1 : 2);
+        d_message.add_enum(4, family == AF_INET ? 1 : 2);
       }
+
       void setSocketProtocol(bool tcp)
       {
-       d_message.add_enum(5, tcp ? 2 : 1);
+        d_message.add_enum(5, tcp ? 2 : 1);
       }
+
       void setFrom(const ComboAddress& ca)
       {
         encodeComboAddress(6, ca);
       }
+
       void setTo(const ComboAddress& ca)
       {
         encodeComboAddress(7, ca);
       }
+
       void setInBytes(uint64_t len)
       {
         if (len) {
          d_message.add_uint64(8, len);
         }
       }
+
       void setTime()
       {
         struct timespec ts;
         gettime(&ts, true);
+
+        setTime(ts.tv_sec, ts.tv_nsec / 1000);
+      }
+
+      void setTime(time_t sec, uint32_t usec)
+      {
         // timeSec
-       d_message.add_uint32(9, ts.tv_sec);
+        d_message.add_uint32(9, sec);
         // timeUsec
-       d_message.add_uint32(10, ts.tv_nsec / 1000);
+        d_message.add_uint32(10, usec);
       }
+
       void setId(uint16_t id)
       {
        d_message.add_uint32(11, ntohs(id));
       }
+
       void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
       {
         protozero::pbf_writer pbf_question{d_message, 12};
-        encodeDNSName(pbf_question, d_msgbuf, 1, qname);
+        encodeDNSName(pbf_question, d_buffer, 1, qname);
         pbf_question.add_uint32(2, qtype);
         pbf_question.add_uint32(3, qclass);
       }
+
       void setEDNSSubnet(const Netmask& nm, uint8_t mask)
       {
         encodeNetmask(14, nm, mask);
       }
+
       void setRequestorId(const std::string& req)
       {
         if (!req.empty()) {
-         d_message.add_string(15, req);
+          d_message.add_string(15, req);
         }
       }
+
       void setInitialRequesId(const std::string& id)
       {
         if (!id.empty()) {
-         d_message.add_string(16, id);
+          d_message.add_string(16, id);
         }
       }
+
       void setDeviceId(const std::string& id)
       {
         if (!id.empty()) {
-         d_message.add_string(17, id);
+          d_message.add_string(17, id);
         }
       }
+
       void setNewlyObservedDomain(bool nod)
       {
-       d_message.add_bool(18, nod);
+        d_message.add_bool(18, nod);
       }
+
       void setDeviceName(const std::string& name)
       {
         if (!name.empty()) {
-         d_message.add_string(19, name);
+          d_message.add_string(19, name);
         }
       }
+
       void setFromPort(in_port_t port)
       {
-       d_message.add_uint32(20, port);
+        d_message.add_uint32(20, port);
       }
+
       void setToPort(in_port_t port)
       {
-       d_message.add_uint32(21, port);
+        d_message.add_uint32(21, port);
       }
 
-      // DNSResponse related fields below
+      void startResponse()
+      {
+        d_response = protozero::pbf_writer{d_message, 13};
+      }
+
+      void commitResponse()
+      {
+        d_response.commit();
+      }
 
       void setResponseCode(uint8_t rcode)
       {
         d_response.add_uint32(1, rcode);
       }
 
-      void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr);
-
       void setAppliedPolicy(const std::string& policy)
       {
         d_response.add_string(3, policy);
       }
+
       void addPolicyTags(const std::unordered_set<std::string>& tags)
       {
         for (const auto& tag : tags) {
           d_response.add_string(4, tag);
         }
       }
+
       void addPolicyTag(const string& tag)
       {
         d_response.add_string(4, tag);
       }
+
       void setQueryTime(uint32_t sec, uint32_t usec)
       {
         d_response.add_uint32(5, sec);
         d_response.add_uint32(6, usec);
       }
-      void setAppliedPolicyType(const DNSFilterEngine::PolicyType type)
-      {
-        uint32_t p;
-
-        switch(type) {
-        case DNSFilterEngine::PolicyType::None:
-          p = 1;
-          break;
-        case DNSFilterEngine::PolicyType::QName:
-          p = 2;
-          break;
-        case DNSFilterEngine::PolicyType::ClientIP:
-          p = 3;
-          break;
-        case DNSFilterEngine::PolicyType::ResponseIP:
-          p = 4;
-          break;
-        case DNSFilterEngine::PolicyType::NSDName:
-          p = 5;
-          break;
-        case DNSFilterEngine::PolicyType::NSIP:
-          p = 6;
-          break;
-        default:
-          throw std::runtime_error("Unsupported protobuf policy type");
-        }
-        d_response.add_uint32(7, p);
-      }
-      void setAppliedPolicyTrigger(const DNSName& trigger)
-      {
-        encodeDNSName(d_response, d_rspbuf, 8, trigger);
-      }
-      void setAppliedPolicyHit(const std::string& hit)
-      {
-        d_response.add_string(9, hit);
-      }
 
-#ifdef NOD_ENABLED      
-      void clearUDR(std::string&);
-#endif
+      void addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME=false);
+      void addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob);
 
-    private:
-      std::string d_msgbuf;
-      std::string d_rspbuf;
+    protected:
+      void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& ca);
+      void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
+      void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
+
+      std::string& d_buffer;
       protozero::pbf_writer d_message;
       protozero::pbf_writer d_response;
-
-#ifdef NOD_ENABLED
-      vector<std::string::size_type> offsets;
-#endif
     };
   };
 };
diff --git a/pdns/rec-dnstap.hh b/pdns/rec-dnstap.hh
deleted file mode 100644 (file)
index 1be6e0a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-
-#ifdef HAVE_FSTRM
-#include "dnstap.hh"
-#endif /* HAVE_FSTRM */
-
-class RecDnstapMessage : public DnstapMessage
-{
-public:
-  RecDnstapMessage(const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, boost::optional<const DNSName&> auth, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime)
-      : DnstapMessage(identity, requestor, responder, isTCP, packet, len, queryTime, responseTime) {
-    const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
-    dnstap::Message* message = proto_message.mutable_message();
-    message->set_type(!dh->qr ? dnstap::Message_Type_RESOLVER_QUERY : dnstap::Message_Type_RESOLVER_RESPONSE);
-    if (auth) {
-      message->set_query_zone(auth->toDNSString());
-    }
-  }
-};
index 9fa34a9ded4bcb61cac8ff038318cafd54fd1d6f..75400b14b4826dc81cfa45cf0dff185a7e9a4a5e 100644 (file)
@@ -34,7 +34,6 @@
 
 #include "packetcache.hh"
 #include "validate.hh"
-#include "protozero.hh"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
index 53771988e1e15699febaa9a3d753ba1eb79a7be7..16ea652280f78610862e22f5972e5d487ce67929 100644 (file)
@@ -5,7 +5,6 @@ AM_CPPFLAGS = $(LUA_CFLAGS) $(YAHTTP_CFLAGS) $(BOOST_CPPFLAGS) $(LIBSODIUM_CFLAG
 
 AM_CPPFLAGS += \
        -I$(top_srcdir)/ext/json11 \
-       -I$(top_srcdir)/ext/protozero/include \
        $(YAHTTP_CFLAGS) \
        $(LIBCRYPTO_INCLUDES)
 
@@ -36,8 +35,6 @@ BUILT_SOURCES=htmlfiles.h \
 CLEANFILES = htmlfiles.h \
        dnsmessage.pb.cc \
        dnsmessage.pb.h \
-       dnstap.pb.cc \
-       dnstap.pb.h \
        recursor.conf-dist
 
 htmlfiles.h: html/*
@@ -67,7 +64,7 @@ EXTRA_DIST = \
        NOTICE \
        opensslsigners.hh opensslsigners.cc \
        portsmplexer.cc \
-       dnstap.proto dnstap.cc dnstap.hh fstrm_logger.cc fstrm_logger.hh rec-dnstap.hh \
+       dnstap.proto dnstap.cc dnstap.hh fstrm_logger.cc fstrm_logger.hh \
        ext/protozero/include/* \
        rrd/* \
        html incfiles \
@@ -157,6 +154,7 @@ pdns_recursor_SOURCES = \
        rec-carbon.cc \
        rec-lua-conf.hh rec-lua-conf.cc \
        rec-protobuf.cc rec-protobuf.hh \
+       rec-protozero.cc rec-protozero.hh \
        rec-snmp.hh rec-snmp.cc \
        rec_channel.cc rec_channel.hh rec_metrics.hh \
        rec_channel_rec.cc \
@@ -401,27 +399,13 @@ if HAVE_PROTOC
 dnsmessage.pb.cc: dnsmessage.proto
        $(AM_V_GEN)$(PROTOC) --cpp_out=./ $<
 
-if FSTRM
-dnstap.pb.cc: dnstap.proto
-       $(AM_V_GEN)$(PROTOC) -I$(srcdir) --cpp_out=./ $<
-endif
-
-
 BUILT_SOURCES += dnsmessage.pb.cc
 pdns_recursor_LDADD += $(PROTOBUF_LIBS)
 nodist_pdns_recursor_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h
 nodist_testrunner_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h
 
-if FSTRM
-BUILT_SOURCES += dnstap.pb.cc
-pdns_recursor.$(OBJEXT): dnstap.pb.cc dnsmessage.pb.cc
-testrunner$(OBJEXT): dnstap.pb.cc dnsmessage.pb.cc
-nodist_pdns_recursor_SOURCES += dnstap.pb.cc dnstap.pb.h
-nodist_testrunner_SOURCES += dnstap.pb.cc dnstap.pb.h
-else
 pdns_recursor.$(OBJEXT): dnsmessage.pb.cc
 testrunner$(OBJEXT): dnsmessage.pb.cc
-endif
 
 testrunner_LDADD += $(PROTOBUF_LIBS)
 
@@ -430,7 +414,7 @@ endif
 
 if FSTRM
 pdns_recursor_SOURCES += \
-       dnstap.cc dnstap.hh rec-dnstap.hh
+       dnstap.cc dnstap.hh
 
 pdns_recursor_LDADD += \
        $(FSTRM_LIBS)
diff --git a/pdns/recursordist/rec-dnstap.hh b/pdns/recursordist/rec-dnstap.hh
deleted file mode 120000 (symlink)
index 4011f47..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../rec-dnstap.hh
\ No newline at end of file
diff --git a/pdns/recursordist/rec-protozero.cc b/pdns/recursordist/rec-protozero.cc
new file mode 100644 (file)
index 0000000..da76144
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsrecords.hh"
+#include "rec-protozero.hh"
+
+void pdns::ProtoZero::RecMessage::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr)
+{
+  if (record.d_place != DNSResourceRecord::ANSWER || record.d_class != QClass::IN) {
+    return;
+  }
+
+  if (exportTypes.count(record.d_type) == 0) {
+    return;
+  }
+
+  protozero::pbf_writer pbf_rr{d_response, 2};
+
+  encodeDNSName(pbf_rr, d_rspbuf, 1, record.d_name);
+  pbf_rr.add_uint32(2, record.d_type);
+  pbf_rr.add_uint32(3, record.d_class);
+  pbf_rr.add_uint32(4, record.d_ttl);
+
+  switch(record.d_type) {
+  case QType::A:
+  {
+    const auto& content = dynamic_cast<const ARecordContent&>(*(record.d_content));
+    ComboAddress data = content.getCA();
+    pbf_rr.add_bytes(5, reinterpret_cast<const char*>(&data.sin4.sin_addr.s_addr), sizeof(data.sin4.sin_addr.s_addr));
+    break;
+  }
+  case QType::AAAA:
+  {
+    const auto& content = dynamic_cast<const AAAARecordContent&>(*(record.d_content));
+    ComboAddress data = content.getCA();
+    pbf_rr.add_bytes(5, reinterpret_cast<const char*>(&data.sin6.sin6_addr.s6_addr), sizeof(data.sin6.sin6_addr.s6_addr));
+    break;
+  }
+  case QType::CNAME:
+  {
+    const auto& content = dynamic_cast<const CNAMERecordContent&>(*(record.d_content));
+    pbf_rr.add_string(5, content.getTarget().toString());
+    break;
+  }
+  case QType::TXT:
+  {
+    const auto& content = dynamic_cast<const TXTRecordContent&>(*(record.d_content));
+    pbf_rr.add_string(5, content.d_text);
+    break;
+  }
+  case QType::NS:
+  {
+    const auto& content = dynamic_cast<const NSRecordContent&>(*(record.d_content));
+    pbf_rr.add_string(5, content.getNS().toString());
+    break;
+  }
+  case QType::PTR:
+  {
+    const auto& content = dynamic_cast<const PTRRecordContent&>(*(record.d_content));
+    pbf_rr.add_string(5, content.getContent().toString());
+    break;
+  }
+  case QType::MX:
+  {
+    const auto& content = dynamic_cast<const MXRecordContent&>(*(record.d_content));
+    pbf_rr.add_string(5, content.d_mxname.toString());
+    break;
+  }
+  case QType::SPF:
+  {
+    const auto& content = dynamic_cast<const SPFRecordContent&>(*(record.d_content));
+    pbf_rr.add_string(5, content.getText());
+    break;
+  }
+  case QType::SRV:
+  {
+    const auto& content = dynamic_cast<const SRVRecordContent&>(*(record.d_content));
+    pbf_rr.add_string(5, content.d_target.toString());
+    break;
+  }
+  default:
+    break;
+  }
+#ifdef NOD_ENABLED
+  pbf_rr.add_bool(6, udr);
+  pbf_rr.commit();
+
+  // Save the offset of the byte containing the just added bool. We can do this since
+  // we know a bit about how protobuf's encoding works.
+  offsets.push_back(d_rspbuf.length() - 1);
+#endif
+}
+
+#ifdef NOD_ENABLED
+void pdns::ProtoZero::RecMessage::clearUDR(std::string& str)
+{
+  for (auto i : offsets) {
+    str.at(i) = 0;
+  }
+}
+#endif
diff --git a/pdns/recursordist/rec-protozero.hh b/pdns/recursordist/rec-protozero.hh
new file mode 100644 (file)
index 0000000..74f2086
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "protozero.hh"
+
+#include "filterpo.hh"
+
+namespace pdns {
+  namespace ProtoZero {
+    class RecMessage : public Message {
+    public:
+      RecMessage(): Message(d_msgbuf)
+      {
+        d_response = protozero::pbf_writer(d_rspbuf);
+      }
+      // Start a new messagebuf, containing separate data for the response part
+      RecMessage(std::string::size_type sz1, std::string::size_type sz2): RecMessage()
+      {
+        reserve(sz1, sz2);
+      }
+
+      // Construct a Message with (partially) constructed content
+      RecMessage(const std::string& buf1, const std::string& buf2, std::string::size_type sz1, std::string::size_type sz2) :
+        Message(d_msgbuf), d_msgbuf{buf1}, d_rspbuf{buf2}
+      {
+        d_message = protozero::pbf_writer(d_msgbuf);
+        d_response = protozero::pbf_writer(d_rspbuf);
+        reserve(sz1, sz2);
+      }
+      RecMessage(const Message&) = delete;
+      RecMessage(Message&&) = delete;
+      RecMessage& operator=(const Message&) = delete;
+      RecMessage& operator=(Message&&) = delete;
+
+      void reserve(std::string::size_type sz1, std::string::size_type sz2)
+      {
+        // We expect to grow the buffers, in the end the d_message will contains the (grown) d_response
+        // This is extra space in addition to what's already there
+        // Different from what string.reserve() does
+        std::string::size_type extra = sz1 + d_rspbuf.length() + sz2;
+        if (d_msgbuf.capacity() < d_msgbuf.size() + extra) {
+          d_message.reserve(extra);
+        }
+        if (d_rspbuf.capacity() < d_rspbuf.size() + sz2) {
+          d_response.reserve(sz2);
+        }
+      }
+
+      const std::string& getMessageBuf() const
+      {
+        return d_msgbuf;
+      }
+
+      const std::string& getResponseBuf() const
+      {
+        return d_rspbuf;
+      }
+
+      std::string&& finishAndMoveBuf()
+      {
+        if (!d_rspbuf.empty()) {
+          d_message.add_message(13, d_rspbuf);
+        }
+        return std::move(d_msgbuf);
+      }
+
+      // DNSResponse related fields below
+
+      void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr);
+
+      void setAppliedPolicyType(const DNSFilterEngine::PolicyType type)
+      {
+        uint32_t p;
+
+        switch(type) {
+        case DNSFilterEngine::PolicyType::None:
+          p = 1;
+          break;
+        case DNSFilterEngine::PolicyType::QName:
+          p = 2;
+          break;
+        case DNSFilterEngine::PolicyType::ClientIP:
+          p = 3;
+          break;
+        case DNSFilterEngine::PolicyType::ResponseIP:
+          p = 4;
+          break;
+        case DNSFilterEngine::PolicyType::NSDName:
+          p = 5;
+          break;
+        case DNSFilterEngine::PolicyType::NSIP:
+          p = 6;
+          break;
+        default:
+          throw std::runtime_error("Unsupported protobuf policy type");
+        }
+        d_response.add_uint32(7, p);
+      }
+
+      void setAppliedPolicyTrigger(const DNSName& trigger)
+      {
+        encodeDNSName(d_response, d_rspbuf, 8, trigger);
+      }
+
+      void setAppliedPolicyHit(const std::string& hit)
+      {
+        d_response.add_string(9, hit);
+      }
+
+#ifdef NOD_ENABLED
+      void clearUDR(std::string&);
+#endif
+
+    private:
+      std::string d_msgbuf;
+      std::string d_rspbuf;
+
+#ifdef NOD_ENABLED
+      vector<std::string::size_type> offsets;
+#endif
+    };
+  };
+};
index 0197fa8d098058fcb34adec5a79d3c962a879116..10101cebda01fe539a6886b5ceb7f6e9cefe180d 100644 (file)
@@ -23,7 +23,7 @@ bool CircularWriteBuffer::hasRoomFor(const std::string& str) const
 
 bool CircularWriteBuffer::write(const std::string& str)
 {
-  if (!hasRoomFor(str)) {
+  if (str.size() > std::numeric_limits<uint16_t>::max() || !hasRoomFor(str)) {
     return false;
   }
 
@@ -134,6 +134,10 @@ bool RemoteLogger::reconnect()
 
 void RemoteLogger::queueData(const std::string& data)
 {
+  if (data.size() > std::numeric_limits<uint16_t>::max()) {
+    throw std::runtime_error("Got a request to write an object of size " + data.size());
+  }
+
   std::unique_lock<std::mutex> lock(d_mutex);
 
   if (!d_writer.hasRoomFor(data)) {
index d931c094368497ab55d2d775c83f33bc06f64e80..bf02435cc77a780a326b96edfcc67920426da972 100644 (file)
@@ -35,6 +35,46 @@ using pdns_string_view = boost::string_view;
 #include <boost/utility/string_ref.hpp>
 using pdns_string_view = boost::string_ref;
 #else
-using pdns_string_view = std::string;
+
+/* this class implements a very restricted view, since nothing else is available
+   and doing a full allocation + copy is just dumb */
+class pdns_string_view
+{
+public:
+  pdns_string_view() noexcept
+  {
+  }
+
+  pdns_string_view(const std::string& str) noexcept: d_ptr{str.data()}, d_size(str.size())
+  {
+  }
+
+  pdns_string_view(const char* str, size_t len) noexcept: d_ptr{str}, d_size(len)
+  {
+  }
+
+  size_t size() const noexcept
+  {
+    return d_size;
+  }
+
+  const char& at(size_t pos) const
+  {
+    if (pos >= d_size) {
+      throw std::out_of_range("pdns_string_view::at() " + std::to_string(pos) + " >= " + std::to_string(d_size));
+    }
+    return *(d_ptr + pos);
+  }
+
+  const char* data() const noexcept
+  {
+    return d_ptr;
+  }
+
+private:
+  const char* d_ptr{nullptr};
+  const size_t d_size{0};
+};
+
 #endif
 #endif
index 103cd22349c95393767db0e8cd5f6d29d6d8405e..a864e39b3abcaa376b899d3add98a754b013f220 100644 (file)
@@ -204,7 +204,7 @@ class TestProtobuf(DNSDistProtobufTest):
 
         protobuf:setProtobufResponseType()                     -- set protobuf to look like a response and not a query, with 0 default time
 
-        blobData = '\127' .. '\000' .. '\000' .. '\001'                -- 127.0.0.1, note: lua 5.1 can only embed decimal not hex
+        blobData = '\127' .. '\000' .. '\000' .. '\002'                -- 127.0.0.2, note: lua 5.1 can only embed decimal not hex
 
         protobuf:addResponseRR(strReqName, 1, 1, 123, blobData) -- add a RR to the protobuf
 
@@ -405,7 +405,7 @@ class TestProtobufIPCipher(DNSDistProtobufTest):
 
     def testProtobuf(self):
         """
-        Protobuf: Send data to a protobuf server
+        Protobuf: Send data to a protobuf server, with pseudonymization
         """
         name = 'query.protobuf-ipcipher.tests.powerdns.com.'