From: JINMEI Tatuya Date: Tue, 14 Feb 2012 18:17:43 +0000 (-0800) Subject: [1585] Merge branch 'master' into trac1585 with fixing conflicts, mainly X-Git-Tag: trac2351_base~97^2~30^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d20389d04053862712eae4e1005ce38faf813f20;p=thirdparty%2Fkea.git [1585] Merge branch 'master' into trac1585 with fixing conflicts, mainly to be more synchronized with merged #1582. --- d20389d04053862712eae4e1005ce38faf813f20 diff --cc src/bin/auth/query.cc index 4c220104c7,70b672c6f2..54361d1f8d --- a/src/bin/auth/query.cc +++ b/src/bin/auth/query.cc @@@ -257,46 -236,28 +257,57 @@@ Query::addNXRRsetProof(ZoneFinder& find if (db_result.isWildcard()) { addWildcardNXRRSETProof(finder, db_result.rrset); } - } else if (db_result.isNSEC3Signed()) { + } else if (db_result.isNSEC3Signed() && !db_result.isWildcard()) { - // Case for RFC5155 Section 7.2.3 - const ZoneFinder::FindNSEC3Result result(finder.findNSEC3(qname_, - false)); + // Handling depends on whether query type is DS or not + // (see RFC5155, 7.2.3 and 7.2.4): If qtype == DS, do + // recursive search (and add next_proof, if necessary), + // otherwise, do non-recursive search + const bool qtype_ds = (qtype_ == RRType::DS()); + ZoneFinder::FindNSEC3Result result(finder.findNSEC3(qname_, qtype_ds)); if (result.matched) { response_.addRRset(Message::SECTION_AUTHORITY, boost::const_pointer_cast( result.closest_proof), dnssec_); + // For qtype == DS, next_proof could be set + // (We could check for opt-out here, but that's really the + // responsibility of the datasource) + if (qtype_ds && result.next_proof != ConstRRsetPtr()) { + response_.addRRset(Message::SECTION_AUTHORITY, + boost::const_pointer_cast( + result.next_proof), dnssec_); + } } else { - isc_throw(BadNSEC3, "No NSEC3 found for existing domain " << - qname_.toText()); + isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain " + << qname_); + } + } else if (db_result.isNSEC3Signed() && db_result.isWildcard()) { + // Case for RFC5155 Section 7.2.5 + const ZoneFinder::FindNSEC3Result result(finder.findNSEC3(qname_, + true)); + // We know there's no exact match for the qname, so findNSEC3() should + // return both closest and next proofs. If the latter is NULL, it + // means a run time collision (or the zone is broken in other way). + // In that case addRRset() will throw, and it will be converted to + // SERVFAIL. + response_.addRRset(Message::SECTION_AUTHORITY, + boost::const_pointer_cast( + result.closest_proof), dnssec_); + response_.addRRset(Message::SECTION_AUTHORITY, + boost::const_pointer_cast( + result.next_proof), dnssec_); + + // Construct the matched wildcard name and add NSEC3 for it. + const Name wname = Name("*").concatenate( + qname_.split(qname_.getLabelCount() - result.closest_labels)); + const ZoneFinder::FindNSEC3Result wresult(finder.findNSEC3(wname, + false)); + if (wresult.matched) { + response_.addRRset(Message::SECTION_AUTHORITY, + boost::const_pointer_cast( + wresult.closest_proof), dnssec_); + } else { + isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain " + << wname); } } } diff --cc src/bin/auth/tests/query_unittest.cc index 7a0d523593,a1672bd682..c5d8a79713 --- a/src/bin/auth/tests/query_unittest.cc +++ b/src/bin/auth/tests/query_unittest.cc @@@ -208,6 -198,16 +208,17 @@@ const char* const unsigned_delegation_t "unsigned-delegation.example.com. 3600 IN NS ns.example.net.\n"; const char* const unsigned_delegation_nsec_txt = "unsigned-delegation.example.com. 3600 IN NSEC " + "unsigned-delegation-optout.example.com. NS RRSIG NSEC\n"; ++// This one will be added on demand + const char* const unsigned_delegation_nsec3_txt = + "q81r598950igr1eqvc60aedlq66425b5.example.com. 3600 IN NSEC3 1 1 12 " + "aabbccdd 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom NS RRSIG\n"; + + // Delegation without DS record, and no direct matching NSEC3 record + const char* const unsigned_delegation_optout_txt = + "unsigned-delegation-optout.example.com. 3600 IN NS ns.example.net.\n"; + const char* const unsigned_delegation_optout_nsec_txt = + "unsigned-delegation-optout.example.com. 3600 IN NSEC " "*.uwild.example.com. NS RRSIG NSEC\n"; // (Secure) delegation data; Delegation where the DS lookup will raise an @@@ -288,6 -287,8 +299,8 @@@ public nsec3_apex_txt << nsec3_www_txt << signed_delegation_txt << signed_delegation_ds_txt << unsigned_delegation_txt << unsigned_delegation_nsec_txt << - unsigned_delegation_nsec3_txt << unsigned_delegation_optout_txt << ++ unsigned_delegation_optout_txt << + unsigned_delegation_optout_nsec_txt << bad_delegation_txt; masterLoad(zone_stream, origin_, rrclass_, @@@ -317,15 -318,9 +330,17 @@@ hash_map_[Name("nxdomain3.example.com")] = "009mhaveqvm6t7vbl5lop2u3t2rp3tom"; hash_map_[Name("unsigned-delegation.example.com")] = - "q04jkcevqvmu85r014c7dkba38o0ji8r"; // a bit larger than H(www) - "q81r598950igr1eqvc60aedlq66425b5"; ++ "q81r598950igr1eqvc60aedlq66425b5"; // a bit larger than H(www) + hash_map_[Name("*.uwild.example.com")] = + "b4um86eghhds6nea196smvmlo4ors995"; + hash_map_[Name("unsigned-delegation-optout.example.com")] = + "vld46lphhasfapj8og1pglgiasa5o5gt"; + + // For closest encloser proof for www1.uwild.example.com: + hash_map_[Name("uwild.example.com")] = + "t644ebqk9bibcna874givr6joj62mlhv"; + hash_map_[Name("www1.uwild.example.com")] = + "q04jkcevqvmu85r014c7dkba38o0ji6r"; // a bit larger than H(www) } virtual isc::dns::Name getOrigin() const { return (origin_); } virtual isc::dns::RRClass getClass() const { return (rrclass_); } @@@ -1041,55 -1028,6 +1056,53 @@@ TEST_F(QueryTest, secureUnsignedDelegat NULL); } +TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3) { + // Similar to the previous case, but the zone is signed with NSEC3, + // and this delegation is NOT an optout. + const Name insecurechild_name("unsigned-delegation.example.com"); - const string nsec3_insecurechild_str = - mock_finder->hash_map_[insecurechild_name] + ".example.com. 3600 " - "IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS\n"; + mock_finder->setNSEC3Flag(true); - mock_finder->addRecord(nsec3_insecurechild_str); ++ mock_finder->addRecord(unsigned_delegation_nsec3_txt); + + Query(memory_client, Name("foo.unsigned-delegation.example.com"), + qtype, response, true).process(); + + // The response should contain the NS and matching NSEC3 with its RRSIG + responseCheck(response, Rcode::NOERROR(), 0, 0, 3, 0, + NULL, + (string(unsigned_delegation_txt) + - nsec3_insecurechild_str + ++ string(unsigned_delegation_nsec3_txt) + + mock_finder->hash_map_[insecurechild_name] + + ".example.com. 3600 IN RRSIG " + + getCommonRRSIGText("NSEC3")).c_str(), + NULL); +} + +TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) { + // Similar to the previous case, but the delegation is an optout. + mock_finder->setNSEC3Flag(true); + + Query(memory_client, Name("foo.unsigned-delegation.example.com"), + qtype, response, true).process(); + + // The response should contain the NS and the closest provable encloser + // proof (and their RRSIGs). The closest encloser is the apex (origin), + // and with our faked hash the covering NSEC3 for the next closer + // (= child zone name) is that for www.example.com. ++ cout << response << endl; + responseCheck(response, Rcode::NOERROR(), 0, 0, 5, 0, + NULL, + (string(unsigned_delegation_txt) + + string(nsec3_apex_txt) + + mock_finder->hash_map_[mock_finder->getOrigin()] + + ".example.com. 3600 IN RRSIG " + + getCommonRRSIGText("NSEC3") + "\n" + + string(nsec3_www_txt) + + mock_finder->hash_map_[Name("www.example.com")] + + ".example.com. 3600 IN RRSIG " + + getCommonRRSIGText("NSEC3")).c_str(), + NULL); +} + TEST_F(QueryTest, badSecureDelegation) { // Test whether exception is raised if DS query at delegation results in // something different than SUCCESS or NXRRSET @@@ -2088,6 -1935,49 +2101,51 @@@ TEST_F(QueryTest, nxrrsetMissingNSEC3) response, true).process(), Query::BadNSEC3); } + TEST_F(QueryTest, nxrrsetWithNSEC3_ds_exact) { ++ mock_finder->addRecord(unsigned_delegation_nsec3_txt); + mock_finder->setNSEC3Flag(true); + + // This delegation has no DS, but does have a matching NSEC3 record + // (See RFC5155 section 7.2.4) + Query(memory_client, Name("unsigned-delegation.example.com."), + RRType::DS(), response, true).process(); + responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL, + (string(soa_txt) + string("example.com. 3600 IN RRSIG ") + + getCommonRRSIGText("SOA") + "\n" + + string(unsigned_delegation_nsec3_txt) + "\n" + + mock_finder-> + hash_map_[Name("unsigned-delegation.example.com.")] + + ".example.com. 3600 IN RRSIG " + + getCommonRRSIGText("NSEC3") + "\n").c_str(), + NULL, mock_finder->getOrigin()); + } + + TEST_F(QueryTest, nxrrsetWithNSEC3_ds_no_exact) { ++ mock_finder->addRecord(unsigned_delegation_nsec3_txt); + mock_finder->setNSEC3Flag(true); + + // This delegation has no DS, and no directly matching NSEC3 record + // So the response should contain closest encloser proof (and the + // 'next closer' should have opt-out set, though that is not + // actually checked) + // (See RFC5155 section 7.2.4) + Query(memory_client, Name("unsigned-delegation-optout.example.com."), + RRType::DS(), response, true).process(); + responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL, + (string(soa_txt) + string("example.com. 3600 IN RRSIG ") + + getCommonRRSIGText("SOA") + "\n" + + string(nsec3_apex_txt) + "\n" + + mock_finder->hash_map_[Name("example.com.")] + + ".example.com. 3600 IN RRSIG " + + getCommonRRSIGText("NSEC3") + "\n" + + string(unsigned_delegation_nsec3_txt) + "\n" + + mock_finder-> + hash_map_[Name("unsigned-delegation.example.com.")] + + ".example.com. 3600 IN RRSIG " + + getCommonRRSIGText("NSEC3") + "\n").c_str(), + NULL, mock_finder->getOrigin()); + } + // The following are tentative tests until we really add tests for the // query logic for these cases. At that point it's probably better to // clean them up.