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 super::NetworkingErr;
#[derive(Debug, PartialEq, Eq)]
pub struct InvalidIPErr;
@ -12,7 +13,7 @@ pub struct InvalidIPErr;
/// IpAddr::V6(String::from("::1"))
/// ```
#[allow(unused)]
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum IpAddr {
V4(u8, u8, u8, u8),
V6(String)
@ -30,7 +31,7 @@ impl ToString for IpAddr {
impl FromStr for IpAddr {
type Err = InvalidIPErr;
type Err = NetworkingErr;
/// Function that generates a IpAddr / Err from a string
///
/// # Limitation
@ -46,18 +47,18 @@ impl FromStr for IpAddr {
let split_ip = s.split('.');
if split_ip.clone().count() != 4 {
//Invalid IP address entered
return Err(InvalidIPErr)
return Err(super::NetworkingErr::InvalidIPErr)
}
let mut ip: [u8; 4] = Default::default();
//Go through each octet and ensure it can be parsed;
for (i, oct) in split_ip.into_iter().enumerate() {
if i > ip.len() {
//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>() {
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]))
@ -106,6 +107,6 @@ mod tests {
use super::*;
let ip = "127.0.0.0.1";
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;
#[derive(Debug, PartialEq, Eq)]
pub struct InvalidCIDRErr;
#[allow(dead_code)]
#[derive(Debug, Eq, PartialEq)]
pub enum NetworkingErr {
InvalidCIDRErr,
InvalidSubnetMask,
InvalidNetwork,
InvalidIPErr
}
#[allow(unused)]
pub struct Network {
network_address: IpAddr,
broadcast_addr: IpAddr,
num_hosts: u32,
subnet_mask: Option<IpAddr>
}
impl Network {
// pub fn new(given_address: &IpAddr, CIDR: u8) -> Network {
// }
#[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);
#[allow(non_snake_case)]
//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.
///
/// ```
/// let CIDR: u8 = 22
/// let subnet_mask: [u8; 4] = gen_subnet_mask(CIDR);
/// let cidr: u8 = 22
/// let subnet_mask: [u8; 4] = gen_subnet_mask(cidr);
///
/// >> IpAddr::V4(255, 255, 252, 0)
/// ```
pub fn gen_subnet_mask(mut CIDR: u8) -> Result<IpAddr, InvalidCIDRErr> {
if CIDR > 32 {
return Err(InvalidCIDRErr)
fn gen_subnet_mask(mut cidr: u8) -> Result<IpAddr, NetworkingErr> {
if cidr > 32 {
return Err(NetworkingErr::InvalidCIDRErr)
}
let mut oct: [u8; 4] = [0; 4];
for octet in oct.iter_mut() {
*octet = if usize::from(CIDR) >= 8 {
CIDR -= 8;
*octet = if usize::from(cidr) >= 8 {
cidr -= 8;
u8::MAX
}else{
// Count the number of remaining 1s and convert to binary
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));
}
CIDR = 0;
cidr = 0;
count
}
}
@ -55,10 +101,14 @@ impl Network {
//pub fn generate_subnets(self) -> Vec<Network> {}
}
enum NetworkClassBits {
A = 8,
B = 16,
C = 24
fn get_num_networks(mut network_bits: u8) -> u8 {
for _ in 0..4 {
if (network_bits / 8) > 1 {
network_bits -= 8;
continue;
}
};
network_bits
}
/// 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(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(35).unwrap_err(), InvalidCIDRErr);
assert_eq!(Network::gen_subnet_mask(35).unwrap_err(), NetworkingErr::InvalidCIDRErr);
}
}