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*> &registry, MDB_cursor *cursor):
+  MDBGenCursor(std::vector<T*> &registry, MDB_cursor *cursor, MDB_txn 
*txn=nullptr, uint64_t txtime=0):
     d_registry(&registry),
-    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;
 

Reply via email to