blob: a4e01304052817c77fdb15396b5b9bbe3481a224 [file] [log] [blame]
Mohammed Naser62c4dd92025-02-16 13:18:14 -05001use ipnet::IpNet;
2use log::error;
3use netlink_packet_route::{
4 route::{RouteAddress, RouteAttribute, RouteMessage, RouteProtocol},
5 AddressFamily,
6};
7use std::{
8 fmt,
9 net::{IpAddr, Ipv4Addr, Ipv6Addr},
10};
11use thiserror::Error;
12
13#[derive(Error, Debug)]
14pub enum RouteError {
15 #[error("Invalid gateway")]
16 InvalidGateway,
17
18 #[error("Invalid destination")]
19 InvalidDestination,
20
21 #[error("Invalid prefix length")]
22 InvalidPrefixLength,
23
24 #[error("Missing gateway")]
25 MissingGateway,
26
27 #[error("Missing destination")]
28 MissingDestination,
29}
30
31pub struct Route {
32 pub protocol: RouteProtocol,
33 pub destination: IpNet,
34 pub gateway: IpAddr,
35}
36
37impl fmt::Debug for Route {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 write!(f, "{} via {}", self.destination, self.gateway)
40 }
41}
42
43impl Route {
44 pub fn from_message(message: RouteMessage) -> Result<Self, RouteError> {
45 let mut gateway = None;
46 let mut destination = None;
47
48 for nla in message.attributes.iter() {
49 if let RouteAttribute::Gateway(ip) = nla {
50 gateway = match ip {
51 RouteAddress::Inet(ip) => Some(IpAddr::V4(*ip)),
52 RouteAddress::Inet6(ip) => Some(IpAddr::V6(*ip)),
53 _ => return Err(RouteError::InvalidGateway),
54 };
55 }
56
57 if let RouteAttribute::Destination(ref ip) = nla {
58 destination = match ip {
59 RouteAddress::Inet(ip) => Some(
60 IpNet::new(IpAddr::V4(*ip), message.header.destination_prefix_length)
61 .map_err(|_| RouteError::InvalidPrefixLength)?,
62 ),
63 RouteAddress::Inet6(ip) => Some(
64 IpNet::new(IpAddr::V6(*ip), message.header.destination_prefix_length)
65 .map_err(|_| RouteError::InvalidPrefixLength)?,
66 ),
67 _ => return Err(RouteError::InvalidDestination),
68 };
69 }
70 }
71
72 let gateway = match gateway {
73 Some(gateway) => gateway,
74 None => return Err(RouteError::MissingGateway),
75 };
76
77 let destination = match destination {
78 Some(destination) => destination,
79 None => match message.header.address_family {
80 AddressFamily::Inet => IpNet::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
81 .map_err(|_| RouteError::InvalidPrefixLength)?,
82 AddressFamily::Inet6 => IpNet::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0)
83 .map_err(|_| RouteError::InvalidPrefixLength)?,
84 _ => return Err(RouteError::InvalidDestination),
85 },
86 };
87
88 Ok(Route {
89 protocol: message.header.protocol,
90 destination,
91 gateway,
92 })
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use netlink_packet_route::AddressFamily;
100 use std::net::Ipv4Addr;
101
102 #[tokio::test]
103 async fn test_default_ipv4_route() {
104 let mut message = RouteMessage::default();
105
106 message.header.address_family = AddressFamily::Inet;
107 message.header.destination_prefix_length = 0;
108 message.header.protocol = RouteProtocol::Static;
109 message
110 .attributes
111 .push(RouteAttribute::Gateway(RouteAddress::Inet(Ipv4Addr::new(
112 192, 168, 1, 1,
113 ))));
114
115 let route = Route::from_message(message).unwrap();
116
117 assert_eq!(route.protocol, RouteProtocol::Static);
118 assert_eq!(
119 route.destination,
120 IpNet::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0).unwrap()
121 );
122 assert_eq!(route.gateway, IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)));
123 }
124
125 #[tokio::test]
126 async fn test_default_ipv6_route() {
127 let mut message = RouteMessage::default();
128
129 message.header.address_family = AddressFamily::Inet6;
130 message.header.destination_prefix_length = 0;
131 message.header.protocol = RouteProtocol::Static;
132 message
133 .attributes
134 .push(RouteAttribute::Gateway(RouteAddress::Inet6(Ipv6Addr::new(
135 0, 0, 0, 0, 0, 0, 0, 1,
136 ))));
137
138 let route = Route::from_message(message).unwrap();
139
140 assert_eq!(route.protocol, RouteProtocol::Static);
141 assert_eq!(
142 route.destination,
143 IpNet::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0).unwrap()
144 );
145 assert_eq!(
146 route.gateway,
147 IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))
148 );
149 }
150}