use core::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum IpNet {
V4(Ipv4Net),
V6(Ipv6Net),
}
impl IpNet {
pub fn new(ip: IpAddr, prefix_len: u8) -> IpNet {
match ip {
IpAddr::V4(addr) => Ipv4Net::new(addr, prefix_len).into(),
IpAddr::V6(addr) => Ipv6Net::new(addr, prefix_len).into(),
}
}
pub fn new_with_netmask(ip: IpAddr, netmask: IpAddr) -> IpNet {
let prefix = ip_netmask_to_prefix(netmask);
Self::new(ip, prefix)
}
pub fn addr(&self) -> IpAddr {
match *self {
IpNet::V4(ref a) => IpAddr::V4(a.addr),
IpNet::V6(ref a) => IpAddr::V6(a.addr),
}
}
pub fn prefix_len(&self) -> u8 {
match *self {
IpNet::V4(ref a) => a.prefix_len,
IpNet::V6(ref a) => a.prefix_len,
}
}
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(),
}
}
pub fn netmask(&self) -> IpAddr {
match *self {
IpNet::V4(ref a) => IpAddr::V4(a.netmask()),
IpNet::V6(ref a) => IpAddr::V6(a.netmask()),
}
}
pub fn hostmask(&self) -> IpAddr {
match *self {
IpNet::V4(ref a) => IpAddr::V4(a.hostmask()),
IpNet::V6(ref a) => IpAddr::V6(a.hostmask()),
}
}
pub fn network(&self) -> IpAddr {
match *self {
IpNet::V4(ref a) => IpAddr::V4(a.network()),
IpNet::V6(ref a) => IpAddr::V6(a.network()),
}
}
pub fn broadcast(&self) -> IpAddr {
match *self {
IpNet::V4(ref a) => IpAddr::V4(a.broadcast()),
IpNet::V6(ref a) => IpAddr::V6(a.broadcast()),
}
}
}
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(addr) => IpNet::V4(addr.into()),
IpAddr::V6(addr) => IpNet::V6(addr.into()),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Ipv4Net {
pub addr: Ipv4Addr,
pub prefix_len: u8,
pub netmask: Ipv4Addr,
}
impl Ipv4Net {
pub fn new(ipv4_addr: Ipv4Addr, prefix_len: u8) -> Ipv4Net {
Ipv4Net {
addr: ipv4_addr,
prefix_len: prefix_len,
netmask: prefix_to_ipv4_netmask(prefix_len),
}
}
pub fn new_with_netmask(ipv4_addr: Ipv4Addr, netmask: Ipv4Addr) -> Ipv4Net {
Ipv4Net {
addr: ipv4_addr,
prefix_len: ipv4_netmask_to_prefix(netmask),
netmask: netmask,
}
}
pub const fn max_prefix_len(&self) -> u8 {
32
}
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)
}
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)
}
pub fn network(&self) -> Ipv4Addr {
Ipv4Addr::from(u32::from(self.addr) & self.netmask_u32())
}
pub fn broadcast(&self) -> Ipv4Addr {
Ipv4Addr::from(u32::from(self.addr) | self.hostmask_u32())
}
}
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,
netmask: prefix_to_ipv4_netmask(32),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Ipv6Net {
pub addr: Ipv6Addr,
pub prefix_len: u8,
pub netmask: Ipv6Addr,
}
impl Ipv6Net {
pub fn new(ipv6_addr: Ipv6Addr, prefix_len: u8) -> Ipv6Net {
Ipv6Net {
addr: ipv6_addr,
prefix_len: prefix_len,
netmask: prefix_to_ipv6_netmask(prefix_len),
}
}
pub fn new_with_netmask(ipv6_addr: Ipv6Addr, netmask: Ipv6Addr) -> Ipv6Net {
Ipv6Net {
addr: ipv6_addr,
prefix_len: ipv6_netmask_to_prefix(netmask),
netmask: netmask,
}
}
pub const fn max_prefix_len(&self) -> u8 {
128
}
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())
}
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())
}
pub fn network(&self) -> Ipv6Addr {
(u128::from(self.addr) & self.netmask_u128()).into()
}
pub fn broadcast(&self) -> Ipv6Addr {
(u128::from(self.addr) | self.hostmask_u128()).into()
}
}
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,
netmask: prefix_to_ipv6_netmask(128),
}
}
}
fn ip_netmask_to_prefix(mask: IpAddr) -> u8 {
match mask {
IpAddr::V4(mask) => ipv4_netmask_to_prefix(mask),
IpAddr::V6(mask) => ipv6_netmask_to_prefix(mask),
}
}
fn ipv4_netmask_to_prefix(netmask: Ipv4Addr) -> u8 {
let netmask = u32::from(netmask);
let prefix = (!netmask).leading_zeros() as u8;
if (u64::from(netmask) << prefix) & 0xffff_ffff != 0 {
0
} else {
prefix
}
}
fn ipv6_netmask_to_prefix(netmask: Ipv6Addr) -> u8 {
let netmask = netmask.segments();
let mut mask_iter = netmask.iter();
let mut prefix = 0;
for &segment in &mut mask_iter {
if segment == 0xffff {
prefix += 16;
} else if segment == 0 {
break;
} else {
let prefix_bits = (!segment).leading_zeros() as u8;
if segment << prefix_bits != 0 {
return 0;
}
prefix += prefix_bits;
break;
}
}
for &segment in mask_iter {
if segment != 0 {
return 0;
}
}
prefix
}
fn prefix_to_ipv4_netmask(prefix_len: u8) -> Ipv4Addr {
let netmask_u32: u32 = u32::max_value()
.checked_shl(32 - prefix_len as u32)
.unwrap_or(0);
Ipv4Addr::from(netmask_u32)
}
fn prefix_to_ipv6_netmask(prefix_len: u8) -> Ipv6Addr {
let netmask_u128: u128 = u128::max_value()
.checked_shl((128 - prefix_len) as u32)
.unwrap_or(u128::min_value());
Ipv6Addr::from(netmask_u128)
}