use crate::error::RouteError;
use crate::utils::command::run_command;
use crate::Result;
use ipnet::IpNet;
use std::net::IpAddr;
#[cfg(target_os = "linux")]
const ROUTE_ADD_COMMAND_V4: &str = "route add -net {network} netmask {netmask} gw {gateway}";
#[cfg(target_os = "macos")]
const ROUTE_ADD_COMMAND_V4: &str = "route -n add -net {network} -netmask {netmask} {gateway}";
#[cfg(target_os = "freebsd")]
const ROUTE_ADD_COMMAND_V4: &str = "route add -net {network} -netmask {netmask} {gateway}";
#[cfg(target_os = "linux")]
const ROUTE_ADD_COMMAND_V6: &str = "route -A inet6 add {network}/{prefix} gw {gateway}";
#[cfg(target_os = "macos")]
const ROUTE_ADD_COMMAND_V6: &str = "route -n add -inet6 {network}/{prefix} {gateway}";
#[cfg(target_os = "freebsd")]
const ROUTE_ADD_COMMAND_V6: &str = "route add -inet6 {network}/{prefix} {gateway}";
pub fn add_routes(networks: &[IpNet], gateway: &IpAddr, _interface_name: &str) -> Result<()> {
for network in networks {
add_route(network, gateway)?;
}
Ok(())
}
fn add_route(network: &IpNet, gateway: &IpAddr) -> Result<()> {
let route_add_command = match network {
IpNet::V4(_) => ROUTE_ADD_COMMAND_V4
.replace("{network}", &network.addr().to_string())
.replace("{netmask}", &network.netmask().to_string())
.replace("{gateway}", &gateway.to_string()),
IpNet::V6(_) => ROUTE_ADD_COMMAND_V6
.replace("{network}", &network.addr().to_string())
.replace("{prefix}", &network.prefix_len().to_string())
.replace("{gateway}", &gateway.to_string()),
};
let route_command_split = route_add_command.split(" ").collect::<Vec<_>>();
let route_program = route_command_split[0];
let route_args = &route_command_split[1..];
let output = run_command(route_program, route_args)
.map_err(|e| RouteError::PlatformError {
message: format!("failed to execute command: {e}"),
})?
.wait_with_output()
.map_err(|e| RouteError::PlatformError {
message: format!("failed to create child process: {e}"),
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(RouteError::AddFailed {
destination: network.to_string(),
message: stderr.trim().to_string(),
}
.into());
}
Ok(())
}