From e1a978cb1fa4f98471ab1da43f81ded4e196ad60 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Mon, 17 Apr 2023 17:24:35 +0100 Subject: [PATCH] Added new functionality to Network and changed error handling to be a single enum. create_subnet() is still WIP --- src/networking/ip.rs | 13 +++--- src/networking/mod.rs | 92 +++++++++++++++++++++++++++++++++---------- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/src/networking/ip.rs b/src/networking/ip.rs index 85e4d86..3999585 100644 --- a/src/networking/ip.rs +++ b/src/networking/ip.rs @@ -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::() { 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)) } } \ No newline at end of file diff --git a/src/networking/mod.rs b/src/networking/mod.rs index 2e5b9de..4201116 100644 --- a/src/networking/mod.rs +++ b/src/networking/mod.rs @@ -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 } 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, 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. /// /// ``` - /// 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 { - if CIDR > 32 { - return Err(InvalidCIDRErr) + fn gen_subnet_mask(mut cidr: u8) -> Result { + 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 {} } -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); } } \ No newline at end of file