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)); }