ftth_rtnl/
address.rs

1#![allow(unreachable_patterns)]
2
3use std::net::{Ipv4Addr, Ipv6Addr};
4
5use futures::TryStreamExt;
6
7use ftth_common::channel::{AsyncWorldClient, AsyncWorldServer};
8
9pub(crate) type Client = AsyncWorldClient<RtnlAddressRequest, RtnlAddressResponse>;
10pub(crate) type Server = AsyncWorldServer<RtnlAddressRequest, RtnlAddressResponse>;
11
12#[derive(Debug, Clone, PartialEq)]
13#[non_exhaustive]
14pub enum RtnlAddressRequest {
15    Ipv4AddrsGet {
16        if_id: u32,
17    },
18    Ipv6AddrsGet {
19        if_id: u32,
20    },
21    Ipv4AddrSet {
22        prefix: crate::Ipv4Net,
23        if_id: u32,
24    },
25    Ipv6AddrSet {
26        prefix: crate::Ipv6Net,
27        if_id: u32,
28    },
29    Ipv4AddrDel {
30        prefix: crate::Ipv4Net,
31        if_id: u32,
32    },
33    Ipv6AddrDel {
34        prefix: crate::Ipv6Net,
35        if_id: u32,
36    },
37}
38
39#[derive(Debug, Clone, PartialEq)]
40#[non_exhaustive]
41pub enum RtnlAddressResponse {
42    Success,
43    Failed,
44    NotImplemented,
45    NotFound,
46    Ipv4Addrs(Vec<Ipv4Addr>),
47    Ipv6Addrs(Vec<Ipv6Addr>),
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Hash)]
51pub struct RtnlAddressClient {
52    client: Client,
53}
54
55impl RtnlAddressClient {
56    pub(crate) fn new(client: Client) -> Self {
57        Self {
58            client,
59        }
60    }
61
62    pub fn ipv4_addrs_get(&self, if_id: Option<u32>) -> std::io::Result<Vec<Ipv4Addr>> {
63        let res = self.client.send_request(RtnlAddressRequest::Ipv4AddrsGet { if_id: if_id.unwrap_or(0) })?;
64        match res {
65            RtnlAddressResponse::Ipv4Addrs(addrs) => {
66                return Ok(addrs);
67            },
68            _ => {},
69        }
70        Err(std::io::Error::other("Failed to get IPv4 addresses"))
71    }
72
73    pub fn ipv6_addrs_get(&self, if_id: Option<u32>) -> std::io::Result<Vec<Ipv6Addr>> {
74        let res = self.client.send_request(RtnlAddressRequest::Ipv6AddrsGet { if_id: if_id.unwrap_or(0) })?;
75        match res {
76            RtnlAddressResponse::Ipv6Addrs(addrs) => {
77                return Ok(addrs);
78            },
79            _ => {},
80        }
81        Err(std::io::Error::other("Failed to get IPv6 addresses"))
82    }
83}
84
85pub(crate) async fn run_server(mut server: Server, handle: rtnetlink::AddressHandle) {
86    while let Some((req, respond)) = server.accept().await {
87        match req {
88            RtnlAddressRequest::Ipv4AddrsGet { if_id } => {
89                let if_index = if_id;
90                let mut addrs = Vec::new();
91                let mut req = handle.get();
92                if if_index != 0 {
93                    req = req.set_link_index_filter(if_index);
94                }
95                let response = req.execute();
96
97                futures::pin_mut!(response);
98                while let Ok(Some(response)) = response.try_next().await {
99                    if response.header.family != netlink_packet_route::AddressFamily::Inet {
100                        continue;
101                    }
102                    for addr in response.attributes.iter() {
103                        if let netlink_packet_route::address::AddressAttribute::Address(std::net::IpAddr::V4(addr)) = addr {
104                            addrs.push(*addr);
105                        }
106                    }
107                }
108                respond(RtnlAddressResponse::Ipv4Addrs(addrs));
109            },
110            RtnlAddressRequest::Ipv6AddrsGet { if_id } => {
111                let if_index = if_id;
112                let mut addrs = Vec::new();
113                let mut req = handle.get();
114                if if_index != 0 {
115                    req = req.set_link_index_filter(if_index);
116                }
117                let response = req.execute();
118
119                futures::pin_mut!(response);
120                while let Ok(Some(response)) = response.try_next().await {
121                    if response.header.family != netlink_packet_route::AddressFamily::Inet6 {
122                        continue;
123                    }
124                    for addr in response.attributes.iter() {
125                        if let netlink_packet_route::address::AddressAttribute::Address(std::net::IpAddr::V6(addr)) = addr {
126                            addrs.push(*addr);
127                        }
128                    }
129                }
130                respond(RtnlAddressResponse::Ipv6Addrs(addrs));
131            },
132            _ => respond(RtnlAddressResponse::NotImplemented),
133        }
134    }
135}