use std::fmt;
use std::net::AddrParseError;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
use std::num::ParseIntError;
use std::result;
use std::str::FromStr;
use std::u32;
use thiserror::Error;
const INIT_NEXT_VALUE: u8 = 0;
const IPV4_PREFIX_MAX_LEN: u8 = 32;
const IPV6_PREFIX_MAX_LEN: u8 = 128;
pub type Result<T, E = SubnetworkError> = result::Result<T, E>;
#[derive(Error, Debug)]
pub enum SubnetworkError {
#[error("invalid input: {msg}")]
InvalidInput { msg: String },
#[error("ip addr parse error")]
AddrParseError(#[from] AddrParseError),
#[error("num parse error")]
ParseIntError(#[from] ParseIntError),
}
#[derive(Debug, Clone, Copy)]
pub struct CrossIpv4Pool {
start: u32,
end: u32,
next: u32,
}
impl Iterator for CrossIpv4Pool {
type Item = Ipv4Addr;
fn next(&mut self) -> Option<Self::Item> {
if self.next <= self.end {
let ret = self.next;
self.next += 1;
Some(ret.into())
} else {
None
}
}
}
impl fmt::Display for CrossIpv4Pool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let start: Ipv4Addr = self.start.into();
let end: Ipv4Addr = self.end.into();
let now: Ipv4Addr = self.next.into();
write!(f, "{}-{}, next {}", start, end, now)
}
}
impl CrossIpv4Pool {
pub fn new<T: Into<Ipv4AddrExt>>(
start: T,
end: Ipv4Addr,
) -> Result<CrossIpv4Pool, SubnetworkError> {
let start_ip_ext: Ipv4AddrExt = start.into();
let end_ip_ext: Ipv4AddrExt = end.into();
let start_u32: u32 = start_ip_ext.addr;
let end_u32: u32 = end_ip_ext.addr;
if start_u32 <= end_u32 {
let cip = CrossIpv4Pool {
start: start_u32,
end: end_u32,
next: start_u32,
};
Ok(cip)
} else {
let error_range = format!("{}-{}", start_u32, end_u32);
Err(SubnetworkError::InvalidInput { msg: error_range })
}
}
pub fn to_vec(&self) -> Vec<Ipv4Addr> {
self.into_iter().collect()
}
pub fn contain(&self, addr: Ipv4Addr) -> bool {
let addr: u32 = addr.into();
if addr <= self.end && addr >= self.start {
true
} else {
false
}
}
pub fn len(&self) -> usize {
let length = self.end - self.start;
length as usize
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ipv4Pool {
prefix: u32,
mask: u32,
next: u32,
stop: u32,
addr: u32,
}
impl Iterator for Ipv4Pool {
type Item = Ipv4Addr;
fn next(&mut self) -> Option<Self::Item> {
if self.next < self.stop {
let ret = self.prefix + self.next;
self.next += 1;
Some(ret.into())
} else {
None
}
}
}
impl fmt::Display for Ipv4Pool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let prefix_addr: Ipv4Addr = self.prefix.into();
let mut prefix = 0;
let mut mask = self.mask;
while mask != 0 {
mask <<= 1;
prefix += 1;
}
write!(f, "{}/{}", prefix_addr, prefix)
}
}
impl FromStr for Ipv4Pool {
type Err = SubnetworkError;
fn from_str(addr: &str) -> Result<Self, Self::Err> {
if addr.contains("/") {
let addr_vec: Vec<&str> = addr.split("/").collect();
if addr_vec.len() == 2 {
let ip_addr = Ipv4Addr::from_str(addr_vec[0])?;
let prefix = u8::from_str(addr_vec[1])?;
if prefix <= IPV4_PREFIX_MAX_LEN {
let addr: u32 = ip_addr.into();
let mask: u32 = u32::MAX << (IPV4_PREFIX_MAX_LEN - prefix);
let next = INIT_NEXT_VALUE as u32;
let stop = 1 << (IPV4_PREFIX_MAX_LEN - prefix);
let prefix = addr & mask;
return Ok(Ipv4Pool {
prefix,
mask,
next,
stop,
addr,
});
}
}
}
Err(SubnetworkError::InvalidInput {
msg: addr.to_string(),
})
}
}
impl Ipv4Pool {
pub fn new<T: Into<Ipv4AddrExt>>(addr: T, prefix: u8) -> Result<Ipv4Pool, SubnetworkError> {
let addr_ext: Ipv4AddrExt = addr.into();
if prefix > IPV4_PREFIX_MAX_LEN {
let error_addr = format!("{}/{}", addr_ext, prefix);
Err(SubnetworkError::InvalidInput {
msg: error_addr.to_string(),
})
} else {
let addr: u32 = addr_ext.addr;
let mask: u32 = u32::MAX << (IPV4_PREFIX_MAX_LEN - prefix);
let next = INIT_NEXT_VALUE as u32;
let stop = 1 << (IPV4_PREFIX_MAX_LEN - prefix);
let prefix = addr & mask;
return Ok(Ipv4Pool {
prefix,
mask,
next,
stop,
addr,
});
}
}
pub fn to_vec(&self) -> Vec<Ipv4Addr> {
self.into_iter().collect()
}
pub fn contain(&self, addr: Ipv4Addr) -> bool {
let addr: u32 = addr.into();
if addr & self.mask == self.prefix {
true
} else {
false
}
}
pub fn network(&self) -> Ipv4Addr {
self.prefix.into()
}
pub fn broadcast(&self) -> Ipv4Addr {
let biggest = !self.mask;
let ret = self.prefix + biggest;
ret.into()
}
pub fn len(&self) -> usize {
let biggest = !self.mask + 1;
biggest as usize
}
pub fn addr(&self) -> Ipv4Addr {
self.addr.into()
}
}
#[derive(Debug, Clone, Copy)]
pub struct CrossIpv6Pool {
start: u128,
end: u128,
next: u128,
}
impl Iterator for CrossIpv6Pool {
type Item = Ipv6Addr;
fn next(&mut self) -> Option<Self::Item> {
if self.next <= self.end {
let ret = self.next;
self.next += 1;
Some(ret.into())
} else {
None
}
}
}
impl fmt::Display for CrossIpv6Pool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let start: Ipv6Addr = self.start.into();
let end: Ipv6Addr = self.end.into();
write!(f, "{}-{}", start, end)
}
}
impl CrossIpv6Pool {
pub fn new(start: Ipv6Addr, end: Ipv6Addr) -> Result<CrossIpv6Pool, SubnetworkError> {
let start_ipv6: Ipv6AddrExt = start.into();
let end_ipv6: Ipv6AddrExt = end.into();
if start_ipv6.addr <= end_ipv6.addr {
let cip = CrossIpv6Pool {
start: start_ipv6.addr,
end: end_ipv6.addr,
next: start_ipv6.addr,
};
Ok(cip)
} else {
let msg = format!("{}-{}", start, end);
Err(SubnetworkError::InvalidInput { msg })
}
}
pub fn to_vec(&self) -> Vec<Ipv6Addr> {
self.into_iter().collect()
}
pub fn contain(&self, addr: Ipv6Addr) -> bool {
let addr: u128 = addr.into();
if addr <= self.end && addr >= self.start {
true
} else {
false
}
}
pub fn len(&self) -> usize {
let length = self.end - self.start;
length as usize
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ipv6Pool {
prefix: u128,
mask: u128,
next: u128,
stop: u128,
addr: u128,
}
impl Iterator for Ipv6Pool {
type Item = Ipv6Addr;
fn next(&mut self) -> Option<Self::Item> {
if self.next < self.stop {
let ret = self.prefix + self.next;
self.next += 1;
Some(ret.into())
} else {
None
}
}
}
impl fmt::Display for Ipv6Pool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let prefix_addr: Ipv6Addr = self.prefix.into();
let mut prefix = 0;
let mut mask = self.mask;
while mask != 0 {
mask <<= 1;
prefix += 1;
}
write!(f, "{}/{}", prefix_addr, prefix)
}
}
impl FromStr for Ipv6Pool {
type Err = SubnetworkError;
fn from_str(addr: &str) -> Result<Self, Self::Err> {
if addr.contains("/") {
let addr_vec: Vec<&str> = addr.split("/").collect();
if addr_vec.len() == 2 {
let ip_addr = Ipv6Addr::from_str(addr_vec[0])?;
let prefix = u8::from_str(addr_vec[1])?;
if prefix <= IPV6_PREFIX_MAX_LEN {
let addr: u128 = ip_addr.into();
let mask: u128 = u128::MAX << (IPV6_PREFIX_MAX_LEN - prefix);
let next = INIT_NEXT_VALUE as u128;
let stop = 1 << (IPV6_PREFIX_MAX_LEN - prefix);
let prefix = addr & mask;
return Ok(Ipv6Pool {
prefix,
mask,
next,
stop,
addr,
});
}
}
}
Err(SubnetworkError::InvalidInput {
msg: addr.to_string(),
})
}
}
impl Ipv6Pool {
pub fn new(addr: Ipv6Addr, prefix: u8) -> Result<Ipv6Pool, SubnetworkError> {
if prefix > IPV6_PREFIX_MAX_LEN {
let error_addr = format!("{}/{}", addr, prefix);
Err(SubnetworkError::InvalidInput {
msg: error_addr.to_string(),
})
} else {
let addr: u128 = addr.into();
let mask: u128 = u128::MAX << (IPV6_PREFIX_MAX_LEN - prefix);
let next = INIT_NEXT_VALUE as u128;
let stop = 1 << (IPV6_PREFIX_MAX_LEN - prefix);
let prefix = addr & mask;
Ok(Ipv6Pool {
prefix,
mask,
next,
stop,
addr,
})
}
}
pub fn to_vec(&self) -> Vec<Ipv6Addr> {
self.into_iter().collect()
}
pub fn contain(&self, addr: Ipv6Addr) -> bool {
let addr: u128 = addr.into();
if addr & self.mask == self.prefix {
true
} else {
false
}
}
pub fn network(&self) -> Ipv6Addr {
self.prefix.into()
}
pub fn len(&self) -> usize {
let biggest = !self.mask + 1;
biggest as usize
}
pub fn addr(&self) -> Ipv6Addr {
self.addr.into()
}
}
#[derive(Debug, Clone, Copy)]
pub enum IpPool {
V4(Ipv4Pool),
V6(Ipv6Pool),
}
impl fmt::Display for IpPool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = match self {
Self::V4(x) => format!("{}", x),
Self::V6(x) => format!("{}", x),
};
write!(f, "{}", output)
}
}
impl Iterator for IpPool {
type Item = IpAddr;
fn next(&mut self) -> Option<Self::Item> {
match self {
IpPool::V4(iter) => iter.next().map(IpAddr::V4),
IpPool::V6(iter) => iter.next().map(IpAddr::V6),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ipv4AddrExt {
addr: u32,
}
impl fmt::Display for Ipv4AddrExt {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr: Ipv4Addr = self.addr.into();
write!(f, "{}", addr)
}
}
impl From<Ipv4Addr> for Ipv4AddrExt {
fn from(addr: Ipv4Addr) -> Self {
let addr: u32 = addr.into();
Ipv4AddrExt { addr }
}
}
impl From<Ipv4AddrExt> for Ipv4Addr {
fn from(addr: Ipv4AddrExt) -> Self {
let new_addr: u32 = addr.addr;
new_addr.into()
}
}
impl FromStr for Ipv4AddrExt {
type Err = SubnetworkError;
fn from_str(addr: &str) -> Result<Self, Self::Err> {
let new_addr = Ipv4Addr::from_str(addr)?;
let addr: u32 = new_addr.into();
Ok(Ipv4AddrExt { addr })
}
}
impl Ipv4AddrExt {
pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4AddrExt {
let a_fix = (a as u32) << 24;
let b_fix = (b as u32) << 16;
let c_fix = (c as u32) << 8;
let d_fix = d as u32;
let addr = a_fix + b_fix + c_fix + d_fix;
Ipv4AddrExt { addr }
}
pub fn largest_identical_prefix<T: Into<Ipv4AddrExt>>(&self, target: T) -> u8 {
let a = self.addr;
let b = target.into().addr;
let init_mask = 2u32.pow(31);
let mut mask = init_mask;
for c in 0..IPV4_PREFIX_MAX_LEN {
if a & mask != b & mask {
return c;
}
mask = (mask >> 1) + init_mask;
}
0
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ipv6AddrExt {
addr: u128,
}
impl fmt::Display for Ipv6AddrExt {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr: Ipv6Addr = self.addr.into();
write!(f, "{}", addr)
}
}
impl From<Ipv6Addr> for Ipv6AddrExt {
fn from(addr: Ipv6Addr) -> Self {
let addr: u128 = addr.into();
Ipv6AddrExt { addr }
}
}
impl From<Ipv6AddrExt> for Ipv6Addr {
fn from(addr: Ipv6AddrExt) -> Self {
let new_addr: u128 = addr.addr;
new_addr.into()
}
}
impl FromStr for Ipv6AddrExt {
type Err = SubnetworkError;
fn from_str(addr: &str) -> Result<Self, Self::Err> {
let new_addr = Ipv6Addr::from_str(addr)?;
let addr: u128 = new_addr.into();
Ok(Ipv6AddrExt { addr })
}
}
impl Ipv6AddrExt {
pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6AddrExt {
let a_fix = (a as u128) << 112;
let b_fix = (b as u128) << 96;
let c_fix = (c as u128) << 80;
let d_fix = (d as u128) << 64;
let e_fix = (e as u128) << 48;
let f_fix = (f as u128) << 32;
let g_fix = (g as u128) << 16;
let h_fix = h as u128;
let addr = a_fix + b_fix + c_fix + d_fix + e_fix + f_fix + g_fix + h_fix;
Ipv6AddrExt { addr }
}
pub fn node_multicast(&self) -> Ipv6Addr {
let node = Ipv6Addr::new(
0xff01, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0xff00, 0x0000,
);
let mask = Ipv6Addr::new(
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ff, 0xffff,
);
let node_u128: u128 = node.into();
let mask_u128: u128 = mask.into();
(node_u128 + (mask_u128 & self.addr)).into()
}
pub fn link_multicast(&self) -> Ipv6Addr {
let link = Ipv6Addr::new(
0xff02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0xff00, 0x0000,
);
let mask = Ipv6Addr::new(
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ff, 0xffff,
);
let link_u128: u128 = link.into();
let mask_u128: u128 = mask.into();
(link_u128 + (mask_u128 & self.addr)).into()
}
pub fn site_multicast(&self) -> Ipv6Addr {
let site = Ipv6Addr::new(
0xff05, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0xff00, 0x0000,
);
let mask = Ipv6Addr::new(
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ff, 0xffff,
);
let site_u128: u128 = site.into();
let mask_u128: u128 = mask.into();
(site_u128 + (mask_u128 & self.addr)).into()
}
pub fn largest_identical_prefix<T: Into<Ipv6AddrExt>>(&self, target: T) -> u8 {
let a = self.addr;
let b = target.into().addr;
let init_mask = 2u128.pow(127);
let mut mask = init_mask;
for c in 0..IPV6_PREFIX_MAX_LEN {
if a & mask != b & mask {
return c;
}
mask = (mask >> 1) + init_mask;
}
0
}
}
#[derive(Debug, Clone, Copy)]
pub struct NetmaskExt {
prefix: u8,
}
impl NetmaskExt {
pub fn new(prefix: u8) -> NetmaskExt {
NetmaskExt { prefix }
}
pub fn from_addr(addr: IpAddr) -> NetmaskExt {
let prefix = match addr {
IpAddr::V4(ipv4) => {
let mask = u32::from_be_bytes(ipv4.octets());
let prefix = mask.count_ones() as u8;
prefix
}
IpAddr::V6(ipv6) => {
let mask = u128::from_be_bytes(ipv6.octets());
let prefix = mask.count_ones() as u8;
prefix
}
};
NetmaskExt { prefix }
}
pub fn get_prefix(&self) -> u8 {
self.prefix
}
pub fn to_ipv4(&self) -> Result<Ipv4Addr, SubnetworkError> {
if self.prefix == 0 {
Ok((0 as u32).into())
} else {
if self.prefix > IPV4_PREFIX_MAX_LEN {
let msg = format!("prefix: {}", self.prefix);
Err(SubnetworkError::InvalidInput { msg })
} else {
Ok((u32::MAX << (IPV4_PREFIX_MAX_LEN - self.prefix)).into())
}
}
}
pub fn to_ipv6(&self) -> Result<Ipv6Addr, SubnetworkError> {
if self.prefix == 0 {
Ok((0 as u128).into())
} else {
if self.prefix > IPV6_PREFIX_MAX_LEN {
let msg = format!("prefix: {}", self.prefix);
Err(SubnetworkError::InvalidInput { msg })
} else {
Ok((u128::MAX << (IPV6_PREFIX_MAX_LEN - self.prefix)).into())
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn readme_example_1() {
let pool = Ipv4Pool::new(Ipv4Addr::new(192, 168, 1, 1), 24).unwrap();
for ipv4 in pool {
println!("{}", ipv4);
}
let pool = Ipv4Pool::from_str("192.168.1.0/24").unwrap();
for ipv4 in pool {
println!("{}", ipv4);
}
let pool: Ipv4Pool = "192.168.1.0/24".parse().unwrap();
for ipv4 in pool {
println!("{}", ipv4);
}
let test_ipv4 = Ipv4Addr::new(192, 168, 1, 233);
assert_eq!(pool.contain(test_ipv4), true);
let broadcast = Ipv4Addr::new(192, 168, 1, 255);
assert_eq!(pool.broadcast(), broadcast);
let network = Ipv4Addr::new(192, 168, 1, 0);
assert_eq!(pool.network(), network);
assert_eq!(pool.len(), 256);
assert_eq!(pool.to_string(), "192.168.1.0/24");
}
#[test]
fn readme_example_2() {
let start = Ipv4Addr::new(192, 168, 1, 16);
let end = Ipv4Addr::new(192, 168, 3, 200);
let pool = CrossIpv4Pool::new(start, end).unwrap();
for i in pool {
println!("{:?}", i);
}
let test_ipv4 = Ipv4Addr::new(192, 168, 1, 233);
assert_eq!(pool.contain(test_ipv4), true);
let test_ipv4 = Ipv4Addr::new(192, 168, 2, 0);
assert_eq!(pool.contain(test_ipv4), true);
let test_ipv4 = Ipv4Addr::new(192, 168, 3, 255);
assert_eq!(pool.contain(test_ipv4), false);
let test_ipv4 = Ipv4Addr::new(192, 168, 3, 200);
assert_eq!(pool.contain(test_ipv4), true);
}
#[test]
fn readme_example_3() {
let ip1 = Ipv4Addr::new(192, 168, 1, 0);
let ip2 = Ipv4Addr::new(192, 168, 1, 255);
let ip1ext: Ipv4AddrExt = ip1.into();
assert_eq!(ip1ext.largest_identical_prefix(ip2), 24);
let ip1 = Ipv4Addr::new(192, 168, 1, 136);
let ip2 = Ipv4Addr::new(192, 168, 1, 192);
let ip1ext: Ipv4AddrExt = ip1.into();
assert_eq!(ip1ext.largest_identical_prefix(ip2), 25);
}
#[test]
fn readme_example_4() {
let ipv6 = Ipv6Addr::from_str("::ffff:192.10.2.255").unwrap();
let ipv6_ext: Ipv6AddrExt = ipv6.into();
let ipv6_node_multicast = Ipv6Addr::from_str("ff01::1:ff0a:2ff").unwrap();
assert_eq!(ipv6_ext.node_multicast(), ipv6_node_multicast);
let ipv6_link_multicast = Ipv6Addr::from_str("ff02::1:ff0a:2ff").unwrap();
assert_eq!(ipv6_ext.link_multicast(), ipv6_link_multicast);
let ipv6_site_multicast = Ipv6Addr::from_str("ff05::1:ff0a:2ff").unwrap();
assert_eq!(ipv6_ext.site_multicast(), ipv6_site_multicast);
}
#[test]
fn readme_example_5() {
let netmask = NetmaskExt::new(24);
let netmask_addr = netmask.to_ipv4().unwrap();
assert_eq!(netmask_addr, Ipv4Addr::new(255, 255, 255, 0));
let netmask = NetmaskExt::new(26);
let netmask_addr = netmask.to_ipv4().unwrap();
assert_eq!(netmask_addr, Ipv4Addr::new(255, 255, 255, 192));
}
#[test]
fn netmask_ext() {
let addr = IpAddr::V4(Ipv4Addr::new(255, 255, 255, 0));
let netmask = NetmaskExt::from_addr(addr);
let prefix = netmask.get_prefix();
assert_eq!(prefix, 24);
let addr = IpAddr::V4(Ipv4Addr::new(255, 255, 255, 192));
let netmask = NetmaskExt::from_addr(addr);
let prefix = netmask.get_prefix();
assert_eq!(prefix, 26);
let addr = IpAddr::V4(Ipv4Addr::new(255, 255, 0, 0));
let netmask = NetmaskExt::from_addr(addr);
let prefix = netmask.get_prefix();
assert_eq!(prefix, 16);
let addr = IpAddr::V4(Ipv4Addr::new(255, 255, 192, 0));
let netmask = NetmaskExt::from_addr(addr);
let prefix = netmask.get_prefix();
assert_eq!(prefix, 18);
}
#[test]
fn ipv4_methods() {
let ipv4 = Ipv4Addr::new(192, 168, 1, 1);
if ipv4.is_private() {
println!("{} is private", ipv4);
} else {
println!("{} is not private", ipv4);
}
let ipv6 = Ipv6Addr::new(0xfe80, 0, 0, 0, 0x20c, 0x29ff, 0xfedd, 0xf57);
if ipv6.is_multicast() {
println!("{} is multicast", ipv6);
} else {
println!("{} is not multicast", ipv6);
}
}
#[test]
fn ipv4_pool_print() {
let test_str = "192.168.1.0/24";
let ipv4_pool = Ipv4Pool::from_str(test_str).unwrap();
let ipv4_pool_str = format!("{}", ipv4_pool);
println!("{}", ipv4_pool_str);
}
#[test]
fn ipv4_print() {
let test_str = "192.168.1.1";
let ipv4 = Ipv4AddrExt::from_str(test_str).unwrap();
let ipv4_str = format!("{}", ipv4);
assert_eq!(ipv4_str, test_str);
}
#[test]
fn ipv4() {
let ipv4 = Ipv4AddrExt::from_str("192.168.1.1").unwrap();
println!("{:8b}", ipv4.addr);
assert_eq!(ipv4.addr, 3232235777);
}
#[test]
fn ipv6() {
let ipv6 = Ipv6AddrExt::from_str("::ffff:192.10.2.255").unwrap();
println!("{:?}", ipv6);
assert_eq!(ipv6.addr, 281473903624959);
}
#[test]
fn test_github_issues_1() {
let _pool1 = Ipv4Pool::from_str("1.2.3.4/33");
let _pool2 = Ipv4Pool::from_str("1.2.3.4/");
let _pool3 = Ipv4Pool::from_str("nonip/24");
}
}