kaspa_utils/
networking.rs

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