mDNSexport void NSEC3NameErrorProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr) { CacheRecord *closerEncloser; CacheRecord *closestEncloser; CacheRecord *wildcard; const domainname *ce = mDNSNULL; domainname wild; if (!NSEC3ClosestEncloserProof(m, ncr, &dv->q.qname, &closestEncloser, &closerEncloser, &ce, dv->q.qtype)) { goto error; } LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser %s, ce %##s", CRDisplayString(m, closestEncloser), ce->c); LogDNSSEC("NSEC3NameErrorProof: CloserEncloser %s", CRDisplayString(m, closerEncloser)); // *.closestEncloser should be covered by some nsec3 which would then prove // that the wildcard does not exist wild.c[0] = 1; wild.c[1] = '*'; wild.c[2] = 0; if (!AppendDomainName(&wild, ce)) { LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce->c); goto error; } if (!NSEC3Find(m, NSEC3Covers, ncr, &wild, mDNSNULL, &wildcard, mDNSNULL, dv->q.qtype)) { LogMsg("NSEC3NameErrorProof: Cannot find encloser for wildcard"); goto error; } else { LogDNSSEC("NSEC3NameErrorProof: Wildcard %##s covered by %s", wild.c, CRDisplayString(m, wildcard)); if (wildcard == closestEncloser) { LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser matching Wildcard %s", CRDisplayString(m, wildcard)); } } if (NSEC3OptOut(closerEncloser)) { dv->flags |= NSEC3_OPT_OUT; } if (!VerifyNSEC3(m, dv, ncr, closestEncloser, closerEncloser, wildcard, NameErrorNSECCallback)) goto error; else return; error: dv->DVCallback(m, dv, DNSSEC_Bogus); }
mDNSlocal mDNSBool NSECNoWildcard(mDNS *const m, ResourceRecord *rr, domainname *qname, mDNSu16 qtype) { const domainname *ce; domainname wild; // If the query name is c.x.w.example and if the name does not exist, we should get // get a nsec back that looks something like this: // // w.example NSEC a.w.example // // First, we need to get the closest encloser which in this case is w.example. Wild // card synthesis works by finding the closest encloser first and then look for // a "*" label (assuming * label does not appear in the question). If it does not // exists, it would return the NSEC at that name. And the wildcard name at the // closest encloser "*.w.example" would be covered by such an NSEC. (Appending "*" // makes it bigger than w.example and "* is smaller than "a" for the above NSEC) // ce = NSECClosestEncloser(rr, qname); if (!ce) { LogMsg("NSECNoWildcard: No closest encloser for rr %s, qname %##s (%s)", qname->c, DNSTypeName(qtype)); return mDNSfalse; } wild.c[0] = 1; wild.c[1] = '*'; wild.c[2] = 0; if (!AppendDomainName(&wild, ce)) { LogMsg("NSECNoWildcard: ERROR!! Can't append domainname closest encloser name %##s, qname %##s (%s)", ce->c, qname->c, DNSTypeName(qtype)); return mDNSfalse; } if (NSECNameExists(m, rr, &wild, qtype) != 0) { LogDNSSEC("NSECNoWildcard: Wildcard name %##s exists or not valid qname %##s (%s)", wild.c, qname->c, DNSTypeName(qtype)); return mDNSfalse; } LogDNSSEC("NSECNoWildcard: Wildcard name %##s does not exist for record %s, qname %##s (%s)", wild.c, RRDisplayString(m, rr), qname->c, DNSTypeName(qtype)); return mDNStrue; }
mDNSexport void NSEC3NoDataProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr) { CacheRecord *closerEncloser = mDNSNULL; CacheRecord *closestEncloser = mDNSNULL; CacheRecord *wildcard = mDNSNULL; const domainname *ce = mDNSNULL; domainname wild; // Section 8.5, 8.6 of RFC 5155 if (NSEC3NoDataError(m, ncr, &dv->q.qname, dv->q.qtype, &closestEncloser)) { goto verify; } // Section 8.6, 8.7: if we can't find the NSEC3 RR, verify the closest encloser proof // for QNAME and the "next closer" should have the opt out if (!NSEC3ClosestEncloserProof(m, ncr, &dv->q.qname, &closestEncloser, &closerEncloser, &ce, dv->q.qtype)) { goto error; } // Section 8.7: find a matching NSEC3 for *.closestEncloser wild.c[0] = 1; wild.c[1] = '*'; wild.c[2] = 0; if (!AppendDomainName(&wild, ce)) { LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce->c); goto error; } if (!NSEC3Find(m, NSEC3ClosestEncloser, ncr, &wild, &wildcard, mDNSNULL, &ce, dv->q.qtype)) { // Not a wild card case. Section 8.6 second para applies. LogDNSSEC("NSEC3NoDataProof: Cannot find encloser for wildcard, perhaps not a wildcard case"); if (!NSEC3OptOut(closerEncloser)) { LogDNSSEC("NSEC3DataProof: opt out not set for %##s (%s), bogus", dv->q.qname.c, DNSTypeName(dv->q.qtype)); goto error; } LogDNSSEC("NSEC3DataProof: opt out set, proof complete for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype)); dv->flags |= NSEC3_OPT_OUT; } else { int bmaplen; mDNSu8 *bmap; NSEC3Parse(&wildcard->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap); if (BitmapTypeCheck(bmap, bmaplen, dv->q.qtype) || BitmapTypeCheck(bmap, bmaplen, kDNSType_CNAME)) { LogDNSSEC("NSEC3NoDataProof: qtype %s exists in %s", DNSTypeName(dv->q.qtype), CRDisplayString(m, wildcard)); goto error; } if (dv->q.qtype == kDNSType_DS && BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA)) { LogDNSSEC("NSEC3NoDataProof: Child side wildcard NSEC3 %s, can't use for parent qname %##s (%s)", CRDisplayString(m, wildcard), dv->q.qname.c, DNSTypeName(dv->q.qtype)); goto error; } else if (dv->q.qtype != kDNSType_DS && !BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA) && BitmapTypeCheck(bmap, bmaplen, kDNSType_NS)) { // Don't use the parent side record for this LogDNSSEC("NSEC3NoDataProof: Parent side wildcard NSEC3 %s, can't use for child qname %##s (%s)", CRDisplayString(m, wildcard), dv->q.qname.c, DNSTypeName(dv->q.qtype)); goto error; } LogDNSSEC("NSEC3NoDataProof: Wildcard %##s matched by %s", wild.c, CRDisplayString(m, wildcard)); } verify: if (!VerifyNSEC3(m, dv, ncr, closestEncloser, closerEncloser, wildcard, NoDataNSECCallback)) goto error; else return; error: dv->DVCallback(m, dv, DNSSEC_Bogus); }