diff --git a/src/lib.rs b/src/lib.rs index e0006b7..7aa35a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,13 @@ pub struct Network { network_address: IpAddr, broadcast_addr: IpAddr, num_hosts: u32, - subnet_mask: Option +} + +#[derive(Debug)] +#[allow(unused)] +pub struct Subnet { + pub networks: Vec, + pub subnet_mask: IpAddr, } impl Network { @@ -38,12 +44,11 @@ impl Network { /// //Awaiting implementation before creating doctest /// //let network = Network::new(&IpAddr::V4(127, 0, 0, 1), 32); /// ``` - fn new(given_address: &IpAddr, subnet_mask: &IpAddr) -> Network { + fn new(given_address: &IpAddr, broadcast_address: &IpAddr, num_hosts: u32) -> Network { Network { network_address: given_address.clone(), - broadcast_addr: given_address.clone(), - num_hosts: 0, - subnet_mask: Some(subnet_mask.clone()) + broadcast_addr: broadcast_address.clone(), + num_hosts, } } @@ -53,11 +58,11 @@ impl Network { /// use subnet_calculator::ip::IpAddr; /// use subnet_calculator::Network; /// - /// let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 1), 16).unwrap(); + /// let subnets = Network::create_subnet(&IpAddr::V4(127, 0, 0, 1), 16).unwrap(); /// - /// assert_eq!(networks.len(), 256); + /// assert_eq!(subnets.networks.len(), 256); /// ``` - pub fn create_subnet(network_address: &IpAddr, cidr: u8) -> Result, NetworkingErr> { + pub fn create_subnet(network_address: &IpAddr, cidr: u8) -> Result { //Get number of host and network bits. let network_class = Network::get_network_class(network_address)?; let network_address = network_address.to_arr()?; @@ -65,9 +70,7 @@ impl Network { // If the CIDR < class network enum associated value, then there is an invalid subnet. if cidr < network_class as u8 { return Err(NetworkingErr::InvalidCIDRErr) - } - - let num_borrowed_bits = cidr - network_class as u8; + } // Determine the starting network let mut base_network = network_address.clone(); @@ -75,35 +78,49 @@ impl Network { NetworkClass::A => 1, NetworkClass::B => 2, NetworkClass::C => 3 - }; - + }; + for i in most_sig_octet..4 { base_network[i as usize] = 0; } + // Remove trailing values from the base network + let num_borrowed_bits = cidr - network_class as u8; + + // Get the base network and next added address as u32's + let mut base_addr = u32::from(IpAddr::from_arr(&base_network)?); + let subnet_mask = u32::from(Network::gen_subnet_mask(cidr)?); + let addr_increment = u32::pow(2, subnet_mask.trailing_zeros()); + + // The number of hosts per network can be determined using the number of remaining + // bits raised to the second power. + let num_hosts = u32::pow(2, (32 - network_class as u8 - num_borrowed_bits) as u32); + // Determine how many networks are available // We know that this value is >0 at this point let num_networks = u32::pow(2, num_borrowed_bits as u32); + // The broadcast address will always be 1 less than the next subnet network address + let mut broadcast_addr = (base_addr + addr_increment) - 1; + //Create the subnets - let mut networks = vec![IpAddr::from_arr(&base_network)?]; + let mut subnet = Subnet::new(&IpAddr::from(base_addr), &IpAddr::from(broadcast_addr), num_hosts, cidr)?; // Determine the networking gaps //If there is only 1 network, returning the base network will be sufficient if num_networks > 1 { - //Get the base network and next added address as u32's - let mut base_address = u32::from(IpAddr::from_arr(&base_network)?); - let subnet_mask = u32::from(Network::gen_subnet_mask(cidr)?); - let addr_increment = u32::pow(2, subnet_mask.trailing_zeros()); for _ in 0..num_networks-1 { //Increment address and append to list - base_address += addr_increment; - networks.push(IpAddr::from(base_address)); + base_addr += addr_increment; + // We can start adding the full subnet range now instead of 1 less + broadcast_addr += addr_increment; + + subnet.networks.push(Network::new(&IpAddr::from(base_addr), &IpAddr::from(broadcast_addr), num_hosts)); } } - Ok(networks) + Ok(subnet) } /// Function that is used to determine the class of network that an IP is in. @@ -206,6 +223,19 @@ pub fn ip_and_cidr_from_string(ip_and_cidr: &String) -> Result<(IpAddr, u8), ip: return Ok((ip_address, cidr)) } +impl Subnet { + /// Function to return a new subbet struct + /// + fn new(base_address: &IpAddr, broadcast_addr: &IpAddr, num_hosts: u32, cidr: u8) -> Result { + Ok( + Subnet { + networks: vec![Network::new(base_address, broadcast_addr, num_hosts)], + subnet_mask: Network::gen_subnet_mask(cidr)?, + } + ) + } +} + mod tests { #[cfg(test)] #[test] @@ -253,26 +283,33 @@ mod tests { assert_eq!(Network::create_subnet(&IpAddr::V4(192, 168, 0, 1), 23).unwrap_err(), NetworkingErr::InvalidCIDRErr); let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 1), 10).unwrap(); - assert_eq!(networks.len(), 4); + assert_eq!(networks.networks.len(), 4); - let networks = Network::create_subnet(&IpAddr::V4(192, 168, 200, 1), 31).unwrap(); + let networks = Network::create_subnet(&IpAddr::V4(192, 168, 200, 1), 31).unwrap().networks; assert_eq!(networks.len(), 128); - assert_eq!(networks.last().unwrap(), &IpAddr::V4(192, 168, 200, 254)); - - let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 0), 8).unwrap(); + assert_eq!(networks.last().unwrap().network_address, IpAddr::V4(192, 168, 200, 254)); + assert_eq!(networks.last().unwrap().broadcast_addr, IpAddr::V4(192, 168, 200, 255)); + assert_eq!(networks.last().unwrap().num_hosts, 2); + + let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 0), 8).unwrap().networks; assert_eq!(networks.len(), 1); - assert_eq!(networks.last().unwrap(), &IpAddr::V4(127, 0, 0, 0)); + assert_eq!(networks.last().unwrap().network_address, IpAddr::V4(127, 0, 0, 0)); + assert_eq!(networks.last().unwrap().broadcast_addr, IpAddr::V4(127, 255, 255, 255)); + assert_eq!(networks.last().unwrap().num_hosts, 16_777_216); - let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 0), 9).unwrap(); + let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 0), 9).unwrap().networks; assert_eq!(networks.len(), 2); - assert_eq!(networks.first().unwrap(), &IpAddr::V4(127, 0, 0, 0)); + assert_eq!(networks.first().unwrap().network_address, IpAddr::V4(127, 0, 0, 0)); + assert_eq!(networks.first().unwrap().broadcast_addr, IpAddr::V4(127, 127, 255, 255)); - let networks = Network::create_subnet(&IpAddr::V4(168, 20, 0, 0), 17).unwrap(); + let networks = Network::create_subnet(&IpAddr::V4(168, 20, 0, 0), 17).unwrap().networks; assert_eq!(networks.len(), 2); - assert_eq!(networks.last().unwrap(), &IpAddr::V4(168, 20, 128, 0)); + assert_eq!(networks.last().unwrap().network_address, IpAddr::V4(168, 20, 128, 0)); + assert_eq!(networks.last().unwrap().broadcast_addr, IpAddr::V4(168, 20, 255, 255)); + assert_eq!(networks.last().unwrap().num_hosts, 32_768); - let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 0), 17).unwrap(); + let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 0), 17).unwrap().networks; assert_eq!(networks.len(), 512); - assert_eq!(networks.last().unwrap(), &IpAddr::V4(127, 255, 128, 0)); + assert_eq!(networks.last().unwrap().network_address, IpAddr::V4(127, 255, 128, 0)); } }