mDNSexport CacheRecord *NSECRecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype) { CacheGroup *cg; CacheRecord *cr; mDNSu32 slot, namehash; slot = HashSlot(name); namehash = DomainNameHashValue(name); cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, name); if (!cg) { LogDNSSEC("NSECRecordForName: cg NULL for %##s", name); return mDNSNULL; } for (cr = cg->members; cr; cr = cr->next) { if (cr->resrec.RecordType == kDNSRecordTypePacketNegative && cr->resrec.rrtype == qtype) { CacheRecord *ncr; for (ncr = cr->nsec; ncr; ncr = ncr->next) { if (ncr->resrec.rrtype == kDNSType_NSEC && SameDomainName(ncr->resrec.name, name)) { // See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit // should be absent if (RRAssertsExistence(&ncr->resrec, kDNSType_SOA) || RRAssertsExistence(&ncr->resrec, kDNSType_DS)) { LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but DS or SOA bit set", CRDisplayString(m, ncr), name, DNSTypeName(qtype)); return mDNSNULL; } // Section 2.3 of RFC 4035 states that: // // Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST // have an NSEC resource record. // // So, if we have an NSEC record matching the question name with the NS bit set, // then this is a delegation. // if (RRAssertsExistence(&ncr->resrec, kDNSType_NS)) { LogDNSSEC("NSECRecordForName: found record %s for %##s (%s)", CRDisplayString(m, ncr), name, DNSTypeName(qtype)); return ncr; } else { LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but NS bit is not set", CRDisplayString(m, ncr), name, DNSTypeName(qtype)); return mDNSNULL; } } } } } return mDNSNULL; }
mDNSlocal CacheRecord *NSECParentForQuestion(mDNS *const m, DNSQuestion *q) { CacheGroup *cg; CacheRecord *cr; mDNSu32 slot; mDNSu32 namehash; slot = HashSlot(&q->qname); namehash = DomainNameHashValue(&q->qname); cg = CacheGroupForName(m, slot, namehash, &q->qname); if (!cg) { LogDNSSEC("NSECParentForQuestion: Cannot find cg for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return mDNSNULL; } for (cr = cg->members; cr; cr = cr->next) if (SameNameRecordAnswersQuestion(&cr->resrec, q)) return cr; return mDNSNULL; }
mDNSexport CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype) { CacheGroup *cg; CacheRecord *cr; CacheRecord *ncr; mDNSu32 slot, namehash; slot = HashSlot(name); namehash = DomainNameHashValue(name); cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, name); if (!cg) { LogDNSSEC("NSEC3RecordForName: cg NULL for %##s", name); return mDNSNULL; } for (ncr = cg->members; ncr; ncr = ncr->next) { if (ncr->resrec.RecordType != kDNSRecordTypePacketNegative || ncr->resrec.rrtype != qtype) { continue; } for (cr = ncr->nsec; cr; cr = cr->next) { int hlen, b32len; const mDNSu8 hashName[NSEC3_MAX_HASH_LEN]; const mDNSu8 b32Name[NSEC3_MAX_B32_LEN+1]; const RDataBody2 *const rdb = (RDataBody2 *)cr->resrec.rdata->u.data; rdataNSEC3 *nsec3; if (cr->resrec.rrtype != kDNSType_NSEC3) continue; nsec3 = (rdataNSEC3 *)rdb->data; if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen)) { LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for ##s", name->c); return mDNSNULL; } b32len = baseEncode((char *)b32Name, sizeof(b32Name), (mDNSu8 *)hashName, hlen, ENC_BASE32); if (!b32len) { LogMsg("NSEC3RecordIsDelegation: baseEncode of name %##s failed", name->c); return mDNSNULL; } // Section 2.3 of RFC 4035 states that: // // Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST // have an NSEC resource record. // // This applies to NSEC3 record. So, if we have an NSEC3 record matching the question name with the // NS bit set, then this is a delegation. // if (!NSEC3SameName(&cr->resrec.name->c[1], cr->resrec.name->c[0], (const mDNSu8 *)b32Name, b32len)) { int bmaplen; mDNSu8 *bmap; LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s matches name %##s, b32name %s", CRDisplayString(m, cr), name->c, b32Name); NSEC3Parse(&cr->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap); // See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit // should be absent if (BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA) || BitmapTypeCheck(bmap, bmaplen, kDNSType_DS)) { LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s has DS or SOA bit set, ignoring", CRDisplayString(m, cr)); return mDNSNULL; } if (BitmapTypeCheck(bmap, bmaplen, kDNSType_NS)) return cr; else return mDNSNULL; } // If opt-out is not set, then it does not cover any delegations if (!(nsec3->flags & NSEC3_FLAGS_OPTOUT)) continue; // Opt-out allows insecure delegations to exist without the NSEC3 RR at the // hashed owner name (see RFC 5155 section 6.0). if (NSEC3CoversName(m, cr, hashName, hlen, b32Name, b32len)) { LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s covers name %##s with optout", CRDisplayString(m, cr), name->c); return cr; } } } return mDNSNULL; }