netlink_packet_route/rtnl/route/
message.rs1use 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 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 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 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 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 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}