Hello community,

here is the log from the commit of package pdns-recursor for openSUSE:Factory 
checked in at 2020-10-13 15:47:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/pdns-recursor (Old)
 and      /work/SRC/openSUSE:Factory/.pdns-recursor.new.3486 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "pdns-recursor"

Tue Oct 13 15:47:15 2020 rev:37 rq:841527 version:4.3.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/pdns-recursor/pdns-recursor.changes      
2020-09-09 18:12:04.123751450 +0200
+++ /work/SRC/openSUSE:Factory/.pdns-recursor.new.3486/pdns-recursor.changes    
2020-10-13 15:47:49.565506177 +0200
@@ -1,0 +2,12 @@
+Tue Oct 13 11:21:54 UTC 2020 - Adam Majer <adam.ma...@suse.de>
+
+- update to 4.3.5:
+  * fixes cache pollution related to DNSSEC validation.
+    (CVE-2020-25829, bsc#1177383)
+  * now raise an exception on invalid content in unknown records
+  * fixes the parsing of dont-throttle-netmasks in the presence of
+    dont-throttle-names
+
+- 9070.patch: refreshed, looks like only partially upstreamed
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ pdns-recursor.spec ++++++
--- /var/tmp/diff_new_pack.uFgRLH/_old  2020-10-13 15:47:50.273506482 +0200
+++ /var/tmp/diff_new_pack.uFgRLH/_new  2020-10-13 15:47:50.273506482 +0200
@@ -35,7 +35,7 @@
 %endif
 
 Name:           pdns-recursor
-Version:        4.3.4
+Version:        4.3.5
 Release:        0
 BuildRequires:  autoconf
 BuildRequires:  automake

++++++ 9070.patch ++++++
--- /var/tmp/diff_new_pack.uFgRLH/_old  2020-10-13 15:47:50.293506491 +0200
+++ /var/tmp/diff_new_pack.uFgRLH/_new  2020-10-13 15:47:50.293506491 +0200
@@ -16,10 +16,10 @@
  pdns/ws-recursor.cc  | 12 ++++++------
  4 files changed, 12 insertions(+), 12 deletions(-)
 
-Index: pdns-recursor-4.3.4/webserver.cc
+Index: pdns-recursor-4.3.5/webserver.cc
 ===================================================================
---- pdns-recursor-4.3.4.orig/webserver.cc
-+++ pdns-recursor-4.3.4/webserver.cc
+--- pdns-recursor-4.3.5.orig/webserver.cc
++++ pdns-recursor-4.3.5/webserver.cc
 @@ -107,7 +107,7 @@ static void bareHandlerWrapper(WebServer
  
  void WebServer::registerBareHandler(const string& url, HandlerFunction 
handler)
@@ -47,10 +47,10 @@
    registerBareHandler(url, f);
  }
  
-Index: pdns-recursor-4.3.4/ws-recursor.cc
+Index: pdns-recursor-4.3.5/ws-recursor.cc
 ===================================================================
---- pdns-recursor-4.3.4.orig/ws-recursor.cc
-+++ pdns-recursor-4.3.4/ws-recursor.cc
+--- pdns-recursor-4.3.5.orig/ws-recursor.cc
++++ pdns-recursor-4.3.5/ws-recursor.cc
 @@ -382,9 +382,9 @@ static void apiServerCacheFlush(HttpRequ
    DNSName canon = apiNameToDNSName(req->getvars["domain"]);
    bool subtree = (req->getvars.count("subtree") > 0 && 
req->getvars["subtree"].compare("true") == 0);
@@ -64,15 +64,6 @@
    resp->setBody(Json::object {
      { "count", count },
      { "result", "Flushed cache." }
-@@ -512,7 +512,7 @@ RecursorWebServer::RecursorWebServer(FDM
-   d_ws->bind();
- 
-   // legacy dispatch
--  d_ws->registerApiHandler("/jsonstat", 
boost::bind(&RecursorWebServer::jsonstat, this, _1, _2), true);
-+  d_ws->registerApiHandler("/jsonstat", 
std::bind(&RecursorWebServer::jsonstat, this, std::placeholders::_1, 
std::placeholders::_2), true);
-   d_ws->registerApiHandler("/api/v1/servers/localhost/cache/flush", 
&apiServerCacheFlush);
-   d_ws->registerApiHandler("/api/v1/servers/localhost/config/allow-from", 
&apiServerConfigAllowFrom);
-   d_ws->registerApiHandler("/api/v1/servers/localhost/config", 
&apiServerConfig);
 @@ -664,7 +664,7 @@ void AsyncServerNewConnectionMT(void *p)
  void AsyncServer::asyncWaitForConnections(FDMultiplexer* fdm, const 
newconnectioncb_t& callback)
  {
@@ -82,10 +73,3 @@
  }
  
  void AsyncServer::newConnection()
-@@ -747,5 +747,5 @@ void AsyncWebServer::go() {
-   auto server = std::dynamic_pointer_cast<AsyncServer>(d_server);
-   if (!server)
-     return;
--  server->asyncWaitForConnections(d_fdm, 
boost::bind(&AsyncWebServer::serveConnection, this, _1));
-+  server->asyncWaitForConnections(d_fdm, 
std::bind(&AsyncWebServer::serveConnection, this, std::placeholders::_1));
- }

++++++ pdns-recursor-4.3.4.tar.bz2 -> pdns-recursor-4.3.5.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/configure 
new/pdns-recursor-4.3.5/configure
--- old/pdns-recursor-4.3.4/configure   2020-09-04 23:19:40.000000000 +0200
+++ new/pdns-recursor-4.3.5/configure   2020-09-28 17:53:43.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.3.4.
+# Generated by GNU Autoconf 2.69 for pdns-recursor 4.3.5.
 #
 #
 # 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.3.4'
-PACKAGE_STRING='pdns-recursor 4.3.4'
+PACKAGE_VERSION='4.3.5'
+PACKAGE_STRING='pdns-recursor 4.3.5'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1519,7 +1519,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.3.4 to adapt to many kinds of systems.
+\`configure' configures pdns-recursor 4.3.5 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1590,7 +1590,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of pdns-recursor 4.3.4:";;
+     short | recursive ) echo "Configuration of pdns-recursor 4.3.5:";;
    esac
   cat <<\_ACEOF
 
@@ -1772,7 +1772,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-pdns-recursor configure 4.3.4
+pdns-recursor configure 4.3.5
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2365,7 +2365,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.3.4, which was
+It was created by pdns-recursor $as_me 4.3.5, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3233,7 +3233,7 @@
 
 # Define the identity of the package.
  PACKAGE='pdns-recursor'
- VERSION='4.3.4'
+ VERSION='4.3.5'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -25391,7 +25391,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.3.4, which was
+This file was extended by pdns-recursor $as_me 4.3.5, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25457,7 +25457,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.3.4
+pdns-recursor config.status 4.3.5
 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.3.4/configure.ac 
new/pdns-recursor-4.3.5/configure.ac
--- old/pdns-recursor-4.3.4/configure.ac        2020-09-04 23:19:23.000000000 
+0200
+++ new/pdns-recursor-4.3.5/configure.ac        2020-09-28 17:53:29.000000000 
+0200
@@ -1,6 +1,6 @@
 AC_PREREQ([2.61])
 
-AC_INIT([pdns-recursor], [4.3.4])
+AC_INIT([pdns-recursor], [4.3.5])
 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.3.4/dnsparser.cc 
new/pdns-recursor-4.3.5/dnsparser.cc
--- old/pdns-recursor-4.3.4/dnsparser.cc        2020-09-04 19:20:52.000000000 
+0200
+++ new/pdns-recursor-4.3.5/dnsparser.cc        2020-09-28 17:49:53.000000000 
+0200
@@ -50,7 +50,9 @@
     out.reserve(total+1);
     for(unsigned int n=0; n < total; ++n) {
       int c;
-      sscanf(relevant.c_str()+2*n, "%02x", &c);
+      if (sscanf(&relevant.at(2*n), "%02x", &c) != 1) {
+        throw MOADNSException("unable to read data at position " + 
std::to_string(2 * n) + " from unknown record of size " + 
std::to_string(relevant.size()));
+      }
       out.append(1, (char)c);
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/effective_tld_names.dat 
new/pdns-recursor-4.3.5/effective_tld_names.dat
--- old/pdns-recursor-4.3.4/effective_tld_names.dat     2020-09-04 
23:21:33.000000000 +0200
+++ new/pdns-recursor-4.3.5/effective_tld_names.dat     2020-09-28 
17:55:15.000000000 +0200
@@ -907,16 +907,18 @@
 sld.do
 web.do
 
-// dz : https://en.wikipedia.org/wiki/.dz
+// dz : http://www.nic.dz/images/pdf_nic/charte.pdf
 dz
+art.dz
+asso.dz
 com.dz
+edu.dz
+gov.dz
 org.dz
 net.dz
-gov.dz
-edu.dz
-asso.dz
 pol.dz
-art.dz
+soc.dz
+tm.dz
 
 // ec : http://www.nic.ec/reg/paso1.asp
 // Submitted by registry <vabb...@nic.ec>
@@ -4697,13 +4699,12 @@
 //      ccTLD for the Netherlands
 nl
 
-// no : http://www.norid.no/regelverk/index.en.html
-// The Norwegian registry has declined to notify us of updates. The web pages
-// referenced below are the official source of the data. There is also an
-// announce mailing list:
-// https://postlister.uninett.no/sympa/info/norid-diskusjon
+// no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/
+// Norid geographical second level domains : 
https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/
+// Norid category second level domains : 
https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/
+// Norid category second-level domains managed by parties other than Norid : 
https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/
 no
-// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html
+// Norid category second level domains : 
https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/
 fhs.no
 vgs.no
 fylkesbibl.no
@@ -4711,13 +4712,13 @@
 museum.no
 idrett.no
 priv.no
-// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html
+// Norid category second-level domains managed by parties other than Norid : 
https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/
 mil.no
 stat.no
 dep.no
 kommune.no
 herad.no
-// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html
+// Norid geographical second level domains : 
https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/
 // counties
 aa.no
 ah.no
@@ -7109,7 +7110,7 @@
 
 // newGTLDs
 
-// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2020-08-07T17:16:50Z
+// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2020-09-17T17:33:58Z
 // This list is auto-generated, don't edit it manually.
 // aaa : 2015-02-26 American Automobile Association, Inc.
 aaa
@@ -9016,9 +9017,6 @@
 // merckmsd : 2016-07-14 MSD Registry Holdings, Inc.
 merckmsd
 
-// metlife : 2015-05-07 MetLife Services and Solutions, LLC
-metlife
-
 // miami : 2013-12-19 Minds + Machines Group Limited
 miami
 
@@ -9187,7 +9185,7 @@
 // northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC
 northwesternmutual
 
-// norton : 2014-12-04 Symantec Corporation
+// norton : 2014-12-04 NortonLifeLock Inc.
 norton
 
 // now : 2015-06-25 Amazon Registry Services, Inc.
@@ -11039,7 +11037,8 @@
 cloudera.site
 
 // Cloudflare, Inc. : https://www.cloudflare.com/
-// Submitted by Jake Riesterer <publicsuffixl...@cloudflare.com>
+// Submitted by Cloudflare Team <publicsuffixl...@cloudflare.com>
+pages.dev
 trycloudflare.com
 workers.dev
 
@@ -13376,7 +13375,9 @@
 
 // WP Engine : https://wpengine.com/
 // Submitted by Michael Smith <michael.sm...@wpengine.com>
+// Submitted by Brandon DuRette <brandon.dure...@wpengine.com>
 wpenginepowered.com
+js.wpenginepowered.com
 
 // Impertrix Solutions : <https://impertrixcdn.com>
 // Submitted by Zhixiang Zhao <csu...@impertrix.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/pdns_recursor.1 
new/pdns-recursor-4.3.5/pdns_recursor.1
--- old/pdns-recursor-4.3.4/pdns_recursor.1     2020-09-04 23:21:33.000000000 
+0200
+++ new/pdns-recursor-4.3.5/pdns_recursor.1     2020-09-28 17:55:15.000000000 
+0200
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "PDNS_RECURSOR" "1" "Sep 04, 2020" "" "PowerDNS Recursor"
+.TH "PDNS_RECURSOR" "1" "Sep 28, 2020" "" "PowerDNS Recursor"
 .SH NAME
 pdns_recursor \- The PowerDNS Recursor binary
 .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/pdns_recursor.cc 
new/pdns-recursor-4.3.5/pdns_recursor.cc
--- old/pdns-recursor-4.3.4/pdns_recursor.cc    2020-09-04 19:20:52.000000000 
+0200
+++ new/pdns-recursor-4.3.5/pdns_recursor.cc    2020-09-28 17:49:53.000000000 
+0200
@@ -1815,11 +1815,15 @@
             ttd.tv_sec += g_tcpTimeout;
             t_fdm->addReadFD(dc->d_socket, handleRunningTCPQuestion, 
dc->d_tcpConnection, &ttd);
           } else {
-            // fd might have been removed by read error code, so expect an 
exception
+            // fd might have been removed by read error code, or a read 
timeout, so expect an exception
             try {
               t_fdm->setReadTTD(dc->d_socket, ttd, g_tcpTimeout);
             }
-            catch (FDMultiplexerException &) {
+            catch (const FDMultiplexerException &) {
+              // but if the FD was removed because of a timeout while we were 
sending a response,
+              // we need to re-arm it. If it was an error it will error again.
+              ttd.tv_sec += g_tcpTimeout;
+              t_fdm->addReadFD(dc->d_socket, handleRunningTCPQuestion, 
dc->d_tcpConnection, &ttd);
             }
           }
         }
@@ -4147,6 +4151,7 @@
     }
     g_dontThrottleNames.setState(std::move(dontThrottleNames));
 
+    parts.clear();
     NetmaskGroup dontThrottleNetmasks;
     stringtok(parts, ::arg()["dont-throttle-netmasks"], " ,");
     for (const auto &p : parts) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/pubsuffix.cc 
new/pdns-recursor-4.3.5/pubsuffix.cc
--- old/pdns-recursor-4.3.4/pubsuffix.cc        2020-09-04 23:21:33.000000000 
+0200
+++ new/pdns-recursor-4.3.5/pubsuffix.cc        2020-09-28 17:55:15.000000000 
+0200
@@ -643,14 +643,16 @@
 "org.do",
 "sld.do",
 "web.do",
+"art.dz",
+"asso.dz",
 "com.dz",
+"edu.dz",
+"gov.dz",
 "org.dz",
 "net.dz",
-"gov.dz",
-"edu.dz",
-"asso.dz",
 "pol.dz",
-"art.dz",
+"soc.dz",
+"tm.dz",
 "com.ec",
 "info.ec",
 "net.ec",
@@ -5706,6 +5708,7 @@
 "cloudcontrolled.com",
 "cloudcontrolapp.com",
 "cloudera.site",
+"pages.dev",
 "trycloudflare.com",
 "workers.dev",
 "wnext.app",
@@ -7104,6 +7107,7 @@
 "mintere.site",
 "cx.ua",
 "wpenginepowered.com",
+"js.wpenginepowered.com",
 "impertrixcdn.com",
 "impertrix.com",
 "gsj.bz",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/rec_control.1 
new/pdns-recursor-4.3.5/rec_control.1
--- old/pdns-recursor-4.3.4/rec_control.1       2020-09-04 23:21:32.000000000 
+0200
+++ new/pdns-recursor-4.3.5/rec_control.1       2020-09-28 17:55:14.000000000 
+0200
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "REC_CONTROL" "1" "Sep 04, 2020" "" "PowerDNS Recursor"
+.TH "REC_CONTROL" "1" "Sep 28, 2020" "" "PowerDNS Recursor"
 .SH NAME
 rec_control \- Command line tool to control a running Recursor
 .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/recursor_cache.cc 
new/pdns-recursor-4.3.5/recursor_cache.cc
--- old/pdns-recursor-4.3.4/recursor_cache.cc   2020-09-04 19:20:52.000000000 
+0200
+++ new/pdns-recursor-4.3.5/recursor_cache.cc   2020-09-28 17:51:57.000000000 
+0200
@@ -38,7 +38,39 @@
   return ret;
 }
 
-int32_t MemRecursorCache::handleHit(MemRecursorCache::OrderedTagIterator_t& 
entry, const DNSName& qname, const ComboAddress& who, vector<DNSRecord>* res, 
vector<std::shared_ptr<RRSIGRecordContent>>* signatures, 
std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* 
state, bool* wasAuth)
+static void updateDNSSECValidationStateFromCache(boost::optional<vState>& 
state, const vState stateUpdate)
+{
+  // if there was no state it's easy */
+  if (state == boost::none) {
+    state = stateUpdate;
+    return;
+  }
+
+  if (stateUpdate == vState::TA) {
+    state = vState::Secure;
+  }
+  else if (stateUpdate == vState::NTA) {
+    state = vState::Insecure;
+  }
+  else if (stateUpdate == vState::Bogus) {
+    state = stateUpdate;
+  }
+  else if (stateUpdate == vState::Indeterminate) {
+    state = stateUpdate;
+  }
+  else if (stateUpdate == vState::Insecure) {
+    if (*state != vState::Bogus && *state != vState::Indeterminate) {
+      state = stateUpdate;
+    }
+  }
+  else if (stateUpdate == vState::Secure) {
+    if (*state != vState::Bogus && *state != vState::Indeterminate) {
+      state = stateUpdate;
+    }
+  }
+}
+
+int32_t MemRecursorCache::handleHit(MemRecursorCache::OrderedTagIterator_t& 
entry, const DNSName& qname, const ComboAddress& who, vector<DNSRecord>* res, 
vector<std::shared_ptr<RRSIGRecordContent>>* signatures, 
std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, 
boost::optional<vState>& state, bool* wasAuth)
 {
   int32_t ttd = entry->d_ttd;
 
@@ -62,20 +94,18 @@
     }
   }
 
-  if(signatures) { // if you do an ANY lookup you are hosed XXXX
-    *signatures = entry->d_signatures;
+  if (signatures) {
+    signatures->insert(signatures->end(), entry->d_signatures.begin(), 
entry->d_signatures.end());
   }
 
-  if(authorityRecs) {
-    *authorityRecs = entry->d_authorityRecs;
+  if (authorityRecs) {
+    authorityRecs->insert(authorityRecs->end(), 
entry->d_authorityRecs.begin(), entry->d_authorityRecs.end());
   }
 
-  if (state) {
-    *state = entry->d_state;
-  }
+  updateDNSSECValidationStateFromCache(state, entry->d_state);
 
   if (wasAuth) {
-    *wasAuth = entry->d_auth;
+    *wasAuth = *wasAuth && entry->d_auth;
   }
 
   moveCacheItemToBack<SequencedTag>(d_cache, entry);
@@ -173,6 +203,7 @@
 // returns -1 for no hits
 int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& 
qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, 
vector<std::shared_ptr<RRSIGRecordContent>>* signatures, 
std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* 
state, bool* wasAuth)
 {
+  boost::optional<vState> cachedState{boost::none};
   time_t ttd=0;
   //  cerr<<"looking up "<< qname<<"|"+qt.getName()<<"\n";
   if(res) {
@@ -180,6 +211,12 @@
   }
 
   const uint16_t qtype = qt.getCode();
+  if (wasAuth) {
+    // we might retrieve more than one entry, we need to set that to true
+    // so it will be set to false if at least one entry is not auth
+    *wasAuth = true;
+  }
+
   /* If we don't have any netmask-specific entries at all, let's just skip this
      to be able to use the nice d_cachecache hack. */
   if (qtype != QType::ANY && !d_ecsIndex.empty()) {
@@ -188,23 +225,32 @@
 
       auto entryA = getEntryUsingECSIndex(now, qname, QType::A, requireAuth, 
who);
       if (entryA != d_cache.end()) {
-        ret = handleHit(entryA, qname, who, res, signatures, authorityRecs, 
variable, state, wasAuth);
+        ret = handleHit(entryA, qname, who, res, signatures, authorityRecs, 
variable, cachedState, wasAuth);
       }
       auto entryAAAA = getEntryUsingECSIndex(now, qname, QType::AAAA, 
requireAuth, who);
       if (entryAAAA != d_cache.end()) {
-        int32_t ttdAAAA = handleHit(entryAAAA, qname, who, res, signatures, 
authorityRecs, variable, state, wasAuth);
+        int32_t ttdAAAA = handleHit(entryAAAA, qname, who, res, signatures, 
authorityRecs, variable, cachedState, wasAuth);
         if (ret > 0) {
           ret = std::min(ret, ttdAAAA);
         } else {
           ret = ttdAAAA;
         }
       }
+
+      if (state && cachedState) {
+        *state = *cachedState;
+      }
       return ret > 0 ? static_cast<int32_t>(ret-now) : ret;
     }
     else {
       auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who);
       if (entry != d_cache.end()) {
-        return static_cast<int32_t>(handleHit(entry, qname, who, res, 
signatures, authorityRecs, variable, state, wasAuth) - now);
+        int32_t ret = handleHit(entry, qname, who, res, signatures, 
authorityRecs, variable, cachedState, wasAuth);
+        if (state && cachedState) {
+          *state = *cachedState;
+        }
+        return static_cast<int32_t>(ret-now);
+
       }
       return -1;
     }
@@ -224,12 +270,14 @@
       if (!entryMatches(firstIndexIterator, qtype, requireAuth, who))
         continue;
 
-      ttd = handleHit(firstIndexIterator, qname, who, res, signatures, 
authorityRecs, variable, state, wasAuth);
+      ttd = handleHit(firstIndexIterator, qname, who, res, signatures, 
authorityRecs, variable, cachedState, wasAuth);
 
       if(qt.getCode()!=QType::ANY && qt.getCode()!=QType::ADDR) // normally if 
we have a hit, we are done
         break;
     }
-
+    if (state && cachedState) {
+      *state = *cachedState;
+    }
     // cerr<<"time left : "<<ttd - now<<", "<< (res ? res->size() : 0) <<"\n";
     return static_cast<int32_t>(ttd-now);
   }
@@ -408,7 +456,15 @@
 {
   bool updated = false;
   uint16_t qtype = qt.getCode();
-  if (qtype != QType::ANY && qtype != QType::ADDR && !d_ecsIndex.empty()) {
+  if (qtype == QType::ANY) {
+    throw std::runtime_error("Trying to update the DNSSEC validation status of 
all (via ANY) records for " + qname.toLogString());
+  }
+  if (qtype == QType::ADDR) {
+    throw std::runtime_error("Trying to update the DNSSEC validation status of 
several (via ADDR) records for " + qname.toLogString());
+  }
+
+  
+  if (!d_ecsIndex.empty()) {
     auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who);
     if (entry == d_cache.end()) {
       return false;
@@ -435,8 +491,7 @@
     }
     updated = true;
 
-    if(qtype != QType::ANY && qtype != QType::ADDR) // normally if we have a 
hit, we are done
-      break;
+    break;
   }
 
   return updated;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/recursor_cache.hh 
new/pdns-recursor-4.3.5/recursor_cache.hh
--- old/pdns-recursor-4.3.4/recursor_cache.hh   2020-09-04 19:20:52.000000000 
+0200
+++ new/pdns-recursor-4.3.5/recursor_cache.hh   2020-09-28 17:51:57.000000000 
+0200
@@ -200,7 +200,7 @@
   bool entryMatches(OrderedTagIterator_t& entry, uint16_t qt, bool 
requireAuth, const ComboAddress& who);
   std::pair<NameOnlyHashedTagIterator_t, NameOnlyHashedTagIterator_t> 
getEntries(const DNSName &qname, const QType& qt);
   cache_t::const_iterator getEntryUsingECSIndex(time_t now, const DNSName 
&qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
-  int32_t handleHit(OrderedTagIterator_t& entry, const DNSName& qname, const 
ComboAddress& who, vector<DNSRecord>* res, 
vector<std::shared_ptr<RRSIGRecordContent>>* signatures, 
std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* 
state, bool* wasAuth);
+  int32_t handleHit(OrderedTagIterator_t& entry, const DNSName& qname, const 
ComboAddress& who, vector<DNSRecord>* res, 
vector<std::shared_ptr<RRSIGRecordContent>>* signatures, 
std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, 
boost::optional<vState>& state, bool* wasAuth);
 
 public:
   void preRemoval(const CacheEntry& entry)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/syncres.cc 
new/pdns-recursor-4.3.5/syncres.cc
--- old/pdns-recursor-4.3.4/syncres.cc  2020-09-04 19:20:52.000000000 +0200
+++ new/pdns-recursor-4.3.5/syncres.cc  2020-09-28 17:51:57.000000000 +0200
@@ -1161,6 +1161,11 @@
 
 void SyncRes::updateValidationStatusInCache(const DNSName &qname, const QType& 
qt, bool aa, vState newState) const
 {
+  if (qt == QType::ANY || qt == QType::ADDR) {
+    // not doing that
+    return;
+  }
+
   if (newState == Bogus) {
     t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, 
newState, s_maxbogusttl + d_now.tv_sec);
   }
@@ -1397,6 +1402,20 @@
   }
 }
 
+static void reapRecordsForValidation(std::map<uint16_t, CacheEntry>& entries, 
const vector<DNSRecord>& records)
+{
+  for (const auto& rec : records) {
+    entries[rec.d_type].records.push_back(rec);
+  }
+}
+
+static void reapSignaturesForValidation(std::map<uint16_t, CacheEntry>& 
entries, const vector<std::shared_ptr<RRSIGRecordContent>>& signatures)
+{
+  for (const auto& sig : signatures) {
+    entries[sig->d_type].signatures.push_back(sig);
+  }
+}
+
 /*!
  * Convience function to push the records from records into ret with a new TTL
  *
@@ -1601,7 +1620,25 @@
           cachedState = validateDNSKeys(sqname, cset, signatures, depth);
         }
         else {
-          cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, 
sqname, cset, signatures);
+          if (sqt == QType::ANY) {
+            std::map<uint16_t, CacheEntry> types;
+            reapRecordsForValidation(types, cset);
+            reapSignaturesForValidation(types, signatures);
+
+            for (const auto& type : types) {
+              vState cachedRecordState;
+              if (type.first == QType::DNSKEY) {
+                cachedRecordState = validateDNSKeys(sqname, 
type.second.records, type.second.signatures, depth);
+              }
+              else {
+                cachedRecordState = SyncRes::validateRecordsWithSigs(depth, 
sqname, QType(type.first), sqname, type.second.records, type.second.signatures);
+              }
+              updateDNSSECValidationState(cachedState, cachedRecordState);
+            }
+          }
+          else {
+            cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, 
sqname, cset, signatures);
+          }
         }
       }
       else {
@@ -1613,7 +1650,9 @@
         if (cachedState == Bogus) {
           capTTL = s_maxbogusttl;
         }
-        updateValidationStatusInCache(sqname, sqt, wasCachedAuth, cachedState);
+        if (sqt != QType::ANY && sqt != QType::ADDR) {
+          updateValidationStatusInCache(sqname, sqt, wasCachedAuth, 
cachedState);
+        }
       }
     }
 
@@ -1962,24 +2001,7 @@
 void SyncRes::updateValidationState(vState& state, const vState stateUpdate)
 {
   LOG(d_prefix<<"validation state was "<<std::string(vStates[state])<<", state 
update is "<<std::string(vStates[stateUpdate]));
-
-  if (stateUpdate == TA) {
-    state = Secure;
-  }
-  else if (stateUpdate == NTA) {
-    state = Insecure;
-  }
-  else if (stateUpdate == Bogus) {
-    state = Bogus;
-  }
-  else if (state == Indeterminate) {
-    state = stateUpdate;
-  }
-  else if (stateUpdate == Insecure) {
-    if (state != Bogus) {
-      state = Insecure;
-    }
-  }
+  updateDNSSECValidationState(state, stateUpdate);
   LOG(", validation state is now "<<std::string(vStates[state])<<endl);
 }
 
@@ -2404,7 +2426,7 @@
     recordcontents.insert(record.d_content);
   }
 
-  LOG(d_prefix<<"Going to validate "<<recordcontents.size()<< " record 
contents with "<<signatures.size()<<" sigs and "<<keys.size()<<" keys for 
"<<name<<endl);
+  LOG(d_prefix<<"Going to validate "<<recordcontents.size()<< " record 
contents with "<<signatures.size()<<" sigs and "<<keys.size()<<" keys for 
"<<name<<"|"<<qtype.getName()<<endl);
   if (validateWithKeySet(d_now.tv_sec, name, recordcontents, signatures, keys, 
false)) {
     LOG(d_prefix<<"Secure!"<<endl);
     return Secure;
@@ -3452,6 +3474,7 @@
     LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have 
negative SOA)" : "")<<endl);
 
     if (state == Secure && (lwr.d_aabit || sendRDQuery) && !negindic) {
+      LOG(prefix<<qname<<": NXDOMAIN without a negative indication (missing 
SOA in authority) in a DNSSEC secure zone, going Bogus"<<endl);
       updateValidationState(state, Bogus);
     }
 
@@ -3466,6 +3489,7 @@
     LOG(prefix<<qname<<": status=noerror, other types may exist, but we are 
done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) 
" : "")<<endl);
 
     if(state == Secure && (lwr.d_aabit || sendRDQuery) && !negindic) {
+      LOG(prefix<<qname<<": NODATA without a negative indication (missing SOA 
in authority) in a DNSSEC secure zone, going Bogus"<<endl);
       updateValidationState(state, Bogus);
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/test-syncres_cc8.cc 
new/pdns-recursor-4.3.5/test-syncres_cc8.cc
--- old/pdns-recursor-4.3.4/test-syncres_cc8.cc 2020-09-04 19:20:52.000000000 
+0200
+++ new/pdns-recursor-4.3.5/test-syncres_cc8.cc 2020-09-28 17:51:57.000000000 
+0200
@@ -1050,4 +1050,102 @@
   BOOST_CHECK_EQUAL(queriesCount, 3U);
 }
 
+BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure_any)
+{
+  /*
+    Validation is optional, and the first two queries (A, AAAA) do not ask for 
it,
+    so the answer are cached as Indeterminate.
+    The third query asks for validation, and is for ANY, so the answer should 
be marked as
+    Secure, after just-in-time validation.
+    The last query also requests validation but is for AAAA only.
+  */
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+
+  setDNSSECValidation(sr, DNSSECMode::Process);
+
+  primeHints();
+  const DNSName target("com.");
+  testkeysset_t keys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, 
DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
+  g_luaconfs.setState(luaconfsCopy);
+
+  size_t queriesCount = 0;
+
+  sr->setAsyncCallback([target, &queriesCount, keys](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 || type == QType::DNSKEY) {
+      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
+    }
+    else {
+      if (domain == target && type == QType::A) {
+        setLWResult(res, 0, true, false, true);
+        addRecordToLW(res, target, QType::A, "192.0.2.1");
+        addRRSIG(keys, res->d_records, DNSName("."), 300);
+        return 1;
+      }
+      else if (domain == target && type == QType::AAAA) {
+        setLWResult(res, 0, true, false, true);
+        addRecordToLW(res, target, QType::AAAA, "2001:db8::1");
+        addRRSIG(keys, res->d_records, DNSName("."), 300);
+        return 1;
+      }
+    }
+
+    return 0;
+  });
+
+  vector<DNSRecord> ret;
+  /* first query does not require validation */
+  sr->setDNSSECValidationRequested(false);
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
+  for (const auto& record : ret) {
+    BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
+  }
+  BOOST_CHECK_EQUAL(queriesCount, 1U);
+
+  ret.clear();
+  /* second query does not require validation either */
+  sr->setDNSSECValidationRequested(false);
+  res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
+  for (const auto& record : ret) {
+    BOOST_CHECK(record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
+  }
+  BOOST_CHECK_EQUAL(queriesCount, 2U);
+
+  ret.clear();
+  /* third one _does_ require validation */
+  sr->setDNSSECValidationRequested(true);
+  res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
+  for (const auto& record : ret) {
+    BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::AAAA || 
record.d_type == QType::RRSIG);
+  }
+  BOOST_CHECK_EQUAL(queriesCount, 4U);
+
+  ret.clear();
+  /* last one also requires validation */
+  sr->setDNSSECValidationRequested(true);
+  res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
+  for (const auto& record : ret) {
+    BOOST_CHECK(record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
+  }
+  BOOST_CHECK_EQUAL(queriesCount, 4U);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/validate.cc 
new/pdns-recursor-4.3.5/validate.cc
--- old/pdns-recursor-4.3.4/validate.cc 2020-09-04 19:20:52.000000000 +0200
+++ new/pdns-recursor-4.3.5/validate.cc 2020-09-28 17:51:57.000000000 +0200
@@ -1098,3 +1098,24 @@
 
   return DNSName();
 }
+
+void updateDNSSECValidationState(vState& state, const vState stateUpdate)
+{
+  if (stateUpdate == vState::TA) {
+    state = vState::Secure;
+  }
+  else if (stateUpdate == vState::NTA) {
+    state = vState::Insecure;
+  }
+  else if (stateUpdate == vState::Bogus) {
+    state = vState::Bogus;
+  }
+  else if (state == vState::Indeterminate) {
+    state = stateUpdate;
+  }
+  else if (stateUpdate == vState::Insecure) {
+    if (state != vState::Bogus) {
+      state = vState::Insecure;
+    }
+  }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/validate.hh 
new/pdns-recursor-4.3.5/validate.hh
--- old/pdns-recursor-4.3.4/validate.hh 2020-09-04 19:20:52.000000000 +0200
+++ new/pdns-recursor-4.3.5/validate.hh 2020-09-28 17:51:57.000000000 +0200
@@ -80,3 +80,4 @@
 bool isRRSIGNotExpired(const time_t now, const shared_ptr<RRSIGRecordContent> 
sig);
 bool isWildcardExpanded(unsigned int labelCount, const 
std::shared_ptr<RRSIGRecordContent>& sign);
 bool isWildcardExpandedOntoItself(const DNSName& owner, unsigned int 
labelCount, const std::shared_ptr<RRSIGRecordContent>& sign);
+void updateDNSSECValidationState(vState& state, const vState stateUpdate);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pdns-recursor-4.3.4/ws-recursor.cc 
new/pdns-recursor-4.3.5/ws-recursor.cc
--- old/pdns-recursor-4.3.4/ws-recursor.cc      2020-09-04 19:20:52.000000000 
+0200
+++ new/pdns-recursor-4.3.5/ws-recursor.cc      2020-09-28 17:49:53.000000000 
+0200
@@ -512,7 +512,7 @@
   d_ws->bind();
 
   // legacy dispatch
-  d_ws->registerApiHandler("/jsonstat", 
boost::bind(&RecursorWebServer::jsonstat, this, _1, _2), true);
+  d_ws->registerApiHandler("/jsonstat", 
std::bind(&RecursorWebServer::jsonstat, this, std::placeholders::_1, 
std::placeholders::_2), true);
   d_ws->registerApiHandler("/api/v1/servers/localhost/cache/flush", 
&apiServerCacheFlush);
   d_ws->registerApiHandler("/api/v1/servers/localhost/config/allow-from", 
&apiServerConfigAllowFrom);
   d_ws->registerApiHandler("/api/v1/servers/localhost/config", 
&apiServerConfig);
@@ -747,5 +747,5 @@
   auto server = std::dynamic_pointer_cast<AsyncServer>(d_server);
   if (!server)
     return;
-  server->asyncWaitForConnections(d_fdm, 
boost::bind(&AsyncWebServer::serveConnection, this, _1));
+  server->asyncWaitForConnections(d_fdm, 
std::bind(&AsyncWebServer::serveConnection, this, std::placeholders::_1));
 }



Reply via email to