route_manager/linux/
mod.rs1use 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
22pub 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 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 #[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 #[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}
97pub 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 pub fn new() -> io::Result<Self> {
133 Ok(Self {
134 _private: std::marker::PhantomData,
135 })
136 }
137 pub fn listener() -> io::Result<RouteListener> {
139 RouteListener::new()
140 }
141
142 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 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 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}