Skip to main content

kaspa_utils/
networking.rs

1// #![allow(dead_code)]
2use alloc::borrow::ToOwned;
3use alloc::format;
4use alloc::string::String;
5use borsh::{BorshDeserialize, BorshSerialize};
6use core::{
7    fmt::Display,
8    net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
9    ops::Deref,
10    str::FromStr,
11};
12use ipnet::IpNet;
13use serde::{Deserialize, Serialize};
14#[cfg(feature = "peer-id")]
15use uuid::Uuid;
16use wasm_bindgen::prelude::*;
17
18// A network address serialization of [`ContextualNetAddress`].
19#[wasm_bindgen(typescript_custom_section)]
20const TS_IP_ADDRESS: &'static str = r#"
21    /**
22     * Generic network address representation.
23     * 
24     * @category General
25     */
26    export interface INetworkAddress {
27        /**
28         * IPv4 or IPv6 address.
29         */
30        ip: string;
31        /**
32         * Optional port number.
33         */
34        port?: number;
35    }
36"#;
37
38/// A bucket based on an ip's prefix bytes.
39/// for ipv4 it consists of 6 leading zero bytes, and the first two octets,
40/// for ipv6 it consists of the first 8 octets,
41/// encoded into a big endian u64.
42#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
43pub struct PrefixBucket(u64);
44
45impl PrefixBucket {
46    pub fn as_u64(&self) -> u64 {
47        self.0
48    }
49}
50
51impl From<&IpAddress> for PrefixBucket {
52    fn from(ip_address: &IpAddress) -> Self {
53        match ip_address.0 {
54            IpAddr::V4(ipv4) => {
55                let prefix_bytes = ipv4.octets();
56                Self(u64::from_be_bytes([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, prefix_bytes[0], prefix_bytes[1]]))
57            }
58            IpAddr::V6(ipv6) => {
59                if let Some(ipv4) = ipv6.to_ipv4() {
60                    let prefix_bytes = ipv4.octets();
61                    Self(u64::from_be_bytes([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, prefix_bytes[0], prefix_bytes[1]]))
62                } else {
63                    // Else use first 8 bytes (routing prefix + subnetwork id) of ipv6
64                    Self(u64::from_be_bytes(ipv6.octets().as_slice()[..8].try_into().expect("Slice with incorrect length")))
65                }
66            }
67        }
68    }
69}
70
71impl From<&NetAddress> for PrefixBucket {
72    fn from(net_address: &NetAddress) -> Self {
73        Self::from(&net_address.ip)
74    }
75}
76
77/// An IP address, newtype of [IpAddr].
78#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, Debug)]
79#[repr(transparent)]
80pub struct IpAddress(pub IpAddr);
81
82impl IpAddress {
83    pub fn new(ip: IpAddr) -> Self {
84        Self(ip)
85    }
86
87    pub fn is_publicly_routable(&self) -> bool {
88        if self.is_loopback() || self.is_unspecified() {
89            return false;
90        }
91
92        match self.0 {
93            IpAddr::V4(ip) => {
94                // RFC 1918 is covered by is_private
95                // RFC 5737 is covered by is_documentation
96                // RFC 3927 is covered by is_link_local
97                // RFC  919 is covered by is_broadcast (wasn't originally covered in go code)
98                if ip.is_broadcast() || ip.is_private() || ip.is_documentation() || ip.is_link_local() {
99                    return false;
100                }
101            }
102            IpAddr::V6(_ip) => {
103                // All of the is_ helper functions for ipv6 are currently marked unstable
104            }
105        }
106
107        // Based on values from network.go
108        let unroutable_nets = [
109            "198.18.0.0/15",   // RFC 2544
110            "2001:DB8::/32",   // RFC 3849
111            "2002::/16",       // RFC 3964
112            "FC00::/7",        // RFC 4193
113            "2001::/32",       // RFC 4380
114            "2001:10::/28",    // RFC 4843
115            "FE80::/64",       // RFC 4862
116            "64:FF9B::/96",    // RFC 6052
117            "::FFFF:0:0:0/96", // RFC 6145
118            "100.64.0.0/10",   // RFC 6598
119            "0.0.0.0/8",       // Zero Net
120            "2001:470::/32",   // Hurricane Electric IPv6 address block.
121        ];
122
123        for curr_net in unroutable_nets {
124            if IpNet::from_str(curr_net).unwrap().contains(&self.0) {
125                return false;
126            }
127        }
128
129        true
130    }
131
132    pub fn prefix_bucket(&self) -> PrefixBucket {
133        PrefixBucket::from(self)
134    }
135}
136
137impl From<IpAddr> for IpAddress {
138    fn from(ip: IpAddr) -> Self {
139        Self(ip)
140    }
141}
142impl From<Ipv4Addr> for IpAddress {
143    fn from(value: Ipv4Addr) -> Self {
144        Self(value.into())
145    }
146}
147impl From<Ipv6Addr> for IpAddress {
148    fn from(value: Ipv6Addr) -> Self {
149        Self(value.into())
150    }
151}
152impl From<IpAddress> for IpAddr {
153    fn from(value: IpAddress) -> Self {
154        value.0
155    }
156}
157
158impl FromStr for IpAddress {
159    type Err = AddrParseError;
160
161    fn from_str(s: &str) -> Result<Self, Self::Err> {
162        IpAddr::from_str(s).map(IpAddress::from)
163    }
164}
165
166impl Display for IpAddress {
167    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
168        self.0.fmt(f)
169    }
170}
171
172impl Deref for IpAddress {
173    type Target = IpAddr;
174
175    fn deref(&self) -> &Self::Target {
176        &self.0
177    }
178}
179
180//
181// Borsh serializers need to be manually implemented for `NetAddress` since
182// IpAddr does not currently support Borsh
183//
184
185impl BorshSerialize for IpAddress {
186    fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> ::core::result::Result<(), borsh::io::Error> {
187        let variant_idx: u8 = match self.0 {
188            IpAddr::V4(..) => 0u8,
189            IpAddr::V6(..) => 1u8,
190        };
191        writer.write_all(&variant_idx.to_le_bytes())?;
192        match self.0 {
193            IpAddr::V4(id0) => {
194                borsh::BorshSerialize::serialize(&id0.octets(), writer)?;
195            }
196            IpAddr::V6(id0) => {
197                borsh::BorshSerialize::serialize(&id0.octets(), writer)?;
198            }
199        }
200        Ok(())
201    }
202}
203
204impl BorshDeserialize for IpAddress {
205    fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> ::core::result::Result<Self, borsh::io::Error> {
206        let variant_idx: u8 = BorshDeserialize::deserialize_reader(reader)?;
207        let ip = match variant_idx {
208            0u8 => {
209                let octets: [u8; 4] = BorshDeserialize::deserialize_reader(reader)?;
210                IpAddr::V4(Ipv4Addr::from(octets))
211            }
212            1u8 => {
213                let octets: [u8; 16] = BorshDeserialize::deserialize_reader(reader)?;
214                IpAddr::V6(Ipv6Addr::from(octets))
215            }
216            _ => {
217                let msg = format!("Unexpected variant index: {:?}", variant_idx);
218                return Err(borsh::io::Error::new(borsh::io::ErrorKind::InvalidInput, msg));
219            }
220        };
221        Ok(Self(ip))
222    }
223}
224
225/// A network address, equivalent of a [SocketAddr].
226#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, Debug, BorshSerialize, BorshDeserialize)]
227pub struct NetAddress {
228    pub ip: IpAddress,
229    pub port: u16,
230}
231
232impl NetAddress {
233    pub fn new(ip: IpAddress, port: u16) -> Self {
234        Self { ip, port }
235    }
236
237    pub fn prefix_bucket(&self) -> PrefixBucket {
238        PrefixBucket::from(self)
239    }
240}
241
242impl From<SocketAddr> for NetAddress {
243    fn from(value: SocketAddr) -> Self {
244        Self::new(value.ip().into(), value.port())
245    }
246}
247
248impl From<NetAddress> for SocketAddr {
249    fn from(value: NetAddress) -> Self {
250        Self::new(value.ip.0, value.port)
251    }
252}
253
254impl FromStr for NetAddress {
255    type Err = AddrParseError;
256
257    fn from_str(s: &str) -> Result<Self, Self::Err> {
258        SocketAddr::from_str(s).map(NetAddress::from)
259    }
260}
261
262impl Display for NetAddress {
263    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
264        SocketAddr::from(self.to_owned()).fmt(f)
265    }
266}
267
268/// A network address possibly without explicit port.
269///
270/// Use `normalize` to get a fully determined address.
271#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, Debug, BorshSerialize, BorshDeserialize)]
272pub struct ContextualNetAddress {
273    ip: IpAddress,
274    port: Option<u16>,
275}
276
277impl ContextualNetAddress {
278    pub fn new(ip: IpAddress, port: Option<u16>) -> Self {
279        Self { ip, port }
280    }
281
282    pub fn has_port(&self) -> bool {
283        self.port.is_some()
284    }
285
286    pub fn normalize(&self, default_port: u16) -> NetAddress {
287        NetAddress::new(self.ip, self.port.unwrap_or(default_port))
288    }
289
290    pub fn unspecified() -> Self {
291        Self { ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).into(), port: None }
292    }
293
294    pub fn loopback() -> Self {
295        Self { ip: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).into(), port: None }
296    }
297
298    pub fn port_not_specified(&self) -> bool {
299        self.port.is_none()
300    }
301
302    pub fn with_port(&self, port: u16) -> Self {
303        Self { ip: self.ip, port: Some(port) }
304    }
305}
306
307impl From<NetAddress> for ContextualNetAddress {
308    fn from(value: NetAddress) -> Self {
309        Self::new(value.ip, Some(value.port))
310    }
311}
312
313impl FromStr for ContextualNetAddress {
314    type Err = AddrParseError;
315
316    fn from_str(s: &str) -> Result<Self, Self::Err> {
317        match SocketAddr::from_str(s) {
318            Ok(socket) => Ok(Self::new(socket.ip().into(), Some(socket.port()))),
319            Err(_) => Ok(Self::new(IpAddress::from_str(s)?, None)),
320        }
321    }
322}
323
324impl TryFrom<&str> for ContextualNetAddress {
325    type Error = AddrParseError;
326
327    fn try_from(s: &str) -> Result<Self, Self::Error> {
328        ContextualNetAddress::from_str(s)
329    }
330}
331
332impl TryFrom<String> for ContextualNetAddress {
333    type Error = AddrParseError;
334
335    fn try_from(s: String) -> Result<Self, Self::Error> {
336        ContextualNetAddress::from_str(&s)
337    }
338}
339
340impl Display for ContextualNetAddress {
341    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
342        match self.port {
343            Some(port) => SocketAddr::new(self.ip.into(), port).fmt(f),
344            None => self.ip.fmt(f),
345        }
346    }
347}
348
349#[cfg(feature = "peer-id")]
350#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, Debug, Default)]
351#[repr(transparent)]
352pub struct PeerId(pub Uuid);
353
354#[cfg(feature = "peer-id")]
355impl PeerId {
356    pub fn new(id: Uuid) -> Self {
357        Self(id)
358    }
359
360    pub fn from_slice(bytes: &[u8]) -> Result<Self, uuid::Error> {
361        Ok(Uuid::from_slice(bytes)?.into())
362    }
363}
364
365#[cfg(feature = "peer-id")]
366impl From<Uuid> for PeerId {
367    fn from(id: Uuid) -> Self {
368        Self(id)
369    }
370}
371
372#[cfg(feature = "peer-id")]
373impl From<PeerId> for Uuid {
374    fn from(value: PeerId) -> Self {
375        value.0
376    }
377}
378
379#[cfg(feature = "peer-id")]
380impl FromStr for PeerId {
381    type Err = uuid::Error;
382
383    fn from_str(s: &str) -> Result<Self, Self::Err> {
384        Uuid::from_str(s).map(PeerId::from)
385    }
386}
387
388#[cfg(feature = "peer-id")]
389impl Display for PeerId {
390    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
391        self.0.fmt(f)
392    }
393}
394
395#[cfg(feature = "peer-id")]
396impl Deref for PeerId {
397    type Target = Uuid;
398
399    fn deref(&self) -> &Self::Target {
400        &self.0
401    }
402}
403
404//
405// Borsh serializers need to be manually implemented for `PeerId` since
406// Uuid does not currently support Borsh
407//
408#[cfg(feature = "peer-id")]
409impl BorshSerialize for PeerId {
410    fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> ::core::result::Result<(), borsh::io::Error> {
411        borsh::BorshSerialize::serialize(&self.0.as_bytes(), writer)?;
412        Ok(())
413    }
414}
415
416#[cfg(feature = "peer-id")]
417impl BorshDeserialize for PeerId {
418    fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> ::core::result::Result<Self, borsh::io::Error> {
419        let bytes: uuid::Bytes = BorshDeserialize::deserialize_reader(reader)?;
420        Ok(Self::new(Uuid::from_bytes(bytes)))
421    }
422}
423
424#[cfg(test)]
425mod tests {
426    use super::*;
427    use std::str::FromStr;
428
429    #[test]
430    fn test_ip_address_borsh() {
431        // Tests for IpAddress Borsh ser/deser since we manually implemented them
432        let ip: IpAddress = Ipv4Addr::from([44u8; 4]).into();
433        let bin = borsh::to_vec(&ip).unwrap();
434        let ip2: IpAddress = BorshDeserialize::try_from_slice(&bin).unwrap();
435        assert_eq!(ip, ip2);
436
437        let ip: IpAddress = Ipv6Addr::from([66u8; 16]).into();
438        let bin = borsh::to_vec(&ip).unwrap();
439        let ip2: IpAddress = BorshDeserialize::try_from_slice(&bin).unwrap();
440        assert_eq!(ip, ip2);
441    }
442
443    #[test]
444    fn test_peer_id_borsh() {
445        // Tests for PeerId Borsh ser/deser since we manually implemented them
446        let id: PeerId = Uuid::new_v4().into();
447        let bin = borsh::to_vec(&id).unwrap();
448        let id2: PeerId = BorshDeserialize::try_from_slice(&bin).unwrap();
449        assert_eq!(id, id2);
450
451        let id: PeerId = Uuid::from_bytes([123u8; 16]).into();
452        let bin = borsh::to_vec(&id).unwrap();
453        let id2: PeerId = BorshDeserialize::try_from_slice(&bin).unwrap();
454        assert_eq!(id, id2);
455    }
456
457    #[test]
458    fn test_net_address_from_str() {
459        let addr_v4 = NetAddress::from_str("1.2.3.4:5678");
460        assert!(addr_v4.is_ok());
461        let addr_v6 = NetAddress::from_str("[2a01:4f8:191:1143::2]:5678");
462        assert!(addr_v6.is_ok());
463    }
464
465    #[test]
466    fn test_prefix_bucket() {
467        let prefix_bytes: [u8; 2] = [42u8, 43u8];
468        let addr = NetAddress::from_str(format!("{0}.{1}.3.4:5678", prefix_bytes[0], prefix_bytes[1]).as_str()).unwrap();
469        assert!(addr.prefix_bucket() == PrefixBucket(u16::from_be_bytes(prefix_bytes) as u64));
470    }
471
472    #[test]
473    fn test_contextual_address_ser() {
474        let addr = IpAddress::from_str("127.0.0.1").unwrap();
475        let port = Some(1234);
476        let net_addr = ContextualNetAddress::new(addr, port);
477        let s = serde_json::to_string(&net_addr).unwrap();
478        assert_eq!(s, r#"{"ip":"127.0.0.1","port":1234}"#);
479    }
480
481    #[test]
482    fn test_is_publicly_routable() {
483        // RFC 2544 tests
484        assert!(!IpAddress::from_str("198.18.0.0").unwrap().is_publicly_routable());
485        assert!(!IpAddress::from_str("198.19.255.255").unwrap().is_publicly_routable());
486        assert!(IpAddress::from_str("198.17.255.255").unwrap().is_publicly_routable());
487        assert!(IpAddress::from_str("198.20.0.0").unwrap().is_publicly_routable());
488
489        // Zero net tests
490        assert!(!IpAddress::from_str("0.0.0.0").unwrap().is_publicly_routable());
491        assert!(!IpAddress::from_str("0.0.0.1").unwrap().is_publicly_routable());
492        assert!(!IpAddress::from_str("0.0.1.0").unwrap().is_publicly_routable());
493        assert!(!IpAddress::from_str("0.1.0.0").unwrap().is_publicly_routable());
494
495        // RFC 3849
496        assert!(!IpAddress::from_str("2001:db8::").unwrap().is_publicly_routable());
497        assert!(!IpAddress::from_str("2001:db8:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
498        assert!(IpAddress::from_str("2001:db7:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
499        assert!(IpAddress::from_str("2001:db9::").unwrap().is_publicly_routable());
500
501        // Localhost
502        assert!(!IpAddress::from_str("127.0.0.1").unwrap().is_publicly_routable());
503
504        // Some random routable IP
505        assert!(IpAddress::from_str("123.45.67.89").unwrap().is_publicly_routable());
506
507        // RFC 1918
508        assert!(!IpAddress::from_str("10.0.0.0").unwrap().is_publicly_routable());
509        assert!(!IpAddress::from_str("10.255.255.255").unwrap().is_publicly_routable());
510        assert!(IpAddress::from_str("9.255.255.255").unwrap().is_publicly_routable());
511        assert!(IpAddress::from_str("11.0.0.0").unwrap().is_publicly_routable());
512
513        assert!(!IpAddress::from_str("172.16.0.0").unwrap().is_publicly_routable());
514        assert!(!IpAddress::from_str("172.31.255.255").unwrap().is_publicly_routable());
515        assert!(IpAddress::from_str("172.15.255.255").unwrap().is_publicly_routable());
516        assert!(IpAddress::from_str("172.32.0.0").unwrap().is_publicly_routable());
517
518        assert!(!IpAddress::from_str("192.168.0.0").unwrap().is_publicly_routable());
519        assert!(!IpAddress::from_str("192.168.255.255").unwrap().is_publicly_routable());
520        assert!(IpAddress::from_str("192.167.255.255").unwrap().is_publicly_routable());
521        assert!(IpAddress::from_str("192.169.0.0").unwrap().is_publicly_routable());
522
523        // RFC 3927
524        assert!(!IpAddress::from_str("169.254.0.0").unwrap().is_publicly_routable());
525        assert!(!IpAddress::from_str("169.254.255.255").unwrap().is_publicly_routable());
526        assert!(IpAddress::from_str("169.253.255.255").unwrap().is_publicly_routable());
527        assert!(IpAddress::from_str("169.255.0.0").unwrap().is_publicly_routable());
528
529        // RFC 3964
530        assert!(!IpAddress::from_str("2002::").unwrap().is_publicly_routable());
531        assert!(!IpAddress::from_str("2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
532        assert!(IpAddress::from_str("2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
533        assert!(IpAddress::from_str("2003::").unwrap().is_publicly_routable());
534
535        // RFC 4193
536        assert!(!IpAddress::from_str("fc00::").unwrap().is_publicly_routable());
537        assert!(!IpAddress::from_str("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
538        assert!(IpAddress::from_str("fb00:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
539        assert!(IpAddress::from_str("fe00::").unwrap().is_publicly_routable());
540
541        // RFC 4380
542        assert!(!IpAddress::from_str("2001::").unwrap().is_publicly_routable());
543        assert!(!IpAddress::from_str("2001:0:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
544        assert!(IpAddress::from_str("2000:0:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
545        assert!(IpAddress::from_str("2001:1::").unwrap().is_publicly_routable());
546
547        // RFC 4843
548        assert!(!IpAddress::from_str("2001:10::").unwrap().is_publicly_routable());
549        assert!(!IpAddress::from_str("2001:1f:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
550        assert!(IpAddress::from_str("2001:f:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
551        assert!(IpAddress::from_str("2001:20::").unwrap().is_publicly_routable());
552
553        // RFC 4862
554        assert!(!IpAddress::from_str("fe80::").unwrap().is_publicly_routable());
555        assert!(!IpAddress::from_str("fe80::ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
556        assert!(IpAddress::from_str("fe7f::ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
557        assert!(IpAddress::from_str("fe81::").unwrap().is_publicly_routable());
558
559        // RFC 5737
560        assert!(!IpAddress::from_str("192.0.2.0").unwrap().is_publicly_routable());
561        assert!(!IpAddress::from_str("192.0.2.255").unwrap().is_publicly_routable());
562        assert!(IpAddress::from_str("192.0.1.255").unwrap().is_publicly_routable());
563        assert!(IpAddress::from_str("192.0.3.0").unwrap().is_publicly_routable());
564
565        assert!(!IpAddress::from_str("198.51.100.0").unwrap().is_publicly_routable());
566        assert!(!IpAddress::from_str("198.51.100.255").unwrap().is_publicly_routable());
567        assert!(IpAddress::from_str("198.51.99.255").unwrap().is_publicly_routable());
568        assert!(IpAddress::from_str("198.51.101.0").unwrap().is_publicly_routable());
569
570        assert!(!IpAddress::from_str("203.0.113.0").unwrap().is_publicly_routable());
571        assert!(!IpAddress::from_str("203.0.113.255").unwrap().is_publicly_routable());
572        assert!(IpAddress::from_str("203.0.112.255").unwrap().is_publicly_routable());
573        assert!(IpAddress::from_str("203.0.114.0").unwrap().is_publicly_routable());
574
575        // RFC 6052
576        assert!(!IpAddress::from_str("64:ff9b::").unwrap().is_publicly_routable());
577        assert!(!IpAddress::from_str("64:ff9b::ffff:ffff").unwrap().is_publicly_routable());
578        assert!(IpAddress::from_str("64:ff9a::ffff:ffff").unwrap().is_publicly_routable());
579        assert!(IpAddress::from_str("64:ff9b:1::").unwrap().is_publicly_routable());
580
581        // RFC 6145
582        assert!(!IpAddress::from_str("::ffff:0:0:0").unwrap().is_publicly_routable());
583        assert!(!IpAddress::from_str("::ffff:0:ffff:ffff").unwrap().is_publicly_routable());
584        assert!(IpAddress::from_str("::fffe:0:ffff:ffff").unwrap().is_publicly_routable());
585        assert!(IpAddress::from_str("::ffff:1:0:0").unwrap().is_publicly_routable());
586
587        // RFC 6598
588        assert!(!IpAddress::from_str("100.64.0.0").unwrap().is_publicly_routable());
589        assert!(!IpAddress::from_str("100.127.255.255").unwrap().is_publicly_routable());
590        assert!(IpAddress::from_str("100.63.255.255").unwrap().is_publicly_routable());
591        assert!(IpAddress::from_str("100.128.0.0").unwrap().is_publicly_routable());
592
593        // Hurricane Electric IPv6 address block.
594        assert!(!IpAddress::from_str("2001:470::").unwrap().is_publicly_routable());
595        assert!(!IpAddress::from_str("2001:470:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
596        assert!(IpAddress::from_str("2001:46f:ffff:ffff:ffff:ffff:ffff:ffff").unwrap().is_publicly_routable());
597        assert!(IpAddress::from_str("2001:471::").unwrap().is_publicly_routable());
598
599        // Broadcast ip
600        assert!(!IpAddress::from_str("255.255.255.255").unwrap().is_publicly_routable());
601    }
602}