move validation to Domain ctor

This commit is contained in:
Jorge Aparicio 2024-02-05 15:53:48 +01:00
parent bab595a412
commit 1b0f1ef59f
4 changed files with 50 additions and 35 deletions

View File

@ -1,4 +1,5 @@
use std::{net::Ipv4Addr, process::Child}; use std::net::Ipv4Addr;
use std::process::Child;
use crate::{container::Container, Domain, Result, CHMOD_RW_EVERYONE}; use crate::{container::Container, Domain, Result, CHMOD_RW_EVERYONE};
@ -14,15 +15,12 @@ impl AuthoritativeNameServer {
container.status_ok(&["mkdir", "-p", "/etc/nsd/zones"])?; container.status_ok(&["mkdir", "-p", "/etc/nsd/zones"])?;
let zone_path = "/etc/nsd/zones/main.zone"; let zone_path = "/etc/nsd/zones/main.zone";
container.cp( container.cp("/etc/nsd/nsd.conf", &nsd_conf(domain), CHMOD_RW_EVERYONE)?;
"/etc/nsd/nsd.conf",
&nsd_conf(domain.fqdn()),
CHMOD_RW_EVERYONE,
)?;
let zone_file_contents = match domain { let zone_file_contents = if domain.is_root() {
Domain::Root => root_zone(), root_zone()
Domain::Tld { domain } => tld_zone(domain), } else {
tld_zone(domain)
}; };
container.cp(zone_path, &zone_file_contents, CHMOD_RW_EVERYONE)?; container.cp(zone_path, &zone_file_contents, CHMOD_RW_EVERYONE)?;
@ -43,13 +41,12 @@ impl Drop for AuthoritativeNameServer {
} }
} }
fn tld_zone(domain: &str) -> String { fn tld_zone(domain: Domain) -> String {
assert!(domain.ends_with('.')); assert!(!domain.is_root());
assert!(!domain.starts_with('.'));
minijinja::render!( minijinja::render!(
include_str!("templates/tld.zone.jinja"), include_str!("templates/tld.zone.jinja"),
tld => domain, tld => domain.as_str()
) )
} }
@ -57,12 +54,10 @@ fn root_zone() -> String {
minijinja::render!(include_str!("templates/root.zone.jinja"),) minijinja::render!(include_str!("templates/root.zone.jinja"),)
} }
fn nsd_conf(domain: &str) -> String { fn nsd_conf(domain: Domain) -> String {
assert!(domain.ends_with('.'));
minijinja::render!( minijinja::render!(
include_str!("templates/nsd.conf.jinja"), include_str!("templates/nsd.conf.jinja"),
domain => domain domain => domain.as_str()
) )
} }
@ -72,7 +67,7 @@ mod tests {
#[test] #[test]
fn tld_setup() -> Result<()> { fn tld_setup() -> Result<()> {
let tld_ns = AuthoritativeNameServer::start(Domain::Tld { domain: "com." })?; let tld_ns = AuthoritativeNameServer::start(Domain("com.")?)?;
let ip_addr = tld_ns.ipv4_addr(); let ip_addr = tld_ns.ipv4_addr();
let client = Container::run()?; let client = Container::run()?;
@ -87,7 +82,7 @@ mod tests {
#[test] #[test]
fn root_setup() -> Result<()> { fn root_setup() -> Result<()> {
let root_ns = AuthoritativeNameServer::start(Domain::Root)?; let root_ns = AuthoritativeNameServer::start(Domain::ROOT)?;
let ip_addr = root_ns.ipv4_addr(); let ip_addr = root_ns.ipv4_addr();
let client = Container::run()?; let client = Container::run()?;

32
src/domain.rs Normal file
View File

@ -0,0 +1,32 @@
use crate::Result;
#[derive(Clone, Copy)]
pub struct Domain<'a> {
inner: &'a str,
}
// TODO likely needs further validation
#[allow(non_snake_case)]
pub fn Domain(input: &str) -> Result<Domain<'_>> {
if !input.ends_with('.') {
return Err("domain must end with a `.`".into());
}
if input != "." && input.starts_with('.') {
return Err("non-root domain cannot start with a `.`".into());
}
Ok(Domain { inner: input })
}
impl<'a> Domain<'a> {
pub const ROOT: Domain<'static> = Domain { inner: "." };
pub fn is_root(&self) -> bool {
self.inner == "."
}
pub fn as_str(&self) -> &'a str {
self.inner
}
}

View File

@ -1,4 +1,5 @@
pub use crate::authoritative_name_server::AuthoritativeNameServer; pub use crate::authoritative_name_server::AuthoritativeNameServer;
pub use crate::domain::Domain;
pub use crate::recursive_resolver::RecursiveResolver; pub use crate::recursive_resolver::RecursiveResolver;
pub type Error = Box<dyn std::error::Error>; pub type Error = Box<dyn std::error::Error>;
@ -8,18 +9,5 @@ const CHMOD_RW_EVERYONE: &str = "666";
mod authoritative_name_server; mod authoritative_name_server;
pub mod container; pub mod container;
mod domain;
mod recursive_resolver; mod recursive_resolver;
pub enum Domain<'a> {
Root,
Tld { domain: &'a str },
}
impl Domain<'_> {
fn fqdn(&self) -> &str {
match self {
Domain::Root => ".",
Domain::Tld { domain } => domain,
}
}
}

View File

@ -52,14 +52,14 @@ impl Drop for RecursiveResolver {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::AuthoritativeNameServer; use crate::{AuthoritativeNameServer, Domain};
use super::*; use super::*;
#[test] #[test]
#[ignore = "FIXME"] #[ignore = "FIXME"]
fn can_resolve() -> Result<()> { fn can_resolve() -> Result<()> {
let root_ns = AuthoritativeNameServer::start(crate::Domain::Root)?; let root_ns = AuthoritativeNameServer::start(Domain::ROOT)?;
let roots = &[RootServer { let roots = &[RootServer {
name: "my.root-server.com".to_string(), name: "my.root-server.com".to_string(),
ip_addr: root_ns.ipv4_addr(), ip_addr: root_ns.ipv4_addr(),