From 873211fac6d2bb8094218cbe2f1c3f6a228261aa Mon Sep 17 00:00:00 2001 From: Thibault Cheneviere Date: Tue, 30 Jul 2024 10:40:42 -0400 Subject: [PATCH] feat: added the new configuration file to handle correct domain creation for acme --- config.yml | 15 ++++++++-- src/error.rs | 9 ++++++ src/key.rs | 75 ++++++++++++++++++++++++++++++++++++++++---------- src/watcher.rs | 22 +++++++++------ 4 files changed, 95 insertions(+), 26 deletions(-) diff --git a/config.yml b/config.yml index d296fdb..00d8609 100644 --- a/config.yml +++ b/config.yml @@ -12,7 +12,16 @@ log: keys: key1: - - thibault-cne.fr + sub.example.fr: + mname: ns-acme.example.fr. + rname: postmaster.example.fr. + example.fr: + mname: ns-acme.example.fr. + rname: postmaster.example.fr. key2: - - example.com - - example.org + another-example.fr: + mname: ns-acme.another-example.fr. + rname: postmaster.another-example.fr. + fake.another-example.fr: + mname: ns-acme.another-example.fr. + rname: postmaster.another-example.fr. diff --git a/src/error.rs b/src/error.rs index 5af3bf7..14b5b3a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -89,6 +89,15 @@ impl From for Error { } } +impl From for Error { + fn from(_: domain::zonetree::error::OutOfZone) -> Self { + Self { + kind: ErrorKind::DomainZone, + message: Some("out of zone".to_string()), + } + } +} + impl From for Error { fn from(value: std::io::Error) -> Self { Self { diff --git a/src/key.rs b/src/key.rs index 6692be8..1262956 100644 --- a/src/key.rs +++ b/src/key.rs @@ -3,17 +3,19 @@ use std::ops::Deref; use std::path::PathBuf; use domain::base::iana::Class; -use domain::zonetree::types::StoredName; -use domain::zonetree::{Zone, ZoneBuilder}; +use domain::base::{Record, Serial, Ttl}; +use domain::rdata::Soa; +use domain::zonetree::types::{StoredName, StoredRecord}; +use domain::zonetree::{Rrset, SharedRrset, Zone, ZoneBuilder}; use serde::Deserialize; use crate::error::Result; #[derive(Debug, Clone, Deserialize, Default)] -pub struct Keys(HashMap>); +pub struct Keys(HashMap>); impl Deref for Keys { - type Target = HashMap>; + type Target = HashMap>; fn deref(&self) -> &Self::Target { &self.0 @@ -21,29 +23,72 @@ impl Deref for Keys { } #[derive(Debug, Clone, Deserialize, PartialEq, Eq)] -#[serde(untagged)] -pub enum Domain { - Unamed(String), +pub struct DomainInfo { + mname: String, + rname: String, +} + +pub trait TryIntoZone { + fn try_into_zone(self) -> Result; } pub trait TryIntoZones { fn try_into_zones(self) -> Result>; } -impl TryIntoZones for &[Domain] { +trait TryIntoStoredName { + fn try_into_stored_name(self) -> Result; +} + +impl TryIntoZones for &HashMap { fn try_into_zones(self) -> Result> { - self.iter().map(|d| d.try_into()).collect() + self.iter().map(|d| d.try_into_zone()).collect() } } -impl TryFrom<&Domain> for Zone { +impl TryFrom<&DomainInfo> for SharedRrset { type Error = crate::error::Error; - fn try_from(value: &Domain) -> Result { - let apex_name = match value { - Domain::Unamed(name) => StoredName::bytes_from_str(name)?, - }; - Ok(ZoneBuilder::new(apex_name, Class::IN).build()) + fn try_from(value: &DomainInfo) -> std::result::Result { + let record: StoredRecord = Record::new( + (&value.mname).try_into_stored_name()?, + Class::IN, + Ttl::HOUR, + Soa::new( + (&value.mname).try_into_stored_name()?, + (&value.rname).try_into_stored_name()?, + Serial::now(), + Ttl::HOUR, + Ttl::HOUR, + Ttl::HOUR, + Ttl::HOUR, + ) + .into(), + ); + let rset: Rrset = record.into(); + + Ok(rset.into_shared()) + } +} + +impl TryIntoZone for (S, &DomainInfo) +where + S: AsRef, +{ + fn try_into_zone(self) -> Result { + let (name, info) = self; + let mut builder = ZoneBuilder::new((&name).try_into_stored_name()?, Class::IN); + builder.insert_rrset(&name.try_into_stored_name()?, info.try_into()?)?; + Ok(builder.build()) + } +} + +impl TryIntoStoredName for S +where + S: AsRef, +{ + fn try_into_stored_name(self) -> Result { + Ok(StoredName::bytes_from_str(self.as_ref())?) } } diff --git a/src/watcher.rs b/src/watcher.rs index 95368a2..2ec8b85 100644 --- a/src/watcher.rs +++ b/src/watcher.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fs::File; use std::path::Path; use std::sync::mpsc::channel; @@ -8,7 +9,7 @@ use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher use crate::dns::State; use crate::error::{ErrorKind, Result}; -use crate::key::{Domain, KeyFile, Keys, TryIntoZones}; +use crate::key::{DomainInfo, KeyFile, Keys, TryIntoZone, TryIntoZones}; #[derive(Debug, Clone)] pub struct Watcher; @@ -85,7 +86,7 @@ fn handle_file_change(keys: &Keys, config_path: &Path, state: &Arc) -> Re fn handle_deleted_keys<'i, I>(state: &Arc, deleted_keys: I) -> Result<()> where - I: IntoIterator)>, + I: IntoIterator)>, { for (k, v) in deleted_keys { v.try_into_zones()?.into_iter().for_each(|z| { @@ -101,7 +102,7 @@ where fn handle_added_keys<'i, I>(state: &Arc, added_keys: I) -> Result<()> where - I: IntoIterator)>, + I: IntoIterator)>, { for (k, v) in added_keys { v.try_into_zones()?.into_iter().for_each(|z| { @@ -117,20 +118,25 @@ where fn handle_modified_keys<'i, I>(state: &Arc, modified_keys: I) -> Result<()> where - I: IntoIterator, &'i Vec)>, + I: IntoIterator< + Item = ( + &'i HashMap, + &'i HashMap, + ), + >, { for (nv, ov) in modified_keys { ov.iter() - .filter(|d| !nv.contains(d)) + .filter(|&(d, _)| nv.get(d).is_none()) .try_for_each(|d| -> Result<()> { - let zone: Zone = d.try_into()?; + let zone: Zone = d.try_into_zone()?; let _ = state.remove_zone(zone.apex_name(), zone.class()); Ok(()) })?; nv.iter() - .filter(|d| !ov.contains(d)) + .filter(|&(d, _)| ov.get(d).is_none()) .try_for_each(|d| -> Result<()> { - let zone: Zone = d.try_into()?; + let zone: Zone = d.try_into_zone()?; let _ = state.insert_zone(zone); Ok(()) })?;