diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:24 +0000 |
commit | 023939b627b7dc93b01471f7d41fb8553ddb4ffa (patch) | |
tree | 60fc59477c605c72b0a1051409062ddecc43f877 /vendor/ipnet/src | |
parent | Adding debian version 1.72.1+dfsg1-1. (diff) | |
download | rustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.tar.xz rustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.zip |
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ipnet/src')
-rw-r--r-- | vendor/ipnet/src/ipext.rs | 964 | ||||
-rw-r--r-- | vendor/ipnet/src/ipnet.rs | 1872 | ||||
-rw-r--r-- | vendor/ipnet/src/ipnet_schemars.rs | 86 | ||||
-rw-r--r-- | vendor/ipnet/src/ipnet_serde.rs | 276 | ||||
-rw-r--r-- | vendor/ipnet/src/lib.rs | 98 | ||||
-rw-r--r-- | vendor/ipnet/src/mask.rs | 128 | ||||
-rw-r--r-- | vendor/ipnet/src/parser.rs | 345 |
7 files changed, 3769 insertions, 0 deletions
diff --git a/vendor/ipnet/src/ipext.rs b/vendor/ipnet/src/ipext.rs new file mode 100644 index 000000000..aff793086 --- /dev/null +++ b/vendor/ipnet/src/ipext.rs @@ -0,0 +1,964 @@ +//! Extensions to the standard IP address types for common operations. +//! +//! The [`IpAdd`], [`IpSub`], [`IpBitAnd`], [`IpBitOr`] traits extend +//! the `Ipv4Addr` and `Ipv6Addr` types with methods to perform these +//! operations. + +use std::cmp::Ordering::{Less, Equal}; +use std::iter::{FusedIterator, DoubleEndedIterator}; +use std::mem; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + +/// Provides a `saturating_add()` method for `Ipv4Addr` and `Ipv6Addr`. +/// +/// Adding an integer to an IP address returns the modified IP address. +/// A `u32` may added to an IPv4 address and a `u128` may be added to +/// an IPv6 address. +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, Ipv6Addr}; +/// use ipnet::IpAdd; +/// +/// let ip0: Ipv4Addr = "192.168.0.0".parse().unwrap(); +/// let ip1: Ipv4Addr = "192.168.0.5".parse().unwrap(); +/// let ip2: Ipv4Addr = "255.255.255.254".parse().unwrap(); +/// let max: Ipv4Addr = "255.255.255.255".parse().unwrap(); +/// +/// assert_eq!(ip0.saturating_add(5), ip1); +/// assert_eq!(ip2.saturating_add(1), max); +/// assert_eq!(ip2.saturating_add(5), max); +/// +/// let ip0: Ipv6Addr = "fd00::".parse().unwrap(); +/// let ip1: Ipv6Addr = "fd00::5".parse().unwrap(); +/// let ip2: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe".parse().unwrap(); +/// let max: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); +/// +/// assert_eq!(ip0.saturating_add(5), ip1); +/// assert_eq!(ip2.saturating_add(1), max); +/// assert_eq!(ip2.saturating_add(5), max); +/// ``` +pub trait IpAdd<RHS = Self> { + type Output; + fn saturating_add(self, rhs: RHS) -> Self::Output; +} + +/// Provides a `saturating_sub()` method for `Ipv4Addr` and `Ipv6Addr`. +/// +/// Subtracting an integer from an IP address returns the modified IP +/// address. A `u32` may be subtracted from an IPv4 address and a `u128` +/// may be subtracted from an IPv6 address. +/// +/// Subtracting an IP address from another IP address of the same type +/// returns an integer of the appropriate width. A `u32` for IPv4 and a +/// `u128` for IPv6. Subtracting IP addresses is useful for getting +/// the range between two IP addresses. +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, Ipv6Addr}; +/// use ipnet::IpSub; +/// +/// let min: Ipv4Addr = "0.0.0.0".parse().unwrap(); +/// let ip1: Ipv4Addr = "192.168.1.5".parse().unwrap(); +/// let ip2: Ipv4Addr = "192.168.1.100".parse().unwrap(); +/// +/// assert_eq!(min.saturating_sub(ip1), 0); +/// assert_eq!(ip2.saturating_sub(ip1), 95); +/// assert_eq!(min.saturating_sub(5), min); +/// assert_eq!(ip2.saturating_sub(95), ip1); +/// +/// let min: Ipv6Addr = "::".parse().unwrap(); +/// let ip1: Ipv6Addr = "fd00::5".parse().unwrap(); +/// let ip2: Ipv6Addr = "fd00::64".parse().unwrap(); +/// +/// assert_eq!(min.saturating_sub(ip1), 0); +/// assert_eq!(ip2.saturating_sub(ip1), 95); +/// assert_eq!(min.saturating_sub(5u128), min); +/// assert_eq!(ip2.saturating_sub(95u128), ip1); +/// ``` +pub trait IpSub<RHS = Self> { + type Output; + fn saturating_sub(self, rhs: RHS) -> Self::Output; +} + +/// Provides a `bitand()` method for `Ipv4Addr` and `Ipv6Addr`. +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, Ipv6Addr}; +/// use ipnet::IpBitAnd; +/// +/// let ip: Ipv4Addr = "192.168.1.1".parse().unwrap(); +/// let mask: Ipv4Addr = "255.255.0.0".parse().unwrap(); +/// let res: Ipv4Addr = "192.168.0.0".parse().unwrap(); +/// +/// assert_eq!(ip.bitand(mask), res); +/// assert_eq!(ip.bitand(0xffff0000), res); +/// +/// let ip: Ipv6Addr = "fd00:1234::1".parse().unwrap(); +/// let mask: Ipv6Addr = "ffff::".parse().unwrap(); +/// let res: Ipv6Addr = "fd00::".parse().unwrap(); +/// +/// assert_eq!(ip.bitand(mask), res); +/// assert_eq!(ip.bitand(0xffff_0000_0000_0000_0000_0000_0000_0000u128), res); +/// ``` +pub trait IpBitAnd<RHS = Self> { + type Output; + fn bitand(self, rhs: RHS) -> Self::Output; +} + +/// Provides a `bitor()` method for `Ipv4Addr` and `Ipv6Addr`. +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, Ipv6Addr}; +/// use ipnet::IpBitOr; +/// +/// let ip: Ipv4Addr = "10.1.1.1".parse().unwrap(); +/// let mask: Ipv4Addr = "0.0.0.255".parse().unwrap(); +/// let res: Ipv4Addr = "10.1.1.255".parse().unwrap(); +/// +/// assert_eq!(ip.bitor(mask), res); +/// assert_eq!(ip.bitor(0x000000ff), res); +/// +/// let ip: Ipv6Addr = "fd00::1".parse().unwrap(); +/// let mask: Ipv6Addr = "::ffff:ffff".parse().unwrap(); +/// let res: Ipv6Addr = "fd00::ffff:ffff".parse().unwrap(); +/// +/// assert_eq!(ip.bitor(mask), res); +/// assert_eq!(ip.bitor(u128::from(0xffffffffu32)), res); +/// ``` +pub trait IpBitOr<RHS = Self> { + type Output; + fn bitor(self, rhs: RHS) -> Self::Output; +} + +macro_rules! ip_add_impl { + ($lhs:ty, $rhs:ty, $output:ty, $inner:ty) => ( + impl IpAdd<$rhs> for $lhs { + type Output = $output; + + fn saturating_add(self, rhs: $rhs) -> $output { + let lhs: $inner = self.into(); + let rhs: $inner = rhs.into(); + (lhs.saturating_add(rhs.into())).into() + } + } + ) +} + +macro_rules! ip_sub_impl { + ($lhs:ty, $rhs:ty, $output:ty, $inner:ty) => ( + impl IpSub<$rhs> for $lhs { + type Output = $output; + + fn saturating_sub(self, rhs: $rhs) -> $output { + let lhs: $inner = self.into(); + let rhs: $inner = rhs.into(); + (lhs.saturating_sub(rhs.into())).into() + } + } + ) +} + +ip_add_impl!(Ipv4Addr, u32, Ipv4Addr, u32); +ip_add_impl!(Ipv6Addr, u128, Ipv6Addr, u128); + +ip_sub_impl!(Ipv4Addr, Ipv4Addr, u32, u32); +ip_sub_impl!(Ipv4Addr, u32, Ipv4Addr, u32); +ip_sub_impl!(Ipv6Addr, Ipv6Addr, u128, u128); +ip_sub_impl!(Ipv6Addr, u128, Ipv6Addr, u128); + +macro_rules! ip_bitops_impl { + ($(($lhs:ty, $rhs:ty, $t:ty),)*) => { + $( + impl IpBitAnd<$rhs> for $lhs { + type Output = $lhs; + + fn bitand(self, rhs: $rhs) -> $lhs { + let lhs: $t = self.into(); + let rhs: $t = rhs.into(); + (lhs & rhs).into() + } + } + + impl IpBitOr<$rhs> for $lhs { + type Output = $lhs; + + fn bitor(self, rhs: $rhs) -> $lhs { + let lhs: $t = self.into(); + let rhs: $t = rhs.into(); + (lhs | rhs).into() + } + } + )* + } +} + +ip_bitops_impl! { + (Ipv4Addr, Ipv4Addr, u32), + (Ipv4Addr, u32, u32), + (Ipv6Addr, Ipv6Addr, u128), + (Ipv6Addr, u128, u128), +} + +// A barebones copy of the current unstable Step trait used by the +// IpAddrRange, Ipv4AddrRange, and Ipv6AddrRange types below, and the +// Subnets types in ipnet. +pub trait IpStep { + fn replace_one(&mut self) -> Self; + fn replace_zero(&mut self) -> Self; + fn add_one(&self) -> Self; + fn sub_one(&self) -> Self; +} + +impl IpStep for Ipv4Addr { + fn replace_one(&mut self) -> Self { + mem::replace(self, Ipv4Addr::new(0, 0, 0, 1)) + } + fn replace_zero(&mut self) -> Self { + mem::replace(self, Ipv4Addr::new(0, 0, 0, 0)) + } + fn add_one(&self) -> Self { + self.saturating_add(1) + } + fn sub_one(&self) -> Self { + self.saturating_sub(1) + } +} + +impl IpStep for Ipv6Addr { + fn replace_one(&mut self) -> Self { + mem::replace(self, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)) + } + fn replace_zero(&mut self) -> Self { + mem::replace(self, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)) + } + fn add_one(&self) -> Self { + self.saturating_add(1) + } + fn sub_one(&self) -> Self { + self.saturating_sub(1) + } +} + +/// An `Iterator` over a range of IP addresses, either IPv4 or IPv6. +/// +/// # Examples +/// +/// ``` +/// use std::net::IpAddr; +/// use ipnet::{IpAddrRange, Ipv4AddrRange, Ipv6AddrRange}; +/// +/// let hosts = IpAddrRange::from(Ipv4AddrRange::new( +/// "10.0.0.0".parse().unwrap(), +/// "10.0.0.3".parse().unwrap(), +/// )); +/// +/// assert_eq!(hosts.collect::<Vec<IpAddr>>(), vec![ +/// "10.0.0.0".parse::<IpAddr>().unwrap(), +/// "10.0.0.1".parse().unwrap(), +/// "10.0.0.2".parse().unwrap(), +/// "10.0.0.3".parse().unwrap(), +/// ]); +/// +/// let hosts = IpAddrRange::from(Ipv6AddrRange::new( +/// "fd00::".parse().unwrap(), +/// "fd00::3".parse().unwrap(), +/// )); +/// +/// assert_eq!(hosts.collect::<Vec<IpAddr>>(), vec![ +/// "fd00::0".parse::<IpAddr>().unwrap(), +/// "fd00::1".parse().unwrap(), +/// "fd00::2".parse().unwrap(), +/// "fd00::3".parse().unwrap(), +/// ]); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub enum IpAddrRange { + V4(Ipv4AddrRange), + V6(Ipv6AddrRange), +} + +/// An `Iterator` over a range of IPv4 addresses. +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// use ipnet::Ipv4AddrRange; +/// +/// let hosts = Ipv4AddrRange::new( +/// "10.0.0.0".parse().unwrap(), +/// "10.0.0.3".parse().unwrap(), +/// ); +/// +/// assert_eq!(hosts.collect::<Vec<Ipv4Addr>>(), vec![ +/// "10.0.0.0".parse::<Ipv4Addr>().unwrap(), +/// "10.0.0.1".parse().unwrap(), +/// "10.0.0.2".parse().unwrap(), +/// "10.0.0.3".parse().unwrap(), +/// ]); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Ipv4AddrRange { + start: Ipv4Addr, + end: Ipv4Addr, +} + +/// An `Iterator` over a range of IPv6 addresses. +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// use ipnet::Ipv6AddrRange; +/// +/// let hosts = Ipv6AddrRange::new( +/// "fd00::".parse().unwrap(), +/// "fd00::3".parse().unwrap(), +/// ); +/// +/// assert_eq!(hosts.collect::<Vec<Ipv6Addr>>(), vec![ +/// "fd00::".parse::<Ipv6Addr>().unwrap(), +/// "fd00::1".parse().unwrap(), +/// "fd00::2".parse().unwrap(), +/// "fd00::3".parse().unwrap(), +/// ]); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Ipv6AddrRange { + start: Ipv6Addr, + end: Ipv6Addr, +} + +impl From<Ipv4AddrRange> for IpAddrRange { + fn from(i: Ipv4AddrRange) -> IpAddrRange { + IpAddrRange::V4(i) + } +} + +impl From<Ipv6AddrRange> for IpAddrRange { + fn from(i: Ipv6AddrRange) -> IpAddrRange { + IpAddrRange::V6(i) + } +} + +impl Ipv4AddrRange { + pub fn new(start: Ipv4Addr, end: Ipv4Addr) -> Self { + Ipv4AddrRange { + start: start, + end: end, + } + } + /// Counts the number of Ipv4Addr in this range. + /// This method will never overflow or panic. + fn count_u64(&self) -> u64 { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let count: u32 = self.end.saturating_sub(self.start); + let count = count as u64 + 1; // Never overflows + count + }, + Some(Equal) => 1, + _ => 0, + } + } +} + +impl Ipv6AddrRange { + pub fn new(start: Ipv6Addr, end: Ipv6Addr) -> Self { + Ipv6AddrRange { + start: start, + end: end, + } + } + /// Counts the number of Ipv6Addr in this range. + /// This method may overflow or panic if start + /// is 0 and end is u128::MAX + fn count_u128(&self) -> u128 { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let count = self.end.saturating_sub(self.start); + // May overflow or panic + count + 1 + }, + Some(Equal) => 1, + _ => 0, + } + } + /// True only if count_u128 does not overflow + fn can_count_u128(&self) -> bool { + self.start != Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0) + || self.end != Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff) + } +} + +impl Iterator for IpAddrRange { + type Item = IpAddr; + + fn next(&mut self) -> Option<Self::Item> { + match *self { + IpAddrRange::V4(ref mut a) => a.next().map(IpAddr::V4), + IpAddrRange::V6(ref mut a) => a.next().map(IpAddr::V6), + } + } + + fn count(self) -> usize { + match self { + IpAddrRange::V4(a) => a.count(), + IpAddrRange::V6(a) => a.count(), + } + } + + fn last(self) -> Option<Self::Item> { + match self { + IpAddrRange::V4(a) => a.last().map(IpAddr::V4), + IpAddrRange::V6(a) => a.last().map(IpAddr::V6), + } + } + + fn max(self) -> Option<Self::Item> { + match self { + IpAddrRange::V4(a) => Iterator::max(a).map(IpAddr::V4), + IpAddrRange::V6(a) => Iterator::max(a).map(IpAddr::V6), + } + } + + fn min(self) -> Option<Self::Item> { + match self { + IpAddrRange::V4(a) => Iterator::min(a).map(IpAddr::V4), + IpAddrRange::V6(a) => Iterator::min(a).map(IpAddr::V6), + } + } + + fn nth(&mut self, n: usize) -> Option<Self::Item> { + match *self { + IpAddrRange::V4(ref mut a) => a.nth(n).map(IpAddr::V4), + IpAddrRange::V6(ref mut a) => a.nth(n).map(IpAddr::V6), + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + match *self { + IpAddrRange::V4(ref a) => a.size_hint(), + IpAddrRange::V6(ref a) => a.size_hint(), + } + } +} + +impl Iterator for Ipv4AddrRange { + type Item = Ipv4Addr; + + fn next(&mut self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let next = self.start.add_one(); + Some(mem::replace(&mut self.start, next)) + }, + Some(Equal) => { + self.end.replace_zero(); + Some(self.start.replace_one()) + }, + _ => None, + } + } + + #[allow(arithmetic_overflow)] + fn count(self) -> usize { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + // Adding one here might overflow u32. + // Instead, wait until after converted to usize + let count: u32 = self.end.saturating_sub(self.start); + + // usize might only be 16 bits, + // so need to explicitly check for overflow. + // 'usize::MAX as u32' is okay here - if usize is 64 bits, + // value truncates to u32::MAX + if count <= std::usize::MAX as u32 { + count as usize + 1 + // count overflows usize + } else { + // emulate standard overflow/panic behavior + std::usize::MAX + 2 + count as usize + } + }, + Some(Equal) => 1, + _ => 0 + } + } + + fn last(self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) | Some(Equal) => Some(self.end), + _ => None, + } + } + + fn max(self) -> Option<Self::Item> { + self.last() + } + + fn min(self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) | Some(Equal) => Some(self.start), + _ => None + } + } + + fn nth(&mut self, n: usize) -> Option<Self::Item> { + let n = n as u64; + let count = self.count_u64(); + if n >= count { + self.end.replace_zero(); + self.start.replace_one(); + None + } else if n == count - 1 { + self.start.replace_one(); + Some(self.end.replace_zero()) + } else { + let nth = self.start.saturating_add(n as u32); + self.start = nth.add_one(); + Some(nth) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.count_u64(); + if count > std::usize::MAX as u64 { + (std::usize::MAX, None) + } else { + let count = count as usize; + (count, Some(count)) + } + } +} + +impl Iterator for Ipv6AddrRange { + type Item = Ipv6Addr; + + fn next(&mut self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let next = self.start.add_one(); + Some(mem::replace(&mut self.start, next)) + }, + Some(Equal) => { + self.end.replace_zero(); + Some(self.start.replace_one()) + }, + _ => None, + } + } + + #[allow(arithmetic_overflow)] + fn count(self) -> usize { + let count = self.count_u128(); + // count fits in usize + if count <= std::usize::MAX as u128 { + count as usize + // count does not fit in usize + } else { + // emulate standard overflow/panic behavior + std::usize::MAX + 1 + count as usize + } + } + + fn last(self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) | Some(Equal) => Some(self.end), + _ => None, + } + } + + fn max(self) -> Option<Self::Item> { + self.last() + } + + fn min(self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) | Some(Equal) => Some(self.start), + _ => None + } + } + + fn nth(&mut self, n: usize) -> Option<Self::Item> { + let n = n as u128; + if self.can_count_u128() { + let count = self.count_u128(); + if n >= count { + self.end.replace_zero(); + self.start.replace_one(); + None + } else if n == count - 1 { + self.start.replace_one(); + Some(self.end.replace_zero()) + } else { + let nth = self.start.saturating_add(n); + self.start = nth.add_one(); + Some(nth) + } + // count overflows u128; n is 64-bits at most. + // therefore, n can never exceed count + } else { + let nth = self.start.saturating_add(n); + self.start = nth.add_one(); + Some(nth) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + if self.can_count_u128() { + let count = self.count_u128(); + if count > std::usize::MAX as u128 { + (std::usize::MAX, None) + } else { + let count = count as usize; + (count, Some(count)) + } + } else { + (std::usize::MAX, None) + } + } +} + +impl DoubleEndedIterator for IpAddrRange { + fn next_back(&mut self) -> Option<Self::Item> { + match *self { + IpAddrRange::V4(ref mut a) => a.next_back().map(IpAddr::V4), + IpAddrRange::V6(ref mut a) => a.next_back().map(IpAddr::V6), + } + } + fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + match *self { + IpAddrRange::V4(ref mut a) => a.nth_back(n).map(IpAddr::V4), + IpAddrRange::V6(ref mut a) => a.nth_back(n).map(IpAddr::V6), + } + } +} + +impl DoubleEndedIterator for Ipv4AddrRange { + fn next_back(&mut self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let next_back = self.end.sub_one(); + Some(mem::replace(&mut self.end, next_back)) + }, + Some(Equal) => { + self.end.replace_zero(); + Some(self.start.replace_one()) + }, + _ => None + } + } + fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + let n = n as u64; + let count = self.count_u64(); + if n >= count { + self.end.replace_zero(); + self.start.replace_one(); + None + } else if n == count - 1 { + self.end.replace_zero(); + Some(self.start.replace_one()) + } else { + let nth_back = self.end.saturating_sub(n as u32); + self.end = nth_back.sub_one(); + Some(nth_back) + } + } +} + +impl DoubleEndedIterator for Ipv6AddrRange { + fn next_back(&mut self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let next_back = self.end.sub_one(); + Some(mem::replace(&mut self.end, next_back)) + }, + Some(Equal) => { + self.end.replace_zero(); + Some(self.start.replace_one()) + }, + _ => None + } + } + fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + let n = n as u128; + if self.can_count_u128() { + let count = self.count_u128(); + if n >= count { + self.end.replace_zero(); + self.start.replace_one(); + None + } + else if n == count - 1 { + self.end.replace_zero(); + Some(self.start.replace_one()) + } else { + let nth_back = self.end.saturating_sub(n); + self.end = nth_back.sub_one(); + Some(nth_back) + } + // count overflows u128; n is 64-bits at most. + // therefore, n can never exceed count + } else { + let nth_back = self.end.saturating_sub(n); + self.end = nth_back.sub_one(); + Some(nth_back) + } + } +} + +impl FusedIterator for IpAddrRange {} +impl FusedIterator for Ipv4AddrRange {} +impl FusedIterator for Ipv6AddrRange {} + +#[cfg(test)] +mod tests { + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + use std::str::FromStr; + use super::*; + + #[test] + fn test_ipaddrrange() { + // Next, Next-Back + let i = Ipv4AddrRange::new( + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap() + ); + + assert_eq!(i.collect::<Vec<Ipv4Addr>>(), vec![ + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.1").unwrap(), + Ipv4Addr::from_str("10.0.0.2").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap(), + ]); + + let mut v = i.collect::<Vec<_>>(); + v.reverse(); + assert_eq!(v, i.rev().collect::<Vec<_>>()); + + let i = Ipv4AddrRange::new( + Ipv4Addr::from_str("255.255.255.254").unwrap(), + Ipv4Addr::from_str("255.255.255.255").unwrap() + ); + + assert_eq!(i.collect::<Vec<Ipv4Addr>>(), vec![ + Ipv4Addr::from_str("255.255.255.254").unwrap(), + Ipv4Addr::from_str("255.255.255.255").unwrap(), + ]); + + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + ); + + assert_eq!(i.collect::<Vec<Ipv6Addr>>(), vec![ + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::1").unwrap(), + Ipv6Addr::from_str("fd00::2").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + ]); + + let mut v = i.collect::<Vec<_>>(); + v.reverse(); + assert_eq!(v, i.rev().collect::<Vec<_>>()); + + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), + Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), + ); + + assert_eq!(i.collect::<Vec<Ipv6Addr>>(), vec![ + Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), + Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), + ]); + + let i = IpAddrRange::from(Ipv4AddrRange::new( + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap(), + )); + + assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ + IpAddr::from_str("10.0.0.0").unwrap(), + IpAddr::from_str("10.0.0.1").unwrap(), + IpAddr::from_str("10.0.0.2").unwrap(), + IpAddr::from_str("10.0.0.3").unwrap(), + ]); + + let mut v = i.collect::<Vec<_>>(); + v.reverse(); + assert_eq!(v, i.rev().collect::<Vec<_>>()); + + let i = IpAddrRange::from(Ipv4AddrRange::new( + Ipv4Addr::from_str("255.255.255.254").unwrap(), + Ipv4Addr::from_str("255.255.255.255").unwrap() + )); + + assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ + IpAddr::from_str("255.255.255.254").unwrap(), + IpAddr::from_str("255.255.255.255").unwrap(), + ]); + + let i = IpAddrRange::from(Ipv6AddrRange::new( + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + )); + + assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ + IpAddr::from_str("fd00::").unwrap(), + IpAddr::from_str("fd00::1").unwrap(), + IpAddr::from_str("fd00::2").unwrap(), + IpAddr::from_str("fd00::3").unwrap(), + ]); + + let mut v = i.collect::<Vec<_>>(); + v.reverse(); + assert_eq!(v, i.rev().collect::<Vec<_>>()); + + let i = IpAddrRange::from(Ipv6AddrRange::new( + Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), + Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), + )); + + assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ + IpAddr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), + IpAddr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), + ]); + + // #11 (infinite iterator when start and stop are 0) + let zero4 = Ipv4Addr::from_str("0.0.0.0").unwrap(); + let zero6 = Ipv6Addr::from_str("::").unwrap(); + + let mut i = Ipv4AddrRange::new(zero4, zero4); + assert_eq!(Some(zero4), i.next()); + assert_eq!(None, i.next()); + + let mut i = Ipv6AddrRange::new(zero6, zero6); + assert_eq!(Some(zero6), i.next()); + assert_eq!(None, i.next()); + + // Count + let i = Ipv4AddrRange::new( + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap() + ); + assert_eq!(i.count(), 4); + + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + ); + assert_eq!(i.count(), 4); + + // Size Hint + let i = Ipv4AddrRange::new( + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap() + ); + assert_eq!(i.size_hint(), (4, Some(4))); + + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + ); + assert_eq!(i.size_hint(), (4, Some(4))); + + // Size Hint: a range where size clearly overflows usize + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("::").unwrap(), + Ipv6Addr::from_str("8000::").unwrap(), + ); + assert_eq!(i.size_hint(), (std::usize::MAX, None)); + + // Min, Max, Last + let i = Ipv4AddrRange::new( + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap() + ); + assert_eq!(Iterator::min(i), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); + assert_eq!(Iterator::max(i), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); + assert_eq!(i.last(), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); + + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + ); + assert_eq!(Iterator::min(i), Some(Ipv6Addr::from_str("fd00::").unwrap())); + assert_eq!(Iterator::max(i), Some(Ipv6Addr::from_str("fd00::3").unwrap())); + assert_eq!(i.last(), Some(Ipv6Addr::from_str("fd00::3").unwrap())); + + // Nth + let i = Ipv4AddrRange::new( + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap() + ); + assert_eq!(i.clone().nth(0), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); + assert_eq!(i.clone().nth(3), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); + assert_eq!(i.clone().nth(4), None); + assert_eq!(i.clone().nth(99), None); + let mut i2 = i.clone(); + assert_eq!(i2.nth(1), Some(Ipv4Addr::from_str("10.0.0.1").unwrap())); + assert_eq!(i2.nth(1), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); + assert_eq!(i2.nth(0), None); + let mut i3 = i.clone(); + assert_eq!(i3.nth(99), None); + assert_eq!(i3.next(), None); + + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + ); + assert_eq!(i.clone().nth(0), Some(Ipv6Addr::from_str("fd00::").unwrap())); + assert_eq!(i.clone().nth(3), Some(Ipv6Addr::from_str("fd00::3").unwrap())); + assert_eq!(i.clone().nth(4), None); + assert_eq!(i.clone().nth(99), None); + let mut i2 = i.clone(); + assert_eq!(i2.nth(1), Some(Ipv6Addr::from_str("fd00::1").unwrap())); + assert_eq!(i2.nth(1), Some(Ipv6Addr::from_str("fd00::3").unwrap())); + assert_eq!(i2.nth(0), None); + let mut i3 = i.clone(); + assert_eq!(i3.nth(99), None); + assert_eq!(i3.next(), None); + + // Nth Back + let i = Ipv4AddrRange::new( + Ipv4Addr::from_str("10.0.0.0").unwrap(), + Ipv4Addr::from_str("10.0.0.3").unwrap() + ); + assert_eq!(i.clone().nth_back(0), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); + assert_eq!(i.clone().nth_back(3), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); + assert_eq!(i.clone().nth_back(4), None); + assert_eq!(i.clone().nth_back(99), None); + let mut i2 = i.clone(); + assert_eq!(i2.nth_back(1), Some(Ipv4Addr::from_str("10.0.0.2").unwrap())); + assert_eq!(i2.nth_back(1), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); + assert_eq!(i2.nth_back(0), None); + let mut i3 = i.clone(); + assert_eq!(i3.nth_back(99), None); + assert_eq!(i3.next(), None); + + let i = Ipv6AddrRange::new( + Ipv6Addr::from_str("fd00::").unwrap(), + Ipv6Addr::from_str("fd00::3").unwrap(), + ); + assert_eq!(i.clone().nth_back(0), Some(Ipv6Addr::from_str("fd00::3").unwrap())); + assert_eq!(i.clone().nth_back(3), Some(Ipv6Addr::from_str("fd00::").unwrap())); + assert_eq!(i.clone().nth_back(4), None); + assert_eq!(i.clone().nth_back(99), None); + let mut i2 = i.clone(); + assert_eq!(i2.nth_back(1), Some(Ipv6Addr::from_str("fd00::2").unwrap())); + assert_eq!(i2.nth_back(1), Some(Ipv6Addr::from_str("fd00::").unwrap())); + assert_eq!(i2.nth_back(0), None); + let mut i3 = i.clone(); + assert_eq!(i3.nth_back(99), None); + assert_eq!(i3.next(), None); + } +} diff --git a/vendor/ipnet/src/ipnet.rs b/vendor/ipnet/src/ipnet.rs new file mode 100644 index 000000000..e190f0669 --- /dev/null +++ b/vendor/ipnet/src/ipnet.rs @@ -0,0 +1,1872 @@ +use std::cmp::{min, max}; +use std::cmp::Ordering::{Less, Equal}; +use std::convert::From; +use std::error::Error; +use std::fmt; +use std::iter::FusedIterator; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::option::Option::{Some, None}; + +use crate::ipext::{IpAdd, IpSub, IpStep, IpAddrRange, Ipv4AddrRange, Ipv6AddrRange}; +use crate::mask::{ip_mask_to_prefix, ipv4_mask_to_prefix, ipv6_mask_to_prefix}; + +/// An IP network address, either IPv4 or IPv6. +/// +/// This enum can contain either an [`Ipv4Net`] or an [`Ipv6Net`]. A +/// [`From`] implementation is provided to convert these into an +/// `IpNet`. +/// +/// # Textual representation +/// +/// `IpNet` provides a [`FromStr`] implementation for parsing network +/// addresses represented in CIDR notation. See [IETF RFC 4632] for the +/// CIDR notation. +/// +/// [`Ipv4Net`]: struct.Ipv4Net.html +/// [`Ipv6Net`]: struct.Ipv6Net.html +/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [IETF RFC 4632]: https://tools.ietf.org/html/rfc4632 +/// +/// # Examples +/// +/// ``` +/// use std::net::IpAddr; +/// use ipnet::IpNet; +/// +/// let net: IpNet = "10.1.1.0/24".parse().unwrap(); +/// assert_eq!(Ok(net.network()), "10.1.1.0".parse()); +/// +/// let net: IpNet = "fd00::/32".parse().unwrap(); +/// assert_eq!(Ok(net.network()), "fd00::".parse()); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum IpNet { + V4(Ipv4Net), + V6(Ipv6Net), +} + +/// An IPv4 network address. +/// +/// See [`IpNet`] for a type encompassing both IPv4 and IPv6 network +/// addresses. +/// +/// # Textual representation +/// +/// `Ipv4Net` provides a [`FromStr`] implementation for parsing network +/// addresses represented in CIDR notation. See [IETF RFC 4632] for the +/// CIDR notation. +/// +/// [`IpNet`]: enum.IpNet.html +/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [IETF RFC 4632]: https://tools.ietf.org/html/rfc4632 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// use ipnet::Ipv4Net; +/// +/// let net: Ipv4Net = "10.1.1.0/24".parse().unwrap(); +/// assert_eq!(Ok(net.network()), "10.1.1.0".parse()); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Ipv4Net { + addr: Ipv4Addr, + prefix_len: u8, +} + +/// An IPv6 network address. +/// +/// See [`IpNet`] for a type encompassing both IPv4 and IPv6 network +/// addresses. +/// +/// # Textual representation +/// +/// `Ipv6Net` provides a [`FromStr`] implementation for parsing network +/// addresses represented in CIDR notation. See [IETF RFC 4632] for the +/// CIDR notation. +/// +/// [`IpNet`]: enum.IpNet.html +/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [IETF RFC 4632]: https://tools.ietf.org/html/rfc4632 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// use ipnet::Ipv6Net; +/// +/// let net: Ipv6Net = "fd00::/32".parse().unwrap(); +/// assert_eq!(Ok(net.network()), "fd00::".parse()); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Ipv6Net { + addr: Ipv6Addr, + prefix_len: u8, +} + +/// An error which can be returned when the prefix length is invalid. +/// +/// Valid prefix lengths are 0 to 32 for IPv4 and 0 to 128 for IPv6. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PrefixLenError; + +impl fmt::Display for PrefixLenError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str("invalid IP prefix length") + } +} + +impl Error for PrefixLenError {} + +impl IpNet { + /// Creates a new IP network address from an `IpAddr` and prefix + /// length. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// use ipnet::{IpNet, PrefixLenError}; + /// + /// let net = IpNet::new(Ipv6Addr::LOCALHOST.into(), 48); + /// assert!(net.is_ok()); + /// + /// let bad_prefix_len = IpNet::new(Ipv6Addr::LOCALHOST.into(), 129); + /// assert_eq!(bad_prefix_len, Err(PrefixLenError)); + /// ``` + pub fn new(ip: IpAddr, prefix_len: u8) -> Result<IpNet, PrefixLenError> { + Ok(match ip { + IpAddr::V4(a) => Ipv4Net::new(a, prefix_len)?.into(), + IpAddr::V6(a) => Ipv6Net::new(a, prefix_len)?.into(), + }) + } + + /// Creates a new IP network address from an `IpAddr` and netmask. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// use ipnet::{IpNet, PrefixLenError}; + /// + /// let net = IpNet::with_netmask(Ipv6Addr::LOCALHOST.into(), Ipv6Addr::from(0xffff_ffff_ffff_0000_0000_0000_0000_0000).into()); + /// assert!(net.is_ok()); + /// + /// let bad_prefix_len = IpNet::with_netmask(Ipv6Addr::LOCALHOST.into(), Ipv6Addr::from(0xffff_ffff_ffff_0000_0001_0000_0000_0000).into()); + /// assert_eq!(bad_prefix_len, Err(PrefixLenError)); + /// ``` + pub fn with_netmask(ip: IpAddr, netmask: IpAddr) -> Result<IpNet, PrefixLenError> { + let prefix = ip_mask_to_prefix(netmask)?; + Self::new(ip, prefix) + } + + /// Returns a copy of the network with the address truncated to the + /// prefix length. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::IpNet; + /// # + /// assert_eq!( + /// "192.168.12.34/16".parse::<IpNet>().unwrap().trunc(), + /// "192.168.0.0/16".parse().unwrap() + /// ); + /// + /// assert_eq!( + /// "fd00::1:2:3:4/16".parse::<IpNet>().unwrap().trunc(), + /// "fd00::/16".parse().unwrap() + /// ); + /// ``` + pub fn trunc(&self) -> IpNet { + match *self { + IpNet::V4(ref a) => IpNet::V4(a.trunc()), + IpNet::V6(ref a) => IpNet::V6(a.trunc()), + } + } + + /// Returns the address. + pub fn addr(&self) -> IpAddr { + match *self { + IpNet::V4(ref a) => IpAddr::V4(a.addr), + IpNet::V6(ref a) => IpAddr::V6(a.addr), + } + } + + /// Returns the prefix length. + pub fn prefix_len(&self) -> u8 { + match *self { + IpNet::V4(ref a) => a.prefix_len(), + IpNet::V6(ref a) => a.prefix_len(), + } + } + + /// Returns the maximum valid prefix length. + pub fn max_prefix_len(&self) -> u8 { + match *self { + IpNet::V4(ref a) => a.max_prefix_len(), + IpNet::V6(ref a) => a.max_prefix_len(), + } + } + + /// Returns the network mask. + /// + /// # Examples + /// + /// ``` + /// # use std::net::IpAddr; + /// # use ipnet::IpNet; + /// # + /// let net: IpNet = "10.1.0.0/20".parse().unwrap(); + /// assert_eq!(Ok(net.netmask()), "255.255.240.0".parse()); + /// + /// let net: IpNet = "fd00::/24".parse().unwrap(); + /// assert_eq!(Ok(net.netmask()), "ffff:ff00::".parse()); + /// ``` + pub fn netmask(&self) -> IpAddr { + match *self { + IpNet::V4(ref a) => IpAddr::V4(a.netmask()), + IpNet::V6(ref a) => IpAddr::V6(a.netmask()), + } + } + + /// Returns the host mask. + /// + /// # Examples + /// + /// ``` + /// # use std::net::IpAddr; + /// # use ipnet::IpNet; + /// # + /// let net: IpNet = "10.1.0.0/20".parse().unwrap(); + /// assert_eq!(Ok(net.hostmask()), "0.0.15.255".parse()); + /// + /// let net: IpNet = "fd00::/24".parse().unwrap(); + /// assert_eq!(Ok(net.hostmask()), "::ff:ffff:ffff:ffff:ffff:ffff:ffff".parse()); + /// ``` + pub fn hostmask(&self) -> IpAddr { + match *self { + IpNet::V4(ref a) => IpAddr::V4(a.hostmask()), + IpNet::V6(ref a) => IpAddr::V6(a.hostmask()), + } + } + + /// Returns the network address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::IpAddr; + /// # use ipnet::IpNet; + /// # + /// let net: IpNet = "172.16.123.123/16".parse().unwrap(); + /// assert_eq!(Ok(net.network()), "172.16.0.0".parse()); + /// + /// let net: IpNet = "fd00:1234:5678::/24".parse().unwrap(); + /// assert_eq!(Ok(net.network()), "fd00:1200::".parse()); + /// ``` + pub fn network(&self) -> IpAddr { + match *self { + IpNet::V4(ref a) => IpAddr::V4(a.network()), + IpNet::V6(ref a) => IpAddr::V6(a.network()), + } + } + + /// Returns the broadcast address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::IpAddr; + /// # use ipnet::IpNet; + /// # + /// let net: IpNet = "172.16.0.0/22".parse().unwrap(); + /// assert_eq!(Ok(net.broadcast()), "172.16.3.255".parse()); + /// + /// let net: IpNet = "fd00:1234:5678::/24".parse().unwrap(); + /// assert_eq!(Ok(net.broadcast()), "fd00:12ff:ffff:ffff:ffff:ffff:ffff:ffff".parse()); + /// ``` + pub fn broadcast(&self) -> IpAddr { + match *self { + IpNet::V4(ref a) => IpAddr::V4(a.broadcast()), + IpNet::V6(ref a) => IpAddr::V6(a.broadcast()), + } + } + + /// Returns the `IpNet` that contains this one. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::IpNet; + /// # + /// let n1: IpNet = "172.16.1.0/24".parse().unwrap(); + /// let n2: IpNet = "172.16.0.0/23".parse().unwrap(); + /// let n3: IpNet = "172.16.0.0/0".parse().unwrap(); + /// + /// assert_eq!(n1.supernet().unwrap(), n2); + /// assert_eq!(n3.supernet(), None); + /// + /// let n1: IpNet = "fd00:ff00::/24".parse().unwrap(); + /// let n2: IpNet = "fd00:fe00::/23".parse().unwrap(); + /// let n3: IpNet = "fd00:fe00::/0".parse().unwrap(); + /// + /// assert_eq!(n1.supernet().unwrap(), n2); + /// assert_eq!(n3.supernet(), None); + /// ``` + pub fn supernet(&self) -> Option<IpNet> { + match *self { + IpNet::V4(ref a) => a.supernet().map(IpNet::V4), + IpNet::V6(ref a) => a.supernet().map(IpNet::V6), + } + } + + /// Returns `true` if this network and the given network are + /// children of the same supernet. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::IpNet; + /// # + /// let n4_1: IpNet = "10.1.0.0/24".parse().unwrap(); + /// let n4_2: IpNet = "10.1.1.0/24".parse().unwrap(); + /// let n4_3: IpNet = "10.1.2.0/24".parse().unwrap(); + /// let n6_1: IpNet = "fd00::/18".parse().unwrap(); + /// let n6_2: IpNet = "fd00:4000::/18".parse().unwrap(); + /// let n6_3: IpNet = "fd00:8000::/18".parse().unwrap(); + /// + /// assert!( n4_1.is_sibling(&n4_2)); + /// assert!(!n4_2.is_sibling(&n4_3)); + /// assert!( n6_1.is_sibling(&n6_2)); + /// assert!(!n6_2.is_sibling(&n6_3)); + /// assert!(!n4_1.is_sibling(&n6_2)); + /// ``` + pub fn is_sibling(&self, other: &IpNet) -> bool { + match (*self, *other) { + (IpNet::V4(ref a), IpNet::V4(ref b)) => a.is_sibling(b), + (IpNet::V6(ref a), IpNet::V6(ref b)) => a.is_sibling(b), + _ => false, + } + } + + /// Return an `Iterator` over the host addresses in this network. + /// + /// # Examples + /// + /// ``` + /// # use std::net::IpAddr; + /// # use ipnet::IpNet; + /// # + /// let net: IpNet = "10.0.0.0/30".parse().unwrap(); + /// assert_eq!(net.hosts().collect::<Vec<IpAddr>>(), vec![ + /// "10.0.0.1".parse::<IpAddr>().unwrap(), + /// "10.0.0.2".parse().unwrap(), + /// ]); + /// + /// let net: IpNet = "10.0.0.0/31".parse().unwrap(); + /// assert_eq!(net.hosts().collect::<Vec<IpAddr>>(), vec![ + /// "10.0.0.0".parse::<IpAddr>().unwrap(), + /// "10.0.0.1".parse().unwrap(), + /// ]); + /// + /// let net: IpNet = "fd00::/126".parse().unwrap(); + /// assert_eq!(net.hosts().collect::<Vec<IpAddr>>(), vec![ + /// "fd00::".parse::<IpAddr>().unwrap(), + /// "fd00::1".parse().unwrap(), + /// "fd00::2".parse().unwrap(), + /// "fd00::3".parse().unwrap(), + /// ]); + /// ``` + pub fn hosts(&self) -> IpAddrRange { + match *self { + IpNet::V4(ref a) => IpAddrRange::V4(a.hosts()), + IpNet::V6(ref a) => IpAddrRange::V6(a.hosts()), + } + } + + /// Returns an `Iterator` over the subnets of this network with the + /// given prefix length. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::{IpNet, PrefixLenError}; + /// # + /// let net: IpNet = "10.0.0.0/24".parse().unwrap(); + /// assert_eq!(net.subnets(26).unwrap().collect::<Vec<IpNet>>(), vec![ + /// "10.0.0.0/26".parse::<IpNet>().unwrap(), + /// "10.0.0.64/26".parse().unwrap(), + /// "10.0.0.128/26".parse().unwrap(), + /// "10.0.0.192/26".parse().unwrap(), + /// ]); + /// + /// let net: IpNet = "fd00::/16".parse().unwrap(); + /// assert_eq!(net.subnets(18).unwrap().collect::<Vec<IpNet>>(), vec![ + /// "fd00::/18".parse::<IpNet>().unwrap(), + /// "fd00:4000::/18".parse().unwrap(), + /// "fd00:8000::/18".parse().unwrap(), + /// "fd00:c000::/18".parse().unwrap(), + /// ]); + /// + /// let net: IpNet = "10.0.0.0/24".parse().unwrap(); + /// assert_eq!(net.subnets(23), Err(PrefixLenError)); + /// + /// let net: IpNet = "10.0.0.0/24".parse().unwrap(); + /// assert_eq!(net.subnets(33), Err(PrefixLenError)); + /// + /// let net: IpNet = "fd00::/16".parse().unwrap(); + /// assert_eq!(net.subnets(15), Err(PrefixLenError)); + /// + /// let net: IpNet = "fd00::/16".parse().unwrap(); + /// assert_eq!(net.subnets(129), Err(PrefixLenError)); + /// ``` + pub fn subnets(&self, new_prefix_len: u8) -> Result<IpSubnets, PrefixLenError> { + match *self { + IpNet::V4(ref a) => a.subnets(new_prefix_len).map(IpSubnets::V4), + IpNet::V6(ref a) => a.subnets(new_prefix_len).map(IpSubnets::V6), + } + } + + /// Test if a network address contains either another network + /// address or an IP address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::IpAddr; + /// # use ipnet::IpNet; + /// # + /// let net4: IpNet = "192.168.0.0/24".parse().unwrap(); + /// let net4_yes: IpNet = "192.168.0.0/25".parse().unwrap(); + /// let net4_no: IpNet = "192.168.0.0/23".parse().unwrap(); + /// let ip4_yes: IpAddr = "192.168.0.1".parse().unwrap(); + /// let ip4_no: IpAddr = "192.168.1.0".parse().unwrap(); + /// + /// assert!(net4.contains(&net4)); + /// assert!(net4.contains(&net4_yes)); + /// assert!(!net4.contains(&net4_no)); + /// assert!(net4.contains(&ip4_yes)); + /// assert!(!net4.contains(&ip4_no)); + /// + /// + /// let net6: IpNet = "fd00::/16".parse().unwrap(); + /// let net6_yes: IpNet = "fd00::/17".parse().unwrap(); + /// let net6_no: IpNet = "fd00::/15".parse().unwrap(); + /// let ip6_yes: IpAddr = "fd00::1".parse().unwrap(); + /// let ip6_no: IpAddr = "fd01::".parse().unwrap(); + /// + /// assert!(net6.contains(&net6)); + /// assert!(net6.contains(&net6_yes)); + /// assert!(!net6.contains(&net6_no)); + /// assert!(net6.contains(&ip6_yes)); + /// assert!(!net6.contains(&ip6_no)); + /// + /// assert!(!net4.contains(&net6)); + /// assert!(!net6.contains(&net4)); + /// assert!(!net4.contains(&ip6_no)); + /// assert!(!net6.contains(&ip4_no)); + /// ``` + pub fn contains<T>(&self, other: T) -> bool where Self: Contains<T> { + Contains::contains(self, other) + } + + /// Aggregate a `Vec` of `IpNet`s and return the result as a new + /// `Vec`. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::IpNet; + /// # + /// let nets = vec![ + /// "10.0.0.0/24".parse::<IpNet>().unwrap(), + /// "10.0.1.0/24".parse().unwrap(), + /// "10.0.2.0/24".parse().unwrap(), + /// "fd00::/18".parse().unwrap(), + /// "fd00:4000::/18".parse().unwrap(), + /// "fd00:8000::/18".parse().unwrap(), + /// ]; + /// + /// assert_eq!(IpNet::aggregate(&nets), vec![ + /// "10.0.0.0/23".parse::<IpNet>().unwrap(), + /// "10.0.2.0/24".parse().unwrap(), + /// "fd00::/17".parse().unwrap(), + /// "fd00:8000::/18".parse().unwrap(), + /// ]); + /// ``` + pub fn aggregate(networks: &Vec<IpNet>) -> Vec<IpNet> { + // It's 2.5x faster to split the input up and run them using the + // specific IPv4 and IPV6 implementations. merge_intervals() and + // the comparisons are much faster running over integers. + let mut ipv4nets: Vec<Ipv4Net> = Vec::new(); + let mut ipv6nets: Vec<Ipv6Net> = Vec::new(); + + for n in networks { + match *n { + IpNet::V4(x) => ipv4nets.push(x), + IpNet::V6(x) => ipv6nets.push(x), + } + } + + let mut res: Vec<IpNet> = Vec::new(); + let ipv4aggs = Ipv4Net::aggregate(&ipv4nets); + let ipv6aggs = Ipv6Net::aggregate(&ipv6nets); + res.extend::<Vec<IpNet>>(ipv4aggs.into_iter().map(IpNet::V4).collect::<Vec<IpNet>>()); + res.extend::<Vec<IpNet>>(ipv6aggs.into_iter().map(IpNet::V6).collect::<Vec<IpNet>>()); + res + } +} + +impl Default for IpNet { + fn default() -> Self { + Self::V4(Ipv4Net::default()) + } +} + +impl fmt::Debug for IpNet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +impl fmt::Display for IpNet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + IpNet::V4(ref a) => a.fmt(fmt), + IpNet::V6(ref a) => a.fmt(fmt), + } + } +} + +impl From<Ipv4Net> for IpNet { + fn from(net: Ipv4Net) -> IpNet { + IpNet::V4(net) + } +} + +impl From<Ipv6Net> for IpNet { + fn from(net: Ipv6Net) -> IpNet { + IpNet::V6(net) + } +} + +impl From<IpAddr> for IpNet { + fn from(addr: IpAddr) -> IpNet { + match addr { + IpAddr::V4(a) => IpNet::V4(a.into()), + IpAddr::V6(a) => IpNet::V6(a.into()), + } + } +} + +impl Ipv4Net { + /// Creates a new IPv4 network address from an `Ipv4Addr` and prefix + /// length. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// use ipnet::{Ipv4Net, PrefixLenError}; + /// + /// let net = Ipv4Net::new(Ipv4Addr::new(10, 1, 1, 0), 24); + /// assert!(net.is_ok()); + /// + /// let bad_prefix_len = Ipv4Net::new(Ipv4Addr::new(10, 1, 1, 0), 33); + /// assert_eq!(bad_prefix_len, Err(PrefixLenError)); + /// ``` + #[inline] + pub const fn new(ip: Ipv4Addr, prefix_len: u8) -> Result<Ipv4Net, PrefixLenError> { + if prefix_len > 32 { + return Err(PrefixLenError); + } + Ok(Ipv4Net { addr: ip, prefix_len: prefix_len }) + } + + /// Creates a new IPv4 network address from an `Ipv4Addr` and netmask. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// use ipnet::{Ipv4Net, PrefixLenError}; + /// + /// let net = Ipv4Net::with_netmask(Ipv4Addr::new(10, 1, 1, 0), Ipv4Addr::new(255, 255, 255, 0)); + /// assert!(net.is_ok()); + /// + /// let bad_prefix_len = Ipv4Net::with_netmask(Ipv4Addr::new(10, 1, 1, 0), Ipv4Addr::new(255, 255, 0, 1)); + /// assert_eq!(bad_prefix_len, Err(PrefixLenError)); + /// ``` + pub fn with_netmask(ip: Ipv4Addr, netmask: Ipv4Addr) -> Result<Ipv4Net, PrefixLenError> { + let prefix = ipv4_mask_to_prefix(netmask)?; + Self::new(ip, prefix) + } + + /// Returns a copy of the network with the address truncated to the + /// prefix length. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::Ipv4Net; + /// # + /// assert_eq!( + /// "192.168.12.34/16".parse::<Ipv4Net>().unwrap().trunc(), + /// "192.168.0.0/16".parse().unwrap() + /// ); + /// ``` + pub fn trunc(&self) -> Ipv4Net { + Ipv4Net::new(self.network(), self.prefix_len).unwrap() + } + + /// Returns the address. + #[inline] + pub const fn addr(&self) -> Ipv4Addr { + self.addr + } + + /// Returns the prefix length. + #[inline] + pub const fn prefix_len(&self) -> u8 { + self.prefix_len + } + + /// Returns the maximum valid prefix length. + #[inline] + pub const fn max_prefix_len(&self) -> u8 { + 32 + } + + /// Returns the network mask. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv4Addr; + /// # use ipnet::Ipv4Net; + /// # + /// let net: Ipv4Net = "10.1.0.0/20".parse().unwrap(); + /// assert_eq!(Ok(net.netmask()), "255.255.240.0".parse()); + /// ``` + pub fn netmask(&self) -> Ipv4Addr { + Ipv4Addr::from(self.netmask_u32()) + } + + fn netmask_u32(&self) -> u32 { + u32::max_value().checked_shl(32 - self.prefix_len as u32).unwrap_or(0) + } + + /// Returns the host mask. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv4Addr; + /// # use ipnet::Ipv4Net; + /// # + /// let net: Ipv4Net = "10.1.0.0/20".parse().unwrap(); + /// assert_eq!(Ok(net.hostmask()), "0.0.15.255".parse()); + /// ``` + pub fn hostmask(&self) -> Ipv4Addr { + Ipv4Addr::from(self.hostmask_u32()) + } + + fn hostmask_u32(&self) -> u32 { + u32::max_value().checked_shr(self.prefix_len as u32).unwrap_or(0) + } + + /// Returns the network address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv4Addr; + /// # use ipnet::Ipv4Net; + /// # + /// let net: Ipv4Net = "172.16.123.123/16".parse().unwrap(); + /// assert_eq!(Ok(net.network()), "172.16.0.0".parse()); + /// ``` + pub fn network(&self) -> Ipv4Addr { + Ipv4Addr::from(u32::from(self.addr) & self.netmask_u32()) + } + + /// Returns the broadcast address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv4Addr; + /// # use ipnet::Ipv4Net; + /// # + /// let net: Ipv4Net = "172.16.0.0/22".parse().unwrap(); + /// assert_eq!(Ok(net.broadcast()), "172.16.3.255".parse()); + /// ``` + pub fn broadcast(&self) -> Ipv4Addr { + Ipv4Addr::from(u32::from(self.addr) | self.hostmask_u32()) + } + + /// Returns the `Ipv4Net` that contains this one. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::Ipv4Net; + /// # + /// let n1: Ipv4Net = "172.16.1.0/24".parse().unwrap(); + /// let n2: Ipv4Net = "172.16.0.0/23".parse().unwrap(); + /// let n3: Ipv4Net = "172.16.0.0/0".parse().unwrap(); + /// + /// assert_eq!(n1.supernet().unwrap(), n2); + /// assert_eq!(n3.supernet(), None); + /// ``` + pub fn supernet(&self) -> Option<Ipv4Net> { + Ipv4Net::new(self.addr, self.prefix_len.wrapping_sub(1)).map(|n| n.trunc()).ok() + } + + /// Returns `true` if this network and the given network are + /// children of the same supernet. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::Ipv4Net; + /// # + /// let n1: Ipv4Net = "10.1.0.0/24".parse().unwrap(); + /// let n2: Ipv4Net = "10.1.1.0/24".parse().unwrap(); + /// let n3: Ipv4Net = "10.1.2.0/24".parse().unwrap(); + /// + /// assert!(n1.is_sibling(&n2)); + /// assert!(!n2.is_sibling(&n3)); + /// ``` + pub fn is_sibling(&self, other: &Ipv4Net) -> bool { + self.prefix_len > 0 && + self.prefix_len == other.prefix_len && + self.supernet().unwrap().contains(other) + } + + /// Return an `Iterator` over the host addresses in this network. + /// + /// If the prefix length is less than 31 both the network address + /// and broadcast address are excluded. These are only valid host + /// addresses when the prefix length is 31. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv4Addr; + /// # use ipnet::Ipv4Net; + /// # + /// let net: Ipv4Net = "10.0.0.0/30".parse().unwrap(); + /// assert_eq!(net.hosts().collect::<Vec<Ipv4Addr>>(), vec![ + /// "10.0.0.1".parse::<Ipv4Addr>().unwrap(), + /// "10.0.0.2".parse().unwrap(), + /// ]); + /// + /// let net: Ipv4Net = "10.0.0.0/31".parse().unwrap(); + /// assert_eq!(net.hosts().collect::<Vec<Ipv4Addr>>(), vec![ + /// "10.0.0.0".parse::<Ipv4Addr>().unwrap(), + /// "10.0.0.1".parse().unwrap(), + /// ]); + /// ``` + pub fn hosts(&self) -> Ipv4AddrRange { + let mut start = self.network(); + let mut end = self.broadcast(); + + if self.prefix_len < 31 { + start = start.saturating_add(1); + end = end.saturating_sub(1); + } + + Ipv4AddrRange::new(start, end) + } + + /// Returns an `Iterator` over the subnets of this network with the + /// given prefix length. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::{Ipv4Net, PrefixLenError}; + /// # + /// let net: Ipv4Net = "10.0.0.0/24".parse().unwrap(); + /// assert_eq!(net.subnets(26).unwrap().collect::<Vec<Ipv4Net>>(), vec![ + /// "10.0.0.0/26".parse::<Ipv4Net>().unwrap(), + /// "10.0.0.64/26".parse().unwrap(), + /// "10.0.0.128/26".parse().unwrap(), + /// "10.0.0.192/26".parse().unwrap(), + /// ]); + /// + /// let net: Ipv4Net = "10.0.0.0/30".parse().unwrap(); + /// assert_eq!(net.subnets(32).unwrap().collect::<Vec<Ipv4Net>>(), vec![ + /// "10.0.0.0/32".parse::<Ipv4Net>().unwrap(), + /// "10.0.0.1/32".parse().unwrap(), + /// "10.0.0.2/32".parse().unwrap(), + /// "10.0.0.3/32".parse().unwrap(), + /// ]); + /// + /// let net: Ipv4Net = "10.0.0.0/24".parse().unwrap(); + /// assert_eq!(net.subnets(23), Err(PrefixLenError)); + /// + /// let net: Ipv4Net = "10.0.0.0/24".parse().unwrap(); + /// assert_eq!(net.subnets(33), Err(PrefixLenError)); + /// ``` + pub fn subnets(&self, new_prefix_len: u8) -> Result<Ipv4Subnets, PrefixLenError> { + if self.prefix_len > new_prefix_len || new_prefix_len > 32 { + return Err(PrefixLenError); + } + + Ok(Ipv4Subnets::new( + self.network(), + self.broadcast(), + new_prefix_len, + )) + } + + /// Test if a network address contains either another network + /// address or an IP address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv4Addr; + /// # use ipnet::Ipv4Net; + /// # + /// let net: Ipv4Net = "192.168.0.0/24".parse().unwrap(); + /// let net_yes: Ipv4Net = "192.168.0.0/25".parse().unwrap(); + /// let net_no: Ipv4Net = "192.168.0.0/23".parse().unwrap(); + /// let ip_yes: Ipv4Addr = "192.168.0.1".parse().unwrap(); + /// let ip_no: Ipv4Addr = "192.168.1.0".parse().unwrap(); + /// + /// assert!(net.contains(&net)); + /// assert!(net.contains(&net_yes)); + /// assert!(!net.contains(&net_no)); + /// assert!(net.contains(&ip_yes)); + /// assert!(!net.contains(&ip_no)); + /// ``` + pub fn contains<T>(&self, other: T) -> bool where Self: Contains<T> { + Contains::contains(self, other) + } + + // It is significantly faster to work on u32 than Ipv4Addr. + fn interval(&self) -> (u32, u32) { + ( + u32::from(self.network()), + u32::from(self.broadcast()).saturating_add(1), + ) + } + + /// Aggregate a `Vec` of `Ipv4Net`s and return the result as a new + /// `Vec`. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::Ipv4Net; + /// # + /// let nets = vec![ + /// "10.0.0.0/24".parse::<Ipv4Net>().unwrap(), + /// "10.0.1.0/24".parse().unwrap(), + /// "10.0.2.0/24".parse().unwrap(), + /// ]; + /// + /// assert_eq!(Ipv4Net::aggregate(&nets), vec![ + /// "10.0.0.0/23".parse::<Ipv4Net>().unwrap(), + /// "10.0.2.0/24".parse().unwrap(), + /// ]); + pub fn aggregate(networks: &Vec<Ipv4Net>) -> Vec<Ipv4Net> { + let mut intervals: Vec<(_, _)> = networks.iter().map(|n| n.interval()).collect(); + intervals = merge_intervals(intervals); + let mut res: Vec<Ipv4Net> = Vec::new(); + + for (start, mut end) in intervals { + if end != std::u32::MAX { + end = end.saturating_sub(1) + } + let iter = Ipv4Subnets::new(start.into(), end.into(), 0); + res.extend(iter); + } + res + } +} + +impl Default for Ipv4Net { + fn default() -> Self { + Self { + addr: Ipv4Addr::from(0), + prefix_len: 0, + } + } +} + +impl fmt::Debug for Ipv4Net { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +impl fmt::Display for Ipv4Net { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}/{}", self.addr, self.prefix_len) + } +} + +impl From<Ipv4Addr> for Ipv4Net { + fn from(addr: Ipv4Addr) -> Ipv4Net { + Ipv4Net { addr, prefix_len: 32 } + } +} + +impl Ipv6Net { + /// Creates a new IPv6 network address from an `Ipv6Addr` and prefix + /// length. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// use ipnet::{Ipv6Net, PrefixLenError}; + /// + /// let net = Ipv6Net::new(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 24); + /// assert!(net.is_ok()); + /// + /// let bad_prefix_len = Ipv6Net::new(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 129); + /// assert_eq!(bad_prefix_len, Err(PrefixLenError)); + /// ``` + #[inline] + pub const fn new(ip: Ipv6Addr, prefix_len: u8) -> Result<Ipv6Net, PrefixLenError> { + if prefix_len > 128 { + return Err(PrefixLenError); + } + Ok(Ipv6Net { addr: ip, prefix_len: prefix_len }) + } + + /// Creates a new IPv6 network address from an `Ipv6Addr` and netmask. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// use ipnet::{Ipv6Net, PrefixLenError}; + /// + /// let net = Ipv6Net::with_netmask(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), Ipv6Addr::from(0xffff_ff00_0000_0000_0000_0000_0000_0000)); + /// assert!(net.is_ok()); + /// + /// let bad_prefix_len = Ipv6Net::with_netmask(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), Ipv6Addr::from(0xffff_ff00_0000_0000_0001_0000_0000_0000)); + /// assert_eq!(bad_prefix_len, Err(PrefixLenError)); + /// ``` + pub fn with_netmask(ip: Ipv6Addr, netmask: Ipv6Addr) -> Result<Ipv6Net, PrefixLenError> { + let prefix = ipv6_mask_to_prefix(netmask)?; + Self::new(ip, prefix) + } + + /// Returns a copy of the network with the address truncated to the + /// prefix length. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::Ipv6Net; + /// # + /// assert_eq!( + /// "fd00::1:2:3:4/16".parse::<Ipv6Net>().unwrap().trunc(), + /// "fd00::/16".parse().unwrap() + /// ); + /// ``` + pub fn trunc(&self) -> Ipv6Net { + Ipv6Net::new(self.network(), self.prefix_len).unwrap() + } + + /// Returns the address. + #[inline] + pub const fn addr(&self) -> Ipv6Addr { + self.addr + } + + /// Returns the prefix length. + #[inline] + pub const fn prefix_len(&self) -> u8 { + self.prefix_len + } + + /// Returns the maximum valid prefix length. + #[inline] + pub const fn max_prefix_len(&self) -> u8 { + 128 + } + + /// Returns the network mask. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv6Addr; + /// # use ipnet::Ipv6Net; + /// # + /// let net: Ipv6Net = "fd00::/24".parse().unwrap(); + /// assert_eq!(Ok(net.netmask()), "ffff:ff00::".parse()); + /// ``` + pub fn netmask(&self) -> Ipv6Addr { + self.netmask_u128().into() + } + + fn netmask_u128(&self) -> u128 { + u128::max_value().checked_shl((128 - self.prefix_len) as u32).unwrap_or(u128::min_value()) + } + + /// Returns the host mask. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv6Addr; + /// # use ipnet::Ipv6Net; + /// # + /// let net: Ipv6Net = "fd00::/24".parse().unwrap(); + /// assert_eq!(Ok(net.hostmask()), "::ff:ffff:ffff:ffff:ffff:ffff:ffff".parse()); + /// ``` + pub fn hostmask(&self) -> Ipv6Addr { + self.hostmask_u128().into() + } + + fn hostmask_u128(&self) -> u128 { + u128::max_value().checked_shr(self.prefix_len as u32).unwrap_or(u128::min_value()) + } + + /// Returns the network address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv6Addr; + /// # use ipnet::Ipv6Net; + /// # + /// let net: Ipv6Net = "fd00:1234:5678::/24".parse().unwrap(); + /// assert_eq!(Ok(net.network()), "fd00:1200::".parse()); + /// ``` + pub fn network(&self) -> Ipv6Addr { + (u128::from(self.addr) & self.netmask_u128()).into() + } + + /// Returns the last address. + /// + /// Technically there is no such thing as a broadcast address for + /// IPv6. The name is used for consistency with colloquial usage. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv6Addr; + /// # use ipnet::Ipv6Net; + /// # + /// let net: Ipv6Net = "fd00:1234:5678::/24".parse().unwrap(); + /// assert_eq!(Ok(net.broadcast()), "fd00:12ff:ffff:ffff:ffff:ffff:ffff:ffff".parse()); + /// ``` + pub fn broadcast(&self) -> Ipv6Addr { + (u128::from(self.addr) | self.hostmask_u128()).into() + } + + /// Returns the `Ipv6Net` that contains this one. + /// + /// # Examples + /// + /// ``` + /// # use std::str::FromStr; + /// # use ipnet::Ipv6Net; + /// # + /// let n1: Ipv6Net = "fd00:ff00::/24".parse().unwrap(); + /// let n2: Ipv6Net = "fd00:fe00::/23".parse().unwrap(); + /// let n3: Ipv6Net = "fd00:fe00::/0".parse().unwrap(); + /// + /// assert_eq!(n1.supernet().unwrap(), n2); + /// assert_eq!(n3.supernet(), None); + /// ``` + pub fn supernet(&self) -> Option<Ipv6Net> { + Ipv6Net::new(self.addr, self.prefix_len.wrapping_sub(1)).map(|n| n.trunc()).ok() + } + + /// Returns `true` if this network and the given network are + /// children of the same supernet. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::Ipv6Net; + /// # + /// let n1: Ipv6Net = "fd00::/18".parse().unwrap(); + /// let n2: Ipv6Net = "fd00:4000::/18".parse().unwrap(); + /// let n3: Ipv6Net = "fd00:8000::/18".parse().unwrap(); + /// + /// assert!(n1.is_sibling(&n2)); + /// assert!(!n2.is_sibling(&n3)); + /// ``` + pub fn is_sibling(&self, other: &Ipv6Net) -> bool { + self.prefix_len > 0 && + self.prefix_len == other.prefix_len && + self.supernet().unwrap().contains(other) + } + + /// Return an `Iterator` over the host addresses in this network. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv6Addr; + /// # use ipnet::Ipv6Net; + /// # + /// let net: Ipv6Net = "fd00::/126".parse().unwrap(); + /// assert_eq!(net.hosts().collect::<Vec<Ipv6Addr>>(), vec![ + /// "fd00::".parse::<Ipv6Addr>().unwrap(), + /// "fd00::1".parse().unwrap(), + /// "fd00::2".parse().unwrap(), + /// "fd00::3".parse().unwrap(), + /// ]); + /// ``` + pub fn hosts(&self) -> Ipv6AddrRange { + Ipv6AddrRange::new(self.network(), self.broadcast()) + } + + /// Returns an `Iterator` over the subnets of this network with the + /// given prefix length. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::{Ipv6Net, PrefixLenError}; + /// # + /// let net: Ipv6Net = "fd00::/16".parse().unwrap(); + /// assert_eq!(net.subnets(18).unwrap().collect::<Vec<Ipv6Net>>(), vec![ + /// "fd00::/18".parse::<Ipv6Net>().unwrap(), + /// "fd00:4000::/18".parse().unwrap(), + /// "fd00:8000::/18".parse().unwrap(), + /// "fd00:c000::/18".parse().unwrap(), + /// ]); + /// + /// let net: Ipv6Net = "fd00::/126".parse().unwrap(); + /// assert_eq!(net.subnets(128).unwrap().collect::<Vec<Ipv6Net>>(), vec![ + /// "fd00::/128".parse::<Ipv6Net>().unwrap(), + /// "fd00::1/128".parse().unwrap(), + /// "fd00::2/128".parse().unwrap(), + /// "fd00::3/128".parse().unwrap(), + /// ]); + /// + /// let net: Ipv6Net = "fd00::/16".parse().unwrap(); + /// assert_eq!(net.subnets(15), Err(PrefixLenError)); + /// + /// let net: Ipv6Net = "fd00::/16".parse().unwrap(); + /// assert_eq!(net.subnets(129), Err(PrefixLenError)); + /// ``` + pub fn subnets(&self, new_prefix_len: u8) -> Result<Ipv6Subnets, PrefixLenError> { + if self.prefix_len > new_prefix_len || new_prefix_len > 128 { + return Err(PrefixLenError); + } + + Ok(Ipv6Subnets::new( + self.network(), + self.broadcast(), + new_prefix_len, + )) + } + + /// Test if a network address contains either another network + /// address or an IP address. + /// + /// # Examples + /// + /// ``` + /// # use std::net::Ipv6Addr; + /// # use ipnet::Ipv6Net; + /// # + /// let net: Ipv6Net = "fd00::/16".parse().unwrap(); + /// let net_yes: Ipv6Net = "fd00::/17".parse().unwrap(); + /// let net_no: Ipv6Net = "fd00::/15".parse().unwrap(); + /// let ip_yes: Ipv6Addr = "fd00::1".parse().unwrap(); + /// let ip_no: Ipv6Addr = "fd01::".parse().unwrap(); + /// + /// assert!(net.contains(&net)); + /// assert!(net.contains(&net_yes)); + /// assert!(!net.contains(&net_no)); + /// assert!(net.contains(&ip_yes)); + /// assert!(!net.contains(&ip_no)); + /// ``` + pub fn contains<T>(&self, other: T) -> bool where Self: Contains<T> { + Contains::contains(self, other) + } + + // It is significantly faster to work on u128 that Ipv6Addr. + fn interval(&self) -> (u128, u128) { + ( + u128::from(self.network()), + u128::from(self.broadcast()).saturating_add(1), + ) + } + + /// Aggregate a `Vec` of `Ipv6Net`s and return the result as a new + /// `Vec`. + /// + /// # Examples + /// + /// ``` + /// # use ipnet::Ipv6Net; + /// # + /// let nets = vec![ + /// "fd00::/18".parse::<Ipv6Net>().unwrap(), + /// "fd00:4000::/18".parse().unwrap(), + /// "fd00:8000::/18".parse().unwrap(), + /// ]; + /// assert_eq!(Ipv6Net::aggregate(&nets), vec![ + /// "fd00::/17".parse::<Ipv6Net>().unwrap(), + /// "fd00:8000::/18".parse().unwrap(), + /// ]); + /// ``` + pub fn aggregate(networks: &Vec<Ipv6Net>) -> Vec<Ipv6Net> { + let mut intervals: Vec<(_, _)> = networks.iter().map(|n| n.interval()).collect(); + intervals = merge_intervals(intervals); + let mut res: Vec<Ipv6Net> = Vec::new(); + + for (start, mut end) in intervals { + if end != std::u128::MAX { + end = end.saturating_sub(1) + } + let iter = Ipv6Subnets::new(start.into(), end.into(), 0); + res.extend(iter); + } + res + } +} + +impl Default for Ipv6Net { + fn default() -> Self { + Self { + addr: Ipv6Addr::from(0), + prefix_len: 0, + } + } +} + +impl fmt::Debug for Ipv6Net { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +impl fmt::Display for Ipv6Net { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}/{}", self.addr, self.prefix_len) + } +} + +impl From<Ipv6Addr> for Ipv6Net { + fn from(addr: Ipv6Addr) -> Ipv6Net { + Ipv6Net { addr, prefix_len: 128 } + } +} + +/// Provides a method to test if a network address contains either +/// another network address or an IP address. +/// +/// # Examples +/// +/// ``` +/// # use std::net::IpAddr; +/// # use ipnet::IpNet; +/// # +/// let n4_1: IpNet = "10.1.1.0/24".parse().unwrap(); +/// let n4_2: IpNet = "10.1.1.0/26".parse().unwrap(); +/// let n4_3: IpNet = "10.1.2.0/26".parse().unwrap(); +/// let ip4_1: IpAddr = "10.1.1.1".parse().unwrap(); +/// let ip4_2: IpAddr = "10.1.2.1".parse().unwrap(); +/// +/// let n6_1: IpNet = "fd00::/16".parse().unwrap(); +/// let n6_2: IpNet = "fd00::/17".parse().unwrap(); +/// let n6_3: IpNet = "fd01::/17".parse().unwrap(); +/// let ip6_1: IpAddr = "fd00::1".parse().unwrap(); +/// let ip6_2: IpAddr = "fd01::1".parse().unwrap(); +/// +/// assert!(n4_1.contains(&n4_2)); +/// assert!(!n4_1.contains(&n4_3)); +/// assert!(n4_1.contains(&ip4_1)); +/// assert!(!n4_1.contains(&ip4_2)); +/// +/// assert!(n6_1.contains(&n6_2)); +/// assert!(!n6_1.contains(&n6_3)); +/// assert!(n6_1.contains(&ip6_1)); +/// assert!(!n6_1.contains(&ip6_2)); +/// +/// assert!(!n4_1.contains(&n6_1) && !n6_1.contains(&n4_1)); +/// assert!(!n4_1.contains(&ip6_1) && !n6_1.contains(&ip4_1)); +/// ``` +pub trait Contains<T> { + fn contains(&self, other: T) -> bool; +} + +impl<'a> Contains<&'a IpNet> for IpNet { + fn contains(&self, other: &IpNet) -> bool { + match (*self, *other) { + (IpNet::V4(ref a), IpNet::V4(ref b)) => a.contains(b), + (IpNet::V6(ref a), IpNet::V6(ref b)) => a.contains(b), + _ => false, + } + } +} + +impl<'a> Contains<&'a IpAddr> for IpNet { + fn contains(&self, other: &IpAddr) -> bool { + match (*self, *other) { + (IpNet::V4(ref a), IpAddr::V4(ref b)) => a.contains(b), + (IpNet::V6(ref a), IpAddr::V6(ref b)) => a.contains(b), + _ => false, + } + } +} + +impl<'a> Contains<&'a Ipv4Net> for Ipv4Net { + fn contains(&self, other: &'a Ipv4Net) -> bool { + self.network() <= other.network() && other.broadcast() <= self.broadcast() + } +} + +impl<'a> Contains<&'a Ipv4Addr> for Ipv4Net { + fn contains(&self, other: &'a Ipv4Addr) -> bool { + self.network() <= *other && *other <= self.broadcast() + } +} + +impl<'a> Contains<&'a Ipv6Net> for Ipv6Net { + fn contains(&self, other: &'a Ipv6Net) -> bool { + self.network() <= other.network() && other.broadcast() <= self.broadcast() + } +} + +impl<'a> Contains<&'a Ipv6Addr> for Ipv6Net { + fn contains(&self, other: &'a Ipv6Addr) -> bool { + self.network() <= *other && *other <= self.broadcast() + } +} + +/// An `Iterator` that generates IP network addresses, either IPv4 or +/// IPv6. +/// +/// Generates the subnets between the provided `start` and `end` IP +/// addresses inclusive of `end`. Each iteration generates the next +/// network address of the largest valid size it can, while using a +/// prefix length not less than `min_prefix_len`. +/// +/// # Examples +/// +/// ``` +/// # use std::net::{Ipv4Addr, Ipv6Addr}; +/// # use std::str::FromStr; +/// # use ipnet::{IpNet, IpSubnets, Ipv4Subnets, Ipv6Subnets}; +/// let subnets = IpSubnets::from(Ipv4Subnets::new( +/// "10.0.0.0".parse().unwrap(), +/// "10.0.0.239".parse().unwrap(), +/// 26, +/// )); +/// +/// assert_eq!(subnets.collect::<Vec<IpNet>>(), vec![ +/// "10.0.0.0/26".parse().unwrap(), +/// "10.0.0.64/26".parse().unwrap(), +/// "10.0.0.128/26".parse().unwrap(), +/// "10.0.0.192/27".parse().unwrap(), +/// "10.0.0.224/28".parse().unwrap(), +/// ]); +/// +/// let subnets = IpSubnets::from(Ipv6Subnets::new( +/// "fd00::".parse().unwrap(), +/// "fd00:ef:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(), +/// 26, +/// )); +/// +/// assert_eq!(subnets.collect::<Vec<IpNet>>(), vec![ +/// "fd00::/26".parse().unwrap(), +/// "fd00:40::/26".parse().unwrap(), +/// "fd00:80::/26".parse().unwrap(), +/// "fd00:c0::/27".parse().unwrap(), +/// "fd00:e0::/28".parse().unwrap(), +/// ]); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub enum IpSubnets { + V4(Ipv4Subnets), + V6(Ipv6Subnets), +} + +/// An `Iterator` that generates IPv4 network addresses. +/// +/// Generates the subnets between the provided `start` and `end` IP +/// addresses inclusive of `end`. Each iteration generates the next +/// network address of the largest valid size it can, while using a +/// prefix length not less than `min_prefix_len`. +/// +/// # Examples +/// +/// ``` +/// # use std::net::Ipv4Addr; +/// # use std::str::FromStr; +/// # use ipnet::{Ipv4Net, Ipv4Subnets}; +/// let subnets = Ipv4Subnets::new( +/// "10.0.0.0".parse().unwrap(), +/// "10.0.0.239".parse().unwrap(), +/// 26, +/// ); +/// +/// assert_eq!(subnets.collect::<Vec<Ipv4Net>>(), vec![ +/// "10.0.0.0/26".parse().unwrap(), +/// "10.0.0.64/26".parse().unwrap(), +/// "10.0.0.128/26".parse().unwrap(), +/// "10.0.0.192/27".parse().unwrap(), +/// "10.0.0.224/28".parse().unwrap(), +/// ]); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Ipv4Subnets { + start: Ipv4Addr, + end: Ipv4Addr, // end is inclusive + min_prefix_len: u8, +} + +/// An `Iterator` that generates IPv6 network addresses. +/// +/// Generates the subnets between the provided `start` and `end` IP +/// addresses inclusive of `end`. Each iteration generates the next +/// network address of the largest valid size it can, while using a +/// prefix length not less than `min_prefix_len`. +/// +/// # Examples +/// +/// ``` +/// # use std::net::Ipv6Addr; +/// # use std::str::FromStr; +/// # use ipnet::{Ipv6Net, Ipv6Subnets}; +/// let subnets = Ipv6Subnets::new( +/// "fd00::".parse().unwrap(), +/// "fd00:ef:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(), +/// 26, +/// ); +/// +/// assert_eq!(subnets.collect::<Vec<Ipv6Net>>(), vec![ +/// "fd00::/26".parse().unwrap(), +/// "fd00:40::/26".parse().unwrap(), +/// "fd00:80::/26".parse().unwrap(), +/// "fd00:c0::/27".parse().unwrap(), +/// "fd00:e0::/28".parse().unwrap(), +/// ]); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Ipv6Subnets { + start: Ipv6Addr, + end: Ipv6Addr, // end is inclusive + min_prefix_len: u8, +} + +impl Ipv4Subnets { + pub fn new(start: Ipv4Addr, end: Ipv4Addr, min_prefix_len: u8) -> Self { + Ipv4Subnets { + start: start, + end: end, + min_prefix_len: min_prefix_len, + } + } +} + +impl Ipv6Subnets { + pub fn new(start: Ipv6Addr, end: Ipv6Addr, min_prefix_len: u8) -> Self { + Ipv6Subnets { + start: start, + end: end, + min_prefix_len: min_prefix_len, + } + } +} + +impl From<Ipv4Subnets> for IpSubnets { + fn from(i: Ipv4Subnets) -> IpSubnets { + IpSubnets::V4(i) + } +} + +impl From<Ipv6Subnets> for IpSubnets { + fn from(i: Ipv6Subnets) -> IpSubnets { + IpSubnets::V6(i) + } +} + +impl Iterator for IpSubnets { + type Item = IpNet; + + fn next(&mut self) -> Option<Self::Item> { + match *self { + IpSubnets::V4(ref mut a) => a.next().map(IpNet::V4), + IpSubnets::V6(ref mut a) => a.next().map(IpNet::V6), + } + } +} + +fn next_ipv4_subnet(start: Ipv4Addr, end: Ipv4Addr, min_prefix_len: u8) -> Ipv4Net { + let range = end.saturating_sub(start).saturating_add(1); + if range == std::u32::MAX && min_prefix_len == 0 { + Ipv4Net::new(start, min_prefix_len).unwrap() + } + else { + let range_bits = 32u32.saturating_sub(range.leading_zeros()).saturating_sub(1); + let start_tz = u32::from(start).trailing_zeros(); + let new_prefix_len = 32 - min(range_bits, start_tz); + let next_prefix_len = max(new_prefix_len as u8, min_prefix_len); + Ipv4Net::new(start, next_prefix_len).unwrap() + } +} + +fn next_ipv6_subnet(start: Ipv6Addr, end: Ipv6Addr, min_prefix_len: u8) -> Ipv6Net { + let range = end.saturating_sub(start).saturating_add(1); + if range == std::u128::MAX && min_prefix_len == 0 { + Ipv6Net::new(start, min_prefix_len).unwrap() + } + else { + let range = end.saturating_sub(start).saturating_add(1); + let range_bits = 128u32.saturating_sub(range.leading_zeros()).saturating_sub(1); + let start_tz = u128::from(start).trailing_zeros(); + let new_prefix_len = 128 - min(range_bits, start_tz); + let next_prefix_len = max(new_prefix_len as u8, min_prefix_len); + Ipv6Net::new(start, next_prefix_len).unwrap() + } +} + +impl Iterator for Ipv4Subnets { + type Item = Ipv4Net; + + fn next(&mut self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let next = next_ipv4_subnet(self.start, self.end, self.min_prefix_len); + self.start = next.broadcast().saturating_add(1); + + // Stop the iterator if we saturated self.start. This + // check worsens performance slightly but overall this + // approach of operating on Ipv4Addr types is faster + // than what we were doing before using Ipv4Net. + if self.start == next.broadcast() { + self.end.replace_zero(); + } + Some(next) + }, + Some(Equal) => { + let next = next_ipv4_subnet(self.start, self.end, self.min_prefix_len); + self.start = next.broadcast().saturating_add(1); + self.end.replace_zero(); + Some(next) + }, + _ => None, + } + } +} + +impl Iterator for Ipv6Subnets { + type Item = Ipv6Net; + + fn next(&mut self) -> Option<Self::Item> { + match self.start.partial_cmp(&self.end) { + Some(Less) => { + let next = next_ipv6_subnet(self.start, self.end, self.min_prefix_len); + self.start = next.broadcast().saturating_add(1); + + // Stop the iterator if we saturated self.start. This + // check worsens performance slightly but overall this + // approach of operating on Ipv6Addr types is faster + // than what we were doing before using Ipv6Net. + if self.start == next.broadcast() { + self.end.replace_zero(); + } + Some(next) + }, + Some(Equal) => { + let next = next_ipv6_subnet(self.start, self.end, self.min_prefix_len); + self.start = next.broadcast().saturating_add(1); + self.end.replace_zero(); + Some(next) + }, + _ => None, + } + } +} + +impl FusedIterator for IpSubnets {} +impl FusedIterator for Ipv4Subnets {} +impl FusedIterator for Ipv6Subnets {} + +// Generic function for merging a vector of intervals. +fn merge_intervals<T: Copy + Ord>(mut intervals: Vec<(T, T)>) -> Vec<(T, T)> { + if intervals.len() == 0 { + return intervals; + } + + intervals.sort(); + let mut res: Vec<(T, T)> = Vec::new(); + let (mut start, mut end) = intervals[0]; + + let mut i = 1; + let len = intervals.len(); + while i < len { + let (next_start, next_end) = intervals[i]; + if end >= next_start { + start = min(start, next_start); + end = max(end, next_end); + } + else { + res.push((start, end)); + start = next_start; + end = next_end; + } + i += 1; + } + + res.push((start, end)); + res +} + +#[cfg(test)] +mod tests { + use super::*; + + macro_rules! make_ipnet_vec { + ($($x:expr),*) => ( vec![$($x.parse::<IpNet>().unwrap(),)*] ); + ($($x:expr,)*) => ( make_ipnet_vec![$($x),*] ); + } + + #[test] + fn test_make_ipnet_vec() { + assert_eq!( + make_ipnet_vec![ + "10.1.1.1/32", "10.2.2.2/24", "10.3.3.3/16", + "fd00::1/128", "fd00::2/127", "fd00::3/126", + ], + vec![ + "10.1.1.1/32".parse().unwrap(), + "10.2.2.2/24".parse().unwrap(), + "10.3.3.3/16".parse().unwrap(), + "fd00::1/128".parse().unwrap(), + "fd00::2/127".parse().unwrap(), + "fd00::3/126".parse().unwrap(), + ] + ); + } + + #[test] + fn test_merge_intervals() { + let v = vec![ + (0, 1), (1, 2), (2, 3), + (11, 12), (13, 14), (10, 15), (11, 13), + (20, 25), (24, 29), + ]; + + let v_ok = vec![ + (0, 3), + (10, 15), + (20, 29), + ]; + + let vv = vec![ + ([0, 1], [0, 2]), ([0, 2], [0, 3]), ([0, 0], [0, 1]), + ([10, 15], [11, 0]), ([10, 0], [10, 16]), + ]; + + let vv_ok = vec![ + ([0, 0], [0, 3]), + ([10, 0], [11, 0]), + ]; + + assert_eq!(merge_intervals(v), v_ok); + assert_eq!(merge_intervals(vv), vv_ok); + } + + macro_rules! make_ipv4_subnets_test { + ($name:ident, $start:expr, $end:expr, $min_prefix_len:expr, $($x:expr),*) => ( + #[test] + fn $name() { + let subnets = IpSubnets::from(Ipv4Subnets::new( + $start.parse().unwrap(), + $end.parse().unwrap(), + $min_prefix_len, + )); + let results = make_ipnet_vec![$($x),*]; + assert_eq!(subnets.collect::<Vec<IpNet>>(), results); + } + ); + ($name:ident, $start:expr, $end:expr, $min_prefix_len:expr, $($x:expr,)*) => ( + make_ipv4_subnets_test!($name, $start, $end, $min_prefix_len, $($x),*); + ); + } + + macro_rules! make_ipv6_subnets_test { + ($name:ident, $start:expr, $end:expr, $min_prefix_len:expr, $($x:expr),*) => ( + #[test] + fn $name() { + let subnets = IpSubnets::from(Ipv6Subnets::new( + $start.parse().unwrap(), + $end.parse().unwrap(), + $min_prefix_len, + )); + let results = make_ipnet_vec![$($x),*]; + assert_eq!(subnets.collect::<Vec<IpNet>>(), results); + } + ); + ($name:ident, $start:expr, $end:expr, $min_prefix_len:expr, $($x:expr,)*) => ( + make_ipv6_subnets_test!($name, $start, $end, $min_prefix_len, $($x),*); + ); + } + + make_ipv4_subnets_test!( + test_ipv4_subnets_zero_zero, + "0.0.0.0", "0.0.0.0", 0, + "0.0.0.0/32", + ); + + make_ipv4_subnets_test!( + test_ipv4_subnets_zero_max, + "0.0.0.0", "255.255.255.255", 0, + "0.0.0.0/0", + ); + + make_ipv4_subnets_test!( + test_ipv4_subnets_max_max, + "255.255.255.255", "255.255.255.255", 0, + "255.255.255.255/32", + ); + + make_ipv4_subnets_test!( + test_ipv4_subnets_none, + "0.0.0.1", "0.0.0.0", 0, + ); + + make_ipv4_subnets_test!( + test_ipv4_subnets_one, + "0.0.0.0", "0.0.0.1", 0, + "0.0.0.0/31", + ); + + make_ipv4_subnets_test!( + test_ipv4_subnets_two, + "0.0.0.0", "0.0.0.2", 0, + "0.0.0.0/31", + "0.0.0.2/32", + ); + + make_ipv4_subnets_test!( + test_ipv4_subnets_taper, + "0.0.0.0", "0.0.0.10", 30, + "0.0.0.0/30", + "0.0.0.4/30", + "0.0.0.8/31", + "0.0.0.10/32", + ); + + make_ipv6_subnets_test!( + test_ipv6_subnets_zero_zero, + "::", "::", 0, + "::/128", + ); + + make_ipv6_subnets_test!( + test_ipv6_subnets_zero_max, + "::", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, + "::/0", + ); + + make_ipv6_subnets_test!( + test_ipv6_subnets_max_max, + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128", + ); + + make_ipv6_subnets_test!( + test_ipv6_subnets_none, + "::1", "::", 0, + ); + + make_ipv6_subnets_test!( + test_ipv6_subnets_one, + "::", "::1", 0, + "::/127", + ); + + make_ipv6_subnets_test!( + test_ipv6_subnets_two, + "::", "::2", 0, + "::/127", + "::2/128", + ); + + make_ipv6_subnets_test!( + test_ipv6_subnets_taper, + "::", "::a", 126, + "::/126", + "::4/126", + "::8/127", + "::a/128", + ); + + #[test] + fn test_aggregate() { + let ip_nets = make_ipnet_vec![ + "10.0.0.0/24", "10.0.1.0/24", "10.0.1.1/24", "10.0.1.2/24", + "10.0.2.0/24", + "10.1.0.0/24", "10.1.1.0/24", + "192.168.0.0/24", "192.168.1.0/24", "192.168.2.0/24", "192.168.3.0/24", + "fd00::/32", "fd00:1::/32", + "fd00:2::/32", + ]; + + let ip_aggs = make_ipnet_vec![ + "10.0.0.0/23", + "10.0.2.0/24", + "10.1.0.0/23", + "192.168.0.0/22", + "fd00::/31", + "fd00:2::/32", + ]; + + let ipv4_nets: Vec<Ipv4Net> = ip_nets.iter().filter_map(|p| if let IpNet::V4(x) = *p { Some(x) } else { None }).collect(); + let ipv4_aggs: Vec<Ipv4Net> = ip_aggs.iter().filter_map(|p| if let IpNet::V4(x) = *p { Some(x) } else { None }).collect(); + let ipv6_nets: Vec<Ipv6Net> = ip_nets.iter().filter_map(|p| if let IpNet::V6(x) = *p { Some(x) } else { None }).collect(); + let ipv6_aggs: Vec<Ipv6Net> = ip_aggs.iter().filter_map(|p| if let IpNet::V6(x) = *p { Some(x) } else { None }).collect(); + + assert_eq!(IpNet::aggregate(&ip_nets), ip_aggs); + assert_eq!(Ipv4Net::aggregate(&ipv4_nets), ipv4_aggs); + assert_eq!(Ipv6Net::aggregate(&ipv6_nets), ipv6_aggs); + } + + #[test] + fn test_aggregate_issue44() { + let nets: Vec<Ipv4Net> = vec!["128.0.0.0/1".parse().unwrap()]; + assert_eq!(Ipv4Net::aggregate(&nets), nets); + + let nets: Vec<Ipv4Net> = vec!["0.0.0.0/1".parse().unwrap(), "128.0.0.0/1".parse().unwrap()]; + assert_eq!(Ipv4Net::aggregate(&nets), vec!["0.0.0.0/0".parse().unwrap()]); + + let nets: Vec<Ipv6Net> = vec!["8000::/1".parse().unwrap()]; + assert_eq!(Ipv6Net::aggregate(&nets), nets); + + let nets: Vec<Ipv6Net> = vec!["::/1".parse().unwrap(), "8000::/1".parse().unwrap()]; + assert_eq!(Ipv6Net::aggregate(&nets), vec!["::/0".parse().unwrap()]); + } + + #[test] + fn ipnet_default() { + let ipnet: IpNet = "0.0.0.0/0".parse().unwrap(); + assert_eq!(ipnet, IpNet::default()); + } + + #[test] + fn ipv4net_default() { + let ipnet: Ipv4Net = "0.0.0.0/0".parse().unwrap(); + assert_eq!(ipnet, Ipv4Net::default()); + } + + #[test] + fn ipv6net_default() { + let ipnet: Ipv6Net = "::/0".parse().unwrap(); + assert_eq!(ipnet, Ipv6Net::default()); + } +} diff --git a/vendor/ipnet/src/ipnet_schemars.rs b/vendor/ipnet/src/ipnet_schemars.rs new file mode 100644 index 000000000..ac722a995 --- /dev/null +++ b/vendor/ipnet/src/ipnet_schemars.rs @@ -0,0 +1,86 @@ +use crate::Ipv4Net; +use crate::Ipv6Net; +use crate::IpNet; + +use schemars::{JsonSchema, gen::SchemaGenerator, schema::{SubschemaValidation, Schema, SchemaObject, StringValidation, Metadata, SingleOrVec, InstanceType}}; + +impl JsonSchema for Ipv4Net { + fn schema_name() -> String { + "Ipv4Net".to_string() + } + + fn json_schema(_gen: &mut SchemaGenerator) -> Schema { + Schema::Object(SchemaObject { + metadata: Some(Box::new(Metadata { + title: Some("IPv4 network".to_string()), + description: Some("An IPv4 address with prefix length".to_string()), + examples: vec![ + schemars::_serde_json::Value::String("0.0.0.0/0".to_string()), + schemars::_serde_json::Value::String("192.168.0.0/24".to_string()), + ], + ..Default::default() + })), + instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))), + string: Some(Box::new(StringValidation { + max_length: Some(18), + min_length: None, + pattern: Some(r#"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(?:3[0-2]|[1-2][0-9]|[0-9])$"#.to_string()), + ..Default::default() + })), + ..Default::default() + }) + } +} +impl JsonSchema for Ipv6Net { + fn schema_name() -> String { + "Ipv6Net".to_string() + } + + fn json_schema(_gen: &mut SchemaGenerator) -> Schema { + Schema::Object(SchemaObject { + metadata: Some(Box::new(Metadata { + title: Some("IPv6 network".to_string()), + description: Some("An IPv6 address with prefix length".to_string()), + examples: vec![ + schemars::_serde_json::Value::String("::/0".to_string()), + schemars::_serde_json::Value::String("fd00::/32".to_string()), + ], + ..Default::default() + })), + instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))), + string: Some(Box::new(StringValidation { + max_length: Some(43), + min_length: None, + pattern: Some(r#"^[0-9A-Fa-f:\.]+\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#.to_string()), + ..Default::default() + })), + ..Default::default() + }) + } +} +impl JsonSchema for IpNet { + fn schema_name() -> String { + "IpNet".to_string() + } + + fn json_schema(gen: &mut SchemaGenerator) -> Schema { + Schema::Object(SchemaObject { + metadata: Some(Box::new(Metadata { + title: Some("IP network".to_string()), + description: Some("An IPv4 or IPv6 address with prefix length".to_string()), + examples: vec![ + schemars::_serde_json::Value::String("192.168.0.0/24".to_string()), + schemars::_serde_json::Value::String("fd00::/32".to_string()), + ], + ..Default::default() + })), + subschemas: Some(Box::new( + SubschemaValidation { + one_of: Some(vec![Ipv4Net::json_schema(gen), Ipv6Net::json_schema(gen)]), + ..Default::default() + } + )), + ..Default::default() + }) + } +} diff --git a/vendor/ipnet/src/ipnet_serde.rs b/vendor/ipnet/src/ipnet_serde.rs new file mode 100644 index 000000000..bbf15ac81 --- /dev/null +++ b/vendor/ipnet/src/ipnet_serde.rs @@ -0,0 +1,276 @@ +use crate::{IpNet, Ipv4Net, Ipv6Net}; +use std::fmt; +use std::net::{Ipv4Addr, Ipv6Addr}; +use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; +use serde::ser::SerializeTuple; +use serde::de::{EnumAccess, Error, VariantAccess, Visitor}; + +impl Serialize for IpNet { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: Serializer + { + if serializer.is_human_readable() { + match *self { + IpNet::V4(ref a) => a.serialize(serializer), + IpNet::V6(ref a) => a.serialize(serializer), + } + } else { + match *self { + IpNet::V4(ref a) => serializer.serialize_newtype_variant("IpNet", 0, "V4", a), + IpNet::V6(ref a) => serializer.serialize_newtype_variant("IpNet", 1, "V6", a), + } + } + } +} + +impl<'de> Deserialize<'de> for IpNet { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where D: Deserializer<'de> + { + if deserializer.is_human_readable() { + struct IpNetVisitor; + + impl<'de> Visitor<'de> for IpNetVisitor { + type Value = IpNet; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("IPv4 or IPv6 network address") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where E: Error + { + s.parse().map_err(Error::custom) + } + } + + deserializer.deserialize_str(IpNetVisitor) + } else { + struct EnumVisitor; + + #[derive(Serialize, Deserialize)] + enum IpNetKind { + V4, + V6, + } + + impl<'de> Visitor<'de> for EnumVisitor { + type Value = IpNet; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("IPv4 or IPv6 network address") + } + + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where A: EnumAccess<'de> + { + match data.variant()? { + (IpNetKind::V4, v) => v.newtype_variant().map(IpNet::V4), + (IpNetKind::V6, v) => v.newtype_variant().map(IpNet::V6), + } + } + } + + deserializer.deserialize_enum("IpNet", &["V4", "V6"], EnumVisitor) + } + } +} + +impl Serialize for Ipv4Net { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: Serializer + { + if serializer.is_human_readable() { + serializer.collect_str(self) + } else { + let mut seq = serializer.serialize_tuple(5)?; + for octet in &self.addr().octets() { + seq.serialize_element(octet)?; + } + seq.serialize_element(&self.prefix_len())?; + seq.end() + } + } +} + +impl<'de> Deserialize<'de> for Ipv4Net { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where D: Deserializer<'de> + { + if deserializer.is_human_readable() { + struct IpAddrVisitor; + + impl<'de> Visitor<'de> for IpAddrVisitor { + type Value = Ipv4Net; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("IPv4 network address") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where E: Error + { + s.parse().map_err(Error::custom) + } + } + + deserializer.deserialize_str(IpAddrVisitor) + } else { + let b = <[u8; 5]>::deserialize(deserializer)?; + Ipv4Net::new(Ipv4Addr::new(b[0], b[1], b[2], b[3]), b[4]).map_err(serde::de::Error::custom) + } + } +} + +impl Serialize for Ipv6Net { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: Serializer + { + if serializer.is_human_readable() { + serializer.collect_str(self) + } else { + let mut seq = serializer.serialize_tuple(17)?; + for octet in &self.addr().octets() { + seq.serialize_element(octet)?; + } + seq.serialize_element(&self.prefix_len())?; + seq.end() + } + } +} + +impl<'de> Deserialize<'de> for Ipv6Net { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where D: Deserializer<'de> + { + if deserializer.is_human_readable() { + struct IpAddrVisitor; + + impl<'de> Visitor<'de> for IpAddrVisitor { + type Value = Ipv6Net; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("IPv6 network address") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where E: Error + { + s.parse().map_err(Error::custom) + } + } + + deserializer.deserialize_str(IpAddrVisitor) + } else { + let b = <[u8; 17]>::deserialize(deserializer)?; + Ipv6Net::new(Ipv6Addr::new( + ((b[0] as u16) << 8) | b[1] as u16, ((b[2] as u16) << 8) | b[3] as u16, + ((b[4] as u16) << 8) | b[5] as u16, ((b[6] as u16) << 8) | b[7] as u16, + ((b[8] as u16) << 8) | b[9] as u16, ((b[10] as u16) << 8) | b[11] as u16, + ((b[12] as u16) << 8) | b[13] as u16, ((b[14] as u16) << 8) | b[15] as u16 + ), b[16]).map_err(Error::custom) + } + } +} + +#[cfg(test)] +mod tests { + extern crate serde_test; + + use crate::{IpNet, Ipv4Net, Ipv6Net}; + use self::serde_test::{assert_tokens, Configure, Token}; + + #[test] + fn test_serialize_ipnet_v4() { + let net_str = "10.1.1.0/24"; + let net: IpNet = net_str.parse().unwrap(); + assert_tokens(&net.readable(), &[Token::Str(net_str)]); + assert_tokens(&net.compact(), &[ + Token::NewtypeVariant { name: "IpNet", variant: "V4", }, + Token::Tuple { len: 5 }, + Token::U8(10), + Token::U8(1), + Token::U8(1), + Token::U8(0), + Token::U8(24), + Token::TupleEnd, + ]); + } + + #[test] + fn test_serialize_ipnet_v6() { + let net_str = "fd00::/32"; + let net: IpNet = net_str.parse().unwrap(); + assert_tokens(&net.readable(), &[Token::Str(net_str)]); + assert_tokens(&net.compact(), &[ + Token::NewtypeVariant { name: "IpNet", variant: "V6", }, + // This is too painful, but Token::Bytes() seems to be + // an array with a length, which is not what we serialize. + Token::Tuple { len: 17 }, + Token::U8(253u8), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(32), + Token::TupleEnd, + ]); + } + + #[test] + fn test_serialize_ipv4_net() { + let net_str = "10.1.1.0/24"; + let net: Ipv4Net = net_str.parse().unwrap(); + assert_tokens(&net.readable(), &[Token::Str(net_str)]); + assert_tokens(&net.compact(), &[ + Token::Tuple { len: 5 }, + Token::U8(10), + Token::U8(1), + Token::U8(1), + Token::U8(0), + Token::U8(24), + Token::TupleEnd, + ]); + } + + #[test] + fn test_serialize_ipv6_net() { + let net_str = "fd00::/32"; + let net: Ipv6Net = net_str.parse().unwrap(); + assert_tokens(&net.readable(), &[Token::Str(net_str)]); + assert_tokens(&net.compact(), &[ + // This is too painful, but Token::Bytes() seems to be + // an array with a length, which is not what we serialize. + Token::Tuple { len: 17 }, + Token::U8(253u8), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(32), + Token::TupleEnd, + ]); + } +} diff --git a/vendor/ipnet/src/lib.rs b/vendor/ipnet/src/lib.rs new file mode 100644 index 000000000..4f8fb166a --- /dev/null +++ b/vendor/ipnet/src/lib.rs @@ -0,0 +1,98 @@ +#![doc(html_root_url = "https://docs.rs/ipnet/2.7.2")] +//! Types for IPv4 and IPv6 network addresses. +//! +//! This module provides types and useful methods for working with IPv4 +//! and IPv6 network addresses, commonly called IP prefixes. The new +//! [`IpNet`], [`Ipv4Net`], and [`Ipv6Net`] types build on the existing +//! [`IpAddr`], [`Ipv4Addr`], and [`Ipv6Addr`] types already provided in +//! Rust's standard library and align to their design to stay +//! consistent. +//! +//! The module also provides the [`IpSubnets`], [`Ipv4Subnets`], and +//! [`Ipv6Subnets`] types for iterating over the subnets contained in +//! an IP address range. The [`IpAddrRange`], [`Ipv4AddrRange`], and +//! [`Ipv6AddrRange`] types for iterating over IP addresses in a range. +//! And traits that extend `Ipv4Addr` and `Ipv6Addr` with methods for +//! addition, subtraction, bitwise-and, and bitwise-or operations that +//! are missing in Rust's standard library. +//! +//! The module only uses stable features so it is guaranteed to compile +//! using the stable toolchain. +//! +//! # Organization +//! +//! * [`IpNet`] represents an IP network address, either IPv4 or IPv6. +//! * [`Ipv4Net`] and [`Ipv6Net`] are respectively IPv4 and IPv6 network +//! addresses. +//! * [`IpSubnets`], [`Ipv4Subnets`], and [`Ipv6Subnets`] are iterators +//! that generate the smallest set of IP network addresses bound by an +//! IP address range and minimum prefix length. These can be created +//! using their constructors. They are also returned by the +//! [`subnets()`] methods and used within the [`aggregate()`] methods. +//! * [`IpAddrRange`], [`Ipv4AddrRange`], and [`Ipv6AddrRange`] are +//! iterators that generate IP addresses. These can be created using +//! their constructors. They are also returned by the [`hosts()`] +//! methods. +//! * The [`IpAdd`], [`IpSub`], [`IpBitAnd`], [`IpBitOr`] traits extend +//! the [`Ipv4Addr`] and [`Ipv6Addr`] types with methods to perform +//! these operations. +//! +//! [`IpNet`]: enum.IpNet.html +//! [`Ipv4Net`]: struct.Ipv4Net.html +//! [`Ipv6Net`]: struct.Ipv6Net.html +//! [`IpAddr`]: https://doc.rust-lang.org/std/net/enum.IpAddr.html +//! [`Ipv4Addr`]: https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html +//! [`Ipv6Addr`]: https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html +//! [`IpSubnets`]: enum.IpSubnets.html +//! [`Ipv4Subnets`]: struct.Ipv4Subnets.html +//! [`Ipv6Subnets`]: struct.Ipv6Subnets.html +//! [`subnets()`]: enum.IpNet.html#method.subnets +//! [`aggregate()`]: enum.IpNet.html#method.aggregate +//! [`IpAddrRange`]: enum.IpAddrRange.html +//! [`Ipv4AddrRange`]: struct.Ipv4AddrRange.html +//! [`Ipv6AddrRange`]: struct.Ipv6AddrRange.html +//! [`hosts()`]: enum.IpNet.html#method.hosts +//! [`IpAdd`]: trait.IpAdd.html +//! [`IpSub`]: trait.IpSub.html +//! [`IpBitAnd`]: trait.IpBitAnd.html +//! [`IpBitOr`]: trait.IpBitOr.html +//! +//! # Serde support +//! +//! This library comes with support for [serde](https://serde.rs) but +//! it's not enabled by default. Use the `serde` [feature] to enable. +//! +//! ```toml +//! [dependencies] +//! ipnet = { version = "2", features = ["serde"] } +//! ``` +//! +//! For human readable formats (e.g. JSON) the `IpNet`, `Ipv4Net`, and +//! `Ipv6Net` types will serialize to their `Display` strings. +//! +//! For compact binary formats (e.g. Bincode) the `Ipv4Net` and +//! `Ipv6Net` types will serialize to a string of 5 and 17 bytes that +//! consist of the network address octects followed by the prefix +//! length. The `IpNet` type will serialize to an Enum with the V4 or V6 +//! variant index prepending the above string of 5 or 17 bytes. +//! +//! [feature]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section + +#[cfg(feature = "serde")] +extern crate serde; +#[cfg(feature = "schemars")] +extern crate schemars; + +pub use self::ipext::{IpAdd, IpSub, IpBitAnd, IpBitOr, IpAddrRange, Ipv4AddrRange, Ipv6AddrRange}; +pub use self::ipnet::{IpNet, Ipv4Net, Ipv6Net, PrefixLenError, IpSubnets, Ipv4Subnets, Ipv6Subnets}; +pub use self::parser::AddrParseError; +pub use self::mask::{ip_mask_to_prefix, ipv4_mask_to_prefix, ipv6_mask_to_prefix}; + +mod ipext; +mod ipnet; +mod parser; +mod mask; +#[cfg(feature = "serde")] +mod ipnet_serde; +#[cfg(feature = "schemars")] +mod ipnet_schemars; diff --git a/vendor/ipnet/src/mask.rs b/vendor/ipnet/src/mask.rs new file mode 100644 index 000000000..1047bf980 --- /dev/null +++ b/vendor/ipnet/src/mask.rs @@ -0,0 +1,128 @@ +use crate::PrefixLenError; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + +/// Converts a `IpAddr` network mask into a prefix. +/// +/// # Errors +/// If the mask is invalid this will return an `PrefixLenError`. +pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, PrefixLenError> { + match mask { + IpAddr::V4(mask) => ipv4_mask_to_prefix(mask), + IpAddr::V6(mask) => ipv6_mask_to_prefix(mask), + } +} + +/// Converts a `Ipv4Addr` network mask into a prefix. +/// +/// # Errors +/// If the mask is invalid this will return an `PrefixLenError`. +pub fn ipv4_mask_to_prefix(mask: Ipv4Addr) -> Result<u8, PrefixLenError> { + let mask = u32::from(mask); + + let prefix = mask.leading_ones(); + if mask.checked_shl(prefix).unwrap_or(0) == 0 { + Ok(prefix as u8) + } else { + Err(PrefixLenError) + } +} + +/// Converts a `Ipv6Addr` network mask into a prefix. +/// +/// # Errors +/// If the mask is invalid this will return an `PrefixLenError`. +pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, PrefixLenError> { + let mask = u128::from(mask); + + let prefix = mask.leading_ones(); + if mask.checked_shl(prefix).unwrap_or(0) == 0 { + Ok(prefix as u8) + } else { + Err(PrefixLenError) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Ipv4Net, Ipv6Net}; + + #[test] + fn v4_mask_to_prefix() { + let mask = Ipv4Addr::new(255, 255, 255, 128); + let prefix = ipv4_mask_to_prefix(mask); + assert_eq!(prefix, Ok(25)); + } + + #[test] + fn v4_mask_to_prefix_max() { + let mask = Ipv4Addr::from(u32::MAX); + let prefix = ipv4_mask_to_prefix(mask); + assert_eq!(prefix, Ok(32)); + } + + #[test] + fn invalid_v4_mask_to_prefix() { + let mask = Ipv4Addr::new(255, 0, 255, 0); + let prefix = ipv4_mask_to_prefix(mask); + assert!(prefix.is_err()); + } + + #[test] + fn ipv4net_with_netmask() { + { + // Positive test-case. + let addr = Ipv4Addr::new(127, 0, 0, 1); + let mask = Ipv4Addr::new(255, 0, 0, 0); + let net = Ipv4Net::with_netmask(addr, mask).unwrap(); + let expected = Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 8).unwrap(); + assert_eq!(net, expected); + } + { + // Negative test-case. + let addr = Ipv4Addr::new(127, 0, 0, 1); + let mask = Ipv4Addr::new(255, 0, 255, 0); + Ipv4Net::with_netmask(addr, mask).unwrap_err(); + } + } + + #[test] + fn v6_mask_to_prefix() { + let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0); + let prefix = ipv6_mask_to_prefix(mask); + assert_eq!(prefix, Ok(48)); + } + + #[test] + fn v6_mask_to_prefix_max() { + let mask = Ipv6Addr::from(u128::MAX); + let prefix = ipv6_mask_to_prefix(mask); + assert_eq!(prefix, Ok(128)); + } + + #[test] + fn invalid_v6_mask_to_prefix() { + let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0); + let prefix = ipv6_mask_to_prefix(mask); + assert!(prefix.is_err()); + } + + #[test] + fn ipv6net_with_netmask() { + { + // Positive test-case. + let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2); + let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0); + let net = Ipv6Net::with_netmask(addr, mask).unwrap(); + let expected = + Ipv6Net::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 48).unwrap(); + assert_eq!(net, expected); + } + { + // Negative test-case. + let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2); + let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0); + Ipv6Net::with_netmask(addr, mask).unwrap_err(); + } + } +} diff --git a/vendor/ipnet/src/parser.rs b/vendor/ipnet/src/parser.rs new file mode 100644 index 000000000..7ec999128 --- /dev/null +++ b/vendor/ipnet/src/parser.rs @@ -0,0 +1,345 @@ +//! A private parser implementation of IPv4 and IPv6 network addresses. +//! +//! The existing `std::net::parser` module cannot be extended because it +//! is private. It is copied and extended here with methods for parsing +//! IP network addresses. + +use std::error::Error; +use std::fmt; +use std::net::{Ipv4Addr, Ipv6Addr}; +use std::str::FromStr; + +use crate::ipnet::{IpNet, Ipv4Net, Ipv6Net}; + +pub struct Parser<'a> { + // parsing as ASCII, so can use byte array + s: &'a [u8], + pos: usize, +} + +impl<'a> Parser<'a> { + fn new(s: &'a str) -> Parser<'a> { + Parser { + s: s.as_bytes(), + pos: 0, + } + } + + fn is_eof(&self) -> bool { + self.pos == self.s.len() + } + + // Commit only if parser returns Some + fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where + F: FnOnce(&mut Parser) -> Option<T>, + { + let pos = self.pos; + let r = cb(self); + if r.is_none() { + self.pos = pos; + } + r + } + + // Commit only if parser read till EOF + fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where + F: FnOnce(&mut Parser) -> Option<T>, + { + self.read_atomically(move |p| { + match cb(p) { + Some(x) => if p.is_eof() {Some(x)} else {None}, + None => None, + } + }) + } + + // Return result of first successful parser + fn read_or<T>(&mut self, parsers: &mut [Box<dyn FnMut(&mut Parser) -> Option<T> + 'static>]) + -> Option<T> { + for pf in parsers { + if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { + return Some(r); + } + } + None + } + + // Apply 3 parsers sequentially + fn read_seq_3<A, B, C, PA, PB, PC>(&mut self, + pa: PA, + pb: PB, + pc: PC) + -> Option<(A, B, C)> where + PA: FnOnce(&mut Parser) -> Option<A>, + PB: FnOnce(&mut Parser) -> Option<B>, + PC: FnOnce(&mut Parser) -> Option<C>, + { + self.read_atomically(move |p| { + let a = pa(p); + let b = if a.is_some() { pb(p) } else { None }; + let c = if b.is_some() { pc(p) } else { None }; + match (a, b, c) { + (Some(a), Some(b), Some(c)) => Some((a, b, c)), + _ => None + } + }) + } + + // Read next char + fn read_char(&mut self) -> Option<char> { + if self.is_eof() { + None + } else { + let r = self.s[self.pos] as char; + self.pos += 1; + Some(r) + } + } + + // Return char and advance iff next char is equal to requested + fn read_given_char(&mut self, c: char) -> Option<char> { + self.read_atomically(|p| { + match p.read_char() { + Some(next) if next == c => Some(next), + _ => None, + } + }) + } + + // Read digit + fn read_digit(&mut self, radix: u8) -> Option<u8> { + fn parse_digit(c: char, radix: u8) -> Option<u8> { + let c = c as u8; + // assuming radix is either 10 or 16 + if c >= b'0' && c <= b'9' { + Some(c - b'0') + } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) { + Some(c - b'a' + 10) + } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) { + Some(c - b'A' + 10) + } else { + None + } + } + + self.read_atomically(|p| { + p.read_char().and_then(|c| parse_digit(c, radix)) + }) + } + + fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { + let mut r = 0; + let mut digit_count = 0; + loop { + match self.read_digit(radix) { + Some(d) => { + r = r * (radix as u32) + (d as u32); + digit_count += 1; + if digit_count > max_digits || r >= upto { + return None + } + } + None => { + if digit_count == 0 { + return None + } else { + return Some(r) + } + } + }; + } + } + + // Read number, failing if max_digits of number value exceeded + fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { + self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto)) + } + + fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> { + let mut bs = [0; 4]; + let mut i = 0; + while i < 4 { + if i != 0 && self.read_given_char('.').is_none() { + return None; + } + + let octet = self.read_number(10, 3, 0x100).map(|n| n as u8); + match octet { + Some(d) => bs[i] = d, + None => return None, + }; + i += 1; + } + Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3])) + } + + // Read IPv4 address + fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> { + self.read_atomically(|p| p.read_ipv4_addr_impl()) + } + + fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> { + fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr { + assert!(head.len() + tail.len() <= 8); + let mut gs = [0; 8]; + gs[..head.len()].copy_from_slice(head); + gs[(8 - tail.len()) .. 8].copy_from_slice(tail); + Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) + } + + fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize) + -> (usize, bool) { + let mut i = 0; + while i < limit { + if i < limit - 1 { + let ipv4 = p.read_atomically(|p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_ipv4_addr() + } else { + None + } + }); + if let Some(v4_addr) = ipv4 { + let octets = v4_addr.octets(); + groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16); + groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16); + return (i + 2, true); + } + } + + let group = p.read_atomically(|p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_number(16, 4, 0x10000).map(|n| n as u16) + } else { + None + } + }); + match group { + Some(g) => groups[i] = g, + None => return (i, false) + } + i += 1; + } + (i, false) + } + + let mut head = [0; 8]; + let (head_size, head_ipv4) = read_groups(self, &mut head, 8); + + if head_size == 8 { + return Some(Ipv6Addr::new( + head[0], head[1], head[2], head[3], + head[4], head[5], head[6], head[7])) + } + + // IPv4 part is not allowed before `::` + if head_ipv4 { + return None + } + + // read `::` if previous code parsed less than 8 groups + if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { + return None; + } + + let mut tail = [0; 8]; + let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size); + Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size])) + } + + fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> { + self.read_atomically(|p| p.read_ipv6_addr_impl()) + } + + /* Additions for IpNet below. */ + + // Read IPv4 network + fn read_ipv4_net(&mut self) -> Option<Ipv4Net> { + let ip_addr = |p: &mut Parser| p.read_ipv4_addr(); + let slash = |p: &mut Parser| p.read_given_char('/'); + let prefix_len = |p: &mut Parser| { + p.read_number(10, 2, 33).map(|n| n as u8) + }; + + self.read_seq_3(ip_addr, slash, prefix_len).map(|t| { + let (ip, _, prefix_len): (Ipv4Addr, char, u8) = t; + Ipv4Net::new(ip, prefix_len).unwrap() + }) + } + + // Read Ipv6 network + fn read_ipv6_net(&mut self) -> Option<Ipv6Net> { + let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); + let slash = |p: &mut Parser| p.read_given_char('/'); + let prefix_len = |p: &mut Parser| { + p.read_number(10, 3, 129).map(|n| n as u8) + }; + + self.read_seq_3(ip_addr, slash, prefix_len).map(|t| { + let (ip, _, prefix_len): (Ipv6Addr, char, u8) = t; + Ipv6Net::new(ip, prefix_len).unwrap() + }) + } + + fn read_ip_net(&mut self) -> Option<IpNet> { + let ipv4_net = |p: &mut Parser| p.read_ipv4_net().map(IpNet::V4); + let ipv6_net = |p: &mut Parser| p.read_ipv6_net().map(IpNet::V6); + self.read_or(&mut [Box::new(ipv4_net), Box::new(ipv6_net)]) + } + + /* Additions for IpNet above. */ +} + +/* Additions for IpNet below. */ + +impl FromStr for IpNet { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<IpNet, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_ip_net()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())) + } + } +} + +impl FromStr for Ipv4Net { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<Ipv4Net, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_ipv4_net()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())) + } + } +} + +impl FromStr for Ipv6Net { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<Ipv6Net, AddrParseError> { + match Parser::new(s).read_till_eof(|p| p.read_ipv6_net()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())) + } + } +} + +/* Additions for IpNet above. */ + +/// An error which can be returned when parsing an IP network address. +/// +/// This error is used as the error type for the [`FromStr`] implementation for +/// [`IpNet`], [`Ipv4Net`], and [`Ipv6Net`]. +/// +/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`IpNet`]: enum.IpNet.html +/// [`Ipv4Net`]: struct.Ipv4Net.html +/// [`Ipv6Net`]: struct.Ipv6Net.html +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AddrParseError(()); + +impl fmt::Display for AddrParseError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str("invalid IP address syntax") + } +} + +impl Error for AddrParseError {} |