use anyhow::{anyhow, Result};
use ipnet::IpNet;
use std::net::IpAddr;
pub const INNISFREE_SUBNET: &str = "10.50.0.1/28";
fn address_in_use(ip: IpAddr) -> bool {
let mut in_use = false;
for iface in pnet::datalink::interfaces() {
for i in iface.ips {
if i.ip() == ip {
in_use = true;
}
}
}
in_use
}
fn subnet_available(n: IpNet) -> bool {
let mut is_available = true;
for h in n.hosts() {
if address_in_use(h) {
is_available = false;
}
}
is_available
}
pub fn generate_unused_subnet() -> Result<IpNet> {
let parent_net: IpNet = INNISFREE_SUBNET.parse()?;
let subnets = parent_net.subnets(30)?.collect::<Vec<IpNet>>();
for subnet in subnets {
if subnet.hosts().count() > 2 {
continue;
}
if subnet_available(subnet) {
return Ok(subnet);
}
}
Err(anyhow!(format!(
"No available subnets within {}",
parent_net
)))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subnet_generation() -> anyhow::Result<()> {
let n = generate_unused_subnet()?;
let x: ipnet::IpNet = "10.50.0.0/30".parse()?;
assert_eq!(n, x);
Ok(())
}
}