@@ -12,6 +12,8 @@ pub struct BlockedNetworks {
12
12
/// A set of IP networks to be blocked
13
13
networks : Arc < IpNetworkTable < ( ) > > ,
14
14
/// 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`]
15
17
block_private : bool ,
16
18
}
17
19
@@ -45,7 +47,16 @@ impl BlockedNetworks {
45
47
if self . block_private && !IpNetwork :: from ( ip_addr) . is_global ( ) {
46
48
return true ;
47
49
}
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
49
60
}
50
61
51
62
/// Removes and returns any addresses with blocked IPs from the given Vec.
@@ -96,6 +107,7 @@ pub(crate) mod tests {
96
107
let blocked = BlockedNetworks :: new ( [ cidr ( "123.123.0.0/16" ) , cidr ( "2001::/96" ) ] , false ) ;
97
108
assert ! ( blocked. is_blocked( & ip( "123.123.123.123" ) ) ) ;
98
109
assert ! ( blocked. is_blocked( & ip( "2001::1000" ) ) ) ;
110
+ assert ! ( blocked. is_blocked( & ip( "::ffff:123.123.123.123" ) ) ) ;
99
111
assert ! ( !blocked. is_blocked( & ip( "123.100.100.100" ) ) ) ;
100
112
assert ! ( !blocked. is_blocked( & ip( "2002::1000" ) ) ) ;
101
113
}
@@ -104,10 +116,20 @@ pub(crate) mod tests {
104
116
fn test_is_blocked_private ( ) {
105
117
let redundant_private_cidr = cidr ( "10.0.0.0/8" ) ;
106
118
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
111
133
assert ! ( !blocked. is_blocked( & ip( "123.123.123.123" ) ) ) ;
112
134
assert ! ( !blocked. is_blocked( & ip( "2600::beef" ) ) ) ;
113
135
}
0 commit comments