use anyhow::{anyhow, Context, Result};
use ipnet::IpNet;
use std::collections::HashSet;
use std::net::IpAddr;
pub const INNISFREE_SUBNET: &str = "10.50.0.1/28";
fn local_addresses() -> Result<HashSet<IpAddr>> {
Ok(if_addrs::get_if_addrs()
.context("listing local network interfaces")?
.iter()
.map(|iface| iface.ip())
.collect())
}
pub fn generate_unused_subnet() -> Result<IpNet> {
let parent_net: IpNet = INNISFREE_SUBNET.parse()?;
let in_use = local_addresses()?;
for subnet in parent_net.subnets(30)? {
if subnet.hosts().count() > 2 {
continue;
}
if subnet.hosts().all(|h| !in_use.contains(&h)) {
return Ok(subnet);
}
}
Err(anyhow!("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(())
}
}