netlink_packet_route/rtnl/route/
message.rs

1// SPDX-License-Identifier: MIT
2
3use std::net::IpAddr;
4
5use anyhow::Context;
6use netlink_packet_utils::{
7    traits::{Emitable, Parseable},
8    DecodeError,
9};
10
11use crate::{nlas::route::Nla, RouteHeader, RouteMessageBuffer};
12
13#[derive(Debug, PartialEq, Eq, Clone, Default)]
14#[non_exhaustive]
15pub struct RouteMessage {
16    pub header: RouteHeader,
17    pub nlas: Vec<Nla>,
18}
19
20impl Emitable for RouteMessage {
21    fn buffer_len(&self) -> usize {
22        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
23    }
24
25    fn emit(&self, buffer: &mut [u8]) {
26        self.header.emit(buffer);
27        self.nlas
28            .as_slice()
29            .emit(&mut buffer[self.header.buffer_len()..]);
30    }
31}
32
33impl<'a, T: AsRef<[u8]> + 'a> Parseable<RouteMessageBuffer<&'a T>>
34    for RouteMessage
35{
36    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
37        Ok(RouteMessage {
38            header: RouteHeader::parse(buf)
39                .context("failed to parse route message header")?,
40            nlas: Vec::<Nla>::parse(buf)
41                .context("failed to parse route message NLAs")?,
42        })
43    }
44}
45
46impl<'a, T: AsRef<[u8]> + 'a> Parseable<RouteMessageBuffer<&'a T>>
47    for Vec<Nla>
48{
49    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
50        let mut nlas = vec![];
51        for nla_buf in buf.nlas() {
52            nlas.push(Nla::parse(&nla_buf?)?);
53        }
54        Ok(nlas)
55    }
56}
57
58fn octets_to_addr(octets: &[u8]) -> Result<IpAddr, DecodeError> {
59    if octets.len() == 4 {
60        let mut ary: [u8; 4] = Default::default();
61        ary.copy_from_slice(octets);
62        Ok(IpAddr::from(ary))
63    } else if octets.len() == 16 {
64        let mut ary: [u8; 16] = Default::default();
65        ary.copy_from_slice(octets);
66        Ok(IpAddr::from(ary))
67    } else {
68        Err(DecodeError::from("Cannot decode IP address"))
69    }
70}
71
72impl RouteMessage {
73    /// Returns the input interface index, if present.
74    pub fn input_interface(&self) -> Option<u32> {
75        self.nlas.iter().find_map(|nla| {
76            if let Nla::Iif(v) = nla {
77                Some(*v)
78            } else {
79                None
80            }
81        })
82    }
83
84    /// Returns the output interface index, if present.
85    pub fn output_interface(&self) -> Option<u32> {
86        self.nlas.iter().find_map(|nla| {
87            if let Nla::Oif(v) = nla {
88                Some(*v)
89            } else {
90                None
91            }
92        })
93    }
94
95    /// Returns the source address prefix, if present.
96    pub fn source_prefix(&self) -> Option<(IpAddr, u8)> {
97        self.nlas.iter().find_map(|nla| {
98            if let Nla::Source(v) = nla {
99                octets_to_addr(v)
100                    .ok()
101                    .map(|addr| (addr, self.header.source_prefix_length))
102            } else {
103                None
104            }
105        })
106    }
107
108    /// Returns the destination subnet prefix, if present.
109    pub fn destination_prefix(&self) -> Option<(IpAddr, u8)> {
110        self.nlas.iter().find_map(|nla| {
111            if let Nla::Destination(v) = nla {
112                octets_to_addr(v)
113                    .ok()
114                    .map(|addr| (addr, self.header.destination_prefix_length))
115            } else {
116                None
117            }
118        })
119    }
120
121    /// Returns the gateway address, if present.
122    pub fn gateway(&self) -> Option<IpAddr> {
123        self.nlas.iter().find_map(|nla| {
124            if let Nla::Gateway(v) = nla {
125                octets_to_addr(v).ok()
126            } else {
127                None
128            }
129        })
130    }
131}