• Bug#1108915: unblock: pdns/4.9.7-1 [pre-approval]

    From Chris =?utf-8?Q?Hofst=C3=A4dtler?=@21:1/5 to All on Mon Jul 7 18:10:01 2025
    XPost: linux.debian.devel.release

    Package: release.debian.org
    Severity: normal
    X-Debbugs-Cc: [email protected]
    Control: affects -1 + src:pdns
    User: [email protected]
    Usertags: unblock

    Please unblock package pdns

    pdns 4.9.7 is an upstream bugfix release in the 4.9 series.
    Previously we had 4.9.4; upstream released 4.9.5 (after the freeze
    started) and 4.9.7 (today) - 4.9.6 was skipped.

    I'd like to take the latest upstream release into unstable and
    testing. Have not uploaded it yet.

    [ Reason ]
    Accepting the upstream bugfix release will hopefully make applying
    future security fixes easier, or we can just use a future bugfix
    release for them.

    4.9.5 includes the patch we applied to 4.9.4 to fix tests on s390x.

    [ Impact ]
    If we stay on 4.9.4, the diff for security fixes will be larger and
    thus harder.
    We'll also miss out on upstream bug- and performance-fixes to the LMDB
    backend, better exception handling in Lua functions leading to
    SERVFAILs, an interop fix for TSIG and a compile fix for newer gcc.

    [ Tests ]
    In Debian we only have smoke tests, however they did find the s390x
    mysql issue in the past. Upstream has a big test suite they run for
    releases.

    [ Risks ]
    Not sure. The diff seems right to me for the fixes upstream
    described.

    [ Checklist ]
    [x] all changes are documented in the d/changelog
    [x] I reviewed all changes and I approve them
    [x] attach debdiff against the package in testing

    [ Other info ]

    The attached debdiff was produced using:
    debdiff pdns_4.9.4-2.dsc pdns_4.9.7-1.dsc | filterdiff -x '*.1' > pdns_4.9.7-1.filtered.debdiff
    to exclude the date changes to the xxx.1 manpages.

    unblock pdns/4.9.7-1

    diff -Nru pdns-4.9.4/configure pdns-4.9.7/configure
    --- pdns-4.9.4/configure 2025-02-06 16:18:00.000000000 +0100
    +++ pdns-4.9.7/configure 2025-07-07 09:42:38.000000000 +0200
    @@ -1,6 +1,6 @@
    #! /bin/sh
    # Guess values for system-dependent variables and create Makefiles.
    -# Generated by GNU Autoconf 2.71 for pdns 4.9.4.
    +# Generated by GNU Autoconf 2.71 for pdns 4.9.7.
    #
    #
    # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
    @@ -618,8 +618,8 @@
    # Identity of this package.
    PACKAGE_NAME='pdns'
    PACKAGE_TARNAME='pdns'
    -PACKAGE_VERSION='4.9.4'
    -PACKAGE_STRING='pdns 4.9.4'
    +PACKAGE_VERSION='4.9.7'
    +PACKAGE_STRING='pdns 4.9.7'
    PACKAGE_BUGREPORT=''
    PACKAGE_URL=''

    @@ -1698,7 +1698,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 pdns 4.9.4 to adapt to many kinds of systems. +\`configure' configures pdns 4.9.7 to adapt to many kinds of systems.

    Usage: $0 [OPTION]... [VAR=VALUE
  • From Chris Hofstaedtler@21:1/5 to All on Mon Jul 7 18:30:02 2025
    XPost: linux.debian.devel.release

    On Mon, Jul 07, 2025 at 06:01:12PM +0200, Chris Hofstädtler wrote:
    [ Tests ]

    Maybe it is unnecessary to ask for a preapproval/unblock, but I
    can't make sense of https://ci.debian.net/packages/p/pdns/
    For the archs where there are no bins (armel, armhf, i386), do these
    "n/a fail" tests count as failing or successful for migration?

    Chris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sebastian Ramacher@21:1/5 to All on Tue Jul 8 08:10:01 2025
    XPost: linux.debian.devel.release

    Control: tags -1 moreinfo

    On 2025-07-07 18:01:12 +0200, Chris Hofstädtler wrote:
    Package: release.debian.org
    Severity: normal
    X-Debbugs-Cc: [email protected]
    Control: affects -1 + src:pdns
    User: [email protected]
    Usertags: unblock

    Please unblock package pdns

    pdns 4.9.7 is an upstream bugfix release in the 4.9 series.
    Previously we had 4.9.4; upstream released 4.9.5 (after the freeze
    started) and 4.9.7 (today) - 4.9.6 was skipped.

    Is there a summary of the changes from 4.9.4 to 4.9.7 somewhere? Or
    could you provide a short summary of those changes?

    Cheers


    I'd like to take the latest upstream release into unstable and
    testing. Have not uploaded it yet.

    [ Reason ]
    Accepting the upstream bugfix release will hopefully make applying
    future security fixes easier, or we can just use a future bugfix
    release for them.

    4.9.5 includes the patch we applied to 4.9.4 to fix tests on s390x.

    [ Impact ]
    If we stay on 4.9.4, the diff for security fixes will be larger and
    thus harder.
    We'll also miss out on upstream bug- and performance-fixes to the LMDB backend, better exception handling in Lua functions leading to
    SERVFAILs, an interop fix for TSIG and a compile fix for newer gcc.

    [ Tests ]
    In Debian we only have smoke tests, however they did find the s390x
    mysql issue in the past. Upstream has a big test suite they run for
    releases.

    [ Risks ]
    Not sure. The diff seems right to me for the fixes upstream
    described.

    [ Checklist ]
    [x] all changes are documented in the d/changelog
    [x] I reviewed all changes and I approve them
    [x] attach debdiff against the package in testing

    [ Other info ]

    The attached debdiff was produced using:
    debdiff pdns_4.9.4-2.dsc pdns_4.9.7-1.dsc | filterdiff -x '*.1' > pdns_4.9.7-1.filtered.debdiff
    to exclude the date changes to the xxx.1 manpages.

    unblock pdns/4.9.7-1

    diff -Nru pdns-4.9.4/configure pdns-4.9.7/configure
    --- pdns-4.9.4/configure 2025-02-06 16:18:00.000000000 +0100
    +++ pdns-4.9.7/configure 2025-07-07 09:42:38.000000000 +0200
    @@ -1,6 +1,6 @@
    #! /bin/sh
    # Guess values for system-dependent variables and create Makefiles.
    -# Generated by GNU Autoconf 2.71 for pdns 4.9.4.
    +# Generated by GNU Autoconf 2.71 for pdns 4.9.7.
    #
    #
    # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
    @@ -618,8 +618,8 @@
    # Identity of this package.
    PACKAGE_NAME='pdns'
    PACKAGE_TARNAME='pdns'
    -PACKAGE_VERSION='4.9.4'
    -PACKAGE_STRING='pdns 4.9.4'
    +PACKAGE_VERSION='4.9.7'
    +PACKAGE_STRING='pdns 4.9.7'
    PACKAGE_BUGREPORT=''
    PACKAGE_URL=''

    @@ -1698,7 +1698,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 pdns 4.9.4 to adapt to many kinds of systems. +\`configure' configures pdns 4.9.7 to adapt to many kinds of systems.

    Usage: $0 [OPTION]... [VAR=VALUE]...

    @@ -1769,7 +1769,7 @@

    if test -n "$ac_init_help"; then
    case $ac_init_help in
    - short | recursive ) echo "Configuration of pdns 4.9.4:";;
    + short | recursive ) echo "Configuration of pdns 4.9.7:";;
    esac
    cat <<\_ACEOF

    @@ -2040,7 +2040,7 @@
    test -n "$ac_init_help" && exit $ac_status
    if $ac_init_version; then
    cat <<\_ACEOF
    -pdns configure 4.9.4
    +pdns configure 4.9.7
    generated by GNU Autoconf 2.71

    Copyright (C) 2021 Free Software Foundation, Inc.
    @@ -2529,7 +2529,7 @@
    This file contains any messages produced by compilers while
    running configure, to aid debugging if configure makes a mistake.

    -It was created by pdns $as_me 4.9.4, which was
    +It was created by pdns $as_me 4.9.7, which was
    generated by GNU Autoconf 2.71. Invocation command line was

    $ $0$ac_configure_args_raw
    @@ -4027,7 +4027,7 @@

    # Define the identity of the package.
    PACKAGE='pdns'
    - VERSION='4.9.4'
    + VERSION='4.9.7'


    printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
    @@ -32467,7 +32467,7 @@
    # report actual input values of CONFIG_FILES etc. instead of their
    # values after options handling.
    ac_log="
    -This file was extended by pdns $as_me 4.9.4, which was
    +This file was extended by pdns $as_me 4.9.7, which was
    generated by GNU Autoconf 2.71. Invocation command line was

    CONFIG_FILES = $CONFIG_FILES
    @@ -32535,7 +32535,7 @@
    cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
    ac_cs_config='$ac_cs_config_escaped'
    ac_cs_version="\\
    -pdns config.status 4.9.4
    +pdns config.status 4.9.7
    configured by $0, generated by GNU Autoconf 2.71,
    with options \\"\$ac_cs_config\\"

    diff -Nru pdns-4.9.4/configure.ac pdns-4.9.7/configure.ac
    --- pdns-4.9.4/configure.ac 2025-02-06 16:17:52.000000000 +0100
    +++ pdns-4.9.7/configure.ac 2025-07-07 09:42:29.000000000 +0200
    @@ -1,6 +1,6 @@
    AC_PREREQ([2.69])

    -AC_INIT([pdns], [4.9.4])
    +AC_INIT([pdns], [4.9.7])
    AC_CONFIG_AUX_DIR([build-aux])
    AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip tar-ustar -Wno-portability subdir-objects parallel-tests 1.11])
    AM_SILENT_RULES([yes])
    diff -Nru pdns-4.9.4/debian/changelog pdns-4.9.7/debian/changelog
    --- pdns-4.9.4/debian/changelog 2025-03-21 13:09:53.000000000 +0100
    +++ pdns-4.9.7/debian/changelog 2025-07-07 12:15:52.000000000 +0200
    @@ -1,3 +1,10 @@
    +pdns (4.9.7-1) unstable; urgency=medium
    +
    + * New upstream version 4.9.7
    + * Drop upstream-applied patch
    +
    + -- Chris Hofstaedtler <[email protected]> Mon, 07 Jul 2025 12:15:52 +0200
    +
    pdns (4.9.4-2) unstable; urgency=medium

    * Add upstream-pending patch to fix mysqlbackend on s390x
    diff -Nru pdns-4.9.4/debian/patches/series pdns-4.9.7/debian/patches/series --- pdns-4.9.4/debian/patches/series 2025-03-21 13:09:34.000000000 +0100
    +++ pdns-4.9.7/debian/patches/series 2025-07-07 12:15:39.000000000 +0200
    @@ -1 +0,0 @@ -upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch
    diff -Nru pdns-4.9.4/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch pdns-4.9.7/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch
    --- pdns-4.9.4/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch 2025-03-21 13:09:34.000000000 +0100
    +++ pdns-4.9.7/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch 1970-01-01 01:00:00.000000000 +0100
    @@ -1,43 +0,0 @@
    -From: Chris Hofstaedtler <[email protected]>
    -Date: Fri, 21 Mar 2025 12:54:21 +0100
    -Subject: mysql: use MYSQL_TYPE_LONGLONG on 64bit platforms
    -
    -Found on s390x.
    -
    -https://github.com/PowerDNS/pdns/pull/15340/
    ----
    - modules/gmysqlbackend/smysql.cc | 14 ++++++++++++--
    - 1 file changed, 12 insertions(+), 2 deletions(-)
    -
    -diff --git a/modules/gmysqlbackend/smysql.cc b/modules/gmysqlbackend/smysql.cc
    -index efcbffd..4cc7856 100644
    ---- a/modules/gmysqlbackend/smysql.cc
    -+++ b/modules/gmysqlbackend/smysql.cc
    -@@ -116,7 +116,12 @@ public:
    - releaseStatement();
    - throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    - }
    -- d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ if constexpr (sizeof(long) == 4) {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ }
    -+ else {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG;
    -+ }
    - d_req_bind[d_paridx].buffer = new long[1];
    - *((long*)d_req_bind[d_paridx].buffer) = value;
    - d_paridx++;
    -@@ -129,7 +134,12 @@ public:
    - releaseStatement();
    - throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    - }
    -- d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ if constexpr (sizeof(long) == 4) {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ }
    -+ else {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG;
    -+ }
    - d_req_bind[d_paridx].buffer = new unsigned long[1];
    - d_req_bind[d_paridx].is_unsigned = 1;
    - *((unsigned long*)d_req_bind[d_paridx].buffer) = value;
    diff -Nru pdns-4.9.4/docs/ixfrdist.yml.5 pdns-4.9.7/docs/ixfrdist.yml.5
    --- pdns-4.9.4/docs/ixfrdist.yml.5 2025-02-06 16:19:08.000000000 +0100
    +++ pdns-4.9.7/docs/ixfrdist.yml.5 2025-07-07 09:43:48.000000000 +0200
    @@ -27,7 +27,7 @@
    .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
    .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
    ..
    -.TH "IXFRDIST.YML" "5" "Feb 06, 2025" "" "PowerDNS Authoritative Server" +.TH "IXFRDIST.YML" "5" "Jul 07, 2025" "" "PowerDNS Authoritative Server"
    .SH NAME
    ixfrdist.yml \- The ixfrdist configuration file
    .SH SYNOPSIS
    diff -Nru pdns-4.9.4/ext/lmdb-safe/lmdb-safe.hh pdns-4.9.7/ext/lmdb-safe/lmdb-safe.hh
    --- pdns-4.9.4/ext/lmdb-safe/lmdb-safe.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/ext/lmdb-safe/lmdb-safe.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -12,6 +12,8 @@
    #include <mutex>
    #include <vector>
    #include <algorithm>
    +#include <string>
    +#include <string_view>

    #include "config.h"

    @@ -24,6 +26,13 @@
    #endif

    using std::string_view;
    +using std::string;
    +
    +#if BOOST_VERSION >= 106100
    +#define StringView string_view
    +#else
    +#define StringView string
    +#endif

    /* open issues:
    *
    @@ -98,7 +107,7 @@
    std::map<std::thread::id, int> d_ROtransactionsOut;
    };

    -std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, int flags, int mode, uint64_t mapsizeMB=(sizeof(void *)==4) ? 100 : 16000);
    +std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, int flags, int mode, uint64_t mapsizeMB);

    #ifndef DNSDIST

    @@ -300,6 +309,9 @@
    return ret;
    }

    + template <class T>
    + T get() const;
    +
    operator MDB_val&()
    {
    return d_mdbval;
    @@ -312,6 +324,12 @@
    #endif
    };

    +template <>
    +inline std::string MDBInVal::get<std::string>() const
    +{
    + return {static_cast<char*>(d_mdbval.mv_data), d_mdbval.mv_size};
    +}
    +
    class MDBROCursor;

    class MDBROTransactionImpl
    @@ -415,6 +433,7 @@
    private:
    std::vector<T*> *d_registry;
    MDB_cursor* d_cursor{nullptr};
    + std::string d_prefix{""};
    public:
    MDB_txn* d_txn{nullptr}; // ew, public
    uint64_t d_txtime{0};
    @@ -523,6 +542,9 @@

    while (true) {
    auto sval = data.getNoStripHeader<std::string_view>();
    + if (d_prefix.length() > 0 && key.getNoStripHeader<StringView>().rfind(d_prefix, 0) != 0) {
    + return MDB_NOTFOUND;
    + }

    if (!LMDBLS::LSisDeleted(sval)) {
    // done!
    @@ -573,6 +595,7 @@
    public:
    int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
    {
    + d_prefix.clear();
    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)));
    @@ -581,6 +604,7 @@

    int find(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
    {
    + d_prefix.clear();
    key.d_mdbval = in.d_mdbval;
    int rc=mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET);
    if(rc && rc != MDB_NOTFOUND)
    @@ -588,8 +612,20 @@
    return skipDeleted(key, data, MDB_SET, rc);
    }

    + int prefix(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
    + {
    + d_prefix = in.get<string>();
    + return _lower_bound(in, key, data);
    + }
    +
    int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
    {
    + d_prefix.clear();
    + return _lower_bound(in, key, data);
    + }
    +
    + int _lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) // used by prefix() and lower_bound()
    + {
    key.d_mdbval = in.d_mdbval;

    int rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET_RANGE);
    diff -Nru pdns-4.9.4/ext/lmdb-safe/lmdb-typed.hh pdns-4.9.7/ext/lmdb-safe/lmdb-typed.hh
    --- pdns-4.9.4/ext/lmdb-safe/lmdb-typed.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/ext/lmdb-safe/lmdb-typed.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -284,14 +284,19 @@
    // }

    //! Get item with id, from main table directly
    - bool get(uint32_t id, T& t)
    + int get2(uint32_t itemId, T& value)
    {
    - MDBOutVal data;
    - if((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
    - return false;
    -
    - serFromString(data.get<std::string>(), t);
    - return true;
    + MDBOutVal data{};
    + int rc;
    + rc = (*d_parent.d_txn)->get(d_parent.d_parent->d_main, itemId, data); + if (rc == 0) {
    + serFromString(data.get<std::string>(), value);
    + }
    + return rc;
    + }
    + bool get(uint32_t itemId, T& value)
    + {
    + return get2(itemId, value) == 0;
    }

    //! Get item through index N, then via the main database
    @@ -309,17 +314,24 @@
    // because we know we only want one item, pass onlyOldest=true to consistently get the same one out of a set of duplicates
    get_multi<N>(key, ids, true);

    - if (ids.size() == 0) {
    + switch (ids.size()) {
    + case 0:
    return 0;
    - }
    -
    - if (ids.size() == 1) {
    - if (get(ids[0], out)) {
    + case 1: {
    + auto rc = get2(ids[0], out);
    + if (rc == 0) {
    return ids[0];
    }
    + if (rc == MDB_NOTFOUND) {
    + /* element not present, or has been marked deleted */
    + return 0;
    + }
    + throw std::runtime_error("in index get, failed (" + std::to_string(rc) + ")");
    + break;
    + }
    + default:
    + throw std::runtime_error("in index get, found more than one item");
    }
    -
    - throw std::runtime_error("in index get, found more than one item");
    }

    // //! Cardinality of index N
    diff -Nru pdns-4.9.4/modules/gmysqlbackend/smysql.cc pdns-4.9.7/modules/gmysqlbackend/smysql.cc
    --- pdns-4.9.4/modules/gmysqlbackend/smysql.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/modules/gmysqlbackend/smysql.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -116,7 +116,12 @@
    releaseStatement();
    throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    }
    - d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    + if constexpr (sizeof(long) == 4) {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    + else {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    d_req_bind[d_paridx].buffer = new long[1];
    *((long*)d_req_bind[d_paridx].buffer) = value;
    d_paridx++;
    @@ -129,7 +134,12 @@
    releaseStatement();
    throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    }
    - d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    + if constexpr (sizeof(long) == 4) {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    + else {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    d_req_bind[d_paridx].buffer = new unsigned long[1];
    d_req_bind[d_paridx].is_unsigned = 1;
    *((unsigned long*)d_req_bind[d_paridx].buffer) = value;
    diff -Nru pdns-4.9.4/modules/lmdbbackend/lmdbbackend.cc pdns-4.9.7/modules/lmdbbackend/lmdbbackend.cc
    --- pdns-4.9.4/modules/lmdbbackend/lmdbbackend.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/modules/lmdbbackend/lmdbbackend.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -656,8 +656,6 @@

    string syncMode = toLower(getArg("sync-mode"));

    - d_random_ids = mustDo("random-ids");
    -
    if (syncMode == "nosync")
    d_asyncFlag = MDB_NOSYNC;
    else if (syncMode == "nometasync")
    @@ -667,17 +665,14 @@
    else
    throw std::runtime_error("Unknown sync mode " + syncMode + " requested for LMDB backend");

    - uint64_t mapSize = 0;
    + d_mapsize = 0;
    try {
    - mapSize = std::stoll(getArg("map-size"));
    + d_mapsize = std::stoll(getArg("map-size"));
    }
    catch (const std::exception& e) {
    throw std::runtime_error(std::string("Unable to parse the 'map-size' LMDB value: ") + e.what());
    }

    - LMDBLS::s_flag_deleted = mustDo("flag-deleted");
    - d_handle_dups = false;
    -
    if (mustDo("lightning-stream")) {
    d_random_ids = true;
    d_handle_dups = true;
    @@ -687,6 +682,11 @@
    throw std::runtime_error(std::string("running with Lightning Stream support requires shards=1"));
    }
    }
    + else {
    + d_random_ids = mustDo("random-ids");
    + d_handle_dups = false;
    + LMDBLS::s_flag_deleted = mustDo("flag-deleted");
    + }

    bool opened = false;

    @@ -723,7 +723,7 @@
    throw std::runtime_error("Somehow, we are not at schema version 5. Giving up");
    }

    - d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, mapSize), "domains_v5");
    + d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize), "domains_v5");
    d_tmeta = std::make_shared<tmeta_t>(d_tdomains->getEnv(), "metadata_v5");
    d_tkdb = std::make_shared<tkdb_t>(d_tdomains->getEnv(), "keydata_v5");
    d_ttsig = std::make_shared<ttsig_t>(d_tdomains->getEnv(), "tsig_v5"); @@ -770,7 +770,7 @@
    }

    if (!opened) {
    - d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, mapSize), "domains_v5");
    + d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize), "domains_v5");
    d_tmeta = std::make_shared<tmeta_t>(d_tdomains->getEnv(), "metadata_v5");
    d_tkdb = std::make_shared<tkdb_t>(d_tdomains->getEnv(), "keydata_v5");
    d_ttsig = std::make_shared<ttsig_t>(d_tdomains->getEnv(), "tsig_v5");
    @@ -1211,7 +1211,7 @@
    auto& shard = d_trecords[id % s_shards];
    if (!shard.env) {
    shard.env = getMDBEnv((getArg("filename") + "-" + std::to_string(id % s_shards)).c_str(),
    - MDB_NOSUBDIR | d_asyncFlag, 0600);
    + MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize);
    shard.dbi = shard.env->openDB("records_v5", MDB_CREATE);
    }
    auto ret = std::make_shared<RecordsRWTransaction>(shard.env->getRWTransaction());
    @@ -1228,7 +1228,7 @@
    throw DBException("attempting to start nested transaction without open parent env");
    }
    shard.env = getMDBEnv((getArg("filename") + "-" + std::to_string(id % s_shards)).c_str(),
    - MDB_NOSUBDIR | d_asyncFlag, 0600);
    + MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize);
    shard.dbi = shard.env->openDB("records_v5", MDB_CREATE);
    }

    @@ -1405,10 +1405,7 @@
    d_matchkey = co(di.id);

    MDBOutVal key, val;
    - auto a = d_getcursor->lower_bound(d_matchkey, key, val);
    - auto b0 = key.getNoStripHeader<StringView>();
    - auto b = b0.rfind(d_matchkey, 0);
    - if (a || b != 0) {
    + if (d_getcursor->prefix(d_matchkey, key, val) != 0) {
    d_getcursor.reset();
    }

    @@ -1470,7 +1467,7 @@
    d_matchkey = co(zoneId, relqname, type.getCode());
    }

    - if (d_getcursor->lower_bound(d_matchkey, key, val) || key.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
    + if (d_getcursor->prefix(d_matchkey, key, val) != 0) {
    d_getcursor.reset();
    if (d_dolog) {
    g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " us to execute (found nothing)" << endl;
    @@ -1508,7 +1505,7 @@

    if (zr.dr.d_type == QType::NSEC3) {
    // Hit a magic NSEC3 skipping
    - if (d_getcursor->next(d_currentKey, d_currentVal) || d_currentKey.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
    + if (d_getcursor->next(d_currentKey, d_currentVal) != 0) {
    // cerr<<"resetting d_getcursor 1"<<endl;
    d_getcursor.reset();
    }
    @@ -1536,7 +1533,7 @@

    if (d_currentrrsetpos >= d_currentrrset.size()) {
    d_currentrrset.clear(); // will invalidate lrr
    - if (d_getcursor->next(d_currentKey, d_currentVal) || d_currentKey.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
    + if (d_getcursor->next(d_currentKey, d_currentVal) != 0) {
    // cerr<<"resetting d_getcursor 2"<<endl;
    d_getcursor.reset();
    }
    @@ -2423,7 +2420,7 @@

    auto cursor = txn->txn->getCursor(txn->db->dbi);
    MDBOutVal key, val;
    - if (cursor.lower_bound(matchkey, key, val)) {
    + if (cursor.prefix(matchkey, key, val) != 0) {
    // cout << "Could not find anything"<<endl;
    return false;
    }
    @@ -2431,7 +2428,7 @@
    bool hasOrderName = !ordername.empty();
    bool needNSEC3 = hasOrderName;

    - for (; key.getNoStripHeader<StringView>().rfind(matchkey, 0) == 0;) {
    + do {
    vector<LMDBResourceRecord> lrrs;

    if (co.getQType(key.getNoStripHeader<StringView>()) != QType::NSEC3) { @@ -2456,9 +2453,7 @@
    }
    }

    - if (cursor.next(key, val))
    - break;
    - }
    + } while (cursor.next(key, val) == 0);

    bool del = false;
    LMDBResourceRecord lrr;
    diff -Nru pdns-4.9.4/modules/lmdbbackend/lmdbbackend.hh pdns-4.9.7/modules/lmdbbackend/lmdbbackend.hh
    --- pdns-4.9.4/modules/lmdbbackend/lmdbbackend.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/modules/lmdbbackend/lmdbbackend.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -333,4 +333,5 @@
    bool d_random_ids;
    bool d_handle_dups;
    DTime d_dtime; // used only for logging
    + uint64_t d_mapsize;
    };
    diff -Nru pdns-4.9.4/pdns/credentials.hh pdns-4.9.7/pdns/credentials.hh
    --- pdns-4.9.4/pdns/credentials.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/pdns/credentials.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -21,7 +21,7 @@
    */
    #pragma once

    -#include <memory>
    +#include <cstdint>
    #include <string>

    class SensitiveData
    diff -Nru pdns-4.9.4/pdns/dnssecinfra.cc pdns-4.9.7/pdns/dnssecinfra.cc
    --- pdns-4.9.4/pdns/dnssecinfra.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/pdns/dnssecinfra.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -782,7 +782,7 @@
    DNSPacketWriter dw(signVect, DNSName(), 0);
    auto pos=signVect.size();
    if(!timersonly) {
    - dw.xfrName(tsigKeyName, false);
    + dw.xfrName(tsigKeyName.makeLowerCase(), false);
    dw.xfr16BitInt(QClass::ANY); // class
    dw.xfr32BitInt(0); // TTL
    dw.xfrName(trc.d_algoName.makeLowerCase(), false);
    diff -Nru pdns-4.9.4/pdns/lua-record.cc pdns-4.9.7/pdns/lua-record.cc
    --- pdns-4.9.4/pdns/lua-record.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/pdns/lua-record.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -915,81 +915,87 @@
    return std::string("error");
    });
    lua.writeFunction("createForward", []() {
    - static string allZerosIP("0.0.0.0");
    - DNSName rel=s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone);
    - // parts is something like ["1", "2", "3", "4", "static"] or
    - // ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
    - auto parts = rel.getRawLabels();
    - // Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply...
    - if(parts.size()>=4) {
    - try {
    - ComboAddress ca(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]); - return ca.toString();
    - } catch (const PDNSException &e) {
    - return allZerosIP;
    - }
    - } else if (!parts.empty()) {
    - auto& input = parts.at(0);
    -
    - // allow a word without - in front, as long as it does not contain anything that could be a number
    - size_t nonhexprefix = strcspn(input.c_str(), "0123456789abcdefABCDEF");
    - if (nonhexprefix > 0) {
    - input = input.substr(nonhexprefix);
    - }
    -
    - // either hex string, or 12-13-14-15
    - vector<string> ip_parts;
    -
    - stringtok(ip_parts, input, "-");
    - unsigned int x1, x2, x3, x4;
    - if (ip_parts.size() >= 4) {
    - // 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
    - string ret;
    - for (size_t index=4; index > 0; index--) {
    - auto octet = ip_parts[ip_parts.size() - index];
    - try {
    - auto octetVal = std::stol(octet);
    + static string allZerosIP{"0.0.0.0"};
    + try {
    + DNSName rel{s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone)};
    +
    + // parts is something like ["1", "2", "3", "4", "static"] or
    + // ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
    + auto parts = rel.getRawLabels();
    + // Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply... + if (parts.size() >= 4) {
    + ComboAddress address(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]);
    + return address.toString();
    + }
    + if (!parts.empty()) {
    + auto& input = parts.at(0);
    +
    + // allow a word without - in front, as long as it does not contain anything that could be a number
    + size_t nonhexprefix = strcspn(input.c_str(), "0123456789abcdefABCDEF");
    + if (nonhexprefix > 0) {
    + input = input.substr(nonhexprefix);
    + }
    +
    + // either hex string, or 12-13-14-15
    + vector<string> ip_parts;
    +
    + stringtok(ip_parts, input, "-");
    + if (ip_parts.size() >= 4) {
    + // 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
    + string ret;
    + for (size_t index=4; index > 0; index--) {
    + auto octet = ip_parts.at(ip_parts.size() - index);
    + auto octetVal = std::stol(octet); // may throw
    if (octetVal >= 0 && octetVal <= 255) {
    - ret += ip_parts.at(ip_parts.size() - index) + ".";
    + ret += octet + ".";
    } else {
    return allZerosIP;
    }
    - } catch (const std::exception &e) {
    - return allZerosIP;
    }
    + ret.resize(ret.size() - 1); // remove trailing dot after last octet
    + return ret;
    }
    - ret.resize(ret.size() - 1); // remove trailing dot after last octet
    - return ret;
    - }
    - if(input.length() >= 8) {
    - auto last8 = input.substr(input.length()-8);
    - if(sscanf(last8.c_str(), "%02x%02x%02x%02x", &x1, &x2, &x3, &x4)==4) {
    - return std::to_string(x1) + "." + std::to_string(x2) + "." + std::to_string(x3) + "." + std::to_string(x4);
    + if (input.length() >= 8) {
    + auto last8 = input.substr(input.length()-8);
    + unsigned int part1{0};
    + unsigned int part2{0};
    + unsigned int part3{0};
    + unsigned int part4{0};
    + if (sscanf(last8.c_str(), "%02x%02x%02x%02x", &part1, &part2, &part3, &part4) == 4) {
    + ComboAddress address(std::to_string(part1) + "." + std::to_string(part2) + "." + std::to_string(part3) + "." + std::to_string(part4));
    + return address.toString();
    + }
    }
    }
    + return allZerosIP;
    + } catch (const PDNSException &e) {
    + return allZerosIP;
    }
    - return allZerosIP;
    });

    lua.writeFunction("createForward6", []() {
    - DNSName rel=s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone);
    - auto parts = rel.getRawLabels();
    - if(parts.size()==8) {
    - string tot;
    - for(int i=0; i<8; ++i) {
    - if(i)
    - tot.append(1,':');
    - tot+=parts[i];
    + static string allZerosIP{"::"};
    + try {
    + DNSName rel{s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone)};
    +
    + auto parts = rel.getRawLabels();
    + if (parts.size() == 8) {
    + string tot;
    + for (int chunk = 0; chunk < 8; ++chunk) {
    + if (chunk != 0) {
    + tot.append(1, ':');
    + }
    + tot += parts.at(chunk);
    + }
    + ComboAddress address(tot);
    + return address.toString();
    }
    - ComboAddress ca(tot);
    - return ca.toString();
    - }
    - else if(parts.size()==1) {
    - if (parts[0].find('-') != std::string::npos) {
    - boost::replace_all(parts[0],"-",":");
    - ComboAddress ca(parts[0]);
    - return ca.toString();
    - } else {
    + if (parts.size() == 1) {
    + if (parts[0].find('-') != std::string::npos) {
    + std::replace(parts[0].begin(), parts[0].end(), '-', ':');
    + ComboAddress address(parts[0]);
    + return address.toString();
    + }
    if (parts[0].size() >= 32) {
    auto ippart = parts[0].substr(parts[0].size()-32);
    auto fulladdress =
    @@ -1002,57 +1008,63 @@
    ippart.substr(24, 4) + ":" +
    ippart.substr(28, 4);

    - ComboAddress ca(fulladdress);
    - return ca.toString();
    + ComboAddress address(fulladdress);
    + return address.toString();
    }
    }
    + return allZerosIP;
    + } catch (const PDNSException &e) {
    + return allZerosIP;
    }
    -
    - return std::string("::");
    });
    - lua.writeFunction("createReverse6", [](string format, boost::optional<std::unordered_map<string,string>> e){
    + lua.writeFunction("createReverse6", [](const string &format, boost::optional<std::unordered_map<string,string>> excp){
    vector<ComboAddress> candidates;

    try {
    auto labels= s_lua_record_ctx->qname.getRawLabels();
    - if(labels.size()<32)
    + if (labels.size()<32) {
    return std::string("unknown");
    + }
    boost::format fmt(format);
    fmt.exceptions( boost::io::all_error_bits ^ ( boost::io::too_many_args_bit | boost::io::too_few_args_bit ) );


    string together;
    vector<string> quads;
    - for(int i=0; i<8; ++i) {
    - if(i)
    - together+=":";
    + for (int chunk = 0; chunk < 8; ++chunk) {
    + if (chunk != 0) {
    + together += ":";
    + }
    string lquad;
    - for(int j=0; j <4; ++j) {
    - lquad.append(1, labels[31-i*4-j][0]);
    - together += labels[31-i*4-j][0];
    + for (int quartet = 0; quartet < 4; ++quartet) {
    + lquad.append(1, labels[31 - chunk * 4 - quartet][0]);
    + together += labels[31 - chunk * 4 - quartet][0];
    }
    quads.push_back(lquad);
    }
    - ComboAddress ip6(together,0);
    + ComboAddress ip6(together,0);

    - if(e) {
    - auto& addrs=*e;
    + if (excp) {
    + auto& addrs=*excp;
    for(const auto& addr: addrs) {
    // this makes sure we catch all forms of the address
    - if(ComboAddress(addr.first,0)==ip6)

    [continued in next message]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Hofstaedtler@21:1/5 to All on Tue Jul 8 09:30:02 2025
    XPost: linux.debian.devel.release

    Cointrol: tags -1 - moreinfo

    (I hope untagging is the right thing to do)


    * Sebastian Ramacher <[email protected]> [250708 08:02]:
    Control: tags -1 moreinfo

    On 2025-07-07 18:01:12 +0200, Chris Hofstädtler wrote:
    Package: release.debian.org
    Severity: normal
    X-Debbugs-Cc: [email protected]
    Control: affects -1 + src:pdns
    User: [email protected]
    Usertags: unblock

    Please unblock package pdns

    pdns 4.9.7 is an upstream bugfix release in the 4.9 series.
    Previously we had 4.9.4; upstream released 4.9.5 (after the freeze
    started) and 4.9.7 (today) - 4.9.6 was skipped.

    Is there a summary of the changes from 4.9.4 to 4.9.7 somewhere? Or
    could you provide a short summary of those changes?

    Yes:

    https://doc.powerdns.com/authoritative/changelog/4.9.html

    4.9.5:

    Improvements
    - Faster LMDB list/lookup/get operations

    Bug Fixes
    - Correctly handle marked-as-deleted elements in LMDB read-only
    queries
    - Fix MySQL operation on 64-bit big-endian platforms
    [zeha: this is our previously applied patch]
    - Fix incorrect behaviour of Lua createForward and createForward6
    functions leading to possible SERVFAIL answers, when processing
    certain data.

    4.9.6:
    not released

    4.9.7:

    Bug Fixes
    - compilation fix: Include cstdint to get uint64_t
    - auth docker: avoid crash on –version caused by doubly loaded modules
    [zeha: does not affect the release tarball]
    - TSIG payload: use canonical (lowercase) name format
    - LMDB: honour map-size for all files
    - Close race window during which LMDB lightning stream flag values might be incorrect


    Hope this helps,
    Chris


    I'd like to take the latest upstream release into unstable and
    testing. Have not uploaded it yet.

    [ Reason ]
    Accepting the upstream bugfix release will hopefully make applying
    future security fixes easier, or we can just use a future bugfix
    release for them.

    4.9.5 includes the patch we applied to 4.9.4 to fix tests on s390x.

    [ Impact ]
    If we stay on 4.9.4, the diff for security fixes will be larger and
    thus harder.
    We'll also miss out on upstream bug- and performance-fixes to the LMDB
    backend, better exception handling in Lua functions leading to
    SERVFAILs, an interop fix for TSIG and a compile fix for newer gcc.

    [ Tests ]
    In Debian we only have smoke tests, however they did find the s390x
    mysql issue in the past. Upstream has a big test suite they run for
    releases.

    [ Risks ]
    Not sure. The diff seems right to me for the fixes upstream
    described.

    [ Checklist ]
    [x] all changes are documented in the d/changelog
    [x] I reviewed all changes and I approve them
    [x] attach debdiff against the package in testing

    [ Other info ]

    The attached debdiff was produced using:
    debdiff pdns_4.9.4-2.dsc pdns_4.9.7-1.dsc | filterdiff -x '*.1' > pdns_4.9.7-1.filtered.debdiff
    to exclude the date changes to the xxx.1 manpages.

    unblock pdns/4.9.7-1

    diff -Nru pdns-4.9.4/configure pdns-4.9.7/configure
    --- pdns-4.9.4/configure 2025-02-06 16:18:00.000000000 +0100
    +++ pdns-4.9.7/configure 2025-07-07 09:42:38.000000000 +0200
    @@ -1,6 +1,6 @@
    #! /bin/sh
    # Guess values for system-dependent variables and create Makefiles.
    -# Generated by GNU Autoconf 2.71 for pdns 4.9.4.
    +# Generated by GNU Autoconf 2.71 for pdns 4.9.7.
    #
    #
    # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, >> @@ -618,8 +618,8 @@
    # Identity of this package.
    PACKAGE_NAME='pdns'
    PACKAGE_TARNAME='pdns'
    -PACKAGE_VERSION='4.9.4'
    -PACKAGE_STRING='pdns 4.9.4'
    +PACKAGE_VERSION='4.9.7'
    +PACKAGE_STRING='pdns 4.9.7'
    PACKAGE_BUGREPORT=''
    PACKAGE_URL=''

    @@ -1698,7 +1698,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 pdns 4.9.4 to adapt to many kinds of systems.
    +\`configure' configures pdns 4.9.7 to adapt to many kinds of systems.

    Usage: $0 [OPTION]... [VAR=VALUE]...

    @@ -1769,7 +1769,7 @@

    if test -n "$ac_init_help"; then
    case $ac_init_help in
    - short | recursive ) echo "Configuration of pdns 4.9.4:";;
    + short | recursive ) echo "Configuration of pdns 4.9.7:";;
    esac
    cat <<\_ACEOF

    @@ -2040,7 +2040,7 @@
    test -n "$ac_init_help" && exit $ac_status
    if $ac_init_version; then
    cat <<\_ACEOF
    -pdns configure 4.9.4
    +pdns configure 4.9.7
    generated by GNU Autoconf 2.71

    Copyright (C) 2021 Free Software Foundation, Inc.
    @@ -2529,7 +2529,7 @@
    This file contains any messages produced by compilers while
    running configure, to aid debugging if configure makes a mistake.

    -It was created by pdns $as_me 4.9.4, which was
    +It was created by pdns $as_me 4.9.7, which was
    generated by GNU Autoconf 2.71. Invocation command line was

    $ $0$ac_configure_args_raw
    @@ -4027,7 +4027,7 @@

    # Define the identity of the package.
    PACKAGE='pdns'
    - VERSION='4.9.4'
    + VERSION='4.9.7'


    printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
    @@ -32467,7 +32467,7 @@
    # report actual input values of CONFIG_FILES etc. instead of their
    # values after options handling.
    ac_log="
    -This file was extended by pdns $as_me 4.9.4, which was
    +This file was extended by pdns $as_me 4.9.7, which was
    generated by GNU Autoconf 2.71. Invocation command line was

    CONFIG_FILES = $CONFIG_FILES
    @@ -32535,7 +32535,7 @@
    cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
    ac_cs_config='$ac_cs_config_escaped'
    ac_cs_version="\\
    -pdns config.status 4.9.4
    +pdns config.status 4.9.7
    configured by $0, generated by GNU Autoconf 2.71,
    with options \\"\$ac_cs_config\\"

    diff -Nru pdns-4.9.4/configure.ac pdns-4.9.7/configure.ac
    --- pdns-4.9.4/configure.ac 2025-02-06 16:17:52.000000000 +0100
    +++ pdns-4.9.7/configure.ac 2025-07-07 09:42:29.000000000 +0200
    @@ -1,6 +1,6 @@
    AC_PREREQ([2.69])

    -AC_INIT([pdns], [4.9.4])
    +AC_INIT([pdns], [4.9.7])
    AC_CONFIG_AUX_DIR([build-aux])
    AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip tar-ustar -Wno-portability subdir-objects parallel-tests 1.11])
    AM_SILENT_RULES([yes])
    diff -Nru pdns-4.9.4/debian/changelog pdns-4.9.7/debian/changelog
    --- pdns-4.9.4/debian/changelog 2025-03-21 13:09:53.000000000 +0100
    +++ pdns-4.9.7/debian/changelog 2025-07-07 12:15:52.000000000 +0200
    @@ -1,3 +1,10 @@
    +pdns (4.9.7-1) unstable; urgency=medium
    +
    + * New upstream version 4.9.7
    + * Drop upstream-applied patch
    +
    + -- Chris Hofstaedtler <[email protected]> Mon, 07 Jul 2025 12:15:52 +0200 >> +
    pdns (4.9.4-2) unstable; urgency=medium

    * Add upstream-pending patch to fix mysqlbackend on s390x
    diff -Nru pdns-4.9.4/debian/patches/series pdns-4.9.7/debian/patches/series >> --- pdns-4.9.4/debian/patches/series 2025-03-21 13:09:34.000000000 +0100
    +++ pdns-4.9.7/debian/patches/series 2025-07-07 12:15:39.000000000 +0200
    @@ -1 +0,0 @@
    -upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch
    diff -Nru pdns-4.9.4/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch pdns-4.9.7/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch
    --- pdns-4.9.4/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch 2025-03-21 13:09:34.000000000 +0100
    +++ pdns-4.9.7/debian/patches/upstream/0001-mysql-use-MYSQL_TYPE_LONGLONG-on-64bit-platforms.patch 1970-01-01 01:00:00.000000000 +0100
    @@ -1,43 +0,0 @@
    -From: Chris Hofstaedtler <[email protected]>
    -Date: Fri, 21 Mar 2025 12:54:21 +0100
    -Subject: mysql: use MYSQL_TYPE_LONGLONG on 64bit platforms
    -
    -Found on s390x.
    -
    -https://github.com/PowerDNS/pdns/pull/15340/
    ----
    - modules/gmysqlbackend/smysql.cc | 14 ++++++++++++--
    - 1 file changed, 12 insertions(+), 2 deletions(-)
    -
    -diff --git a/modules/gmysqlbackend/smysql.cc b/modules/gmysqlbackend/smysql.cc
    -index efcbffd..4cc7856 100644
    ---- a/modules/gmysqlbackend/smysql.cc
    -+++ b/modules/gmysqlbackend/smysql.cc
    -@@ -116,7 +116,12 @@ public:
    - releaseStatement();
    - throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    - }
    -- d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ if constexpr (sizeof(long) == 4) {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ }
    -+ else {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG;
    -+ }
    - d_req_bind[d_paridx].buffer = new long[1];
    - *((long*)d_req_bind[d_paridx].buffer) = value;
    - d_paridx++;
    -@@ -129,7 +134,12 @@ public:
    - releaseStatement();
    - throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    - }
    -- d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ if constexpr (sizeof(long) == 4) {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    -+ }
    -+ else {
    -+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG;
    -+ }
    - d_req_bind[d_paridx].buffer = new unsigned long[1];
    - d_req_bind[d_paridx].is_unsigned = 1;
    - *((unsigned long*)d_req_bind[d_paridx].buffer) = value;
    diff -Nru pdns-4.9.4/docs/ixfrdist.yml.5 pdns-4.9.7/docs/ixfrdist.yml.5
    --- pdns-4.9.4/docs/ixfrdist.yml.5 2025-02-06 16:19:08.000000000 +0100
    +++ pdns-4.9.7/docs/ixfrdist.yml.5 2025-07-07 09:43:48.000000000 +0200
    @@ -27,7 +27,7 @@
    .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
    .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
    ..
    -.TH "IXFRDIST.YML" "5" "Feb 06, 2025" "" "PowerDNS Authoritative Server"
    +.TH "IXFRDIST.YML" "5" "Jul 07, 2025" "" "PowerDNS Authoritative Server"
    .SH NAME
    ixfrdist.yml \- The ixfrdist configuration file
    .SH SYNOPSIS
    diff -Nru pdns-4.9.4/ext/lmdb-safe/lmdb-safe.hh pdns-4.9.7/ext/lmdb-safe/lmdb-safe.hh
    --- pdns-4.9.4/ext/lmdb-safe/lmdb-safe.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/ext/lmdb-safe/lmdb-safe.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -12,6 +12,8 @@
    #include <mutex>
    #include <vector>
    #include <algorithm>
    +#include <string>
    +#include <string_view>

    #include "config.h"

    @@ -24,6 +26,13 @@
    #endif

    using std::string_view;
    +using std::string;
    +
    +#if BOOST_VERSION >= 106100
    +#define StringView string_view
    +#else
    +#define StringView string
    +#endif

    /* open issues:
    *
    @@ -98,7 +107,7 @@
    std::map<std::thread::id, int> d_ROtransactionsOut;
    };

    -std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, int flags, int mode, uint64_t mapsizeMB=(sizeof(void *)==4) ? 100 : 16000);
    +std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, int flags, int mode, uint64_t mapsizeMB);

    #ifndef DNSDIST

    @@ -300,6 +309,9 @@
    return ret;
    }

    + template <class T>
    + T get() const;
    +
    operator MDB_val&()
    {
    return d_mdbval;
    @@ -312,6 +324,12 @@
    #endif
    };

    +template <>
    +inline std::string MDBInVal::get<std::string>() const
    +{
    + return {static_cast<char*>(d_mdbval.mv_data), d_mdbval.mv_size};
    +}
    +
    class MDBROCursor;

    class MDBROTransactionImpl
    @@ -415,6 +433,7 @@
    private:
    std::vector<T*> *d_registry;
    MDB_cursor* d_cursor{nullptr};
    + std::string d_prefix{""};
    public:
    MDB_txn* d_txn{nullptr}; // ew, public
    uint64_t d_txtime{0};
    @@ -523,6 +542,9 @@

    while (true) {
    auto sval = data.getNoStripHeader<std::string_view>();
    + if (d_prefix.length() > 0 && key.getNoStripHeader<StringView>().rfind(d_prefix, 0) != 0) {
    + return MDB_NOTFOUND;
    + }

    if (!LMDBLS::LSisDeleted(sval)) {
    // done!
    @@ -573,6 +595,7 @@
    public:
    int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
    {
    + d_prefix.clear();
    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)));
    @@ -581,6 +604,7 @@

    int find(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
    {
    + d_prefix.clear();
    key.d_mdbval = in.d_mdbval;
    int rc=mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET);
    if(rc && rc != MDB_NOTFOUND)
    @@ -588,8 +612,20 @@
    return skipDeleted(key, data, MDB_SET, rc);
    }

    + int prefix(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
    + {
    + d_prefix = in.get<string>();
    + return _lower_bound(in, key, data);
    + }
    +
    int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
    {
    + d_prefix.clear();
    + return _lower_bound(in, key, data);
    + }
    +
    + int _lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) // used by prefix() and lower_bound()
    + {
    key.d_mdbval = in.d_mdbval;

    int rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET_RANGE);
    diff -Nru pdns-4.9.4/ext/lmdb-safe/lmdb-typed.hh pdns-4.9.7/ext/lmdb-safe/lmdb-typed.hh
    --- pdns-4.9.4/ext/lmdb-safe/lmdb-typed.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/ext/lmdb-safe/lmdb-typed.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -284,14 +284,19 @@
    // }

    //! Get item with id, from main table directly
    - bool get(uint32_t id, T& t)
    + int get2(uint32_t itemId, T& value)
    {
    - MDBOutVal data;
    - if((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
    - return false;
    -
    - serFromString(data.get<std::string>(), t);
    - return true;
    + MDBOutVal data{};
    + int rc;
    + rc = (*d_parent.d_txn)->get(d_parent.d_parent->d_main, itemId, data); >> + if (rc == 0) {
    + serFromString(data.get<std::string>(), value);
    + }
    + return rc;
    + }
    + bool get(uint32_t itemId, T& value)
    + {
    + return get2(itemId, value) == 0;
    }

    //! Get item through index N, then via the main database
    @@ -309,17 +314,24 @@
    // because we know we only want one item, pass onlyOldest=true to consistently get the same one out of a set of duplicates
    get_multi<N>(key, ids, true);

    - if (ids.size() == 0) {
    + switch (ids.size()) {
    + case 0:
    return 0;
    - }
    -
    - if (ids.size() == 1) {
    - if (get(ids[0], out)) {
    + case 1: {
    + auto rc = get2(ids[0], out);
    + if (rc == 0) {
    return ids[0];
    }
    + if (rc == MDB_NOTFOUND) {
    + /* element not present, or has been marked deleted */
    + return 0;
    + }
    + throw std::runtime_error("in index get, failed (" + std::to_string(rc) + ")");
    + break;
    + }
    + default:
    + throw std::runtime_error("in index get, found more than one item"); >> }
    -
    - throw std::runtime_error("in index get, found more than one item"); >> }

    // //! Cardinality of index N
    diff -Nru pdns-4.9.4/modules/gmysqlbackend/smysql.cc pdns-4.9.7/modules/gmysqlbackend/smysql.cc
    --- pdns-4.9.4/modules/gmysqlbackend/smysql.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/modules/gmysqlbackend/smysql.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -116,7 +116,12 @@
    releaseStatement();
    throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    }
    - d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    + if constexpr (sizeof(long) == 4) {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    + else {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    d_req_bind[d_paridx].buffer = new long[1];
    *((long*)d_req_bind[d_paridx].buffer) = value;
    d_paridx++;
    @@ -129,7 +134,12 @@
    releaseStatement();
    throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
    }
    - d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
    + if constexpr (sizeof(long) == 4) {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    + else {
    + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    + }
    d_req_bind[d_paridx].buffer = new unsigned long[1];
    d_req_bind[d_paridx].is_unsigned = 1;
    *((unsigned long*)d_req_bind[d_paridx].buffer) = value;
    diff -Nru pdns-4.9.4/modules/lmdbbackend/lmdbbackend.cc pdns-4.9.7/modules/lmdbbackend/lmdbbackend.cc
    --- pdns-4.9.4/modules/lmdbbackend/lmdbbackend.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/modules/lmdbbackend/lmdbbackend.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -656,8 +656,6 @@

    string syncMode = toLower(getArg("sync-mode"));

    - d_random_ids = mustDo("random-ids");
    -
    if (syncMode == "nosync")
    d_asyncFlag = MDB_NOSYNC;
    else if (syncMode == "nometasync")
    @@ -667,17 +665,14 @@
    else
    throw std::runtime_error("Unknown sync mode " + syncMode + " requested for LMDB backend");

    - uint64_t mapSize = 0;
    + d_mapsize = 0;
    try {
    - mapSize = std::stoll(getArg("map-size"));
    + d_mapsize = std::stoll(getArg("map-size"));
    }
    catch (const std::exception& e) {
    throw std::runtime_error(std::string("Unable to parse the 'map-size' LMDB value: ") + e.what());
    }

    - LMDBLS::s_flag_deleted = mustDo("flag-deleted");
    - d_handle_dups = false;
    -
    if (mustDo("lightning-stream")) {
    d_random_ids = true;
    d_handle_dups = true;
    @@ -687,6 +682,11 @@
    throw std::runtime_error(std::string("running with Lightning Stream support requires shards=1"));
    }
    }
    + else {
    + d_random_ids = mustDo("random-ids");
    + d_handle_dups = false;
    + LMDBLS::s_flag_deleted = mustDo("flag-deleted");
    + }

    bool opened = false;

    @@ -723,7 +723,7 @@
    throw std::runtime_error("Somehow, we are not at schema version 5. Giving up");
    }

    - d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, mapSize), "domains_v5");
    + d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize), "domains_v5");
    d_tmeta = std::make_shared<tmeta_t>(d_tdomains->getEnv(), "metadata_v5");
    d_tkdb = std::make_shared<tkdb_t>(d_tdomains->getEnv(), "keydata_v5");
    d_ttsig = std::make_shared<ttsig_t>(d_tdomains->getEnv(), "tsig_v5"); >> @@ -770,7 +770,7 @@
    }

    if (!opened) {
    - d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, mapSize), "domains_v5");
    + d_tdomains = std::make_shared<tdomains_t>(getMDBEnv(getArg("filename").c_str(), MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize), "domains_v5");
    d_tmeta = std::make_shared<tmeta_t>(d_tdomains->getEnv(), "metadata_v5");
    d_tkdb = std::make_shared<tkdb_t>(d_tdomains->getEnv(), "keydata_v5"); >> d_ttsig = std::make_shared<ttsig_t>(d_tdomains->getEnv(), "tsig_v5"); >> @@ -1211,7 +1211,7 @@
    auto& shard = d_trecords[id % s_shards];
    if (!shard.env) {
    shard.env = getMDBEnv((getArg("filename") + "-" + std::to_string(id % s_shards)).c_str(),
    - MDB_NOSUBDIR | d_asyncFlag, 0600);
    + MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize);
    shard.dbi = shard.env->openDB("records_v5", MDB_CREATE);
    }
    auto ret = std::make_shared<RecordsRWTransaction>(shard.env->getRWTransaction());
    @@ -1228,7 +1228,7 @@
    throw DBException("attempting to start nested transaction without open parent env");
    }
    shard.env = getMDBEnv((getArg("filename") + "-" + std::to_string(id % s_shards)).c_str(),
    - MDB_NOSUBDIR | d_asyncFlag, 0600);
    + MDB_NOSUBDIR | d_asyncFlag, 0600, d_mapsize);
    shard.dbi = shard.env->openDB("records_v5", MDB_CREATE);
    }

    @@ -1405,10 +1405,7 @@
    d_matchkey = co(di.id);

    MDBOutVal key, val;
    - auto a = d_getcursor->lower_bound(d_matchkey, key, val);
    - auto b0 = key.getNoStripHeader<StringView>();
    - auto b = b0.rfind(d_matchkey, 0);
    - if (a || b != 0) {
    + if (d_getcursor->prefix(d_matchkey, key, val) != 0) {
    d_getcursor.reset();
    }

    @@ -1470,7 +1467,7 @@
    d_matchkey = co(zoneId, relqname, type.getCode());
    }

    - if (d_getcursor->lower_bound(d_matchkey, key, val) || key.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
    + if (d_getcursor->prefix(d_matchkey, key, val) != 0) {
    d_getcursor.reset();
    if (d_dolog) {
    g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " us to execute (found nothing)" << endl;
    @@ -1508,7 +1505,7 @@

    if (zr.dr.d_type == QType::NSEC3) {
    // Hit a magic NSEC3 skipping
    - if (d_getcursor->next(d_currentKey, d_currentVal) || d_currentKey.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
    + if (d_getcursor->next(d_currentKey, d_currentVal) != 0) {
    // cerr<<"resetting d_getcursor 1"<<endl;
    d_getcursor.reset();
    }
    @@ -1536,7 +1533,7 @@

    if (d_currentrrsetpos >= d_currentrrset.size()) {
    d_currentrrset.clear(); // will invalidate lrr
    - if (d_getcursor->next(d_currentKey, d_currentVal) || d_currentKey.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
    + if (d_getcursor->next(d_currentKey, d_currentVal) != 0) {
    // cerr<<"resetting d_getcursor 2"<<endl;
    d_getcursor.reset();
    }
    @@ -2423,7 +2420,7 @@

    auto cursor = txn->txn->getCursor(txn->db->dbi);
    MDBOutVal key, val;
    - if (cursor.lower_bound(matchkey, key, val)) {
    + if (cursor.prefix(matchkey, key, val) != 0) {
    // cout << "Could not find anything"<<endl;
    return false;
    }
    @@ -2431,7 +2428,7 @@
    bool hasOrderName = !ordername.empty();
    bool needNSEC3 = hasOrderName;

    - for (; key.getNoStripHeader<StringView>().rfind(matchkey, 0) == 0;) {
    + do {
    vector<LMDBResourceRecord> lrrs;

    if (co.getQType(key.getNoStripHeader<StringView>()) != QType::NSEC3) { >> @@ -2456,9 +2453,7 @@
    }
    }

    - if (cursor.next(key, val))
    - break;
    - }
    + } while (cursor.next(key, val) == 0);

    bool del = false;
    LMDBResourceRecord lrr;
    diff -Nru pdns-4.9.4/modules/lmdbbackend/lmdbbackend.hh pdns-4.9.7/modules/lmdbbackend/lmdbbackend.hh
    --- pdns-4.9.4/modules/lmdbbackend/lmdbbackend.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/modules/lmdbbackend/lmdbbackend.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -333,4 +333,5 @@
    bool d_random_ids;
    bool d_handle_dups;
    DTime d_dtime; // used only for logging
    + uint64_t d_mapsize;
    };
    diff -Nru pdns-4.9.4/pdns/credentials.hh pdns-4.9.7/pdns/credentials.hh
    --- pdns-4.9.4/pdns/credentials.hh 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/pdns/credentials.hh 2025-07-07 09:42:15.000000000 +0200
    @@ -21,7 +21,7 @@
    */
    #pragma once

    -#include <memory>
    +#include <cstdint>
    #include <string>

    class SensitiveData
    diff -Nru pdns-4.9.4/pdns/dnssecinfra.cc pdns-4.9.7/pdns/dnssecinfra.cc
    --- pdns-4.9.4/pdns/dnssecinfra.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/pdns/dnssecinfra.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -782,7 +782,7 @@
    DNSPacketWriter dw(signVect, DNSName(), 0);
    auto pos=signVect.size();
    if(!timersonly) {
    - dw.xfrName(tsigKeyName, false);
    + dw.xfrName(tsigKeyName.makeLowerCase(), false);
    dw.xfr16BitInt(QClass::ANY); // class
    dw.xfr32BitInt(0); // TTL
    dw.xfrName(trc.d_algoName.makeLowerCase(), false);
    diff -Nru pdns-4.9.4/pdns/lua-record.cc pdns-4.9.7/pdns/lua-record.cc
    --- pdns-4.9.4/pdns/lua-record.cc 2025-02-06 16:17:38.000000000 +0100
    +++ pdns-4.9.7/pdns/lua-record.cc 2025-07-07 09:42:15.000000000 +0200
    @@ -915,81 +915,87 @@
    return std::string("error");
    });
    lua.writeFunction("createForward", []() {
    - static string allZerosIP("0.0.0.0");
    - DNSName rel=s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone);
    - // parts is something like ["1", "2", "3", "4", "static"] or
    - // ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
    - auto parts = rel.getRawLabels();
    - // Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply... >> - if(parts.size()>=4) {
    - try {
    - ComboAddress ca(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]); >> - return ca.toString();
    - } catch (const PDNSException &e) {
    - return allZerosIP;
    - }
    - } else if (!parts.empty()) {
    - auto& input = parts.at(0);
    -
    - // allow a word without - in front, as long as it does not contain anything that could be a number
    - size_t nonhexprefix = strcspn(input.c_str(), "0123456789abcdefABCDEF");
    - if (nonhexprefix > 0) {
    - input = input.substr(nonhexprefix);
    - }
    -
    - // either hex string, or 12-13-14-15
    - vector<string> ip_parts;
    -
    - stringtok(ip_parts, input, "-");
    - unsigned int x1, x2, x3, x4;
    - if (ip_parts.size() >= 4) {
    - // 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
    - string ret;
    - for (size_t index=4; index > 0; index--) {
    - auto octet = ip_parts[ip_parts.size() - index];
    - try {
    - auto octetVal = std::stol(octet);
    + static string allZerosIP{"0.0.0.0"};
    + try {
    + DNSName rel{s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone)};
    +
    + // parts is something like ["1", "2", "3", "4", "static"] or
    + // ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
    + auto parts = rel.getRawLabels();
    + // Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply...
    + if (parts.size() >= 4) {
    + ComboAddress address(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]);
    + return address.toString();
    + }
    + if (!parts.empty()) {
    + auto& input = parts.at(0);
    +
    + // allow a word without - in front, as long as it does not contain anything that could be a number
    + size_t nonhexprefix = strcspn(input.c_str(), "0123456789abcdefABCDEF");
    + if (nonhexprefix > 0) {
    + input = input.substr(nonhexprefix);
    + }
    +
    + // either hex string, or 12-13-14-15
    + vector<string> ip_parts;
    +
    + stringtok(ip_parts, input, "-");
    + if (ip_parts.size() >= 4) {
    + // 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
    + string ret;
    + for (size_t index=4; index > 0; index--) {
    + auto octet = ip_parts.at(ip_parts.size() - index);
    + auto octetVal = std::stol(octet); // may throw
    if (octetVal >= 0 && octetVal <= 255) {
    - ret += ip_parts.at(ip_parts.size() - index) + ".";
    + ret += octet + ".";
    } else {
    return allZerosIP;
    }
    - } catch (const std::exception &e) {
    - return allZerosIP;
    }
    + ret.resize(ret.size() - 1); // remove trailing dot after last octet
    + return ret;
    }
    - ret.resize(ret.size() - 1); // remove trailing dot after last octet
    - return ret;
    - }
    - if(input.length() >= 8) {
    - auto last8 = input.substr(input.length()-8);
    - if(sscanf(last8.c_str(), "%02x%02x%02x%02x", &x1, &x2, &x3, &x4)==4) {
    - return std::to_string(x1) + "." + std::to_string(x2) + "." + std::to_string(x3) + "." + std::to_string(x4);
    + if (input.length() >= 8) {
    + auto last8 = input.substr(input.length()-8);
    + unsigned int part1{0};
    + unsigned int part2{0};
    + unsigned int part3{0};
    + unsigned int part4{0};
    + if (sscanf(last8.c_str(), "%02x%02x%02x%02x", &part1, &part2, &part3, &part4) == 4) {
    + ComboAddress address(std::to_string(part1) + "." + std::to_string(part2) + "." + std::to_string(part3) + "." + std::to_string(part4));
    + return address.toString();
    + }
    }
    }
    + return allZerosIP;
    + } catch (const PDNSException &e) {
    + return allZerosIP;
    }
    - return allZerosIP;
    });

    lua.writeFunction("createForward6", []() {
    - DNSName rel=s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone);
    - auto parts = rel.getRawLabels();
    - if(parts.size()==8) {
    - string tot;
    - for(int i=0; i<8; ++i) {
    - if(i)
    - tot.append(1,':');
    - tot+=parts[i];
    + static string allZerosIP{"::"};
    + try {
    + DNSName rel{s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone)};
    +
    + auto parts = rel.getRawLabels();
    + if (parts.size() == 8) {
    + string tot;
    + for (int chunk = 0; chunk < 8; ++chunk) {
    + if (chunk != 0) {
    + tot.append(1, ':');
    + }
    + tot += parts.at(chunk);
    + }
    + ComboAddress address(tot);
    + return address.toString();
    }
    - ComboAddress ca(tot);
    - return ca.toString();
    - }
    - else if(parts.size()==1) {
    - if (parts[0].find('-') != std::string::npos) {
    - boost::replace_all(parts[0],"-",":");
    - ComboAddress ca(parts[0]);
    - return ca.toString();
    - } else {
    + if (parts.size() == 1) {
    + if (parts[0].find('-') != std::string::npos) {
    + std::replace(parts[0].begin(), parts[0].end(), '-', ':');
    + ComboAddress address(parts[0]);
    + return address.toString();
    + }
    if (parts[0].size() >= 32) {
    auto ippart = parts[0].substr(parts[0].size()-32);
    auto fulladdress =
    @@ -1002,57 +1008,63 @@
    ippart.substr(24, 4) + ":" +
    ippart.substr(28, 4);

    - ComboAddress ca(fulladdress);
    - return ca.toString();
    + ComboAddress address(fulladdress);
    + return address.toString();
    }
    }
    + return allZerosIP;
    + } catch (const PDNSException &e) {

    [continued in next message]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sebastian Ramacher@21:1/5 to Chris Hofstaedtler on Tue Jul 8 11:40:01 2025
    XPost: linux.debian.devel.release

    Control: tags -1 moreinfo confirmed

    On 2025-07-08 09:19:40 +0200, Chris Hofstaedtler wrote:
    Cointrol: tags -1 - moreinfo

    (I hope untagging is the right thing to do)

    Yes

    * Sebastian Ramacher <[email protected]> [250708 08:02]:
    Control: tags -1 moreinfo

    On 2025-07-07 18:01:12 +0200, Chris Hofstädtler wrote:
    Package: release.debian.org
    Severity: normal
    X-Debbugs-Cc: [email protected]
    Control: affects -1 + src:pdns
    User: [email protected]
    Usertags: unblock

    Please unblock package pdns

    pdns 4.9.7 is an upstream bugfix release in the 4.9 series.
    Previously we had 4.9.4; upstream released 4.9.5 (after the freeze started) and 4.9.7 (today) - 4.9.6 was skipped.

    Is there a summary of the changes from 4.9.4 to 4.9.7 somewhere? Or
    could you provide a short summary of those changes?

    Yes:

    https://doc.powerdns.com/authoritative/changelog/4.9.html

    4.9.5:

    Improvements
    - Faster LMDB list/lookup/get operations

    Bug Fixes
    - Correctly handle marked-as-deleted elements in LMDB read-only queries
    - Fix MySQL operation on 64-bit big-endian platforms
    [zeha: this is our previously applied patch]
    - Fix incorrect behaviour of Lua createForward and createForward6
    functions leading to possible SERVFAIL answers, when processing certain data.

    4.9.6:
    not released

    4.9.7:

    Bug Fixes
    - compilation fix: Include cstdint to get uint64_t
    - auth docker: avoid crash on –version caused by doubly loaded modules
    [zeha: does not affect the release tarball]
    - TSIG payload: use canonical (lowercase) name format
    - LMDB: honour map-size for all files
    - Close race window during which LMDB lightning stream flag values might be incorrect

    Thanks. Please go ahead and remove the moreinfo tag once the upload is available in unstable.

    Cheers
    --
    Sebastian Ramacher

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Gevers@21:1/5 to Chris Hofstaedtler on Tue Jul 8 11:50:01 2025
    XPost: linux.debian.devel.release
    To: [email protected]

    This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --------------YcfY0HfKuno7eFIofNyKkl0j
    Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: base64

    SGkgQ2hyaXMNCg0KT24gNy83LzI1IDE4OjI1LCBDaHJpcyBIb2ZzdGFlZHRsZXIgd3JvdGU6 DQo+IE1heWJlIGl0IGlzIHVubmVjZXNzYXJ5IHRvIGFzayBmb3IgYSBwcmVhcHByb3ZhbC91 bmJsb2NrLCBidXQgSQ0KPiBjYW4ndCBtYWtlIHNlbnNlIG9mIGh0dHBzOi8vY2kuZGViaWFu Lm5ldC9wYWNrYWdlcy9wL3BkbnMvDQo+IEZvciB0aGUgYXJjaHMgd2hlcmUgdGhlcmUgYXJl IG5vIGJpbnMgKGFybWVsLCBhcm1oZiwgaTM4NiksIGRvIHRoZXNlDQo+ICJuL2EgZmFpbCIg dGVzdHMgY291bnQgYXMgZmFpbGluZyBvciBzdWNjZXNzZnVsIGZvciBtaWdyYXRpb24/DQoN Cg0KTG9va2luZyBhdCB0aGUgaGlzdG9yeSBvZiBhcm1lbCB0aGVyZSwgaXQgZG9lc24ndCBz ZWVtIHRoYXQgdGhlcmUgYXJlIA0KYW55IG1pZ3JhdGlvbiBydW5zIHRoZXJlLCBvbmx5IG1p Z3JhdGlvbi1yZWZlcmVuY2UvMCBydW5zLiBXaGljaCBtZWFucyANCnRoYXQgYnJpdG5leTIg ZmlndXJlcyBvdXQgdGhhdCBubyBwYWNrYWdlIGZyb20gcGRucyBhcmUgaW5zdGFsbGFibGUg DQp0aGVyZSBhbmQgZG9lc24ndCBzY2hlZHVsZSBhbnkgdGVzdCBhbmQgdGh1cyBkb2Vzbid0 IGJsb2NrIG9uIHRob3NlIA0KYXJjaGl0ZWN0dXJlcy4gVGhlIG1pZ3JhdGlvbi1yZWZlcmVu Y2UvMCBydW5zIGFyZSBzY2hlZHVsZWQgYnkgc29tZSANCm90aGVyIHNjcmlwdCBvZiBtaW5l OyBhcHBhcmVudGx5IGl0IGRvZXNuJ3QgZGV0ZWN0IHRoZSBzaXR1YXRpb24gcHJvcGVybHku DQoNClBhdWwNCg0K

    --------------YcfY0HfKuno7eFIofNyKkl0j--

    -----BEGIN PGP SIGNATURE-----

    wsC7BAABCABvBYJobOj9CRCcXJnrBb11CkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u cy5zZXF1b2lhLXBncC5vcmd1ef2CaeBdt+dTcFbcVXcBcWN1Q6vq9AHo86/uoB2n hBYhBFi2bUhza+k7BS3mcpxcmesFvXUKAAB1pgf+KKWvmIGSbkcASWpDmgzzEMrq sISq300m04/fpijpoQH+2nBJ53KTTRCVP6Qd02PXmuRiEN2VIm79BXrNCdcSZeUJ gRBMXOvxLOiYomiLKgFVdLT5dq3cxnpxrpXZBzfpWK7ma4js7FcD9qL3LvVoYyhy NgB7YStULZPT6NolwqS9bIT+lh2rrR/sFieKjqd/GENpQ/qiBiac+I0JNTCvMcFT wC5raRI/dQriCyKEhHNtyyUWpoba6Iuk6JuSdb9Cnv4vQaWAwldYsurvdPJz9f18 z5eh2R+nxnO+Yq41UzaKfR32SsTFpYELJ5Ng3l84vrhvyCM0vXTCTDUdCyx4Fg==
    =GAHj
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)