minecraft_pinger/common/
ip_filter.rs1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2
3pub type IpFilter = dyn Fn(IpAddr) -> bool + Send + Sync;
5
6pub fn is_public_ip(ip: IpAddr) -> bool {
10 match ip {
11 IpAddr::V4(v4) => is_public_ipv4(v4),
12 IpAddr::V6(v6) => is_public_ipv6(v6),
13 }
14}
15
16fn is_public_ipv4(ip: Ipv4Addr) -> bool {
17 let o = ip.octets();
18 !(
19 o[0] == 0
21 || o[0] == 10
23 || (o[0] == 100 && (o[1] & 0b1100_0000) == 64)
25 || o[0] == 127
27 || (o[0] == 169 && o[1] == 254)
29 || (o[0] == 172 && (o[1] & 0xF0) == 16)
31 || (o[0] == 192 && o[1] == 0 && o[2] == 0)
33 || (o[0] == 192 && o[1] == 0 && o[2] == 2)
35 || (o[0] == 192 && o[1] == 168)
37 || (o[0] == 198 && (o[1] & 0xFE) == 18)
39 || (o[0] == 198 && o[1] == 51 && o[2] == 100)
41 || (o[0] == 203 && o[1] == 0 && o[2] == 113)
43 || o[0] >= 224
45 )
46}
47
48fn is_public_ipv6(ip: Ipv6Addr) -> bool {
49 if let Some(mapped) = ip.to_ipv4_mapped() {
51 return is_public_ipv4(mapped);
52 }
53
54 let s = ip.segments();
55 !(ip.is_loopback()
56 || ip.is_unspecified()
57 || s[0] == 0
59 || (s[0] & 0xfe00) == 0xfc00
61 || (s[0] & 0xffc0) == 0xfe80
63 || (s[0] & 0xff00) == 0xff00
65 || s[0] == 0x0100
67 || (s[0] == 0x2001 && (s[1] & 0xff00) == 0x0000)
70 || (s[0] == 0x2001 && s[1] == 0x0db8))
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use std::net::IpAddr;
78
79 fn allowed(s: &str) -> bool {
80 is_public_ip(s.parse::<IpAddr>().unwrap())
81 }
82
83 #[test]
84 fn rejects_private_and_reserved_ipv4() {
85 assert!(!allowed("127.0.0.1"));
86 assert!(!allowed("10.0.0.1"));
87 assert!(!allowed("172.16.0.1"));
88 assert!(!allowed("172.31.255.255"));
89 assert!(!allowed("192.168.1.1"));
90 assert!(!allowed("169.254.169.254")); assert!(!allowed("0.0.0.0"));
92 assert!(!allowed("255.255.255.255"));
93 assert!(!allowed("100.64.0.1")); assert!(!allowed("192.0.2.1")); assert!(!allowed("198.51.100.7")); assert!(!allowed("203.0.113.9")); assert!(!allowed("198.18.0.1")); assert!(!allowed("224.0.0.1")); assert!(!allowed("240.0.0.1")); assert!(!allowed("192.0.0.8")); }
102
103 #[test]
104 fn accepts_public_ipv4() {
105 assert!(allowed("8.8.8.8"));
106 assert!(allowed("1.1.1.1"));
107 assert!(allowed("51.75.20.104"));
108 assert!(allowed("172.32.0.1")); assert!(allowed("100.128.0.1")); assert!(allowed("9.9.9.9"));
111 }
112
113 #[test]
114 fn rejects_private_and_reserved_ipv6() {
115 assert!(!allowed("::1"));
116 assert!(!allowed("::"));
117 assert!(!allowed("fe80::1"));
118 assert!(!allowed("fc00::1"));
119 assert!(!allowed("fd12:3456:789a::1"));
120 assert!(!allowed("ff02::1"));
121 assert!(!allowed("2001:db8::1"));
122 assert!(!allowed("2001::1")); assert!(!allowed("::ffff:127.0.0.1")); assert!(!allowed("::ffff:10.0.0.1"));
125 assert!(!allowed("::ffff:169.254.169.254"));
126 }
127
128 #[test]
129 fn accepts_public_ipv6() {
130 assert!(allowed("2606:4700:4700::1111"));
131 assert!(allowed("2001:4860:4860::8888"));
132 assert!(allowed("::ffff:8.8.8.8")); }
134
135 #[test]
136 fn test_ipv4_edge_cases() {
137 assert!(!allowed("10.255.255.255"));
138 assert!(allowed("172.15.255.255")); assert!(!allowed("172.16.0.0")); assert!(!allowed("172.31.255.255")); assert!(allowed("172.32.0.0")); assert!(allowed("192.167.255.255")); assert!(allowed("192.169.0.0")); assert!(allowed("169.253.255.255")); assert!(allowed("169.255.0.0")); assert!(allowed("100.63.255.255")); assert!(!allowed("100.127.255.255")); assert!(allowed("100.128.0.0")); }
150
151 #[test]
152 fn test_ipv6_edge_cases() {
153 assert!(!allowed("::ffff:192.168.1.1"));
154 assert!(!allowed("2001:0:0:1::1"));
155 assert!(allowed("2001:200::1"));
156 assert!(!allowed("2001:db8:1::1"));
157 }
158}