Skip to content

Commit

Permalink
aardvark-dns: add support for container's custom dns_servers
Browse files Browse the repository at this point in the history
Aardvark-dns's config now allows containers to define a list of one of
more custom DNS servers. If custom DNS servers are specified for a
container aardvark-dns will use these custom DNS servers are resolvers
instead of host's default resolvers.

Signed-off-by: Aditya R <[email protected]>
  • Loading branch information
flouthoc committed Oct 17, 2022
1 parent 6b9f3f3 commit 89571c7
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 38 deletions.
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][(optional)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
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
68fb291b0318b54a71f6f3636e58bd0896f084e5ba4fa311ecf36e019c5e6e48 10.88.0.5 HelloWorld 3.3.3.3,1.1.1.1
95655fb6832ba134efa66e9c80862a6c9b04f3cc6abf8adfdda8c38112c2c6fa 10.88.0.3 hopefulmontalcini,testdbctr
8bcc5fe0cb09bee5dfb71d61503a87688cfc82aa5f130bcedb19357a17765926 10.88.0.4 trustingzhukovsky,ctr1,ctra
43 changes: 43 additions & 0 deletions src/test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ mod tests {
}
}
#[test]
// Test loading of config file from directory with custom DNS for containers
fn test_loading_config_file_with_dns_servers() {
match config::parse_configs("src/test/config/podman_custom_dns_servers") {
Ok(_) => {}
Err(e) => panic!("{}", e),
}
}
#[test]
// Parse config files from stub data
fn test_parsing_config_files() {
match config::parse_configs("src/test/config/podman") {
Expand All @@ -40,6 +48,41 @@ 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);

// 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
63 changes: 56 additions & 7 deletions test/100-basic-name-resolution.bats
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,60 @@

load helpers

@test "basic container - dns itself" {
# custom DNS server is set to `3.3.3.3` 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 "podman1" $(random_string 64) "aone" "$subnet_a" "10.10.10.10" "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` which is invalid 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 "podman1" $(random_string 64) "aone" "$subnet_a" "8.8.8.8" "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 "podman1" $(random_string 64) "aone" "$subnet_a" "" "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 +82,7 @@ load helpers
setup_slirp4netns

subnet_a=$(random_subnet 5)
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "a1" "1a"
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "" "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 +96,7 @@ load helpers
setup_slirp4netns

subnet_a=$(random_subnet 6)
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "a1" "1a"
create_config "podman1" $(random_string 64) "aone" "$subnet_a" "" "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 +123,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 "$long_name" $(random_string 64) "aone" "$subnet_a" "" "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 +139,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 "podman1" $(random_string 64) "aone" "$subnet_a" "" "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 "podman1" $(random_string 64) "atwo" "$subnet_a" "" "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 "podman1" $(random_string 64) "aone" "$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 "podman2" $(random_string 64) "bone" "$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 "podman1" $(random_string 64) "aone" "$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 "podman2" $(random_string 64) "bone" "$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 "podman1" $(random_string 64) "abtwo" "$subnet_a" ""
a2_config=$config
a2_ip=$(echo "$a2_config" | jq -r .networks.podman1.static_ips[0])

Expand Down
Loading

0 comments on commit 89571c7

Please sign in to comment.