Skip to content

Commit b07571c

Browse files
committed
Prevent bypassing IPv4 blocked_networks with IPv6 compat addresses
Signed-off-by: Lann Martin <lann.martin@fermyon.com>
1 parent 94ecf44 commit b07571c

File tree

1 file changed

+27
-5
lines changed

1 file changed

+27
-5
lines changed

crates/factor-outbound-networking/src/blocked_networks.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub struct BlockedNetworks {
1212
/// A set of IP networks to be blocked
1313
networks: Arc<IpNetworkTable<()>>,
1414
/// If true, block all non-globally-routable networks, in addition to `networks`
15+
///
16+
/// See: [`ip_network::Ipv4Network::is_global`] / [`ip_network::Ipv6Network::is_global`]
1517
block_private: bool,
1618
}
1719

@@ -45,7 +47,16 @@ impl BlockedNetworks {
4547
if self.block_private && !IpNetwork::from(ip_addr).is_global() {
4648
return true;
4749
}
48-
self.networks.longest_match(ip_addr).is_some()
50+
if self.networks.longest_match(ip_addr).is_some() {
51+
return true;
52+
}
53+
// Convert IPv4-compatible IPv6 addresses to IPv4 and check again to prevent bypass
54+
if let IpAddr::V6(ipv6) = ip_addr {
55+
if let Some(ipv4_compat) = ipv6.to_ipv4() {
56+
return self.is_blocked(&IpAddr::V4(ipv4_compat));
57+
}
58+
}
59+
false
4960
}
5061

5162
/// Removes and returns any addresses with blocked IPs from the given Vec.
@@ -96,6 +107,7 @@ pub(crate) mod tests {
96107
let blocked = BlockedNetworks::new([cidr("123.123.0.0/16"), cidr("2001::/96")], false);
97108
assert!(blocked.is_blocked(&ip("123.123.123.123")));
98109
assert!(blocked.is_blocked(&ip("2001::1000")));
110+
assert!(blocked.is_blocked(&ip("::ffff:123.123.123.123")));
99111
assert!(!blocked.is_blocked(&ip("123.100.100.100")));
100112
assert!(!blocked.is_blocked(&ip("2002::1000")));
101113
}
@@ -104,10 +116,20 @@ pub(crate) mod tests {
104116
fn test_is_blocked_private() {
105117
let redundant_private_cidr = cidr("10.0.0.0/8");
106118
let blocked = BlockedNetworks::new([redundant_private_cidr], true);
107-
assert!(blocked.is_blocked(&ip("127.0.0.1")));
108-
assert!(blocked.is_blocked(&ip("10.10.10.10")));
109-
assert!(blocked.is_blocked(&ip("::1")));
110-
assert!(blocked.is_blocked(&ip("fc00::f00d")));
119+
for private in [
120+
"0.0.0.0",
121+
"10.10.10.10",
122+
"100.64.1.1",
123+
"127.0.0.1",
124+
"169.254.0.1",
125+
"192.0.0.1",
126+
"::1",
127+
"::ffff:10.10.10.10",
128+
"fc00::f00d",
129+
] {
130+
assert!(blocked.is_blocked(&ip(private)), "{private}");
131+
}
132+
// Public addresses not blocked
111133
assert!(!blocked.is_blocked(&ip("123.123.123.123")));
112134
assert!(!blocked.is_blocked(&ip("2600::beef")));
113135
}

0 commit comments

Comments
 (0)