@@ -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