diff options
Diffstat (limited to 'src/route.rs')
-rw-r--r-- | src/route.rs | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/src/route.rs b/src/route.rs new file mode 100644 index 0000000..b180e96 --- /dev/null +++ b/src/route.rs @@ -0,0 +1,167 @@ +use crate::{Error, Result}; + +use std::net::{Ipv4Addr, Ipv6Addr}; + +use futures::{future, TryStreamExt}; +use netlink_packet_route::{RouteMessage, RT_SCOPE_LINK}; +use rtnetlink::IpVersion; +use tokio::runtime::Runtime; + +async fn do_flush4(link: String) -> Result<()> { + let (conn, handle, _) = rtnetlink::new_connection()?; + tokio::spawn(conn); + + let link = handle + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let routes: Vec<RouteMessage> = handle + .route() + .get(IpVersion::V4) + .execute() + .try_filter(|route| { + future::ready(if let Some(ifi) = route.output_interface() { + ifi == id + } else { + false + }) + }) + .try_collect() + .await?; + + for route in routes { + handle.route().del(route).execute().await?; + } + + Ok(()) +} + +// pub fn flush4(link: String) -> Result<()> { +// Runtime::new()?.block_on(do_flush4(link)) +// } + +async fn do_flush6(link: String) -> Result<()> { + let (conn, handle, _) = rtnetlink::new_connection()?; + tokio::spawn(conn); + + let link = handle + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let routes: Vec<RouteMessage> = handle + .route() + .get(IpVersion::V6) + .execute() + .try_filter(|route| { + future::ready(if let Some(ifi) = route.output_interface() { + ifi == id + } else { + false + }) + }) + .try_collect() + .await?; + + for route in routes { + handle.route().del(route).execute().await?; + } + + Ok(()) +} + +// pub fn flush6(link: String) -> Result<()> { +// Runtime::new()?.block_on(do_flush6(link)) +// } +// +// pub fn flush(link: String) -> Result<()> { +// flush4(link.clone())?; +// flush6(link)?; +// +// Ok(()) +// } + +async fn do_add4(dst: Ipv4Addr, prefix_len: u8, rtr: Option<Ipv4Addr>, link: String) -> Result<()> { + let (conn, handle, _) = rtnetlink::new_connection()?; + tokio::spawn(conn); + + let link = handle + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let mut add = handle + .route() + .add() + .v4() + .destination_prefix(dst, prefix_len) + .output_interface(id); + + if let Some(rtr) = rtr { + add = add.gateway(rtr); + } else { + add = add.scope(RT_SCOPE_LINK); + } + + add.execute().await?; + Ok(()) +} + +// pub fn add4(dst: Ipv4Addr, prefix_len: u8, rtr: Option<Ipv4Addr>, link: String) -> Result<()> { +// Runtime::new()?.block_on(do_add4(dst, prefix_len, rtr, link)) +// } + +async fn do_add6(dst: Ipv6Addr, prefix_len: u8, rtr: Option<Ipv6Addr>, link: String) -> Result<()> { + let (conn, handle, _) = rtnetlink::new_connection()?; + tokio::spawn(conn); + + let link = handle + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let mut add = handle + .route() + .add() + .v6() + .destination_prefix(dst, prefix_len) + .output_interface(id); + + if let Some(rtr) = rtr { + add = add.gateway(rtr); + } else { + add = add.scope(RT_SCOPE_LINK); + } + + add.execute().await?; + Ok(()) +} + +// pub fn add6(dst: Ipv6Addr, prefix_len: u8, rtr: Option<Ipv6Addr>, link: String) -> Result<()> { +// Runtime::new()?.block_on(do_add6(dst, prefix_len, rtr, link)) +// } |