From 913da3146ebc35c5d580d8d349a6bfb34d508ca2 Mon Sep 17 00:00:00 2001 From: Philip Homburg Date: Thu, 15 Jan 2026 11:51:59 +0100 Subject: [PATCH] Now passes test3/NSEC. --- src/commands/signer.rs | 143 ++++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 25 deletions(-) diff --git a/src/commands/signer.rs b/src/commands/signer.rs index 69387da..a7c4724 100644 --- a/src/commands/signer.rs +++ b/src/commands/signer.rs @@ -1728,7 +1728,7 @@ type ChangesValue = (RtypeSet, RtypeSet); // add set followed by delete set. struct IncrementalSigningState { origin: Name, old_data: HashMap<(Name, Rtype), Vec>, - new_data: HashMap<(Name, Rtype), Vec>, + new_data: BTreeMap<(Name, Rtype), Vec>, nsecs: BTreeMap, ZRD>, rrsigs: HashMap<(Name, Rtype), Vec>, @@ -1749,7 +1749,7 @@ impl IncrementalSigningState { Self { origin, old_data: HashMap::new(), - new_data: HashMap::new(), + new_data: BTreeMap::new(), nsecs: BTreeMap::new(), rrsigs: HashMap::new(), changes: HashMap::new(), @@ -2109,9 +2109,6 @@ fn incremental_nsec( iss: &mut IncrementalSigningState,) -> Result<(), Error> { let changes = iss.changes.clone(); for (key, (add, delete)) in &changes { - dbg!(key); - dbg!(add); - dbg!(delete); // The intersection between add and delete is empty. assert!(add.intersection(delete).next().is_none()); @@ -2136,7 +2133,34 @@ fn incremental_nsec( iss: &mut IncrementalSigningState,) -> Result<(), Error> { assert!(delete.difference(&curr).next().is_none()); if add.contains(&Rtype::NS) { - println!("should handle existing name, adding NS nsec {nsec:?}"); + // Remove the signatures for the existing types. + for rtype in nsec.types().iter() { + // When NS is added, we should keep the signatures for + // DS and NSEC. The NSEC signature will be updated but + // there is no point in removing it first. Do no try to + // remove a signature for RRSIG because it does not exist. + if rtype == Rtype::DS || rtype == Rtype::NSEC || + rtype == Rtype::RRSIG { + continue; + } + let key = (key.clone(), rtype); + iss.rrsigs.remove(&key); + } + + // Restrict curr and add to these types. + let mask: HashSet = [Rtype::NS, Rtype::DS, Rtype::NSEC, Rtype::RRSIG].into(); + + let curr: HashSet = curr.intersection(&mask).map(|r| *r).collect(); + let add: HashSet = add.intersection(&mask).map(|r| *r).collect(); + + // Update the NSEC record. + nsec_update_bitmap(&record_nsec, &nsec, &curr, &add, delete, &set_nsec_rrsig, iss); + + // Mark descendents as occluded after updating the bitmap. + // The reason is that nsec_update_bitmap uses that current + // next_name and nsec_set_occluded may change that. + nsec_set_occluded(key, iss); + continue; } if delete.contains(&Rtype::NS) { @@ -2144,6 +2168,21 @@ fn incremental_nsec( iss: &mut IncrementalSigningState,) -> Result<(), Error> { // be removed from apex. assert!(*key != iss.origin); + // Curr does not include all types at this name. Add the + // missing types to curr. + let range_key = (key.clone(), 0.into()); + let range = iss.new_data.range(range_key..); + for ((r_name, r_type), _) in range { + if r_name != key { + break; + } + if add.contains(r_type) { + // Skip what we are trying to add. + continue; + } + curr.insert(*r_type); + } + let mut new = nsec_update_bitmap(&record_nsec, &nsec, &curr, add, delete, &set_nsec_rrsig, iss); // Sign the types at this name except for NSEC, and RRSIG. @@ -2152,7 +2191,7 @@ fn incremental_nsec( iss: &mut IncrementalSigningState,) -> Result<(), Error> { sign_rtype_set(key, &new, iss)?; // Name that were previously occluded are no longer. - nsec_clear_occluded(key); + nsec_clear_occluded(key, iss)?; continue; } if *key != iss.origin && nsec.types().contains(Rtype::NS) { @@ -2220,9 +2259,6 @@ fn incremental_nsec( iss: &mut IncrementalSigningState,) -> Result<(), Error> { } fn nsec_insert(name: &Name, rtypebitmap: RtypeBitmap, iss: &mut IncrementalSigningState) { - dbg!(&rtypebitmap); - dbg!(name); - // Try to find the NSEC record that comes before the one we are trying // to insert. Assume that the APEX NSEC will always exist can sort // before anything else. @@ -2231,17 +2267,13 @@ fn nsec_insert(name: &Name, rtypebitmap: RtypeBitmap, iss: &mut In let previous_name = previous_name.clone(); let previous_record = previous_record.clone(); drop(range); - dbg!(&previous_name); - dbg!(&previous_record); let ZoneRecordData::Nsec(previous_nsec) = previous_record.data() else { panic!("NSEC record expected"); }; - dbg!(previous_nsec); let next = previous_nsec.next_name(); let new_nsec = Nsec::new(next.clone(), rtypebitmap); let new_record = Record::new(name.clone(), previous_record.class(), previous_record.ttl(), ZoneRecordData::Nsec(new_nsec)); - dbg!(&new_record); iss.nsecs.insert(name.clone(), new_record); iss.modified_nsecs.insert(name.clone()); let previous_nsec = Nsec::new(name.clone(), previous_nsec.types().clone()); @@ -2252,9 +2284,6 @@ fn nsec_insert(name: &Name, rtypebitmap: RtypeBitmap, iss: &mut In } fn nsec_remove(name: &Name, next_name: &Name, iss: &mut IncrementalSigningState) { - dbg!(name); - dbg!(next_name); - // Try to find the NSEC record that comes before the one we are trying // to remove. Assume that the APEX NSEC will always exist can sort // before anything else. @@ -2263,12 +2292,9 @@ fn nsec_remove(name: &Name, next_name: &Name, iss: &mut Incrementa let previous_name = previous_name.clone(); let previous_record = previous_record.clone(); drop(range); - dbg!(&previous_name); - dbg!(&previous_record); let ZoneRecordData::Nsec(previous_nsec) = previous_record.data() else { panic!("NSEC record expected"); }; - dbg!(previous_nsec); let previous_nsec = Nsec::new(next_name.clone(), previous_nsec.types().clone()); let previous_record = Record::new(previous_name.clone(), previous_record.class(), previous_record.ttl(), ZoneRecordData::Nsec(previous_nsec)); @@ -2323,13 +2349,10 @@ fn nsec_set_occluded(name: &Name, iss: &mut IncrementalSigningState) { if next == name { break; } - dbg!(&next); - let curr = next; let Some(nsec_record) = iss.nsecs.get(&curr) else { panic!("NSEC for {name} expected to exist"); }; - dbg!(nsec_record); let ZoneRecordData::Nsec(nsec) = nsec_record.data() else { panic!("NSEC record expected"); }; @@ -2346,8 +2369,78 @@ fn nsec_set_occluded(name: &Name, iss: &mut IncrementalSigningState) { } } -fn nsec_clear_occluded(_name: &Name) { - println!("Should implement nsec_clear_occluded"); +fn nsec_clear_occluded(name: &Name, iss: &mut IncrementalSigningState) -> Result<(), Error> { + let key = (name.clone(), Rtype::SOA); + let range = iss.new_data.range(key..); + let mut opt_curr_name: Option<&Name> = None; + let mut curr_types: HashSet = HashSet::new(); + let mut work = vec![]; + + // Keep track of delegations. Name below a delegation remain occluded. + let mut delegation: Option> = None; + + for ((key_name, key_rtype), _) in range { + // There is no easy way to avoid name showing up in the range. Just + // filter out name. + if key_name == name { + continue; + } + + // Make sure curr_name is below name. + if !key_name.ends_with(name) { + break; + } + if let Some(d) = &delegation { + if key_name.ends_with(d) && key_name != d { + // Skip. + continue; + } + } + if *key_rtype == Rtype::NS { + // Set key_name as a delegation. + delegation = Some(key_name.clone()); + } + if let Some(curr_name) = opt_curr_name { + if key_name == curr_name { + curr_types.insert(*key_rtype); + } else { + work.push((curr_name.clone(), curr_types)); + opt_curr_name = Some(key_name); + curr_types = [*key_rtype].into(); + } + } else { + opt_curr_name = Some(key_name); + curr_types.insert(*key_rtype); + } + } + if let Some(curr_name) = opt_curr_name { + work.push((curr_name.clone(), curr_types)); + } + for (curr_name, curr_types) in work { + let mut curr_types = if curr_types.contains(&Rtype::NS) { + let has_ds = curr_types.contains(&Rtype::DS); + let mut curr_types: HashSet = [Rtype::NS].into(); + if has_ds { + curr_types.insert(Rtype::DS); + } + curr_types + } else { + curr_types + }; + let mut rtypebitmap = RtypeBitmap::::builder(); + rtypebitmap.add(Rtype::NSEC).expect("should not fail"); + rtypebitmap.add(Rtype::RRSIG).expect("should not fail"); + for rtype in &curr_types { + rtypebitmap.add(*rtype).expect("should not fail"); + } + let rtypebitmap = rtypebitmap.finalize(); + + // Make sure NS doesn't get signed. + curr_types.remove(&Rtype::NS); + sign_rtype_set(&curr_name, &curr_types, iss)?; + nsec_insert(&curr_name, rtypebitmap, iss); + } + Ok(()) } fn is_occluded(name: &Name, iss: &IncrementalSigningState) -> bool {