|
@@ -167,38 +167,65 @@ Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+uint8_t
|
|
|
+Query::addClosestEncloserProof(ZoneFinder& finder, const Name& name,
|
|
|
+ bool exact_ok, bool add_closest)
|
|
|
+{
|
|
|
+ const ZoneFinder::FindNSEC3Result result = finder.findNSEC3(name, true);
|
|
|
+
|
|
|
+ // Validity check (see the method description). Note that a completely
|
|
|
+ // broken findNSEC3 implementation could even return NULL RRset in
|
|
|
+ // closest_proof. We don't explicitly check such case; addRRset() will
|
|
|
+ // throw an exception, and it will be converted to SERVFAIL at the caller.
|
|
|
+ if (!exact_ok && !result.next_proof) {
|
|
|
+ isc_throw(BadNSEC3, "Matching NSEC3 found for a non existent name: "
|
|
|
+ << qname_);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (add_closest) {
|
|
|
+ response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
+ boost::const_pointer_cast<AbstractRRset>(
|
|
|
+ result.closest_proof),
|
|
|
+ dnssec_);
|
|
|
+ }
|
|
|
+ if (result.next_proof) {
|
|
|
+ response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
+ boost::const_pointer_cast<AbstractRRset>(
|
|
|
+ result.next_proof),
|
|
|
+ dnssec_);
|
|
|
+ }
|
|
|
+ return (result.closest_labels);
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
-Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
|
|
|
- // Firstly get the NSEC3 proves for Closest Encloser Proof
|
|
|
- // See section 7.2.1 of RFC 5155.
|
|
|
- // Since this is a Name Error case both closest and next proofs should
|
|
|
- // be available (see addNXRRsetProof).
|
|
|
- const ZoneFinder::FindNSEC3Result fresult1 = finder.findNSEC3(qname_,
|
|
|
- true);
|
|
|
- response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
- boost::const_pointer_cast<AbstractRRset>(
|
|
|
- fresult1.closest_proof),
|
|
|
- dnssec_);
|
|
|
+Query::addNSEC3ForName(ZoneFinder& finder, const Name& name, bool match) {
|
|
|
+ const ZoneFinder::FindNSEC3Result result = finder.findNSEC3(name, false);
|
|
|
+
|
|
|
+ // See the comment for addClosestEncloserProof(). We don't check a
|
|
|
+ // totally bogus case where closest_proof is NULL here.
|
|
|
+ if (match != result.matched) {
|
|
|
+ isc_throw(BadNSEC3, "Unexpected "
|
|
|
+ << (result.matched ? "matching" : "covering")
|
|
|
+ << " NSEC3 found for " << name);
|
|
|
+ }
|
|
|
response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
boost::const_pointer_cast<AbstractRRset>(
|
|
|
- fresult1.next_proof),
|
|
|
+ result.closest_proof),
|
|
|
dnssec_);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
|
|
|
+ // Firstly get the NSEC3 proves for Closest Encloser Proof
|
|
|
+ // See Section 7.2.1 of RFC 5155.
|
|
|
+ const uint8_t closest_labels =
|
|
|
+ addClosestEncloserProof(finder, qname_, false);
|
|
|
|
|
|
// Next, construct the wildcard name at the closest encloser, i.e.,
|
|
|
// '*' followed by the closest encloser, and add NSEC3 for it.
|
|
|
const Name wildname(Name("*").concatenate(
|
|
|
- qname_.split(qname_.getLabelCount() -
|
|
|
- fresult1.closest_labels)));
|
|
|
- const ZoneFinder::FindNSEC3Result fresult2 =
|
|
|
- finder.findNSEC3(wildname, false);
|
|
|
- if (fresult2.matched) {
|
|
|
- isc_throw(BadNSEC3, "Matching NSEC3 found for nonexistent domain "
|
|
|
- << wildname);
|
|
|
- }
|
|
|
- response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
- boost::const_pointer_cast<AbstractRRset>(
|
|
|
- fresult2.closest_proof),
|
|
|
- dnssec_);
|
|
|
+ qname_.split(qname_.getLabelCount() - closest_labels)));
|
|
|
+ addNSEC3ForName(finder, wildname, false);
|
|
|
}
|
|
|
|
|
|
void
|
|
@@ -224,20 +251,13 @@ Query::addWildcardProof(ZoneFinder& finder,
|
|
|
fresult.rrset),
|
|
|
dnssec_);
|
|
|
} else if (db_result.isNSEC3Signed()) {
|
|
|
- // Case for RFC5155 Section 7.2.6.
|
|
|
+ // Case for RFC 5155 Section 7.2.6.
|
|
|
//
|
|
|
// Note that the closest encloser must be the immediate ancestor
|
|
|
- // of the matching wildcard, so NSEC3 for its next closer is what
|
|
|
- // we are expected to provided per the RFC (if this assumption isn't
|
|
|
- // met the zone is broken anyway).
|
|
|
- const ZoneFinder::FindNSEC3Result NSEC3Result(
|
|
|
- finder.findNSEC3(qname_, true));
|
|
|
- // Note that at this point next_proof must not be NULL unless it's
|
|
|
- // a run time collision (or zone/findNSEC3() is broken). The
|
|
|
- // unexpected case will be caught in addRRset() and result in SERVFAIL.
|
|
|
- response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
- boost::const_pointer_cast<AbstractRRset>(
|
|
|
- NSEC3Result.next_proof), dnssec_);
|
|
|
+ // of the matching wildcard, so NSEC3 for its next closer (and only
|
|
|
+ // that NSEC3) is what we are expected to provided per the RFC (if
|
|
|
+ // this assumption isn't met the zone is broken anyway).
|
|
|
+ addClosestEncloserProof(finder, qname_, false, false);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -279,23 +299,8 @@ Query::addDS(ZoneFinder& finder, const Name& dname) {
|
|
|
addNXRRsetProof(finder, ds_result);
|
|
|
} else if (ds_result.code == ZoneFinder::NXRRSET &&
|
|
|
ds_result.isNSEC3Signed()) {
|
|
|
- // Add no DS proof with NSEC3 as specified in RFC5155 Section 7.2.7.
|
|
|
- // Depending on whether the zone is optout or not, findNSEC3() may
|
|
|
- // return non-NULL or NULL next_proof (respectively). The Opt-Out flag
|
|
|
- // must be set or cleared accordingly, but we don't check that
|
|
|
- // in this level (as long as the zone signed validly and findNSEC3()
|
|
|
- // is valid, the condition should be met; otherwise we'd let the
|
|
|
- // validator detect the error).
|
|
|
- const ZoneFinder::FindNSEC3Result nsec3_result =
|
|
|
- finder.findNSEC3(dname, true);
|
|
|
- response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
- boost::const_pointer_cast<AbstractRRset>(
|
|
|
- nsec3_result.closest_proof), dnssec_);
|
|
|
- if (nsec3_result.next_proof) {
|
|
|
- response_.addRRset(Message::SECTION_AUTHORITY,
|
|
|
- boost::const_pointer_cast<AbstractRRset>(
|
|
|
- nsec3_result.next_proof), dnssec_);
|
|
|
- }
|
|
|
+ // Add no DS proof with NSEC3 as specified in RFC 5155 Section 7.2.7.
|
|
|
+ addClosestEncloserProof(finder, dname, true);
|
|
|
} else {
|
|
|
// Any other case should be an error
|
|
|
isc_throw(BadDS, "Unexpected result for DS lookup for delegation");
|
|
@@ -315,57 +320,22 @@ Query::addNXRRsetProof(ZoneFinder& finder,
|
|
|
addWildcardNXRRSETProof(finder, db_result.rrset);
|
|
|
}
|
|
|
} else if (db_result.isNSEC3Signed() && !db_result.isWildcard()) {
|
|
|
- // 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_);
|
|
|
- }
|
|
|
+ if (qtype_ == RRType::DS()) {
|
|
|
+ // RFC 5155, Section 7.2.4. Add either NSEC3 for the qname or
|
|
|
+ // closest (provable) encloser proof in case of optout.
|
|
|
+ addClosestEncloserProof(finder, qname_, true);
|
|
|
} else {
|
|
|
- isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain "
|
|
|
- << qname_);
|
|
|
+ // RFC 5155, Section 7.2.3. Just add NSEC3 for the qname.
|
|
|
+ addNSEC3ForName(finder, qname_, true);
|
|
|
}
|
|
|
} 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.
|
|
|
+ // Case for RFC 5155 Section 7.2.5: add closest encloser proof for the
|
|
|
+ // qname, construct the matched wildcard name and add NSEC3 for it.
|
|
|
+ const uint8_t closest_labels =
|
|
|
+ addClosestEncloserProof(finder, qname_, false);
|
|
|
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);
|
|
|
- }
|
|
|
+ qname_.split(qname_.getLabelCount() - closest_labels));
|
|
|
+ addNSEC3ForName(finder, wname, true);
|
|
|
}
|
|
|
}
|
|
|
|