diff options
Diffstat (limited to 'src/addr.rs')
-rw-r--r-- | src/addr.rs | 406 |
1 files changed, 205 insertions, 201 deletions
diff --git a/src/addr.rs b/src/addr.rs index 36efe1a..97e87d4 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -1,6 +1,6 @@ //! Simple functions to add and delete IP addresses. -use crate::{Error, Result}; +use crate::{Connection, Error, Result}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -9,216 +9,220 @@ use netlink_packet_route::{ address::Nla, AddressMessage, AF_INET, AF_INET6, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE, }; -/// Flushes all addresses of an interface. -pub async fn flush(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 addrs: Vec<AddressMessage> = handle - .address() - .get() - .set_link_index_filter(id) - .execute() - .try_collect() - .await?; - - for addr in addrs { - handle.address().del(addr).execute().await?; +impl Connection { + /// Flushes all addresses of an interface. + pub async fn address_flush(&self, link: String) -> Result<()> { + let link = self + .handle() + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let addrs: Vec<AddressMessage> = self + .handle() + .address() + .get() + .set_link_index_filter(id) + .execute() + .try_collect() + .await?; + + for addr in addrs { + self.handle().address().del(addr).execute().await?; + } + + Ok(()) } - Ok(()) -} - -/// Flushes the IPv4 addresses of an interface. -pub async fn 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 addrs: Vec<AddressMessage> = handle - .address() - .get() - .set_link_index_filter(id) - .execute() - .try_filter(|addr| future::ready(addr.header.family == AF_INET as u8)) - .try_collect() - .await?; - - for addr in addrs { - handle.address().del(addr).execute().await?; + /// Flushes the IPv4 addresses of an interface. + pub async fn address_flush4(&self, link: String) -> Result<()> { + let link = self + .handle() + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let addrs: Vec<AddressMessage> = self + .handle() + .address() + .get() + .set_link_index_filter(id) + .execute() + .try_filter(|addr| future::ready(addr.header.family == AF_INET as u8)) + .try_collect() + .await?; + + for addr in addrs { + self.handle().address().del(addr).execute().await?; + } + + Ok(()) } - Ok(()) -} - -/// Flushes the IPv6 addresses of an interface. -pub async fn 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 addrs: Vec<AddressMessage> = handle - .address() - .get() - .set_link_index_filter(id) - .execute() - .try_filter(|addr| future::ready(addr.header.family == AF_INET6 as u8)) - .try_collect() - .await?; - - for addr in addrs { - handle.address().del(addr).execute().await?; + /// Flushes the IPv6 addresses of an interface. + pub async fn address_flush6(&self, link: String) -> Result<()> { + let link = self + .handle() + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let addrs: Vec<AddressMessage> = self + .handle() + .address() + .get() + .set_link_index_filter(id) + .execute() + .try_filter(|addr| future::ready(addr.header.family == AF_INET6 as u8)) + .try_collect() + .await?; + + for addr in addrs { + self.handle().address().del(addr).execute().await?; + } + + Ok(()) } - Ok(()) -} - -/// Flushes all global unicast IPv6 addresses from all interfaces. -pub async fn 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?; + /// Flushes all global unicast IPv6 addresses from all interfaces. + pub async fn address_flush6_global(&self) -> Result<()> { + let addrs: Vec<AddressMessage> = self + .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 { + self.handle().address().del(addr).execute().await?; + } + + Ok(()) } - Ok(()) -} - -/// Adds an IP address to an interface. -pub async fn add(link: String, addr: IpAddr, prefix_len: u8) -> 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; - - handle.address().add(id, addr, prefix_len).execute().await?; - - Ok(()) -} - -/// Adds a link-scope IP address to an interface. -/// This is especially useful with IPv6. -pub async fn add_link_local(link: String, addr: IpAddr, prefix_len: u8) -> 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 req = handle.address().add(id, addr, prefix_len); - req.message_mut().header.scope = RT_SCOPE_LINK; - - req.execute().await?; + /// Adds an IP address to an interface. + pub async fn address_add(&self, link: String, addr: IpAddr, prefix_len: u8) -> Result<()> { + let link = self + .handle() + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + self.handle() + .address() + .add(id, addr, prefix_len) + .execute() + .await?; + + Ok(()) + } - Ok(()) -} + /// Adds a link-scope IP address to an interface. + /// This is especially useful with IPv6. + pub async fn address_add_link_local( + &self, + link: String, + addr: IpAddr, + prefix_len: u8, + ) -> Result<()> { + let link = self + .handle() + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + let id = link.header.index; + + let mut req = self.handle().address().add(id, addr, prefix_len); + req.message_mut().header.scope = RT_SCOPE_LINK; + + req.execute().await?; + + Ok(()) + } -/// Returns an iterator over the IP addresses of an interface. -pub async fn get(link: String) -> Result<impl TryStream<Ok = IpAddr, Error = Error>> { - 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))?; - - Ok(handle - .address() - .get() - .set_link_index_filter(link.header.index) - .execute() - .err_into::<Error>() - .try_filter_map(|msg| { - future::ready(Ok(if let Some(Nla::Address(bytes)) = msg.nlas.first() { - match msg.header.family as u16 { - AF_INET => { - let octets: [u8; 4] = (*bytes) - .clone() - .try_into() - .expect("nla does not match ipv4 address length"); - let ip = IpAddr::from(Ipv4Addr::from(octets)); - - Some(ip) + /// Returns an iterator over the IP addresses of an interface. + pub async fn address_get( + &self, + link: String, + ) -> Result<impl TryStream<Ok = IpAddr, Error = Error>> { + let link = self + .handle() + .link() + .get() + .match_name(link.clone()) + .execute() + .try_next() + .await? + .ok_or(Error::LinkNotFound(link))?; + + Ok(self + .handle() + .address() + .get() + .set_link_index_filter(link.header.index) + .execute() + .err_into::<Error>() + .try_filter_map(|msg| { + future::ready(Ok(if let Some(Nla::Address(bytes)) = msg.nlas.first() { + match msg.header.family as u16 { + AF_INET => { + let octets: [u8; 4] = (*bytes) + .clone() + .try_into() + .expect("nla does not match ipv4 address length"); + let ip = IpAddr::from(Ipv4Addr::from(octets)); + + Some(ip) + } + AF_INET6 => { + let octets: [u8; 16] = (*bytes) + .clone() + .try_into() + .expect("nla does not match ipv6 address length"); + let ip = IpAddr::from(Ipv6Addr::from(octets)); + + Some(ip) + } + _ => None, } - AF_INET6 => { - let octets: [u8; 16] = (*bytes) - .clone() - .try_into() - .expect("nla does not match ipv6 address length"); - let ip = IpAddr::from(Ipv6Addr::from(octets)); - - Some(ip) - } - _ => None, - } - } else { - None + } else { + None + })) })) - })) + } } |