use std::str::FromStr; use ip::IpAddr; pub mod ip; #[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 { #[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 = Network::gen_subnet_mask(cidr)?.to_arr()?; let network_address = network_address.to_arr()?; let mut network_bits: u8 = Default::default(); let mut host_bits: u8 = Default::default(); //Get first address of each network //Need to get the most significant octet //Get number of bits available for host in specific octet let mut most_sig_octet: usize = Default::default(); for (i, oct) in subnet_mask.iter().enumerate(){ if *oct == 0 { most_sig_octet = i-1; network_bits = subnet_mask[most_sig_octet].count_ones() as u8; break; } if *oct < 255 { most_sig_octet = i; network_bits = oct.count_ones() as u8; break; } //There is no significant octet if i >= 4 { return Err(NetworkingErr::InvalidSubnetMask); } } //Determine the number of networks needed for the subnet. host_bits = subnet_mask.map(|o| o.count_zeros() as u8).iter().sum(); host_bits -= network_bits; //Determine Spacing let network_spacing = 2 ^ subnet_mask[most_sig_octet].count_ones() as u8; //Determine number of networks in the subnet let mut num_networks: u8 = 0; for i in 1..network_bits { num_networks += 2^i; } //Generate base address let mut base_address = network_address; base_address[most_sig_octet] = 255 - num_networks; for i in most_sig_octet+1..4 { base_address[i] = 0; } //Use Class constructor to generate each network. let mut networks = vec![]; for i in 0..num_networks { let mut new_ip = base_address; new_ip[most_sig_octet] += i * network_spacing; let new_network = Network::new(&IpAddr::from_arr(&new_ip)?, &IpAddr::from_arr(&subnet_mask)?); networks.push(new_network); } Ok(networks) } /// 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); /// /// >> IpAddr::V4(255, 255, 252, 0) /// ``` 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; 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() { count += u8::pow(2, u32::from(i)); } cidr = 0; count } } Ok(IpAddr::V4(oct[0], oct[1], oct[2], oct[3])) } //pub fn generate_subnets(self) -> Vec {} } /// Function that takes in a string reference and returns the result of splitting a string into /// both its Address and CIDR /// /// ``` /// let ip_string = String::from("192.168.0.1/24"); /// let result = match ip_and_cidr_from_string(&ip_string) { /// Err(_) => panic!(), /// Ok(ip_and_cidr) => ip_and_cidr /// }; /// /// >> (IpAddr::V4(192, 168, 0, 1), 24) /// ``` pub fn ip_and_cidr_from_string(ip_and_cidr: &String) -> Result<(IpAddr, u8), ip::InvalidIPErr>{ let mut cidr: u8 = Default::default(); let mut ip: String = Default::default(); if ip_and_cidr.contains("/") { let split_ip_cidr = ip_and_cidr.split("/"); if split_ip_cidr.clone().count() > 2 { return Err(ip::InvalidIPErr); } ip = split_ip_cidr.clone().into_iter().next().unwrap_or("0.0.0.0").to_owned(); cidr = match split_ip_cidr.into_iter().last() { None => return Err(ip::InvalidIPErr), Some(cidr) => match cidr.trim().parse::() { Err(_) => return Err(ip::InvalidIPErr), Ok(cidr) => cidr } }; } let ip_address: IpAddr = match IpAddr::from_str(&ip.trim()) { Err(_) => return Err(ip::InvalidIPErr), Ok(ip) => ip, }; return Ok((ip_address, cidr)) } mod tests { #[cfg(test)] #[test] fn string_to_ip_cidr_test() { use super::*; let ip_string = String::from("127.0.0.1/8"); let result = match ip_and_cidr_from_string(&ip_string) { Err(_) => panic!(), Ok(ip_and_cidr) => ip_and_cidr }; assert_eq!(result.0, IpAddr::V4(127, 0, 0, 1)); assert_eq!(result.1, 8); } #[test] fn cidr_to_ip_test() { use super::*; assert_eq!(Network::gen_subnet_mask(22).unwrap(), IpAddr::V4(255, 255, 252, 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(4).unwrap(), IpAddr::V4(240, 0, 0, 0)); assert_eq!(Network::gen_subnet_mask(35).unwrap_err(), NetworkingErr::InvalidCIDRErr); } }