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<AbstractRRset>(
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<AbstractRRset>(
+ 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<AbstractRRset>(
+ result.closest_proof), dnssec_);
+ response_.addRRset(Message::SECTION_AUTHORITY,
+ boost::const_pointer_cast<AbstractRRset>(
+ 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<AbstractRRset>(
+ wresult.closest_proof), dnssec_);
+ } else {
+ isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain "
+ << wname);
}
}
}
"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
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_,
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_); }
NULL);
}
- const string nsec3_insecurechild_str =
- mock_finder->hash_map_[insecurechild_name] + ".example.com. 3600 "
- "IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS\n";
+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");
- mock_finder->addRecord(nsec3_insecurechild_str);
+ mock_finder->setNSEC3Flag(true);
- 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) +
++ 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
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.