Added new functionality to Network and changed error handling to be a single enum. create_subnet() is still WIP

This commit is contained in:
Luke Else 2023-04-17 17:24:35 +01:00
parent a067a3e349
commit e1a978cb1f
2 changed files with 78 additions and 27 deletions

View File

@ -1,4 +1,5 @@
use std::str::FromStr; use std::str::FromStr;
use super::NetworkingErr;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct InvalidIPErr; pub struct InvalidIPErr;
@ -12,7 +13,7 @@ pub struct InvalidIPErr;
/// IpAddr::V6(String::from("::1")) /// IpAddr::V6(String::from("::1"))
/// ``` /// ```
#[allow(unused)] #[allow(unused)]
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum IpAddr { pub enum IpAddr {
V4(u8, u8, u8, u8), V4(u8, u8, u8, u8),
V6(String) V6(String)
@ -30,7 +31,7 @@ impl ToString for IpAddr {
impl FromStr for IpAddr { impl FromStr for IpAddr {
type Err = InvalidIPErr; type Err = NetworkingErr;
/// Function that generates a IpAddr / Err from a string /// Function that generates a IpAddr / Err from a string
/// ///
/// # Limitation /// # Limitation
@ -46,18 +47,18 @@ impl FromStr for IpAddr {
let split_ip = s.split('.'); let split_ip = s.split('.');
if split_ip.clone().count() != 4 { if split_ip.clone().count() != 4 {
//Invalid IP address entered //Invalid IP address entered
return Err(InvalidIPErr) return Err(super::NetworkingErr::InvalidIPErr)
} }
let mut ip: [u8; 4] = Default::default(); let mut ip: [u8; 4] = Default::default();
//Go through each octet and ensure it can be parsed; //Go through each octet and ensure it can be parsed;
for (i, oct) in split_ip.into_iter().enumerate() { for (i, oct) in split_ip.into_iter().enumerate() {
if i > ip.len() { if i > ip.len() {
//Ip string is out of the range of the 4 octets in an IPv4 Address //Ip string is out of the range of the 4 octets in an IPv4 Address
return Err(InvalidIPErr) return Err(NetworkingErr::InvalidIPErr)
} }
match oct.parse::<u8>() { match oct.parse::<u8>() {
Ok(parsed_oct) => ip[i] = parsed_oct, Ok(parsed_oct) => ip[i] = parsed_oct,
Err(_) => return Err(InvalidIPErr) Err(_) => return Err(NetworkingErr::InvalidIPErr)
} }
} }
Ok(IpAddr::V4(ip[0],ip[1],ip[2],ip[3])) Ok(IpAddr::V4(ip[0],ip[1],ip[2],ip[3]))
@ -106,6 +107,6 @@ mod tests {
use super::*; use super::*;
let ip = "127.0.0.0.1"; let ip = "127.0.0.0.1";
IpAddr::from_str(ip).unwrap(); IpAddr::from_str(ip).unwrap();
assert_eq!(IpAddr::from_str(ip), Err(InvalidIPErr)) assert_eq!(IpAddr::from_str(ip), Err(NetworkingErr::InvalidIPErr))
} }
} }

View File

@ -3,49 +3,95 @@ use ip::IpAddr;
pub mod ip; pub mod ip;
#[derive(Debug, PartialEq, Eq)] #[allow(dead_code)]
pub struct InvalidCIDRErr; #[derive(Debug, Eq, PartialEq)]
pub enum NetworkingErr {
InvalidCIDRErr,
InvalidSubnetMask,
InvalidNetwork,
InvalidIPErr
}
#[allow(unused)] #[allow(unused)]
pub struct Network { pub struct Network {
network_address: IpAddr, network_address: IpAddr,
broadcast_addr: IpAddr, broadcast_addr: IpAddr,
num_hosts: u32,
subnet_mask: Option<IpAddr> subnet_mask: Option<IpAddr>
} }
impl Network { impl Network {
// pub fn new(given_address: &IpAddr, CIDR: u8) -> Network {
// }
#[allow(non_snake_case)] #[allow(unused)]
/// Function that constucts a network struct.
///
/// ```
/// let network = Network::new(&IpAddr::V4(127, 0, 0, 1), 32);
/// ```
pub fn new(given_address: &IpAddr, subnet_mask: &IpAddr) -> Network {
Network {
network_address: given_address.clone(),
broadcast_addr: given_address.clone(),
num_hosts: 0,
subnet_mask: Some(subnet_mask.clone())
}
}
/// Function that constucts a subnet, returning a vector of all subnets included
///
/// ```
/// let networks = Network::create_subnet(&IpAddr::V4(127, 0, 0, 1), 32);
/// ```
pub fn create_subnet(network_address: &IpAddr, cidr: u8) -> Result<Vec<Network>, NetworkingErr> {
//Get number of host and network bits.
let subnet_mask = match Network::gen_subnet_mask(cidr) {
Ok(ip) => ip,
Err(_) => return Err(NetworkingErr::InvalidCIDRErr)
};
let network_bits = match subnet_mask {
IpAddr::V4(oct1, oct2, oct3, oct4) => {
oct1.count_zeros() + oct2.count_zeros() + oct3.count_zeros() + oct4.count_zeros()
},
IpAddr::V6(_) => return Err(NetworkingErr::InvalidIPErr)
};
//Determine the number of networks needed for the subnet.
let num_networks = get_num_networks(network_bits);
//Get first address of each network
//Use Class constructor to generate each network.
Ok(vec![Network::new(&IpAddr::V4(0, 0, 0, 0), &IpAddr::V4(0, 0, 0, 0))])
}
/// Function that takes in a u8 CIDR and converts it to an IP address. /// Function that takes in a u8 CIDR and converts it to an IP address.
/// ///
/// ``` /// ```
/// let CIDR: u8 = 22 /// let cidr: u8 = 22
/// let subnet_mask: [u8; 4] = gen_subnet_mask(CIDR); /// let subnet_mask: [u8; 4] = gen_subnet_mask(cidr);
/// ///
/// >> IpAddr::V4(255, 255, 252, 0) /// >> IpAddr::V4(255, 255, 252, 0)
/// ``` /// ```
pub fn gen_subnet_mask(mut CIDR: u8) -> Result<IpAddr, InvalidCIDRErr> { fn gen_subnet_mask(mut cidr: u8) -> Result<IpAddr, NetworkingErr> {
if CIDR > 32 { if cidr > 32 {
return Err(InvalidCIDRErr) return Err(NetworkingErr::InvalidCIDRErr)
} }
let mut oct: [u8; 4] = [0; 4]; let mut oct: [u8; 4] = [0; 4];
for octet in oct.iter_mut() { for octet in oct.iter_mut() {
*octet = if usize::from(CIDR) >= 8 { *octet = if usize::from(cidr) >= 8 {
CIDR -= 8; cidr -= 8;
u8::MAX u8::MAX
}else{ }else{
// Count the number of remaining 1s and convert to binary // Count the number of remaining 1s and convert to binary
let mut count: u8 = 0; let mut count: u8 = 0;
for i in ((8-CIDR)..8).rev() { for i in ((8-cidr)..8).rev() {
count += u8::pow(2, u32::from(i)); count += u8::pow(2, u32::from(i));
} }
CIDR = 0; cidr = 0;
count count
} }
} }
@ -55,10 +101,14 @@ impl Network {
//pub fn generate_subnets(self) -> Vec<Network> {} //pub fn generate_subnets(self) -> Vec<Network> {}
} }
enum NetworkClassBits { fn get_num_networks(mut network_bits: u8) -> u8 {
A = 8, for _ in 0..4 {
B = 16, if (network_bits / 8) > 1 {
C = 24 network_bits -= 8;
continue;
}
};
network_bits
} }
/// Function that takes in a string reference and returns the result of splitting a string into /// Function that takes in a string reference and returns the result of splitting a string into
@ -123,6 +173,6 @@ mod tests {
assert_eq!(Network::gen_subnet_mask(24).unwrap(), IpAddr::V4(255, 255, 255, 0)); assert_eq!(Network::gen_subnet_mask(24).unwrap(), IpAddr::V4(255, 255, 255, 0));
assert_eq!(Network::gen_subnet_mask(0).unwrap(), IpAddr::V4(0, 0, 0, 0)); assert_eq!(Network::gen_subnet_mask(0).unwrap(), IpAddr::V4(0, 0, 0, 0));
assert_eq!(Network::gen_subnet_mask(4).unwrap(), IpAddr::V4(240, 0, 0, 0)); assert_eq!(Network::gen_subnet_mask(4).unwrap(), IpAddr::V4(240, 0, 0, 0));
assert_eq!(Network::gen_subnet_mask(35).unwrap_err(), InvalidCIDRErr); assert_eq!(Network::gen_subnet_mask(35).unwrap_err(), NetworkingErr::InvalidCIDRErr);
} }
} }