Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package pdns-recursor for openSUSE:Factory 
checked in at 2022-04-12 21:51:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/pdns-recursor (Old)
 and      /work/SRC/openSUSE:Factory/.pdns-recursor.new.1900 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "pdns-recursor"

Tue Apr 12 21:51:10 2022 rev:53 rq:969514 version:4.6.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/pdns-recursor/pdns-recursor.changes      
2022-03-29 18:16:07.087175009 +0200
+++ /work/SRC/openSUSE:Factory/.pdns-recursor.new.1900/pdns-recursor.changes    
2022-04-12 21:52:01.969810841 +0200
@@ -1,0 +2,31 @@
+Mon Apr  4 16:41:19 UTC 2022 - Michael Str??der <[email protected]>
+
+- update to 4.6.2
+  * Improvements
+    - Allow disabling of processing the root hints.
+    - References: #11283, pull request 11360
+    - Log an error if pdns.DROP is used as rcode in Lua callbacks.
+    - References: #11288, pull request 11361
+    - A CNAME answer on DS query should abort DS retrieval.
+    - References: #11245, pull request 11358
+    - Reject non-apex NSEC(3)s that have both the NS and SOA bits set.
+    - References: #11225, pull request 11357
+    - Fix build with OpenSSL 3.0.0.
+    - References: pull request 11260
+    - Shorter thread names.
+    - References: #11137, pull request 11170
+    - Two more features to print (DoT and scrypt).
+    - References: #11109, pull request 11169
+  * Bug Fixes
+    - Be more careful using refresh mode only for the record asked.
+    - References: #11371, pull request 11418
+    - Use the Lua context stored in SyncRes when calling hooks.
+    - References: #11300, pull request 11380
+    - QType ADDR is supposed to be used internally only.
+    - References: #11338, pull request 11363
+    - If we get NODATA on an AAAA in followCNAMERecords, try native dns64.
+    - References: #11327, pull request 11362
+    - Initialize isNew before calling a exception throwing function.
+    - References: #11257, pull request 11359
+
+-------------------------------------------------------------------

Old:
----
  pdns-recursor-4.6.1.tar.bz2
  pdns-recursor-4.6.1.tar.bz2.sig

New:
----
  pdns-recursor-4.6.2.tar.bz2
  pdns-recursor-4.6.2.tar.bz2.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ pdns-recursor.spec ++++++
--- /var/tmp/diff_new_pack.YEa0cB/_old  2022-04-12 21:52:02.677802889 +0200
+++ /var/tmp/diff_new_pack.YEa0cB/_new  2022-04-12 21:52:02.681802845 +0200
@@ -25,7 +25,7 @@
 %endif
 
 Name:           pdns-recursor
-Version:        4.6.1
+Version:        4.6.2
 Release:        0
 BuildRequires:  autoconf
 BuildRequires:  automake

++++++ pdns-recursor-4.6.1.tar.bz2 -> pdns-recursor-4.6.2.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/configure 
new/pdns-recursor-4.6.2/configure
--- old/pdns-recursor-4.6.1/configure   2022-03-21 09:06:06.000000000 +0100
+++ new/pdns-recursor-4.6.2/configure   2022-03-30 15:30:59.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for pdns-recursor 4.6.1.
+# Generated by GNU Autoconf 2.69 for pdns-recursor 4.6.2.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@
 # Identity of this package.
 PACKAGE_NAME='pdns-recursor'
 PACKAGE_TARNAME='pdns-recursor'
-PACKAGE_VERSION='4.6.1'
-PACKAGE_STRING='pdns-recursor 4.6.1'
+PACKAGE_VERSION='4.6.2'
+PACKAGE_STRING='pdns-recursor 4.6.2'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1552,7 +1552,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-recursor 4.6.1 to adapt to many kinds of systems.
+\`configure' configures pdns-recursor 4.6.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1623,7 +1623,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of pdns-recursor 4.6.1:";;
+     short | recursive ) echo "Configuration of pdns-recursor 4.6.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1810,7 +1810,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-pdns-recursor configure 4.6.1
+pdns-recursor configure 4.6.2
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2527,7 +2527,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-recursor $as_me 4.6.1, which was
+It was created by pdns-recursor $as_me 4.6.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3395,7 +3395,7 @@
 
 # Define the identity of the package.
  PACKAGE='pdns-recursor'
- VERSION='4.6.1'
+ VERSION='4.6.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -28087,7 +28087,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by pdns-recursor $as_me 4.6.1, which was
+This file was extended by pdns-recursor $as_me 4.6.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -28153,7 +28153,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-pdns-recursor config.status 4.6.1
+pdns-recursor config.status 4.6.2
 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/pdns-recursor-4.6.1/configure.ac 
new/pdns-recursor-4.6.2/configure.ac
--- old/pdns-recursor-4.6.1/configure.ac        2022-03-21 09:05:54.000000000 
+0100
+++ new/pdns-recursor-4.6.2/configure.ac        2022-03-30 15:30:44.000000000 
+0200
@@ -1,6 +1,6 @@
 AC_PREREQ([2.69])
 
-AC_INIT([pdns-recursor], [4.6.1])
+AC_INIT([pdns-recursor], [4.6.2])
 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/credentials.cc 
new/pdns-recursor-4.6.2/credentials.cc
--- old/pdns-recursor-4.6.1/credentials.cc      2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/credentials.cc      2022-03-30 13:10:51.000000000 
+0200
@@ -31,6 +31,7 @@
 #ifdef HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT
 #include <openssl/evp.h>
 #include <openssl/kdf.h>
+#include <openssl/opensslv.h>
 #include <openssl/rand.h>
 #endif
 
@@ -105,8 +106,13 @@
     throw std::runtime_error("Error intializing the scrypt context to hash the 
supplied password");
   }
 
-  // OpenSSL 3.0 changed the string arg to const unsigned char*, other 
versions use const char *, so cast to const void * to satisfy both
-  if (EVP_PKEY_CTX_set1_pbe_pass(pctx.get(), reinterpret_cast<const 
void*>(password.data()), password.size()) <= 0) {
+  // OpenSSL 3.0 changed the string arg to const unsigned char*, other 
versions use const char *
+#if OPENSSL_VERSION_MAJOR >= 3
+  auto passwordData = reinterpret_cast<const char*>(password.data());
+#else
+  auto passwordData = reinterpret_cast<const unsigned char*>(password.data());
+#endif
+  if (EVP_PKEY_CTX_set1_pbe_pass(pctx.get(), passwordData, password.size()) <= 
0) {
     throw std::runtime_error("Error adding the password to the scrypt context 
to hash the supplied password");
   }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/effective_tld_names.dat 
new/pdns-recursor-4.6.2/effective_tld_names.dat
--- old/pdns-recursor-4.6.1/effective_tld_names.dat     2022-03-21 
09:07:30.000000000 +0100
+++ new/pdns-recursor-4.6.2/effective_tld_names.dat     2022-03-30 
15:33:30.000000000 +0200
@@ -7131,7 +7131,7 @@
 
 // newGTLDs
 
-// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2022-02-18T15:13:38Z
+// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2022-03-27T15:13:38Z
 // This list is auto-generated, don't edit it manually.
 // aaa : 2015-02-26 American Automobile Association, Inc.
 aaa
@@ -7334,7 +7334,7 @@
 // audible : 2015-06-25 Amazon Registry Services, Inc.
 audible
 
-// audio : 2014-03-20 UNR Corp.
+// audio : 2014-03-20 XYZ.COM LLC
 audio
 
 // auspost : 2015-08-13 Australian Postal Corporation
@@ -7703,7 +7703,7 @@
 // chintai : 2015-06-11 CHINTAI Corporation
 chintai
 
-// christmas : 2013-11-21 UNR Corp.
+// christmas : 2013-11-21 XYZ.COM LLC
 christmas
 
 // chrome : 2014-07-24 Charleston Road Registry Inc.
@@ -7952,7 +7952,7 @@
 // diamonds : 2013-09-22 Binky Moon, LLC
 diamonds
 
-// diet : 2014-06-26 UNR Corp.
+// diet : 2014-06-26 XYZ.COM LLC
 diet
 
 // digital : 2014-03-06 Binky Moon, LLC
@@ -8198,7 +8198,7 @@
 // florist : 2013-11-07 Binky Moon, LLC
 florist
 
-// flowers : 2014-10-09 UNR Corp.
+// flowers : 2014-10-09 XYZ.COM LLC
 flowers
 
 // fly : 2014-05-08 Charleston Road Registry Inc.
@@ -8285,7 +8285,7 @@
 // gallup : 2015-02-19 Gallup, Inc.
 gallup
 
-// game : 2015-05-28 UNR Corp.
+// game : 2015-05-28 XYZ.COM LLC
 game
 
 // games : 2015-05-28 Dog Beach, LLC
@@ -8420,7 +8420,7 @@
 // guide : 2013-09-13 Binky Moon, LLC
 guide
 
-// guitars : 2013-11-14 UNR Corp.
+// guitars : 2013-11-14 XYZ.COM LLC
 guitars
 
 // guru : 2013-08-27 Binky Moon, LLC
@@ -8468,7 +8468,7 @@
 // hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc.
 hgtv
 
-// hiphop : 2014-03-06 UNR Corp.
+// hiphop : 2014-03-06 Dot Hip Hop, LLC
 hiphop
 
 // hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc.
@@ -8516,7 +8516,7 @@
 // host : 2014-04-17 Radix FZC
 host
 
-// hosting : 2014-05-29 UNR Corp.
+// hosting : 2014-05-29 XYZ.COM LLC
 hosting
 
 // hot : 2015-08-27 Amazon Registry Services, Inc.
@@ -8885,7 +8885,7 @@
 // loft : 2015-07-30 Annco, Inc.
 loft
 
-// lol : 2015-01-30 UNR Corp.
+// lol : 2015-01-30 XYZ.COM LLC
 lol
 
 // london : 2013-11-14 Dot London Domains Limited
@@ -9041,7 +9041,7 @@
 // moi : 2014-12-18 Amazon Registry Services, Inc.
 moi
 
-// mom : 2015-04-16 UNR Corp.
+// mom : 2015-04-16 XYZ.COM LLC
 mom
 
 // monash : 2013-09-30 Monash University
@@ -9320,7 +9320,7 @@
 // physio : 2014-05-01 PhysBiz Pty Ltd
 physio
 
-// pics : 2013-11-14 UNR Corp.
+// pics : 2013-11-14 XYZ.COM LLC
 pics
 
 // pictet : 2014-06-26 Pictet Europe S.A.
@@ -9995,7 +9995,7 @@
 // toshiba : 2014-04-10 TOSHIBA Corporation
 toshiba
 
-// total : 2015-08-06 Total SA
+// total : 2015-08-06 TOTAL SE
 total
 
 // tours : 2015-01-22 Binky Moon, LLC
@@ -10633,6 +10633,12 @@
 // Submitted by Przemyslaw Plewa <[email protected]>
 beep.pl
 
+// Airkit : https://www.airkit.com/
+// Submitted by Grant Cooksey <[email protected]>
+airkitapps.com
+airkitapps-au.com
+airkitapps.eu
+
 // Aiven: https://aiven.io/
 // Submitted by Etienne Stalmans <[email protected]>
 aivencloud.com
@@ -11663,6 +11669,11 @@
 mytuleap.com
 tuleap-partners.com
 
+// Encoretivity AB: https://encore.dev
+// Submitted by Andr?? Eriksson <[email protected]>
+encr.app
+encoreapi.com
+
 // ECG Robotics, Inc: https://ecgrobotics.org
 // Submitted by <[email protected]>
 onred.one
@@ -11987,6 +11998,7 @@
 independent-review.uk
 public-inquiry.uk
 royal-commission.uk
+campaign.gov.uk
 service.gov.uk
 
 // CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk
@@ -12656,6 +12668,10 @@
 // Submitted by Victor Velchev <[email protected]>
 we.bs
 
+// Localcert : https://localcert.dev
+// Submitted by Lann Martin <[email protected]>
+*.user.localcert.dev
+
 // localzone.xyz
 // Submitted by Kenny Niehage <[email protected]>
 localzone.xyz
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/lua-base4.cc 
new/pdns-recursor-4.6.2/lua-base4.cc
--- old/pdns-recursor-4.6.1/lua-base4.cc        2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/lua-base4.cc        2022-03-30 13:10:52.000000000 
+0200
@@ -244,7 +244,8 @@
                                        {"YXRRSET",  RCode::YXRRSet  },
                                        {"NXRRSET",  RCode::NXRRSet  },
                                        {"NOTAUTH",  RCode::NotAuth  },
-                                       {"NOTZONE",  RCode::NotZone  }};
+                                       {"NOTZONE",  RCode::NotZone  },
+                                       {"DROP",    -2               }}; // To 
give backport-incompatibility warning
   for(const auto& rcode : rcodes)
     d_pd.push_back({rcode.first, rcode.second});
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/lua-recursor4.cc 
new/pdns-recursor-4.6.2/lua-recursor4.cc
--- old/pdns-recursor-4.6.1/lua-recursor4.cc    2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/lua-recursor4.cc    2022-03-30 13:10:52.000000000 
+0200
@@ -495,6 +495,15 @@
   features.emplace_back("PR8001_devicename", true);
 }
 
+static void warnDrop(const RecursorLua4::DNSQuestion& dq)
+{
+  if (dq.rcode == -2) {
+    g_log << Logger::Error << "Returning -2 (pdns.DROP) is not supported 
anymore, see 
https://docs.powerdns.com/recursor/lua-scripting/hooks.html#hooksemantics"; << 
endl;
+    // We *could* set policy here, but that would also mean interfering with 
rcode and the return code of the hook.
+    // So leave it at the error message.
+  }
+}
+
 void RecursorLua4::maintenance() const
 {
   if (d_maintenance) {
@@ -510,6 +519,7 @@
   et.add(RecEventTrace::LuaPreRPZ);
   bool ok = genhook(d_prerpz, dq, ret);
   et.add(RecEventTrace::LuaPreRPZ, ok, false);
+  warnDrop(dq);
   return ok;
 }
 
@@ -521,6 +531,7 @@
   et.add(RecEventTrace::LuaPreResolve);
   bool ok = genhook(d_preresolve, dq, ret);
   et.add(RecEventTrace::LuaPreResolve, ok, false);
+  warnDrop(dq);
   return ok;
 }
 
@@ -532,6 +543,7 @@
   et.add(RecEventTrace::LuaNXDomain);
   bool ok = genhook(d_nxdomain, dq, ret);
   et.add(RecEventTrace::LuaNXDomain, ok, false);
+  warnDrop(dq);
   return ok;
 }
 
@@ -543,6 +555,7 @@
   et.add(RecEventTrace::LuaNoData);
   bool ok = genhook(d_nodata, dq, ret);
   et.add(RecEventTrace::LuaNoData, ok, false);
+  warnDrop(dq);
   return ok;
 }
 
@@ -554,6 +567,7 @@
   et.add(RecEventTrace::LuaPostResolve);
   bool ok = genhook(d_postresolve, dq, ret);
   et.add(RecEventTrace::LuaPostResolve, ok, false);
+  warnDrop(dq);
   return ok;
 }
 
@@ -571,6 +585,7 @@
   et.add(RecEventTrace::LuaPreOutQuery);
   bool ok = genhook(d_preoutquery, dq, ret);
   et.add(RecEventTrace::LuaPreOutQuery, ok, false);
+  warnDrop(dq);
   return ok;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/lwres.cc 
new/pdns-recursor-4.6.2/lwres.cc
--- old/pdns-recursor-4.6.1/lwres.cc    2022-03-21 09:05:17.000000000 +0100
+++ new/pdns-recursor-4.6.2/lwres.cc    2022-03-30 13:10:52.000000000 +0200
@@ -434,32 +434,33 @@
     ret = arecvfrom(buf, 0, ip, &len, qid, domain, type, queryfd, now);
   }
   else {
-      bool isNew;
-      do {
-        try {
-          // If we get a new (not re-used) TCP connection that does not
-          // work, we give up. For reused connections, we assume the
-          // peer has closed it on error, so we retry. At some point we
-          // *will* get a new connection, so this loop is not endless.
-          isNew = tcpconnect(*now, ip, connection, dnsOverTLS);
-          ret = tcpsendrecv(ip, connection, localip, vpacket, len, buf);
+    bool isNew;
+    do {
+      try {
+        // If we get a new (not re-used) TCP connection that does not
+        // work, we give up. For reused connections, we assume the
+        // peer has closed it on error, so we retry. At some point we
+        // *will* get a new connection, so this loop is not endless.
+        isNew = true; // tcpconnect() might throw for new connections. In that 
case, we want to break the loop
+        isNew = tcpconnect(*now, ip, connection, dnsOverTLS);
+        ret = tcpsendrecv(ip, connection, localip, vpacket, len, buf);
 #ifdef HAVE_FSTRM
-          if (fstrmQEnabled) {
-            logFstreamQuery(fstrmLoggers, queryTime, localip, ip, !dnsOverTLS 
? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoT, 
context ? context->d_auth : boost::none, vpacket);
-          }
-#endif /* HAVE_FSTRM */
-          if (ret == LWResult::Result::Success) {
-            break;
-          }
-          connection.d_handler->close();
-        }
-        catch (const NetworkError&) {
-          ret = LWResult::Result::OSLimitError; // OS limits error
+        if (fstrmQEnabled) {
+          logFstreamQuery(fstrmLoggers, queryTime, localip, ip, !dnsOverTLS ? 
DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoT, context 
? context->d_auth : boost::none, vpacket);
         }
-        catch (const runtime_error&) {
-          ret = LWResult::Result::OSLimitError; // OS limits error 
(PermanentError is transport related)
+#endif /* HAVE_FSTRM */
+        if (ret == LWResult::Result::Success) {
+          break;
         }
-      } while (!isNew);
+        connection.d_handler->close();
+      }
+      catch (const NetworkError&) {
+        ret = LWResult::Result::OSLimitError; // OS limits error
+      }
+      catch (const runtime_error&) {
+        ret = LWResult::Result::OSLimitError; // OS limits error 
(PermanentError is transport related)
+      }
+    } while (!isNew);
   }
 
   lwr->d_usec=dt.udiff();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/pdns_recursor.1 
new/pdns-recursor-4.6.2/pdns_recursor.1
--- old/pdns-recursor-4.6.1/pdns_recursor.1     2022-03-21 09:07:29.000000000 
+0100
+++ new/pdns-recursor-4.6.2/pdns_recursor.1     2022-03-30 15:33:29.000000000 
+0200
@@ -27,7 +27,7 @@
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "PDNS_RECURSOR" "1" "Mar 21, 2022" "" "PowerDNS Recursor"
+.TH "PDNS_RECURSOR" "1" "Mar 30, 2022" "" "PowerDNS Recursor"
 .SH NAME
 pdns_recursor \- The PowerDNS Recursor binary
 .SH SYNOPSIS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/pdns_recursor.cc 
new/pdns-recursor-4.6.2/pdns_recursor.cc
--- old/pdns-recursor-4.6.1/pdns_recursor.cc    2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/pdns_recursor.cc    2022-03-30 13:10:52.000000000 
+0200
@@ -293,11 +293,11 @@
 
 //! used to send information to a newborn mthread
 struct DNSComboWriter {
-  DNSComboWriter(const std::string& query, const struct timeval& now): 
d_mdp(true, query), d_now(now), d_query(query)
+  DNSComboWriter(const std::string& query, const struct timeval& now, 
shared_ptr<RecursorLua4> luaContext): d_mdp(true, query), d_now(now), 
d_query(query), d_luaContext(luaContext)
   {
   }
 
-  DNSComboWriter(const std::string& query, const struct timeval& now, 
std::unordered_set<std::string>&& policyTags, LuaContext::LuaObject&& data, 
std::vector<DNSRecord>&& records): d_mdp(true, query), d_now(now), 
d_query(query), d_policyTags(std::move(policyTags)), 
d_records(std::move(records)), d_data(std::move(data))
+  DNSComboWriter(const std::string& query, const struct timeval& now, 
std::unordered_set<std::string>&& policyTags, shared_ptr<RecursorLua4> 
luaContext, LuaContext::LuaObject&& data, std::vector<DNSRecord>&& records): 
d_mdp(true, query), d_now(now), d_query(query), 
d_policyTags(std::move(policyTags)), d_records(std::move(records)), 
d_luaContext(luaContext), d_data(std::move(data))
   {
   }
 
@@ -359,7 +359,11 @@
   std::unordered_set<std::string> d_policyTags;
   std::string d_routingTag;
   std::vector<DNSRecord> d_records;
+
+  // d_data is tied to this LuaContext so we need to keep it alive and use it, 
not a newer one, as long as d_data exists
+  shared_ptr<RecursorLua4> d_luaContext;
   LuaContext::LuaObject d_data;
+
   EDNSSubnetOpts d_ednssubnet;
   shared_ptr<TCPConnection> d_tcpConnection;
   boost::optional<uint16_t> d_extendedErrorCode{boost::none};
@@ -1469,6 +1473,8 @@
 }
 #endif /* NOD_ENABLED */
 
+static bool answerIsNOData(uint16_t requestedType, int rcode, const 
std::vector<DNSRecord>& records);
+
 int followCNAMERecords(vector<DNSRecord>& ret, const QType qtype, int rcode)
 {
   vector<DNSRecord> resolved;
@@ -1489,8 +1495,14 @@
 
   rcode = directResolve(target, qtype, QClass::IN, resolved, t_pdl);
 
-  for(DNSRecord& rr :  resolved) {
-    ret.push_back(std::move(rr));
+  if (g_dns64Prefix && qtype == QType::AAAA && answerIsNOData(qtype, rcode, 
resolved)) {
+    rcode = getFakeAAAARecords(target, *g_dns64Prefix, resolved);
+  }
+
+  for (DNSRecord& rr : resolved) {
+    if (rr.d_place == DNSResourceRecord::ANSWER) {
+      ret.push_back(std::move(rr));
+    }
   }
   return rcode;
 }
@@ -1733,8 +1745,8 @@
     sr.setId(MT->getTid());
 
     bool DNSSECOK=false;
-    if(t_pdl) {
-      sr.setLuaEngine(t_pdl);
+    if(dc->d_luaContext) {
+      sr.setLuaEngine(dc->d_luaContext);
     }
     if(g_dnssecmode != DNSSECMode::Off) {
       sr.setDoDNSSEC(true);
@@ -1827,8 +1839,8 @@
       sr.setCacheOnly();
     }
 
-    if (t_pdl) {
-      t_pdl->prerpz(dq, res, sr.d_eventTrace);
+    if (dc->d_luaContext) {
+      dc->d_luaContext->prerpz(dq, res, sr.d_eventTrace);
     }
 
     // Check if the client has a policy attached to it
@@ -1875,7 +1887,7 @@
     }
 
     // if there is a RecursorLua active, and it 'took' the query in 
preResolve, we don't launch beginResolve
-    if (!t_pdl || !t_pdl->preresolve(dq, res, sr.d_eventTrace)) {
+    if (!dc->d_luaContext || !dc->d_luaContext->preresolve(dq, res, 
sr.d_eventTrace)) {
 
       if (!g_dns64PrefixReverse.empty() && dq.qtype == QType::PTR && 
dq.qname.isPartOf(g_dns64PrefixReverse)) {
         res = getFakePTRRecords(dq.qname, ret);
@@ -1886,7 +1898,7 @@
 
       if (wantsRPZ && appliedPolicy.d_kind != 
DNSFilterEngine::PolicyKind::NoAction) {
 
-        if (t_pdl && t_pdl->policyHitEventFilter(dc->d_source, 
dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, appliedPolicy, 
dc->d_policyTags, sr.d_discardedPolicies)) {
+        if (dc->d_luaContext && 
dc->d_luaContext->policyHitEventFilter(dc->d_source, dc->d_mdp.d_qname, 
QType(dc->d_mdp.d_qtype), dc->d_tcp, appliedPolicy, dc->d_policyTags, 
sr.d_discardedPolicies)) {
           /* reset to no match */
           appliedPolicy = DNSFilterEngine::Policy();
         }
@@ -1961,10 +1973,10 @@
         }
       }
 
-      if (t_pdl || (g_dns64Prefix && dq.qtype == QType::AAAA && 
!vStateIsBogus(dq.validationState))) {
+      if (dc->d_luaContext || (g_dns64Prefix && dq.qtype == QType::AAAA && 
!vStateIsBogus(dq.validationState))) {
         if (res == RCode::NoError) {
           if (answerIsNOData(dc->d_mdp.d_qtype, res, ret)) {
-            if (t_pdl && t_pdl->nodata(dq, res, sr.d_eventTrace)) {
+            if (dc->d_luaContext && dc->d_luaContext->nodata(dq, res, 
sr.d_eventTrace)) {
               shouldNotValidate = true;
               auto policyResult = handlePolicyHit(appliedPolicy, dc, sr, res, 
ret, pw);
               if (policyResult == PolicyResult::HaveAnswer) {
@@ -1980,7 +1992,7 @@
             }
           }
        }
-       else if (res == RCode::NXDomain && t_pdl && t_pdl->nxdomain(dq, res, 
sr.d_eventTrace)) {
+       else if (res == RCode::NXDomain && dc->d_luaContext && 
dc->d_luaContext->nxdomain(dq, res, sr.d_eventTrace)) {
           shouldNotValidate = true;
           auto policyResult = handlePolicyHit(appliedPolicy, dc, sr, res, ret, 
pw);
           if (policyResult == PolicyResult::HaveAnswer) {
@@ -1991,7 +2003,7 @@
           }
         }
 
-       if (t_pdl && t_pdl->postresolve(dq, res, sr.d_eventTrace)) {
+       if (dc->d_luaContext && dc->d_luaContext->postresolve(dq, res, 
sr.d_eventTrace)) {
           shouldNotValidate = true;
           auto policyResult = handlePolicyHit(appliedPolicy, dc, sr, res, ret, 
pw);
           // haveAnswer case redundant
@@ -2001,7 +2013,7 @@
         }
       }
     }
-    else if (t_pdl) {
+    else if (dc->d_luaContext) {
       // preresolve returned true
       shouldNotValidate = true;
       auto policyResult = handlePolicyHit(appliedPolicy, dc, sr, res, ret, pw);
@@ -2781,7 +2793,7 @@
       conn->state = TCPConnection::BYTE0;
       std::unique_ptr<DNSComboWriter> dc;
       try {
-        dc = std::make_unique<DNSComboWriter>(conn->data, g_now);
+        dc = std::make_unique<DNSComboWriter>(conn->data, g_now, t_pdl);
       }
       catch(const MOADNSException &mde) {
         g_stats.clientParseError++;
@@ -3328,7 +3340,7 @@
     return 0;
   }
 
-  auto dc = std::make_unique<DNSComboWriter>(question, g_now, 
std::move(policyTags), std::move(data), std::move(records));
+  auto dc = std::make_unique<DNSComboWriter>(question, g_now, 
std::move(policyTags), t_pdl, std::move(data), std::move(records));
   dc->setSocket(fd);
   dc->d_tag=ctag;
   dc->d_qhash=qhash;
@@ -3948,10 +3960,10 @@
       // Divide by 12 to get the original 2 hour cycle if s_maxcachettl is 
default (1 day)
       if (now.tv_sec - last_rootupdate > max(SyncRes::s_maxcachettl / 12, 
10U)) {
         int res = SyncRes::getRootNS(g_now, nullptr, 0);
-        if (!res) {
+        if (res == 0) {
           last_rootupdate=now.tv_sec;
           try {
-            primeRootNSZones(g_dnssecmode != DNSSECMode::Off, 0);
+            primeRootNSZones(g_dnssecmode, 0);
           }
           catch (const std::exception& e) {
             g_log<<Logger::Error<<"Exception while priming the root NS zones: 
"<<e.what()<<endl;
@@ -5716,7 +5728,7 @@
       g_log<<Logger::Critical<<"Priming cache failed, stopping"<<endl;
       return nullptr;
     }
-    g_log<<Logger::Warning<<"Done priming cache with root hints"<<endl;
+    g_log<<Logger::Debug<<"Done priming cache with root hints"<<endl;
   }
 
   t_packetCache = std::make_unique<RecursorPacketCache>();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/pubsuffix.cc 
new/pdns-recursor-4.6.2/pubsuffix.cc
--- old/pdns-recursor-4.6.1/pubsuffix.cc        2022-03-21 09:07:30.000000000 
+0100
+++ new/pdns-recursor-4.6.2/pubsuffix.cc        2022-03-30 15:33:30.000000000 
+0200
@@ -5546,6 +5546,9 @@
 "hlx.page",
 "hlx3.page",
 "beep.pl",
+"airkitapps.com",
+"airkitapps-au.com",
+"airkitapps.eu",
 "aivencloud.com",
 "barsy.ca",
 "kasserver.com",
@@ -6158,6 +6161,8 @@
 "en-root.fr",
 "mytuleap.com",
 "tuleap-partners.com",
+"encr.app",
+"encoreapi.com",
 "onred.one",
 "staging.onred.one",
 "eu.encoway.cloud",
@@ -6373,6 +6378,7 @@
 "independent-review.uk",
 "public-inquiry.uk",
 "royal-commission.uk",
+"campaign.gov.uk",
 "service.gov.uk",
 "api.gov.uk",
 "gehirn.ne.jp",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/rec-taskqueue.cc 
new/pdns-recursor-4.6.2/rec-taskqueue.cc
--- old/pdns-recursor-4.6.1/rec-taskqueue.cc    2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/rec-taskqueue.cc    2022-03-30 13:10:52.000000000 
+0200
@@ -76,6 +76,14 @@
 void pushAlmostExpiredTask(const DNSName& qname, uint16_t qtype, time_t 
deadline)
 {
   ++s_almost_expired_tasks_pushed;
+  switch (qtype) {
+    // Internal types
+  case QType::ENT:
+  case QType::ADDR:
+  case QType::ALIAS:
+  case QType::LUA:
+    return;
+  }
   pdns::ResolveTask task{qname, qtype, deadline, true, resolve};
   t_taskQueue.push(std::move(task));
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/rec_control.1 
new/pdns-recursor-4.6.2/rec_control.1
--- old/pdns-recursor-4.6.1/rec_control.1       2022-03-21 09:07:29.000000000 
+0100
+++ new/pdns-recursor-4.6.2/rec_control.1       2022-03-30 15:33:29.000000000 
+0200
@@ -27,7 +27,7 @@
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "REC_CONTROL" "1" "Mar 21, 2022" "" "PowerDNS Recursor"
+.TH "REC_CONTROL" "1" "Mar 30, 2022" "" "PowerDNS Recursor"
 .SH NAME
 rec_control \- Command line tool to control a running Recursor
 .SH SYNOPSIS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/recursor_cache.cc 
new/pdns-recursor-4.6.2/recursor_cache.cc
--- old/pdns-recursor-4.6.1/recursor_cache.cc   2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/recursor_cache.cc   2022-03-30 13:10:52.000000000 
+0200
@@ -248,7 +248,13 @@
       }
       else {
         if (!entry->d_submitted) {
-          pushAlmostExpiredTask(qname, qtype, entry->d_ttd);
+          if (qtype == QType::ADDR) {
+            pushAlmostExpiredTask(qname, QType::A, entry->d_ttd);
+            pushAlmostExpiredTask(qname, QType::AAAA, entry->d_ttd);
+          }
+          else {
+            pushAlmostExpiredTask(qname, qtype, entry->d_ttd);
+          }
           entry->d_submitted = true;
         }
       }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/reczones.cc 
new/pdns-recursor-4.6.2/reczones.cc
--- old/pdns-recursor-4.6.1/reczones.cc 2022-03-21 09:05:17.000000000 +0100
+++ new/pdns-recursor-4.6.2/reczones.cc 2022-03-30 13:10:52.000000000 +0200
@@ -53,7 +53,12 @@
 
   time_t now = time(nullptr);
 
-  if (::arg()["hint-file"].empty()) {
+  const string hintfile = ::arg()["hint-file"];
+  if (hintfile == "no") {
+    g_log << Logger::Debug << "Priming root disabled by hint-file=no" << endl;
+    return true;
+  }
+  if (hintfile.empty()) {
     DNSRecord arr, aaaarr, nsrr;
     nsrr.d_name = g_rootdnsname;
     arr.d_type = QType::A;
@@ -97,7 +102,7 @@
     }
   }
   else {
-    ZoneParserTNG zpt(::arg()["hint-file"]);
+    ZoneParserTNG zpt(hintfile);
     zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
     zpt.setMaxIncludes(::arg().asNum("max-include-depth"));
     DNSResourceRecord rr;
@@ -168,16 +173,14 @@
 // servers are authoritative for root-servers.net, and some
 // implementations reply not with a delegation on a root-servers.net
 // DS query, but with a NODATA response (the domain is unsigned).
-void primeRootNSZones(bool dnssecmode, unsigned int depth)
+void primeRootNSZones(DNSSECMode mode, unsigned int depth)
 {
   struct timeval now;
   gettimeofday(&now, 0);
   SyncRes sr(now);
 
-  if (dnssecmode) {
-    sr.setDoDNSSEC(true);
-    sr.setDNSSECValidationRequested(true);
-  }
+  sr.setDoDNSSEC(mode != DNSSECMode::Off);
+  sr.setDNSSECValidationRequested(mode != DNSSECMode::Off && mode != 
DNSSECMode::ProcessNoValidate);
 
   // beginResolve() can yield to another mthread that could trigger 
t_rootNSZones updates,
   // so make a local copy
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/syncres.cc 
new/pdns-recursor-4.6.2/syncres.cc
--- old/pdns-recursor-4.6.1/syncres.cc  2022-03-21 09:05:17.000000000 +0100
+++ new/pdns-recursor-4.6.2/syncres.cc  2022-03-30 13:10:52.000000000 +0200
@@ -1094,14 +1094,14 @@
   try {
     // First look for both A and AAAA in the cache and be satisfied if we find 
anything
     res_t cset;
-    if (s_doIPv4 && g_recCache->get(d_now.tv_sec, qname, QType::A, false, 
&cset, d_cacheRemote, d_refresh, d_routingTag) > 0) {
+    if (s_doIPv4 && g_recCache->get(d_now.tv_sec, qname, QType::A, false, 
&cset, d_cacheRemote, false, d_routingTag) > 0) {
       for (const auto &i : cset) {
         if (auto rec = getRR<ARecordContent>(i)) {
           ret.push_back(rec->getCA(53));
         }
       }
     }
-    if (s_doIPv6 && g_recCache->get(d_now.tv_sec, qname, QType::AAAA, false, 
&cset, d_cacheRemote, d_refresh, d_routingTag) > 0) {
+    if (s_doIPv6 && g_recCache->get(d_now.tv_sec, qname, QType::AAAA, false, 
&cset, d_cacheRemote, false, d_routingTag) > 0) {
       for (const auto &i : cset) {
         if (auto rec = getRR<AAAARecordContent>(i)) {
           ret.push_back(rec->getCA(53));
@@ -1139,7 +1139,7 @@
           // We have some IPv4 records, don't bother with going out to get 
IPv6, but do consult the cache, we might have
           // encountered some IPv6 glue
           cset.clear();
-          if (g_recCache->get(d_now.tv_sec, qname, QType::AAAA, false, &cset, 
d_cacheRemote, d_refresh, d_routingTag) > 0) {
+          if (g_recCache->get(d_now.tv_sec, qname, QType::AAAA, false, &cset, 
d_cacheRemote, false, d_routingTag) > 0) {
             for (const auto &i : cset) {
               if (auto rec = getRR<AAAARecordContent>(i)) {
                 ret.push_back(rec->getCA(53));
@@ -1222,7 +1222,7 @@
     vector<DNSRecord> ns;
     *flawedNSSet = false;
 
-    if(g_recCache->get(d_now.tv_sec, subdomain, QType::NS, false, &ns, 
d_cacheRemote, d_refresh, d_routingTag) > 0) {
+    if(g_recCache->get(d_now.tv_sec, subdomain, QType::NS, false, &ns, 
d_cacheRemote, false, d_routingTag) > 0) {
       bestns.reserve(ns.size());
 
       for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
@@ -1238,7 +1238,7 @@
           const DNSRecord& dr=*k;
          auto nrr = getRR<NSRecordContent>(dr);
           if(nrr && (!nrr->getNS().isPartOf(subdomain) || 
g_recCache->get(d_now.tv_sec, nrr->getNS(), nsqt,
-                                                                          
false, doLog() ? &aset : 0, d_cacheRemote, d_refresh, d_routingTag) > 5)) {
+                                                                          
false, doLog() ? &aset : 0, d_cacheRemote, false, d_routingTag) > 5)) {
             bestns.push_back(dr);
             LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for 
'"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);
             LOG(prefix<<qname<<": within bailiwick: "<< 
nrr->getNS().isPartOf(subdomain));
@@ -1292,7 +1292,7 @@
       LOG(prefix<<qname<<": reprimed the root"<<endl);
       /* let's prevent an infinite loop */
       if (!d_updatingRootNS) {
-        primeRootNSZones(g_dnssecmode != DNSSECMode::Off, depth);
+        primeRootNSZones(g_dnssecmode, depth);
         getRootNS(d_now, d_asyncResolve, depth);
       }
     }
@@ -2860,12 +2860,18 @@
         state = vState::BogusSelfSignedDS;
         dsFailed = true;
       }
-      else if (qtype == QType::DS && signer == qname && !signer.isRoot() && 
(type == QType::SOA || type == QType::NSEC || type == QType::NSEC3)) {
+      else if (qtype == QType::DS && signer == qname && !signer.isRoot()) {
+        if (type == QType::SOA || type == QType::NSEC || type == QType::NSEC3) 
{
         /* if we are trying to validate the DS or more likely NSEC(3)s proving 
that it does not exist, we have a problem.
            In that case let's go Bogus (we will check later if we missed a cut)
         */
-        state = vState::BogusSelfSignedDS;
-        dsFailed = true;
+          state = vState::BogusSelfSignedDS;
+          dsFailed = true;
+        }
+        else if (type == QType::CNAME) {
+          state = vState::BogusUnableToGetDSs;
+          dsFailed = true;
+        }
       }
       else if (qtype == QType::DNSKEY && signer == qname) {
         /* that actually does happen when a server returns NS records in 
authority
@@ -4614,9 +4620,9 @@
   sr.setAsyncCallback(asyncCallback);
 
   vector<DNSRecord> ret;
-  int res=-1;
+  int res = -1;
   try {
-    res=sr.beginResolve(g_rootdnsname, QType::NS, 1, ret, depth + 1);
+    res = sr.beginResolve(g_rootdnsname, QType::NS, 1, ret, depth + 1);
     if (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != 
DNSSECMode::ProcessNoValidate) {
       auto state = sr.getValidationState();
       if (vStateIsBogus(state)) {
@@ -4641,11 +4647,11 @@
     g_log<<Logger::Error<<"Failed to update . records, got an exception"<<endl;
   }
 
-  if(!res) {
-    g_log<<Logger::Notice<<"Refreshed . records"<<endl;
+  if (res == 0) {
+    g_log<<Logger::Debug<<"Refreshed . records"<<endl;
+  }
+  else {
+    g_log<<Logger::Warning<<"Failed to update root NS records, 
RCODE="<<res<<endl;
   }
-  else
-    g_log<<Logger::Warning<<"Failed to update . records, RCODE="<<res<<endl;
-
   return res;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/syncres.hh 
new/pdns-recursor-4.6.2/syncres.hh
--- old/pdns-recursor-4.6.1/syncres.hh  2022-03-21 09:05:17.000000000 +0100
+++ new/pdns-recursor-4.6.2/syncres.hh  2022-03-30 13:10:52.000000000 +0200
@@ -45,7 +45,7 @@
 #include <boost/tuple/tuple_comparison.hpp>
 #include "mtasker.hh"
 #include "iputils.hh"
-#include "validate.hh"
+#include "validate-recursor.hh"
 #include "ednssubnet.hh"
 #include "filterpo.hh"
 #include "negcache.hh"
@@ -1194,7 +1194,7 @@
 uint64_t* pleaseGetPacketCacheSize();
 void doCarbonDump(void*);
 bool primeHints(time_t now = time(nullptr));
-void primeRootNSZones(bool, unsigned int depth);
+void primeRootNSZones(DNSSECMode, unsigned int depth);
 
 struct WipeCacheResult
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/test-syncres_cc.cc 
new/pdns-recursor-4.6.2/test-syncres_cc.cc
--- old/pdns-recursor-4.6.1/test-syncres_cc.cc  2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/test-syncres_cc.cc  2022-03-30 13:10:52.000000000 
+0200
@@ -27,7 +27,7 @@
   return theArg;
 }
 
-void primeRootNSZones(bool, unsigned int)
+void primeRootNSZones(DNSSECMode, unsigned int)
 {
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/test-syncres_cc6.cc 
new/pdns-recursor-4.6.2/test-syncres_cc6.cc
--- old/pdns-recursor-4.6.1/test-syncres_cc6.cc 2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/test-syncres_cc6.cc 2022-03-30 13:10:52.000000000 
+0200
@@ -1767,4 +1767,116 @@
   BOOST_CHECK_EQUAL(queriesCount, 6U);
 }
 
+BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_broken_cname_ds)
+{
+  /* Test an Insecure domain that responds with a CNAME on a DS query */
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+
+  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+  primeHints();
+  const DNSName target("www.sub.powerdns.com.");
+  const ComboAddress targetAddr("192.0.2.42");
+  testkeysset_t keys, pdnskeys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+
+  // We have two set of keys as powerdns.com and sub.powerdns.com are Insecure 
but still have RRSIGS
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, 
DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, 
DNSSECKeeper::DIGEST_SHA256, keys);
+
+  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, 
DNSSECKeeper::DIGEST_SHA256, pdnskeys);
+  generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, 
DNSSECKeeper::DIGEST_SHA256, pdnskeys);
+
+  g_luaconfs.setState(luaconfsCopy);
+
+  size_t queriesCount = 0;
+
+  sr->setAsyncCallback([target, targetAddr, &queriesCount, keys, 
pdnskeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, 
bool sendRDQuery, int EDNS0Level, struct timeval* now, 
boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> 
context, LWResult* res, bool* chained) {
+    queriesCount++;
+
+    if (type == QType::DS) {
+      // Return a signed CNAME on a DS query for powerdns.com and 
sub.powerdns.com
+      if (domain == DNSName("powerdns.com.") || domain == 
DNSName("sub.powerdns.com.")) {
+        setLWResult(res, 0, true, false, true);
+        addRecordToLW(res, domain, QType::CNAME, "some.name", 
DNSResourceRecord::ANSWER, 300);
+        addRRSIG(pdnskeys, res->d_records, domain, 300);
+        return LWResult::Result::Success;
+      }
+      else {
+        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
+      }
+    }
+    else if (type == QType::DNSKEY) {
+      if (domain == DNSName("powerdns.com.") || domain == 
DNSName("sub.powerdns.com.")) {
+        return genericDSAndDNSKEYHandler(res, domain, domain, type, pdnskeys);
+      }
+      else {
+        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
+      }
+    }
+    else {
+      if (isRootServer(ip)) {
+        setLWResult(res, 0, false, false, true);
+        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", 
DNSResourceRecord::AUTHORITY, 3600);
+        addDS(DNSName("com."), 300, res->d_records, keys);
+        addRRSIG(keys, res->d_records, DNSName("."), 300);
+        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", 
DNSResourceRecord::ADDITIONAL, 3600);
+        return LWResult::Result::Success;
+      }
+      else if (ip == ComboAddress("192.0.2.1:53")) {
+        if (domain == DNSName("com.")) {
+          setLWResult(res, 0, true, false, true);
+          addRecordToLW(res, DNSName("com."), QType::NS, 
"a.gtld-servers.com.");
+          addRRSIG(keys, res->d_records, DNSName("com."), 300);
+          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", 
DNSResourceRecord::ADDITIONAL, 3600);
+        }
+        else {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, DNSName("powerdns.com."), QType::NS, 
"ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
+          addNSECRecordToLW(DNSName("powerdns.com."), 
DNSName("z.powerdns.com."), {QType::NS, QType::RRSIG}, 600, res->d_records);
+          addRRSIG(keys, res->d_records, DNSName("com."), 300);
+          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", 
DNSResourceRecord::ADDITIONAL, 3600);
+        }
+        return LWResult::Result::Success;
+      }
+      else if (ip == ComboAddress("192.0.2.2:53")) {
+        setLWResult(res, 0, false, false, true);
+        addRecordToLW(res, DNSName("sub.powerdns.com."), QType::NS, 
"ns1.sub.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
+        addRRSIG(pdnskeys, res->d_records, DNSName("powerdns.com."), 300);
+
+        addRecordToLW(res, "ns1.sub.powerdns.com.", QType::A, "192.0.2.3", 
DNSResourceRecord::ADDITIONAL, 3600);
+        return LWResult::Result::Success;
+      }
+      else if (ip == ComboAddress("192.0.2.3:53")) {
+        setLWResult(res, 0, true, false, true);
+        addRecordToLW(res, domain, QType::A, targetAddr.toString(), 
DNSResourceRecord::ANSWER, 3600);
+        addRRSIG(pdnskeys, res->d_records, DNSName("sub.powerdns.com."), 300);
+        return LWResult::Result::Success;
+      }
+    }
+
+    return LWResult::Result::Timeout;
+  });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
+  BOOST_CHECK(ret[0].d_type == QType::A);
+  BOOST_CHECK_EQUAL(queriesCount, 8U);
+
+  /* again, to test the cache */
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
+  BOOST_CHECK(ret[0].d_type == QType::A);
+  BOOST_CHECK_EQUAL(queriesCount, 8U);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/test-syncres_cc8.cc 
new/pdns-recursor-4.6.2/test-syncres_cc8.cc
--- old/pdns-recursor-4.6.1/test-syncres_cc8.cc 2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/test-syncres_cc8.cc 2022-03-30 13:10:52.000000000 
+0200
@@ -332,6 +332,46 @@
   BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
 }
 
+BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial_soa)
+{
+  initSR();
+
+  testkeysset_t keys;
+  generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, 
DNSSECKeeper::DIGEST_SHA256, keys);
+
+  vector<DNSRecord> records;
+
+  sortedRecords_t recordContents;
+  vector<shared_ptr<RRSIGRecordContent>> signatureContents;
+
+  /*
+   * RFC 5155 section 8.9:
+   * If there is an NSEC3 RR present in the response that matches the
+   * delegation name, then the validator MUST ensure that the NS bit is
+   * set and that the DS bit is not set in the Type Bit Maps field of the
+   * NSEC3 RR.
+   */
+  /*
+    The RRSIG from "." denies the existence of any type at a except NS and SOA.
+    NS has to be set since it is proving an insecure delegation, but SOA 
should NOT!
+  */
+  addNSECRecordToLW(DNSName("a."), DNSName("b."), {QType::NS, QType::SOA}, 
600, records);
+  recordContents.insert(records.at(0).d_content);
+  addRRSIG(keys, records, DNSName("."), 300);
+  signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
+  records.clear();
+
+  ContentSigPair pair;
+  pair.records = recordContents;
+  pair.signatures = signatureContents;
+  cspmap_t denialMap;
+  denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
+
+  /* Insecure because both NS and SOA are set, so this is not a proper 
delegation */
+  dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, 
true);
+  BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
+}
+
 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname)
 {
   initSR();
@@ -873,6 +913,46 @@
   dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, 
true);
   BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
 }
+
+BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial_soa)
+{
+  initSR();
+
+  testkeysset_t keys;
+  generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, 
DNSSECKeeper::DIGEST_SHA256, keys);
+
+  vector<DNSRecord> records;
+
+  sortedRecords_t recordContents;
+  vector<shared_ptr<RRSIGRecordContent>> signatureContents;
+
+  /*
+   * RFC 5155 section 8.9:
+   * If there is an NSEC3 RR present in the response that matches the
+   * delegation name, then the validator MUST ensure that the NS bit is
+   * set and that the DS bit is not set in the Type Bit Maps field of the
+   * NSEC3 RR.
+   */
+  /*
+    The RRSIG from "." denies the existence of any type at a except NS and SOA.
+    NS has to be set since it is proving an insecure delegation, but SOA 
should NOT!
+  */
+  addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", 
{QType::NS, QType::SOA}, 600, records);
+  recordContents.insert(records.at(0).d_content);
+  addRRSIG(keys, records, DNSName("."), 300);
+  signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
+
+  ContentSigPair pair;
+  pair.records = recordContents;
+  pair.signatures = signatureContents;
+  cspmap_t denialMap;
+  denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
+  records.clear();
+
+  /* Insecure because both NS and SOA are set, so it is not a proper 
delegation */
+  dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, 
true);
+  BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
+}
 
 BOOST_AUTO_TEST_CASE(test_nsec3_ent_opt_out)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/threadname.cc 
new/pdns-recursor-4.6.2/threadname.cc
--- old/pdns-recursor-4.6.1/threadname.cc       2022-03-21 09:05:17.000000000 
+0100
+++ new/pdns-recursor-4.6.2/threadname.cc       2022-03-30 13:10:52.000000000 
+0200
@@ -39,7 +39,7 @@
 
 #include "threadname.hh"
 
-void setThreadName(const std::string& threadName) {
+static int trySetThreadName(const std::string& threadName) {
   int retval = 0;
 
 #ifdef HAVE_PTHREAD_SETNAME_NP_2
@@ -58,6 +58,16 @@
   retval = pthread_setname_np(pthread_self(), threadName.c_str(), nullptr);
 #endif
 
+  return retval;
+}
+
+void setThreadName(const std::string& threadName) {
+  int retval = trySetThreadName(threadName);
+  if (retval == ERANGE) {
+    const std::string shortThreadName(threadName.substr(0, 15));
+    retval = trySetThreadName(shortThreadName);
+  }
+
   if (retval != 0) {
 #ifdef DNSDIST
     warnlog("Could not set thread name %s for thread: %s", threadName, 
strerror(retval));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/validate.cc 
new/pdns-recursor-4.6.2/validate.cc
--- old/pdns-recursor-4.6.1/validate.cc 2022-03-21 09:05:17.000000000 +0100
+++ new/pdns-recursor-4.6.2/validate.cc 2022-03-30 13:10:52.000000000 +0200
@@ -512,6 +512,16 @@
            continue;
         }
 
+        /* The NSEC is either a delegation one, from the parent zone, and
+         * must have the NS bit set but not the SOA one, or a regular NSEC
+         * either at apex (signer == owner) or with the SOA or NS bits clear.
+         */
+        const bool notApex = signer.countLabels() < owner.countLabels();
+        if (notApex && nsec->isSet(QType::NS) && nsec->isSet(QType::SOA)) {
+          LOG("However, that NSEC is not at the apex and has both the NS and 
the SOA bits set!"<<endl);
+          continue;
+        }
+
         /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
            Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
            nonexistence of any RRs below that zone cut, which include all RRs 
at
@@ -546,9 +556,11 @@
            * attention.  Bits corresponding to the delegation NS RRset and any
            * RRsets for which the parent zone has authoritative data MUST be 
set
            */
-          if (referralToUnsigned && qtype == QType::DS && 
!nsec->isSet(QType::NS)) {
-            LOG("However, no NS record exists at this level!"<<endl);
-            return dState::NODENIAL;
+          if (referralToUnsigned && qtype == QType::DS) {
+            if (!nsec->isSet(QType::NS)) {
+              LOG("However, no NS record exists at this level!"<<endl);
+              return dState::NODENIAL;
+            }
           }
 
           /* we know that the name exists (but this qtype doesn't) so except
@@ -641,9 +653,10 @@
           continue;
         }
 
+        const DNSName& hashedOwner = v.first.first;
         const DNSName signer = getSigner(v.second.signatures);
-        if (!v.first.first.isPartOf(signer)) {
-          LOG("Owner "<<v.first.first<<" is not part of the signer 
"<<signer<<", ignoring"<<endl);
+        if (!hashedOwner.isPartOf(signer)) {
+          LOG("Owner "<<hashedOwner<<" is not part of the signer "<<signer<<", 
ignoring"<<endl);
           continue;
         }
 
@@ -661,18 +674,28 @@
         nsec3Seen = true;
 
         LOG("\tquery hash: "<<toBase32Hex(h)<<endl);
-        string beginHash=fromBase32Hex(v.first.first.getRawLabels()[0]);
+        string beginHash = fromBase32Hex(hashedOwner.getRawLabels()[0]);
 
         // If the name exists, check if the qtype is denied
         if (beginHash == h) {
 
+          /* The NSEC3 is either a delegation one, from the parent zone, and
+           * must have the NS bit set but not the SOA one, or a regular NSEC3
+           * either at apex (signer == owner) or with the SOA or NS bits clear.
+           */
+          const bool notApex = signer.countLabels() < qname.countLabels();
+          if (notApex && nsec3->isSet(QType::NS) && nsec3->isSet(QType::SOA)) {
+            LOG("However, that NSEC3 is not at the apex and has both the NS 
and the SOA bits set!"<<endl);
+            continue;
+          }
+
           /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
              Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
              nonexistence of any RRs below that zone cut, which include all 
RRs at
              that (original) owner name other than DS RRs, and all RRs below 
that
              owner name regardless of type.
           */
-          if (qtype != QType::DS && isNSEC3AncestorDelegation(signer, 
v.first.first, nsec3)) {
+          if (qtype != QType::DS && isNSEC3AncestorDelegation(signer, qname, 
nsec3)) {
             /* this is an "ancestor delegation" NSEC3 RR */
             LOG("An ancestor delegation NSEC3 RR can only deny the existence 
of a DS"<<endl);
             return dState::NODENIAL;
@@ -692,9 +715,11 @@
            * set and that the DS bit is not set in the Type Bit Maps field of 
the
            * NSEC3 RR.
            */
-          if (referralToUnsigned && qtype == QType::DS && 
!nsec3->isSet(QType::NS)) {
-            LOG("However, no NS record exists at this level!"<<endl);
-            return dState::NODENIAL;
+          if (referralToUnsigned && qtype == QType::DS) {
+            if (!nsec3->isSet(QType::NS)) {
+              LOG("However, no NS record exists at this level!"<<endl);
+              return dState::NODENIAL;
+            }
           }
 
           return dState::NXQTYPE;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.6.1/version.cc 
new/pdns-recursor-4.6.2/version.cc
--- old/pdns-recursor-4.6.1/version.cc  2022-03-21 09:05:17.000000000 +0100
+++ new/pdns-recursor-4.6.2/version.cc  2022-03-30 13:10:52.000000000 +0200
@@ -138,6 +138,12 @@
 #ifdef HAVE_LIBCURL
     "curl " <<
 #endif
+#ifdef HAVE_DNS_OVER_TLS
+    "DoT " <<
+#endif
+#ifdef HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT
+    "scrypt " <<
+#endif
 #ifdef VERBOSELOG
     "verboselog" <<
 #endif

Reply via email to