ip/traits/
primitive.rs

1use core::borrow::{Borrow, BorrowMut};
2use core::fmt::{Binary, Debug, Display};
3use core::hash::Hash;
4use core::mem;
5use core::ops::{Add, BitAnd, BitOr, BitXor, Deref, DerefMut, Not, RangeInclusive, Shl, Shr, Sub};
6
7use bitvec::{slice::BitSlice, BitArr};
8use num_traits::CheckedAdd;
9
10use super::Afi;
11use crate::{
12    concrete::{Ipv4, Ipv6},
13    error::Error,
14    parser,
15};
16
17/// Underlying integer-like type used to represent an IP address.
18pub trait Address<A: Afi>:
19    Copy
20    + Debug
21    + Default
22    + Hash
23    + Ord
24    + BitAnd<Self, Output = Self>
25    + BitOr<Self, Output = Self>
26    + BitXor<Self, Output = Self>
27    + Add<Self, Output = Self>
28    + CheckedAdd
29    + Not<Output = Self>
30    + Shl<Self::Length, Output = Self>
31    + Shr<Self::Length, Output = Self>
32    + 'static
33{
34    /// Underlying primitive type used to store bit-widths of `Self`.
35    type Length: Length;
36
37    /// Underlying primitive type used to store bitmaps of prefix-lengths.
38    type LengthMap: LengthMap;
39
40    /// Minimum valid value of the underlying primitive value used to store
41    /// prefix-lengths for this address-family.
42    const MIN_LENGTH: Self::Length = Self::Length::ZERO;
43
44    /// Maximum valid value of the underlying primitive value used to store
45    /// prefix-lengths for this address-family.
46    const MAX_LENGTH: Self::Length;
47
48    /// "All-zeros" IP address representation.
49    const ZERO: Self;
50    /// "All-ones" IP address representation.
51    const ONES: Self;
52
53    /// The primitive value of the subnet-local broadcast address, if it is
54    /// defined for the address family.
55    const BROADCAST: Option<Self>;
56
57    /// The primitive value of the `localhost` address for this address family.
58    const LOCALHOST: Self;
59
60    /// The primitive value of the "unspecified" address for this address
61    /// family.
62    const UNSPECIFIED: Self;
63
64    /// The range of primitive address values defined for "loopback" use for
65    /// this address family.
66    const LOOPBACK_RANGE: RangeInclusive<Self>;
67
68    /// The range of primitive address values defined for "benchmarking" use for
69    /// this address family.
70    const BENCHMARK_RANGE: RangeInclusive<Self>;
71
72    /// The range of primitive address values defined for "multicast" use for
73    /// this address family.
74    const MULTICAST_RANGE: RangeInclusive<Self>;
75
76    /// The range of primitive address values defined for "link-local" use for
77    /// this address family.
78    const LINK_LOCAL_RANGE: RangeInclusive<Self>;
79
80    /// The range of primitive address values reserved for IETF protocol
81    /// assignments for this address family.
82    const PROTOCOL_ASSIGNMENTS_RANGE: RangeInclusive<Self>;
83
84    /// The range of primitive address values defined for "documentation" use
85    /// for this address family.
86    const DOCUMENTATION_RANGES: &'static [RangeInclusive<Self>];
87
88    /// The range of primitive address values defined for "private" use, if
89    /// that is defined for this address family.
90    const PRIVATE_RANGES: Option<&'static [RangeInclusive<Self>]>;
91
92    /// The range of primitive address values reserved for future use, if that
93    /// is defined for this address family.
94    const RESERVED_RANGE: Option<RangeInclusive<Self>>;
95
96    /// The range of primitive address values reserved for "shared" use, if that
97    /// is defined for this address family.
98    const SHARED_RANGE: Option<RangeInclusive<Self>>;
99
100    /// The range of primitive address values having "this network" semantics,
101    /// if that is defined for this address family.
102    const THISNET_RANGE: Option<RangeInclusive<Self>>;
103
104    /// The range of primitive address values defined as "unique local
105    /// addresses", if that is defined for this address family.
106    const ULA_RANGE: Option<RangeInclusive<Self>>;
107
108    /// Get the number of leading zeros in the binary representation of `self`.
109    fn leading_zeros(self) -> Self::Length;
110
111    /// Convert `self` to big-endian [`A::Octets`][Afi::Octets].
112    fn to_be_bytes(self) -> A::Octets;
113
114    /// Construct `Self` from big-endian [`A::Octets`][Afi::Octets].
115    fn from_be_bytes(bytes: A::Octets) -> Self;
116
117    // TODO: This really is a horrible hack. Will do better.
118    /// Returns [`true`] if this primitive value represents a "globally
119    /// routable" address, according to the address family semantics.
120    fn is_global(&self) -> bool;
121
122    /// Parse a string into [`Self`].
123    ///
124    /// This method is primarily intended for use via the
125    /// [`FromStr`][core::str::FromStr] implementation for
126    /// [`Address<A>`][crate::Address].
127    ///
128    /// # Errors
129    ///
130    /// Fails if the string does not conform to the textual address
131    /// representation rules for `A`.
132    fn parse_addr<S>(s: &S) -> Result<Self, Error>
133    where
134        S: AsRef<str> + ?Sized;
135
136    /// Parse a string into [`Self::Length`].
137    ///
138    /// This method is primarily intended for use via the
139    /// [`FromStr`][core::str::FromStr] implementation for
140    /// [`PrefixLength<A>`][crate::PrefixLength].
141    ///
142    /// # Errors
143    ///
144    /// Fails if the string does not conform to the textual address
145    /// representation rules for `A`.
146    fn parse_length<S>(s: &S) -> Result<Self::Length, Error>
147    where
148        S: AsRef<str> + ?Sized;
149
150    /// Parse a string into a `(Self, Self::Length>)`
151    /// pair.
152    ///
153    /// This method is primarily intended for use via the
154    /// [`FromStr`][core::str::FromStr] implementation for
155    /// [`Prefix<A>`][crate::Prefix].
156    ///
157    /// # Errors
158    ///
159    /// Fails if the string does not conform to the textual prefix
160    /// representation rules for `A`.
161    fn parse_prefix<S>(s: &S) -> Result<(Self, Self::Length), Error>
162    where
163        S: AsRef<str> + ?Sized;
164
165    /// Parse a string into a `(Self, Self::Length>, Self::Length,
166    /// Self::Length)` quad.
167    ///
168    /// This method is primarily intended for use via the
169    /// [`FromStr`][core::str::FromStr] implementation for
170    /// [`PrefixRange<A>`][crate::PrefixRange].
171    ///
172    /// # Errors
173    ///
174    /// Fails if the string does not conform to the textual prefix
175    /// representation rules for `A`.
176    #[allow(clippy::type_complexity)]
177    fn parse_range<S>(s: &S) -> Result<(Self, Self::Length, Self::Length, Self::Length), Error>
178    where
179        S: AsRef<str> + ?Sized;
180}
181
182macro_rules! ipv4 {
183    ($a:literal, $b:literal, $c:literal, $d:literal) => {
184        u32::from_be_bytes([$a, $b, $c, $d])
185    };
186}
187
188impl Address<Ipv4> for u32 {
189    type Length = u8;
190    type LengthMap = BitArr!(for 33);
191
192    const MAX_LENGTH: Self::Length = 32;
193    const ZERO: Self = ipv4!(0, 0, 0, 0);
194    const ONES: Self = ipv4!(255, 255, 255, 255);
195
196    const BROADCAST: Option<Self> = Some(ipv4!(255, 255, 255, 255));
197    const LOCALHOST: Self = ipv4!(127, 0, 0, 1);
198    const UNSPECIFIED: Self = ipv4!(0, 0, 0, 0);
199
200    const LOOPBACK_RANGE: RangeInclusive<Self> = ipv4!(127, 0, 0, 0)..=ipv4!(127, 255, 255, 255);
201    const BENCHMARK_RANGE: RangeInclusive<Self> = ipv4!(198, 18, 0, 0)..=ipv4!(198, 19, 255, 255);
202    const MULTICAST_RANGE: RangeInclusive<Self> = ipv4!(224, 0, 0, 0)..=ipv4!(239, 255, 255, 255);
203    const LINK_LOCAL_RANGE: RangeInclusive<Self> =
204        ipv4!(169, 254, 0, 0)..=ipv4!(169, 254, 255, 255);
205    const PROTOCOL_ASSIGNMENTS_RANGE: RangeInclusive<Self> =
206        ipv4!(192, 0, 0, 0)..=ipv4!(192, 0, 0, 255);
207    const DOCUMENTATION_RANGES: &'static [RangeInclusive<Self>] = &[
208        ipv4!(192, 0, 2, 0)..=ipv4!(192, 0, 2, 255),
209        ipv4!(198, 51, 100, 0)..=ipv4!(198, 51, 100, 255),
210        ipv4!(203, 0, 113, 0)..=ipv4!(203, 0, 113, 255),
211    ];
212    const PRIVATE_RANGES: Option<&'static [RangeInclusive<Self>]> = Some(&[
213        ipv4!(10, 0, 0, 0)..=ipv4!(10, 255, 255, 255),
214        ipv4!(172, 16, 0, 0)..=ipv4!(172, 31, 255, 255),
215        ipv4!(192, 168, 0, 0)..=ipv4!(192, 168, 255, 255),
216    ]);
217    const RESERVED_RANGE: Option<RangeInclusive<Self>> =
218        Some(ipv4!(240, 0, 0, 0)..=ipv4!(255, 255, 255, 255));
219    const SHARED_RANGE: Option<RangeInclusive<Self>> =
220        Some(ipv4!(100, 64, 0, 0)..=ipv4!(100, 127, 255, 255));
221    const THISNET_RANGE: Option<RangeInclusive<Self>> =
222        Some(ipv4!(0, 0, 0, 0)..=ipv4!(0, 255, 255, 255));
223    const ULA_RANGE: Option<RangeInclusive<Self>> = None;
224
225    #[allow(clippy::cast_possible_truncation)]
226    fn leading_zeros(self) -> Self::Length {
227        self.leading_zeros() as Self::Length
228    }
229
230    fn to_be_bytes(self) -> <Ipv4 as Afi>::Octets {
231        self.to_be_bytes()
232    }
233
234    // TODO: remove `allow` once https://github.com/rust-lang/rust-clippy/pull/8804
235    // is merged
236    #[allow(clippy::only_used_in_recursion)]
237    fn from_be_bytes(bytes: <Ipv4 as Afi>::Octets) -> Self {
238        Self::from_be_bytes(bytes)
239    }
240
241    fn is_global(&self) -> bool {
242        if Self::LOOPBACK_RANGE.contains(self)
243            || Self::LINK_LOCAL_RANGE.contains(self)
244            || Self::BENCHMARK_RANGE.contains(self)
245            || Self::DOCUMENTATION_RANGES
246                .iter()
247                .any(|range| range.contains(self))
248        {
249            return false;
250        }
251        if let Some(ref broadcast) = Self::BROADCAST {
252            if broadcast == self {
253                return false;
254            }
255        }
256        if let Some(ranges) = Self::PRIVATE_RANGES {
257            if ranges.iter().any(|range| range.contains(self)) {
258                return false;
259            }
260        }
261        if let Some(range) = Self::SHARED_RANGE {
262            if range.contains(self) {
263                return false;
264            }
265        }
266        if let Some(range) = Self::RESERVED_RANGE {
267            if range.contains(self) {
268                return false;
269            }
270        }
271        if let Some(range) = Self::THISNET_RANGE {
272            if range.contains(self) {
273                return false;
274            }
275        }
276        // non-global multicast
277        if Self::MULTICAST_RANGE.contains(self)
278            && !(ipv4!(224, 0, 1, 0)..=ipv4!(238, 255, 255, 255)).contains(self)
279        {
280            return false;
281        }
282        if Self::PROTOCOL_ASSIGNMENTS_RANGE.contains(self)
283            // Port Control Protocol Anycast
284            && self != &ipv4!(192, 0, 0, 9)
285            // TURN Anycast
286            && self != &ipv4!(192, 0, 0, 10)
287        {
288            return false;
289        }
290        true
291    }
292
293    fn parse_addr<S>(s: &S) -> Result<Self, Error>
294    where
295        S: AsRef<str> + ?Sized,
296    {
297        parser::ipv4::parse_addr(s.as_ref())
298    }
299
300    fn parse_length<S>(s: &S) -> Result<Self::Length, Error>
301    where
302        S: AsRef<str> + ?Sized,
303    {
304        parser::ipv4::parse_length(s.as_ref())
305    }
306
307    fn parse_prefix<S>(s: &S) -> Result<(Self, Self::Length), Error>
308    where
309        S: AsRef<str> + ?Sized,
310    {
311        parser::ipv4::parse_prefix(s.as_ref())
312    }
313
314    fn parse_range<S>(s: &S) -> Result<(Self, Self::Length, Self::Length, Self::Length), Error>
315    where
316        S: AsRef<str> + ?Sized,
317    {
318        parser::ipv4::parse_range(s.as_ref())
319    }
320}
321
322impl Address<Ipv6> for u128 {
323    type Length = u8;
324    type LengthMap = BitArr!(for 129);
325
326    const MAX_LENGTH: Self::Length = 128;
327    const ZERO: Self = 0x0000_0000_0000_0000_0000_0000_0000_0000;
328    const ONES: Self = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
329
330    const BROADCAST: Option<Self> = None;
331    const LOCALHOST: Self = 0x0000_0000_0000_0000_0000_0000_0000_0001;
332    const UNSPECIFIED: Self = Self::ZERO;
333
334    const LOOPBACK_RANGE: RangeInclusive<Self> = 0x1..=0x1;
335    const BENCHMARK_RANGE: RangeInclusive<Self> =
336        0x2001_0002_0000_0000_0000_0000_0000_0000..=0x2001_0002_0000_ffff_ffff_ffff_ffff_ffff;
337    const MULTICAST_RANGE: RangeInclusive<Self> =
338        0xff00_0000_0000_0000_0000_0000_0000_0000..=0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
339    const LINK_LOCAL_RANGE: RangeInclusive<Self> =
340        0xfe80_0000_0000_0000_0000_0000_0000_0000..=0xfebf_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
341    const PROTOCOL_ASSIGNMENTS_RANGE: RangeInclusive<Self> =
342        0x2001_0000_0000_0000_0000_0000_0000_0000..=0x2001_01ff_ffff_ffff_ffff_ffff_ffff_ffff;
343    const DOCUMENTATION_RANGES: &'static [RangeInclusive<Self>] =
344        &[(0x2001_0db8_0000_0000_0000_0000_0000_0000..=0x2001_0db8_ffff_ffff_ffff_ffff_ffff_ffff)];
345    const PRIVATE_RANGES: Option<&'static [RangeInclusive<Self>]> = None;
346    const RESERVED_RANGE: Option<RangeInclusive<Self>> = None;
347    const SHARED_RANGE: Option<RangeInclusive<Self>> = None;
348    const THISNET_RANGE: Option<RangeInclusive<Self>> = None;
349    const ULA_RANGE: Option<RangeInclusive<Self>> =
350        Some(0xfc00_0000_0000_0000_0000_0000_0000_0000..=0xfd00_0000_0000_0000_0000_0000_0000_0000);
351
352    #[allow(clippy::cast_possible_truncation)]
353    fn leading_zeros(self) -> Self::Length {
354        self.leading_zeros() as Self::Length
355    }
356
357    fn to_be_bytes(self) -> <Ipv6 as Afi>::Octets {
358        self.to_be_bytes()
359    }
360
361    fn from_be_bytes(bytes: <Ipv6 as Afi>::Octets) -> Self {
362        Self::from_be_bytes(bytes)
363    }
364
365    fn is_global(&self) -> bool {
366        if Self::LOOPBACK_RANGE.contains(self)
367            || Self::LINK_LOCAL_RANGE.contains(self)
368            || self == &Self::UNSPECIFIED
369            || Self::BENCHMARK_RANGE.contains(self)
370            || Self::DOCUMENTATION_RANGES
371                .iter()
372                .any(|range| range.contains(self))
373        {
374            return false;
375        }
376        if let Some(range) = Self::ULA_RANGE {
377            if range.contains(self) {
378                return false;
379            }
380        }
381        // non-global multicast
382        if Self::MULTICAST_RANGE.contains(self)
383            && self & 0x000f_0000_0000_0000_0000_0000_0000_0000
384                != 0x000e_0000_0000_0000_0000_0000_0000_0000
385        {
386            return false;
387        }
388        if Self::PROTOCOL_ASSIGNMENTS_RANGE.contains(self)
389            // TEREDO
390            && !(0x2001_0000_0000_0000_0000_0000_0000_0000..=0x2001_0000_ffff_ffff_ffff_ffff_ffff_ffff).contains(self)
391            // Port Control Protocol Anycast
392            && self != &0x2001_0001_0000_0000_0000_0000_0000_0001
393            // TURN Anycast
394            && self != &0x2001_0001_0000_0000_0000_0000_0000_0002
395            // AMT
396            && !(0x2001_0003_0000_0000_0000_0000_0000_0000..=0x2001_0003_ffff_ffff_ffff_ffff_ffff_ffff).contains(self)
397            // AS112
398            && !(0x2001_0004_0112_0000_0000_0000_0000_0000..=0x2001_0004_0112_ffff_ffff_ffff_ffff_ffff).contains(self)
399            // ORCHIDv2
400            && !(0x2001_0020_0000_0000_0000_0000_0000_0000..=0x2001_002f_ffff_ffff_ffff_ffff_ffff_ffff).contains(self)
401        {
402            return false;
403        }
404        true
405    }
406
407    fn parse_addr<S>(s: &S) -> Result<Self, Error>
408    where
409        S: AsRef<str> + ?Sized,
410    {
411        parser::ipv6::parse_addr(s.as_ref())
412    }
413
414    fn parse_length<S>(s: &S) -> Result<Self::Length, Error>
415    where
416        S: AsRef<str> + ?Sized,
417    {
418        parser::ipv6::parse_length(s.as_ref())
419    }
420
421    fn parse_prefix<S>(s: &S) -> Result<(Self, Self::Length), Error>
422    where
423        S: AsRef<str> + ?Sized,
424    {
425        parser::ipv6::parse_prefix(s.as_ref())
426    }
427
428    fn parse_range<S>(s: &S) -> Result<(Self, Self::Length, Self::Length, Self::Length), Error>
429    where
430        S: AsRef<str> + ?Sized,
431    {
432        parser::ipv6::parse_range(s.as_ref())
433    }
434}
435
436pub(crate) trait IntoIpv6Segments: Address<Ipv6> {
437    // TODO:
438    // const UNSPECIFIED_SEGMENTS: [u16; 8] = Self::UNSPECIFIED.into_segments();
439    // const LOCALHOST_SEGMENTS: [u16; 8] = Self::LOCALHOST.into_segments();
440
441    #[allow(unsafe_code)]
442    fn into_segments(self) -> [u16; 8] {
443        // Safety:
444        // it is always safe to transmute `[u8; 16]` to `[u16; 8]`
445        let [a, b, c, d, e, f, g, h]: [u16; 8] = unsafe { mem::transmute(self.to_be_bytes()) };
446        [
447            u16::from_be(a),
448            u16::from_be(b),
449            u16::from_be(c),
450            u16::from_be(d),
451            u16::from_be(e),
452            u16::from_be(f),
453            u16::from_be(g),
454            u16::from_be(h),
455        ]
456    }
457
458    #[allow(unsafe_code)]
459    #[allow(clippy::inline_always)]
460    #[inline(always)]
461    fn from_segments(segments: [u16; 8]) -> Self {
462        // Safety:
463        // it is always safe to transmute `[u16; 8]` to `[u8; 16]`
464        let octets = unsafe {
465            mem::transmute([
466                segments[0].to_be(),
467                segments[1].to_be(),
468                segments[2].to_be(),
469                segments[3].to_be(),
470                segments[4].to_be(),
471                segments[5].to_be(),
472                segments[6].to_be(),
473                segments[7].to_be(),
474            ])
475        };
476        Self::from_be_bytes(octets)
477    }
478}
479impl<P: Address<Ipv6>> IntoIpv6Segments for P {}
480
481/// Underlying byte-array like type used to represent the octets of an IP
482/// address.
483pub trait Octets: Borrow<[u8]> + BorrowMut<[u8]> {
484    /// The length of `Self`, in bytes.
485    const LENGTH: usize;
486
487    /// The zero-value of `Self`.
488    const ZEROS: Self;
489}
490
491impl<const N: usize> Octets for [u8; N] {
492    const LENGTH: usize = N;
493    const ZEROS: Self = [0; N];
494}
495
496/// Underlying integer-like type used to represent an IP prefix-length.
497pub trait Length:
498    Copy
499    + Clone
500    + Debug
501    + Display
502    + Hash
503    + Ord
504    + Add<Output = Self>
505    + Sub<Output = Self>
506    + Into<usize>
507    + TryFrom<usize>
508{
509    /// Additive identity value.
510    const ZERO: Self;
511    /// Additive unit value.
512    const ONE: Self;
513}
514
515impl Length for u8 {
516    const ZERO: Self = 0;
517    const ONE: Self = 1;
518}
519
520/// Underlying bit-vector-like type used to represent bitmaps of IP
521/// prefix-lengths.
522pub trait LengthMap:
523    Copy
524    + Binary
525    + BitAnd<Output = Self>
526    + BitOr<Output = Self>
527    + Not<Output = Self>
528    + Default
529    + Deref<Target = BitSlice>
530    + DerefMut<Target = BitSlice>
531    + Eq
532{
533    /// The all-zeros value of `Self`.
534    const ZERO: Self;
535}
536
537impl LengthMap for BitArr!(for 33) {
538    const ZERO: Self = Self::ZERO;
539}
540
541impl LengthMap for BitArr!(for 129) {
542    const ZERO: Self = Self::ZERO;
543}