}
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
}
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
-#ifdef HAVE_PROTOBUF
if (!dq->uniqueId) {
dq->uniqueId = getUniqueID();
}
(*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
}
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
}
DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
{
-#ifdef HAVE_PROTOBUF
if (!dr->uniqueId) {
dr->uniqueId = getUniqueID();
}
(*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
}
}
-#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) {
}
}
-#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) {
#include "dnswriter.hh"
#include "dolog.hh"
#include "lock.hh"
-#include "protobuf.hh"
#include "sodcrypto.hh"
#ifdef HAVE_LIBSSL
frontend->cleanup();
}
g_tlslocals.clear();
-#ifdef HAVE_PROTOBUF
- google::protobuf::ShutdownProtobufLibrary();
-#endif /* HAVE_PROTOBUF */
#endif /* 0 */
_exit(0);
} );
* 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();
+}
*/
#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};
};
{
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;
#ifdef HAVE_LMDB
cout<<"lmdb ";
#endif
-#ifdef HAVE_PROTOBUF
cout<<"protobuf ";
-#endif
#ifdef HAVE_RE2
cout<<"re2 ";
#endif
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) */
throw std::runtime_error("Trying to move an in-use IDState");
}
-#ifdef HAVE_PROTOBUF
uniqueId = std::move(rhs.uniqueId);
-#endif
}
IDState& operator=(IDState&& rhs)
dnssecOK = rhs.dnssecOK;
useZeroScope = rhs.useZeroScope;
-#ifdef HAVE_PROTOBUF
uniqueId = std::move(rhs.uniqueId);
-#endif
return *this;
}
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};
-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
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
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
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 \
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
PDNS_CHECK_PTHREAD_NP
PDNS_CHECK_SECURE_MEMSET
-
-PDNS_WITH_PROTOBUF
-
BOOST_REQUIRE([1.42])
PDNS_ENABLE_UNIT_TESTS
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])]
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);
}
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
}
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);
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) {
}
});
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);
}
}
});
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);
}
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);
});
--- /dev/null
+../../../ext/protozero
\ No newline at end of file
+++ /dev/null
-../../../m4/pdns_check_dnstap.m4
\ No newline at end of file
--- /dev/null
+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])
+ ])
+ ])
+])
+++ /dev/null
-../../../m4/pdns_with_protobuf.m4
\ No newline at end of file
+++ /dev/null
-../protobuf.cc
\ No newline at end of file
+++ /dev/null
-../protobuf.hh
\ No newline at end of file
--- /dev/null
+../protozero.cc
\ No newline at end of file
--- /dev/null
+../protozero.hh
\ No newline at end of file
#include "pdnsexception.hh"
#include "iputils.hh"
#include "svc-records.hh"
+#include "views.hh"
/** DNS records have three representations:
1) in the packet
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())
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;
+#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);
}
#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;
};
#include "uuid-utils.hh"
#ifdef HAVE_FSTRM
-#include "rec-dnstap.hh"
+#include "dnstap.hh"
#include "fstrm_logger.hh"
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);
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);
#ifdef HAVE_PROTOBUF
#include "uuid-utils.hh"
-#include "protozero.hh"
+#include "rec-protozero.hh"
#endif /* HAVE_PROTOBUF */
#include "xpf.hh"
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);
}
}
-static void protobufLogResponse(pdns::ProtoZero::Message& message)
+static void protobufLogResponse(pdns::ProtoZero::RecMessage& message)
{
if (!t_protobufServers) {
return;
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);
#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 {
*/
#include "protozero.hh"
-#include "dnsrecords.hh"
-
+#include "dnsparser.hh"
void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& ca)
{
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);
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
*/
#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"
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
};
};
};
+++ /dev/null
-/*
- * 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());
- }
- }
-};
#include "packetcache.hh"
#include "validate.hh"
-#include "protozero.hh"
#ifdef HAVE_CONFIG_H
#include "config.h"
AM_CPPFLAGS += \
-I$(top_srcdir)/ext/json11 \
- -I$(top_srcdir)/ext/protozero/include \
$(YAHTTP_CFLAGS) \
$(LIBCRYPTO_INCLUDES)
CLEANFILES = htmlfiles.h \
dnsmessage.pb.cc \
dnsmessage.pb.h \
- dnstap.pb.cc \
- dnstap.pb.h \
recursor.conf-dist
htmlfiles.h: html/*
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 \
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 \
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)
if FSTRM
pdns_recursor_SOURCES += \
- dnstap.cc dnstap.hh rec-dnstap.hh
+ dnstap.cc dnstap.hh
pdns_recursor_LDADD += \
$(FSTRM_LIBS)
+++ /dev/null
-../rec-dnstap.hh
\ No newline at end of file
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+ };
+ };
+};
bool CircularWriteBuffer::write(const std::string& str)
{
- if (!hasRoomFor(str)) {
+ if (str.size() > std::numeric_limits<uint16_t>::max() || !hasRoomFor(str)) {
return false;
}
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)) {
#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
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
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.'