]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Implement a "no-initialization" vector to avoid a perf regression
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 13 Oct 2020 14:27:27 +0000 (16:27 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 11 Jan 2021 09:22:00 +0000 (10:22 +0100)
42 files changed:
pdns/Makefile.am
pdns/dnscrypt.cc
pdns/dnscrypt.hh
pdns/dnsdist-cache.cc
pdns/dnsdist-cache.hh
pdns/dnsdist-dnscrypt.cc
pdns/dnsdist-ecs.cc
pdns/dnsdist-ecs.hh
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-lua-bindings-dnsquestion.cc
pdns/dnsdist-lua-bindings.cc
pdns/dnsdist-lua-rules.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/dnsdist-healthchecks.cc
pdns/dnsdistdist/dnsdist-idstate.cc
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/dnsdist-proxy-protocol.cc
pdns/dnsdistdist/dnsdist-proxy-protocol.hh
pdns/dnsdistdist/dnsdist-secpoll.cc
pdns/dnsdistdist/dnsdist-tcp-downstream.cc
pdns/dnsdistdist/dnsdist-tcp-downstream.hh
pdns/dnsdistdist/dnsdist-tcp-upstream.hh
pdns/dnsdistdist/doh.cc
pdns/dnsdistdist/noinitvector.hh [new symlink]
pdns/dnsdistdist/tcpiohandler.cc
pdns/dnsdistdist/test-dnsdistkvs_cc.cc
pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc
pdns/dnsdistdist/test-dnsdistrules_cc.cc
pdns/dnswriter.cc
pdns/dnswriter.hh
pdns/doh.hh
pdns/fuzz_dnsdistcache.cc
pdns/noinitvector.hh [new file with mode: 0644]
pdns/recursordist/Makefile.am
pdns/recursordist/noinitvector.hh [new symlink]
pdns/sodcrypto.cc
pdns/tcpiohandler.hh
pdns/test-dnscrypt_cc.cc
pdns/test-dnsdist_cc.cc
pdns/test-dnsdistpacketcache_cc.cc

index 7050349d954bc21c65fa2d214c26e3b3808fd7db..5244f412bb0a919ad7137ecf05c462b4022bc602 100644 (file)
@@ -224,6 +224,7 @@ pdns_server_SOURCES = \
        misc.cc misc.hh \
        nameserver.cc nameserver.hh \
        namespaces.hh \
+       noinitvector.hh \
        nsecrecords.cc \
        opensslsigners.cc opensslsigners.hh \
        packetcache.hh \
index dca863977f36d2f879e62eb682fbfd79594fa3a2..4a0abe56569f2e408ac1858a36755d21ed9783df 100644 (file)
@@ -384,7 +384,7 @@ void DNSCryptContext::removeInactiveCertificate(uint32_t serial)
   throw std::runtime_error("No inactive certificate found with this serial");
 }
 
-bool DNSCryptQuery::parsePlaintextQuery(const std::vector<uint8_t>& packet)
+bool DNSCryptQuery::parsePlaintextQuery(const PacketBuffer& packet)
 {
   assert(d_ctx != nullptr);
 
@@ -418,9 +418,9 @@ bool DNSCryptQuery::parsePlaintextQuery(const std::vector<uint8_t>& packet)
   return true;
 }
 
-void DNSCryptContext::getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, std::vector<uint8_t>& response)
+void DNSCryptContext::getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, PacketBuffer& response)
 {
-  DNSPacketWriter pw(response, qname, QType::TXT, QClass::IN, Opcode::Query);
+  GenericDNSPacketWriter<PacketBuffer> pw(response, qname, QType::TXT, QClass::IN, Opcode::Query);
   struct dnsheader * dh = pw.getHeader();
   dh->id = qid;
   dh->qr = true;
@@ -458,7 +458,7 @@ bool DNSCryptContext::magicMatchesAPublicKey(DNSCryptQuery& query, time_t now)
   return false;
 }
 
-bool DNSCryptQuery::isEncryptedQuery(const std::vector<uint8_t>& packet, bool tcp, time_t now)
+bool DNSCryptQuery::isEncryptedQuery(const PacketBuffer& packet, bool tcp, time_t now)
 {
   assert(d_ctx != nullptr);
 
@@ -485,7 +485,7 @@ bool DNSCryptQuery::isEncryptedQuery(const std::vector<uint8_t>& packet, bool tc
   return true;
 }
 
-void DNSCryptQuery::getDecrypted(bool tcp, std::vector<uint8_t>& packet)
+void DNSCryptQuery::getDecrypted(bool tcp, PacketBuffer& packet)
 {
   assert(d_encrypted);
   assert(d_pair != nullptr);
@@ -576,13 +576,13 @@ void DNSCryptQuery::getDecrypted(bool tcp, std::vector<uint8_t>& packet)
   d_valid = true;
 }
 
-void DNSCryptQuery::getCertificateResponse(time_t now, std::vector<uint8_t>& response) const
+void DNSCryptQuery::getCertificateResponse(time_t now, PacketBuffer& response) const
 {
   assert(d_ctx != nullptr);
   d_ctx->getCertificateResponse(now, d_qname, d_id, response);
 }
 
-void DNSCryptQuery::parsePacket(std::vector<uint8_t>& packet, bool tcp, time_t now)
+void DNSCryptQuery::parsePacket(PacketBuffer& packet, bool tcp, time_t now)
 {
   d_valid = false;
 
@@ -635,7 +635,7 @@ uint16_t DNSCryptQuery::computePaddingSize(uint16_t unpaddedLen, size_t maxLen)
   return result;
 }
 
-int DNSCryptQuery::encryptResponse(std::vector<uint8_t>& response, size_t maxResponseSize, bool tcp)
+int DNSCryptQuery::encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp)
 {
   struct DNSCryptResponseHeader responseHeader;
   assert(response.size() > 0);
@@ -746,7 +746,7 @@ int DNSCryptQuery::encryptResponse(std::vector<uint8_t>& response, size_t maxRes
   return res;
 }
 
-int DNSCryptContext::encryptQuery(std::vector<uint8_t>& packet, size_t maximumSize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, const std::shared_ptr<DNSCryptCert>& cert) const
+int DNSCryptContext::encryptQuery(PacketBuffer& packet, size_t maximumSize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, const std::shared_ptr<DNSCryptCert>& cert) const
 {
   assert(packet.size() > 0);
   assert(cert != nullptr);
index 018e90025ad304bb5d4e39b38bf4c1e89c2d718d..a9a579e9c40d8a428b7cfec22981ef5af08fc089 100644 (file)
@@ -52,6 +52,7 @@ private:
 
 #include "dnsname.hh"
 #include "lock.hh"
+#include "noinitvector.hh"
 
 #define DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE (crypto_sign_ed25519_PUBLICKEYBYTES)
 #define DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE (crypto_sign_ed25519_SECRETKEYBYTES)
@@ -207,10 +208,10 @@ public:
     d_pair = pair;
   }
 
-  void parsePacket(std::vector<uint8_t>& packet, bool tcp, time_t now);
-  void getDecrypted(bool tcp, std::vector<uint8_t>& packet);
-  void getCertificateResponse(time_t now, std::vector<uint8_t>& response) const;
-  int encryptResponse(std::vector<uint8_t>& response, size_t maxResponseSize, bool tcp);
+  void parsePacket(PacketBuffer& packet, bool tcp, time_t now);
+  void getDecrypted(bool tcp, PacketBuffer& packet);
+  void getCertificateResponse(time_t now, PacketBuffer& response) const;
+  int encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp);
 
   static const size_t s_minUDPLength = 256;
 
@@ -221,8 +222,8 @@ private:
 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
   void fillServerNonce(unsigned char* dest) const;
   uint16_t computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const;
-  bool parsePlaintextQuery(const std::vector<uint8_t>& packet);
-  bool isEncryptedQuery(const std::vector<uint8_t>& packet, bool tcp, time_t now);
+  bool parsePlaintextQuery(const PacketBuffer& packet);
+  bool isEncryptedQuery(const PacketBuffer& packet, bool tcp, time_t now);
 
   DNSCryptQueryHeader d_header;
 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
@@ -275,9 +276,9 @@ public:
   std::vector<std::shared_ptr<DNSCryptCertificatePair>> getCertificates() { return d_certs; };
   const DNSName& getProviderName() const { return providerName; }
 
-  int encryptQuery(std::vector<uint8_t>& query, size_t maximumSize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, const std::shared_ptr<DNSCryptCert>& cert) const;
+  int encryptQuery(PacketBuffer& query, size_t maximumSize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, const std::shared_ptr<DNSCryptCert>& cert) const;
   bool magicMatchesAPublicKey(DNSCryptQuery& query, time_t now);
-  void getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, std::vector<uint8_t>& response);
+  void getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, PacketBuffer& response);
 
 private:
   static void computePublicKeyFromPrivate(const DNSCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE]);
index f893a0621a75a650095cf010394c1ce50673e4d4..860322c17ae5bc6c1ab752d6873df0b9f3d9381f 100644 (file)
@@ -53,7 +53,7 @@ DNSDistPacketCache::~DNSDistPacketCache()
   }
 }
 
-bool DNSDistPacketCache::getClientSubnet(const std::vector<uint8_t>& packet, size_t qnameWireLength, boost::optional<Netmask>& subnet)
+bool DNSDistPacketCache::getClientSubnet(const PacketBuffer& packet, size_t qnameWireLength, boost::optional<Netmask>& subnet)
 {
   uint16_t optRDPosition;
   size_t remaining = 0;
@@ -127,7 +127,7 @@ void DNSDistPacketCache::insertLocked(CacheShard& shard, uint32_t key, CacheValu
   value = newValue;
 }
 
-void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::vector<uint8_t>& response, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL)
+void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const PacketBuffer& response, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL)
 {
   if (response.size() < sizeof(dnsheader)) {
     return;
@@ -414,7 +414,7 @@ uint32_t DNSDistPacketCache::getMinTTL(const char* packet, uint16_t length, bool
   return getDNSPacketMinTTL(packet, length, seenNoDataSOA);
 }
 
-uint32_t DNSDistPacketCache::getKey(const DNSName::string_t& qname, size_t qnameWireLength, const std::vector<uint8_t>& packet, bool tcp)
+uint32_t DNSDistPacketCache::getKey(const DNSName::string_t& qname, size_t qnameWireLength, const PacketBuffer& packet, bool tcp)
 {
   uint32_t result = 0;
   /* skip the query ID */
index c899a93df5425d865e53abfe12d59e3fe61366e7..3b4b14038abb4f69f5cd5fa8a439b68efe147b35 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "iputils.hh"
 #include "lock.hh"
+#include "noinitvector.hh"
 
 struct DNSQuestion;
 
@@ -35,7 +36,7 @@ public:
   DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t tempFailureTTL=60, uint32_t maxNegativeTTL=3600, uint32_t staleTTL=60, bool dontAge=false, uint32_t shards=1, bool deferrableInsertLock=true, bool parseECS=false);
   ~DNSDistPacketCache();
 
-  void insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::vector<uint8_t>& response, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL);
+  void insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const PacketBuffer& response, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL);
   bool get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, uint32_t allowExpired = 0, bool skipAging = false);
   size_t purgeExpired(size_t upTo=0);
   size_t expunge(size_t upTo=0);
@@ -76,10 +77,10 @@ public:
     d_parseECS = enabled;
   }
 
-  uint32_t getKey(const DNSName::string_t& qname, size_t qnameWireLength, const std::vector<uint8_t>& packet, bool tcp);
+  uint32_t getKey(const DNSName::string_t& qname, size_t qnameWireLength, const PacketBuffer& packet, bool tcp);
 
   static uint32_t getMinTTL(const char* packet, uint16_t length, bool* seenNoDataSOA);
-  static bool getClientSubnet(const std::vector<uint8_t>& packet, size_t qnameWireLength, boost::optional<Netmask>& subnet);
+  static bool getClientSubnet(const PacketBuffer& packet, size_t qnameWireLength, boost::optional<Netmask>& subnet);
 
 private:
 
index ac254fe9e5b03ad0b8c1ddf668217d68fac95e8a..fe18169db98b075ba502c00b21061af75bfb12c4 100644 (file)
@@ -24,7 +24,7 @@
 #include "dnscrypt.hh"
 
 #ifdef HAVE_DNSCRYPT
-int handleDNSCryptQuery(std::vector<uint8_t>& packet, std::shared_ptr<DNSCryptQuery>& query, bool tcp, time_t now, std::vector<uint8_t>& response)
+int handleDNSCryptQuery(PacketBuffer& packet, std::shared_ptr<DNSCryptQuery>& query, bool tcp, time_t now, PacketBuffer& response)
 {
   query->parsePacket(packet, tcp, now);
 
index a45ecd86be2aa94062189e211690f23106a8245e..fc664da941900ac54edd6122a8256141c33ac08f 100644 (file)
@@ -41,7 +41,7 @@ uint16_t g_ECSSourcePrefixV6 = 56;
 bool g_ECSOverride{false};
 bool g_addEDNSToSelfGeneratedResponses{true};
 
-int rewriteResponseWithoutEDNS(const std::vector<uint8_t>& initialPacket, vector<uint8_t>& newContent)
+int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent)
 {
   assert(initialPacket.size() >= sizeof(dnsheader));
   const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
@@ -52,7 +52,7 @@ int rewriteResponseWithoutEDNS(const std::vector<uint8_t>& initialPacket, vector
   if (ntohs(dh->qdcount) == 0)
     return ENOENT;
 
-  GenericPacketReader<std::vector<uint8_t>> pr(initialPacket);
+  PacketReader pr(pdns_string_view(reinterpret_cast<const char*>(initialPacket.data()), initialPacket.size()));
 
   size_t idx = 0;
   DNSName rrname;
@@ -69,7 +69,7 @@ int rewriteResponseWithoutEDNS(const std::vector<uint8_t>& initialPacket, vector
   rrtype = pr.get16BitInt();
   rrclass = pr.get16BitInt();
 
-  DNSPacketWriter pw(newContent, rrname, rrtype, rrclass, dh->opcode);
+  GenericDNSPacketWriter<PacketBuffer> pw(newContent, rrname, rrtype, rrclass, dh->opcode);
   pw.getHeader()->id=dh->id;
   pw.getHeader()->qr=dh->qr;
   pw.getHeader()->aa=dh->aa;
@@ -149,7 +149,7 @@ static bool addOrReplaceECSOption(std::vector<std::pair<uint16_t, std::string>>&
   return true;
 }
 
-static bool slowRewriteQueryWithExistingEDNS(const std::vector<uint8_t>& initialPacket, vector<uint8_t>& newContent, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption)
+static bool slowRewriteQueryWithExistingEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption)
 {
   assert(initialPacket.size() >= sizeof(dnsheader));
   const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
@@ -165,7 +165,7 @@ static bool slowRewriteQueryWithExistingEDNS(const std::vector<uint8_t>& initial
     throw std::runtime_error("slowRewriteQueryWithExistingEDNS() should not be called for queries that have no EDNS");
   }
 
-  GenericPacketReader<std::vector<uint8_t>> pr(initialPacket);
+  PacketReader pr(pdns_string_view(reinterpret_cast<const char*>(initialPacket.data()), initialPacket.size()));
 
   size_t idx = 0;
   DNSName rrname;
@@ -182,7 +182,7 @@ static bool slowRewriteQueryWithExistingEDNS(const std::vector<uint8_t>& initial
   rrtype = pr.get16BitInt();
   rrclass = pr.get16BitInt();
 
-  DNSPacketWriter pw(newContent, rrname, rrtype, rrclass, dh->opcode);
+  GenericDNSPacketWriter<PacketBuffer> pw(newContent, rrname, rrtype, rrclass, dh->opcode);
   pw.getHeader()->id=dh->id;
   pw.getHeader()->qr=dh->qr;
   pw.getHeader()->aa=dh->aa;
@@ -261,7 +261,7 @@ static bool slowRewriteQueryWithExistingEDNS(const std::vector<uint8_t>& initial
   return true;
 }
 
-static bool slowParseEDNSOptions(const std::vector<uint8_t>& packet, std::shared_ptr<std::map<uint16_t, EDNSOptionView> >& options)
+static bool slowParseEDNSOptions(const PacketBuffer& packet, std::shared_ptr<std::map<uint16_t, EDNSOptionView> >& options)
 {
   if (packet.size() < sizeof(dnsheader)) {
     return false;
@@ -317,7 +317,7 @@ static bool slowParseEDNSOptions(const std::vector<uint8_t>& packet, std::shared
   return true;
 }
 
-int locateEDNSOptRR(const std::vector<uint8_t>& packet, uint16_t * optStart, size_t * optLen, bool * last)
+int locateEDNSOptRR(const PacketBuffer& packet, uint16_t * optStart, size_t * optLen, bool * last)
 {
   assert(optStart != NULL);
   assert(optLen != NULL);
@@ -327,7 +327,7 @@ int locateEDNSOptRR(const std::vector<uint8_t>& packet, uint16_t * optStart, siz
   if (ntohs(dh->arcount) == 0)
     return ENOENT;
 
-  GenericPacketReader<std::vector<uint8_t>> pr(packet);
+  PacketReader pr(pdns_string_view(reinterpret_cast<const char*>(packet.data()), packet.size()));
 
   size_t idx = 0;
   DNSName rrname;
@@ -384,7 +384,7 @@ int locateEDNSOptRR(const std::vector<uint8_t>& packet, uint16_t * optStart, siz
 }
 
 /* extract the start of the OPT RR in a QUERY packet if any */
-int getEDNSOptionsStart(const std::vector<uint8_t>& packet, const size_t offset, uint16_t* optRDPosition, size_t* remaining)
+int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_t* optRDPosition, size_t* remaining)
 {
   assert(optRDPosition != nullptr);
   assert(remaining != nullptr);
@@ -437,7 +437,7 @@ void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPref
   generateEDNSOption(EDNSOptionCode::ECS, payload, res);
 }
 
-bool generateOptRR(const std::string& optRData, std::vector<uint8_t>& res, size_t maximumSize, uint16_t udpPayloadSize, uint8_t ednsrcode, bool dnssecOK)
+bool generateOptRR(const std::string& optRData, PacketBuffer& res, size_t maximumSize, uint16_t udpPayloadSize, uint8_t ednsrcode, bool dnssecOK)
 {
   const uint8_t name = 0;
   dnsrecordheader dh;
@@ -464,7 +464,7 @@ bool generateOptRR(const std::string& optRData, std::vector<uint8_t>& res, size_
   return true;
 }
 
-static bool replaceEDNSClientSubnetOption(std::vector<uint8_t>& packet, size_t maximumSize, size_t const oldEcsOptionStartPosition, size_t const oldEcsOptionSize, size_t const optRDLenPosition, const string& newECSOption)
+static bool replaceEDNSClientSubnetOption(PacketBuffer& packet, size_t maximumSize, size_t const oldEcsOptionStartPosition, size_t const oldEcsOptionSize, size_t const optRDLenPosition, const string& newECSOption)
 {
   assert(oldEcsOptionStartPosition < packet.size());
   assert(optRDLenPosition < packet.size());
@@ -536,7 +536,7 @@ bool parseEDNSOptions(const DNSQuestion& dq)
   return false;
 }
 
-static bool addECSToExistingOPT(std::vector<uint8_t>& packet, size_t maximumSize, const string& newECSOption, size_t optRDLenPosition, bool& ecsAdded)
+static bool addECSToExistingOPT(PacketBuffer& packet, size_t maximumSize, const string& newECSOption, size_t optRDLenPosition, bool& ecsAdded)
 {
   /* we need to add one EDNS0 ECS option, fixing the size of EDNS0 RDLENGTH */
   /* getEDNSOptionsStart has already checked that there is exactly one AR,
@@ -562,7 +562,7 @@ static bool addECSToExistingOPT(std::vector<uint8_t>& packet, size_t maximumSize
   return true;
 }
 
-static bool addEDNSWithECS(std::vector<uint8_t>& packet, size_t maximumSize, const string& newECSOption, bool& ednsAdded, bool& ecsAdded)
+static bool addEDNSWithECS(PacketBuffer& packet, size_t maximumSize, const string& newECSOption, bool& ednsAdded, bool& ecsAdded)
 {
   if (!generateOptRR(newECSOption, packet, maximumSize, g_EdnsUDPPayloadSize, 0, false)) {
     return false;
@@ -578,14 +578,14 @@ static bool addEDNSWithECS(std::vector<uint8_t>& packet, size_t maximumSize, con
   return true;
 }
 
-bool handleEDNSClientSubnet(std::vector<uint8_t>& packet, const size_t maximumSize, const size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption)
+bool handleEDNSClientSubnet(PacketBuffer& packet, const size_t maximumSize, const size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption)
 {
   assert(qnameWireLength <= packet.size());
 
   const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
 
   if (ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || (ntohs(dh->arcount) != 0 && ntohs(dh->arcount) != 1)) {
-    vector<uint8_t> newContent;
+    PacketBuffer newContent;
     newContent.reserve(packet.size());
 
     if (!slowRewriteQueryWithExistingEDNS(packet, newContent, ednsAdded, ecsAdded, overrideExisting, newECSOption)) {
@@ -709,7 +709,7 @@ int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optio
   return 0;
 }
 
-bool isEDNSOptionInOpt(const std::vector<uint8_t>& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart, uint16_t* optContentLen)
+bool isEDNSOptionInOpt(const PacketBuffer& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart, uint16_t* optContentLen)
 {
   if (optLen < optRecordMinimumSize) {
     return false;
@@ -748,7 +748,7 @@ bool isEDNSOptionInOpt(const std::vector<uint8_t>& packet, const size_t optStart
   return false;
 }
 
-int rewriteResponseWithoutEDNSOption(const std::vector<uint8_t>& initialPacket, const uint16_t optionCodeToSkip, vector<uint8_t>& newContent)
+int rewriteResponseWithoutEDNSOption(const PacketBuffer& initialPacket, const uint16_t optionCodeToSkip, PacketBuffer& newContent)
 {
   assert(initialPacket.size() >= sizeof(dnsheader));
   const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
@@ -759,7 +759,7 @@ int rewriteResponseWithoutEDNSOption(const std::vector<uint8_t>& initialPacket,
   if (ntohs(dh->qdcount) == 0)
     return ENOENT;
 
-  GenericPacketReader<std::vector<uint8_t>> pr(initialPacket);
+  PacketReader pr(pdns_string_view(reinterpret_cast<const char*>(initialPacket.data()), initialPacket.size()));
 
   size_t idx = 0;
   DNSName rrname;
@@ -776,7 +776,7 @@ int rewriteResponseWithoutEDNSOption(const std::vector<uint8_t>& initialPacket,
   rrtype = pr.get16BitInt();
   rrclass = pr.get16BitInt();
 
-  DNSPacketWriter pw(newContent, rrname, rrtype, rrclass, dh->opcode);
+  GenericDNSPacketWriter<PacketBuffer> pw(newContent, rrname, rrtype, rrclass, dh->opcode);
   pw.getHeader()->id=dh->id;
   pw.getHeader()->qr=dh->qr;
   pw.getHeader()->aa=dh->aa;
@@ -845,7 +845,7 @@ int rewriteResponseWithoutEDNSOption(const std::vector<uint8_t>& initialPacket,
   return 0;
 }
 
-bool addEDNS(std::vector<uint8_t>& packet, size_t maximumSize, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode)
+bool addEDNS(PacketBuffer& packet, size_t maximumSize, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode)
 {
   if (!generateOptRR(std::string(), packet, maximumSize, payloadSize, ednsrcode, dnssecOK)) {
     return false;
index 60492576958c2fc30d9fc8035d59934df55802ed..26f758b6dbbd1ed4ef57275327e994a6c2c3a107 100644 (file)
@@ -27,20 +27,20 @@ static const size_t optRecordMinimumSize = 11;
 extern size_t g_EdnsUDPPayloadSize;
 extern uint16_t g_PayloadSizeSelfGenAnswers;
 
-int rewriteResponseWithoutEDNS(const std::vector<uint8_t>& initialPacket, vector<uint8_t>& newContent);
-int locateEDNSOptRR(const std::vector<uint8_t> & packet, uint16_t * optStart, size_t * optLen, bool * last);
-bool generateOptRR(const std::string& optRData, std::vector<uint8_t>& res, size_t maximumSize, uint16_t udpPayloadSize, uint8_t ednsrcode, bool dnssecOK);
+int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent);
+int locateEDNSOptRR(const PacketBuffer & packet, uint16_t * optStart, size_t * optLen, bool * last);
+bool generateOptRR(const std::string& optRData, PacketBuffer& res, size_t maximumSize, uint16_t udpPayloadSize, uint8_t ednsrcode, bool dnssecOK);
 void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength);
 int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove);
-int rewriteResponseWithoutEDNSOption(const std::vector<uint8_t>& initialPacket, const uint16_t optionCodeToSkip, vector<uint8_t>& newContent);
-int getEDNSOptionsStart(const std::vector<uint8_t>& packet, const size_t offset, uint16_t* optRDPosition, size_t * remaining);
-bool isEDNSOptionInOpt(const std::vector<uint8_t>& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr);
-bool addEDNS(std::vector<uint8_t>& packet, size_t maximumSize, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode);
+int rewriteResponseWithoutEDNSOption(const PacketBuffer& initialPacket, const uint16_t optionCodeToSkip, PacketBuffer& newContent);
+int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_t* optRDPosition, size_t * remaining);
+bool isEDNSOptionInOpt(const PacketBuffer& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr);
+bool addEDNS(PacketBuffer& packet, size_t maximumSize, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode);
 bool addEDNSToQueryTurnedResponse(DNSQuestion& dq);
 bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum);
 
 bool handleEDNSClientSubnet(DNSQuestion& dq, bool& ednsAdded, bool& ecsAdded);
-bool handleEDNSClientSubnet(std::vector<uint8_t>& packet, size_t maximumSize, size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption);
+bool handleEDNSClientSubnet(PacketBuffer& packet, size_t maximumSize, size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption);
 
 bool parseEDNSOptions(const DNSQuestion& dq);
 
index 0a3d7abaa9bbfa5f8253e429a3a90bc7c95076fa..4a234bf1aa597e1a55334a2107d1da2968b3a7f0 100644 (file)
@@ -174,7 +174,7 @@ DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult
     d_queries++;
 
     if(d_addECS) {
-      std::vector<uint8_t> query(dq->getData());
+      PacketBuffer query(dq->getData());
       bool ednsAdded = false;
       bool ecsAdded = false;
 
@@ -1309,7 +1309,7 @@ private:
 class HTTPStatusAction: public DNSAction
 {
 public:
-  HTTPStatusAction(int code, const std::vector<uint8_t>& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
+  HTTPStatusAction(int code, const PacketBuffer& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
   {
   }
 
@@ -1319,7 +1319,7 @@ public:
       return Action::None;
     }
 
-    dq->du->setHTTPResponse(d_code, std::vector<uint8_t>(d_body), d_contentType);
+    dq->du->setHTTPResponse(d_code, PacketBuffer(d_body), d_contentType);
     dq->getHeader()->qr = true; // for good measure
     setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
     return Action::HeaderModify;
@@ -1332,7 +1332,7 @@ public:
 
   ResponseConfig d_responseConfig;
 private:
-  std::vector<uint8_t> d_body;
+  PacketBuffer d_body;
   std::string d_contentType;
   int d_code;
 };
@@ -1811,7 +1811,7 @@ void setupLuaActions(LuaContext& luaCtx)
 
 #ifdef HAVE_DNS_OVER_HTTPS
   luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
-      auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, std::vector<uint8_t>(body.begin(), body.end()), contentType ? *contentType : ""));
+      auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : ""));
       auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
       parseResponseConfig(vars, hsa->d_responseConfig);
       return ret;
index 553b1f521762891b9af1435e4b73249a5f28afd5..34f52accb81e2a2ee9d41eefd9eaebbbcfd0e0f9 100644 (file)
@@ -236,7 +236,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
       if (dq.du == nullptr) {
         return;
       }
-      std::vector<uint8_t> vect(body.begin(), body.end());
+      PacketBuffer vect(body.begin(), body.end());
       dq.du->setHTTPResponse(statusCode, std::move(vect), contentType ? *contentType : "");
     });
 #endif /* HAVE_DNS_OVER_HTTPS */
index d7a8b6abfe61c65c60bef1ef4bca8e50d574eeed..8be20c596503ed0cc1b73e83b09d57a04c8078f8 100644 (file)
@@ -490,6 +490,6 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
         headers->push_back({ boost::to_lower_copy(header.first), header.second });
       }
     }
-    return std::make_shared<DOHResponseMapEntry>(regex, status, std::vector<uint8_t>(content.begin(), content.end()), headers);
+    return std::make_shared<DOHResponseMapEntry>(regex, status, PacketBuffer(content.begin(), content.end()), headers);
   });
 }
index 0ad71bd8e556bc9d036397e391b8279416cde1fb..68dee6bf96f6ebc836f8308f049412c3c223d41a 100644 (file)
@@ -419,7 +419,7 @@ void setupLuaRules(LuaContext& luaCtx)
       int times = times_.get_value_or(100000);
       DNSName suffix(suffix_.get_value_or("powerdns.com"));
       struct item {
-        vector<uint8_t> packet;
+        PacketBuffer packet;
         ComboAddress rem;
         DNSName qname;
         uint16_t qtype, qclass;
@@ -434,7 +434,7 @@ void setupLuaRules(LuaContext& luaCtx)
         i.qclass = 1;
         i.rem=ComboAddress("127.0.0.1");
         i.rem.sin4.sin_addr.s_addr = random();
-        DNSPacketWriter pw(i.packet, i.qname, i.qtype);
+        GenericDNSPacketWriter<PacketBuffer> pw(i.packet, i.qname, i.qtype);
         items.push_back(i);
       }
 
index a64483c8d2f1daaf745b511721f8c8e657dc4da9..09585afc22bc7b629093b96912e4e8688dd523cc 100644 (file)
@@ -147,7 +147,7 @@ std::set<std::string> g_capabilitiesToRetain;
 static size_t const s_initialUDPPacketBufferSize = s_maxPacketCacheEntrySize + DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE;
 static_assert(s_initialUDPPacketBufferSize <= UINT16_MAX, "Packet size should fit in a uint16_t");
 
-static void truncateTC(std::vector<uint8_t>& packet, size_t maximumSize, unsigned int qnameWireLength)
+static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qnameWireLength)
 {
   try
   {
@@ -176,7 +176,7 @@ static void truncateTC(std::vector<uint8_t>& packet, size_t maximumSize, unsigne
 struct DelayedPacket
 {
   int fd;
-  std::vector<uint8_t> packet;
+  PacketBuffer packet;
   ComboAddress destination;
   ComboAddress origDest;
   void operator()()
@@ -235,7 +235,7 @@ void doLatencyStats(double udiff)
   doAvg(g_stats.latencyAvg1000000, udiff, 1000000);
 }
 
-bool responseContentMatches(const std::vector<uint8_t>& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength)
 {
   if (response.size() < sizeof(dnsheader)) {
     return false;
@@ -298,7 +298,7 @@ static bool fixUpQueryTurnedResponse(DNSQuestion& dq, const uint16_t origFlags)
   return addEDNSToQueryTurnedResponse(dq);
 }
 
-static bool fixUpResponse(std::vector<uint8_t>& response, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, bool* zeroScope)
+static bool fixUpResponse(PacketBuffer& response, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, bool* zeroScope)
 {
   if (response.size() < sizeof(dnsheader)) {
     return false;
@@ -350,7 +350,7 @@ static bool fixUpResponse(std::vector<uint8_t>& response, const DNSName& qname,
         }
         else {
           /* Removing an intermediary RR could lead to compression error */
-          std::vector<uint8_t> rewrittenResponse;
+          PacketBuffer rewrittenResponse;
           if (rewriteResponseWithoutEDNS(response, rewrittenResponse) == 0) {
             response = std::move(rewrittenResponse);
           }
@@ -370,7 +370,7 @@ static bool fixUpResponse(std::vector<uint8_t>& response, const DNSName& qname,
           response.resize(response.size() - (existingOptLen - optLen));
         }
         else {
-          std::vector<uint8_t> rewrittenResponse;
+          PacketBuffer rewrittenResponse;
           /* Removing an intermediary RR could lead to compression error */
           if (rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, rewrittenResponse) == 0) {
             response = std::move(rewrittenResponse);
@@ -387,7 +387,7 @@ static bool fixUpResponse(std::vector<uint8_t>& response, const DNSName& qname,
 }
 
 #ifdef HAVE_DNSCRYPT
-static bool encryptResponse(std::vector<uint8_t>& response, size_t maximumSize, bool tcp, std::shared_ptr<DNSCryptQuery> dnsCryptQuery)
+static bool encryptResponse(PacketBuffer& response, size_t maximumSize, bool tcp, std::shared_ptr<DNSCryptQuery> dnsCryptQuery)
 {
   if (dnsCryptQuery) {
     int res = dnsCryptQuery->encryptResponse(response, maximumSize, tcp);
@@ -436,7 +436,7 @@ static bool applyRulesToResponse(LocalStateHolder<vector<DNSDistResponseRuleActi
   return true;
 }
 
-bool processResponse(std::vector<uint8_t>& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, bool muted)
+bool processResponse(PacketBuffer& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, bool muted)
 {
   if (!applyRulesToResponse(localRespRulactions, dr)) {
     return false;
@@ -474,7 +474,7 @@ bool processResponse(std::vector<uint8_t>& response, LocalStateHolder<vector<DNS
   return true;
 }
 
-static bool sendUDPResponse(int origFD, const std::vector<uint8_t>& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
+static bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
 {
   if(delayMsec && g_delay) {
     DelayedPacket dp{origFD, response, origRemote, origDest};
@@ -524,7 +524,7 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
   try {
   setThreadName("dnsdist/respond");
   auto localRespRulactions = g_resprulactions.getLocal();
-  std::vector<uint8_t> response(s_initialUDPPacketBufferSize);
+  PacketBuffer response(s_initialUDPPacketBufferSize);
 
   /* when the answer is encrypted in place, we need to get a copy
      of the original header before encryption to fill the ring buffer */
@@ -976,7 +976,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
   return true;
 }
 
-ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const std::vector<uint8_t>& request, bool healthCheck)
+ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const PacketBuffer& request, bool healthCheck)
 {
   ssize_t result;
 
@@ -1039,11 +1039,11 @@ static bool isUDPQueryAcceptable(ClientState& cs, LocalHolders& holders, const s
   return true;
 }
 
-bool checkDNSCryptQuery(const ClientState& cs, std::vector<uint8_t>& query, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
+bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
 {
   if (cs.dnscryptCtx) {
 #ifdef HAVE_DNSCRYPT
-    vector<uint8_t> response;
+    PacketBuffer response;
     dnsCryptQuery = std::make_shared<DNSCryptQuery>(cs.dnscryptCtx);
 
     bool decrypted = handleDNSCryptQuery(query, dnsCryptQuery, tcp, now, response);
@@ -1080,7 +1080,7 @@ bool checkQueryHeaders(const struct dnsheader* dh)
 }
 
 #if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-static void queueResponse(const ClientState& cs, const std::vector<uint8_t>& response, const ComboAddress& dest, const ComboAddress& remote, struct mmsghdr& outMsg, struct iovec* iov, cmsgbuf_aligned* cbuf)
+static void queueResponse(const ClientState& cs, const PacketBuffer& response, const ComboAddress& dest, const ComboAddress& remote, struct mmsghdr& outMsg, struct iovec* iov, cmsgbuf_aligned* cbuf)
 {
   outMsg.msg_len = 0;
   fillMSGHdr(&outMsg.msg_hdr, iov, nullptr, 0, const_cast<char*>(reinterpret_cast<const char *>(&response.at(0))), response.size(), const_cast<ComboAddress*>(&remote));
@@ -1249,7 +1249,7 @@ ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders&
   return ProcessQueryResult::Drop;
 }
 
-static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, std::vector<uint8_t>& query, struct mmsghdr* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
+static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, PacketBuffer& query, struct mmsghdr* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
 {
   assert(responsesVect == nullptr || (queuedResponses != nullptr && respIOV != nullptr && respCBuf != nullptr));
   uint16_t queryId = 0;
@@ -1385,7 +1385,7 @@ static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holde
 {
   struct MMReceiver
   {
-    std::vector<uint8_t> packet;
+    PacketBuffer packet;
     ComboAddress remote;
     ComboAddress dest;
     struct iovec iov;
@@ -1478,7 +1478,7 @@ try
   else
 #endif /* defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE) */
   {
-    std::vector<uint8_t> packet(s_initialUDPPacketBufferSize);
+    PacketBuffer packet(s_initialUDPPacketBufferSize);
     /* the actual buffer is larger because:
        - we may have to add EDNS and/or ECS
        - we use it for self-generated responses (from rule or cache)
index 7ab0be192b1da6c6c2c57b6dc0675dd15ee53d4d..bd9387dc131d8b937144a89f02c624006fec5901 100644 (file)
@@ -46,6 +46,7 @@
 #include "iputils.hh"
 #include "misc.hh"
 #include "mplexer.hh"
+#include "noinitvector.hh"
 #include "sholder.hh"
 #include "tcpiohandler.hh"
 #include "uuid-utils.hh"
@@ -58,11 +59,11 @@ extern uint16_t g_ECSSourcePrefixV4;
 extern uint16_t g_ECSSourcePrefixV6;
 extern bool g_ECSOverride;
 
-typedef std::unordered_map<string, string> QTag;
+using QTag = std::unordered_map<string, string>;
 
 struct DNSQuestion
 {
-  DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, std::vector<uint8_t>& data_, bool isTcp, const struct timespec* queryTime_):
+  DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, PacketBuffer& data_, bool isTcp, const struct timespec* queryTime_):
     data(data_), qname(name), local(lc), remote(rem), queryTime(queryTime_), tempFailureTTL(boost::none), qtype(type), qclass(class_), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tcp(isTcp), ecsOverride(g_ECSOverride) {
     const uint16_t* flags = getFlagsFromDNSHeader(getHeader());
     origFlags = *flags;
@@ -73,11 +74,11 @@ struct DNSQuestion
 
   std::string getTrailingData() const;
   bool setTrailingData(const std::string&);
-  const std::vector<uint8_t>& getData() const
+  const PacketBuffer& getData() const
   {
     return data;
   }
-  std::vector<uint8_t>& getMutableData()
+  PacketBuffer& getMutableData()
   {
     return data;
   }
@@ -112,7 +113,7 @@ struct DNSQuestion
   }
 
 protected:
-    std::vector<uint8_t>& data;
+    PacketBuffer& data;
 
 public:
   boost::optional<boost::uuids::uuid> uniqueId;
@@ -153,7 +154,7 @@ public:
 
 struct DNSResponse : DNSQuestion
 {
-  DNSResponse(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, std::vector<uint8_t>& data_, bool isTcp, const struct timespec* queryTime_):
+  DNSResponse(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, PacketBuffer& data_, bool isTcp, const struct timespec* queryTime_):
     DNSQuestion(name, type, class_, lc, rem, data_, isTcp, queryTime_) { }
   DNSResponse(const DNSResponse&) = delete;
   DNSResponse& operator=(const DNSResponse&) = delete;
@@ -1211,15 +1212,15 @@ void setLuaSideEffect();   // set to report a side effect, cancelling all _no_ s
 bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
 void resetLuaSideEffect(); // reset to indeterminate state
 
-bool responseContentMatches(const std::vector<uint8_t>& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength);
-bool processResponse(std::vector<uint8_t>& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, bool muted);
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength);
+bool processResponse(PacketBuffer& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, bool muted);
 bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::string& ruleresult, bool& drop);
 
 bool checkQueryHeaders(const struct dnsheader* dh);
 
 extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
-int handleDNSCryptQuery(std::vector<uint8_t>& packet, std::shared_ptr<DNSCryptQuery>& query, bool tcp, time_t now, std::vector<uint8_t>& response);
-bool checkDNSCryptQuery(const ClientState& cs, std::vector<uint8_t>& query, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
+int handleDNSCryptQuery(PacketBuffer& packet, std::shared_ptr<DNSCryptQuery>& query, bool tcp, time_t now, PacketBuffer& response);
+bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
 
 uint16_t getRandomDNSID();
 
@@ -1237,8 +1238,8 @@ static const size_t s_maxPacketCacheEntrySize{4096}; // don't cache responses la
 enum class ProcessQueryResult { Drop, SendAnswer, PassToBackend };
 ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
 
-DNSResponse makeDNSResponseFromIDState(IDState& ids, std::vector<uint8_t>& data, bool isTCP);
+DNSResponse makeDNSResponseFromIDState(IDState& ids, PacketBuffer& data, bool isTCP);
 void setIDStateFromDNSQuestion(IDState& ids, DNSQuestion& dq, DNSName&& qname);
 
 int pickBackendSocketForSending(std::shared_ptr<DownstreamState>& state);
-ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const std::vector<uint8_t>& request, bool healthCheck = false);
+ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const PacketBuffer& request, bool healthCheck = false);
index d912fb859f3a5dcf6205b32d712782c2a4f5a8b2..812d8e1e011d1f290551e76b13294044649b0d68 100644 (file)
@@ -191,6 +191,7 @@ dnsdist_SOURCES = \
        misc.cc misc.hh \
        mplexer.hh \
        namespaces.hh \
+       noinitvector.hh \
        packetcache.hh \
        pdnsexception.hh \
        pollmplexer.cc \
@@ -247,6 +248,7 @@ testrunner_SOURCES = \
        iputils.cc iputils.hh \
        misc.cc misc.hh \
        namespaces.hh \
+       noinitvector.hh \
        pdnsexception.hh \
        pollmplexer.cc \
        proxy-protocol.cc proxy-protocol.hh \
index e66a45ea26e45bebc0269695ff91ab22665cf1fc..395a500a1d0e10fac0a114c8650a5f39f4e97de6 100644 (file)
@@ -202,8 +202,8 @@ bool queueHealthCheck(std::shared_ptr<FDMultiplexer>& mplexer, const std::shared
       checkClass = std::get<2>(ret);
     }
 
-    vector<uint8_t> packet;
-    DNSPacketWriter dpw(packet, checkName, checkType, checkClass);
+    PacketBuffer packet;
+    GenericDNSPacketWriter<PacketBuffer> dpw(packet, checkName, checkType, checkClass);
     dnsheader * requestHeader = dpw.getHeader();
     *requestHeader = checkHeader;
 
index 9db149ada414d32726a2799d68a4d730903980ea..ef91d77d96dc31d651fc8eb1387c4fda922667c1 100644 (file)
@@ -1,7 +1,7 @@
 
 #include "dnsdist.hh"
 
-DNSResponse makeDNSResponseFromIDState(IDState& ids, std::vector<uint8_t>& data, bool isTCP)
+DNSResponse makeDNSResponseFromIDState(IDState& ids, PacketBuffer& data, bool isTCP)
 {
   DNSResponse dr(&ids.qname, ids.qtype, ids.qclass, &ids.origDest, &ids.origRemote, data, isTCP, &ids.sentTime.d_start);
   dr.origFlags = ids.origFlags;
index 4a96a208d8d012ffb93777763670c4210e790d70..602aafa466fd655937546cdac6e80e375c0e8a30 100644 (file)
@@ -356,7 +356,7 @@ void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, ui
   }
 
 #ifdef HAVE_DNS_OVER_HTTPS
-  std::vector<uint8_t> bodyVect(body, body + bodyLen);
+  PacketBuffer bodyVect(body, body + bodyLen);
   dq->dq->du->setHTTPResponse(statusCode, std::move(bodyVect), contentType);
   dq->dq->getHeader()->qr = true;
 #endif
index eb10ca73736f65b9422d26b74a3dfde743962a78..0a3d330e90a088b43d3aee4a09c6189be96af334 100644 (file)
@@ -42,7 +42,7 @@ bool addProxyProtocol(DNSQuestion& dq)
   return addProxyProtocol(dq, payload);
 }
 
-bool addProxyProtocol(std::vector<uint8_t>& buffer, const std::string& payload)
+bool addProxyProtocol(PacketBuffer& buffer, const std::string& payload)
 {
   auto previousSize = buffer.size();
   if (payload.size() > (std::numeric_limits<size_t>::max() - previousSize)) {
@@ -54,7 +54,7 @@ bool addProxyProtocol(std::vector<uint8_t>& buffer, const std::string& payload)
   return true;
 }
 
-bool addProxyProtocol(std::vector<uint8_t>& buffer, bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values)
+bool addProxyProtocol(PacketBuffer& buffer, bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values)
 {
   auto payload = makeProxyHeader(tcp, source, destination, values);
   return addProxyProtocol(buffer, payload);
index a218a403d411a12261351e193a281a4ea95a5694..9ca60eb361f5619179c1ea1ab9e3de2adf7ac789 100644 (file)
@@ -27,5 +27,5 @@ std::string getProxyProtocolPayload(const DNSQuestion& dq);
 
 bool addProxyProtocol(DNSQuestion& dq);
 bool addProxyProtocol(DNSQuestion& dq, const std::string& payload);
-bool addProxyProtocol(std::vector<uint8_t>& buffer, const std::string& payload);
-bool addProxyProtocol(std::vector<uint8_t>& buffer, bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values);
+bool addProxyProtocol(PacketBuffer& buffer, const std::string& payload);
+bool addProxyProtocol(PacketBuffer& buffer, bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values);
index 358f943b18bae084f47ead8461577d6565829b53..8737dec4798b52bd736a312bc8877134c04a1883 100644 (file)
@@ -91,7 +91,7 @@ static std::string getFirstTXTAnswer(const std::string& answer)
 static std::string getSecPollStatus(const std::string& queriedName, int timeout=2)
 {
   const DNSName& sentName = DNSName(queriedName);
-  vector<uint8_t> packet;
+  std::vector<uint8_t> packet;
   DNSPacketWriter pw(packet, sentName, QType::TXT);
   pw.getHeader()->id = getRandomDNSID();
   pw.getHeader()->rd = 1;
index 622b6a93316e0daf8e56569469c08d67bac81a0c..b16195fa1049ac9cca096ca450ea058fb53fa6d0 100644 (file)
@@ -48,7 +48,7 @@ IOState TCPConnectionToBackend::queueNextQuery(std::shared_ptr<TCPConnectionToBa
    would block.
 */
 // XXX could probably be implemented as a TCPIOHandler
-static IOState tryRead(int fd, std::vector<uint8_t>& buffer, size_t& pos, size_t toRead)
+static IOState tryRead(int fd, PacketBuffer& buffer, size_t& pos, size_t toRead)
 {
   if (buffer.size() < (pos + toRead)) {
     throw std::out_of_range("Calling tryRead() with a too small buffer (" + std::to_string(buffer.size()) + ") for a read of " + std::to_string(toRead) + " bytes starting at " + std::to_string(pos));
index 48c0901d9bf652e8a6797935156882afee6864d0..9bb64909b8d1ee74d9167a0105063c5b47fcdfbd 100644 (file)
@@ -12,12 +12,12 @@ struct TCPQuery
   {
   }
 
-  TCPQuery(std::vector<uint8_t>&& buffer, IDState&& state): d_idstate(std::move(state)), d_buffer(std::move(buffer))
+  TCPQuery(PacketBuffer&& buffer, IDState&& state): d_idstate(std::move(state)), d_buffer(std::move(buffer))
   {
   }
 
   IDState d_idstate;
-  std::vector<uint8_t> d_buffer;
+  PacketBuffer d_buffer;
 };
 
 class TCPConnectionToBackend;
@@ -30,7 +30,7 @@ struct TCPResponse : public TCPQuery
     memset(&d_cleartextDH, 0, sizeof(d_cleartextDH));
   }
 
-  TCPResponse(std::vector<uint8_t>&& buffer, IDState&& state, std::shared_ptr<TCPConnectionToBackend> conn): TCPQuery(std::move(buffer), std::move(state)), d_connection(conn)
+  TCPResponse(PacketBuffer&& buffer, IDState&& state, std::shared_ptr<TCPConnectionToBackend> conn): TCPQuery(std::move(buffer), std::move(state)), d_connection(conn)
   {
     memset(&d_cleartextDH, 0, sizeof(d_cleartextDH));
   }
@@ -214,7 +214,7 @@ private:
 
   static const uint16_t s_xfrID;
 
-  std::vector<uint8_t> d_responseBuffer;
+  PacketBuffer d_responseBuffer;
   std::deque<TCPQuery> d_pendingQueries;
   std::unordered_map<uint16_t, TCPQuery> d_pendingResponses;
   std::unique_ptr<Socket> d_socket{nullptr};
index f5e063cae317c993442adec8be5f8c85ede5f748..58210dc40ebbe84f4f5c274235fd6edffc29aa45 100644 (file)
@@ -199,7 +199,7 @@ public:
   enum class State { doingHandshake, readingQuerySize, readingQuery, sendingResponse, idle /* in case of XFR, we stop processing queries */ };
 
   std::map<std::shared_ptr<DownstreamState>, std::deque<std::shared_ptr<TCPConnectionToBackend>>> d_activeConnectionsToBackend;
-  std::vector<uint8_t> d_buffer;
+  PacketBuffer d_buffer;
   std::deque<TCPResponse> d_queuedResponses;
   TCPClientThreadData& d_threadData;
   TCPResponse d_currentResponse;
index de8b322733e2ab30588040edcc0806ba660a97d0..60c8487b96facb63b0a5ff355406b59fe1d80310 100644 (file)
@@ -328,7 +328,7 @@ static const std::string& getReasonFromStatusCode(uint16_t statusCode)
 }
 
 /* Always called from the main DoH thread */
-static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCode, const std::vector<uint8_t>& response, const std::vector<std::pair<std::string, std::string>>& customResponseHeaders, const std::string& contentType, bool addContentType)
+static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCode, const PacketBuffer& response, const std::vector<std::pair<std::string, std::string>>& customResponseHeaders, const std::string& contentType, bool addContentType)
 {
   constexpr int overwrite_if_exists = 1;
   constexpr int maybe_token = 1;
@@ -654,7 +654,7 @@ static void on_generator_dispose(void *_self)
 /* This executes in the main DoH thread.
    We allocate a DOHUnit and send it to dnsdistclient() function in the doh client thread
    via a pipe */
-static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_req_t* req, std::vector<uint8_t>&& query, const ComboAddress& local, const ComboAddress& remote, std::string&& path)
+static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_req_t* req, PacketBuffer&& query, const ComboAddress& local, const ComboAddress& remote, std::string&& path)
 {
   try {
     /* we only parse it there as a sanity check, we will parse it again later */
@@ -858,7 +858,7 @@ try
     else
       ++dsc->df->d_http1Stats.d_nbQueries;
 
-    std::vector<uint8_t> query;
+    PacketBuffer query;
     /* We reserve at least 512 additional bytes to be able to add EDNS, but we also want
        at least s_maxPacketCacheEntrySize bytes to be able to fill the answer from the packet cache */
     query.reserve(std::max(req->entity.len + 512, s_maxPacketCacheEntrySize));
@@ -885,7 +885,7 @@ try
         break;
       }
 
-      std::vector<uint8_t> decoded;
+      PacketBuffer decoded;
 
       /* rough estimate so we hopefully don't need a new allocation later */
       /* We reserve at least 512 additional bytes to be able to add EDNS, but we also want
@@ -1036,7 +1036,7 @@ std::string DOHUnit::getHTTPQueryString() const
   }
 }
 
-void DOHUnit::setHTTPResponse(uint16_t statusCode, std::vector<uint8_t>&& body_, const std::string& contentType_)
+void DOHUnit::setHTTPResponse(uint16_t statusCode, PacketBuffer&& body_, const std::string& contentType_)
 {
   status_code = statusCode;
   response = std::move(body_);
diff --git a/pdns/dnsdistdist/noinitvector.hh b/pdns/dnsdistdist/noinitvector.hh
new file mode 120000 (symlink)
index 0000000..ee1de09
--- /dev/null
@@ -0,0 +1 @@
+../noinitvector.hh
\ No newline at end of file
index c1ff709344e50d134782c559732552c56094c412..7c9aae7c53767c0c6907044416b6e528db5e93b9 100644 (file)
@@ -144,7 +144,7 @@ public:
     }
   }
 
-  IOState tryWrite(std::vector<uint8_t>& buffer, size_t& pos, size_t toWrite) override
+  IOState tryWrite(PacketBuffer& buffer, size_t& pos, size_t toWrite) override
   {
     do {
       int res = SSL_write(d_conn.get(), reinterpret_cast<const char *>(&buffer.at(pos)), static_cast<int>(toWrite - pos));
@@ -159,7 +159,7 @@ public:
     return IOState::Done;
   }
 
-  IOState tryRead(std::vector<uint8_t>& buffer, size_t& pos, size_t toRead) override
+  IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead) override
   {
     do {
       int res = SSL_read(d_conn.get(), reinterpret_cast<char *>(&buffer.at(pos)), static_cast<int>(toRead - pos));
@@ -572,7 +572,7 @@ public:
     throw std::runtime_error("Error accepting a new connection");
   }
 
-  IOState tryWrite(std::vector<uint8_t>& buffer, size_t& pos, size_t toWrite) override
+  IOState tryWrite(PacketBuffer& buffer, size_t& pos, size_t toWrite) override
   {
     do {
       ssize_t res = gnutls_record_send(d_conn.get(), reinterpret_cast<const char *>(&buffer.at(pos)), toWrite - pos);
@@ -596,7 +596,7 @@ public:
     return IOState::Done;
   }
 
-  IOState tryRead(std::vector<uint8_t>& buffer, size_t& pos, size_t toRead) override
+  IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead) override
   {
     do {
       ssize_t res = gnutls_record_recv(d_conn.get(), reinterpret_cast<char *>(&buffer.at(pos)), toRead - pos);
index 783e9fabf01d9672836696a8840be3163299f4c4..04f19ce140d67c940266342b4e2ea1f0c978fcb8 100644 (file)
@@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(test_LMDB) {
   uint16_t qclass = QClass::IN;
   ComboAddress lc("192.0.2.1:53");
   ComboAddress rem("192.0.2.128:42");
-  std::vector<uint8_t> packet(sizeof(dnsheader));
+  PacketBuffer packet(sizeof(dnsheader));
   bool isTcp = false;
   struct timespec queryRealTime;
   gettime(&queryRealTime, true);
@@ -288,7 +288,7 @@ BOOST_AUTO_TEST_CASE(test_CDB) {
   uint16_t qclass = QClass::IN;
   ComboAddress lc("192.0.2.1:53");
   ComboAddress rem("192.0.2.128:42");
-  std::vector<uint8_t> packet(sizeof(dnsheader));
+  PacketBuffer packet(sizeof(dnsheader));
   bool isTcp = false;
   struct timespec queryRealTime;
   gettime(&queryRealTime, true);
index 67fdae00c926dab1e5b8452cd131a968aeb0c6d8..ce76c8bab1f9a631a8b2c3361c9097059ac37bce 100644 (file)
@@ -59,7 +59,7 @@ std::string DOHUnit::getHTTPQueryString() const
   return "";
 }
 
-void DOHUnit::setHTTPResponse(uint16_t statusCode, std::vector<uint8_t>&& body_, const std::string& contentType_)
+void DOHUnit::setHTTPResponse(uint16_t statusCode, PacketBuffer&& body_, const std::string& contentType_)
 {
 }
 #endif /* HAVE_DNS_OVER_HTTPS */
@@ -91,7 +91,7 @@ static DNSQuestion getDQ(const DNSName* providedName = nullptr)
   static const ComboAddress lc("127.0.0.1:53");
   static const ComboAddress rem("192.0.2.1:42");
   static struct timespec queryRealTime;
-  static std::vector<uint8_t> packet(sizeof(dnsheader));
+  static PacketBuffer packet(sizeof(dnsheader));
 
   uint16_t qtype = QType::A;
   uint16_t qclass = QClass::IN;
index bc396d8b7d2b0c801dfa1a6fd545f9f30f3ae134..f7f939944c73c45c3294e35b8b348743a0df6409 100644 (file)
@@ -22,7 +22,7 @@ BOOST_AUTO_TEST_CASE(test_MaxQPSIPRule) {
   uint16_t qclass = QClass::IN;
   ComboAddress lc("127.0.0.1:53");
   ComboAddress rem("192.0.2.1:42");
-  std::vector<uint8_t> packet(sizeof(dnsheader));
+  PacketBuffer packet(sizeof(dnsheader));
   bool isTcp = false;
   struct timespec queryRealTime;
   gettime(&queryRealTime, true);
index adad9e0214309dd61729754cf627531694ce95eb..09f195db853ec226819bd4c3a865981b5e538e4e 100644 (file)
@@ -41,7 +41,7 @@
 */
 
 
-DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const DNSName& qname, uint16_t  qtype, uint16_t qclass, uint8_t opcode)
+template <typename Container> GenericDNSPacketWriter<Container>::GenericDNSPacketWriter(Container& content, const DNSName& qname, uint16_t  qtype, uint16_t qclass, uint8_t opcode)
   : d_content(content), d_qname(qname), d_canonic(false), d_lowerCase(false)
 {
   d_content.clear();
@@ -68,13 +68,13 @@ DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const DNSName& qname,
   d_rollbackmarker = 0;
 }
 
-dnsheader* DNSPacketWriter::getHeader()
+template <typename Container> dnsheader* GenericDNSPacketWriter<Container>::getHeader()
 {
   return reinterpret_cast<dnsheader*>(&*d_content.begin());
 }
 
 
-void DNSPacketWriter::startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, DNSResourceRecord::Place place, bool compress)
+template <typename Container> void GenericDNSPacketWriter<Container>::startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, DNSResourceRecord::Place place, bool compress)
 {
   d_compress = compress;
   commit();
@@ -95,7 +95,7 @@ void DNSPacketWriter::startRecord(const DNSName& name, uint16_t qtype, uint32_t
   d_sor=d_content.size(); // this will remind us where to stuff the record size
 }
 
-void DNSPacketWriter::addOpt(const uint16_t udpsize, const uint16_t extRCode, const uint16_t ednsFlags, const optvect_t& options, const uint8_t version)
+template <typename Container> void GenericDNSPacketWriter<Container>::addOpt(const uint16_t udpsize, const uint16_t extRCode, const uint16_t ednsFlags, const optvect_t& options, const uint8_t version)
 {
   uint32_t ttl=0;
 
@@ -129,7 +129,7 @@ void DNSPacketWriter::addOpt(const uint16_t udpsize, const uint16_t extRCode, co
   }
 }
 
-void DNSPacketWriter::xfr48BitInt(uint64_t val)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfr48BitInt(uint64_t val)
 {
   unsigned char bytes[6];
   uint16_t theLeft = htons((val >> 32)&0xffffU);
@@ -141,21 +141,21 @@ void DNSPacketWriter::xfr48BitInt(uint64_t val)
 }
 
 
-void DNSPacketWriter::xfr32BitInt(uint32_t val)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfr32BitInt(uint32_t val)
 {
   uint32_t rval=htonl(val);
   uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
   d_content.insert(d_content.end(), ptr, ptr+4);
 }
 
-void DNSPacketWriter::xfr16BitInt(uint16_t val)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfr16BitInt(uint16_t val)
 {
   uint16_t rval=htons(val);
   uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
   d_content.insert(d_content.end(), ptr, ptr+2);
 }
 
-void DNSPacketWriter::xfr8BitInt(uint8_t val)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfr8BitInt(uint8_t val)
 {
   d_content.push_back(val);
 }
@@ -174,7 +174,7 @@ void DNSPacketWriter::xfr8BitInt(uint8_t val)
   "blah" -> blah
   "blah\"blah" -> blah"blah
   */
-void DNSPacketWriter::xfrText(const string& text, bool, bool lenField)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrText(const string& text, bool, bool lenField)
 {
   if(text.empty()) {
     d_content.push_back(0);
@@ -188,7 +188,7 @@ void DNSPacketWriter::xfrText(const string& text, bool, bool lenField)
   }
 }
 
-void DNSPacketWriter::xfrUnquotedText(const string& text, bool lenField)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrUnquotedText(const string& text, bool lenField)
 {
   if(text.empty()) {
     d_content.push_back(0);
@@ -202,7 +202,7 @@ void DNSPacketWriter::xfrUnquotedText(const string& text, bool lenField)
 
 static constexpr bool l_verbose=false;
 static constexpr uint16_t maxCompressionOffset=16384;
-uint16_t DNSPacketWriter::lookupName(const DNSName& name, uint16_t* matchLen)
+template <typename Container> uint16_t GenericDNSPacketWriter<Container>::lookupName(const DNSName& name, uint16_t* matchLen)
 {
   // iterate over the written labels, see if we find a match
   const auto& raw = name.getStorage();
@@ -315,7 +315,7 @@ uint16_t DNSPacketWriter::lookupName(const DNSName& name, uint16_t* matchLen)
   return bestpos;
 }
 // this is the absolute hottest function in the pdns recursor
-void DNSPacketWriter::xfrName(const DNSName& name, bool compress, bool)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrName(const DNSName& name, bool compress, bool)
 {
   if(l_verbose)
     cout<<"Wants to write "<<name<<", compress="<<compress<<", canonic="<<d_canonic<<", LC="<<d_lowerCase<<endl;
@@ -372,23 +372,23 @@ void DNSPacketWriter::xfrName(const DNSName& name, bool compress, bool)
   }
 }
 
-void DNSPacketWriter::xfrBlob(const string& blob, int  )
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlob(const string& blob, int  )
 {
   const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
   d_content.insert(d_content.end(), ptr, ptr+blob.size());
 }
 
-void DNSPacketWriter::xfrBlobNoSpaces(const string& blob, int  )
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrBlobNoSpaces(const string& blob, int  )
 {
   xfrBlob(blob);
 }
 
-void DNSPacketWriter::xfrHexBlob(const string& blob, bool keepReading)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrHexBlob(const string& blob, bool keepReading)
 {
   xfrBlob(blob);
 }
 
-void DNSPacketWriter::xfrSvcParamKeyVals(const std::set<SvcParam> &kvs)
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrSvcParamKeyVals(const std::set<SvcParam> &kvs)
 {
   for (auto const &param : kvs) {
     // Key first!
@@ -446,30 +446,30 @@ void DNSPacketWriter::xfrSvcParamKeyVals(const std::set<SvcParam> &kvs)
 }
 
 // call __before commit__
-void DNSPacketWriter::getRecordPayload(string& records)
+template <typename Container> void GenericDNSPacketWriter<Container>::getRecordPayload(string& records)
 {
   records.assign(d_content.begin() + d_sor, d_content.end());
 }
 
-uint32_t DNSPacketWriter::size()
+template <typename Container> uint32_t GenericDNSPacketWriter<Container>::size()
 {
   return d_content.size();
 }
 
-void DNSPacketWriter::rollback()
+template <typename Container> void GenericDNSPacketWriter<Container>::rollback()
 {
   d_content.resize(d_rollbackmarker);
   d_sor = 0;
 }
 
-void DNSPacketWriter::truncate()
+template <typename Container> void GenericDNSPacketWriter<Container>::truncate()
 {
   d_content.resize(d_truncatemarker);
   dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
   dh->ancount = dh->nscount = dh->arcount = 0;
 }
 
-void DNSPacketWriter::commit()
+template <typename Container> void GenericDNSPacketWriter<Container>::commit()
 {
   if(!d_sor)
     return;
@@ -494,3 +494,9 @@ void DNSPacketWriter::commit()
   }
 
 }
+
+template class GenericDNSPacketWriter<std::vector<uint8_t>>;
+#include "noinitvector.hh"
+template class GenericDNSPacketWriter<PacketBuffer>;
+
+
index 25cfd6f3e5e5c8517488670f4a3fa7a9a6655bc6..aef99ae49d7da5e7ca158391ec2e613fe8c947c2 100644 (file)
 
 */
 
-class DNSPacketWriter : public boost::noncopyable
+template <typename Container> class GenericDNSPacketWriter : public boost::noncopyable
 {
 
 public:
   //! Start a DNS Packet in the vector passed, with question qname, qtype and qclass
-  DNSPacketWriter(vector<uint8_t>& content, const DNSName& qname, uint16_t  qtype, uint16_t qclass=QClass::IN, uint8_t opcode=0);
+  GenericDNSPacketWriter(Container& content, const DNSName& qname, uint16_t  qtype, uint16_t qclass=QClass::IN, uint8_t opcode=0);
 
   /** Start a new DNS record within this packet for namq, qtype, ttl, class and in the requested place. Note that packets can only be written in natural order -
       ANSWER, AUTHORITY, ADDITIONAL */
@@ -146,7 +146,7 @@ public:
   {
     d_lowerCase=val;
   }
-  vector <uint8_t>& getContent()
+  Container& getContent()
   {
     return d_content;
   }
@@ -162,7 +162,7 @@ private:
   uint16_t d_sor;
   uint16_t d_rollbackmarker; // start of last complete packet, for rollback
 
-  vector <uint8_t>& d_content;
+  Container& d_content;
   DNSName d_qname;
 
   uint16_t d_truncatemarker; // end of header, for truncate
@@ -170,6 +170,8 @@ private:
   bool d_canonic, d_lowerCase, d_compress{false};
 };
 
+using DNSPacketWriter = GenericDNSPacketWriter<std::vector<uint8_t>>;
+
 typedef vector<pair<string::size_type, string::size_type> > labelparts_t;
 // bool labeltokUnescape(labelparts_t& parts, const DNSName& label);
 std::vector<string> segmentDNSText(const string& text); // from dnslabeltext.rl
index ed17ad26041c7f574104a23fd54956de1e1f44ea..5327457d7fbe24bc7c14d4c81475c6c2822057ac 100644 (file)
 #pragma once
 #include "iputils.hh"
 #include "libssl.hh"
+#include "noinitvector.hh"
 
 struct DOHServerConfig;
 
 class DOHResponseMapEntry
 {
 public:
-  DOHResponseMapEntry(const std::string& regex, uint16_t status, const std::vector<uint8_t>& content, const boost::optional<std::vector<std::pair<std::string, std::string>>>& headers): d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
+  DOHResponseMapEntry(const std::string& regex, uint16_t status, const PacketBuffer& content, const boost::optional<std::vector<std::pair<std::string, std::string>>>& headers): d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
   {
     if (status >= 400 && !d_content.empty() && d_content.at(d_content.size() -1) != 0) {
       // we need to make sure it's null-terminated
@@ -46,7 +47,7 @@ public:
     return d_status;
   }
 
-  const std::vector<uint8_t>& getContent() const
+  const PacketBuffer& getContent() const
   {
     return d_content;
   }
@@ -59,7 +60,7 @@ public:
 private:
   Regex d_regex;
   boost::optional<std::vector<std::pair<std::string, std::string>>> d_customHeaders;
-  std::vector<uint8_t> d_content;
+  PacketBuffer d_content;
   uint16_t d_status;
 };
 
@@ -189,8 +190,8 @@ struct DOHUnit
   }
 
   std::vector<std::pair<std::string, std::string>> headers;
-  std::vector<uint8_t> query;
-  std::vector<uint8_t> response;
+  PacketBuffer query;
+  PacketBuffer response;
   std::string sni;
   std::string path;
   std::string scheme;
@@ -219,7 +220,7 @@ struct DOHUnit
   std::string getHTTPScheme() const;
   std::string getHTTPQueryString() const;
   std::unordered_map<std::string, std::string> getHTTPHeaders() const;
-  void setHTTPResponse(uint16_t statusCode, std::vector<uint8_t>&& body, const std::string& contentType="");
+  void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType="");
 };
 
 #endif /* HAVE_DNS_OVER_HTTPS  */
index 1b12f356025aab0aa17b211de9237159fb7fd35b..eb68950bddd132b71ffad458966a4c154d8f2edb 100644 (file)
@@ -43,7 +43,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     uint16_t qtype;
     uint16_t qclass;
     unsigned int consumed;
-    std::vector<uint8_t> vect(data, data+size);
+    PacketBuffer vect(data, data+size);
     const DNSName qname(reinterpret_cast<const char*>(data), size, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
     pcSkipCookies.getKey(qname.getStorage(), consumed, vect, false);
     pcHashCookies.getKey(qname.getStorage(), consumed, vect, false);
diff --git a/pdns/noinitvector.hh b/pdns/noinitvector.hh
new file mode 100644 (file)
index 0000000..cc7efc3
--- /dev/null
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <memory>
+#include <new>
+#include <utility>
+#include <vector>
+
+// based on boost::core::noinit_adaptor
+// The goal is to avoid initialization of the content of a container,
+// because setting several kB of uint8_t to 0 has a real cost if you
+// do 100k times per second.
+template<class Allocator>
+struct noinit_adaptor: Allocator
+{
+  template<class U>
+  struct rebind {
+    typedef noinit_adaptor<typename std::allocator_traits<Allocator>::template
+                           rebind_alloc<U> > other;
+    };
+
+  noinit_adaptor(): Allocator() { }
+
+  template<class U>
+  noinit_adaptor(U&& u) noexcept : Allocator(std::forward<U>(u)) { }
+
+  template<class U>
+  noinit_adaptor(const noinit_adaptor<U>& u) noexcept : Allocator(static_cast<const U&>(u)) { }
+
+  template<class U>
+  void construct(U* p) {
+    ::new((void*)p) U;
+  }
+
+  template<class U, class V, class... Args>
+  void construct(U* p, V&& v, Args&&... args) {
+    ::new((void*)p) U(std::forward<V>(v), std::forward<Args>(args)...);
+  }
+
+  template<class U>
+  void destroy(U* p) {
+    p->~U();
+  }
+};
+
+template<class T, class U>
+inline bool operator==(const noinit_adaptor<T>& lhs,
+                       const noinit_adaptor<U>& rhs) noexcept
+{
+  return static_cast<const T&>(lhs) == static_cast<const U&>(rhs);
+}
+
+template<class T, class U>
+inline bool operator!=(const noinit_adaptor<T>& lhs,
+                       const noinit_adaptor<U>& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+template<class Allocator>
+inline noinit_adaptor<Allocator> noinit_adapt(const Allocator& a) noexcept
+{
+  return noinit_adaptor<Allocator>(a);
+}
+
+template<class T> using NoInitVector = std::vector<T, noinit_adaptor<std::allocator<T>>>;
+
+using PacketBuffer = NoInitVector<uint8_t>;
index 725cf5c3cbdaed5cac4a6739622c13336c251e39..f3757f165cb85c802918ef2cd64d0c512fd6aa1b 100644 (file)
@@ -135,6 +135,7 @@ pdns_recursor_SOURCES = \
        mtasker_context.cc mtasker_context.hh \
        namespaces.hh \
        negcache.hh negcache.cc \
+       noinitvector.hh \
        nsecrecords.cc \
        opensslsigners.cc opensslsigners.hh \
        packetcache.hh \
diff --git a/pdns/recursordist/noinitvector.hh b/pdns/recursordist/noinitvector.hh
new file mode 120000 (symlink)
index 0000000..ee1de09
--- /dev/null
@@ -0,0 +1 @@
+../noinitvector.hh
\ No newline at end of file
index 5c96e1a1625e643b3212592f67c0f6a71f4720f9..b92c6e0e53bb716f3649be5ab6ae7814b6b6336a 100644 (file)
@@ -21,6 +21,7 @@
  */
 #include <iostream>
 #include "namespaces.hh"
+#include "noinitvector.hh"
 #include "misc.hh"
 #include "base64.hh"
 #include "sodcrypto.hh"
@@ -292,6 +293,7 @@ template<typename Container> int B64Decode(const std::string& strInput, Containe
 }
 
 template int B64Decode<std::vector<uint8_t>>(const std::string& strInput, std::vector<uint8_t>& strOutput);
+template int B64Decode<PacketBuffer>(const std::string& strInput, PacketBuffer& strOutput);
 template int B64Decode<std::string>(const std::string& strInput, std::string& strOutput);
 
 /*
index a5e83208986e315658865491db69959577d964a6..98f1e8ed55557ed05a4e5f1cc5f58ac3620ca08c 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "libssl.hh"
 #include "misc.hh"
+#include "noinitvector.hh"
 
 enum class IOState { Done, NeedRead, NeedWrite };
 
@@ -15,8 +16,8 @@ public:
   virtual IOState tryHandshake() = 0;
   virtual size_t read(void* buffer, size_t bufferSize, unsigned int readTimeout, unsigned int totalTimeout=0) = 0;
   virtual size_t write(const void* buffer, size_t bufferSize, unsigned int writeTimeout) = 0;
-  virtual IOState tryWrite(std::vector<uint8_t>& buffer, size_t& pos, size_t toWrite) = 0;
-  virtual IOState tryRead(std::vector<uint8_t>& buffer, size_t& pos, size_t toRead) = 0;
+  virtual IOState tryWrite(PacketBuffer& buffer, size_t& pos, size_t toWrite) = 0;
+  virtual IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead) = 0;
   virtual bool hasBufferedData() const = 0;
   virtual std::string getServerNameIndication() const = 0;
   virtual LibsslTLSVersion getTLSVersion() const = 0;
@@ -217,7 +218,7 @@ public:
      return Done when toRead bytes have been read, needRead or needWrite if the IO operation
      would block.
   */
-  IOState tryRead(std::vector<uint8_t>& buffer, size_t& pos, size_t toRead)
+  IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead)
   {
     if (buffer.size() < toRead || pos >= toRead) {
       throw std::out_of_range("Calling tryRead() with a too small buffer (" + std::to_string(buffer.size()) + ") for a read of " + std::to_string(toRead - pos) + " bytes starting at " + std::to_string(pos));
@@ -254,7 +255,7 @@ public:
      return Done when toWrite bytes have been written, needRead or needWrite if the IO operation
      would block.
   */
-  IOState tryWrite(std::vector<uint8_t>& buffer, size_t& pos, size_t toWrite)
+  IOState tryWrite(PacketBuffer& buffer, size_t& pos, size_t toWrite)
   {
     if (buffer.size() < toWrite || pos >= toWrite) {
       throw std::out_of_range("Calling tryWrite() with a too small buffer (" + std::to_string(buffer.size()) + ") for a write of " + std::to_string(toWrite - pos) + " bytes starting at " + std::to_string(pos));
index bbc08e83efc7bdcb5b838f3b6217d50aa164de53..f3627971fa7f4b459dc859e3d93a55b724bc199a 100644 (file)
@@ -49,8 +49,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQuery) {
   auto ctx = std::make_shared<DNSCryptContext>("2.name", resolverCert, resolverPrivateKey);
 
   DNSName name("2.name.");
-  vector<uint8_t> plainQuery;
-  DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0);
+  PacketBuffer plainQuery;
+  GenericDNSPacketWriter<PacketBuffer> pw(plainQuery, name, QType::TXT, QClass::IN, 0);
   pw.getHeader()->rd = 0;
 
   std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
@@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQuery) {
   BOOST_CHECK_EQUAL(query->isValid(), true);
   BOOST_CHECK_EQUAL(query->isEncrypted(), false);
 
-  std::vector<uint8_t> response;
+  PacketBuffer response;
 
   query->getCertificateResponse(now, response);
 
@@ -88,8 +88,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQueryInvalidA) {
 
   DNSName name("2.name.");
 
-  vector<uint8_t> plainQuery;
-  DNSPacketWriter pw(plainQuery, name, QType::A, QClass::IN, 0);
+  PacketBuffer plainQuery;
+  GenericDNSPacketWriter<PacketBuffer> pw(plainQuery, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 0;
 
   std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
@@ -111,8 +111,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQueryInvalidProviderName) {
 
   DNSName name("2.WRONG.name.");
 
-  vector<uint8_t> plainQuery;
-  DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0);
+  PacketBuffer plainQuery;
+  GenericDNSPacketWriter<PacketBuffer> pw(plainQuery, name, QType::TXT, QClass::IN, 0);
   pw.getHeader()->rd = 0;
 
   std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
@@ -140,8 +140,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValid) {
   unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
 
   DNSName name("www.powerdns.com.");
-  vector<uint8_t> plainQuery;
-  DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
+  PacketBuffer plainQuery;
+  GenericDNSPacketWriter<PacketBuffer> pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   size_t requiredSize = plainQuery.size() + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE;
   if (requiredSize < DNSCryptQuery::s_minUDPLength) {
@@ -194,8 +194,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValidButShort) {
   unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
 
   DNSName name("www.powerdns.com.");
-  vector<uint8_t> plainQuery;
-  DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
+  PacketBuffer plainQuery;
+  GenericDNSPacketWriter<PacketBuffer> pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
   pw.getHeader()->rd = 1;
 
   int res = ctx->encryptQuery(plainQuery, /* not enough room */ plainQuery.size(), clientPublicKey, clientPrivateKey, clientNonce, false, std::make_shared<DNSCryptCert>(resolverCert));
@@ -221,8 +221,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValidWithOldKey) {
   unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
 
   DNSName name("www.powerdns.com.");
-  vector<uint8_t> plainQuery;
-  DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
+  PacketBuffer plainQuery;
+  GenericDNSPacketWriter<PacketBuffer> pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
   pw.getHeader()->rd = 1;
 
   size_t requiredSize = plainQuery.size() + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE;
@@ -279,8 +279,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryInvalidWithWrongKey) {
   unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0A, 0x0B };
 
   DNSName name("www.powerdns.com.");
-  vector<uint8_t> plainQuery;
-  DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
+  PacketBuffer plainQuery;
+  GenericDNSPacketWriter<PacketBuffer> pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
   pw.getHeader()->rd = 1;
 
   size_t initialSize = plainQuery.size();
index df7ca35099f7a4e11f325ecaf9f3124df81842df..f17e3992810fa032955b30888ad2fcd1b0489b08 100644 (file)
@@ -42,7 +42,7 @@ BOOST_AUTO_TEST_SUITE(test_dnsdist_cc)
 static const uint16_t ECSSourcePrefixV4 = 24;
 static const uint16_t ECSSourcePrefixV6 = 56;
 
-static void validateQuery(const std::vector<uint8_t>& packet, bool hasEdns=true, bool hasXPF=false, uint16_t additionals=0, uint16_t answers=0, uint16_t authorities=0)
+static void validateQuery(const PacketBuffer& packet, bool hasEdns=true, bool hasXPF=false, uint16_t additionals=0, uint16_t answers=0, uint16_t authorities=0)
 {
   MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
 
@@ -55,14 +55,14 @@ static void validateQuery(const std::vector<uint8_t>& packet, bool hasEdns=true,
   BOOST_CHECK_EQUAL(mdp.d_header.arcount, expectedARCount);
 }
 
-static void validateECS(const std::vector<uint8_t>& packet, const ComboAddress& expected)
+static void validateECS(const PacketBuffer& packet, const ComboAddress& expected)
 {
   ComboAddress rem("::1");
   unsigned int consumed = 0;
   uint16_t qtype;
   uint16_t qclass;
   DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
-  DNSQuestion dq(&qname, qtype, qclass, nullptr, &rem, const_cast<std::vector<uint8_t>&>(packet), false, nullptr);
+  DNSQuestion dq(&qname, qtype, qclass, nullptr, &rem, const_cast<PacketBuffer&>(packet), false, nullptr);
   BOOST_CHECK(parseEDNSOptions(dq));
   BOOST_REQUIRE(dq.ednsOptions != nullptr);
   BOOST_CHECK_EQUAL(dq.ednsOptions->size(), 1U);
@@ -76,7 +76,7 @@ static void validateECS(const std::vector<uint8_t>& packet, const ComboAddress&
   BOOST_CHECK_EQUAL(expectedOption.substr(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), std::string(ecsOption->second.values.at(0).content, ecsOption->second.values.at(0).size));
 }
 
-static void validateResponse(const std::vector<uint8_t>& packet, bool hasEdns, uint8_t additionalCount=0)
+static void validateResponse(const PacketBuffer& packet, bool hasEdns, uint8_t additionalCount=0)
 {
   MOADNSParser mdp(false, reinterpret_cast<const char*>(packet.data()), packet.size());
 
@@ -98,13 +98,13 @@ BOOST_AUTO_TEST_CASE(test_addXPF)
   ComboAddress remote;
   DNSName name("www.powerdns.com.");
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
-  vector<uint8_t> queryWithXPF;
+  PacketBuffer queryWithXPF;
 
   {
-    std::vector<uint8_t> packet = query;
+    PacketBuffer packet = query;
 
     /* large enough packet */
     unsigned int consumed = 0;
@@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(test_addXPF)
   }
 
   {
-    std::vector<uint8_t> packet = query;
+    PacketBuffer packet = query;
 
     /* packet is already too large for the 4096 limit over UDP */
     packet.resize(4096);
@@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(test_addXPF)
   }
 
   {
-    std::vector<uint8_t> packet = query;
+    PacketBuffer packet = query;
 
     /* packet with trailing data (overriding it) */
     unsigned int consumed = 0;
@@ -176,13 +176,13 @@ BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   uint16_t len = query.size();
 
   /* large enough packet */
-  std::vector<uint8_t> packet = query;
+  PacketBuffer packet = query;
 
   unsigned int consumed = 0;
   uint16_t qtype;
@@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
   BOOST_CHECK_EQUAL(ecsAdded, true);
   validateQuery(packet);
   validateECS(packet, remote);
-  vector<uint8_t> queryWithEDNS = packet;
+  PacketBuffer queryWithEDNS = packet;
 
   /* not large enough packet */
   packet = query;
@@ -245,8 +245,8 @@ BOOST_AUTO_TEST_CASE(addECSWithoutEDNSAlreadyParsed)
   ComboAddress remote("192.0.2.1");
   DNSName name("www.powerdns.com.");
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
 
   auto packet = query;
@@ -301,8 +301,8 @@ BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   pw.addOpt(512, 0, 0);
   pw.commit();
@@ -345,8 +345,8 @@ BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECSAlreadyParsed) {
   ComboAddress remote("2001:DB8::1");
   DNSName name("www.powerdns.com.");
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   pw.addOpt(512, 0, 0);
   pw.commit();
@@ -403,13 +403,13 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -438,13 +438,13 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSameSizeAlreadyParsed) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -483,13 +483,13 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, 32);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -519,15 +519,15 @@ BOOST_AUTO_TEST_CASE(replaceECSWithLarger) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   EDNSSubnetOpts ecsOpts;
   // smaller (less specific so less bits) option
   static_assert(8 < ECSSourcePrefixV4, "The ECS scope should be smaller");
   ecsOpts.source = Netmask(origRemote, 8);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -574,13 +574,13 @@ BOOST_AUTO_TEST_CASE(replaceECSFollowedByTSIG) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, 8);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.addOpt(512, 0, 0, opts);
   pw.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
@@ -628,15 +628,15 @@ BOOST_AUTO_TEST_CASE(replaceECSAfterAN) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   pw.startRecord(DNSName("powerdns.com."), QType::A, 0, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.commit();
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, 8);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -683,15 +683,15 @@ BOOST_AUTO_TEST_CASE(replaceECSAfterAuth) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   pw.startRecord(DNSName("powerdns.com."), QType::A, 0, QClass::IN, DNSResourceRecord::AUTHORITY, true);
   pw.commit();
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, 8);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -738,13 +738,13 @@ BOOST_AUTO_TEST_CASE(replaceECSBetweenTwoRecords) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, 8);
   string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
   pw.startRecord(DNSName("additional"), QType::A, 0, QClass::IN, DNSResourceRecord::ADDITIONAL, false);
   pw.xfr32BitInt(0x01020304);
@@ -794,8 +794,8 @@ BOOST_AUTO_TEST_CASE(insertECSInEDNSBetweenTwoRecords) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   pw.startRecord(DNSName("additional"), QType::A, 0, QClass::IN, DNSResourceRecord::ADDITIONAL, false);
   pw.xfr32BitInt(0x01020304);
@@ -845,8 +845,8 @@ BOOST_AUTO_TEST_CASE(insertECSAfterTSIG) {
   string newECSOption;
   generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
 
-  vector<uint8_t> query;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
   pw.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
   pw.commit();
@@ -889,8 +889,8 @@ BOOST_AUTO_TEST_CASE(insertECSAfterTSIG) {
 BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) {
   DNSName name("www.powerdns.com.");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -900,7 +900,7 @@ BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) {
   pw.xfr32BitInt(0x01020304);
   pw.commit();
 
-  vector<uint8_t> newResponse;
+  PacketBuffer newResponse;
   int res = rewriteResponseWithoutEDNS(response, newResponse);
   BOOST_CHECK_EQUAL(res, 0);
 
@@ -918,8 +918,8 @@ BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) {
 BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) {
   DNSName name("www.powerdns.com.");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -932,7 +932,7 @@ BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) {
   pw.xfr32BitInt(0x01020304);
   pw.commit();
 
-  vector<uint8_t> newResponse;
+  PacketBuffer newResponse;
   int res = rewriteResponseWithoutEDNS(response, newResponse);
   BOOST_CHECK_EQUAL(res, 0);
 
@@ -950,8 +950,8 @@ BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) {
 BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) {
   DNSName name("www.powerdns.com.");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -962,7 +962,7 @@ BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) {
   pw.addOpt(512, 0, 0);
   pw.commit();
 
-  vector<uint8_t> newResponse;
+  PacketBuffer newResponse;
   int res = rewriteResponseWithoutEDNS(response, newResponse);
 
   BOOST_CHECK_EQUAL(res, 0);
@@ -982,8 +982,8 @@ BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -995,7 +995,7 @@ BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) {
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
   string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -1029,8 +1029,8 @@ BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -1046,7 +1046,7 @@ BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) {
   cookiesOpt.client = string("deadbeef");
   cookiesOpt.server = string("deadbeef");
   string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
   pw.addOpt(512, 0, 0, opts);
@@ -1081,8 +1081,8 @@ BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -1101,7 +1101,7 @@ BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) {
   string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt);
   string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt);
 
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1));
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2));
@@ -1137,8 +1137,8 @@ BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -1154,7 +1154,7 @@ BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) {
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
   string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   pw.addOpt(512, 0, 0, opts);
@@ -1189,8 +1189,8 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -1198,7 +1198,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) {
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
   string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   pw.addOpt(512, 0, 0, opts);
   pw.commit();
@@ -1207,7 +1207,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) {
   pw.xfr32BitInt(0x01020304);
   pw.commit();
 
-  vector<uint8_t> newResponse;
+  PacketBuffer newResponse;
   int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
   BOOST_CHECK_EQUAL(res, 0);
 
@@ -1226,8 +1226,8 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -1239,7 +1239,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) {
   cookiesOpt.client = string("deadbeef");
   cookiesOpt.server = string("deadbeef");
   string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
   pw.addOpt(512, 0, 0, opts);
@@ -1249,7 +1249,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) {
   pw.xfr32BitInt(0x01020304);
   pw.commit();
 
-  vector<uint8_t> newResponse;
+  PacketBuffer newResponse;
   int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
   BOOST_CHECK_EQUAL(res, 0);
 
@@ -1268,8 +1268,8 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -1282,7 +1282,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) {
   cookiesOpt.server = string("deadbeef");
   string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt);
   string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1));
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2));
@@ -1293,7 +1293,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) {
   pw.xfr32BitInt(0x01020304);
   pw.commit();
 
-  vector<uint8_t> newResponse;
+  PacketBuffer newResponse;
   int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
   BOOST_CHECK_EQUAL(res, 0);
 
@@ -1312,8 +1312,8 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
   DNSName name("www.powerdns.com.");
   ComboAddress origRemote("127.0.0.1");
 
-  vector<uint8_t> response;
-  DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
+  PacketBuffer response;
+  GenericDNSPacketWriter<PacketBuffer> pw(response, name, QType::A, QClass::IN, 0);
   pw.getHeader()->qr = 1;
   pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
   pw.xfr32BitInt(0x01020304);
@@ -1325,7 +1325,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
   cookiesOpt.client = string("deadbeef");
   cookiesOpt.server = string("deadbeef");
   string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   pw.addOpt(512, 0, 0, opts);
@@ -1335,7 +1335,7 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
   pw.xfr32BitInt(0x01020304);
   pw.commit();
 
-  vector<uint8_t> newResponse;
+  PacketBuffer newResponse;
   int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
   BOOST_CHECK_EQUAL(res, 0);
 
@@ -1350,12 +1350,12 @@ BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
   validateResponse(newResponse, true, 1);
 }
 
-static DNSQuestion getDNSQuestion(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& realTime, vector<uint8_t>& query)
+static DNSQuestion getDNSQuestion(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& realTime, PacketBuffer& query)
 {
   return DNSQuestion(&qname, qtype, qclass, &lc, &rem, query, false, &realTime);
 }
 
-static DNSQuestion turnIntoResponse(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& queryRealTime, vector<uint8_t>&  query, bool resizeBuffer=true)
+static DNSQuestion turnIntoResponse(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& queryRealTime, PacketBuffer&  query, bool resizeBuffer=true)
 {
   if (resizeBuffer) {
     query.resize(4096);
@@ -1368,7 +1368,7 @@ static DNSQuestion turnIntoResponse(const DNSName& qname, const uint16_t qtype,
   return dq;
 }
 
-static int getZ(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, vector<uint8_t>& query)
+static int getZ(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, PacketBuffer& query)
 {
   ComboAddress lc("127.0.0.1");
   ComboAddress rem("127.0.0.1");
@@ -1393,14 +1393,14 @@ BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
   cookiesOpt.client = string("deadbeef");
   cookiesOpt.server = string("deadbeef");
   string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
 
   {
     /* no EDNS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.commit();
 
     BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
@@ -1411,8 +1411,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
 
   {
     /* truncated EDNS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
     pw.commit();
 
@@ -1425,8 +1425,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
 
   {
     /* valid EDNS, no options, DO not set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, 0);
     pw.commit();
 
@@ -1438,8 +1438,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
 
   {
     /* valid EDNS, no options, DO set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
     pw.commit();
 
@@ -1451,8 +1451,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
 
     {
     /* valid EDNS, options, DO not set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, 0, opts);
     pw.commit();
 
@@ -1464,8 +1464,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
 
   {
     /* valid EDNS, options, DO set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts);
     pw.commit();
 
@@ -1491,7 +1491,7 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
   cookiesOpt.client = string("deadbeef");
   cookiesOpt.server = string("deadbeef");
   string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
   opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
   ComboAddress lc("127.0.0.1");
@@ -1501,8 +1501,8 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
 
   {
     /* no EDNS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.getHeader()->qr = 1;
     pw.getHeader()->rcode = RCode::NXDomain;
     pw.commit();
@@ -1516,8 +1516,8 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
 
   {
     /* truncated EDNS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
     pw.commit();
 
@@ -1531,8 +1531,8 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
 
   {
     /* valid EDNS, no options, DO not set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, 0);
     pw.commit();
 
@@ -1545,8 +1545,8 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
 
   {
     /* valid EDNS, no options, DO set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
     pw.commit();
 
@@ -1559,8 +1559,8 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
 
   {
     /* valid EDNS, options, DO not set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, 0, opts);
     pw.commit();
 
@@ -1573,8 +1573,8 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
 
   {
     /* valid EDNS, options, DO set */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts);
     pw.commit();
 
@@ -1593,7 +1593,7 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart) {
   EDNSSubnetOpts ecsOpts;
   ecsOpts.source = Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4);
   const string ecsOptionStr = makeEDNSSubnetOptsString(ecsOpts);
-  DNSPacketWriter::optvect_t opts;
+  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
   opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
   const ComboAddress lc("127.0.0.1");
   const ComboAddress rem("127.0.0.1");
@@ -1604,8 +1604,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart) {
 
   {
     /* no EDNS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.getHeader()->qr = 1;
     pw.getHeader()->rcode = RCode::NXDomain;
     pw.commit();
@@ -1623,8 +1623,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart) {
 
   {
     /* valid EDNS, no options */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, 0);
     pw.commit();
 
@@ -1643,8 +1643,8 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart) {
 
   {
     /* valid EDNS, options */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, 0, opts);
     pw.commit();
 
@@ -1666,7 +1666,7 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart) {
 
 BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
 
-  auto locateEDNSOption = [](const vector<uint8_t>& query, uint16_t code, size_t* optContentStart, uint16_t* optContentLen) {
+  auto locateEDNSOption = [](const PacketBuffer& query, uint16_t code, size_t* optContentStart, uint16_t* optContentLen) {
     uint16_t optStart;
     size_t optLen;
     bool last = false;
@@ -1702,7 +1702,7 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
   const string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
   const size_t sizeOfCookieOption = /* option code */ 2 + /* option length */ 2 + cookiesOpt.client.size() + cookiesOpt.server.size();
   /*
-    DNSPacketWriter::optvect_t opts;
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
     opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
     opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
     opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
@@ -1716,8 +1716,8 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
 
   {
     /* no EDNS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.getHeader()->qr = 1;
     pw.getHeader()->rcode = RCode::NXDomain;
     pw.commit();
@@ -1733,8 +1733,8 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
 
   {
     /* valid EDNS, no options */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
     pw.addOpt(512, 0, 0);
     pw.commit();
 
@@ -1748,9 +1748,9 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
 
   {
     /* valid EDNS, two cookie options but no ECS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
-    DNSPacketWriter::optvect_t opts;
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
     opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
     opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
     pw.addOpt(512, 0, 0, opts);
@@ -1766,9 +1766,9 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
 
   {
     /* valid EDNS, two ECS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
-    DNSPacketWriter::optvect_t opts;
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
     opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
     opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
     pw.addOpt(512, 0, 0, opts);
@@ -1788,9 +1788,9 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
 
   {
     /* valid EDNS, one ECS between two cookies */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
-    DNSPacketWriter::optvect_t opts;
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
     opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
     opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
     opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
@@ -1811,9 +1811,9 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
 
   {
     /* valid EDNS, one 65002 after an ECS */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, qname, qtype, qclass, 0);
-    DNSPacketWriter::optvect_t opts;
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, qname, qtype, qclass, 0);
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
     opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
     opts.push_back(make_pair(65535, cookiesOptionStr));
     pw.addOpt(512, 0, 0, opts);
@@ -1838,11 +1838,11 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA) {
   ComboAddress remote;
   DNSName name("www.powerdns.com.");
 
-  vector<uint8_t> query;
-  vector<uint8_t> queryWithEDNS;
-  DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+  PacketBuffer query;
+  PacketBuffer queryWithEDNS;
+  GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
   pw.getHeader()->rd = 1;
-  DNSPacketWriter pwEDNS(queryWithEDNS, name, QType::A, QClass::IN, 0);
+  GenericDNSPacketWriter<PacketBuffer> pwEDNS(queryWithEDNS, name, QType::A, QClass::IN, 0);
   pwEDNS.getHeader()->rd = 1;
   pwEDNS.addOpt(1232, 0, 0);
   pwEDNS.commit();
@@ -1960,8 +1960,8 @@ BOOST_AUTO_TEST_CASE(getEDNSOptionsWithoutEDNS) {
 
   {
     /* no EDNS and no other additional record */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
     pw.getHeader()->rd = 1;
     pw.commit();
 
@@ -1979,8 +1979,8 @@ BOOST_AUTO_TEST_CASE(getEDNSOptionsWithoutEDNS) {
 
   {
     /* nothing in additional (so no EDNS) but a record in ANSWER */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
     pw.getHeader()->rd = 1;
     pw.startRecord(name, QType::A, 60, QClass::IN, DNSResourceRecord::ANSWER);
     pw.xfrIP(v4.sin4.sin_addr.s_addr);
@@ -2000,8 +2000,8 @@ BOOST_AUTO_TEST_CASE(getEDNSOptionsWithoutEDNS) {
 
   {
     /* nothing in additional (so no EDNS) but a record in AUTHORITY */
-    vector<uint8_t> query;
-    DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
     pw.getHeader()->rd = 1;
     pw.startRecord(name, QType::A, 60, QClass::IN, DNSResourceRecord::AUTHORITY);
     pw.xfrIP(v4.sin4.sin_addr.s_addr);
index 428e12cb98ccb04fece7667468e124360d9d8465..4acd98a75d2dd07d67a8440e68bf66194ca232fd 100644 (file)
@@ -31,12 +31,12 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
       DNSName a=DNSName(std::to_string(counter))+DNSName(" hello");
       BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
 
-      vector<uint8_t> query;
-      DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
+      PacketBuffer query;
+      GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
       pwQ.getHeader()->rd = 1;
 
-      vector<uint8_t> response;
-      DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
+      PacketBuffer response;
+      GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::A, QClass::IN, 0);
       pwR.getHeader()->rd = 1;
       pwR.getHeader()->ra = 1;
       pwR.getHeader()->qr = 1;
@@ -73,8 +73,8 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
     size_t delcounter=0;
     for(delcounter=0; delcounter < counter/1000; ++delcounter) {
       DNSName a=DNSName(std::to_string(delcounter))+DNSName(" hello");
-      vector<uint8_t> query;
-      DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
+      PacketBuffer query;
+      GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
       pwQ.getHeader()->rd = 1;
       uint32_t key = 0;
       boost::optional<Netmask> subnet;
@@ -93,8 +93,8 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
     size_t expected=counter-skipped-deleted;
     for(; delcounter < counter; ++delcounter) {
       DNSName a(DNSName(std::to_string(delcounter))+DNSName(" hello"));
-      vector<uint8_t> query;
-      DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
+      PacketBuffer query;
+      GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
       pwQ.getHeader()->rd = 1;
       uint32_t key = 0;
       boost::optional<Netmask> subnet;
@@ -131,12 +131,12 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) {
     DNSName a = DNSName("servfail");
     BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
 
-    vector<uint8_t> query;
-    DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
     pwQ.getHeader()->rd = 1;
 
-    vector<uint8_t> response;
-    DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
+    PacketBuffer response;
+    GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::A, QClass::IN, 0);
     pwR.getHeader()->rd = 1;
     pwR.getHeader()->ra = 0;
     pwR.getHeader()->qr = 1;
@@ -180,12 +180,12 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) {
   bool dnssecOK = false;
   try {
     DNSName name("nodata");
-    vector<uint8_t> query;
-    DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
     pwQ.getHeader()->rd = 1;
 
-    vector<uint8_t> response;
-    DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0);
+    PacketBuffer response;
+    GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
     pwR.getHeader()->rd = 1;
     pwR.getHeader()->ra = 0;
     pwR.getHeader()->qr = 1;
@@ -232,12 +232,12 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) {
   bool dnssecOK = false;
   try {
     DNSName name("nxdomain");
-    vector<uint8_t> query;
-    DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
     pwQ.getHeader()->rd = 1;
 
-    vector<uint8_t> response;
-    DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0);
+    PacketBuffer response;
+    GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
     pwR.getHeader()->rd = 1;
     pwR.getHeader()->ra = 0;
     pwR.getHeader()->qr = 1;
@@ -284,12 +284,12 @@ static void threadMangler(unsigned int offset)
     bool dnssecOK = false;
     for(unsigned int counter=0; counter < 100000; ++counter) {
       DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
-      vector<uint8_t> query;
-      DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
+      PacketBuffer query;
+      GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
       pwQ.getHeader()->rd = 1;
 
-      vector<uint8_t> response;
-      DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
+      PacketBuffer response;
+      GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::A, QClass::IN, 0);
       pwR.getHeader()->rd = 1;
       pwR.getHeader()->ra = 1;
       pwR.getHeader()->qr = 1;
@@ -325,8 +325,8 @@ static void threadReader(unsigned int offset)
     ComboAddress remote;
     for(unsigned int counter=0; counter < 100000; ++counter) {
       DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
-      vector<uint8_t> query;
-      DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
+      PacketBuffer query;
+      GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
       pwQ.getHeader()->rd = 1;
 
       uint32_t key = 0;
@@ -393,11 +393,11 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
   /* lookup for a query with a first ECS value,
      insert a corresponding response */
   {
-    vector<uint8_t> query;
-    DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, qtype, QClass::IN, 0);
     pwQ.getHeader()->rd = 1;
     pwQ.getHeader()->id = qid;
-    DNSPacketWriter::optvect_t ednsOptions;
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions;
     EDNSSubnetOpts opt;
     opt.source = Netmask("10.0.59.220/32");
     ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
@@ -413,8 +413,8 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
     BOOST_REQUIRE(subnetOut);
     BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
 
-    vector<uint8_t> response;
-    DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0);
+    PacketBuffer response;
+    GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, qtype, QClass::IN, 0);
     pwR.getHeader()->rd = 1;
     pwR.getHeader()->id = qid;
     pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
@@ -436,11 +436,11 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
   /* now lookup for the same query with a different ECS value,
      we should get the same key (collision) but no match */
   {
-    vector<uint8_t> query;
-    DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, qtype, QClass::IN, 0);
     pwQ.getHeader()->rd = 1;
     pwQ.getHeader()->id = qid;
-    DNSPacketWriter::optvect_t ednsOptions;
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions;
     EDNSSubnetOpts opt;
     opt.source = Netmask("10.0.167.48/32");
     ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
@@ -463,7 +463,7 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
   /* to be able to compute a new collision if the packet cache hashing code is updated */
   {
     DNSDistPacketCache pc(10000);
-    DNSPacketWriter::optvect_t ednsOptions;
+    GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions;
     EDNSSubnetOpts opt;
     std::map<uint32_t, Netmask> colMap;
     size_t collisions = 0;
@@ -473,8 +473,8 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
     for (size_t idxA = 0; idxA < 256; idxA++) {
       for (size_t idxB = 0; idxB < 256; idxB++) {
         for (size_t idxC = 0; idxC < 256; idxC++) {
-          vector<uint8_t> secondQuery;
-          DNSPacketWriter pwFQ(secondQuery, qname, QType::AAAA, QClass::IN, 0);
+          PacketBuffer secondQuery;
+          GenericDNSPacketWriter<PacketBuffer> pwFQ(secondQuery, qname, QType::AAAA, QClass::IN, 0);
           pwFQ.getHeader()->rd = 1;
           pwFQ.getHeader()->qr = false;
           pwFQ.getHeader()->id = 0x42;
@@ -516,8 +516,8 @@ BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
      insert a corresponding response with DO set,
      check that it doesn't match without DO, but does with it */
   {
-    vector<uint8_t> query;
-    DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, qtype, QClass::IN, 0);
     pwQ.getHeader()->rd = 1;
     pwQ.getHeader()->id = qid;
     pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
@@ -530,8 +530,8 @@ BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
     bool found = PC.get(dq, 0, &key, subnetOut, true);
     BOOST_CHECK_EQUAL(found, false);
 
-    vector<uint8_t> response;
-    DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0);
+    PacketBuffer response;
+    GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, qtype, QClass::IN, 0);
     pwR.getHeader()->rd = 1;
     pwR.getHeader()->id = qid;
     pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);