Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dnsdist for openSUSE:Factory checked in at 2023-04-04 21:26:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dnsdist (Old) and /work/SRC/openSUSE:Factory/.dnsdist.new.19717 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dnsdist" Tue Apr 4 21:26:49 2023 rev:4 rq:1077173 version:1.8.0 Changes: -------- --- /work/SRC/openSUSE:Factory/dnsdist/dnsdist.changes 2023-03-22 22:32:34.634777481 +0100 +++ /work/SRC/openSUSE:Factory/.dnsdist.new.19717/dnsdist.changes 2023-04-04 21:26:56.627414903 +0200 @@ -1,0 +2,6 @@ +Thu Mar 30 13:37:37 UTC 2023 - Adam Majer <adam.ma...@suse.de> - 1.8.0 + +- update to 1.8.0 + https://dnsdist.org/changelog.html#change-1.8.0 + +------------------------------------------------------------------- Old: ---- dnsdist-1.8.0-rc3.tar.bz2 dnsdist-1.8.0-rc3.tar.bz2.sig New: ---- dnsdist-1.8.0.tar.bz2 dnsdist-1.8.0.tar.bz2.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dnsdist.spec ++++++ --- /var/tmp/diff_new_pack.iA1J83/_old 2023-04-04 21:26:57.167417968 +0200 +++ /var/tmp/diff_new_pack.iA1J83/_new 2023-04-04 21:26:57.175418013 +0200 @@ -35,17 +35,15 @@ %bcond_with dnsdist_re2 %endif -%define file_version 1.8.0-rc3 - Name: dnsdist -Version: 1.8.0~rc3 +Version: 1.8.0 Release: 0 License: GPL-2.0-only Summary: A highly DNS-, DoS- and abuse-aware loadbalancer URL: http://www.powerdns.com/ Group: Productivity/Networking/DNS/Servers -Source0: https://downloads.powerdns.com/releases/dnsdist-%{file_version}.tar.bz2 -Source1: https://downloads.powerdns.com/releases/dnsdist-%{file_version}.tar.bz2.sig +Source0: https://downloads.powerdns.com/releases/dnsdist-%{version}.tar.bz2 +Source1: https://downloads.powerdns.com/releases/dnsdist-%{version}.tar.bz2.sig Source2: https://dnsdist.org/_static/dnsdist-keyblock.asc#/dnsdist.keyring Source10: dnsdist.user Source11: dnsdist.lua @@ -91,7 +89,7 @@ runtime, and that its statistics can be queried from a console-like interface. %prep -%autosetup -p1 -n %name-%file_version +%autosetup -p1 -n %name-%version %build export CFLAGS="%{optflags} -Wno-error=deprecated-declarations" ++++++ dnsdist-1.8.0-rc3.tar.bz2 -> dnsdist-1.8.0.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/configure new/dnsdist-1.8.0/configure --- old/dnsdist-1.8.0-rc3/configure 2023-03-15 13:57:30.000000000 +0100 +++ new/dnsdist-1.8.0/configure 2023-03-28 13:07:31.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for dnsdist 1.8.0-rc3. +# Generated by GNU Autoconf 2.69 for dnsdist 1.8.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ # Identity of this package. PACKAGE_NAME='dnsdist' PACKAGE_TARNAME='dnsdist' -PACKAGE_VERSION='1.8.0-rc3' -PACKAGE_STRING='dnsdist 1.8.0-rc3' +PACKAGE_VERSION='1.8.0' +PACKAGE_STRING='dnsdist 1.8.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1585,7 +1585,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures dnsdist 1.8.0-rc3 to adapt to many kinds of systems. +\`configure' configures dnsdist 1.8.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1656,7 +1656,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dnsdist 1.8.0-rc3:";; + short | recursive ) echo "Configuration of dnsdist 1.8.0:";; esac cat <<\_ACEOF @@ -1870,7 +1870,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dnsdist configure 1.8.0-rc3 +dnsdist configure 1.8.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2542,7 +2542,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dnsdist $as_me 1.8.0-rc3, which was +It was created by dnsdist $as_me 1.8.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3408,7 +3408,7 @@ # Define the identity of the package. PACKAGE='dnsdist' - VERSION='1.8.0-rc3' + VERSION='1.8.0' cat >>confdefs.h <<_ACEOF @@ -25866,7 +25866,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by dnsdist $as_me 1.8.0-rc3, which was +This file was extended by dnsdist $as_me 1.8.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -25932,7 +25932,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -dnsdist config.status 1.8.0-rc3 +dnsdist config.status 1.8.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/configure.ac new/dnsdist-1.8.0/configure.ac --- old/dnsdist-1.8.0-rc3/configure.ac 2023-03-15 13:57:21.000000000 +0100 +++ new/dnsdist-1.8.0/configure.ac 2023-03-28 13:07:22.000000000 +0200 @@ -1,6 +1,6 @@ AC_PREREQ([2.69]) -AC_INIT([dnsdist], [1.8.0-rc3]) +AC_INIT([dnsdist], [1.8.0]) AM_INIT_AUTOMAKE([foreign tar-ustar dist-bzip2 no-dist-gzip parallel-tests 1.11 subdir-objects]) AM_SILENT_RULES([yes]) AC_CONFIG_MACRO_DIR([m4]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/dnsdist-cache.cc new/dnsdist-1.8.0/dnsdist-cache.cc --- old/dnsdist-1.8.0-rc3/dnsdist-cache.cc 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/dnsdist-cache.cc 2023-03-28 13:06:46.000000000 +0200 @@ -296,7 +296,8 @@ if (!d_dontAge && !skipAging) { if (!stale) { // coverity[store_truncates_time_t] - ageDNSPacket(reinterpret_cast<char *>(&response[0]), response.size(), age); + dnsheader_aligned dh_aligned(response.data()); + ageDNSPacket(reinterpret_cast<char *>(&response[0]), response.size(), age, dh_aligned); } else { editDNSPacketTTL(reinterpret_cast<char*>(&response[0]), response.size(), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/dnsdist-lua-rules.cc new/dnsdist-1.8.0/dnsdist-lua-rules.cc --- old/dnsdist-1.8.0-rc3/dnsdist-lua-rules.cc 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/dnsdist-lua-rules.cc 2023-03-28 13:06:46.000000000 +0200 @@ -67,7 +67,7 @@ return getUniqueID(id); } -void parseRuleParams(boost::optional<luaruleparams_t> params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder) +void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder) { static uint64_t s_creationOrder = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/dnsdist-lua.hh new/dnsdist-1.8.0/dnsdist-lua.hh --- old/dnsdist-1.8.0-rc3/dnsdist-lua.hh 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/dnsdist-lua.hh 2023-03-28 13:06:46.000000000 +0200 @@ -161,7 +161,7 @@ using nmts_t = NetmaskTree<DynBlock, AddressAndPortRange>; std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var); -void parseRuleParams(boost::optional<luaruleparams_t> params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder); +void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder); void checkParameterBound(const std::string& parameter, uint64_t value, size_t max = std::numeric_limits<uint16_t>::max()); vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/dnsdist-secpoll.hh new/dnsdist-1.8.0/dnsdist-secpoll.hh --- old/dnsdist-1.8.0-rc3/dnsdist-secpoll.hh 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/dnsdist-secpoll.hh 2023-03-28 13:06:46.000000000 +0200 @@ -25,6 +25,7 @@ #ifndef DISABLE_SECPOLL #include <string> +#include <ctime> extern std::string g_secPollSuffix; extern time_t g_secPollInterval; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/dnsdist.1 new/dnsdist-1.8.0/dnsdist.1 --- old/dnsdist-1.8.0-rc3/dnsdist.1 2023-03-15 13:57:59.000000000 +0100 +++ new/dnsdist-1.8.0/dnsdist.1 2023-03-28 13:08:02.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "DNSDIST" "1" "Mar 15, 2023" "" "dnsdist" +.TH "DNSDIST" "1" "Mar 28, 2023" "" "dnsdist" .SH NAME dnsdist \- A DNS and DoS aware, scriptable loadbalancer .SH SYNOPSIS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/dnsparser.cc new/dnsdist-1.8.0/dnsparser.cc --- old/dnsdist-1.8.0-rc3/dnsparser.cc 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/dnsparser.cc 2023-03-28 13:06:46.000000000 +0200 @@ -73,7 +73,7 @@ return str.str(); } -void UnknownRecordContent::toPacket(DNSPacketWriter& pw) +void UnknownRecordContent::toPacket(DNSPacketWriter& pw) const { pw.xfrBlob(string(d_record.begin(),d_record.end())); } @@ -211,7 +211,7 @@ rr.qname = d.d_name; rr.qtype = QType(d.d_type); rr.ttl = d.d_ttl; - rr.content = d.d_content->getZoneRepresentation(true); + rr.content = d.getContent()->getZoneRepresentation(true); rr.auth = false; rr.qclass = d.d_class; return rr; @@ -279,11 +279,11 @@ !(d_qtype == QType::IXFR && dr.d_place == DNSResourceRecord::AUTHORITY && dr.d_type == QType::SOA) && // IXFR queries have a SOA in their AUTHORITY section (dr.d_place == DNSResourceRecord::ANSWER || dr.d_place == DNSResourceRecord::AUTHORITY || (dr.d_type != QType::OPT && dr.d_type != QType::TSIG && dr.d_type != QType::SIG && dr.d_type != QType::TKEY) || ((dr.d_type == QType::TSIG || dr.d_type == QType::SIG || dr.d_type == QType::TKEY) && dr.d_class != QClass::ANY))) { // cerr<<"discarding RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl; - dr.d_content=std::make_shared<UnknownRecordContent>(dr, pr); + dr.setContent(std::make_shared<UnknownRecordContent>(dr, pr)); } else { // cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl; - dr.d_content=DNSRecordContent::mastermake(dr, pr, d_header.opcode); + dr.setContent(DNSRecordContent::mastermake(dr, pr, d_header.opcode)); } /* XXX: XPF records should be allowed after TSIG as soon as the actual XPF option code has been assigned: @@ -925,47 +925,45 @@ } // method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it -void ageDNSPacket(char* packet, size_t length, uint32_t seconds) +void ageDNSPacket(char* packet, size_t length, uint32_t seconds, const dnsheader_aligned& aligned_dh) { - if(length < sizeof(dnsheader)) + if (length < sizeof(dnsheader)) { return; - try - { - const dnsheader* dh = reinterpret_cast<const dnsheader*>(packet); - const uint64_t dqcount = ntohs(dh->qdcount); - const uint64_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); + } + try { + const dnsheader* dhp = aligned_dh.get(); + const uint64_t dqcount = ntohs(dhp->qdcount); + const uint64_t numrecords = ntohs(dhp->ancount) + ntohs(dhp->nscount) + ntohs(dhp->arcount); DNSPacketMangler dpm(packet, length); - uint64_t n; - for(n=0; n < dqcount; ++n) { + for (uint64_t rec = 0; rec < dqcount; ++rec) { dpm.skipDomainName(); /* type and class */ dpm.skipBytes(4); } - // cerr<<"Skipped "<<n<<" questions, now parsing "<<numrecords<<" records"<<endl; - for(n=0; n < numrecords; ++n) { + + for(uint64_t rec = 0; rec < numrecords; ++rec) { dpm.skipDomainName(); uint16_t dnstype = dpm.get16BitInt(); /* class */ dpm.skipBytes(2); - if(dnstype == QType::OPT) // not aging that one with a stick - break; - - dpm.decreaseAndSkip32BitInt(seconds); + if (dnstype != QType::OPT) { // not aging that one with a stick + dpm.decreaseAndSkip32BitInt(seconds); + } else { + dpm.skipBytes(4); + } dpm.skipRData(); } } - catch(...) - { - return; + catch(...) { } } -void ageDNSPacket(std::string& packet, uint32_t seconds) +void ageDNSPacket(std::string& packet, uint32_t seconds, const dnsheader_aligned& aligned_dh) { - ageDNSPacket((char*)packet.c_str(), packet.length(), seconds); + ageDNSPacket(packet.data(), packet.length(), seconds, aligned_dh); } uint32_t getDNSPacketMinTTL(const char* packet, size_t length, bool* seenAuthSOA) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/dnsparser.hh new/dnsdist-1.8.0/dnsparser.hh --- old/dnsdist-1.8.0-rc3/dnsparser.hh 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/dnsparser.hh 2023-03-28 13:06:46.000000000 +0200 @@ -199,9 +199,9 @@ virtual std::string getZoneRepresentation(bool noDot=false) const = 0; virtual ~DNSRecordContent() {} - virtual void toPacket(DNSPacketWriter& pw)=0; + virtual void toPacket(DNSPacketWriter& pw) const = 0; // returns the wire format of the content, possibly including compressed pointers pointing to the owner name (unless canonic or lowerCase are set) - virtual string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard because we use the same method (xfrPacket) for both kinds of conversion (fromPacket, toPacket) + string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) const { vector<uint8_t> packet; DNSPacketWriter pw(packet, g_rootdnsname, 1); @@ -312,7 +312,9 @@ d_place(place) {} DNSName d_name; - std::shared_ptr<DNSRecordContent> d_content; +private: + std::shared_ptr<const DNSRecordContent> d_content; +public: uint16_t d_type{}; uint16_t d_class{}; uint32_t d_ttl{}; @@ -331,6 +333,21 @@ return s.str(); } + void setContent(const std::shared_ptr<const DNSRecordContent>& content) + { + d_content = content; + } + + void setContent(std::shared_ptr<const DNSRecordContent>&& content) + { + d_content = std::move(content); + } + + [[nodiscard]] const std::shared_ptr<const DNSRecordContent>& getContent() const + { + return d_content; + } + bool operator<(const DNSRecord& rhs) const { if(std::tie(d_name, d_type, d_class, d_ttl) < std::tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl)) @@ -416,7 +433,7 @@ UnknownRecordContent(const string& zone); string getZoneRepresentation(bool noDot) const override; - void toPacket(DNSPacketWriter& pw) override; + void toPacket(DNSPacketWriter& pw) const override; uint16_t getType() const override { return d_dr.d_type; @@ -471,8 +488,8 @@ }; string simpleCompress(const string& label, const string& root=""); -void ageDNSPacket(char* packet, size_t length, uint32_t seconds); -void ageDNSPacket(std::string& packet, uint32_t seconds); +void ageDNSPacket(char* packet, size_t length, uint32_t seconds, const dnsheader_aligned&); +void ageDNSPacket(std::string& packet, uint32_t seconds, const dnsheader_aligned&); void editDNSPacketTTL(char* packet, size_t length, const std::function<uint32_t(uint8_t, uint16_t, uint16_t, uint32_t)>& visitor); void clearDNSPacketRecordTypes(vector<uint8_t>& packet, const std::unordered_set<QType>& qtypes); void clearDNSPacketRecordTypes(PacketBuffer& packet, const std::unordered_set<QType>& qtypes); @@ -486,9 +503,9 @@ bool visitDNSPacket(const std::string_view& packet, const std::function<bool(uint8_t, uint16_t, uint16_t, uint32_t, uint16_t, const char*)>& visitor); template<typename T> -std::shared_ptr<T> getRR(const DNSRecord& dr) +std::shared_ptr<const T> getRR(const DNSRecord& dr) { - return std::dynamic_pointer_cast<T>(dr.d_content); + return std::dynamic_pointer_cast<const T>(dr.getContent()); } /** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/ext/lmdb-safe/lmdb-safe.cc new/dnsdist-1.8.0/ext/lmdb-safe/lmdb-safe.cc --- old/dnsdist-1.8.0-rc3/ext/lmdb-safe/lmdb-safe.cc 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/ext/lmdb-safe/lmdb-safe.cc 2023-03-28 13:06:46.000000000 +0200 @@ -6,6 +6,10 @@ #include <string.h> #include <map> +#ifndef DNSDIST +#include "../../pdns/gettime.hh" +#endif + using std::string; using std::runtime_error; using std::tuple; @@ -16,6 +20,59 @@ return mdb_strerror(rc); } +#ifndef DNSDIST + +namespace LMDBLS { + // this also returns a pointer to the string's data. Do not hold on to it too long! + const LSheader* LSassertFixedHeaderSize(std::string_view val) { + // cerr<<"val.size()="<<val.size()<<endl; + if (val.size() < LS_MIN_HEADER_SIZE) { + throw std::runtime_error("LSheader too short"); + } + + return reinterpret_cast<const LSheader*>(val.data()); + } + + size_t LScheckHeaderAndGetSize(std::string_view val, size_t datasize) { + const LSheader* lsh = LSassertFixedHeaderSize(val); + + if (lsh->d_version != 0) { + throw std::runtime_error("LSheader has wrong version (not zero)"); + } + + size_t headersize = LS_MIN_HEADER_SIZE; + + unsigned char* tmp = (unsigned char*)val.data(); + uint16_t numextra = (tmp[LS_NUMEXTRA_OFFSET] << 8) + tmp[LS_NUMEXTRA_OFFSET+1]; + + headersize += numextra * LS_BLOCK_SIZE; + + if (val.size() < headersize) { + throw std::runtime_error("LSheader too short for promised extra data"); + } + + if (datasize && val.size() < (headersize+datasize)) { + throw std::runtime_error("Trailing data after LSheader has wrong size"); + } + + return headersize; + } + + size_t LScheckHeaderAndGetSize(const MDBOutVal *val, size_t datasize) { + return LScheckHeaderAndGetSize(val->getNoStripHeader<string_view>(), datasize); + } + + bool LSisDeleted(std::string_view val) { + const LSheader* lsh = LSassertFixedHeaderSize(val); + + return (lsh->d_flags & LS_FLAG_DELETED) != 0; + } + + bool s_flag_deleted{false}; +} + +#endif /* #ifndef DNSDIST */ + MDBDbi::MDBDbi(MDB_env* env, MDB_txn* txn, const string_view dbname, int flags) { // A transaction that uses this function must finish (either commit or abort) before any other transaction in the process may use this function. @@ -184,6 +241,13 @@ MDBRWTransactionImpl::MDBRWTransactionImpl(MDBEnv* parent, int flags): MDBRWTransactionImpl(parent, openRWTransaction(parent, nullptr, flags)) { +#ifndef DNSDIST + struct timespec tp; + + gettime(&tp, true); + + d_txtime = tp.tv_sec * (1000 * 1000 * 1000) + tp.tv_nsec; +#endif } MDBRWTransactionImpl::~MDBRWTransactionImpl() @@ -301,9 +365,10 @@ MDB_cursor *cursor; int rc= mdb_cursor_open(d_txn, dbi, &cursor); if(rc) { - throw std::runtime_error("Error creating RO cursor: "+std::string(mdb_strerror(rc))); + throw std::runtime_error("Error creating RW cursor: "+std::string(mdb_strerror(rc))); } - return MDBRWCursor(d_rw_cursors, cursor); + + return MDBRWCursor(d_rw_cursors, cursor, d_txn, d_txtime); } MDBRWCursor MDBRWTransactionImpl::getCursor(const MDBDbi &dbi) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/ext/lmdb-safe/lmdb-safe.hh new/dnsdist-1.8.0/ext/lmdb-safe/lmdb-safe.hh --- old/dnsdist-1.8.0-rc3/ext/lmdb-safe/lmdb-safe.hh 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/ext/lmdb-safe/lmdb-safe.hh 2023-03-28 13:06:46.000000000 +0200 @@ -13,6 +13,16 @@ #include <vector> #include <algorithm> +#include "config.h" + +#ifndef DNSDIST +#include <boost/range/detail/common.hpp> +#include <stdint.h> +#include <netinet/in.h> +#include <stdexcept> +#include "../../pdns/misc.hh" +#endif + using std::string_view; /* open issues: @@ -90,6 +100,67 @@ std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, int flags, int mode, uint64_t mapsizeMB=(sizeof(void *)==4) ? 100 : 16000); +#ifndef DNSDIST + +#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || !defined(__ORDER_BIG_ENDIAN__) +#error "your compiler did not define byte order macros" +#endif + +// FIXME do something more portable than __builtin_bswap64 +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define _LMDB_SAFE_BSWAP64MAYBE(x) __builtin_bswap64(x) +#else +#define _LMDB_SAFE_BSWAP64MAYBE(x) (x) +#endif + +struct MDBOutVal; // forward declaration because of how the functions below tie in with MDBOutVal + +namespace LMDBLS { + class __attribute__((__packed__)) LSheader { + public: + uint64_t d_timestamp; + uint64_t d_txnid; + uint8_t d_version; + uint8_t d_flags; + uint32_t d_reserved; + uint16_t d_numextra; + + LSheader(uint64_t timestamp, uint64_t txnid, uint8_t flags=0, uint8_t version=0, uint8_t numextra=0): + d_timestamp(_LMDB_SAFE_BSWAP64MAYBE(timestamp)), + d_txnid(_LMDB_SAFE_BSWAP64MAYBE(txnid)), + d_version(version), + d_flags(flags), + d_reserved(0), + d_numextra(htons(numextra)) + { + + } + + std::string toString() { + return std::string((char*)this, sizeof(*this)) + std::string(ntohs(d_numextra)*8, '\0'); + } + + + }; + + static_assert(sizeof(LSheader)==24, "LSheader size is wrong"); + + const size_t LS_MIN_HEADER_SIZE = sizeof(LSheader); + const size_t LS_BLOCK_SIZE = 8; + const size_t LS_NUMEXTRA_OFFSET = 22; + const uint8_t LS_FLAG_DELETED = 0x01; + + const LSheader* LSassertFixedHeaderSize(std::string_view val); + size_t LScheckHeaderAndGetSize(std::string_view val, size_t datasize=0); + size_t LScheckHeaderAndGetSize(const MDBOutVal *val, size_t datasize=0); + bool LSisDeleted(std::string_view val); + + extern bool s_flag_deleted; +} + +#undef _LMDB_SAFE_BSWAP64MAYBE + +#endif /* ifndef DNSDIST */ struct MDBOutVal @@ -99,54 +170,80 @@ return d_mdbval; } +#ifndef DNSDIST template <class T, - typename std::enable_if<std::is_arithmetic<T>::value, + typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> const T get() { T ret; - if(d_mdbval.mv_size != sizeof(T)) - throw std::runtime_error("MDB data has wrong length for type"); - memcpy(&ret, d_mdbval.mv_data, sizeof(T)); + size_t offset = LMDBLS::LScheckHeaderAndGetSize(this, sizeof(T)); + + memcpy(&ret, reinterpret_cast<const char *>(d_mdbval.mv_data)+offset, sizeof(T)); + + static_assert(sizeof(T) == 4, "this code currently only supports 32 bit integers"); + ret = ntohl(ret); return ret; } template <class T, - typename std::enable_if<std::is_class<T>::value,T>::type* = nullptr> - T get() const; - - template<class T> - T get_struct() const + typename std::enable_if<std::is_integral<T>::value, + T>::type* = nullptr> const + T getNoStripHeader() { T ret; if(d_mdbval.mv_size != sizeof(T)) throw std::runtime_error("MDB data has wrong length for type"); memcpy(&ret, d_mdbval.mv_data, sizeof(T)); + + static_assert(sizeof(T) == 4, "this code currently only supports 32 bit integers"); + ret = ntohl(ret); return ret; } - template<class T> - const T* get_struct_ptr() const - { - if(d_mdbval.mv_size != sizeof(T)) - throw std::runtime_error("MDB data has wrong length for type"); +#endif /* ifndef DNSDIST */ - return reinterpret_cast<const T*>(d_mdbval.mv_data); - } + template <class T, + typename std::enable_if<std::is_class<T>::value,T>::type* = nullptr> + T get() const; +#ifndef DNSDIST + template <class T, + typename std::enable_if<std::is_class<T>::value,T>::type* = nullptr> + T getNoStripHeader() const; +#endif + MDB_val d_mdbval; }; template<> inline std::string MDBOutVal::get<std::string>() const { +#ifndef DNSDIST + size_t offset = LMDBLS::LScheckHeaderAndGetSize(this); + + return std::string((char*)d_mdbval.mv_data+offset, d_mdbval.mv_size-offset); +} + +template<> inline std::string MDBOutVal::getNoStripHeader<std::string>() const +{ +#endif return std::string((char*)d_mdbval.mv_data, d_mdbval.mv_size); } template<> inline string_view MDBOutVal::get<string_view>() const { +#ifndef DNSDIST + size_t offset = LMDBLS::LScheckHeaderAndGetSize(this); + + return string_view((char*)d_mdbval.mv_data+offset, d_mdbval.mv_size-offset); +} + +template<> inline string_view MDBOutVal::getNoStripHeader<string_view>() const +{ +#endif return string_view((char*)d_mdbval.mv_data, d_mdbval.mv_size); } @@ -157,15 +254,20 @@ { } +#ifndef DNSDIST template <class T, - typename std::enable_if<std::is_arithmetic<T>::value, + typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr> MDBInVal(T i) { - memcpy(&d_memory[0], &i, sizeof(i)); + static_assert(sizeof(T) == 4, "this code currently only supports 32 bit integers"); + auto j = htonl(i); // all actual usage in our codebase is 32 bits. If that ever changes, this will break the build and avoid runtime surprises + memcpy(&d_memory[0], &j, sizeof(j)); + d_mdbval.mv_size = sizeof(T); d_mdbval.mv_data = d_memory;; } +#endif MDBInVal(const char* s) { @@ -202,13 +304,11 @@ MDB_val d_mdbval; private: MDBInVal(){} +#ifndef DNSDIST char d_memory[sizeof(double)]; - +#endif }; - - - class MDBROCursor; class MDBROTransactionImpl @@ -249,8 +349,19 @@ int rc = mdb_get(d_txn, dbi, const_cast<MDB_val*>(&key.d_mdbval), const_cast<MDB_val*>(&val.d_mdbval)); - if(rc && rc != MDB_NOTFOUND) + + if(rc && rc != MDB_NOTFOUND) { throw std::runtime_error("getting data: " + std::string(mdb_strerror(rc))); + } + +#ifndef DNSDIST + if(rc != MDB_NOTFOUND) { // key was found, value was retrieved + std::string sval = val.getNoStripHeader<std::string>(); + if (LMDBLS::LSisDeleted(sval)) { // but it was deleted + rc = MDB_NOTFOUND; + } + } +#endif return rc; } @@ -301,18 +412,23 @@ private: std::vector<T*> *d_registry; MDB_cursor* d_cursor{nullptr}; - public: + MDB_txn* d_txn{nullptr}; // ew, public + uint64_t d_txtime{0}; + MDBGenCursor(): d_registry(nullptr), - d_cursor(nullptr) + d_cursor(nullptr), + d_txn(nullptr) { } - MDBGenCursor(std::vector<T*> ®istry, MDB_cursor *cursor): + MDBGenCursor(std::vector<T*> ®istry, MDB_cursor *cursor, MDB_txn *txn=nullptr, uint64_t txtime=0): d_registry(®istry), - d_cursor(cursor) + d_cursor(cursor), + d_txn(txn), + d_txtime(txtime) { registry.emplace_back(static_cast<T*>(this)); } @@ -363,13 +479,101 @@ close(); } + /* + to support (skip) entries marked deleted=1 in the LS header, we need to do some magic here + this table notes, for each cursor op: + * the maximum number of entries we may need to look at (1 or inf) + * the subsequent op that needs to be done to skip over a deleted entry (or MDB_NOTFOUND to give up and say no) + (table partially copied from http://www.lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127 which I hope is a stable URL) + (ops only relevant for DUPSORT/DUPFIXED have been omitted) + (table is grouped by "skip op") + + | base op | maxentries | skip op | doc description of base op + | MDB_FIRST | inf | MDB_NEXT | Position at first key/data item + | MDB_NEXT | inf | MDB_NEXT | Position at next data item + | MDB_SET_RANGE | inf | MDB_NEXT | Position at first key greater than or equal to specified key. + | MDB_LAST | inf | MDB_PREV | Position at last key/data item + | MDB_PREV | inf | MDB_PREV | Position at previous data item + | MDB_GET_CURRENT | 1 | MDB_NOTFOUND | Return key/data at current cursor position + | MDB_SET | 1 | MDB_NOTFOUND | Position at specified key + | MDB_SET_KEY | 1 | MDB_NOTFOUND | Position at specified key, return key + data + */ + +private: + int skipDeleted(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op, int rc) + { +#ifndef DNSDIST + // when we get here + // * mdb_cursor_get has been called once + // * it did not return an error, but it might have returned MDB_NOTFOUND + // * if it returned MDB_NOTFOUND, there is nothing for us to do and we pass that on + + if (rc == MDB_NOTFOUND) { + return rc; + } + + // when we get here + // * mdb_cursor_get has been called at least once + // * it found an entry, as far as LMDB is concerned, so key+data contain something + // * but that might be a LS deleted=1 entry + // * we know the cursor op that got us here + + while (true) { + auto sval = data.getNoStripHeader<std::string_view>(); + + if (!LMDBLS::LSisDeleted(sval)) { + // done! + + return rc; + } + + // the found entry is set deleted, so we need to do something + + // if this was a 1-entry op, this is the end + if (op == MDB_GET_CURRENT || op == MDB_SET || op == MDB_SET_KEY) { + return MDB_NOTFOUND; + } + + // otherwise, we need to try to carry on + // all ops that do not map to NOTFOUND map to NEXT or PREV, including NEXT and PREV themselves + // so we just override the op to NEXT or PREV + if (op == MDB_FIRST || op == MDB_NEXT || op == MDB_SET_RANGE) { + op = MDB_NEXT; + } + else if (op == MDB_LAST || op == MDB_PREV) { + op = MDB_PREV; + } + else { + throw std::runtime_error("got unsupported mdb cursor op"); + } + + rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op); + if(rc && rc != MDB_NOTFOUND) { + throw std::runtime_error("Unable to get from cursor: " + std::string(mdb_strerror(rc))); + } + + if (rc == MDB_NOTFOUND) { + // we ended up finding nothing, so tell the caller + return rc; + } + + // when we get here + // * the situation is just like the last time I wrote "when we get here" + // * except mdb_cursor_get has been called at least twice + // * so let's go back + } +#else /* ifndef DNSDIST */ + return rc; +#endif + } + public: int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op) { int rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op); if(rc && rc != MDB_NOTFOUND) throw std::runtime_error("Unable to get from cursor: " + std::string(mdb_strerror(rc))); - return rc; + return skipDeleted(key, data, op, rc); } int find(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) @@ -378,7 +582,7 @@ int rc=mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET); if(rc && rc != MDB_NOTFOUND) throw std::runtime_error("Unable to find from cursor: " + std::string(mdb_strerror(rc))); - return rc; + return skipDeleted(key, data, MDB_SET, rc); } int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) @@ -388,7 +592,7 @@ int rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET_RANGE); if(rc && rc != MDB_NOTFOUND) throw std::runtime_error("Unable to lower_bound from cursor: " + std::string(mdb_strerror(rc))); - return rc; + return skipDeleted(key, data, MDB_SET_RANGE, rc); } @@ -397,7 +601,7 @@ int rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, op); if(rc && rc != MDB_NOTFOUND) throw std::runtime_error("Unable to prevnext from cursor: " + std::string(mdb_strerror(rc))); - return rc; + return skipDeleted(key, data, op, rc); } int next(MDBOutVal& key, MDBOutVal& data) @@ -415,7 +619,7 @@ int rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, op); if(rc && rc != MDB_NOTFOUND) throw std::runtime_error("Unable to next from cursor: " + std::string(mdb_strerror(rc))); - return rc; + return skipDeleted(key, data, op, rc); } int current(MDBOutVal& key, MDBOutVal& data) @@ -485,6 +689,8 @@ private: std::vector<MDBRWCursor*> d_rw_cursors; + uint64_t d_txtime{0}; + void closeRWCursors(); inline void closeRORWCursors() { closeROCursors(); @@ -506,26 +712,41 @@ void clear(MDB_dbi dbi); +#ifndef DNSDIST void put(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, int flags=0) { if(!d_txn) throw std::runtime_error("Attempt to use a closed RW transaction for put"); int rc; + + size_t txid = mdb_txn_id(d_txn); + + if (d_txtime == 0) { throw std::runtime_error("got zero txtime"); } + + std::string ins = + LMDBLS::LSheader(d_txtime, txid).toString()+ + std::string((const char*)val.d_mdbval.mv_data, val.d_mdbval.mv_size); + + MDBInVal pval = ins; + if((rc=mdb_put(d_txn, dbi, const_cast<MDB_val*>(&key.d_mdbval), - const_cast<MDB_val*>(&val.d_mdbval), flags))) + const_cast<MDB_val*>(&pval.d_mdbval), flags))) { throw std::runtime_error("putting data: " + std::string(mdb_strerror(rc))); + } } - - - int del(MDBDbi& dbi, const MDBInVal& key, const MDBInVal& val) +#else + void put(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, int flags=0) { + if(!d_txn) + throw std::runtime_error("Attempt to use a closed RW transaction for put"); int rc; - rc=mdb_del(d_txn, dbi, (MDB_val*)&key.d_mdbval, (MDB_val*)&val.d_mdbval); - if(rc && rc != MDB_NOTFOUND) - throw std::runtime_error("deleting data: " + std::string(mdb_strerror(rc))); - return rc; + if((rc=mdb_put(d_txn, dbi, + const_cast<MDB_val*>(&key.d_mdbval), + const_cast<MDB_val*>(&val.d_mdbval), flags))) + throw std::runtime_error("putting data: " + std::string(mdb_strerror(rc))); } +#endif int del(MDBDbi& dbi, const MDBInVal& key) { @@ -533,6 +754,26 @@ rc=mdb_del(d_txn, dbi, (MDB_val*)&key.d_mdbval, 0); if(rc && rc != MDB_NOTFOUND) throw std::runtime_error("deleting data: " + std::string(mdb_strerror(rc))); +#ifndef DNSDIST + if(rc != MDB_NOTFOUND && LMDBLS::s_flag_deleted) { + // if it did exist, we need to mark it as deleted now + + size_t txid = mdb_txn_id(d_txn); + if (d_txtime == 0) { throw std::runtime_error("got zero txtime"); } + + std::string ins = + // std::string((const char*)&txid, sizeof(txid)) + + LMDBLS::LSheader(d_txtime, txid, LMDBLS::LS_FLAG_DELETED).toString(); + + MDBInVal pval = ins; + + if((rc=mdb_put(d_txn, dbi, + const_cast<MDB_val*>(&key.d_mdbval), + const_cast<MDB_val*>(&pval.d_mdbval), 0))) { + throw std::runtime_error("marking data deleted: " + std::string(mdb_strerror(rc))); + } + } +#endif return rc; } @@ -544,17 +785,19 @@ int rc = mdb_get(d_txn, dbi, const_cast<MDB_val*>(&key.d_mdbval), const_cast<MDB_val*>(&val.d_mdbval)); - if(rc && rc != MDB_NOTFOUND) - throw std::runtime_error("getting data: " + std::string(mdb_strerror(rc))); - return rc; - } + if(rc && rc != MDB_NOTFOUND) { + throw std::runtime_error("getting data: " + std::string(mdb_strerror(rc))); + } + +#ifndef DNSDIST + if(rc != MDB_NOTFOUND) { // key was found, value was retrieved + auto sval = val.getNoStripHeader<std::string_view>(); + if (LMDBLS::LSisDeleted(sval)) { // but it was deleted + rc = MDB_NOTFOUND; + } + } +#endif - int get(MDBDbi& dbi, const MDBInVal& key, string_view& val) - { - MDBOutVal out; - int rc = get(dbi, key, out); - if(!rc) - val = out.get<string_view>(); return rc; } @@ -568,6 +811,7 @@ MDBRWTransaction getRWTransaction(); MDBROTransaction getROTransaction(); + }; /* "A cursor in a write-transaction can be closed before its transaction ends, and will otherwise be closed when its transaction ends" @@ -584,27 +828,71 @@ MDBRWCursor &operator=(MDBRWCursor &&src) = default; ~MDBRWCursor() = default; +#ifndef DNSDIST void put(const MDBOutVal& key, const MDBInVal& data) { + size_t txid = mdb_txn_id(this->d_txn); + + if (d_txtime == 0) { throw std::runtime_error("got zero txtime"); } + + std::string ins = + LMDBLS::LSheader(d_txtime, txid).toString()+ + std::string((const char*)data.d_mdbval.mv_data, data.d_mdbval.mv_size); + + MDBInVal pval = ins; + int rc = mdb_cursor_put(*this, const_cast<MDB_val*>(&key.d_mdbval), - const_cast<MDB_val*>(&data.d_mdbval), MDB_CURRENT); + const_cast<MDB_val*>(&pval.d_mdbval), MDB_CURRENT); if(rc) throw std::runtime_error("mdb_cursor_put: " + std::string(mdb_strerror(rc))); } - - - int put(const MDBOutVal& key, const MDBOutVal& data, int flags=0) +#else + void put(const MDBOutVal& key, const MDBInVal& data) { - // XXX check errors - return mdb_cursor_put(*this, - const_cast<MDB_val*>(&key.d_mdbval), - const_cast<MDB_val*>(&data.d_mdbval), flags); + int rc = mdb_cursor_put(*this, + const_cast<MDB_val*>(&key.d_mdbval), + const_cast<MDB_val*>(&data.d_mdbval), MDB_CURRENT); + if(rc) + throw std::runtime_error("mdb_cursor_put: " + std::string(mdb_strerror(rc))); } +#endif +#ifndef DNSDIST int del(int flags=0) { - return mdb_cursor_del(*this, flags); - } + MDBOutVal key, val; + + if (LMDBLS::s_flag_deleted) { + int rc_get = mdb_cursor_get (*this, &key.d_mdbval, &val.d_mdbval, MDB_GET_CURRENT); + if(rc_get) { + throw std::runtime_error("getting key to mark data as deleted: " + std::string(mdb_strerror(rc_get))); + } + + size_t txid = mdb_txn_id(d_txn); + if (d_txtime == 0) { throw std::runtime_error("got zero txtime"); } + + std::string ins = + LMDBLS::LSheader(d_txtime, txid, LMDBLS::LS_FLAG_DELETED).toString(); + + std::string skey((const char*)key.d_mdbval.mv_data, key.d_mdbval.mv_size); + + MDBInVal pkey = MDBInVal(skey); + MDBInVal pval = ins; + + int rc_put = mdb_cursor_put(*this, + const_cast<MDB_val*>(&pkey.d_mdbval), + const_cast<MDB_val*>(&pval.d_mdbval), 0 /* MDB_CURRENT */); + if(rc_put) { + throw std::runtime_error("marking data deleted: " + std::string(mdb_strerror(rc_put))); + } + return rc_put; + } + else { + // do a normal delete + return mdb_cursor_del(*this, flags); + } + } +#endif }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/test-dnsdist-dnsparser.cc new/dnsdist-1.8.0/test-dnsdist-dnsparser.cc --- old/dnsdist-1.8.0-rc3/test-dnsdist-dnsparser.cc 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/test-dnsdist-dnsparser.cc 2023-03-28 13:06:46.000000000 +0200 @@ -194,7 +194,7 @@ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::CNAME)); BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN); BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget); - auto content = std::dynamic_pointer_cast<UnknownRecordContent>(mdp.d_answers.at(0).first.d_content); + auto content = getRR<UnknownRecordContent>(mdp.d_answers.at(0).first); BOOST_REQUIRE(content != nullptr); BOOST_CHECK_EQUAL(content->getRawContent().size(), notTheTarget.getStorage().size()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsdist-1.8.0-rc3/test-dnsparser_cc.cc new/dnsdist-1.8.0/test-dnsparser_cc.cc --- old/dnsdist-1.8.0-rc3/test-dnsparser_cc.cc 2023-03-15 13:56:49.000000000 +0100 +++ new/dnsdist-1.8.0/test-dnsparser_cc.cc 2023-03-28 13:06:46.000000000 +0200 @@ -117,7 +117,8 @@ auto firstPacket = generatePacket(3600); auto expectedAlteredPacket = generatePacket(1800); - ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size(), 1800); + dnsheader_aligned dh_aligned(firstPacket.data()); + ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size(), 1800, dh_aligned); BOOST_REQUIRE_EQUAL(firstPacket.size(), expectedAlteredPacket.size()); for (size_t idx = 0; idx < firstPacket.size(); idx++) { @@ -127,14 +128,14 @@ /* now call it with a truncated packet, missing the last TTL and rdata, the packet should not be altered. */ - ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size() - sizeof(uint32_t) - /* rdata length */ sizeof (uint16_t) - /* IPv4 payload in rdata */ 4 - /* size of OPT record */ 11, 900); + ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size() - sizeof(uint32_t) - /* rdata length */ sizeof (uint16_t) - /* IPv4 payload in rdata */ 4 - /* size of OPT record */ 11, 900, dh_aligned); BOOST_CHECK(firstPacket == expectedAlteredPacket); /* now remove more than the remaining TTL. We expect ageDNSPacket to cap this at zero and not cause an unsigned underflow into the 2^32-1 neighbourhood */ - ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size(), 1801); + ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size(), 1801, dh_aligned); uint32_t ttl = 0;