Skip to content

Commit 9645631

Browse files
committed
Updated code as suggested.
Added tests for nftables and iptables Signed-off-by: lto-dev <[email protected]>
1 parent ec928f1 commit 9645631

File tree

9 files changed

+117
-49
lines changed

9 files changed

+117
-49
lines changed

src/firewall/iptables.rs

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use crate::firewall;
33
use crate::firewall::firewalld;
44
use crate::firewall::varktables::types::TeardownPolicy::OnComplete;
55
use crate::firewall::varktables::types::{
6-
create_network_chains, get_network_chains, get_port_forwarding_chains, TeardownPolicy,
6+
create_network_chains, get_network_chains, get_port_forwarding_chains, NetworkChainConfig,
7+
TeardownPolicy,
78
};
89
use crate::network::internal_types::{
910
PortForwardConfig, SetupNetwork, TearDownNetwork, TeardownPortForward,
@@ -54,16 +55,15 @@ impl firewall::FirewallDriver for IptablesDriver {
5455
conn = &self.conn6;
5556
}
5657

57-
let chains = get_network_chains(
58-
conn,
58+
let config = NetworkChainConfig {
5959
network,
60-
&network_setup.network_hash_name,
61-
is_ipv6,
62-
network_setup.bridge_name.clone(),
63-
network_setup.isolation,
64-
network_setup.dns_port,
65-
network_setup.outbound_addr,
66-
);
60+
network_hash_name: network_setup.network_hash_name.clone(),
61+
interface_name: network_setup.bridge_name.clone(),
62+
isolation: network_setup.isolation,
63+
dns_port: network_setup.dns_port,
64+
outbound_addr: network_setup.outbound_addr,
65+
};
66+
let chains = get_network_chains(conn, config);
6767

6868
create_network_chains(chains)?;
6969

@@ -84,16 +84,15 @@ impl firewall::FirewallDriver for IptablesDriver {
8484
if is_ipv6 {
8585
conn = &self.conn6;
8686
}
87-
let chains = get_network_chains(
88-
conn,
87+
let config = NetworkChainConfig {
8988
network,
90-
&tear.config.network_hash_name,
91-
is_ipv6,
92-
tear.config.bridge_name.clone(),
93-
tear.config.isolation,
94-
tear.config.dns_port,
95-
tear.config.outbound_addr,
96-
);
89+
network_hash_name: tear.config.network_hash_name.clone(),
90+
interface_name: tear.config.bridge_name.clone(),
91+
isolation: tear.config.isolation,
92+
dns_port: tear.config.dns_port,
93+
outbound_addr: tear.config.outbound_addr,
94+
};
95+
let chains = get_network_chains(conn, config);
9796

9897
for c in &chains {
9998
c.remove_rules(tear.complete_teardown)?;

src/firewall/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ mod tests {
274274
dns_port: 53,
275275
outbound_addr: None,
276276
};
277-
let net_conf_json = r#"{"subnets":["10.0.0.0/24"],"bridge_name":"bridge","network_id":"c2c8a073252874648259997d53b0a1bffa491e21f04bc1bf8609266359931395","network_hash_name":"hash","isolation":"Never","dns_port":53,"outbound_addr":null}"#;
277+
let net_conf_json = r#"{"subnets":["10.0.0.0/24"],"bridge_name":"bridge","network_id":"c2c8a073252874648259997d53b0a1bffa491e21f04bc1bf8609266359931395","network_hash_name":"hash","isolation":"Never","dns_port":53}"#;
278278

279279
let port_conf = PortForwardConfig {
280280
container_id: container_id.to_string(),

src/firewall/varktables/types.rs

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ impl VarkRule {
6666
&self.rule
6767
}
6868
}
69+
6970
// Varkchain is an iptable chain with extra info
7071
pub struct VarkChain<'a> {
7172
// name of chain
@@ -192,19 +193,23 @@ pub fn create_network_chains(chains: Vec<VarkChain<'_>>) -> NetavarkResult<()> {
192193
Ok(())
193194
}
194195

195-
#[allow(clippy::too_many_arguments)]
196-
pub fn get_network_chains<'a>(
197-
conn: &'a IPTables,
198-
network: IpNet,
199-
network_hash_name: &'a str,
200-
is_ipv6: bool,
201-
interface_name: String,
202-
isolation: IsolateOption,
203-
dns_port: u16,
204-
outbound_addr: Option<IpAddr>,
205-
) -> Vec<VarkChain<'a>> {
196+
pub struct NetworkChainConfig {
197+
pub network: IpNet,
198+
pub network_hash_name: String,
199+
pub interface_name: String,
200+
pub isolation: IsolateOption,
201+
pub dns_port: u16,
202+
pub outbound_addr: Option<IpAddr>,
203+
}
204+
205+
pub fn get_network_chains(conn: &IPTables, config: NetworkChainConfig) -> Vec<VarkChain<'_>> {
206206
let mut chains = Vec::new();
207-
let prefixed_network_hash_name = format!("{}-{}", "NETAVARK", network_hash_name);
207+
let prefixed_network_hash_name = format!("{}-{}", "NETAVARK", config.network_hash_name);
208+
209+
let is_ipv6 = match config.network {
210+
IpNet::V4(_) => false,
211+
IpNet::V6(_) => true,
212+
};
208213

209214
// NETAVARK-HASH
210215
let mut hashed_network_chain = VarkChain::new(
@@ -216,15 +221,15 @@ pub fn get_network_chains<'a>(
216221
hashed_network_chain.create = true;
217222

218223
hashed_network_chain.build_rule(VarkRule::new(
219-
format!("-d {network} -j {ACCEPT}"),
224+
format!("-d {} -j {}", config.network, ACCEPT),
220225
Some(TeardownPolicy::OnComplete),
221226
));
222227

223228
let mut multicast_dest = MULTICAST_NET_V4;
224229
if is_ipv6 {
225230
multicast_dest = MULTICAST_NET_V6;
226231
}
227-
if let Some(addr) = outbound_addr {
232+
if let Some(addr) = config.outbound_addr {
228233
if !is_ipv6 && addr.is_ipv4() {
229234
log::trace!("Creating SNAT rule with outbound address {}", addr);
230235
hashed_network_chain.build_rule(VarkRule::new(
@@ -254,7 +259,7 @@ pub fn get_network_chains<'a>(
254259
let mut postrouting_chain =
255260
VarkChain::new(conn, NAT.to_string(), POSTROUTING.to_string(), None);
256261
postrouting_chain.build_rule(VarkRule::new(
257-
format!("-s {network} -j {prefixed_network_hash_name}"),
262+
format!("-s {} -j {}", config.network, prefixed_network_hash_name),
258263
Some(TeardownPolicy::OnComplete),
259264
));
260265
chains.push(postrouting_chain);
@@ -294,7 +299,7 @@ pub fn get_network_chains<'a>(
294299
);
295300
netavark_isolation_chain_3.create = true;
296301

297-
if let IsolateOption::Normal | IsolateOption::Strict = isolation {
302+
if let IsolateOption::Normal | IsolateOption::Strict = config.isolation {
298303
debug!("Add extra isolate rules");
299304
// NETAVARK_ISOLATION_1
300305
let mut netavark_isolation_chain_1 = VarkChain::new(
@@ -312,7 +317,7 @@ pub fn get_network_chains<'a>(
312317
td_policy: Some(TeardownPolicy::OnComplete),
313318
});
314319

315-
let netavark_isolation_1_target = if let IsolateOption::Strict = isolation {
320+
let netavark_isolation_1_target = if let IsolateOption::Strict = config.isolation {
316321
// NETAVARK_ISOLATION_1 -i bridge_name ! -o bridge_name -j NETAVARK_ISOLATION_3
317322
NETAVARK_ISOLATION_3
318323
} else {
@@ -321,15 +326,16 @@ pub fn get_network_chains<'a>(
321326
};
322327
netavark_isolation_chain_1.build_rule(VarkRule {
323328
rule: format!(
324-
"-i {interface_name} ! -o {interface_name} -j {netavark_isolation_1_target}"
329+
"-i {} ! -o {} -j {}",
330+
config.interface_name, config.interface_name, netavark_isolation_1_target
325331
),
326332
position: Some(ind),
327333
td_policy: Some(TeardownPolicy::OnComplete),
328334
});
329335

330336
// NETAVARK_ISOLATION_2 -o bridge_name -j DROP
331337
netavark_isolation_chain_2.build_rule(VarkRule {
332-
rule: format!("-o {} -j {}", interface_name, "DROP"),
338+
rule: format!("-o {} -j {}", config.interface_name, "DROP"),
333339
position: Some(ind),
334340
td_policy: Some(TeardownPolicy::OnComplete),
335341
});
@@ -350,7 +356,7 @@ pub fn get_network_chains<'a>(
350356

351357
// NETAVARK_ISOLATION_3 -o bridge_name -j DROP
352358
netavark_isolation_chain_3.build_rule(VarkRule {
353-
rule: format!("-o {} -j {}", interface_name, "DROP"),
359+
rule: format!("-o {} -j {}", config.interface_name, "DROP"),
354360
position: Some(ind),
355361
td_policy: Some(TeardownPolicy::OnComplete),
356362
});
@@ -399,7 +405,7 @@ pub fn get_network_chains<'a>(
399405
netavark_input_chain.build_rule(VarkRule::new(
400406
format!(
401407
"-p {} -s {} --dport {} -j {}",
402-
proto, network, dns_port, ACCEPT
408+
proto, config.network, config.dns_port, ACCEPT
403409
),
404410
Some(TeardownPolicy::OnComplete),
405411
));
@@ -417,14 +423,17 @@ pub fn get_network_chains<'a>(
417423
// Create incoming traffic rule
418424
// CNI did this by IP address, this is implemented per subnet
419425
netavark_forward_chain.build_rule(VarkRule::new(
420-
format!("-d {network} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT"),
426+
format!(
427+
"-d {} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT",
428+
config.network
429+
),
421430
Some(TeardownPolicy::OnComplete),
422431
));
423432

424433
// Create outgoing traffic rule
425434
// CNI did this by IP address, this is implemented per subnet
426435
netavark_forward_chain.build_rule(VarkRule::new(
427-
format!("-s {network} -j ACCEPT"),
436+
format!("-s {} -j ACCEPT", config.network),
428437
Some(TeardownPolicy::OnComplete),
429438
));
430439
chains.push(netavark_forward_chain);

src/network/bridge.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use super::{
2323
constants::{
2424
ISOLATE_OPTION_FALSE, ISOLATE_OPTION_STRICT, ISOLATE_OPTION_TRUE,
2525
NO_CONTAINER_INTERFACE_ERROR, OPTION_HOST_INTERFACE_NAME, OPTION_ISOLATE, OPTION_METRIC,
26-
OPTION_MODE, OPTION_MTU, OPTION_NO_DEFAULT_ROUTE, OPTION_VLAN, OPTION_VRF,
26+
OPTION_MODE, OPTION_MTU, OPTION_NO_DEFAULT_ROUTE, OPTION_OUTBOUND_ADDR, OPTION_VLAN,
27+
OPTION_VRF,
2728
},
2829
core_utils::{self, get_ipam_addresses, join_netns, parse_option, CoreUtils},
2930
driver::{self, DriverInfo},
@@ -392,7 +393,10 @@ impl<'a> Bridge<'a> {
392393
network_hash_name: id_network_hash.clone(),
393394
isolation: isolate,
394395
dns_port: self.info.dns_port,
395-
outbound_addr: self.info.network.outbound_addr,
396+
outbound_addr: parse_option::<IpAddr>(
397+
&self.info.network.options,
398+
OPTION_OUTBOUND_ADDR,
399+
)?,
396400
};
397401

398402
let mut has_ipv4 = false;

src/network/internal_types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub struct SetupNetwork {
2727
/// port used for the dns server
2828
pub dns_port: u16,
2929
/// outbound address for SNAT
30+
#[serde(skip_serializing_if = "Option::is_none")]
31+
#[serde(default)]
3032
pub outbound_addr: Option<IpAddr>,
3133
}
3234

src/network/types.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ pub struct Network {
5757
/// Network DNS servers for aardvark-dns.
5858
#[serde(rename = "network_dns_servers")]
5959
pub network_dns_servers: Option<Vec<IpAddr>>,
60-
61-
/// outbound addr for this network.
62-
#[serde(rename = "outbound_addr")]
63-
pub outbound_addr: Option<IpAddr>,
6460
}
6561

6662
/// NetworkOptions for a given container.

test/100-bridge-iptables.bats

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,19 @@ function check_simple_bridge_iptables() {
10931093
assert "${#lines[@]}" = 4 "too many NETAVARK_FORWARD rules"
10941094
}
10951095

1096+
@test "$fw_driver - bridge with outbound addr" {
1097+
run_netavark --file ${TESTSDIR}/testfiles/bridge-outbound-addr.json setup $(get_container_netns_path)
1098+
1099+
# Check that the iptables rules were created with SNAT
1100+
run_in_host_netns iptables -t nat -S NETAVARK-2F259BAB93AAAAA
1101+
assert "${lines[2]}" == "-A NETAVARK-2F259BAB93AAAAA ! -d 224.0.0.0/4 -j SNAT --to-source 100.1.100.1" "SNAT rule with outbound address"
1102+
1103+
run_netavark --file ${TESTSDIR}/testfiles/bridge-outbound-addr.json teardown $(get_container_netns_path)
1104+
1105+
# Check that the chain is removed
1106+
expected_rc=1 run_in_host_netns iptables -t nat -nvL NETAVARK-2F259BAB93AAAAA
1107+
}
1108+
10961109
@test "$fw_driver - aardvark-dns error cleanup" {
10971110
expected_rc=1 run_netavark -a /usr/bin/false --file ${TESTSDIR}/testfiles/dualstack-bridge-custom-dns-server.json setup $(get_container_netns_path)
10981111
assert_json ".error" "error while applying dns entries: IO error: aardvark-dns exited unexpectedly without error message" "aardvark-dns error"

test/250-bridge-nftables.bats

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,19 @@ function check_simple_bridge_nftables() {
10321032
assert "$output" == $'table inet netavark {\n\tchain NETAVARK-HOSTPORT-DNAT {\n\t}\n}' "NETAVARK-HOSTPORT-DNAT chain must be empty"
10331033
}
10341034

1035+
@test "$fw_driver - bridge with outbound addr" {
1036+
run_netavark --file ${TESTSDIR}/testfiles/bridge-outbound-addr.json setup $(get_container_netns_path)
1037+
1038+
# Check that the nftables rules were created with SNAT
1039+
run_in_host_netns nft list chain inet netavark nv_2f259bab_10_89_0_0_nm24
1040+
assert "${lines[3]}" =~ "ip daddr != 224.0.0.0/4 snat ip to 100.1.100.1" "SNAT rule with outbound address"
1041+
1042+
run_netavark --file ${TESTSDIR}/testfiles/bridge-outbound-addr.json teardown $(get_container_netns_path)
1043+
1044+
# Check that the chain is removed
1045+
expected_rc=1 run_in_host_netns nft list chain inet netavark nv_2f259bab_10_89_0_0_nm24
1046+
}
1047+
10351048
@test "$fw_driver - aardvark-dns error cleanup" {
10361049
expected_rc=1 run_netavark -a /usr/bin/false --file ${TESTSDIR}/testfiles/dualstack-bridge-custom-dns-server.json setup $(get_container_netns_path)
10371050
assert_json ".error" "error while applying dns entries: IO error: aardvark-dns exited unexpectedly without error message" "aardvark-dns error"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"container_id": "someID",
3+
"container_name": "someName",
4+
"networks": {
5+
"podman1": {
6+
"interface_name": "eth0",
7+
"static_ips": [
8+
"10.89.0.2"
9+
]
10+
}
11+
},
12+
"network_info": {
13+
"podman1": {
14+
"name": "podman1",
15+
"id": "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a9fc6",
16+
"driver": "bridge",
17+
"network_interface": "podman1",
18+
"subnets": [
19+
{
20+
"gateway": "10.89.0.1",
21+
"subnet": "10.89.0.0/24"
22+
}
23+
],
24+
"ipv6_enabled": false,
25+
"internal": false,
26+
"dns_enabled": true,
27+
"options": {
28+
"outbound_addr": "100.1.100.1"
29+
}
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)