2023-04-20 20:42:13 +00:00
|
|
|
use std::str::FromStr;
|
2023-02-11 16:15:28 +00:00
|
|
|
use ip::IpAddr;
|
|
|
|
|
2023-02-20 18:06:57 +00:00
|
|
|
pub mod ip;
|
|
|
|
|
2023-04-17 16:24:35 +00:00
|
|
|
#[allow(dead_code)]
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
|
|
pub enum NetworkingErr {
|
|
|
|
InvalidCIDRErr,
|
|
|
|
InvalidSubnetMask,
|
|
|
|
InvalidNetwork,
|
|
|
|
InvalidIPErr
|
|
|
|
}
|
|
|
|
|
2023-02-11 16:15:28 +00:00
|
|
|
#[allow(unused)]
|
|
|
|
pub struct Network {
|
|
|
|
network_address: IpAddr,
|
|
|
|
broadcast_addr: IpAddr,
|
2023-04-17 16:24:35 +00:00
|
|
|
num_hosts: u32,
|
2023-02-11 16:15:28 +00:00
|
|
|
subnet_mask: Option<IpAddr>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Network {
|
2023-04-17 16:24:35 +00:00
|
|
|
|
|
|
|
#[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.
|
2023-04-20 20:42:13 +00:00
|
|
|
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();
|
|
|
|
|
2023-04-17 16:24:35 +00:00
|
|
|
//Get first address of each network
|
2023-04-18 19:40:53 +00:00
|
|
|
//Need to get the most significant octet
|
|
|
|
//Get number of bits available for host in specific octet
|
2023-04-20 20:42:13 +00:00
|
|
|
let mut most_sig_octet: usize = Default::default();
|
|
|
|
for (i, oct) in subnet_mask.iter().enumerate(){
|
2023-04-20 21:30:33 +00:00
|
|
|
if *oct == 0 {
|
|
|
|
most_sig_octet = i-1;
|
|
|
|
network_bits = subnet_mask[most_sig_octet].count_ones() as u8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-04-20 20:42:13 +00:00
|
|
|
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
|
2023-04-24 16:45:59 +00:00
|
|
|
let network_spacing = u8::pow(2, subnet_mask[most_sig_octet].count_ones());
|
2023-04-20 20:42:13 +00:00
|
|
|
|
|
|
|
//Determine number of networks in the subnet
|
|
|
|
let mut num_networks: u8 = 0;
|
|
|
|
for i in 1..network_bits {
|
2023-04-24 16:45:59 +00:00
|
|
|
num_networks += u8::pow(2, u32::from(i));
|
2023-04-20 20:42:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Generate base address
|
|
|
|
let mut base_address = network_address;
|
|
|
|
base_address[most_sig_octet] = 255 - num_networks;
|
2023-04-20 21:30:33 +00:00
|
|
|
for i in most_sig_octet+1..4 {
|
2023-04-20 20:42:13 +00:00
|
|
|
base_address[i] = 0;
|
|
|
|
}
|
|
|
|
|
2023-04-17 16:24:35 +00:00
|
|
|
//Use Class constructor to generate each network.
|
2023-04-20 20:42:13 +00:00
|
|
|
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)
|
2023-04-17 16:24:35 +00:00
|
|
|
}
|
2023-04-09 09:07:15 +00:00
|
|
|
|
|
|
|
/// Function that takes in a u8 CIDR and converts it to an IP address.
|
|
|
|
///
|
|
|
|
/// ```
|
2023-04-17 16:24:35 +00:00
|
|
|
/// let cidr: u8 = 22
|
|
|
|
/// let subnet_mask: [u8; 4] = gen_subnet_mask(cidr);
|
2023-04-09 09:07:15 +00:00
|
|
|
///
|
|
|
|
/// >> IpAddr::V4(255, 255, 252, 0)
|
|
|
|
/// ```
|
2023-04-17 16:24:35 +00:00
|
|
|
fn gen_subnet_mask(mut cidr: u8) -> Result<IpAddr, NetworkingErr> {
|
|
|
|
if cidr > 32 {
|
|
|
|
return Err(NetworkingErr::InvalidCIDRErr)
|
2023-04-09 09:07:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut oct: [u8; 4] = [0; 4];
|
|
|
|
|
|
|
|
for octet in oct.iter_mut() {
|
2023-04-17 16:24:35 +00:00
|
|
|
*octet = if usize::from(cidr) >= 8 {
|
|
|
|
cidr -= 8;
|
2023-04-09 09:07:15 +00:00
|
|
|
u8::MAX
|
|
|
|
}else{
|
|
|
|
// Count the number of remaining 1s and convert to binary
|
|
|
|
let mut count: u8 = 0;
|
2023-04-17 16:24:35 +00:00
|
|
|
for i in ((8-cidr)..8).rev() {
|
2023-04-09 09:07:15 +00:00
|
|
|
count += u8::pow(2, u32::from(i));
|
|
|
|
}
|
2023-04-17 16:24:35 +00:00
|
|
|
cidr = 0;
|
2023-04-09 09:07:15 +00:00
|
|
|
count
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(IpAddr::V4(oct[0], oct[1], oct[2], oct[3]))
|
|
|
|
}
|
|
|
|
//pub fn generate_subnets(self) -> Vec<Network> {}
|
|
|
|
}
|
|
|
|
|
2023-02-20 21:25:37 +00:00
|
|
|
/// 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)
|
|
|
|
/// ```
|
2023-02-20 18:06:57 +00:00
|
|
|
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);
|
|
|
|
}
|
2023-04-09 09:07:15 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn cidr_to_ip_test() {
|
|
|
|
use super::*;
|
2023-04-10 10:13:36 +00:00
|
|
|
|
2023-04-09 09:07:15 +00:00
|
|
|
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));
|
2023-04-17 16:24:35 +00:00
|
|
|
assert_eq!(Network::gen_subnet_mask(35).unwrap_err(), NetworkingErr::InvalidCIDRErr);
|
2023-04-09 09:07:15 +00:00
|
|
|
}
|
2023-02-11 16:15:28 +00:00
|
|
|
}
|