Pass in Network to containers

This commit is contained in:
Sebastian Ziebell 2024-02-13 11:25:52 +01:00
parent 5630dd79e9
commit 820f1c3447
No known key found for this signature in database
GPG Key ID: 7CFCF2A8E3AE3A09
8 changed files with 79 additions and 52 deletions

View File

@ -4,17 +4,18 @@ use dns_test::client::{Client, Dnssec, Recurse};
use dns_test::name_server::NameServer;
use dns_test::record::RecordType;
use dns_test::zone_file::Root;
use dns_test::{Resolver, Result, TrustAnchor, FQDN};
use dns_test::{Network, Resolver, Result, TrustAnchor, FQDN};
#[test]
fn can_resolve() -> Result<()> {
let expected_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4);
let needle_fqdn = FQDN("example.nameservers.com.")?;
let mut root_ns = NameServer::new(FQDN::ROOT)?;
let mut com_ns = NameServer::new(FQDN::COM)?;
let network = Network::new()?;
let mut root_ns = NameServer::new(FQDN::ROOT, &network)?;
let mut com_ns = NameServer::new(FQDN::COM, &network)?;
let mut nameservers_ns = NameServer::new(FQDN("nameservers.com.")?)?;
let mut nameservers_ns = NameServer::new(FQDN("nameservers.com.")?, &network)?;
nameservers_ns
.a(root_ns.fqdn().clone(), root_ns.ipv4_addr())
.a(com_ns.fqdn().clone(), com_ns.ipv4_addr())
@ -38,10 +39,10 @@ fn can_resolve() -> Result<()> {
eprintln!("root.zone:\n{}", root_ns.zone_file());
let roots = &[Root::new(root_ns.fqdn().clone(), root_ns.ipv4_addr())];
let resolver = Resolver::start(dns_test::subject(), roots, &TrustAnchor::empty())?;
let resolver = Resolver::start(dns_test::subject(), roots, &TrustAnchor::empty(), &network)?;
let resolver_ip_addr = resolver.ipv4_addr();
let client = Client::new()?;
let client = Client::new(&network)?;
let output = client.dig(
Recurse::Yes,
Dnssec::No,
@ -66,10 +67,11 @@ fn can_resolve() -> Result<()> {
fn nxdomain() -> Result<()> {
let needle_fqdn = FQDN("unicorn.nameservers.com.")?;
let mut root_ns = NameServer::new(FQDN::ROOT)?;
let mut com_ns = NameServer::new(FQDN::COM)?;
let network = Network::new()?;
let mut root_ns = NameServer::new(FQDN::ROOT, &network)?;
let mut com_ns = NameServer::new(FQDN::COM, &network)?;
let mut nameservers_ns = NameServer::new(FQDN("nameservers.com.")?)?;
let mut nameservers_ns = NameServer::new(FQDN("nameservers.com.")?, &network)?;
nameservers_ns
.a(root_ns.fqdn().clone(), root_ns.ipv4_addr())
.a(com_ns.fqdn().clone(), com_ns.ipv4_addr());
@ -86,10 +88,10 @@ fn nxdomain() -> Result<()> {
let root_ns = root_ns.start()?;
let roots = &[Root::new(root_ns.fqdn().clone(), root_ns.ipv4_addr())];
let resolver = Resolver::start(dns_test::subject(), roots, &TrustAnchor::empty())?;
let resolver = Resolver::start(dns_test::subject(), roots, &TrustAnchor::empty(), &network)?;
let resolver_ip_addr = resolver.ipv4_addr();
let client = Client::new()?;
let client = Client::new(&network)?;
let output = client.dig(
Recurse::Yes,
Dnssec::No,

View File

@ -4,13 +4,14 @@ use dns_test::client::{Client, Dnssec, Recurse};
use dns_test::name_server::NameServer;
use dns_test::record::RecordType;
use dns_test::zone_file::Root;
use dns_test::{Resolver, Result, TrustAnchor, FQDN};
use dns_test::{Network, Resolver, Result, TrustAnchor, FQDN};
// no DS records are involved; this is a single-link chain of trust
#[ignore]
#[test]
fn can_validate_without_delegation() -> Result<()> {
let mut ns = NameServer::new(FQDN::ROOT)?;
let network = Network::new()?;
let mut ns = NameServer::new(FQDN::ROOT, &network)?;
ns.a(ns.fqdn().clone(), ns.ipv4_addr());
let ns = ns.sign()?;
@ -26,10 +27,10 @@ fn can_validate_without_delegation() -> Result<()> {
let roots = &[Root::new(ns.fqdn().clone(), ns.ipv4_addr())];
let trust_anchor = TrustAnchor::from_iter([root_ksk.clone(), root_zsk.clone()]);
let resolver = Resolver::start(dns_test::subject(), roots, &trust_anchor)?;
let resolver = Resolver::start(dns_test::subject(), roots, &trust_anchor, &network)?;
let resolver_addr = resolver.ipv4_addr();
let client = Client::new()?;
let client = Client::new(&network)?;
let output = client.dig(
Recurse::Yes,
Dnssec::Yes,
@ -53,10 +54,11 @@ fn can_validate_with_delegation() -> Result<()> {
let expected_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4);
let needle_fqdn = FQDN("example.nameservers.com.")?;
let mut root_ns = NameServer::new(FQDN::ROOT)?;
let mut com_ns = NameServer::new(FQDN::COM)?;
let network = Network::new()?;
let mut root_ns = NameServer::new(FQDN::ROOT, &network)?;
let mut com_ns = NameServer::new(FQDN::COM, &network)?;
let mut nameservers_ns = NameServer::new(FQDN("nameservers.com.")?)?;
let mut nameservers_ns = NameServer::new(FQDN("nameservers.com.")?, &network)?;
nameservers_ns
.a(root_ns.fqdn().clone(), root_ns.ipv4_addr())
.a(com_ns.fqdn().clone(), com_ns.ipv4_addr())
@ -96,10 +98,10 @@ fn can_validate_with_delegation() -> Result<()> {
let roots = &[Root::new(root_ns.fqdn().clone(), root_ns.ipv4_addr())];
let trust_anchor = TrustAnchor::from_iter([root_ksk.clone(), root_zsk.clone()]);
let resolver = Resolver::start(dns_test::subject(), roots, &trust_anchor)?;
let resolver = Resolver::start(dns_test::subject(), roots, &trust_anchor, &network)?;
let resolver_addr = resolver.ipv4_addr();
let client = Client::new()?;
let client = Client::new(&network)?;
let output = client.dig(
Recurse::Yes,
Dnssec::Yes,

View File

@ -1,7 +1,7 @@
use core::str::FromStr;
use std::net::Ipv4Addr;
use crate::container::Container;
use crate::container::{Container, Network};
use crate::record::{Record, RecordType};
use crate::trust_anchor::TrustAnchor;
use crate::{Error, Implementation, Result, FQDN};
@ -11,9 +11,9 @@ pub struct Client {
}
impl Client {
pub fn new() -> Result<Self> {
pub fn new(network: &Network) -> Result<Self> {
Ok(Self {
inner: Container::run(Implementation::Unbound)?,
inner: Container::run(Implementation::Unbound, network)?,
})
}

View File

@ -12,6 +12,8 @@ use tempfile::{NamedTempFile, TempDir};
use crate::{Error, Implementation, Result};
pub use crate::container::network::Network;
pub struct Container {
inner: Arc<Inner>,
}
@ -20,7 +22,7 @@ const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
impl Container {
/// Starts the container in a "parked" state
pub fn run(implementation: Implementation) -> Result<Self> {
pub fn run(implementation: Implementation, network: &Network) -> Result<Self> {
// TODO make this configurable and support hickory & bind
let dockerfile = implementation.dockerfile();
let docker_build_dir = TempDir::new()?;
@ -269,7 +271,8 @@ mod tests {
#[test]
fn run_works() -> Result<()> {
let container = Container::run(Implementation::Unbound)?;
let network = Network::new()?;
let container = Container::run(Implementation::Unbound, &network)?;
let output = container.output(&["true"])?;
assert!(output.status.success());
@ -279,7 +282,8 @@ mod tests {
#[test]
fn ipv4_addr_works() -> Result<()> {
let container = Container::run(Implementation::Unbound)?;
let network = Network::new()?;
let container = Container::run(Implementation::Unbound, &network)?;
let ipv4_addr = container.ipv4_addr();
let output = container.output(&["ping", "-c1", &format!("{ipv4_addr}")])?;
@ -290,7 +294,8 @@ mod tests {
#[test]
fn cp_works() -> Result<()> {
let container = Container::run(Implementation::Unbound)?;
let network = Network::new()?;
let container = Container::run(Implementation::Unbound, &network)?;
let path = "/tmp/somefile";
let contents = "hello";

View File

@ -1,5 +1,5 @@
use std::{
process::{Command, Stdio},
process::{Command, ExitStatus, Stdio},
sync::atomic::{self, AtomicUsize},
};
@ -10,6 +10,7 @@ const NETWORK_NAME: &str = "dnssec-network";
/// Represents a network in which to put containers into.
pub struct Network {
name: String,
config: NetworkConfig,
}
impl Network {
@ -17,6 +18,9 @@ impl Network {
let id = network_count();
let network_name = format!("{NETWORK_NAME}-{id}");
// A network can exist, for example when a test panics
let _ = remove_network(network_name.as_str())?;
let mut command = Command::new("docker");
command
.args(["network", "create"])
@ -33,8 +37,12 @@ impl Network {
);
// inspect & parse network details
let config = get_network_config(&network_name)?;
Ok(Self { name: network_name })
Ok(Self {
name: network_name,
config,
})
}
/// Returns the name of the network.
@ -49,7 +57,7 @@ pub struct NetworkConfig {
subnet: String,
}
///
/// Return network config
fn get_network_config(network_name: &str) -> Result<NetworkConfig> {
let mut command = Command::new("docker");
command
@ -70,19 +78,22 @@ fn get_network_config(network_name: &str) -> Result<NetworkConfig> {
Ok(NetworkConfig { subnet })
}
/// This ensure the Docket network is deleted after the test runner process ends.
/// This ensure the Docker network is deleted after the test runner process ends.
impl Drop for Network {
fn drop(&mut self) {
// Remove the network
// TODO check if all containers need to disconnect first
let _ = Command::new("docker")
.args(["network", "rm", "--force", self.name.as_str()])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
let _ = remove_network(&self.name);
}
}
fn remove_network(network_name: &str) -> Result<ExitStatus> {
let mut command = Command::new("docker");
command
.args(["network", "rm", "--force", network_name])
.stdout(Stdio::null())
.stderr(Stdio::null());
Ok(command.status()?)
}
fn network_count() -> usize {
static COUNT: AtomicUsize = AtomicUsize::new(1);

View File

@ -3,6 +3,7 @@
use core::fmt;
use std::sync::Once;
pub use crate::container::Network;
pub use crate::fqdn::FQDN;
pub use crate::resolver::Resolver;
pub use crate::trust_anchor::TrustAnchor;

View File

@ -1,7 +1,7 @@
use core::sync::atomic::{self, AtomicUsize};
use std::net::Ipv4Addr;
use crate::container::{Child, Container};
use crate::container::{Child, Container, Network};
use crate::zone_file::{self, SoaSettings, ZoneFile, DNSKEY, DS};
use crate::{Implementation, Result, FQDN};
@ -24,7 +24,7 @@ impl<'a> NameServer<'a, Stopped> {
/// - one SOA record, with the primary name server field set to this name server's FQDN
/// - one NS record, with this name server's FQDN set as the only available name server for
/// the zone
pub fn new(zone: FQDN<'a>) -> Result<Self> {
pub fn new(zone: FQDN<'a>, network: &Network) -> Result<Self> {
let ns_count = ns_count();
let nameserver = primary_ns(ns_count);
@ -42,7 +42,7 @@ impl<'a> NameServer<'a, Stopped> {
});
Ok(Self {
container: Container::run(Implementation::Unbound)?,
container: Container::run(Implementation::Unbound, network)?,
zone_file,
state: Stopped,
})
@ -290,10 +290,11 @@ mod tests {
#[test]
fn simplest() -> Result<()> {
let tld_ns = NameServer::new(FQDN::COM)?.start()?;
let network = Network::new()?;
let tld_ns = NameServer::new(FQDN::COM, &network)?.start()?;
let ip_addr = tld_ns.ipv4_addr();
let client = Client::new()?;
let client = Client::new(&network)?;
let output = client.dig(
Recurse::No,
Dnssec::No,
@ -309,8 +310,9 @@ mod tests {
#[test]
fn with_referral() -> Result<()> {
let network = Network::new()?;
let expected_ip_addr = Ipv4Addr::new(172, 17, 200, 1);
let mut root_ns = NameServer::new(FQDN::ROOT)?;
let mut root_ns = NameServer::new(FQDN::ROOT, &network)?;
root_ns.referral(
FQDN::COM,
FQDN("primary.tld-server.com.")?,
@ -322,7 +324,7 @@ mod tests {
let ipv4_addr = root_ns.ipv4_addr();
let client = Client::new()?;
let client = Client::new(&network)?;
let output = client.dig(
Recurse::No,
Dnssec::No,
@ -338,7 +340,8 @@ mod tests {
#[test]
fn signed() -> Result<()> {
let ns = NameServer::new(FQDN::ROOT)?.sign()?;
let network = Network::new()?;
let ns = NameServer::new(FQDN::ROOT, &network)?.sign()?;
eprintln!("KSK:\n{}", ns.key_signing_key());
eprintln!("ZSK:\n{}", ns.zone_signing_key());
@ -348,7 +351,7 @@ mod tests {
let ns_addr = tld_ns.ipv4_addr();
let client = Client::new()?;
let client = Client::new(&network)?;
let output = client.dig(
Recurse::No,
Dnssec::Yes,
@ -373,7 +376,8 @@ mod tests {
#[test]
fn terminate_works() -> Result<()> {
let ns = NameServer::new(FQDN::ROOT)?.start()?;
let network = Network::new()?;
let ns = NameServer::new(FQDN::ROOT, &network)?.start()?;
let logs = ns.terminate()?;
assert!(logs.contains("nsd starting"));

View File

@ -1,7 +1,7 @@
use core::fmt::Write;
use std::net::Ipv4Addr;
use crate::container::{Child, Container};
use crate::container::{Child, Container, Network};
use crate::trust_anchor::TrustAnchor;
use crate::zone_file::Root;
use crate::{Implementation, Result};
@ -23,6 +23,7 @@ impl Resolver {
implementation: Implementation,
roots: &[Root],
trust_anchor: &TrustAnchor,
network: &Network,
) -> Result<Self> {
const TRUST_ANCHOR_FILE: &str = "/etc/trusted-key.key";
@ -31,7 +32,7 @@ impl Resolver {
"must configure at least one local root server"
);
let container = Container::run(implementation)?;
let container = Container::run(implementation, network)?;
let mut hints = String::new();
for root in roots {
@ -110,12 +111,13 @@ mod tests {
#[test]
fn terminate_works() -> Result<()> {
let ns = NameServer::new(FQDN::ROOT)?.start()?;
let network = Network::new()?;
let ns = NameServer::new(FQDN::ROOT, &network)?.start()?;
let resolver = Resolver::start(
Implementation::Unbound,
&[Root::new(ns.fqdn().clone(), ns.ipv4_addr())],
&TrustAnchor::empty(),
&network,
)?;
let logs = resolver.terminate()?;