use Ipv4Addr type for IP addresses

This commit is contained in:
Jorge Aparicio 2024-02-05 14:42:20 +01:00
parent d79581bdcc
commit c7e0580c7a
3 changed files with 56 additions and 46 deletions

View File

@ -1,4 +1,4 @@
use std::process::Child;
use std::{net::Ipv4Addr, process::Child};
use minijinja::{context, Environment};
@ -34,8 +34,8 @@ impl AuthoritativeNameServer {
Ok(Self { child, container })
}
pub fn ip_addr(&self) -> Result<String> {
self.container.ip_addr()
pub fn ipv4_addr(&self) -> Ipv4Addr {
self.container.ipv4_addr()
}
}
@ -84,7 +84,7 @@ mod tests {
#[test]
fn tld_setup() -> Result<()> {
let tld_ns = AuthoritativeNameServer::start(Domain::Tld { domain: "com." })?;
let ip_addr = tld_ns.ip_addr()?;
let ip_addr = tld_ns.ipv4_addr();
let client = Container::run()?;
let output = client.exec(&["dig", &format!("@{ip_addr}"), "SOA", "com."])?;
@ -100,7 +100,7 @@ mod tests {
#[test]
fn root_setup() -> Result<()> {
let root_ns = AuthoritativeNameServer::start(Domain::Root)?;
let ip_addr = root_ns.ip_addr()?;
let ip_addr = root_ns.ipv4_addr();
let client = Container::run()?;
let output = client.exec(&["dig", &format!("@{ip_addr}"), "SOA", "."])?;

View File

@ -1,4 +1,6 @@
use core::str;
use std::fs;
use std::net::Ipv4Addr;
use std::path::Path;
use std::process::{self, Child, Output};
use std::process::{Command, Stdio};
@ -10,8 +12,10 @@ use tempfile::NamedTempFile;
use crate::Result;
pub struct Container {
id: String,
_name: String,
id: String,
// TODO probably also want the IPv6 address
ipv4_addr: Ipv4Addr,
}
impl Container {
@ -61,15 +65,16 @@ impl Container {
return Err(format!("`{command:?}` failed").into());
}
let id = core::str::from_utf8(&output.stdout)?.trim().to_string();
let id = str::from_utf8(&output.stdout)?.trim().to_string();
dbg!(&id);
let container = Self {
let ipv4_addr = get_ipv4_addr(&id)?;
Ok(Self {
id,
_name: container_name,
};
dbg!(container.ip_addr()?);
Ok(container)
ipv4_addr,
})
}
pub fn cp(&self, path_in_container: &str, file_contents: &str, chmod: &str) -> Result<()> {
@ -114,29 +119,33 @@ impl Container {
Ok(child)
}
// TODO cache this to avoid calling `docker inspect` every time
pub fn ip_addr(&self) -> Result<String> {
let mut command = Command::new("docker");
command
.args([
"inspect",
"-f",
"{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}",
])
.arg(&self.id);
let output = command.output()?;
if !output.status.success() {
return Err(format!("`{command:?}` failed").into());
}
let ip_addr = core::str::from_utf8(&output.stdout)?.trim().to_string();
dbg!(&ip_addr);
Ok(ip_addr)
pub fn ipv4_addr(&self) -> Ipv4Addr {
self.ipv4_addr
}
}
// TODO cache this to avoid calling `docker inspect` every time
fn get_ipv4_addr(container_id: &str) -> Result<Ipv4Addr> {
let mut command = Command::new("docker");
command
.args([
"inspect",
"-f",
"{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}",
])
.arg(container_id);
let output = command.output()?;
if !output.status.success() {
return Err(format!("`{command:?}` failed").into());
}
let ipv4_addr = str::from_utf8(&output.stdout)?.trim().to_string();
dbg!(&ipv4_addr);
Ok(ipv4_addr.parse()?)
}
// ensure the container gets deleted
impl Drop for Container {
fn drop(&mut self) {
@ -152,8 +161,6 @@ impl Drop for Container {
#[cfg(test)]
mod tests {
use std::net::Ipv4Addr;
use crate::CHMOD_RW_EVERYONE;
use super::*;
@ -169,11 +176,12 @@ mod tests {
}
#[test]
fn ip_addr_works() -> Result<()> {
fn ipv4_addr_works() -> Result<()> {
let container = Container::run()?;
let ipv4_addr = container.ipv4_addr();
let ip_addr = container.ip_addr()?;
assert!(ip_addr.parse::<Ipv4Addr>().is_ok());
let output = container.exec(&["ping", "-c1", &format!("{ipv4_addr}")])?;
assert!(output.status.success());
Ok(())
}

View File

@ -1,3 +1,4 @@
use std::net::Ipv4Addr;
use std::process::Child;
use serde::Serialize;
@ -13,7 +14,7 @@ pub struct RecursiveResolver {
#[derive(Serialize)]
pub struct RootServer {
name: String,
ip_addr: String,
ip_addr: Ipv4Addr,
}
fn root_hints(roots: &[RootServer]) -> String {
@ -38,8 +39,8 @@ impl RecursiveResolver {
Ok(Self { child, container })
}
pub fn ip_addr(&self) -> Result<String> {
self.container.ip_addr()
pub fn ipv4_addr(&self) -> Ipv4Addr {
self.container.ipv4_addr()
}
}
@ -56,14 +57,15 @@ mod tests {
use super::*;
#[test]
#[ignore = "FIXME"]
fn can_resolve() -> Result<()> {
let root_ns = AuthoritativeNameServer::start(crate::Domain::Root)?;
let roots = &[RootServer {
name: "my.root-server.com".to_string(),
ip_addr: root_ns.ip_addr()?,
ip_addr: root_ns.ipv4_addr(),
}];
let resolver = RecursiveResolver::start(roots)?;
let resolver_ip_addr = resolver.ip_addr()?;
let resolver_ip_addr = resolver.ipv4_addr();
let container = Container::run()?;
let output = container.exec(&["dig", &format!("@{}", resolver_ip_addr), "example.com"])?;
@ -77,15 +79,15 @@ mod tests {
#[test]
fn root_hints_template_works() {
let expected = [
("a.root-server.com", "172.17.0.1"),
("b.root-server.com", "172.17.0.2"),
("a.root-server.com", Ipv4Addr::new(172, 17, 0, 1)),
("b.root-server.com", Ipv4Addr::new(172, 17, 0, 2)),
];
let roots = expected
.iter()
.map(|(ns_name, ip_addr)| RootServer {
name: ns_name.to_string(),
ip_addr: ip_addr.to_string(),
ip_addr: *ip_addr,
})
.collect::<Vec<_>>();
@ -117,7 +119,7 @@ mod tests {
.unwrap();
assert_eq!(expected_ns_name, ns_name);
assert_eq!("A", record_type);
assert_eq!(expected_ip_addr, ip_addr);
assert_eq!(expected_ip_addr.to_string(), ip_addr);
}
}
}