protobuf strings to allow for mod of the response.
if msg.HasField('initialRequestId'):
initialrequestidstr = ', initial uuid: %s ' % (binascii.hexlify(bytearray(msg.initialRequestId)))
- requestorstr = ''
+ requestorstr = '(N/A)'
requestor = self.getRequestorSubnet(msg)
if requestor:
requestorstr = ' (' + requestor + ')'
- deviceId = binascii.hexlify(bytearray(msg.deviceId))
- requestorId = msg.requestorId
+ deviceId = 'N/A'
+ if msg.HasField('deviceId'):
+ deviceId = binascii.hexlify(bytearray(msg.deviceId))
+ deviceName = 'N/A'
+ if msg.HasField('deviceName'):
+ deviceName = msg.deviceName
+
+ requestorId = 'N/A'
+ if msg.HasField('requestorId'):
+ requestorId = msg.requestorId
+
nod = 0
if (msg.HasField('newlyObservedDomain')):
nod = msg.newlyObservedDomain
- print('[%s] %s of size %d: %s%s%s -> %s%s (%s), id: %d, uuid: %s%s '
- 'requestorid: %s deviceid: %s serverid: %s nod: %d' % (datestr,
+ print('[%s] %s of size %d: %s%s%s -> %s%s(%s) id: %d uuid: %s%s '
+ 'requestorid: %s deviceid: %s devicename: %s serverid: %s nod: %d' % (datestr,
typestr,
msg.inBytes,
ipfromstr,
initialrequestidstr,
requestorId,
deviceId,
+ deviceName,
serveridstr,
nod))
}
std::string DNSName::toString(const std::string& separator, const bool trailing) const
+{
+ std::string ret;
+ toString(ret, separator, trailing);
+ return ret;
+}
+
+void DNSName::toString(std::string& output, const std::string& separator, const bool trailing) const
{
if (empty()) {
throw std::out_of_range("Attempt to print an unset dnsname");
}
- if(isRoot())
- return trailing ? separator : "";
+ if (isRoot()) {
+ output += (trailing ? separator : "");
+ return;
+ }
- std::string ret;
- ret.reserve(d_storage.size());
+ if (output.capacity() < (output.size() + d_storage.size())) {
+ output.reserve(output.size() + d_storage.size());
+ }
{
// iterate over the raw labels
const char* end = p + d_storage.size();
while (p < end && *p) {
- appendEscapedLabel(ret, p + 1, static_cast<size_t>(*p));
- ret += separator;
+ appendEscapedLabel(output, p + 1, static_cast<size_t>(*p));
+ output += separator;
p += *p + 1;
}
}
+
if (!trailing) {
- ret.resize(ret.size() - separator.size());
+ output.resize(output.size() - separator.size());
}
- return ret;
}
std::string DNSName::toLogString() const
bool operator!=(const DNSName& other) const { return !(*this == other); }
std::string toString(const std::string& separator=".", const bool trailing=true) const; //!< Our human-friendly, escaped, representation
+ void toString(std::string& output, const std::string& separator=".", const bool trailing=true) const;
std::string toLogString() const; //!< like plain toString, but returns (empty) on empty names
std::string toStringNoDot() const { return toString(".", false); }
std::string toStringRootDot() const { if(isRoot()) return "."; else return toString(".", false); }
#ifdef HAVE_PROTOBUF
#include "uuid-utils.hh"
+#include "protozero.hh"
#endif /* HAVE_PROTOBUF */
#include "xpf.hh"
Netmask requestorNM(remote, remote.sin4.sin_family == AF_INET ? maskV4 : maskV6);
ComboAddress requestor = requestorNM.getMaskedNetwork();
requestor.setPort(remote.getPort());
- RecProtoBufMessage message(DNSProtoBufMessage::Query, uniqueId, &requestor, &local, qname, qtype, qclass, id, tcp, len);
- message.setServerIdentity(SyncRes::s_serverID);
- message.setEDNSSubnet(ednssubnet, ednssubnet.isIPv4() ? maskV4 : maskV6);
- message.setRequestorId(requestorId);
- message.setDeviceId(deviceId);
- message.setDeviceName(deviceName);
+
+ pdns::ProtoZero::Message m{128}; // guess at size
+ m.request(uniqueId, requestor, local, qname, qtype, qclass, id, tcp, len);
+ m.setServerIdentity(SyncRes::s_serverID);
+ m.setEDNSSubnet(ednssubnet, ednssubnet.isIPv4() ? maskV4 : maskV6);
+ m.setRequestorId(requestorId);
+ m.setDeviceId(deviceId);
+ m.setDeviceName(deviceName);
if (!policyTags.empty()) {
- message.setPolicyTags(policyTags);
+ m.startResponse();
+ m.setPolicyTags(policyTags);
+ m.finishResponse();
}
-// cerr <<message.toDebugString()<<endl;
- std::string str;
- message.serialize(str);
-
for (auto& server : *t_protobufServers) {
- server->queueData(str);
+ server->queueData(m.getbuf());
}
}
-static void protobufLogResponse(const RecProtoBufMessage& message)
+static void protobufLogResponse(const pdns::ProtoZero::Message& message)
{
if (!t_protobufServers) {
return;
}
-// cerr <<message.toDebugString()<<endl;
- std::string str;
- message.serialize(str);
-
+ string data = message.getbuf();
for (auto& server : *t_protobufServers) {
- server->queueData(str);
+ server->queueData(data);
}
}
#endif
auto luaconfsLocal = g_luaconfs.getLocal();
// Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query
bool wantsRPZ(true);
- boost::optional<RecProtoBufMessage> pbMessage(boost::none);
+ std::unique_ptr<pdns::ProtoZero::Message> pbMessage;
+ std::string::size_type pbUnmutablePart; // defines the (first) part of the protobuf message that is equal for everyone
#ifdef HAVE_PROTOBUF
if (checkProtobufExport(luaconfsLocal)) {
- Netmask requestorNM(dc->d_source, dc->d_source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
- ComboAddress requestor = requestorNM.getMaskedNetwork();
- requestor.setPort(dc->d_source.getPort());
- pbMessage = RecProtoBufMessage(RecProtoBufMessage::Response, dc->d_uuid, &requestor, &dc->d_destination, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass, dc->d_mdp.d_header.id, dc->d_tcp, 0);
+ pbMessage = make_unique<pdns::ProtoZero::Message>(128); // guess at size
+ pbMessage->response(dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
pbMessage->setServerIdentity(SyncRes::s_serverID);
- pbMessage->setEDNSSubnet(dc->d_ednssubnet.source, dc->d_ednssubnet.source.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
+
+ // RRSets added below
+ pbMessage->startResponse();
}
#endif /* HAVE_PROTOBUF */
#endif /* NOD_ENABLED */
#ifdef HAVE_PROTOBUF
if (t_protobufServers && !(luaconfsLocal->protobufExportConfig.taggedOnly && appliedPolicy.getName().empty() && dc->d_policyTags.empty())) {
- pbMessage->setBytes(packet.size());
+ // Start constructing embedded DNSResponse object
pbMessage->setResponseCode(pw.getHeader()->rcode);
if (!appliedPolicy.getName().empty()) {
pbMessage->setAppliedPolicy(appliedPolicy.getName());
pbMessage->setAppliedPolicyTrigger(appliedPolicy.d_trigger);
pbMessage->setAppliedPolicyHit(appliedPolicy.d_hit);
}
+ // XXX if (nod)
pbMessage->setPolicyTags(dc->d_policyTags);
+ pbMessage->finishResponse();
+ pbMessage->setInBytes(packet.size());
+
+ // Done with embedded DNSResponse object and done with unmutable part.
+ pbUnmutablePart = pbMessage->getbuf().length();
+
+ // Below arte the fields that are not stored in the packet cache and will be appended here and on a cache hit
+ pbMessage->startResponse();
if (g_useKernelTimestamp && dc->d_kernelTimestamp.tv_sec) {
pbMessage->setQueryTime(dc->d_kernelTimestamp.tv_sec, dc->d_kernelTimestamp.tv_usec);
}
else {
pbMessage->setQueryTime(dc->d_now.tv_sec, dc->d_now.tv_usec);
}
+ pbMessage->finishResponse();
+ pbMessage->setMessageIdentity(dc->d_uuid);
+ pbMessage->setSocketFamily(dc->d_source.sin4.sin_family);
+ pbMessage->setSocketProtocol(dc->d_tcp);
+ Netmask requestorNM(dc->d_source, dc->d_source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
+ ComboAddress requestor = requestorNM.getMaskedNetwork();
+ pbMessage->setFrom(requestor);
+ pbMessage->setTo(dc->d_destination);
+ pbMessage->setId(dc->d_mdp.d_header.id);
+
+ // Th exact semantics of timeSec/timeUsec vs queryTimeSec/queryTimeUsec are unclear to me ATM
+ pbMessage->setTime();
+ pbMessage->setEDNSSubnet(dc->d_ednssubnet.source, dc->d_ednssubnet.source.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
pbMessage->setRequestorId(dq.requestorId);
pbMessage->setDeviceId(dq.deviceId);
pbMessage->setDeviceName(dq.deviceName);
+ pbMessage->setFromPort(dc->d_source.getPort());
+ pbMessage->setToPort(dc->d_destination.getPort());
#ifdef NOD_ENABLED
if (g_nodEnabled) {
if (nod) {
- pbMessage->setNOD(true);
+ pbMessage->setNewlyObservedDomain(true);
pbMessage->addPolicyTag(g_nod_pbtag);
}
if (hasUDR) {
}
#ifdef NOD_ENABLED
if (g_nodEnabled) {
- pbMessage->setNOD(false);
+ pbMessage->setNewlyObservedDomain(false);
pbMessage->clearUDR();
if (nod)
pbMessage->removePolicyTag(g_nod_pbtag);
pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
min(minTTL,SyncRes::s_packetcachettl),
dq.validationState,
- std::move(pbMessage));
+ pbMessage.get(), pbUnmutablePart);
}
// else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
}
}
bool cacheHit = false;
- boost::optional<RecProtoBufMessage> pbMessage(boost::none);
+ string *pbString = nullptr;
#ifdef HAVE_PROTOBUF
if (t_protobufServers) {
- pbMessage = RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response);
- pbMessage->setServerIdentity(SyncRes::s_serverID);
if (logQuery && !(luaconfsLocal->protobufExportConfig.taggedOnly && policyTags.empty())) {
protobufLogQuery(luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, source, destination, ednssubnet.source, false, dh->id, question.size(), qname, qtype, qclass, policyTags, requestorId, deviceId, deviceName);
}
as cacheable we would cache it with a wrong tag, so better safe than sorry. */
vState valState;
if (qnameParsed) {
- cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &valState, &qhash, pbMessage ? &(*pbMessage) : nullptr));
+ cacheHit = !SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &valState, &qhash, &pbString);
}
else {
- cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, &qtype, &qclass, g_now.tv_sec, &response, &age, &valState, &qhash, pbMessage ? &(*pbMessage) : nullptr));
+ cacheHit = !SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, &qtype, &qclass, g_now.tv_sec, &response, &age, &valState, &qhash, &pbString);
}
if (cacheHit) {
}
#ifdef HAVE_PROTOBUF
- if(t_protobufServers && logResponse && !(luaconfsLocal->protobufExportConfig.taggedOnly && pbMessage->getAppliedPolicy().empty() && pbMessage->getPolicyTags().empty())) {
+ if(t_protobufServers && logResponse /* && !(luaconfsLocal->protobufExportConfig.taggedOnly && pbMessage->appliedPolicyIsSet() && pbMessage->policyTagsAreSet()) */) {
+ std::unique_ptr<pdns::ProtoZero::Message> pbMessage;
+ if (pbString != nullptr) {
+ // We take the inmutable string form the cache an are appending a few values
+ pbMessage = make_unique<pdns::ProtoZero::Message>(*pbString, 128); // The extra bytes we are going to add
+ } else {
+ pbMessage = make_unique<pdns::ProtoZero::Message>(128);
+ pbMessage->setType(2); // Response
+ pbMessage->setServerIdentity(SyncRes::s_serverID);
+ }
+ //cerr << "from cache: " << pbMessage->getbuf().length() << endl;
Netmask requestorNM(source, source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
ComboAddress requestor = requestorNM.getMaskedNetwork();
- requestor.setPort(source.getPort());
- pbMessage->update(uniqueId, &requestor, &destination, false, dh->id);
- pbMessage->setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
+ pbMessage->setMessageIdentity(uniqueId);
+ pbMessage->setFrom(requestor);
+ pbMessage->setTo(destination);
+ pbMessage->setSocketProtocol(false);
+ pbMessage->setId(dh->id);
+ // Exact semantics of the various timestamps are unclear to me ATM
+ pbMessage->setTime();
+ pbMessage->startResponse();
if (g_useKernelTimestamp && tv.tv_sec) {
pbMessage->setQueryTime(tv.tv_sec, tv.tv_usec);
}
else {
pbMessage->setQueryTime(g_now.tv_sec, g_now.tv_usec);
}
+ pbMessage->finishResponse();
+ pbMessage->setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
pbMessage->setRequestorId(requestorId);
pbMessage->setDeviceId(deviceId);
pbMessage->setDeviceName(deviceName);
+ pbMessage->setFromPort(source.getPort());
+ pbMessage->setToPort(destination.getPort());
+ //cerr << "affter adding: " << pbMessage->getbuf().length() << endl;
protobufLogResponse(*pbMessage);
}
#endif /* HAVE_PROTOBUF */
--- /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 "protozero.hh"
+#include "dnsrecords.hh"
+
+
+void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& ca)
+{
+ if (ca.sin4.sin_family == AF_INET) {
+ d_pbf.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr));
+ }
+ else if (ca.sin4.sin_family == AF_INET6) {
+ d_pbf.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr));
+ }
+}
+
+void pdns::ProtoZero::Message::encodeNetmask(const protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask)
+{
+ if (!subnet.empty()) {
+ ComboAddress ca(subnet.getNetwork());
+ ca.truncate(mask);
+ if (ca.sin4.sin_family == AF_INET) {
+ d_pbf.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr));
+ }
+ else if (ca.sin4.sin_family == AF_INET6) {
+ d_pbf.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr));
+ }
+ }
+}
+
+void pdns::ProtoZero::Message::encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, const protozero::pbf_tag_type type, const DNSName& name)
+{
+ // this will append the tag, mark the current position then reserve enough place to write the size
+ protozero::pbf_writer pbf_name{pbf, type};
+ // we append the name to the buffer
+ name.toString(buffer);
+ // leaving the block will cause the sub writer to compute how much was written based on the new size and update the size accordingly
+}
+
+void pdns::ProtoZero::Message::request(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);
+ setFrom(requestor);
+ setTo(local);
+ setInBytes(len);
+ setTime();
+ setId(id);
+ setQuestion(qname, qtype, qclass);
+ setFromPort(requestor.getPort());
+ setToPort(local.getPort());
+}
+
+void pdns::ProtoZero::Message::response(const DNSName& qname, uint16_t qtype, uint16_t qclass)
+{
+ setType(2);
+ setQuestion(qname, qtype, qclass);
+}
+
+
+#ifdef NOD_ENABLED
+void pdns::ProtoZero::Message::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr)
+#else
+void pdns::ProtoZero::Message::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes)
+#endif /* NOD_ENABLED */
+{
+ 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_buffer, 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);
+#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/pbf_writer.hpp>
+#include <string>
+
+#include "config.h"
+#include "iputils.hh"
+#include "filterpo.hh"
+#include "gettime.hh"
+#include "uuid-utils.hh"
+
+namespace pdns {
+ namespace ProtoZero {
+ class Message {
+ public:
+ Message(size_t sz) : d_pbf{d_buffer}
+ {
+ d_buffer.reserve(sz);
+ }
+ Message(const std::string& buf, size_t sz) : d_buffer(buf), d_pbf(d_buffer)
+ {
+ // We expect to grow the buffwer
+ d_buffer.reserve(d_buffer.capacity() + sz);
+ }
+ const std::string& getbuf() const
+ {
+ return d_buffer;
+ }
+ std::string&& movebuf()
+ {
+ return std::move(d_buffer);
+ }
+ void encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& ca);
+ void encodeNetmask(const protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
+ void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, const protozero::pbf_tag_type type, const DNSName& name);
+ void request(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 response(const DNSName& qname, uint16_t qtype, uint16_t qclass);
+
+ void setType(int mtype)
+ {
+ d_pbf.add_enum(1, mtype);
+ }
+ void setMessageIdentity(const boost::uuids::uuid& uniqueId)
+ {
+ d_pbf.add_bytes(2, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
+ }
+ void setServerIdentity(const std::string& serverIdentity)
+ {
+ d_pbf.add_bytes(3, serverIdentity.data(), serverIdentity.length());
+ }
+ void setSocketFamily(int family)
+ {
+ d_pbf.add_enum(4, family == AF_INET ? 1 : 2);
+ }
+ void setSocketProtocol(bool tcp)
+ {
+ d_pbf.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_pbf.add_uint64(8, len);
+ }
+ }
+ void setTime()
+ {
+ struct timespec ts;
+ gettime(&ts, true);
+ // timeSec
+ d_pbf.add_uint32(9, ts.tv_sec);
+ // timeUsec
+ d_pbf.add_uint32(10, ts.tv_nsec / 1000);
+ }
+ void setId(uint16_t id)
+ {
+ d_pbf.add_uint32(11, ntohs(id));
+ }
+ void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
+ {
+ protozero::pbf_writer pbf_question{d_pbf, 12};
+ 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 (true || !req.empty()) {
+ d_pbf.add_string(15, req);
+ }
+ }
+ void setInitialRequesId(const std::string& id)
+ {
+ if (!id.empty()) {
+ d_pbf.add_string(16, id);
+ }
+ }
+ void setDeviceId(const std::string& id)
+ {
+ if (true || !id.empty()) {
+ d_pbf.add_string(17, id);
+ }
+ }
+ void setNewlyObservedDomain(bool nod)
+ {
+ d_pbf.add_bool(18, nod);
+ }
+ void setDeviceName(const std::string& name)
+ {
+ if (true || !name.empty()) {
+ d_pbf.add_string(19, name);
+ }
+ }
+ void setFromPort(in_port_t port)
+ {
+ d_pbf.add_uint32(20, port);
+ }
+ void setToPort(in_port_t port)
+ {
+ d_pbf.add_uint32(21, port);
+ }
+
+ // DNSResponse related fields below
+ void startResponse()
+ {
+ if (d_response != nullptr) {
+ throw new runtime_error("response already inited");
+ }
+ d_response = new protozero::pbf_writer(d_pbf, 13);
+ }
+ void finishResponse()
+ {
+ delete d_response;
+ d_response = nullptr;
+ }
+ void setResponseCode(uint8_t rcode)
+ {
+ d_response->add_uint32(1, rcode);
+ }
+#ifdef NOD_ENABLED
+ void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr);
+#else
+ void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes);
+#endif
+ void clearUDR()
+ {
+ }
+ void setAppliedPolicy(const std::string& policy)
+ {
+ d_response->add_string(3, policy);
+ }
+ bool appliedPolicyIsSet() const
+ {
+ return false;
+ }
+ void setPolicyTags(const std::unordered_set<std::string>& tags)
+ {
+ for (const auto& tag : tags) {
+ d_response->add_string(4, tag);
+ }
+ }
+ void addPolicyTag(const string& tag)
+ {
+ }
+ void removePolicyTag(const string& tag)
+ {
+ }
+ bool policyTagsAreSet() const
+ {
+ return false;
+ }
+ 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_buffer, 8, trigger);
+ }
+ void setAppliedPolicyHit(const std::string& hit)
+ {
+ d_response->add_string(9, hit);
+ }
+
+ private:
+ std::string d_buffer;
+ protozero::pbf_writer d_pbf;
+ protozero::pbf_writer *d_response{nullptr};
+ };
+ };
+};
return queryMatches(iter->d_query, queryPacket, qname, optionsToSkip);
}
-bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, RecProtoBufMessage* protobufMessage)
+bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, std::string** protobufMessage)
{
for(auto iter = range.first ; iter != range.second ; ++iter) {
// the possibility is VERY real that we get hits that are not right - birthday paradox
#ifdef HAVE_PROTOBUF
if (protobufMessage) {
if (iter->d_protobufMessage) {
- protobufMessage->copyFrom(*(iter->d_protobufMessage));
+ *protobufMessage = &*iter->d_protobufMessage;
}
else {
- *protobufMessage = RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response);
+ *protobufMessage = nullptr;
}
}
#endif
}
bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
- std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, RecProtoBufMessage* protobufMessage)
+ std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, std::string** protobufMessage)
{
*qhash = canHashPacket(queryPacket, true);
const auto& idx = d_packetCache.get<HashTag>();
}
bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now,
- std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, RecProtoBufMessage* protobufMessage)
+ std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, std::string** protobufMessage)
{
*qhash = canHashPacket(queryPacket, true);
const auto& idx = d_packetCache.get<HashTag>();
}
-void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, boost::optional<RecProtoBufMessage>&& protobufMessage)
+void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, pdns::ProtoZero::Message* protobufMessage, std::string::size_type pbUnmutablePart)
{
auto& idx = d_packetCache.get<HashTag>();
auto range = idx.equal_range(tie(tag,qhash));
iter->d_vstate = valState;
#ifdef HAVE_PROTOBUF
if (protobufMessage) {
- iter->d_protobufMessage = std::move(*protobufMessage);
+ std::string s(protobufMessage->movebuf());
+ s.resize(pbUnmutablePart);
+ s.shrink_to_fit();
+ iter->d_protobufMessage = boost::optional<std::string>(s);
}
#endif
e.d_vstate = valState;
#ifdef HAVE_PROTOBUF
if (protobufMessage) {
- e.d_protobufMessage = std::move(*protobufMessage);
+ std::string s(protobufMessage->movebuf());
+ s.resize(pbUnmutablePart);
+ s.shrink_to_fit();
+ e.d_protobufMessage = boost::optional<std::string>(s);
}
#endif
d_packetCache.insert(e);
for(auto i=sidx.cbegin(); i != sidx.cend(); ++i) {
count++;
try {
- fprintf(fp.get(), "%s %" PRId64 " %s ; tag %d\n", i->d_name.toString().c_str(), static_cast<int64_t>(i->d_ttd - now), DNSRecordContent::NumberToType(i->d_type).c_str(), i->d_tag);
+ fprintf(fp.get(), "%s %" PRId64 " %s ; tag %d pb %zu\n", i->d_name.toString().c_str(), static_cast<int64_t>(i->d_ttd - now), DNSRecordContent::NumberToType(i->d_type).c_str(), i->d_tag, i->d_protobufMessage ? i->d_protobufMessage->length() : 0);
}
catch(...) {
fprintf(fp.get(), "; error printing '%s'\n", i->d_name.empty() ? "EMPTY" : i->d_name.toString().c_str());
#include "packetcache.hh"
#include "validate.hh"
+#include "protozero.hh"
#ifdef HAVE_CONFIG_H
#include "config.h"
RecursorPacketCache();
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash);
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash);
- bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, RecProtoBufMessage* protobufMessage);
- bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, RecProtoBufMessage* protobufMessage);
- void insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, boost::optional<RecProtoBufMessage>&& protobufMessage);
+ bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, std::string** protobufMessage);
+ bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t *qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, std::string** protobufMessage);
+
+ void insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, pdns::ProtoZero::Message* protobufMessage = nullptr, std::string::size_type pbUnmutablePart = 0);
void doPruneTo(size_t maxSize=250000);
uint64_t doDump(int fd);
int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false);
mutable std::string d_packet; // "I know what I am doing"
mutable std::string d_query;
#ifdef HAVE_PROTOBUF
- mutable boost::optional<RecProtoBufMessage> d_protobufMessage;
+ mutable boost::optional<std::string> d_protobufMessage;
#endif
mutable time_t d_ttd;
mutable time_t d_creation; // so we can 'age' our packets
packetCache_t d_packetCache;
static bool qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass);
- bool checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, RecProtoBufMessage* protobufMessage);
+ bool checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, std::string** protobufMessage);
public:
void preRemoval(const Entry& entry)
AM_CPPFLAGS += \
-I$(top_srcdir)/ext/json11 \
+ -I$(top_srcdir)/ext/protozero/include \
$(YAHTTP_CFLAGS) \
$(LIBCRYPTO_INCLUDES)
opensslsigners.hh opensslsigners.cc \
portsmplexer.cc \
dnstap.proto dnstap.cc dnstap.hh fstrm_logger.cc fstrm_logger.hh rec-dnstap.hh \
+ ext/protozero/include/* \
rrd/* \
html incfiles \
test_libcrypto \
ws-api.cc ws-api.hh \
ws-recursor.cc ws-recursor.hh \
xpf.cc xpf.hh \
- zoneparser-tng.cc zoneparser-tng.hh
+ zoneparser-tng.cc zoneparser-tng.hh \
+ protozero.cc protozero.hh
if !HAVE_LUA_HPP
BUILT_SOURCES += lua.hpp
--- /dev/null
+../../../ext/protozero
\ 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
pw.commit();
string rpacket((const char*)&packet[0], packet.size());
- rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
rpc.doPruneTo(0);
BOOST_CHECK_EQUAL(rpc.size(), 0U);
- rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
rpc.doWipePacketCache(qname);
BOOST_CHECK_EQUAL(rpc.size(), 0U);
- rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
uint32_t qhash2 = 0;
bool found = rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash2);
BOOST_CHECK(r1packet != r2packet);
/* inserting a response for tag1 */
- rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
/* inserting a different response for tag2, should not override the first one */
- rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 2U);
/* remove all responses from the cache */
BOOST_CHECK_EQUAL(rpc.size(), 0U);
/* reinsert both */
- rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
- rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 2U);
/* remove the responses by qname, should remove both */
BOOST_CHECK_EQUAL(rpc.size(), 0U);
/* insert the response for tag1 */
- rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
/* we can retrieve it */
BOOST_CHECK_EQUAL(temphash, qhash);
/* adding a response for the second tag */
- rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none);
+ rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, nullptr);
BOOST_CHECK_EQUAL(rpc.size(), 2U);
/* We still get the correct response for the first tag */