From 49afb3a45addfaad06f10890ea278874a43edfd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=A7=E9=9D=9C?= Date: Mon, 5 Feb 2018 23:13:52 +0800 Subject: [PATCH] Add from_netmask()/netmask()/broadcast()/network() methods on IPv4Cidr --- src/wire/ipv4.rs | 152 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/src/wire/ipv4.rs b/src/wire/ipv4.rs index c39c967..e6be5ba 100644 --- a/src/wire/ipv4.rs +++ b/src/wire/ipv4.rs @@ -124,6 +124,16 @@ impl Cidr { Cidr { address, prefix_len } } + /// Create an IPv4 CIDR block from the given address and network mask. + pub fn from_netmask(addr: Address, netmask: Address) -> Result { + let netmask = NetworkEndian::read_u32(&netmask.0[..]); + if netmask.leading_zeros() == 0 && netmask.trailing_zeros() == netmask.count_zeros() { + Ok(Cidr { address: addr, prefix_len: netmask.count_ones() as u8 }) + } else { + Err(Error::Illegal) + } + } + /// Return the address of this IPv4 CIDR block. pub fn address(&self) -> Address { self.address @@ -134,6 +144,55 @@ impl Cidr { self.prefix_len } + /// Return the network mask of this IPv4 CIDR. + pub fn netmask(&self) -> Address { + if self.prefix_len == 0 { + return Address([0, 0, 0, 0]); + } + + let number = 0xffffffffu32 << (32 - self.prefix_len); + let data = [ + ((number >> 24) & 0xff) as u8, + ((number >> 16) & 0xff) as u8, + ((number >> 8) & 0xff) as u8, + ((number >> 0) & 0xff) as u8, + ]; + + Address(data) + } + + /// Return the broadcast address of this IPv4 CIDR. + pub fn broadcast(&self) -> Option
{ + let network = self.network(); + + if network.prefix_len == 31 || network.prefix_len == 32 { + return None; + } + + let network_number = NetworkEndian::read_u32(&network.address.0[..]); + let number = network_number | 0xffffffffu32 >> network.prefix_len; + let data = [ + ((number >> 24) & 0xff) as u8, + ((number >> 16) & 0xff) as u8, + ((number >> 8) & 0xff) as u8, + ((number >> 0) & 0xff) as u8, + ]; + + Some(Address(data)) + } + + /// Return the network block of this IPv4 CIDR. + pub fn network(&self) -> Cidr { + let mask = self.netmask().0; + let network = [ + self.address.0[0] & mask[0], + self.address.0[1] & mask[1], + self.address.0[2] & mask[2], + self.address.0[3] & mask[3], + ]; + Cidr { address: Address(network), prefix_len: self.prefix_len } + } + /// Query whether the subnetwork described by this IPv4 CIDR block contains /// the given address. pub fn contains_addr(&self, addr: &Address) -> bool { @@ -829,4 +888,97 @@ mod test { let cidr_without_prefix = Cidr::new(cidr.address(), 0); assert!(cidr_without_prefix.contains_addr(&Address::new(127, 0, 0, 1))); } + + #[test] + fn test_cidr_from_netmask() { + assert_eq!(Cidr::from_netmask(Address([0, 0, 0, 0]), Address([1, 0, 2, 0])).is_err(), + true); + assert_eq!(Cidr::from_netmask(Address([0, 0, 0, 0]), Address([0, 0, 0, 0])).is_err(), + true); + assert_eq!(Cidr::from_netmask(Address([0, 0, 0, 1]), Address([255, 255, 255, 0])).unwrap(), + Cidr::new(Address([0, 0, 0, 1]), 24)); + assert_eq!(Cidr::from_netmask(Address([192, 168, 0, 1]), Address([255, 255, 0, 0])).unwrap(), + Cidr::new(Address([192, 168, 0, 1]), 16)); + assert_eq!(Cidr::from_netmask(Address([172, 16, 0, 1]), Address([255, 240, 0, 0])).unwrap(), + Cidr::new(Address([172, 16, 0, 1]), 12)); + assert_eq!(Cidr::from_netmask(Address([255, 255, 255, 1]), Address([255, 255, 255, 0])).unwrap(), + Cidr::new(Address([255, 255, 255, 1]), 24)); + assert_eq!(Cidr::from_netmask(Address([255, 255, 255, 255]), Address([255, 255, 255, 255])).unwrap(), + Cidr::new(Address([255, 255, 255, 255]), 32)); + } + + #[test] + fn test_cidr_netmask() { + assert_eq!(Cidr::new(Address([0, 0, 0, 0]), 0).netmask(), + Address([0, 0, 0, 0])); + assert_eq!(Cidr::new(Address([0, 0, 0, 1]), 24).netmask(), + Address([255, 255, 255, 0])); + assert_eq!(Cidr::new(Address([0, 0, 0, 0]), 32).netmask(), + Address([255, 255, 255, 255])); + assert_eq!(Cidr::new(Address([127, 0, 0, 0]), 8).netmask(), + Address([255, 0, 0, 0])); + assert_eq!(Cidr::new(Address([192, 168, 0, 0]), 16).netmask(), + Address([255, 255, 0, 0])); + assert_eq!(Cidr::new(Address([192, 168, 1, 1]), 16).netmask(), + Address([255, 255, 0, 0])); + assert_eq!(Cidr::new(Address([192, 168, 1, 1]), 17).netmask(), + Address([255, 255, 128, 0])); + assert_eq!(Cidr::new(Address([172, 16, 0, 0]), 12).netmask(), + Address([255, 240, 0, 0])); + assert_eq!(Cidr::new(Address([255, 255, 255, 1]), 24).netmask(), + Address([255, 255, 255, 0])); + assert_eq!(Cidr::new(Address([255, 255, 255, 255]), 32).netmask(), + Address([255, 255, 255, 255])); + } + + #[test] + fn test_cidr_broadcast() { + assert_eq!(Cidr::new(Address([0, 0, 0, 0]), 0).broadcast().unwrap(), + Address([255, 255, 255, 255])); + assert_eq!(Cidr::new(Address([0, 0, 0, 1]), 24).broadcast().unwrap(), + Address([0, 0, 0, 255])); + assert_eq!(Cidr::new(Address([0, 0, 0, 0]), 32).broadcast(), + None); + assert_eq!(Cidr::new(Address([127, 0, 0, 0]), 8).broadcast().unwrap(), + Address([127, 255, 255, 255])); + assert_eq!(Cidr::new(Address([192, 168, 0, 0]), 16).broadcast().unwrap(), + Address([192, 168, 255, 255])); + assert_eq!(Cidr::new(Address([192, 168, 1, 1]), 16).broadcast().unwrap(), + Address([192, 168, 255, 255])); + assert_eq!(Cidr::new(Address([192, 168, 1, 1]), 17).broadcast().unwrap(), + Address([192, 168, 127, 255])); + assert_eq!(Cidr::new(Address([172, 16, 0, 1]), 12).broadcast().unwrap(), + Address([172, 31, 255, 255])); + assert_eq!(Cidr::new(Address([255, 255, 255, 1]), 24).broadcast().unwrap(), + Address([255, 255, 255, 255])); + assert_eq!(Cidr::new(Address([255, 255, 255, 254]), 31).broadcast(), + None); + assert_eq!(Cidr::new(Address([255, 255, 255, 255]), 32).broadcast(), + None); + + } + + #[test] + fn test_cidr_network() { + assert_eq!(Cidr::new(Address([0, 0, 0, 0]), 0).network(), + Cidr::new(Address([0, 0, 0, 0]), 0)); + assert_eq!(Cidr::new(Address([0, 0, 0, 1]), 24).network(), + Cidr::new(Address([0, 0, 0, 0]), 24)); + assert_eq!(Cidr::new(Address([0, 0, 0, 0]), 32).network(), + Cidr::new(Address([0, 0, 0, 0]), 32)); + assert_eq!(Cidr::new(Address([127, 0, 0, 0]), 8).network(), + Cidr::new(Address([127, 0, 0, 0]), 8)); + assert_eq!(Cidr::new(Address([192, 168, 0, 0]), 16).network(), + Cidr::new(Address([192, 168, 0, 0]), 16)); + assert_eq!(Cidr::new(Address([192, 168, 1, 1]), 16).network(), + Cidr::new(Address([192, 168, 0, 0]), 16)); + assert_eq!(Cidr::new(Address([192, 168, 1, 1]), 17).network(), + Cidr::new(Address([192, 168, 0, 0]), 17)); + assert_eq!(Cidr::new(Address([172, 16, 0, 1]), 12).network(), + Cidr::new(Address([172, 16, 0, 0]), 12)); + assert_eq!(Cidr::new(Address([255, 255, 255, 1]), 24).network(), + Cidr::new(Address([255, 255, 255, 0]), 24)); + assert_eq!(Cidr::new(Address([255, 255, 255, 255]), 32).network(), + Cidr::new(Address([255, 255, 255, 255]), 32)); + } }