1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18// *************************************************************************** 19// nsec.c: This file contains support functions to validate NSEC records for 20// NODATA and NXDOMAIN error. 21// *************************************************************************** 22 23#include "mDNSEmbeddedAPI.h" 24#include "DNSCommon.h" 25#include "nsec.h" 26#include "nsec3.h" 27 28// Define DNSSEC_DISABLED to remove all the DNSSEC functionality 29// and use the stub functions implemented later in this file. 30 31#ifndef DNSSEC_DISABLED 32 33// Implementation Notes 34// 35// NSEC records in DNSSEC are used for authenticated denial of existence i.e., if the response to a query 36// results in NXDOMAIN or NODATA error, the response also contains NSEC records in the additional section 37// to prove the non-existence of the original name. In most of the cases, NSEC records don't have any 38// relationship to the original name queried i.e, if they are cached based on the name like other records, 39// it can't be located to prove the non-existence of the original name. Hence, we create a negative cache 40// record like we do for the NXDOMAIN/NODATA error and then cache the NSEC records as part of that. Sometimes, 41// NSEC records are also used for wildcard expanded answer in which case they are cached with the cache record 42// that is created for the original name. NSEC records are freed when the parent cache (the record that they 43// are attached to is expired). 44// 45// NSEC records also can be queried like any other record and hence can exist independent of the negative 46// cache record. It exists as part of negative cache record only when we get a NXDOMAIN/NODATA error with 47// NSEC records. When a query results in NXDOMAIN/NODATA error and needs to be validated, the NSEC 48// records (and its RRSIGS) are cached as part of the negative cache record. The NSEC records that 49// exist separately from the negative cache record should not be used to answer ValidationRequired/ 50// ValidatingResponse questions as it may not be sufficient to prove the non-existence of the name. 51// The exception is when the NSEC record is looked up explicitly. See DNSSECRecordAnswersQuestion 52// for more details. 53// 54 55mDNSlocal CacheRecord *NSECParentForQuestion(mDNS *const m, DNSQuestion *q) 56{ 57 CacheGroup *cg; 58 CacheRecord *cr; 59 mDNSu32 slot; 60 mDNSu32 namehash; 61 62 slot = HashSlot(&q->qname); 63 namehash = DomainNameHashValue(&q->qname); 64 cg = CacheGroupForName(m, slot, namehash, &q->qname); 65 if (!cg) 66 { 67 LogDNSSEC("NSECParentForQuestion: Cannot find cg for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 68 return mDNSNULL; 69 } 70 for (cr = cg->members; cr; cr = cr->next) 71 if (SameNameRecordAnswersQuestion(&cr->resrec, q)) 72 return cr; 73 return mDNSNULL; 74} 75 76mDNSlocal void UpdateParent(DNSSECVerifier *dv) 77{ 78 AuthChainLink(dv->parent, dv->ac); 79 ResetAuthChain(dv); 80 dv->parent->NumPackets += dv->NumPackets; 81} 82 83// Note: This should just call the parent callback which will free the DNSSECVerifier. 84mDNSlocal void VerifyNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status) 85{ 86 if (!dv->parent) 87 { 88 LogMsg("VerifyNSECCCallback: ERROR!! no parent DV\n"); 89 FreeDNSSECVerifier(m, dv); 90 return; 91 } 92 if (dv->ac) 93 { 94 // Before we free the "dv", we need to update the 95 // parent with our AuthChain information 96 UpdateParent(dv); 97 } 98 // "status" indicates whether we are able to successfully verify 99 // the NSEC/NSEC3 signatures. For NSEC3, the OptOut flag may be set 100 // for which we need to deliver insecure result. 101 if ((dv->parent->flags & NSEC3_OPT_OUT) && (status == DNSSEC_Secure)) 102 { 103 dv->parent->DVCallback(m, dv->parent, DNSSEC_Insecure); 104 } 105 else 106 { 107 dv->parent->DVCallback(m, dv->parent, status); 108 } 109 // The callback we called in the previous line should recursively 110 // free all the DNSSECVerifiers starting from dv->parent and above. 111 // So, set that to NULL and free the "dv" itself here. 112 dv->parent = mDNSNULL; 113 FreeDNSSECVerifier(m, dv); 114} 115 116// If the caller provides a callback, it takes the responsibility of calling the original callback 117// in "pdv" when it is done. 118// 119// INPUT: 120// 121// rr: The NSEC record that should be verified 122// rv: The NSEC record can also be provided like this 123// pdv: Parent DNSSECVerifier which will be called when the verification is done. 124// callback: As part of the proof, we need multiple NSEC verifications before we call the "pdv" callback in 125// which case a intermediate "callback" is provided which can be used to do multiple verifications. 126// ncr: The cache record where the RRSIGS are cached 127// 128// NSEC records and signatures are cached along with the cache record so that we can expire them all together. We can't cache 129// them based on the name hash like other records as in most cases the returned NSECs has a different name than we asked for 130// (except for NODATA error where the name exists but type does not exist). 131// 132mDNSexport void VerifyNSEC(mDNS *const m, ResourceRecord *rr, RRVerifier *rv, DNSSECVerifier *pdv, CacheRecord *ncr, DNSSECVerifierCallback callback) 133{ 134 DNSSECVerifier *dv = mDNSNULL; 135 CacheRecord **rp; 136 const domainname *name; 137 mDNSu16 rrtype; 138 139 if (!rv && !rr) 140 { 141 LogDNSSEC("VerifyNSEC: Both rr and rv are NULL"); 142 goto error; 143 } 144 if (!pdv) 145 { 146 LogDNSSEC("VerifyNSEC: ERROR!! pdv is NULL"); 147 return; 148 } 149 // Remember the name and type for which we are verifying, so that when we are done processing all 150 // the verifications, we can trace it back. 151 // 152 // Note: Currently it is not used because when the verification completes as we just 153 // call the "pdv" callback which has its origName and origType. 154 if (rr) 155 { 156 name = rr->name; 157 rrtype = rr->rrtype; 158 } 159 else 160 { 161 name = &rv->name; 162 rrtype = rv->rrtype; 163 } 164 165 dv = AllocateDNSSECVerifier(m, name, rrtype, pdv->q.InterfaceID, DNSSEC_VALIDATION_SECURE, 166 (callback ? callback : VerifyNSECCallback), mDNSNULL); 167 if (!dv) 168 { 169 LogMsg("VerifyNSEC: mDNSPlatformMemAlloc failed"); 170 return; 171 } 172 173 dv->parent = pdv; 174 175 if (AddRRSetToVerifier(dv, rr, rv, RRVS_rr) != mStatus_NoError) 176 { 177 LogMsg("VerifyNSEC: ERROR!! AddRRSetToVerifier failed to add NSEC"); 178 goto error; 179 } 180 181 // Add the signatures after validating them 182 rp = &(ncr->nsec); 183 while (*rp) 184 { 185 if ((*rp)->resrec.rrtype == kDNSType_RRSIG) 186 { 187 ValidateRRSIG(dv, RRVS_rrsig, &(*rp)->resrec); 188 } 189 rp=&(*rp)->next; 190 } 191 192 if (!dv->rrset) 193 { 194 LogMsg("VerifyNSEC: ERROR!! AddRRSetToVerifier missing rrset"); 195 goto error; 196 } 197 // Expired signatures. 198 if (!dv->rrsig) 199 goto error; 200 201 // Next step is to fetch the keys 202 dv->next = RRVS_key; 203 204 StartDNSSECVerification(m, dv); 205 return; 206error: 207 pdv->DVCallback(m, pdv, DNSSEC_Bogus); 208 if (dv) 209 { 210 dv->parent = mDNSNULL; 211 FreeDNSSECVerifier(m, dv); 212 } 213 return; 214} 215 216mDNSlocal void DeleteCachedNSECS(mDNS *const m, CacheRecord *cr) 217{ 218 CacheRecord *rp, *next; 219 220 if (cr->nsec) LogDNSSEC("DeleteCachedNSECS: Deleting NSEC Records\n"); 221 for (rp = cr->nsec; rp; rp = next) 222 { 223 next = rp->next; 224 ReleaseCacheRecord(m, rp); 225 } 226 cr->nsec = mDNSNULL; 227} 228 229// Returns success if it adds the nsecs and the rrsigs to the cache record. Otherwise, it returns 230// failure (mDNSfalse) 231mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode) 232{ 233 CacheRecord *cr; 234 mDNSBool nsecs_seen = mDNSfalse; 235 mDNSBool nsec3s_seen = mDNSfalse; 236 237 if (rcode != kDNSFlag1_RC_NoErr && rcode != kDNSFlag1_RC_NXDomain) 238 { 239 LogMsg("AddNSECSForCacheRecord: Addings nsecs for rcode %d", rcode); 240 return mDNSfalse; 241 } 242 243 // Sanity check the list to see if we have anything else other than 244 // NSECs and its RRSIGs 245 for (cr = crlist; cr; cr = cr->next) 246 { 247 if (cr->resrec.rrtype != kDNSType_NSEC && cr->resrec.rrtype != kDNSType_NSEC3 && 248 cr->resrec.rrtype != kDNSType_SOA && cr->resrec.rrtype != kDNSType_RRSIG) 249 { 250 LogMsg("AddNSECSForCacheRecord: ERROR!! Adding Wrong record %s", CRDisplayString(m, cr)); 251 return mDNSfalse; 252 } 253 if (cr->resrec.rrtype == kDNSType_RRSIG) 254 { 255 RDataBody2 *const rdb = (RDataBody2 *)cr->smallrdatastorage.data; 256 rdataRRSig *rrsig = &rdb->rrsig; 257 mDNSu16 tc = swap16(rrsig->typeCovered); 258 if (tc != kDNSType_NSEC && tc != kDNSType_NSEC3 && tc != kDNSType_SOA) 259 { 260 LogMsg("AddNSECSForCacheRecord:ERROR!! Adding RRSIG with Wrong type %s", CRDisplayString(m, cr)); 261 return mDNSfalse; 262 } 263 } 264 else if (cr->resrec.rrtype == kDNSType_NSEC) 265 { 266 nsecs_seen = mDNStrue; 267 } 268 else if (cr->resrec.rrtype == kDNSType_NSEC3) 269 { 270 nsec3s_seen = mDNStrue; 271 } 272 LogDNSSEC("AddNSECSForCacheRecord: Found a valid record %s", CRDisplayString(m, cr)); 273 } 274 if ((nsecs_seen && nsec3s_seen) || (!nsecs_seen && !nsec3s_seen)) 275 { 276 LogDNSSEC("AddNSECSForCacheRecord:ERROR nsecs_seen %d, nsec3s_seen %d", nsecs_seen, nsec3s_seen); 277 return mDNSfalse; 278 } 279 DeleteCachedNSECS(m, negcr); 280 LogDNSSEC("AddNSECSForCacheRecord: Adding NSEC Records for %s", CRDisplayString(m, negcr)); 281 negcr->nsec = crlist; 282 return mDNStrue; 283} 284 285// Return the number of labels that matches starting from the right (excluding the 286// root label) 287mDNSexport int CountLabelsMatch(const domainname *const d1, const domainname *const d2) 288{ 289 int count, c1, c2; 290 int match, i, skip1, skip2; 291 292 c1 = CountLabels(d1); 293 skip1 = c1 - 1; 294 c2 = CountLabels(d2); 295 skip2 = c2 - 1; 296 297 // Root label always matches. And we don't include it here to 298 // match CountLabels 299 match = 0; 300 301 // Compare as many labels as possible starting from the rightmost 302 count = c1 < c2 ? c1 : c2; 303 for (i = count; i > 0; i--) 304 { 305 const domainname *da, *db; 306 307 da = SkipLeadingLabels(d1, skip1); 308 db = SkipLeadingLabels(d2, skip2); 309 if (!SameDomainName(da, db)) return match; 310 skip1--; 311 skip2--; 312 match++; 313 } 314 return match; 315} 316 317// Empty Non-Terminal (ENT): if the qname is bigger than nsec owner's name and a 318// subdomain of the nsec's nxt field, then the qname is a empty non-terminal. For 319// example, if you are looking for (in RFC 4035 example zone) "y.w.example A" 320// record, if it is a ENT, then it would return 321// 322// x.w.example. 3600 NSEC x.y.w.example. MX RRSIG NSEC 323// 324// This function is normally called before checking for wildcard matches. If you 325// find this NSEC, there is no need to look for a wildcard record 326// that could possibly answer the question. 327mDNSlocal mDNSBool NSECAnswersENT(const ResourceRecord *const rr, domainname *qname) 328{ 329 const domainname *oname = rr->name; 330 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 331 const domainname *nxt = (const domainname *)&rdb->data; 332 int ret; 333 int subdomain; 334 335 // Is the owner name smaller than qname? 336 ret = DNSSECCanonicalOrder(oname, qname, mDNSNULL); 337 if (ret < 0) 338 { 339 // Is the next domain field a subdomain of qname ? 340 ret = DNSSECCanonicalOrder(nxt, qname, &subdomain); 341 if (subdomain) 342 { 343 if (ret <= 0) 344 { 345 LogMsg("NSECAnswersENT: ERROR!! DNSSECCanonicalOrder subdomain set " 346 " qname %##s, NSEC %##s", qname->c, rr->name->c); 347 } 348 return mDNStrue; 349 } 350 } 351 return mDNSfalse; 352} 353 354mDNSlocal const domainname *NSECClosestEncloser(ResourceRecord *rr, domainname *qname) 355{ 356 const domainname *oname = rr->name; 357 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 358 const domainname *nxt = (const domainname *)&rdb->data; 359 int match1, match2; 360 361 match1 = CountLabelsMatch(oname, qname); 362 match2 = CountLabelsMatch(nxt, qname); 363 // Return the closest i.e the one that matches more labels 364 if (match1 > match2) 365 return SkipLeadingLabels(oname, CountLabels(oname) - match1); 366 else 367 return SkipLeadingLabels(nxt, CountLabels(nxt) - match2); 368} 369 370// Assumption: NSEC has been validated outside of this function 371// 372// Does the name exist given the name and NSEC rr ? 373// 374// Returns -1 if it is an inappropriate nsec 375// Returns 1 if the name exists 376// Returns 0 if the name does not exist 377// 378mDNSlocal int NSECNameExists(mDNS *const m, ResourceRecord *rr, domainname *name, mDNSu16 qtype) 379{ 380 const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; 381 const domainname *nxt = (const domainname *)&rdb->data; 382 const domainname *oname = rr->name; // owner name 383 int ret1, subdomain1; 384 int ret2, subdomain2; 385 int ret3, subdomain3; 386 387 ret1 = DNSSECCanonicalOrder(oname, name, &subdomain1); 388 if (ret1 > 0) 389 { 390 LogDNSSEC("NSECNameExists: owner name %##s is bigger than name %##s", oname->c, name->c); 391 return -1; 392 } 393 394 // Section 4.1 of draft-ietf-dnsext-dnssec-bis-updates-14: 395 // 396 // Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume non- 397 // existence of any RRs below that zone cut, which include all RRs at 398 // that (original) owner name other than DS RRs, and all RRs below that 399 // owner name regardless of type. 400 // 401 // This also implies that we can't use the child side NSEC for DS question. 402 403 if (!ret1) 404 { 405 mDNSBool soa = RRAssertsExistence(rr, kDNSType_SOA); 406 mDNSBool ns = RRAssertsExistence(rr, kDNSType_NS); 407 408 // We are here because the owner name is the same as "name". Make sure the 409 // NSEC has the right NS and SOA bits set. 410 if (qtype != kDNSType_DS && ns && !soa) 411 { 412 LogDNSSEC("NSECNameExists: Parent side NSEC %s can't be used for question %##s (%s)", 413 RRDisplayString(m, rr), name->c, DNSTypeName(qtype)); 414 return -1; 415 } 416 else if (qtype == kDNSType_DS && soa) 417 { 418 LogDNSSEC("NSECNameExists: Child side NSEC %s can't be used for question %##s (%s)", 419 RRDisplayString(m, rr), name->c, DNSTypeName(qtype)); 420 return -1; 421 } 422 LogDNSSEC("NSECNameExists: owner name %##s is same as name %##s", oname->c, name->c); 423 return 1; 424 } 425 426 // If the name is a.b.com and NSEC's owner name is b.com i.e., a subdomain 427 // and nsec comes from the parent (NS is set and SOA is not set), then this 428 // NSEC can't be used for names below the owner name. 429 // 430 // Similarly if DNAME is set, we can't use it here. See RFC2672-bis-dname 431 // appendix. 432 if (subdomain1 && (RRAssertsExistence(rr, kDNSType_DNAME) || 433 (RRAssertsNonexistence(rr, kDNSType_SOA) && RRAssertsExistence(rr, kDNSType_NS)))) 434 { 435 LogDNSSEC("NSECNameExists: NSEC %s comes from the parent, can't use it here", 436 RRDisplayString(m, rr)); 437 return -1; 438 } 439 440 // At this stage, we know that name is greater than the owner name and 441 // the nsec is not from the parent side. 442 // 443 // Compare with the next field in the nsec. 444 // 445 ret2 = DNSSECCanonicalOrder(name, nxt, &subdomain2); 446 447 // Exact match with the nsec next name 448 if (!ret2) 449 { 450 LogDNSSEC("NSECNameExists: name %##s is same as nxt name %##s", name->c, nxt->c); 451 return 1; 452 } 453 454 ret3 = DNSSECCanonicalOrder(oname, nxt, &subdomain3); 455 456 if (!ret3) 457 { 458 // Pathological case of a single name in the domain. This means only the 459 // apex of the zone itself exists. Nothing below it. "subdomain2" indicates 460 // that name is a subdmain of "next" and hence below the zone. 461 if (subdomain2) 462 { 463 LogDNSSEC("NSECNameExists: owner name %##s subdomain of nxt name %##s", oname->c, nxt->c); 464 return 0; 465 } 466 else 467 { 468 LogDNSSEC("NSECNameExists: Single name in zone, owner name %##s is same as nxt name %##s", oname->c, nxt->c); 469 return -1; 470 } 471 } 472 473 if (ret3 < 0) 474 { 475 // Regular NSEC in the zone. Make sure that the "name" lies within 476 // oname and next. oname < name and name < next 477 if (ret1 < 0 && ret2 < 0) 478 { 479 LogDNSSEC("NSECNameExists: Normal NSEC name %##s lies within owner %##s and nxt name %##s", 480 name->c, oname->c, nxt->c); 481 return 0; 482 } 483 else 484 { 485 LogDNSSEC("NSECNameExists: Normal NSEC name %##s does not lie within owner %##s and nxt name %##s", 486 name->c, oname->c, nxt->c); 487 return -1; 488 } 489 } 490 else 491 { 492 // Last NSEC in the zone. The "next" is pointing to the apex. All names 493 // should be a subdomain of that and the name should be bigger than 494 // oname 495 if (ret1 < 0 && subdomain2) 496 { 497 LogDNSSEC("NSECNameExists: Last NSEC name %##s lies within owner %##s and nxt name %##s", 498 name->c, oname->c, nxt->c); 499 return 0; 500 } 501 else 502 { 503 LogDNSSEC("NSECNameExists: Last NSEC name %##s does not lie within owner %##s and nxt name %##s", 504 name->c, oname->c, nxt->c); 505 return -1; 506 } 507 } 508 509 LogDNSSEC("NSECNameExists: NSEC %s did not match any case", RRDisplayString(m, rr)); 510 return -1; 511} 512 513// If the answer was result of a wildcard match, then this function proves 514// that a proper wildcard was used to answer the question and that the 515// original name does not exist 516mDNSexport void WildcardAnswerProof(mDNS *const m, DNSSECVerifier *dv) 517{ 518 CacheRecord *ncr; 519 CacheRecord **rp; 520 const domainname *ce; 521 DNSQuestion q; 522 CacheRecord **nsec3 = mDNSNULL; 523 524 LogDNSSEC("WildcardAnswerProof: Question %##s (%s)", dv->origName.c, DNSTypeName(dv->origType)); 525 // 526 // RFC 4035: Section 3.1.3.3 527 // 528 // 1) We used a wildcard because the qname does not exist, so verify 529 // that the qname does not exist 530 // 531 // 2) Is the wildcard the right one ? 532 // 533 // Unfortunately, this is not well explained in that section. Refer to 534 // RFC 5155 section 7.2.6. 535 536 // Walk the list of nsecs we received and see if they prove that 537 // the name does not exist 538 539 mDNSPlatformMemZero(&q, sizeof(DNSQuestion)); 540 q.ThisQInterval = -1; 541 InitializeQuestion(m, &q, dv->InterfaceID, &dv->origName, dv->origType, mDNSNULL, mDNSNULL); 542 543 ncr = NSECParentForQuestion(m, &q); 544 if (!ncr) 545 { 546 LogMsg("WildcardAnswerProof: Can't find NSEC Parent for %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); 547 goto error; 548 } 549 else 550 { 551 LogDNSSEC("WildcardAnswerProof: found %s", CRDisplayString(m, ncr)); 552 } 553 rp = &(ncr->nsec); 554 while (*rp) 555 { 556 if ((*rp)->resrec.rrtype == kDNSType_NSEC) 557 { 558 CacheRecord *cr = *rp; 559 if (!NSECNameExists(m, &cr->resrec, &dv->origName, dv->origType)) 560 break; 561 } 562 else if ((*rp)->resrec.rrtype == kDNSType_NSEC3) 563 { 564 nsec3 = rp; 565 } 566 rp=&(*rp)->next; 567 } 568 if (!(*rp)) 569 { 570 mDNSBool ret = mDNSfalse; 571 if (nsec3) 572 { 573 ret = NSEC3WildcardAnswerProof(m, ncr, dv); 574 } 575 if (!ret) 576 { 577 LogDNSSEC("WildcardAnswerProof: NSEC3 wildcard proof failed for %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); 578 goto error; 579 } 580 rp = nsec3; 581 } 582 else 583 { 584 ce = NSECClosestEncloser(&((*rp)->resrec), &dv->origName); 585 if (!ce) 586 { 587 LogMsg("WildcardAnswerProof: ERROR!! Closest Encloser NULL for %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); 588 goto error; 589 } 590 if (!SameDomainName(ce, dv->wildcardName)) 591 { 592 LogMsg("WildcardAnswerProof: ERROR!! Closest Encloser %##s does not match wildcard name %##s", q.qname.c, dv->wildcardName->c); 593 goto error; 594 } 595 } 596 597 VerifyNSEC(m, &((*rp)->resrec), mDNSNULL, dv, ncr, mDNSNULL); 598 return; 599error: 600 dv->DVCallback(m, dv, DNSSEC_Bogus); 601} 602 603// We have a NSEC. Need to see if it proves that NODATA exists for the given name. Note that this 604// function does not prove anything as proof may require more than one NSEC and this function 605// processes only one NSEC at a time. 606// 607// Returns mDNSfalse if the NSEC does not prove the NODATA error 608// Returns mDNStrue if the NSEC proves the NODATA error 609// 610mDNSlocal mDNSBool NSECNoDataError(mDNS *const m, ResourceRecord *rr, domainname *name, mDNSu16 qtype, domainname **wildcard) 611{ 612 const domainname *oname = rr->name; // owner name 613 614 if (wildcard) *wildcard = mDNSNULL; 615 // RFC 4035 616 // 617 // section 3.1.3.1 : Name matches. Prove that the type does not exist and also CNAME is 618 // not set as in that case CNAME should have been returned ( CNAME part is mentioned in 619 // section 4.3 of dnssec-bis-updates.) Without the CNAME check, a positive response can 620 // be converted to a NODATA/NOERROR response. 621 // 622 // section 3.1.3.4 : No exact match for the name but there is a wildcard that could match 623 // the name but not the type. There are two NSECs in this case. One of them is a wildcard 624 // NSEC and another NSEC proving that the qname does not exist. We are called with one 625 // NSEC at a time. We return what we matched and the caller should decide whether all 626 // conditions are met for the proof. 627 if (SameDomainName(oname, name)) 628 { 629 mDNSBool soa = RRAssertsExistence(rr, kDNSType_SOA); 630 mDNSBool ns = RRAssertsExistence(rr, kDNSType_NS); 631 if (qtype != kDNSType_DS) 632 { 633 // For non-DS type questions, we don't want to use the parent side records to 634 // answer it 635 if (ns && !soa) 636 { 637 LogDNSSEC("NSECNoDataError: Parent side NSEC %s, can't use for child qname %##s (%s)", 638 RRDisplayString(m, rr), name->c, DNSTypeName(qtype)); 639 return mDNSfalse; 640 } 641 } 642 else 643 { 644 if (soa) 645 { 646 LogDNSSEC("NSECNoDataError: Child side NSEC %s, can't use for parent qname %##s (%s)", 647 RRDisplayString(m, rr), name->c, DNSTypeName(qtype)); 648 return mDNSfalse; 649 } 650 } 651 if (RRAssertsExistence(rr, qtype) || RRAssertsExistence(rr, kDNSType_CNAME)) 652 { 653 LogMsg("NSECNoDataError: ERROR!! qtype %s exists in %s", DNSTypeName(qtype), RRDisplayString(m, rr)); 654 return mDNSfalse; 655 } 656 LogDNSSEC("NSECNoDataError: qype %s does not exist in %s", DNSTypeName(qtype), RRDisplayString(m, rr)); 657 return mDNStrue; 658 } 659 else 660 { 661 // Name does not exist. Before we check for a wildcard match, make sure that 662 // this is not an ENT. 663 if (NSECAnswersENT(rr, name)) 664 { 665 LogDNSSEC("NSECNoDataError: name %##s exists %s", name->c, RRDisplayString(m, rr)); 666 return mDNSfalse; 667 } 668 669 // Wildcard check. If this is a wildcard NSEC, then check to see if we could 670 // have answered the question using this wildcard and it should not have the 671 // "qtype" passed in with its bitmap. 672 // 673 // See RFC 4592, on how wildcards are used to synthesize answers. Find the 674 // closest encloser and the qname should be a subdomain i.e if the wildcard 675 // is *.x.example, x.example is the closest encloser and the qname should be 676 // a subdomain e.g., y.x.example or z.y.x.example and so on. 677 if (oname->c[0] == 1 && oname->c[1] == '*') 678 { 679 int r, s; 680 const domainname *ce = SkipLeadingLabels(oname, 1); 681 682 r = DNSSECCanonicalOrder(name, ce, &s); 683 if (s) 684 { 685 if (RRAssertsExistence(rr, qtype) || RRAssertsExistence(rr, kDNSType_CNAME)) 686 { 687 LogMsg("NSECNoDataError: ERROR!! qtype %s exists in wildcard %s", DNSTypeName(qtype), RRDisplayString(m, rr)); 688 return mDNSfalse; 689 } 690 if (qtype == kDNSType_DS && RRAssertsExistence(rr, kDNSType_SOA)) 691 { 692 LogDNSSEC("NSECNoDataError: Child side wildcard NSEC %s, can't use for parent qname %##s (%s)", 693 RRDisplayString(m, rr), name->c, DNSTypeName(qtype)); 694 return mDNSfalse; 695 } 696 else if (qtype != kDNSType_DS && RRAssertsNonexistence(rr, kDNSType_SOA) && 697 RRAssertsExistence(rr, kDNSType_NS)) 698 { 699 // Don't use the parent side record for this 700 LogDNSSEC("NSECNoDataError: Parent side wildcard NSEC %s, can't use for child qname %##s (%s)", 701 RRDisplayString(m, rr), name->c, DNSTypeName(qtype)); 702 return mDNSfalse; 703 } 704 *wildcard = (domainname *)ce; 705 LogDNSSEC("NSECNoDataError: qtype %s does not exist in wildcard %s", DNSTypeName(qtype), RRDisplayString(m, rr)); 706 return mDNStrue; 707 } 708 } 709 return mDNSfalse; 710 } 711} 712 713mDNSexport void NoDataNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status) 714{ 715 RRVerifier *rv; 716 DNSSECVerifier *pdv; 717 CacheRecord *ncr; 718 719 LogDNSSEC("NoDataNSECCallback: called"); 720 if (!dv->parent) 721 { 722 LogMsg("NoDataNSECCCallback: no parent DV"); 723 FreeDNSSECVerifier(m, dv); 724 return; 725 } 726 727 if (dv->ac) 728 { 729 // Before we free the "dv", we need to update the 730 // parent with our AuthChain information 731 UpdateParent(dv); 732 } 733 734 pdv = dv->parent; 735 736 // We don't care about the "dv" that was allocated in VerifyNSEC 737 // as it just verifies one of the nsecs. Get the original verifier and 738 // verify the other NSEC like we did the first time. 739 dv->parent = mDNSNULL; 740 FreeDNSSECVerifier(m, dv); 741 742 if (status != DNSSEC_Secure) 743 { 744 goto error; 745 } 746 747 ncr = NSECParentForQuestion(m, &pdv->q); 748 if (!ncr) 749 { 750 LogMsg("NoDataNSECCallback: Can't find NSEC Parent for %##s (%s)", pdv->q.qname.c, DNSTypeName(pdv->q.qtype)); 751 goto error; 752 } 753 rv = pdv->pendingNSEC; 754 pdv->pendingNSEC = rv->next; 755 // We might have more than one pendingNSEC in the case of NSEC3. If this is the last one, 756 // we don't need to come back here; let the regular NSECCallback call the original callback. 757 rv->next = mDNSNULL; 758 LogDNSSEC("NoDataNSECCallback: Verifying %##s (%s)", rv->name.c, DNSTypeName(rv->rrtype)); 759 if (!pdv->pendingNSEC) 760 VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, mDNSNULL); 761 else 762 VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, NoDataNSECCallback); 763 return; 764 765error: 766 pdv->DVCallback(m, pdv, status); 767} 768 769mDNSexport void NameErrorNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status) 770{ 771 RRVerifier *rv; 772 DNSSECVerifier *pdv; 773 CacheRecord *ncr; 774 775 LogDNSSEC("NameErrorNSECCallback: called"); 776 if (!dv->parent) 777 { 778 LogMsg("NameErrorNSECCCallback: no parent DV"); 779 FreeDNSSECVerifier(m, dv); 780 return; 781 } 782 783 if (dv->ac) 784 { 785 // Before we free the "dv", we need to update the 786 // parent with our AuthChain information 787 UpdateParent(dv); 788 } 789 790 pdv = dv->parent; 791 // We don't care about the "dv" that was allocated in VerifyNSEC 792 // as it just verifies one of the nsecs. Get the original verifier and 793 // verify the other NSEC like we did the first time. 794 dv->parent = mDNSNULL; 795 FreeDNSSECVerifier(m, dv); 796 797 if (status != DNSSEC_Secure) 798 { 799 goto error; 800 } 801 802 ncr = NSECParentForQuestion(m, &pdv->q); 803 if (!ncr) 804 { 805 LogMsg("NameErrorNSECCallback: Can't find NSEC Parent for %##s (%s)", pdv->q.qname.c, DNSTypeName(pdv->q.qtype)); 806 goto error; 807 } 808 rv = pdv->pendingNSEC; 809 pdv->pendingNSEC = rv->next; 810 // We might have more than one pendingNSEC in the case of NSEC3. If this is the last one, 811 // we don't need to come back here; let the regular NSECCallback call the original callback. 812 rv->next = mDNSNULL; 813 LogDNSSEC("NameErrorNSECCallback: Verifying %##s (%s)", rv->name.c, DNSTypeName(rv->rrtype)); 814 if (!pdv->pendingNSEC) 815 VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, mDNSNULL); 816 else 817 VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, NameErrorNSECCallback); 818 819 return; 820 821error: 822 pdv->DVCallback(m, pdv, status); 823} 824 825// We get a NODATA error with no records in answer section. This proves 826// that qname does not exist. 827mDNSlocal void NoDataProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr) 828{ 829 CacheRecord **rp; 830 domainname *wildcard = mDNSNULL; 831 const domainname *ce = mDNSNULL; 832 ResourceRecord *nsec_wild = mDNSNULL; 833 ResourceRecord *nsec_noname = mDNSNULL; 834 835 // NODATA Error could mean two things. The name exists with no type or there is a 836 // wildcard that matches the name but no type. This is done by NSECNoDataError. 837 // 838 // If it is the case of wildcard, there are two NSECs. One is the wildcard NSEC and 839 // the other NSEC to prove that there is no other closer match. 840 841 wildcard = mDNSNULL; 842 rp = &(ncr->nsec); 843 while (*rp) 844 { 845 if ((*rp)->resrec.rrtype == kDNSType_NSEC) 846 { 847 CacheRecord *cr = *rp; 848 if (NSECNoDataError(m, &cr->resrec, &dv->q.qname, dv->q.qtype, &wildcard)) 849 { 850 if (wildcard) 851 { 852 dv->flags |= WILDCARD_PROVES_NONAME_EXISTS; 853 LogDNSSEC("NoDataProof: NSEC %s proves NODATA error for %##s (%s)", 854 RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype)); 855 } 856 else 857 { 858 dv->flags |= NSEC_PROVES_NOTYPE_EXISTS; 859 LogDNSSEC("NoDataProof: NSEC %s proves NOTYPE error for %##s (%s)", 860 RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype)); 861 } 862 nsec_wild = &cr->resrec; 863 } 864 if (!NSECNameExists(m, &cr->resrec, &dv->q.qname, dv->q.qtype)) 865 { 866 LogDNSSEC("NoDataProof: NSEC %s proves that name %##s (%s) does not exist", 867 RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype)); 868 // If we have a wildcard, then we should check to see if the closest 869 // encloser is the same as the wildcard. 870 ce = NSECClosestEncloser(&cr->resrec, &dv->q.qname); 871 dv->flags |= NSEC_PROVES_NONAME_EXISTS; 872 nsec_noname = &cr->resrec; 873 } 874 } 875 rp=&(*rp)->next; 876 } 877 if (!nsec_noname && !nsec_wild) 878 { 879 LogDNSSEC("NoDataProof: No valid NSECs for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype)); 880 goto error; 881 } 882 // If the type exists, then we have to verify just that NSEC 883 if (!(dv->flags & NSEC_PROVES_NOTYPE_EXISTS)) 884 { 885 // If we have a wildcard, then we should have a "ce" which matches the wildcard 886 // If we don't have a wildcard, then we should have proven that the name does not 887 // exist which means we would have set the "ce". 888 if (wildcard && !ce) 889 { 890 LogMsg("NoDataProof: Cannot prove that the name %##s (%s) does not exist", dv->q.qname.c, DNSTypeName(dv->q.qtype)); 891 goto error; 892 } 893 if (wildcard && !SameDomainName(wildcard, ce)) 894 { 895 LogMsg("NoDataProof: wildcard %##s does not match closest encloser %##s", wildcard->c, ce->c); 896 goto error; 897 } 898 // If a single NSEC can prove both, then we just have validate that one NSEC. 899 if (nsec_wild == nsec_noname) 900 { 901 nsec_noname = mDNSNULL; 902 dv->flags &= ~NSEC_PROVES_NONAME_EXISTS; 903 } 904 } 905 906 if ((dv->flags & (WILDCARD_PROVES_NONAME_EXISTS|NSEC_PROVES_NONAME_EXISTS)) == 907 (WILDCARD_PROVES_NONAME_EXISTS|NSEC_PROVES_NONAME_EXISTS)) 908 { 909 mStatus status; 910 RRVerifier *r = AllocateRRVerifier(nsec_noname, &status); 911 if (!r) goto error; 912 // First verify wildcard NSEC and then when we are done, we 913 // will verify the noname nsec 914 dv->pendingNSEC = r; 915 LogDNSSEC("NoDataProof: Verifying wild and noname %s", RRDisplayString(m, nsec_wild)); 916 VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, NoDataNSECCallback); 917 } 918 else if ((dv->flags & WILDCARD_PROVES_NONAME_EXISTS) || 919 (dv->flags & NSEC_PROVES_NOTYPE_EXISTS)) 920 { 921 LogDNSSEC("NoDataProof: Verifying wild %s", RRDisplayString(m, nsec_wild)); 922 VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, mDNSNULL); 923 } 924 else if (dv->flags & NSEC_PROVES_NONAME_EXISTS) 925 { 926 LogDNSSEC("NoDataProof: Verifying noname %s", RRDisplayString(m, nsec_noname)); 927 VerifyNSEC(m, nsec_noname, mDNSNULL, dv, ncr, mDNSNULL); 928 } 929 return; 930error: 931 LogDNSSEC("NoDataProof: Error return"); 932 dv->DVCallback(m, dv, DNSSEC_Bogus); 933} 934 935mDNSlocal mDNSBool NSECNoWildcard(mDNS *const m, ResourceRecord *rr, domainname *qname, mDNSu16 qtype) 936{ 937 const domainname *ce; 938 domainname wild; 939 940 // If the query name is c.x.w.example and if the name does not exist, we should get 941 // get a nsec back that looks something like this: 942 // 943 // w.example NSEC a.w.example 944 // 945 // First, we need to get the closest encloser which in this case is w.example. Wild 946 // card synthesis works by finding the closest encloser first and then look for 947 // a "*" label (assuming * label does not appear in the question). If it does not 948 // exists, it would return the NSEC at that name. And the wildcard name at the 949 // closest encloser "*.w.example" would be covered by such an NSEC. (Appending "*" 950 // makes it bigger than w.example and "* is smaller than "a" for the above NSEC) 951 // 952 ce = NSECClosestEncloser(rr, qname); 953 if (!ce) { LogMsg("NSECNoWildcard: No closest encloser for rr %s, qname %##s (%s)", qname->c, DNSTypeName(qtype)); return mDNSfalse; } 954 955 wild.c[0] = 1; 956 wild.c[1] = '*'; 957 wild.c[2] = 0; 958 if (!AppendDomainName(&wild, ce)) 959 { 960 LogMsg("NSECNoWildcard: ERROR!! Can't append domainname closest encloser name %##s, qname %##s (%s)", ce->c, qname->c, DNSTypeName(qtype)); 961 return mDNSfalse; 962 } 963 if (NSECNameExists(m, rr, &wild, qtype) != 0) 964 { 965 LogDNSSEC("NSECNoWildcard: Wildcard name %##s exists or not valid qname %##s (%s)", wild.c, qname->c, DNSTypeName(qtype)); 966 return mDNSfalse; 967 } 968 LogDNSSEC("NSECNoWildcard: Wildcard name %##s does not exist for record %s, qname %##s (%s)", wild.c, 969 RRDisplayString(m, rr), qname->c, DNSTypeName(qtype)); 970 return mDNStrue; 971} 972 973// We get a NXDOMAIN error with no records in answer section. This proves 974// that qname does not exist. 975mDNSlocal void NameErrorProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr) 976{ 977 CacheRecord **rp; 978 ResourceRecord *nsec_wild = mDNSNULL; 979 ResourceRecord *nsec_noname = mDNSNULL; 980 mStatus status; 981 982 // NXDOMAIN Error. We need to prove that the qname does not exist and there 983 // is no wildcard that can be used to answer the question. 984 985 rp = &(ncr->nsec); 986 while (*rp) 987 { 988 if ((*rp)->resrec.rrtype == kDNSType_NSEC) 989 { 990 CacheRecord *cr = *rp; 991 if (!NSECNameExists(m, &cr->resrec, &dv->q.qname, dv->q.qtype)) 992 { 993 LogDNSSEC("NameErrorProof: NSEC %s proves name does not exist for %##s (%s)", 994 RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype)); 995 // If we have a wildcard, then we should check to see if the closest 996 // encloser is the same as the wildcard. 997 dv->flags |= NSEC_PROVES_NONAME_EXISTS; 998 nsec_noname = &cr->resrec; 999 } 1000 if (NSECNoWildcard(m, &cr->resrec, &dv->q.qname, dv->q.qtype)) 1001 { 1002 dv->flags |= WILDCARD_PROVES_NONAME_EXISTS; 1003 nsec_wild = &cr->resrec; 1004 LogDNSSEC("NameErrorProof: NSEC %s proves wildcard cannot answer question for %##s (%s)", 1005 RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype)); 1006 } 1007 } 1008 rp=&(*rp)->next; 1009 } 1010 if (!nsec_noname || !nsec_wild) 1011 { 1012 LogMsg("NameErrorProof: Proof failed for %##s (%s) noname %p, wild %p", dv->q.qname.c, DNSTypeName(dv->q.qtype), nsec_noname, nsec_wild); 1013 goto error; 1014 } 1015 1016 // First verify wildcard NSEC and then when we are done, we will verify the noname nsec. 1017 // Sometimes a single NSEC can prove both that the "qname" does not exist and a wildcard 1018 // could not have produced qname. These are a few examples where this can happen. 1019 // 1020 // 1. If the zone is example.com and you look up *.example.com and if there are no wildcards, 1021 // you will get a NSEC back "example.com NSEC a.example.com". This proves that both the 1022 // name does not exist and *.example.com also does not exist 1023 // 1024 // 2. If the zone is example.com and it has a record like this: 1025 // 1026 // example.com NSEC d.example.com 1027 // 1028 // any name you lookup in between like a.example.com,b.example.com etc. you will get a single 1029 // NSEC back. In that case we just have to verify only once. 1030 // 1031 if (nsec_wild != nsec_noname) 1032 { 1033 RRVerifier *r = AllocateRRVerifier(nsec_noname, &status); 1034 if (!r) goto error; 1035 dv->pendingNSEC = r; 1036 LogDNSSEC("NoDataProof: Verifying wild %s", RRDisplayString(m, nsec_wild)); 1037 VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, NameErrorNSECCallback); 1038 } 1039 else 1040 { 1041 LogDNSSEC("NoDataProof: Verifying only one %s", RRDisplayString(m, nsec_wild)); 1042 VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, mDNSNULL); 1043 } 1044 return; 1045error: 1046 dv->DVCallback(m, dv, DNSSEC_Bogus); 1047} 1048 1049mDNSexport CacheRecord *NSECRecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype) 1050{ 1051 CacheGroup *cg; 1052 CacheRecord *cr; 1053 mDNSu32 slot, namehash; 1054 1055 slot = HashSlot(name); 1056 namehash = DomainNameHashValue(name); 1057 1058 cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, name); 1059 if (!cg) 1060 { 1061 LogDNSSEC("NSECRecordForName: cg NULL for %##s", name); 1062 return mDNSNULL; 1063 } 1064 for (cr = cg->members; cr; cr = cr->next) 1065 { 1066 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative && cr->resrec.rrtype == qtype) 1067 { 1068 CacheRecord *ncr; 1069 for (ncr = cr->nsec; ncr; ncr = ncr->next) 1070 { 1071 if (ncr->resrec.rrtype == kDNSType_NSEC && 1072 SameDomainName(ncr->resrec.name, name)) 1073 { 1074 // See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit 1075 // should be absent 1076 if (RRAssertsExistence(&ncr->resrec, kDNSType_SOA) || 1077 RRAssertsExistence(&ncr->resrec, kDNSType_DS)) 1078 { 1079 LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but DS or SOA bit set", CRDisplayString(m, ncr), name, 1080 DNSTypeName(qtype)); 1081 return mDNSNULL; 1082 } 1083 // Section 2.3 of RFC 4035 states that: 1084 // 1085 // Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST 1086 // have an NSEC resource record. 1087 // 1088 // So, if we have an NSEC record matching the question name with the NS bit set, 1089 // then this is a delegation. 1090 // 1091 if (RRAssertsExistence(&ncr->resrec, kDNSType_NS)) 1092 { 1093 LogDNSSEC("NSECRecordForName: found record %s for %##s (%s)", CRDisplayString(m, ncr), name, DNSTypeName(qtype)); 1094 return ncr; 1095 } 1096 else 1097 { 1098 LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but NS bit is not set", CRDisplayString(m, ncr), name, 1099 DNSTypeName(qtype)); 1100 return mDNSNULL; 1101 } 1102 } 1103 } 1104 } 1105 } 1106 return mDNSNULL; 1107} 1108 1109mDNSlocal void StartInsecureProof(mDNS * const m, DNSSECVerifier *dv) 1110{ 1111 domainname trigger; 1112 DNSSECVerifier *prevdv = mDNSNULL; 1113 1114 // Remember the name that triggered the insecure proof 1115 AssignDomainName(&trigger, &dv->q.qname); 1116 while (dv->parent) 1117 { 1118 prevdv = dv; 1119 dv = dv->parent; 1120 } 1121 if (prevdv) 1122 { 1123 prevdv->parent = mDNSNULL; 1124 FreeDNSSECVerifier(m, prevdv); 1125 } 1126 // For Optional DNSSEC, we are opportunistically verifying dnssec. We don't care 1127 // if something results in bogus as we still want to deliver results to the 1128 // application e.g., CNAME processing results in bogus because the path is broken, 1129 // but we still want to follow CNAMEs so that we can deliver the final results to 1130 // the application. 1131 if (dv->ValidationRequired == DNSSEC_VALIDATION_SECURE_OPTIONAL) 1132 { 1133 LogDNSSEC("StartInsecureProof: Aborting insecure proof for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype)); 1134 dv->DVCallback(m, dv, DNSSEC_Bogus); 1135 return; 1136 } 1137 1138 LogDNSSEC("StartInsecureProof for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype)); 1139 // Don't start the insecure proof again after we finish the one that we start here by 1140 // setting InsecureProofDone. 1141 dv->InsecureProofDone = 1; 1142 ProveInsecure(m, dv, mDNSNULL, &trigger); 1143 return; 1144} 1145 1146mDNSexport void ValidateWithNSECS(mDNS *const m, DNSSECVerifier *dv, CacheRecord *cr) 1147{ 1148 LogDNSSEC("ValidateWithNSECS: called for %s", CRDisplayString(m, cr)); 1149 1150 // If we are encountering a break in the chain of trust i.e., NSEC/NSEC3s for 1151 // DS query, then do the insecure proof. This is important because if we 1152 // validate these NSECs normally and prove that they are "secure", we will 1153 // end up delivering the secure result to the original question where as 1154 // these NSEC/NSEC3s actually prove that DS does not exist and hence insecure. 1155 // 1156 // This break in the chain can happen after we have partially validated the 1157 // path (dv->ac is non-NULL) or the first time (dv->ac is NULL) after we 1158 // fetched the DNSKEY (dv->key is non-NULL). We don't want to do this 1159 // if we have just started the non-existence proof (dv->key is NULL) as 1160 // it does not indicate a break in the chain of trust. 1161 // 1162 // If we are already doing a insecurity proof, don't start another one. In 1163 // the case of NSECs, it is possible that insecurity proof starts and it 1164 // gets NSECs and as part of validating that we receive more NSECS in which 1165 // case we don't want to start another insecurity proof. 1166 if (dv->ValidationRequired != DNSSEC_VALIDATION_INSECURE && 1167 (!dv->parent || dv->parent->ValidationRequired != DNSSEC_VALIDATION_INSECURE)) 1168 { 1169 if ((dv->ac && dv->q.qtype == kDNSType_DS) || 1170 (!dv->ac && dv->key && dv->q.qtype == kDNSType_DS)) 1171 { 1172 LogDNSSEC("ValidateWithNSECS: Starting insecure proof: name %##s ac %p, key %p, parent %p", dv->q.qname.c, 1173 dv->ac, dv->key, dv->parent); 1174 StartInsecureProof(m, dv); 1175 return; 1176 } 1177 } 1178 // "parent" is set when we are validating a NSEC and we should not be here in 1179 // the normal case when parent is set. For example, we are looking up the A 1180 // record for www.example.com and following can happen. 1181 // 1182 // a) Record does not exist and we get a NSEC 1183 // b) While validating (a), we get an NSEC for the first DS record that we look up 1184 // c) Record exists but we get NSECs for the first DS record 1185 // d) We are able to partially validate (a) or (b), but we get NSECs somewhere in 1186 // the chain 1187 // 1188 // For (a), parent is not set as we are not validating the NSEC yet. Hence we would 1189 // start the validation now. 1190 // 1191 // For (b), the parent is set, but should be caught by the above "if" block because we 1192 // should have gotten the DNSKEY at least. In the case of nested insecurity proof, 1193 // we would end up here and fail with bogus. 1194 // 1195 // For (c), the parent is not set and should be caught by the above "if" block because we 1196 // should have gotten the DNSKEY at least. 1197 // 1198 // For (d), the above "if" block would catch it as "dv->ac" is non-NULL. 1199 // 1200 // Hence, we should not come here in the normal case. Possible pathological cases are: 1201 // Insecure proof getting NSECs while validating NSECs, getting NSECs for DNSKEY for (c) 1202 // above etc. 1203 if (dv->parent) 1204 { 1205 LogDNSSEC("ValidateWithNSECS: dv parent set for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype)); 1206 dv->DVCallback(m, dv, DNSSEC_Bogus); 1207 return; 1208 } 1209 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative) 1210 { 1211 mDNSu8 rcode; 1212 CacheRecord *neg = cr->nsec; 1213 mDNSBool nsecs_seen = mDNSfalse; 1214 1215 while (neg) 1216 { 1217 // The list can only have NSEC or NSEC3s. This was checked when we added the 1218 // NSECs to the cache record. 1219 if (neg->resrec.rrtype == kDNSType_NSEC) 1220 nsecs_seen = mDNStrue; 1221 LogDNSSEC("ValidateWithNSECS: NSECCached Record %s", CRDisplayString(m, neg)); 1222 neg = neg->next; 1223 } 1224 1225 rcode = (mDNSu8)(cr->responseFlags.b[1] & kDNSFlag1_RC_Mask); 1226 if (rcode == kDNSFlag1_RC_NoErr) 1227 { 1228 if (nsecs_seen) 1229 NoDataProof(m, dv, cr); 1230 else 1231 NSEC3NoDataProof(m, dv, cr); 1232 } 1233 else if (rcode == kDNSFlag1_RC_NXDomain) 1234 { 1235 if (nsecs_seen) 1236 NameErrorProof(m, dv, cr); 1237 else 1238 NSEC3NameErrorProof(m, dv, cr); 1239 } 1240 else 1241 { 1242 LogDNSSEC("ValidateWithNSECS: Rcode %d invalid", rcode); 1243 dv->DVCallback(m, dv, DNSSEC_Bogus); 1244 } 1245 } 1246 else 1247 { 1248 LogMsg("ValidateWithNSECS: Not a valid cache record %s for NSEC proofs", CRDisplayString(m, cr)); 1249 dv->DVCallback(m, dv, DNSSEC_Bogus); 1250 return; 1251 } 1252} 1253 1254#else // !DNSSEC_DISABLED 1255 1256mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode) 1257{ 1258 (void)m; 1259 (void)crlist; 1260 (void)negcr; 1261 (void)rcode; 1262 1263 return mDNSfalse; 1264} 1265 1266#endif // !DNSSEC_DISABLED 1267