From f7d9524f708898b93d700bda3526a99290274f10 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Thu, 5 Dec 2019 20:15:21 +0100 Subject: [PATCH 1/4] Make the iterators slightly better * Implement some useful traits on them. * Make reference an into-iterator. --- src/ipv4.rs | 9 +++++++++ src/ipv6.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/ipv4.rs b/src/ipv4.rs index 95e2a27..0d8ee6a 100644 --- a/src/ipv4.rs +++ b/src/ipv4.rs @@ -253,6 +253,7 @@ impl From for Ipv4Network { } } +#[derive(Clone, Debug)] pub struct Ipv4NetworkIterator { next: u32, end: u32, @@ -272,6 +273,14 @@ impl Iterator for Ipv4NetworkIterator { } } +impl IntoIterator for &'_ Ipv4Network { + type IntoIter = Ipv4NetworkIterator; + type Item = Ipv4Addr; + fn into_iter(self) -> Ipv4NetworkIterator { + self.iter() + } +} + /// Converts a `Ipv4Addr` network mask into a prefix. /// /// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`. diff --git a/src/ipv6.rs b/src/ipv6.rs index 0790f93..9152d08 100644 --- a/src/ipv6.rs +++ b/src/ipv6.rs @@ -227,6 +227,7 @@ impl From for Ipv6Network { } } +#[derive(Clone, Debug)] pub struct Ipv6NetworkIterator { next: u128, end: u128, @@ -246,6 +247,14 @@ impl Iterator for Ipv6NetworkIterator { } } +impl IntoIterator for &'_ Ipv6Network { + type IntoIter = Ipv6NetworkIterator; + type Item = Ipv6Addr; + fn into_iter(self) -> Ipv6NetworkIterator { + self.iter() + } +} + impl fmt::Display for Ipv6Network { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "{}/{}", self.ip(), self.prefix()) From 6cbb011597cdf61b2e37655817625f88b5fb2c37 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sat, 7 Dec 2019 19:32:51 +0100 Subject: [PATCH 2/4] Iterators for the IpNetwork Version-agnostic iterator in addition to the version specific ones. --- src/lib.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 24abf7a..09377d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,8 @@ mod ipv6; pub use crate::common::IpNetworkError; pub use crate::ipv4::{ipv4_mask_to_prefix, Ipv4Network}; pub use crate::ipv6::{ipv6_mask_to_prefix, Ipv6Network}; +use crate::ipv4::Ipv4NetworkIterator; +use crate::ipv6::Ipv6NetworkIterator; /// Represents a generic network range. This type can have two variants: /// the v4 and the v6 case. @@ -247,6 +249,17 @@ impl IpNetwork { IpNetwork::V6(ref ip) => NetworkSize::V6(ip.size()), } } + + /// Returns an iterator over the addresses contained in the network. + /// + /// This lists all the addresses in the network range, in ascending order. + pub fn iter(&self) -> IpNetworkIterator { + let inner = match self { + IpNetwork::V4(ip) => IpNetworkIteratorInner::V4(ip.iter()), + IpNetwork::V6(ip) => IpNetworkIteratorInner::V6(ip.iter()), + }; + IpNetworkIterator { inner } + } } /// Tries to parse the given string into a `IpNetwork`. Will first try to parse @@ -306,6 +319,34 @@ impl fmt::Display for IpNetwork { } } +#[derive(Clone, Debug)] +enum IpNetworkIteratorInner { + V4(Ipv4NetworkIterator), + V6(Ipv6NetworkIterator), +} + +pub struct IpNetworkIterator { + inner: IpNetworkIteratorInner, +} + +impl Iterator for IpNetworkIterator { + type Item = IpAddr; + fn next(&mut self) -> Option { + match &mut self.inner { + IpNetworkIteratorInner::V4(iter) => iter.next().map(IpAddr::V4), + IpNetworkIteratorInner::V6(iter) => iter.next().map(IpAddr::V6), + } + } +} + +impl IntoIterator for &'_ IpNetwork { + type IntoIter = IpNetworkIterator; + type Item = IpAddr; + fn into_iter(self) -> IpNetworkIterator { + self.iter() + } +} + /// Converts a `IpAddr` network mask into a prefix. /// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`. pub fn ip_mask_to_prefix(mask: IpAddr) -> Result { From dbf366cfdf07f9615b95d98e9d344079f7f69fe4 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sat, 7 Dec 2019 19:53:56 +0100 Subject: [PATCH 3/4] Iterators: reproducer for overflow on high end of iteration --- src/ipv4.rs | 15 +++++++++++++++ src/ipv6.rs | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/ipv4.rs b/src/ipv4.rs index 0d8ee6a..015c1f4 100644 --- a/src/ipv4.rs +++ b/src/ipv4.rs @@ -614,4 +614,19 @@ mod test { assert_eq!(skynet.overlaps(other2), false); assert_eq!(other2.overlaps(other3), true); } + + #[test] + fn edges() { + let low: Ipv4Network = "0.0.0.0/24".parse().unwrap(); + let low_addrs: Vec = low.iter().collect(); + assert_eq!(256, low_addrs.len()); + assert_eq!("0.0.0.0".parse::().unwrap(), low_addrs[0]); + assert_eq!("0.0.0.255".parse::().unwrap(), low_addrs[255]); + + let high: Ipv4Network = "255.255.255.0/24".parse().unwrap(); + let high_addrs: Vec = high.iter().collect(); + assert_eq!(256, high_addrs.len()); + assert_eq!("255.255.255.0".parse::().unwrap(), high_addrs[0]); + assert_eq!("255.255.255.255".parse::().unwrap(), high_addrs[255]); + } } diff --git a/src/ipv6.rs b/src/ipv6.rs index 9152d08..800ef8c 100644 --- a/src/ipv6.rs +++ b/src/ipv6.rs @@ -589,4 +589,15 @@ mod test { assert_eq!(other2.overlaps(other), true); } + + #[test] + fn edges() { + let low: Ipv6Network = "::0/120".parse().unwrap(); + let low_addrs: Vec = low.iter().collect(); + assert_eq!(256, low_addrs.len()); + + let high: Ipv6Network = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/120".parse().unwrap(); + let high_addrs: Vec = high.iter().collect(); + assert_eq!(256, high_addrs.len()); + } } From 5b09d82d43eb3ef6e72ea1d22a7a915ece1ea68d Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sat, 7 Dec 2019 21:24:19 +0100 Subject: [PATCH 4/4] Fix bug with overflow in iterator --- src/ipv4.rs | 18 +++++++++--------- src/ipv6.rs | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/ipv4.rs b/src/ipv4.rs index 015c1f4..9a8578c 100644 --- a/src/ipv4.rs +++ b/src/ipv4.rs @@ -62,8 +62,8 @@ impl Ipv4Network { /// addresses. pub fn iter(&self) -> Ipv4NetworkIterator { let start = u32::from(self.network()); - let end = start + self.size(); - Ipv4NetworkIterator { next: start, end } + let end = start + (self.size() - 1); + Ipv4NetworkIterator { next: Some(start), end } } pub fn ip(&self) -> Ipv4Addr { @@ -255,7 +255,7 @@ impl From for Ipv4Network { #[derive(Clone, Debug)] pub struct Ipv4NetworkIterator { - next: u32, + next: Option, end: u32, } @@ -263,13 +263,13 @@ impl Iterator for Ipv4NetworkIterator { type Item = Ipv4Addr; fn next(&mut self) -> Option { - if self.next < self.end { - let next = Ipv4Addr::from(self.next as u32); - self.next += 1; - Some(next) - } else { + let next = self.next?; + self.next = if next == self.end { None - } + } else { + Some(next + 1) + }; + Some(next.into()) } } diff --git a/src/ipv6.rs b/src/ipv6.rs index 800ef8c..5ddcf73 100644 --- a/src/ipv6.rs +++ b/src/ipv6.rs @@ -70,7 +70,7 @@ impl Ipv6Network { let end: u128 = dec | mask; Ipv6NetworkIterator { - next: start, + next: Some(start), end: end, } } @@ -229,7 +229,7 @@ impl From for Ipv6Network { #[derive(Clone, Debug)] pub struct Ipv6NetworkIterator { - next: u128, + next: Option, end: u128, } @@ -237,13 +237,13 @@ impl Iterator for Ipv6NetworkIterator { type Item = Ipv6Addr; fn next(&mut self) -> Option { - if self.next <= self.end { - let next = Ipv6Addr::from(self.next); - self.next += 1; - Some(next) - } else { + let next = self.next?; + self.next = if next == self.end { None - } + } else { + Some(next + 1) + }; + Some(next.into()) } }