route_manager/linux/
mod.rs

1use libc::RTM_DELROUTE;
2use netlink_packet_core::{
3    NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_EXCL,
4    NLM_F_REQUEST,
5};
6use netlink_packet_route::route::{
7    RouteAddress, RouteAttribute, RouteMessage, RouteProtocol, RouteScope, RouteType,
8};
9use netlink_packet_route::{AddressFamily, RouteNetlinkMessage};
10use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
11use std::collections::VecDeque;
12use std::io;
13use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
14use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
15
16use crate::{Route, RouteChange};
17#[cfg(any(feature = "async", feature = "async_io"))]
18pub(crate) mod async_route;
19#[cfg(any(feature = "async", feature = "async_io"))]
20pub use async_route::*;
21
22/// RouteListener for receiving route change events.
23pub struct RouteListener {
24    list: VecDeque<RouteChange>,
25    route_socket: RouteSocket,
26    #[cfg(feature = "shutdown")]
27    pub(crate) shutdown_handle: crate::RouteListenerShutdown,
28}
29impl AsRawFd for RouteListener {
30    fn as_raw_fd(&self) -> RawFd {
31        self.route_socket.as_raw_fd()
32    }
33}
34
35impl RouteListener {
36    /// Creates a new RouteListener.
37    pub fn new() -> io::Result<Self> {
38        let mut route_socket = RouteSocket::new()?;
39        route_socket.add_membership()?;
40        #[cfg(feature = "shutdown")]
41        route_socket.0.set_non_blocking(true)?;
42        Ok(Self {
43            list: Default::default(),
44            route_socket,
45            #[cfg(feature = "shutdown")]
46            shutdown_handle: crate::RouteListenerShutdown::new()?,
47        })
48    }
49    /// Listens for a route change event and returns a RouteChange.
50    #[cfg(not(feature = "shutdown"))]
51    pub fn listen(&mut self) -> io::Result<RouteChange> {
52        if let Some(route) = self.list.pop_front() {
53            return Ok(route);
54        }
55        let mut buf = vec![0; 4096];
56        loop {
57            let len = self.route_socket.recv(&mut buf)?;
58            deserialize_res(
59                |route| {
60                    self.list.push_back(route);
61                },
62                &buf[..len],
63            )?;
64            if let Some(route) = self.list.pop_front() {
65                return Ok(route);
66            }
67        }
68    }
69}
70impl RouteListener {
71    /// Listens for a route change event and returns a RouteChange.
72    #[cfg(feature = "shutdown")]
73    pub fn listen(&mut self) -> io::Result<RouteChange> {
74        if let Some(route) = self.list.pop_front() {
75            return Ok(route);
76        }
77        let mut buf = vec![0; 4096];
78        loop {
79            self.wait()?;
80            let len = match self.route_socket.recv(&mut buf) {
81                Ok(list) => list,
82                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
83                Err(e) => return Err(e),
84            };
85            deserialize_res(
86                |route| {
87                    self.list.push_back(route);
88                },
89                &buf[..len],
90            )?;
91            if let Some(route) = self.list.pop_front() {
92                return Ok(route);
93            }
94        }
95    }
96}
97/// RouteManager is used for managing routes (adding, deleting, and listing).
98pub struct RouteManager {
99    _private: std::marker::PhantomData<()>,
100}
101
102pub(crate) struct RouteSocket(Socket);
103impl AsRawFd for RouteSocket {
104    fn as_raw_fd(&self) -> RawFd {
105        self.0.as_raw_fd()
106    }
107}
108impl AsFd for RouteSocket {
109    fn as_fd(&self) -> BorrowedFd<'_> {
110        self.0.as_fd()
111    }
112}
113impl RouteSocket {
114    pub(crate) fn new() -> io::Result<Self> {
115        Ok(Self(route_socket()?))
116    }
117    pub(crate) fn send(&self, buf: &[u8]) -> io::Result<usize> {
118        self.0.send(buf, 0)
119    }
120    pub(crate) fn recv(&self, mut buf: &mut [u8]) -> io::Result<usize> {
121        self.0.recv(&mut buf, 0)
122    }
123    pub(crate) fn add_membership(&mut self) -> io::Result<()> {
124        self.0.add_membership(libc::RTNLGRP_IPV4_ROUTE)?;
125        self.0.add_membership(libc::RTNLGRP_IPV6_ROUTE)?;
126        Ok(())
127    }
128}
129
130impl RouteManager {
131    /// Creates a new RouteManager.
132    pub fn new() -> io::Result<Self> {
133        Ok(Self {
134            _private: std::marker::PhantomData,
135        })
136    }
137    /// Returns a new instance of RouteListener.
138    pub fn listener() -> io::Result<RouteListener> {
139        RouteListener::new()
140    }
141
142    /// Lists all current routes.
143    pub fn list(&mut self) -> io::Result<Vec<Route>> {
144        let req = list_route_req();
145        let socket = RouteSocket::new()?;
146        socket.send(&req)?;
147        let mut buf = vec![0; 4096];
148        let mut list = Vec::new();
149        loop {
150            let len = socket.recv(&mut buf)?;
151            let rs = deserialize_res(
152                |route| {
153                    list.push(route);
154                },
155                &buf[..len],
156            )?;
157            if !rs {
158                break;
159            }
160        }
161        Ok(convert_add_route(list))
162    }
163    /// Adds a new route.
164    pub fn add(&mut self, route: &Route) -> io::Result<()> {
165        let req = add_route_req(route)?;
166        let socket = RouteSocket::new()?;
167        socket.send(&req)?;
168        let mut buf = vec![0; 4096];
169        let len = socket.recv(&mut buf)?;
170        deserialize_res(|_| {}, &buf[..len]).map(|_| ())
171    }
172    /// Deletes an existing route.
173    pub fn delete(&mut self, route: &Route) -> io::Result<()> {
174        let req = delete_route_req(route)?;
175        let socket = RouteSocket::new()?;
176        socket.send(&req)?;
177        let mut buf = vec![0; 4096];
178        let len = socket.recv(&mut buf)?;
179        deserialize_res(|_| {}, &buf[..len]).map(|_| ())
180    }
181}
182pub(crate) fn route_socket() -> io::Result<Socket> {
183    let mut socket = Socket::new(NETLINK_ROUTE)?;
184    let _port_number = socket.bind_auto()?.port_number();
185    socket.connect(&SocketAddr::new(0, 0))?;
186    Ok(socket)
187}
188pub(crate) fn convert_add_route(list: Vec<RouteChange>) -> Vec<Route> {
189    list.into_iter()
190        .filter_map(|v| {
191            if let RouteChange::Add(route) = v {
192                Some(route)
193            } else {
194                None
195            }
196        })
197        .collect()
198}
199
200pub(crate) fn deserialize_res<F: FnMut(RouteChange)>(
201    mut add_fn: F,
202    receive_buffer: &[u8],
203) -> io::Result<bool> {
204    let mut offset = 0;
205    loop {
206        let bytes = &receive_buffer[offset..];
207        if bytes.is_empty() {
208            return Ok(false);
209        }
210        let rx_packet = <NetlinkMessage<RouteNetlinkMessage>>::deserialize(bytes)
211            .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{e:?}")))?;
212        match rx_packet.payload {
213            NetlinkPayload::Done(_) => return Ok(true),
214            NetlinkPayload::Error(e) => {
215                if e.code.is_none() {
216                    return Ok(true);
217                }
218                return Err(e.to_io());
219            }
220            NetlinkPayload::Noop => {}
221            NetlinkPayload::Overrun(_) => {}
222            NetlinkPayload::InnerMessage(msg) => match msg {
223                RouteNetlinkMessage::NewRoute(msg) => add_fn(RouteChange::Add(msg.try_into()?)),
224                RouteNetlinkMessage::DelRoute(msg) => add_fn(RouteChange::Delete(msg.try_into()?)),
225                _ => {}
226            },
227            _ => {}
228        }
229
230        offset += rx_packet.header.length as usize;
231        if rx_packet.header.length == 0 {
232            return Ok(false);
233        }
234    }
235}
236
237impl TryFrom<RouteMessage> for Route {
238    type Error = io::Error;
239
240    fn try_from(msg: RouteMessage) -> Result<Self, Self::Error> {
241        let mut destination = None;
242        let mut gateway = None;
243        let prefix = msg.header.destination_prefix_length;
244        let source_prefix = msg.header.source_prefix_length;
245        let mut source = None;
246        let table = msg.header.table;
247        let mut if_index = None;
248        let mut metric = None;
249        let mut pref_source = None;
250        for x in msg.attributes {
251            match x {
252                RouteAttribute::Metrics(_) => {}
253                RouteAttribute::MfcStats(_) => {}
254                RouteAttribute::MultiPath(_) => {}
255                RouteAttribute::CacheInfo(_) => {}
256                RouteAttribute::Destination(addr) => {
257                    destination = route_address_to_ip(addr);
258                }
259                RouteAttribute::Source(addr) => {
260                    source = route_address_to_ip(addr);
261                }
262                RouteAttribute::Gateway(addr) => {
263                    gateway = route_address_to_ip(addr);
264                }
265                RouteAttribute::PrefSource(addr) => {
266                    pref_source = route_address_to_ip(addr);
267                }
268                RouteAttribute::Via(_) => {}
269                RouteAttribute::NewDestination(_) => {}
270                RouteAttribute::Preference(_) => {}
271                RouteAttribute::EncapType(_) => {}
272                RouteAttribute::Encap(_) => {}
273                RouteAttribute::Expires(_) => {}
274                RouteAttribute::MulticastExpires(_) => {}
275                RouteAttribute::Uid(_) => {}
276                RouteAttribute::TtlPropagate(_) => {}
277                RouteAttribute::Iif(_) => {}
278                RouteAttribute::Oif(v) => {
279                    if_index = Some(v);
280                }
281                RouteAttribute::Priority(v) => metric = Some(v),
282                RouteAttribute::Realm(_) => {}
283                RouteAttribute::Table(_) => {}
284                RouteAttribute::Mark(_) => {}
285                RouteAttribute::Other(_) => {}
286                _ => {}
287            }
288        }
289        let destination = if let Some(destination) = destination {
290            destination
291        } else {
292            match msg.header.address_family {
293                AddressFamily::Inet => Ipv4Addr::UNSPECIFIED.into(),
294                AddressFamily::Inet6 => Ipv6Addr::UNSPECIFIED.into(),
295                _ => {
296                    return Err(io::Error::new(
297                        io::ErrorKind::InvalidData,
298                        "invalid destination family",
299                    ))
300                }
301            }
302        };
303        let mut route = Route::new(destination, prefix).with_table(table);
304        if let Some(source) = source {
305            route = route.with_source(source, source_prefix);
306        }
307        if let Some(if_index) = if_index {
308            route = route.with_if_index(if_index);
309            route.if_name = crate::unix::if_index_to_name(if_index).ok();
310        }
311        if let Some(gateway) = gateway {
312            route = route.with_gateway(gateway);
313        }
314        if let Some(metric) = metric {
315            route = route.with_metric(metric);
316        }
317        if let Some(pref_source) = pref_source {
318            route = route.with_pref_source(pref_source);
319        }
320        Ok(route)
321    }
322}
323impl TryFrom<&Route> for RouteMessage {
324    type Error = io::Error;
325    fn try_from(route: &Route) -> Result<Self, Self::Error> {
326        route.check()?;
327        let mut route_msg = RouteMessage::default();
328        route_msg.header.address_family = if route.destination.is_ipv4() {
329            AddressFamily::Inet
330        } else {
331            AddressFamily::Inet6
332        };
333        route_msg.header.destination_prefix_length = route.prefix;
334        route_msg.header.protocol = RouteProtocol::Static;
335        route_msg.header.scope = RouteScope::Universe;
336        route_msg.header.kind = RouteType::Unicast;
337        route_msg.header.table = route.table;
338        route_msg
339            .attributes
340            .push(RouteAttribute::Destination(route.destination.into()));
341        if let Some(gateway) = route.gateway {
342            route_msg
343                .attributes
344                .push(RouteAttribute::Gateway(gateway.into()));
345        }
346        if let Some(if_index) = route.get_index() {
347            route_msg.attributes.push(RouteAttribute::Oif(if_index));
348        }
349        if let Some(metric) = route.metric {
350            route_msg.attributes.push(RouteAttribute::Priority(metric));
351        }
352        if let Some(source) = route.source {
353            route_msg.header.source_prefix_length = route.source_prefix;
354            route_msg
355                .attributes
356                .push(RouteAttribute::Source(source.into()));
357        }
358        if let Some(pref_source) = route.pref_source {
359            route_msg
360                .attributes
361                .push(RouteAttribute::PrefSource(pref_source.into()));
362        }
363
364        Ok(route_msg)
365    }
366}
367
368pub(crate) fn list_route_req() -> Vec<u8> {
369    let mut nl_hdr = NetlinkHeader::default();
370    nl_hdr.flags = NLM_F_REQUEST | NLM_F_DUMP;
371    let mut packet = NetlinkMessage::new(
372        nl_hdr,
373        NetlinkPayload::from(RouteNetlinkMessage::GetRoute(RouteMessage::default())),
374    );
375
376    packet.finalize();
377
378    let mut buf = vec![0; packet.header.length as usize];
379    packet.serialize(&mut buf[..]);
380    buf
381}
382
383pub(crate) fn add_route_req(route: &Route) -> io::Result<Vec<u8>> {
384    let mut nl_hdr = NetlinkHeader::default();
385    nl_hdr.flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
386
387    let mut packet = NetlinkMessage::new(
388        nl_hdr,
389        NetlinkPayload::from(RouteNetlinkMessage::NewRoute(route.try_into()?)),
390    );
391
392    packet.finalize();
393
394    let mut buf = vec![0; packet.header.length as usize];
395    packet.serialize(&mut buf[..]);
396    Ok(buf)
397}
398
399pub(crate) fn delete_route_req(route: &Route) -> io::Result<Vec<u8>> {
400    let mut nl_hdr = NetlinkHeader::default();
401    nl_hdr.message_type = RTM_DELROUTE;
402    nl_hdr.flags = NLM_F_REQUEST | NLM_F_ACK;
403
404    let mut packet = NetlinkMessage::new(
405        nl_hdr,
406        NetlinkPayload::from(RouteNetlinkMessage::DelRoute(route.try_into()?)),
407    );
408
409    packet.finalize();
410
411    let mut buf = vec![0; packet.header.length as usize];
412    packet.serialize(&mut buf[..]);
413    Ok(buf)
414}
415
416fn route_address_to_ip(addr: RouteAddress) -> Option<IpAddr> {
417    match addr {
418        RouteAddress::Inet(ip) => Some(IpAddr::V4(ip)),
419        RouteAddress::Inet6(ip) => Some(IpAddr::V6(ip)),
420        _ => None,
421    }
422}