diff options
-rw-r--r-- | Cargo.lock | 3 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | src/addr.rs | 31 | ||||
-rw-r--r-- | src/main.rs | 3 | ||||
-rw-r--r-- | src/route.rs | 91 |
5 files changed, 126 insertions, 5 deletions
@@ -475,8 +475,9 @@ dependencies = [ [[package]] name = "rsdsl_netlinkd" -version = "0.6.0" +version = "0.6.1" dependencies = [ + "futures", "futures-util", "ipnet", "netlink-packet-route", @@ -1,11 +1,12 @@ [package] name = "rsdsl_netlinkd" -version = "0.6.0" +version = "0.6.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +futures = "0.3.28" futures-util = "0.3.27" ipnet = "2.8.0" netlink-packet-route = "0.17.0" diff --git a/src/addr.rs b/src/addr.rs index 36ddea1..ceae1ec 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -2,9 +2,9 @@ use crate::error::{Error, Result}; use std::net::IpAddr; +use futures::future; use futures_util::TryStreamExt; -use netlink_packet_route::rtnl::AddressMessage; -use netlink_packet_route::RT_SCOPE_LINK; +use netlink_packet_route::{AddressMessage, AF_INET6, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE}; use tokio::runtime::Runtime; async fn do_flush(link: String) -> Result<()> { @@ -41,6 +41,33 @@ pub fn flush(link: String) -> Result<()> { Runtime::new()?.block_on(do_flush(link)) } +async fn do_flush6_global() -> Result<()> { + let (conn, handle, _) = rtnetlink::new_connection()?; + tokio::spawn(conn); + + let addrs: Vec<AddressMessage> = handle + .address() + .get() + .execute() + .try_filter(|addr| { + future::ready( + addr.header.family == AF_INET6 as u8 && addr.header.scope == RT_SCOPE_UNIVERSE, + ) + }) + .try_collect() + .await?; + + for addr in addrs { + handle.address().del(addr).execute().await?; + } + + Ok(()) +} + +pub fn flush6_global() -> Result<()> { + Runtime::new()?.block_on(do_flush6_global()) +} + async fn do_add(link: String, addr: IpAddr, prefix_len: u8) -> Result<()> { let (conn, handle, _) = rtnetlink::new_connection()?; tokio::spawn(conn); diff --git a/src/main.rs b/src/main.rs index 8ea3f89..eef8154 100644 --- a/src/main.rs +++ b/src/main.rs @@ -157,6 +157,7 @@ fn configure_ppp0() -> Result<()> { let ip_config: DsConfig = serde_json::from_reader(&mut file)?; addr::flush("ppp0".into())?; + route::flush("ppp0".into())?; if let Some(v4) = ip_config.v4 { addr::add("ppp0".into(), IpAddr::V4(v4.addr), 32)?; @@ -179,6 +180,8 @@ fn configure_ipv6() { } fn configure_all_v6() -> Result<()> { + addr::flush6_global()?; + let mut file = File::open(rsdsl_pd_config::LOCATION)?; let pd_config: PdConfig = serde_json::from_reader(&mut file)?; diff --git a/src/route.rs b/src/route.rs index b3e7cc9..0e5cd5d 100644 --- a/src/route.rs +++ b/src/route.rs @@ -2,10 +2,99 @@ use crate::error::{Error, Result}; use std::net::{Ipv4Addr, Ipv6Addr}; +use futures::future; use futures_util::TryStreamExt; -use netlink_packet_route::rtnl::RT_SCOPE_LINK; +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); |