Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aardvark-dns: add support for container's custom dns_servers #240

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions config.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ At least one ip must be given.

All following lines must contain the dns entries in this format:
```
[containerID][space][comma sparated ipv4 list][space][comma separated ipv6 list][space][comma separated dns names]
[containerID][space][comma sparated ipv4 list][space][comma separated ipv6 list][space][comma separated dns names][(optional)[space][comma seperated DNS servers]]
```

Aardvark-dns will reload all config files when receiving a SIGHUB signal.
Expand All @@ -19,7 +19,7 @@ Aardvark-dns will reload all config files when receiving a SIGHUB signal.

```
10.0.0.1,fdfd::1
f35256b5e2f72ec8cb7d974d4f8841686fc8921fdfbc867285b50164e313f715 10.0.0.2 fdfd::2 testmulti1
f35256b5e2f72ec8cb7d974d4f8841686fc8921fdfbc867285b50164e313f715 10.0.0.2 fdfd::2 testmulti1 8.8.8.8,1.1.1.1
e5df0cdbe0136a30cc3e848d495d2cc6dada25b7dedc776b4584ce2cbba6f06f 10.0.0.3 fdfd::3 testmulti2
```

Expand Down
2 changes: 2 additions & 0 deletions contrib/cirrus/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ if [[ $(uname -m) != "x86_64" ]]; then
mv netavark.$(uname -m)-unknown-linux-gnu netavark
fi
chmod a+x /usr/libexec/podman/netavark
# show netavark commit in CI logs
/usr/libexec/podman/netavark version

# Warning, this isn't the end. An exit-handler is installed to finalize
# setup of env. vars. This is required for runner.sh to operate properly.
Expand Down
5 changes: 3 additions & 2 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ pub struct DNSBackend {
pub reverse_mappings: HashMap<String, HashMap<IpAddr, Vec<String>>>,
// Map of IP address to DNS server IPs to service queries not handled
// directly.
// Not implemented in initial version, we will always use host resolvers.
//ctr_dns: HashMap<IpAddr, Vec<IpAddr>>,
pub ctr_dns_server: HashMap<IpAddr, Option<Vec<IpAddr>>>,
}

pub enum DNSResult {
Expand All @@ -42,11 +41,13 @@ impl DNSBackend {
containers: HashMap<IpAddr, Vec<String>>,
networks: HashMap<String, HashMap<String, Vec<IpAddr>>>,
reverse: HashMap<String, HashMap<IpAddr, Vec<String>>>,
ctr_dns_server: HashMap<IpAddr, Option<Vec<IpAddr>>>,
) -> DNSBackend {
DNSBackend {
ip_mappings: containers,
name_mappings: networks,
reverse_mappings: reverse,
ctr_dns_server,
}
}

Expand Down
24 changes: 22 additions & 2 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub fn parse_configs(
let mut network_names: HashMap<String, HashMap<String, Vec<IpAddr>>> = HashMap::new();
let mut listen_ips_4: HashMap<String, Vec<Ipv4Addr>> = HashMap::new();
let mut listen_ips_6: HashMap<String, Vec<Ipv6Addr>> = HashMap::new();
let mut ctr_dns_server: HashMap<IpAddr, Option<Vec<IpAddr>>> = HashMap::new();

// Enumerate all files in the directory, read them in one by one.
// Steadily build a map of what container has what IPs and what
Expand Down Expand Up @@ -115,6 +116,7 @@ pub fn parse_configs(
.entry(IpAddr::V4(ip))
.or_insert_with(Vec::new)
.append(&mut entry.aliases.clone());
ctr_dns_server.insert(IpAddr::V4(ip), entry.dns_servers.clone());
new_ctr_ips.push(IpAddr::V4(ip));
}
}
Expand All @@ -126,6 +128,7 @@ pub fn parse_configs(
.entry(IpAddr::V6(ip))
.or_insert_with(Vec::new)
.append(&mut entry.aliases.clone());
ctr_dns_server.insert(IpAddr::V6(ip), entry.dns_servers.clone());
new_ctr_ips.push(IpAddr::V6(ip));
}
}
Expand Down Expand Up @@ -173,7 +176,7 @@ pub fn parse_configs(
}

Ok((
DNSBackend::new(ctrs, network_names, reverse),
DNSBackend::new(ctrs, network_names, reverse, ctr_dns_server),
listen_ips_4,
listen_ips_6,
))
Expand All @@ -185,6 +188,7 @@ struct CtrEntry {
v4: Option<Vec<Ipv4Addr>>,
v6: Option<Vec<Ipv6Addr>>,
aliases: Vec<String>,
dns_servers: Option<Vec<IpAddr>>,
}

// Read and parse a single given configuration file
Expand Down Expand Up @@ -220,7 +224,7 @@ fn parse_config(path: &std::path::Path) -> Result<(Vec<IpAddr>, Vec<CtrEntry>),

// Split on space
let parts = line.split(' ').collect::<Vec<&str>>();
if parts.len() != 4 {
if parts.len() < 4 {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
Expand Down Expand Up @@ -277,11 +281,27 @@ fn parse_config(path: &std::path::Path) -> Result<(Vec<IpAddr>, Vec<CtrEntry>),
));
}

let dns_servers: Option<Vec<IpAddr>> = if parts.len() == 5 && !parts[4].is_empty() {
let dns_server = match parts[4].split(',').map(|i| i.parse()).collect() {
Ok(i) => i,
Err(e) => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("error parsing DNS server address {}: {}", parts[4], e),
))
}
};
Some(dns_server)
} else {
None
};

ctrs.push(CtrEntry {
id: parts[0].to_string().to_lowercase(),
v4: v4_addrs,
v6: v6_addrs,
aliases,
dns_servers,
});
}

Expand Down
14 changes: 13 additions & 1 deletion src/dns/coredns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::backend::DNSResult;
use futures_util::StreamExt;
use log::{debug, error, trace, warn};
use resolv_conf;
use resolv_conf::ScopedIp;
use std::env;
use std::fs::File;
use std::io::Read;
Expand Down Expand Up @@ -122,6 +123,7 @@ impl CoreDns {
match msg_received {
Ok(msg) => {
let src_address = msg.addr();
let mut dns_resolver = self.resolv_conf.clone();
let sender = sender.clone();
let (name, record_type, mut req) = match parse_dns_msg(msg) {
Some((name, record_type, req)) => (name, record_type, req),
Expand All @@ -131,6 +133,16 @@ impl CoreDns {
}
};
let mut resolved_ip_list: Vec<IpAddr> = Vec::new();
if let Some(Some(dns_servers)) = self.backend.ctr_dns_server.get(&src_address.ip()) {
if !dns_servers.is_empty() {
let mut nameservers_scoped: Vec<ScopedIp> = Vec::new();
for dns_server in dns_servers.iter() {
nameservers_scoped.push(ScopedIp::from(*dns_server));
}
dns_resolver = resolv_conf::Config::new();
dns_resolver.nameservers = nameservers_scoped;
}
}

// Create debug and trace info for key parameters.
trace!("server name: {:?}", self.name.to_ascii());
Expand Down Expand Up @@ -302,7 +314,7 @@ impl CoreDns {
nx_message.set_response_code(ResponseCode::NXDomain);
reply(sender.clone(), src_address, &nx_message);
} else {
let nameservers = self.resolv_conf.nameservers.clone();
let nameservers = dns_resolver.nameservers.clone();
tokio::spawn(async move {
// forward dns request to hosts's /etc/resolv.conf
for nameserver in nameservers {
Expand Down
5 changes: 5 additions & 0 deletions src/test/config/podman_custom_dns_servers/podman
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
10.88.0.1
68fb291b0318b54a71f6f3636e58bd0896f084e5ba4fa311ecf36e019c5e6e43 10.88.0.2 condescendingnash 8.8.8.8
flouthoc marked this conversation as resolved.
Show resolved Hide resolved
68fb291b0318b54a71f6f3636e58bd0896f084e5ba4fa311ecf36e019c5e6e48 10.88.0.5 HelloWorld 3.3.3.3,1.1.1.1,::1
95655fb6832ba134efa66e9c80862a6c9b04f3cc6abf8adfdda8c38112c2c6fa 10.88.0.3 hopefulmontalcini,testdbctr
8bcc5fe0cb09bee5dfb71d61503a87688cfc82aa5f130bcedb19357a17765926 10.88.0.4 trustingzhukovsky,ctr1,ctra
42 changes: 42 additions & 0 deletions src/test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ mod tests {
}
}
#[test]
// Test loading of config file from directory with custom DNS for containers
fn test_loading_config_file_with_dns_servers() {
config::parse_configs("src/test/config/podman_custom_dns_servers").unwrap();
}
#[test]
// Parse config files from stub data
fn test_parsing_config_files() {
match config::parse_configs("src/test/config/podman") {
Expand All @@ -40,6 +45,43 @@ mod tests {
Err(_) => {}
}
}
/* -------------------------------------------- */
// -------Verify backend custom dns server ----
/* -------------------------------------------- */
#[test]
// Backend must populate ctr_dns_servers via custom
// DNS servers for container from the aardvark config
fn test_backend_custom_dns_server() {
match config::parse_configs("src/test/config/podman_custom_dns_servers") {
Ok((backend, _, _)) => {
// Should contain custom DNS server 8.8.8.8
let mut dns_server = backend
.ctr_dns_server
.get(&IpAddr::V4(Ipv4Addr::new(10, 88, 0, 2)));
let mut expected_dns_server = IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8));
assert_eq!(dns_server.unwrap().clone().unwrap()[0], expected_dns_server);

// Should contain custom DNS servers 3.3.3.3 and 1.1.1.1
dns_server = backend
.ctr_dns_server
.get(&IpAddr::V4(Ipv4Addr::new(10, 88, 0, 5)));
expected_dns_server = IpAddr::V4(Ipv4Addr::new(3, 3, 3, 3));
assert_eq!(dns_server.unwrap().clone().unwrap()[0], expected_dns_server);
expected_dns_server = IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1));
assert_eq!(dns_server.unwrap().clone().unwrap()[1], expected_dns_server);
expected_dns_server = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
assert_eq!(dns_server.unwrap().clone().unwrap()[2], expected_dns_server);

// Shoudld not contain any DNS server
dns_server = backend
.ctr_dns_server
.get(&IpAddr::V4(Ipv4Addr::new(10, 88, 0, 3)));
assert_eq!(dns_server.unwrap().clone(), None);
}
Err(e) => panic!("{}", e),
}
}

/* -------------------------------------------- */
// -------Test aardvark-dns lookup logic ------
/* -------------------------------------------- */
Expand Down
64 changes: 57 additions & 7 deletions test/100-basic-name-resolution.bats
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,61 @@

load helpers

@test "basic container - dns itself" {
# custom DNS server is set to `10.10.10.10` which is invalid DNS server
# hence all the external request must fail, this test is expected to fail
# with exit code 124
@test "basic container - dns itself (custom bad dns server)" {
setup_slirp4netns

subnet_a=$(random_subnet 5)
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "a1" "1a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a" custom_dns_server='"10.10.10.10"' aliases='"a1", "1a"'
config_a1=$config
ip_a1=$(echo "$config_a1" | jq -r .networks.podman1.static_ips[0])
gw=$(echo "$config_a1" | jq -r .network_info.podman1.subnets[0].gateway)
create_container "$config_a1"
a1_pid=$CONTAINER_NS_PID
run_in_container_netns "$a1_pid" "dig" "+short" "aone" "@$gw"
assert "$ip_a1"
# Set recursion bit is already set if requested so output must not
# contain unexpected warning.
assert "$output" !~ "WARNING: recursion requested but not available"

# custom dns server is set to 3.3.3.3 which is not a valid DNS server so external DNS request must fail
expected_rc=124 run_in_container_netns "$a1_pid" "dig" "+short" "google.com" "@$gw"
}

# custom DNS server is set to `8.8.8.8, 1.1.1.1` which is valid DNS server
# hence all the external request must paas.
@test "basic container - dns itself (custom good dns server)" {
setup_slirp4netns

subnet_a=$(random_subnet 5)
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a" custom_dns_server='"8.8.8.8","1.1.1.1"' aliases='"a1", "1a"'

config_a1=$config
ip_a1=$(echo "$config_a1" | jq -r .networks.podman1.static_ips[0])
gw=$(echo "$config_a1" | jq -r .network_info.podman1.subnets[0].gateway)
create_container "$config_a1"
a1_pid=$CONTAINER_NS_PID
run_in_container_netns "$a1_pid" "dig" "+short" "aone" "@$gw"
assert "$ip_a1"
# Set recursion bit is already set if requested so output must not
# contain unexpected warning.
assert "$output" !~ "WARNING: recursion requested but not available"

run_in_container_netns "$a1_pid" "dig" "+short" "google.com" "@$gw"
# validate that we get an ipv4
assert "$output" =~ "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"
# Set recursion bit is already set if requested so output must not
# contain unexpected warning.
assert "$output" !~ "WARNING: recursion requested but not available"
}

@test "basic container - dns itself custom" {
setup_slirp4netns

subnet_a=$(random_subnet 5)
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a" aliases='"a1", "1a"'
config_a1=$config
ip_a1=$(echo "$config_a1" | jq -r .networks.podman1.static_ips[0])
gw=$(echo "$config_a1" | jq -r .network_info.podman1.subnets[0].gateway)
Expand All @@ -33,7 +83,7 @@ load helpers
setup_slirp4netns

subnet_a=$(random_subnet 5)
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "a1" "1a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a" aliases='"a1", "1a"'
config_a1=$config
ip_a1=$(echo "$config_a1" | jq -r .networks.podman1.static_ips[0])
gw=$(echo "$config_a1" | jq -r .network_info.podman1.subnets[0].gateway)
Expand All @@ -47,7 +97,7 @@ load helpers
setup_slirp4netns

subnet_a=$(random_subnet 6)
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "a1" "1a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a" aliases='"a1", "1a"'
config_a1=$config
ip_a1=$(echo "$config_a1" | jq -r .networks.podman1.static_ips[0])
gw=$(echo "$config_a1" | jq -r .network_info.podman1.subnets[0].gateway)
Expand All @@ -74,7 +124,7 @@ load helpers
@test "basic container - dns itself with long network name" {
subnet_a=$(random_subnet 5)
long_name="podman11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
create_config "$long_name" $(random_string 64) "aone" "$subnet_a" "a1" "1a"
create_config network_name="$long_name" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a" aliases='"a1", "1a"'
config_a1=$config
ip_a1=$(echo "$config_a1" | jq -r .networks.$long_name.static_ips[0])
gw=$(echo "$config_a1" | jq -r .network_info.$long_name.subnets[0].gateway)
Expand All @@ -90,15 +140,15 @@ load helpers
@test "two containers on the same network" {
# container a1
subnet_a=$(random_subnet 5)
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "a1" "1a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a" aliases='"a1", "1a"'
config_a1="$config"
a1_ip=$(echo "$config_a1" | jq -r .networks.podman1.static_ips[0])
gw=$(echo "$config_a1" | jq -r .network_info.podman1.subnets[0].gateway)
create_container "$config_a1"
a1_pid=$CONTAINER_NS_PID

# container a2
create_config "podman1" $(random_string 64) "atwo" "$subnet_a" "a2" "2a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="atwo" subnet="$subnet_a" aliases='"a2", "2a"'
config_a2="$config"
a2_ip=$(echo "$config_a2" | jq -r .networks.podman1.static_ips[0])
create_container "$config_a2"
Expand Down
10 changes: 5 additions & 5 deletions test/200-two-networks.bats
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ load helpers

# container a1 on subnet a
subnet_a=$(random_subnet 5)
create_config "podman1" $(random_string 64) "aone" "$subnet_a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a"
a1_config="$config"
a1_ip=$(echo "$a1_config" | jq -r .networks.podman1.static_ips[0])
a_gw=$(echo "$a1_config" | jq -r .network_info.podman1.subnets[0].gateway)
Expand All @@ -19,7 +19,7 @@ load helpers

# container b1 on subnet b
subnet_b=$(random_subnet 5)
create_config "podman2" $(random_string 64) "bone" "$subnet_b"
create_config network_name="podman2" container_id=$(random_string 64) container_name="bone" subnet="$subnet_b"
b1_config="$config"
b1_ip=$(echo "$b1_config" | jq -r .networks.podman2.static_ips[0])
b_gw=$(echo "$b1_config" | jq -r .network_info.podman2.subnets[0].gateway)
Expand Down Expand Up @@ -56,7 +56,7 @@ load helpers
subnet_b=$(random_subnet 5)

# A1
create_config "podman1" $(random_string 64) "aone" "$subnet_a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="aone" subnet="$subnet_a"
a1_config=$config
a1_container_id=$(echo "$a1_config" | jq -r .container_id)
a1_ip=$(echo "$a1_config" | jq -r .networks.podman1.static_ips[0])
Expand All @@ -66,7 +66,7 @@ load helpers
a1_pid=$CONTAINER_NS_PID

# container b1 on subnet b
create_config "podman2" $(random_string 64) "bone" "$subnet_b"
create_config network_name="podman2" container_id=$(random_string 64) container_name="bone" subnet="$subnet_b"
b1_config=$config
b1_ip=$(echo "$b1_config" | jq -r .networks.podman2.static_ips[0])
b_gw=$(echo "$b1_config" | jq -r .network_info.podman2.subnets[0].gateway)
Expand All @@ -76,7 +76,7 @@ load helpers
b_subnets=$(echo $b1_config | jq -r .network_info.podman2.subnets[0])

# AB2
create_config "podman1" $(random_string 64) "abtwo" "$subnet_a"
create_config network_name="podman1" container_id=$(random_string 64) container_name="abtwo" subnet="$subnet_a"
a2_config=$config
a2_ip=$(echo "$a2_config" | jq -r .networks.podman1.static_ips[0])

Expand Down
Loading