From 89ecfe3db62b254d6a25eb79637cbb222ae40044 Mon Sep 17 00:00:00 2001 From: Aditya R Date: Mon, 17 Oct 2022 14:03:06 +0530 Subject: [PATCH] netavark ,aardvark: accept and populate custom dns_servers for containers Netavark now accepts `dns_servers` as part of `NetworkOptions` which contains list of comma seperated custom DNS servers for containers. Aardvark-dns will use these as resolver for a specific container instead of host's default resolver. Implements feature here: https://github.com/containers/aardvark-dns/pull/240 Signed-off-by: Aditya R --- src/commands/setup.rs | 2 +- src/commands/teardown.rs | 1 + src/dns/aardvark.rs | 17 ++++++++- src/network/bridge.rs | 8 ++++ src/network/driver.rs | 3 ++ src/network/types.rs | 4 ++ test/100-bridge-iptables.bats | 33 ++++++++++++++++ .../dualstack-bridge-custom-dns-server.json | 38 +++++++++++++++++++ 8 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 test/testfiles/dualstack-bridge-custom-dns-server.json diff --git a/src/commands/setup.rs b/src/commands/setup.rs index 4676e35cc..d8caa35de 100644 --- a/src/commands/setup.rs +++ b/src/commands/setup.rs @@ -42,7 +42,6 @@ impl Setup { } } debug!("{:?}", "Setting up..."); - let network_options = match network::types::NetworkOptions::load(&input_file) { Ok(opts) => opts, Err(e) => { @@ -95,6 +94,7 @@ impl Setup { firewall: firewall_driver.as_ref(), container_id: &network_options.container_id, container_name: &network_options.container_name, + container_dns_servers: &network_options.dns_servers, netns_host: hostns.fd, netns_container: netns.fd, network, diff --git a/src/commands/teardown.rs b/src/commands/teardown.rs index 737d16325..9884aff8f 100644 --- a/src/commands/teardown.rs +++ b/src/commands/teardown.rs @@ -91,6 +91,7 @@ impl Teardown { firewall: firewall_driver.as_ref(), container_id: &network_options.container_id, container_name: &network_options.container_name, + container_dns_servers: &network_options.dns_servers, netns_host: hostns.fd, netns_container: netns.fd, network, diff --git a/src/dns/aardvark.rs b/src/dns/aardvark.rs index 8466a2e66..9e7bfb789 100644 --- a/src/dns/aardvark.rs +++ b/src/dns/aardvark.rs @@ -24,6 +24,7 @@ pub struct AardvarkEntry<'a> { pub container_ips_v4: Vec, pub container_ips_v6: Vec, pub container_names: Vec, + pub container_dns_servers: &'a Option>, } #[derive(Debug, Clone)] @@ -249,9 +250,21 @@ impl Aardvark { .collect::>() .join(","); + let mut dns_server: String = "".to_string(); + + if let Some(dns_servers) = &entry.container_dns_servers { + if !dns_servers.is_empty() { + let dns_server_collected = dns_servers + .iter() + .map(|g| g.to_string()) + .collect::>() + .join(","); + dns_server = format!(" {}", dns_server_collected); + } + } let data = format!( - "{} {} {} {}\n", - entry.container_id, ipv4s, ipv6s, container_names + "{} {} {} {}{}\n", + entry.container_id, ipv4s, ipv6s, container_names, dns_server ); file.write_all(data.as_bytes())?; // return error if write fails diff --git a/src/network/bridge.rs b/src/network/bridge.rs index b966c36e3..247ca36a3 100644 --- a/src/network/bridge.rs +++ b/src/network/bridge.rs @@ -181,8 +181,16 @@ impl driver::NetworkDriver for Bridge<'_> { container_ips_v4: ipv4, container_ips_v6: ipv6, container_names: names, + container_dns_servers: self.info.container_dns_servers, }) } else { + // If --dns-enable=false and --dns was set then return following DNS servers + // in status_block so podman can use these and populate resolv.conf + if let Some(container_dns_servers) = self.info.container_dns_servers { + let _ = response + .dns_server_ips + .insert(container_dns_servers.clone()); + } None }; diff --git a/src/network/driver.rs b/src/network/driver.rs index d719390a2..81bf2ed81 100644 --- a/src/network/driver.rs +++ b/src/network/driver.rs @@ -4,6 +4,8 @@ use crate::{ firewall::FirewallDriver, }; +use std::net::IpAddr; + use super::{ bridge::Bridge, constants, @@ -17,6 +19,7 @@ pub struct DriverInfo<'a> { pub firewall: &'a dyn FirewallDriver, pub container_id: &'a String, pub container_name: &'a String, + pub container_dns_servers: &'a Option>, pub netns_host: RawFd, pub netns_container: RawFd, pub network: &'a Network, diff --git a/src/network/types.rs b/src/network/types.rs index 8c681f0f9..e97a9f497 100644 --- a/src/network/types.rs +++ b/src/network/types.rs @@ -77,6 +77,10 @@ pub struct NetworkOptions { /// The port mappings for this container. #[serde(rename = "port_mappings")] pub port_mappings: Option>, + + /// Custom DNS servers for aardvark-dns. + #[serde(rename = "dns_servers")] + pub dns_servers: Option>, } // PerNetworkOptions are options which should be set on a per network basis diff --git a/test/100-bridge-iptables.bats b/test/100-bridge-iptables.bats index a294b5d6f..d4483ec3d 100644 --- a/test/100-bridge-iptables.bats +++ b/test/100-bridge-iptables.bats @@ -148,6 +148,39 @@ fw_driver=iptables run_netavark --file ${TESTSDIR}/testfiles/ipv6-bridge.json teardown $(get_container_netns_path) } +@test "$fw_driver - bridge driver must generate config for aardvark with custom dns server" { + # TODO !!! Unkip after https://github.com/containers/aardvark-dns/pull/240 + skip "unskip after https://github.com/containers/aardvark-dns/pull/240" + # get a random port directly to avoid low ports e.g. 53 would not create iptables + dns_port=$((RANDOM+10000)) + + # hack to make aardvark-dns run when really root or when running as user with + # podman unshare --rootless-netns; since netavark runs aardvark with systemd-run + # it needs to know if it should use systemd user instance or not. + # iptables are still setup identically. + rootless=false + if [[ ! -e "/run/dbus/system_bus_socket" ]]; then + rootless=true + fi + + mkdir -p "$NETAVARK_TMPDIR/config" + + NETAVARK_DNS_PORT="$dns_port" run_netavark --file ${TESTSDIR}/testfiles/dualstack-bridge-custom-dns-server.json \ + --rootless "$rootless" --config "$NETAVARK_TMPDIR/config" \ + setup $(get_container_netns_path) + + # check aardvark config and running + run_helper cat "$NETAVARK_TMPDIR/config/aardvark-dns/podman1" + assert "${lines[0]}" =~ "10.89.3.1,fd10:88:a::1" "aardvark set to listen to all IPs" + assert "${lines[1]}" =~ "^[0-9a-f]{64} 10.89.3.2 fd10:88:a::2 somename 8.8.8.8$" "aardvark config's container" + assert "${#lines[@]}" = 2 "too many lines in aardvark config" + + aardvark_pid=$(cat "$NETAVARK_TMPDIR/config/aardvark-dns/aardvark.pid") + assert "$ardvark_pid" =~ "[0-9]*" "aardvark pid not found" + run_helper ps "$aardvark_pid" + assert "${lines[1]}" =~ ".*aardvark-dns --config $NETAVARK_TMPDIR/config/aardvark-dns -p $dns_port run" "aardvark not running or bad options" +} + @test "$fw_driver - dual stack dns with alt port" { # get a random port directly to avoid low ports e.g. 53 would not create iptables dns_port=$((RANDOM+10000)) diff --git a/test/testfiles/dualstack-bridge-custom-dns-server.json b/test/testfiles/dualstack-bridge-custom-dns-server.json new file mode 100644 index 000000000..19f31f11a --- /dev/null +++ b/test/testfiles/dualstack-bridge-custom-dns-server.json @@ -0,0 +1,38 @@ +{ + "container_id": "f031bf33eecba75d0d84952337b1ceef6a239eb8e94b48aee0993d0791345325", + "container_name": "somename", + "dns_servers": ["8.8.8.8"], + "networks": { + "podman1": { + "static_ips": [ + "10.89.3.2", + "fd10:88:a::2" + ], + "interface_name": "eth0" + } + }, + "network_info": { + "podman1": { + "name": "podman1", + "id": "ec79dd0cad82083c8ac5cc23e9542e4ddea813dff60d68258d36e84f6393b63b", + "driver": "bridge", + "network_interface": "podman1", + "subnets": [ + { + "subnet": "10.89.3.0/24", + "gateway": "10.89.3.1" + }, + { + "subnet": "fd10:88:a::/64", + "gateway": "fd10:88:a::1" + } + ], + "ipv6_enabled": true, + "internal": false, + "dns_enabled": true, + "ipam_options": { + "driver": "host-local" + } + } + } +}