Hello community, here is the log from the commit of package pdns-recursor for openSUSE:Factory checked in at 2019-01-24 14:12:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/pdns-recursor (Old) and /work/SRC/openSUSE:Factory/.pdns-recursor.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "pdns-recursor" Thu Jan 24 14:12:25 2019 rev:24 rq:667620 version:4.1.9 Changes: -------- --- /work/SRC/openSUSE:Factory/pdns-recursor/pdns-recursor.changes 2018-11-27 10:46:18.979955971 +0100 +++ /work/SRC/openSUSE:Factory/.pdns-recursor.new.28833/pdns-recursor.changes 2019-01-24 14:12:26.763429558 +0100 @@ -1,0 +2,11 @@ +Mon Jan 21 14:02:26 UTC 2019 - adam.ma...@suse.de + +- update to 4.1.9 + https://blog.powerdns.com/2019/01/21/powerdns-recursor-4-1-9-released/ + + - Fixes case when Lua hooks are not called over TCP + (CVE-2019-3806, bsc#1121887) + - Fixes DNSSEC validation is not performed for AA=0 responses + (CVE-2019-3807, bsc#1121889) + +------------------------------------------------------------------- Old: ---- pdns-recursor-4.1.8.tar.bz2 pdns-recursor-4.1.8.tar.bz2.sig New: ---- pdns-recursor-4.1.9.tar.bz2 pdns-recursor-4.1.9.tar.bz2.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ pdns-recursor.spec ++++++ --- /var/tmp/diff_new_pack.o45Du3/_old 2019-01-24 14:12:27.223429027 +0100 +++ /var/tmp/diff_new_pack.o45Du3/_new 2019-01-24 14:12:27.223429027 +0100 @@ -1,7 +1,7 @@ # # spec file for package pdns-recursor # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -35,7 +35,7 @@ %endif Name: pdns-recursor -Version: 4.1.8 +Version: 4.1.9 Release: 0 BuildRequires: autoconf BuildRequires: automake ++++++ pdns-recursor-4.1.8.tar.bz2 -> pdns-recursor-4.1.9.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pdns-recursor-4.1.8/.version new/pdns-recursor-4.1.9/.version --- old/pdns-recursor-4.1.8/.version 2018-11-26 14:23:43.000000000 +0100 +++ new/pdns-recursor-4.1.9/.version 2019-01-21 10:28:55.000000000 +0100 @@ -1 +1 @@ -4.1.8 +4.1.9 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pdns-recursor-4.1.8/configure new/pdns-recursor-4.1.9/configure --- old/pdns-recursor-4.1.8/configure 2018-11-26 14:23:42.000000000 +0100 +++ new/pdns-recursor-4.1.9/configure 2019-01-21 10:28:54.000000000 +0100 @@ -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.1.8. +# Generated by GNU Autoconf 2.69 for pdns-recursor 4.1.9. # # # 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.1.8' -PACKAGE_STRING='pdns-recursor 4.1.8' +PACKAGE_VERSION='4.1.9' +PACKAGE_STRING='pdns-recursor 4.1.9' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1445,7 +1445,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.1.8 to adapt to many kinds of systems. +\`configure' configures pdns-recursor 4.1.9 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1515,7 +1515,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pdns-recursor 4.1.8:";; + short | recursive ) echo "Configuration of pdns-recursor 4.1.9:";; esac cat <<\_ACEOF @@ -1677,7 +1677,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pdns-recursor configure 4.1.8 +pdns-recursor configure 4.1.9 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2270,7 +2270,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.1.8, which was +It was created by pdns-recursor $as_me 4.1.9, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3133,7 +3133,7 @@ # Define the identity of the package. PACKAGE='pdns-recursor' - VERSION='4.1.8' + VERSION='4.1.9' cat >>confdefs.h <<_ACEOF @@ -21846,7 +21846,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.1.8, which was +This file was extended by pdns-recursor $as_me 4.1.9, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -21912,7 +21912,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.1.8 +pdns-recursor config.status 4.1.9 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.1.8/pdns_recursor.1 new/pdns-recursor-4.1.9/pdns_recursor.1 --- old/pdns-recursor-4.1.8/pdns_recursor.1 2018-11-26 14:24:33.000000000 +0100 +++ new/pdns-recursor-4.1.9/pdns_recursor.1 2019-01-21 10:29:46.000000000 +0100 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "PDNS_RECURSOR" "1" "Nov 26, 2018" "4.1" "PowerDNS Recursor" +.TH "PDNS_RECURSOR" "1" "Jan 21, 2019" "4.1" "PowerDNS Recursor" .SH NAME pdns_recursor \- The PowerDNS Recursor binary . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pdns-recursor-4.1.8/pdns_recursor.cc new/pdns-recursor-4.1.9/pdns_recursor.cc --- old/pdns-recursor-4.1.8/pdns_recursor.cc 2018-11-26 14:23:30.000000000 +0100 +++ new/pdns-recursor-4.1.9/pdns_recursor.cc 2019-01-21 10:28:41.000000000 +0100 @@ -1542,9 +1542,9 @@ dc->d_uuid = (*t_uuidGenerator)(); } + const struct dnsheader* dh = (const struct dnsheader*) conn->data; if(luaconfsLocal->protobufServer) { try { - const struct dnsheader* dh = (const struct dnsheader*) conn->data; if (!luaconfsLocal->protobufTaggedOnly) { protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, dc->d_uuid, conn->d_remote, dest, dc->d_ednssubnet.source, true, dh->id, conn->qlen, qname, qtype, qclass, dc->d_policyTags, dc->d_requestorId, dc->d_deviceId); @@ -1556,6 +1556,16 @@ } } #endif + if(t_pdl) { + if(t_pdl->ipfilter(dc->d_remote, dc->d_local, *dh)) { + delete dc; + if(!g_quiet) + L<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED TCP question from "<<conn->d_remote.toStringWithPort()<<" based on policy"<<endl; + g_stats.policyDrops++; + return; + } + } + if(dc->d_mdp.d_header.qr) { delete dc; g_stats.ignoredCount++; @@ -2310,27 +2320,14 @@ } } -// This function is only called by the distributor thread, when pdns-distributes-queries is set -void distributeAsyncFunction(const string& packet, const pipefunc_t& func) +static bool trySendingQueryToWorker(unsigned int target, ThreadMSG* tmsg) { - if (t_id != s_distributorThreadID) { - L<<Logger::Error<<"distributeAsyncFunction() has been called by a worker ("<<t_id<<")"<<endl; - exit(1); - } - - unsigned int hash = hashQuestion(packet.c_str(), packet.length(), g_disthashseed); - unsigned int target = 1 + (hash % (g_pipes.size()-1)); - if(target == static_cast<unsigned int>(s_distributorThreadID)) { L<<Logger::Error<<"distributeAsyncFunction() tried to assign a query to the distributor"<<endl; exit(1); } ThreadPipeSet& tps = g_pipes[target]; - ThreadMSG* tmsg = new ThreadMSG(); - tmsg->func = func; - tmsg->wantAnswer = false; - ssize_t written = write(tps.writeQueriesToThread, &tmsg, sizeof(tmsg)); if (written > 0) { if (static_cast<size_t>(written) != sizeof(tmsg)) { @@ -2340,13 +2337,46 @@ } else { int error = errno; - delete tmsg; if (error == EAGAIN || error == EWOULDBLOCK) { - g_stats.queryPipeFullDrops++; + /* the pipe is full, sorry */ + return false; } else { + delete tmsg; unixDie("write to thread pipe returned wrong size or error:" + std::to_string(error)); } } + + return true; +} + +// This function is only called by the distributor thread, when pdns-distributes-queries is set +void distributeAsyncFunction(const string& packet, const pipefunc_t& func) +{ + if (t_id != s_distributorThreadID) { + L<<Logger::Error<<"distributeAsyncFunction() has been called by a worker ("<<t_id<<")"<<endl; + exit(1); + } + + unsigned int hash = hashQuestion(packet.c_str(), packet.length(), g_disthashseed); + unsigned int target = 1 + (hash % (g_pipes.size()-1)); + + ThreadMSG* tmsg = new ThreadMSG(); + tmsg->func = func; + tmsg->wantAnswer = false; + + if (!trySendingQueryToWorker(target, tmsg)) { + /* if this function failed but did not raise an exception, it means that the pipe + was full, let's try another one */ + unsigned int newTarget = 0; + do { + newTarget = 1 + dns_random(g_pipes.size()-1); + } while (newTarget == target); + + if (!trySendingQueryToWorker(newTarget, tmsg)) { + g_stats.queryPipeFullDrops++; + delete tmsg; + } + } } static void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var) @@ -3258,7 +3288,7 @@ #endif L<<Logger::Warning<<"Done priming cache with root hints"<<endl; - if(worker && (!g_weDistributeQueries || t_id != s_distributorThreadID)) { + if(worker) { try { if(!::arg()["lua-dns-script"].empty()) { t_pdl = std::make_shared<RecursorLua4>(::arg()["lua-dns-script"]); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pdns-recursor-4.1.8/rec_control.1 new/pdns-recursor-4.1.9/rec_control.1 --- old/pdns-recursor-4.1.8/rec_control.1 2018-11-26 14:24:33.000000000 +0100 +++ new/pdns-recursor-4.1.9/rec_control.1 2019-01-21 10:29:46.000000000 +0100 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "REC_CONTROL" "1" "Nov 26, 2018" "4.1" "PowerDNS Recursor" +.TH "REC_CONTROL" "1" "Jan 21, 2019" "4.1" "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.1.8/syncres.cc new/pdns-recursor-4.1.9/syncres.cc --- old/pdns-recursor-4.1.8/syncres.cc 2018-11-26 14:23:30.000000000 +0100 +++ new/pdns-recursor-4.1.9/syncres.cc 2019-01-21 10:28:41.000000000 +0100 @@ -1916,8 +1916,9 @@ return Bogus; } -RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount) +RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery) { + bool wasForwardRecurse = wasForwarded && rdQuery; tcache_t tcache; string prefix; @@ -2068,7 +2069,8 @@ set the TC bit solely because these RRSIG RRs didn't fit." */ bool isAA = lwr.d_aabit && i->first.place != DNSResourceRecord::ADDITIONAL; - if (isAA && isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) { + bool expectSignature = i->first.place == DNSResourceRecord::ANSWER || ((lwr.d_aabit || wasForwardRecurse) && i->first.place != DNSResourceRecord::ADDITIONAL); + if (isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) { /* rfc2181 states: Note that the answer section of an authoritative answer normally @@ -2080,6 +2082,7 @@ associated with the alias. */ isAA = false; + expectSignature = false; } vState recordState = getValidationStatus(i->first.name, false); @@ -2088,7 +2091,7 @@ if (shouldValidate() && recordState == Secure) { vState initialState = recordState; - if (isAA) { + if (expectSignature) { if (i->first.place != DNSResourceRecord::ADDITIONAL) { /* the additional entries can be insecure, like glue: @@ -2118,7 +2121,7 @@ } } - if (initialState == Secure && state != recordState && isAA) { + if (initialState == Secure && state != recordState && expectSignature) { updateValidationState(state, recordState); } } @@ -2508,7 +2511,7 @@ bool needWildcardProof = false; unsigned int wildcardLabelsCount; - *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, wildcardLabelsCount); + *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, wildcardLabelsCount, sendRDQuery); if (*rcode != RCode::NoError) { return true; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pdns-recursor-4.1.8/syncres.hh new/pdns-recursor-4.1.9/syncres.hh --- old/pdns-recursor-4.1.8/syncres.hh 2018-11-26 14:23:30.000000000 +0100 +++ new/pdns-recursor-4.1.9/syncres.hh 2019-01-21 10:28:41.000000000 +0100 @@ -750,7 +750,7 @@ bool throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery); vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<DNSName >::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<DNSName >& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly); - RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount); + RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery); bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const unsigned int wildcardLabelsCount); bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pdns-recursor-4.1.8/test-recursorcache_cc.cc new/pdns-recursor-4.1.9/test-recursorcache_cc.cc --- old/pdns-recursor-4.1.8/test-recursorcache_cc.cc 2018-11-26 14:23:30.000000000 +0100 +++ new/pdns-recursor-4.1.9/test-recursorcache_cc.cc 2019-01-21 10:28:41.000000000 +0100 @@ -340,6 +340,46 @@ } } +BOOST_AUTO_TEST_CASE(test_RecursorCacheGhost) { + MemRecursorCache MRC; + + std::vector<DNSRecord> records; + std::vector<std::shared_ptr<DNSRecord>> authRecords; + std::vector<std::shared_ptr<RRSIGRecordContent>> signatures; + time_t now = time(nullptr); + + BOOST_CHECK_EQUAL(MRC.size(), 0); + + /* insert NS coming from a delegation */ + time_t ttd = now + 30; + DNSName ghost("ghost.powerdns.com."); + DNSRecord ns1; + std::string ns1Content("ns1.ghost.powerdns.com."); + ns1.d_name = ghost; + ns1.d_type = QType::NS; + ns1.d_class = QClass::IN; + ns1.d_content = std::make_shared<NSRecordContent>(ns1Content); + ns1.d_ttl = static_cast<uint32_t>(ttd); + ns1.d_place = DNSResourceRecord::ANSWER; + records.push_back(ns1); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* try to raise the TTL, simulating the delegated authoritative server + raising the TTL so the zone stays alive */ + records.clear(); + ns1.d_ttl = static_cast<uint32_t>(ttd + 3600); + records.push_back(ns1); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, boost::none); + BOOST_CHECK_EQUAL(MRC.size(), 1); + + /* the TTL should not have been raisd */ + std::vector<DNSRecord> retrieved; + BOOST_CHECK_EQUAL(MRC.get(now, ghost, QType(QType::NS), false, &retrieved, ComboAddress("192.0.2.2"), nullptr), (ttd-now)); + BOOST_REQUIRE_EQUAL(retrieved.size(), 1); + BOOST_CHECK_EQUAL(retrieved.at(0).d_ttl, static_cast<uint32_t>(ttd)); +} + BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries) { MemRecursorCache MRC; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pdns-recursor-4.1.8/test-syncres_cc.cc new/pdns-recursor-4.1.9/test-syncres_cc.cc --- old/pdns-recursor-4.1.8/test-syncres_cc.cc 2018-11-26 14:23:30.000000000 +0100 +++ new/pdns-recursor-4.1.9/test-syncres_cc.cc 2019-01-21 10:28:41.000000000 +0100 @@ -233,17 +233,19 @@ return false; } -static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign, boost::optional<uint8_t> algo=boost::none, boost::optional<uint32_t> inception=boost::none) +static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign, boost::optional<uint8_t> algo=boost::none, boost::optional<uint32_t> inception=boost::none, boost::optional<time_t> now=boost::none) { - time_t now = time(nullptr); + if (!now) { + now = time(nullptr); + } DNSKEYRecordContent drc = dpk.getDNSKEY(); const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey(); rrc.d_type = signQType; rrc.d_labels = signQName.countLabels() - signQName.isWildcard(); rrc.d_originalttl = signTTL; - rrc.d_siginception = inception ? *inception : (now - 10); - rrc.d_sigexpire = now + sigValidity; + rrc.d_siginception = inception ? *inception : (*now - 10); + rrc.d_sigexpire = *now + sigValidity; rrc.d_signer = signer; rrc.d_tag = 0; rrc.d_tag = drc.getTag(); @@ -256,7 +258,7 @@ typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t; -static bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional<uint8_t> algo=boost::none, boost::optional<DNSName> wildcard=boost::none) +static bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional<uint8_t> algo=boost::none, boost::optional<DNSName> wildcard=boost::none, boost::optional<time_t> now=boost::none) { if (records.empty()) { return false; @@ -279,7 +281,7 @@ } RRSIGRecordContent rrc; - computeRRSIG(it->second.first, signer, wildcard ? *wildcard : records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo); + computeRRSIG(it->second.first, signer, wildcard ? *wildcard : records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo, boost::none, now); if (broken) { rrc.d_signature[0] ^= 42; } @@ -4268,6 +4270,74 @@ BOOST_CHECK_EQUAL(queriesCount, 2); } +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig_no_aa) { + std::unique_ptr<SyncRes> sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, 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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) { + queriesCount++; + + if (domain == target && type == QType::NS) { + + /* set AA=0 */ + setLWResult(res, 0, false, false, true); + char addr[] = "a.root-servers.net."; + for (char idx = 'a'; idx <= 'm'; idx++) { + addr[0] = idx; + addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); + } + + addRRSIG(keys, res->d_records, domain, 300, true); + + addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); + + return 1; + } else if (domain == target && type == QType::DNSKEY) { + + setLWResult(res, 0, true, false, true); + + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + + return 1; + } + + return 0; + }); + + vector<DNSRecord> ret; + int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + /* 13 NS + 1 RRSIG */ + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 2); + + /* again, to test the cache, but we will trigger a new outgoing query since + the answer did not have the AA bit set */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); + BOOST_REQUIRE_EQUAL(ret.size(), 14); + BOOST_CHECK_EQUAL(queriesCount, 3); +} + BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) { std::unique_ptr<SyncRes> sr; initSR(sr, true); @@ -8853,8 +8923,9 @@ g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; + const time_t fixedNow = sr->getNow().tv_sec; - 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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) { + sr->setAsyncCallback([target,&queriesCount,keys,fixedNow](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, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) { queriesCount++; DNSName auth = domain; @@ -8868,14 +8939,13 @@ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); addRRSIG(keys, res->d_records, domain, 300); addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records); - addRRSIG(keys, res->d_records, domain, 1); + addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, fixedNow); return 1; } return 0; }); - const time_t now = sr->getNow().tv_sec; vector<DNSRecord> ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); @@ -8887,7 +8957,7 @@ NegCache::NegCacheEntry ne; BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1); BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true); - BOOST_CHECK_EQUAL(ne.d_ttd, now + 1); + BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + 1); BOOST_CHECK_EQUAL(ne.d_validationState, Secure); BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1); BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);