1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use crate::network::firewall::Firewall;
use crate::network::netns::NetworkNamespace;
pub fn open_ports(
netns: &NetworkNamespace,
ports: &[u16],
firewall: Firewall,
) -> anyhow::Result<()> {
// IPv6 is configured on the veth pair only when it is enabled for this
// namespace. Use that as the source of truth so callers do not have to
// thread the CLI flag through every protocol implementation.
let ipv6_enabled = netns
.veth_pair_ips
.as_ref()
.and_then(|ips| ips.ipv6.as_ref())
.is_some();
for port in ports {
let port_str = &port.to_string();
match firewall {
Firewall::IpTables => {
let iptables_cmds: &[&str] = if ipv6_enabled {
&["iptables", "ip6tables"]
} else {
&["iptables"]
};
for iptables_cmd in iptables_cmds {
for protocol in ["tcp", "udp"] {
NetworkNamespace::exec(
&netns.name,
&[
iptables_cmd,
"-I",
"INPUT",
"-p",
protocol,
"--dport",
port_str,
"-j",
"ACCEPT",
],
)?;
NetworkNamespace::exec(
&netns.name,
&[
iptables_cmd,
"-I",
"OUTPUT",
"-p",
protocol,
"--sport",
port_str,
"-j",
"ACCEPT",
],
)?;
}
}
}
Firewall::NfTables => {
for protocol in ["tcp", "udp"] {
let family = if ipv6_enabled {
Vec::new()
} else {
vec!["ip", "protocol", protocol]
};
let mut input = vec!["nft", "insert", "rule", "inet", &netns.name, "input"];
input.extend(family.iter().copied());
input.extend([protocol, "dport", port_str, "counter", "accept"]);
NetworkNamespace::exec(&netns.name, &input)?;
let mut output = vec!["nft", "insert", "rule", "inet", &netns.name, "output"];
output.extend(family.iter().copied());
output.extend([protocol, "sport", port_str, "counter", "accept"]);
NetworkNamespace::exec(&netns.name, &output)?;
}
}
}
}
Ok(())
}