Added ability to create full networks, including the number of hosts on each as well as the broadcast address for each given network

This commit is contained in:
Luke Else 2023-08-04 11:30:03 +01:00
parent 108f8f2ab4
commit f224cf4c29

View File

@ -26,7 +26,13 @@ pub struct Network {
network_address: IpAddr,
broadcast_addr: IpAddr,
num_hosts: u32,
subnet_mask: Option<IpAddr>
}
#[derive(Debug)]
#[allow(unused)]
pub struct Subnet {
pub networks: Vec<Network>,
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<Vec<IpAddr>, NetworkingErr> {
pub fn create_subnet(network_address: &IpAddr, cidr: u8) -> Result<Subnet, NetworkingErr> {
//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<Subnet, NetworkingErr> {
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));
}
}