subnet_calculator/src/networking/mod.rs

197 lines
6.5 KiB
Rust

use std::{str::FromStr, f32::consts::E};
use ip::IpAddr;
use self::ip::InvalidIPErr;
pub mod ip;
#[allow(dead_code)]
#[derive(Debug, Eq, PartialEq)]
pub enum NetworkingErr {
InvalidCIDRErr,
InvalidSubnetMask,
InvalidNetwork,
InvalidIPErr
}
/// enum to allow the identification of the class of the network
#[derive(Debug, Eq, PartialEq)]
enum NetworkClass {
A = 8,
B = 16,
C = 24
}
#[allow(unused)]
pub struct Network {
network_address: IpAddr,
broadcast_addr: IpAddr,
num_hosts: u32,
subnet_mask: Option<IpAddr>
}
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<Vec<Network>, 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()?;
// Determine the network class that the given address is in.
let networks = vec![];
Ok(networks)
}
/// Function that is used to determine the class of network that an IP is in.
///
/// ```
/// let network_class = Network::get_network_class(&[127, 0, 0, 1])?;
/// >>> NetworkClass::A
/// ```
fn get_network_class(network_address: &[u8; 4]) -> Result<NetworkClass, NetworkingErr> {
if network_address[0] > 224 {
return Err(NetworkingErr::InvalidIPErr)
}else if network_address[0] >= 192 {
return Ok(NetworkClass::C)
}else if network_address[0] >= 128 {
return Ok(NetworkClass::B)
}else if network_address[0] >= 1 {
return Ok(NetworkClass::A);
}
return Err(NetworkingErr::InvalidIPErr)
}
/// 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<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;
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<Network> {}
}
/// 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::<u8>() {
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);
}
#[test]
fn test_network_class() {
use super::*;
assert_eq!(Network::get_network_class(&IpAddr::V4(127, 0, 0, 1).to_arr().unwrap()).unwrap(), NetworkClass::A);
assert_eq!(Network::get_network_class(&IpAddr::V4(172, 6, 8, 10).to_arr().unwrap()).unwrap(), NetworkClass::B);
assert_eq!(Network::get_network_class(&IpAddr::V4(192, 168, 0, 1).to_arr().unwrap()).unwrap(), NetworkClass::C);
assert_eq!(Network::get_network_class(&IpAddr::V4(10, 6, 8, 10).to_arr().unwrap()).unwrap(), NetworkClass::A);
assert_eq!(Network::get_network_class(&IpAddr::V4(225, 255, 255, 255).to_arr().unwrap()).unwrap_err(), NetworkingErr::InvalidIPErr);
assert_eq!(Network::get_network_class(&IpAddr::V4(225, 0, 0, 0).to_arr().unwrap()).unwrap_err(), NetworkingErr::InvalidIPErr);
assert_eq!(Network::get_network_class(&IpAddr::V4(0, 0, 0, 0).to_arr().unwrap()).unwrap_err(), NetworkingErr::InvalidIPErr);
assert_eq!(Network::get_network_class(&IpAddr::V4(0, 0, 0, 1).to_arr().unwrap()).unwrap_err(), NetworkingErr::InvalidIPErr);
}
}