1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
4
5pub fn is_global_ip(ip_addr: &IpAddr) -> bool {
7 match ip_addr {
8 IpAddr::V4(ip) => is_global_ipv4(ip),
9 IpAddr::V6(ip) => is_global_ipv6(ip),
10 }
11}
12
13pub fn unspecified_ip_for(ip_addr: &IpAddr) -> IpAddr {
15 match ip_addr {
16 IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
17 IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::UNSPECIFIED),
18 }
19}
20
21pub fn unspecified_socket_addr_for(ip_addr: &IpAddr, port: u16) -> SocketAddr {
23 SocketAddr::new(unspecified_ip_for(ip_addr), port)
24}
25
26pub fn is_global_ipv4(ipv4_addr: &Ipv4Addr) -> bool {
29 !(ipv4_addr.octets()[0] == 0 || ipv4_addr.is_private()
31 || is_shared_ipv4(ipv4_addr)
32 || ipv4_addr.is_loopback()
33 || ipv4_addr.is_link_local()
34 || (
37 ipv4_addr.octets()[0] == 192 && ipv4_addr.octets()[1] == 0 && ipv4_addr.octets()[2] == 0
38 && ipv4_addr.octets()[3] != 9 && ipv4_addr.octets()[3] != 10
39 )
40 || ipv4_addr.is_documentation()
41 || is_benchmarking_ipv4(ipv4_addr)
42 || is_reserved_ipv4(ipv4_addr)
43 || ipv4_addr.is_broadcast())
44}
45
46pub fn is_global_ipv6(ipv6_addr: &Ipv6Addr) -> bool {
49 !(ipv6_addr.is_unspecified()
50 || ipv6_addr.is_loopback()
51 || matches!(ipv6_addr.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
53 || matches!(ipv6_addr.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
55 || matches!(ipv6_addr.segments(), [0x100, 0, 0, 0, _, _, _, _])
57 || (matches!(ipv6_addr.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
59 && !(
60 u128::from_be_bytes(ipv6_addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
62 || u128::from_be_bytes(ipv6_addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
64 || matches!(ipv6_addr.segments(), [0x2001, 3, _, _, _, _, _, _])
66 || matches!(ipv6_addr.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
68 || matches!(ipv6_addr.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
71 ))
72 || matches!(ipv6_addr.segments(), [0x2002, _, _, _, _, _, _, _])
75 || is_documentation_ipv6(ipv6_addr)
76 || ipv6_addr.is_unique_local()
77 || ipv6_addr.is_unicast_link_local())
78}
79
80fn is_shared_ipv4(ipv4_addr: &Ipv4Addr) -> bool {
85 ipv4_addr.octets()[0] == 100 && (ipv4_addr.octets()[1] & 0b1100_0000 == 0b0100_0000)
86}
87
88fn is_benchmarking_ipv4(ipv4_addr: &Ipv4Addr) -> bool {
91 ipv4_addr.octets()[0] == 198 && (ipv4_addr.octets()[1] & 0xfe) == 18
92}
93
94fn is_reserved_ipv4(ipv4_addr: &Ipv4Addr) -> bool {
96 ipv4_addr.octets()[0] & 240 == 240 && !ipv4_addr.is_broadcast()
97}
98
99fn is_documentation_ipv6(ipv6_addr: &Ipv6Addr) -> bool {
102 matches!(
103 ipv6_addr.segments(),
104 [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..]
105 )
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
112
113 #[test]
114 fn test_is_global_ipv4() {
115 let global = Ipv4Addr::new(1, 1, 1, 1); let private = Ipv4Addr::new(192, 168, 1, 1);
117 let loopback = Ipv4Addr::new(127, 0, 0, 1);
118 let shared = Ipv4Addr::new(100, 64, 0, 1); let doc = Ipv4Addr::new(192, 0, 2, 1); assert!(is_global_ipv4(&global));
122 assert!(!is_global_ipv4(&private));
123 assert!(!is_global_ipv4(&loopback));
124 assert!(!is_global_ipv4(&shared));
125 assert!(!is_global_ipv4(&doc));
126 }
127
128 #[test]
129 fn test_is_global_ipv6() {
130 let global = Ipv6Addr::new(0x2606, 0x4700, 0, 0, 0, 0, 0, 0x1111); let loopback = Ipv6Addr::LOCALHOST;
132 let unspecified = Ipv6Addr::UNSPECIFIED;
133 let unique_local = Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 1);
134 let doc = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1); assert!(is_global_ipv6(&global));
137 assert!(!is_global_ipv6(&loopback));
138 assert!(!is_global_ipv6(&unspecified));
139 assert!(!is_global_ipv6(&unique_local));
140 assert!(!is_global_ipv6(&doc));
141 }
142
143 #[test]
144 fn test_is_global_ip() {
145 let ip_v4 = IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1));
146 let ip_v6 = IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0, 0, 0, 0, 0, 0x1111)); let ip_private = IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1));
148 let ip_ula = IpAddr::V6(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 1));
149
150 assert!(is_global_ip(&ip_v4));
151 assert!(is_global_ip(&ip_v6));
152 assert!(!is_global_ip(&ip_private));
153 assert!(!is_global_ip(&ip_ula));
154 }
155
156 #[test]
157 fn test_unspecified_helpers() {
158 let v4 = IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1));
159 let v6 = IpAddr::V6(Ipv6Addr::LOCALHOST);
160
161 assert_eq!(unspecified_ip_for(&v4), IpAddr::V4(Ipv4Addr::UNSPECIFIED));
162 assert_eq!(unspecified_ip_for(&v6), IpAddr::V6(Ipv6Addr::UNSPECIFIED));
163
164 assert_eq!(
165 unspecified_socket_addr_for(&v4, 1234),
166 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 1234)
167 );
168 assert_eq!(
169 unspecified_socket_addr_for(&v6, 4321),
170 SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 4321)
171 );
172 }
173}