aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2022-10-30 23:42:35 +0100
committerHimbeerserverDE <himbeerserverde@gmail.com>2022-10-30 23:42:35 +0100
commit761b0bed81bcadb407cbc827177b86e5a0cc79fd (patch)
tree23b1713faadbd0457519f6b96b6b63e19261c098
parent17c2a8ad3ce2c11a58e1229ed2c7f8d304a00f1d (diff)
all addresses of single interface
-rw-r--r--Cargo.toml12
-rw-r--r--src/lib.rs108
2 files changed, 120 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..29a7f20
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "linkaddrs"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+futures = "0.3.25"
+netlink-packet-route = "0.13.0"
+rtnetlink = "0.11.0"
+tokio = { version = "1.0.1", features = ["rt-multi-thread"] }
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..f08026b
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,108 @@
+use std::fmt;
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+
+use futures::future;
+use futures::stream::{StreamExt, TryStreamExt};
+use netlink_packet_route::address::Nla::Address;
+use netlink_packet_route::rtnl::constants::{AF_INET, AF_INET6};
+use rtnetlink::new_connection;
+use tokio::runtime::Runtime;
+
+#[derive(Debug)]
+pub enum Error {
+ RtNetlink(rtnetlink::Error),
+ IoError(std::io::Error),
+ LinkNotFound(String),
+}
+
+impl std::error::Error for Error {}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::RtNetlink(e) => write!(fmt, "rtnetlink error: {}", e),
+ Self::IoError(e) => write!(fmt, "rtnetlink connection failed: {}", e),
+ Self::LinkNotFound(link) => write!(fmt, "link not found: {}", link),
+ }
+ }
+}
+
+impl From<rtnetlink::Error> for Error {
+ fn from(e: rtnetlink::Error) -> Self {
+ Self::RtNetlink(e)
+ }
+}
+
+impl From<std::io::Error> for Error {
+ fn from(e: std::io::Error) -> Self {
+ Self::IoError(e)
+ }
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+pub fn addresses(link: String) -> Result<Vec<IpAddr>> {
+ let rt = Runtime::new()?;
+
+ rt.block_on(internal_addresses(link))
+}
+
+async fn internal_addresses(link: String) -> Result<Vec<IpAddr>> {
+ let (connection, handle, _) = new_connection()?;
+ tokio::spawn(connection);
+
+ let mut links = handle
+ .link()
+ .get()
+ .match_name(link.clone())
+ .execute();
+
+ if let Some(link) = links.try_next().await? {
+ let addrs = handle
+ .address()
+ .get()
+ .set_link_index_filter(link.header.index)
+ .execute();
+
+ let addrs = addrs
+ .map_ok(|v| {
+ if let Some(Address(bytes)) = v.nlas.first() {
+ match v.header.family as u16 {
+ AF_INET => {
+ let octets: [u8; 4] = (*bytes)
+ .clone()
+ .try_into()
+ .unwrap();
+
+ let ip = IpAddr::from(
+ Ipv4Addr::from(octets)
+ );
+
+ Some(ip)
+ }
+ AF_INET6 => {
+ let octets: [u8; 16] = (*bytes)
+ .clone()
+ .try_into()
+ .unwrap();
+
+ let ip = IpAddr::from(
+ Ipv6Addr::from(octets)
+ );
+
+ Some(ip)
+ }
+ _ => None
+ }
+ } else {
+ None
+ }
+ })
+ .try_filter(|v| future::ready(v.is_some()))
+ .filter_map(|v| future::ready(v.unwrap()));
+
+ Ok(addrs.collect::<Vec<IpAddr>>().await)
+ } else {
+ Err(Error::LinkNotFound(link))
+ }
+}