1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
use super::{
data::{self, MessageType, RouteMessage, RouteSocketMessage},
routing_socket,
};
use std::io;
type Result<T> = std::result::Result<T, Error>;
/// Errors that can occur for a PF_ROUTE socket
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Generic routing socket error
#[error("Routing socket error")]
RoutingSocket(#[source] routing_socket::Error),
/// Failed to parse route message
#[error("Invalid message")]
InvalidMessage(#[source] data::Error),
/// Failed to send route message
#[error("Failed to send routing message")]
Send(#[source] routing_socket::Error),
/// Received unexpected response to route message
#[error("Unexpected message type")]
UnexpectedMessageType(Box<RouteSocketMessage>, MessageType),
/// Route not found
#[error("Route not found")]
RouteNotFound,
/// No route to destination
#[error("Destination unreachable")]
Unreachable,
/// Failed to delete route
#[error("Failed to delete a route")]
Deletion(RouteMessage),
}
/// Provides an interface for PF_ROUTE sockets
pub struct RoutingTable {
socket: routing_socket::RoutingSocket,
}
/// Result of successfully adding a route
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum AddResult {
/// A new route was created
Ok,
/// The route already exists
AlreadyExists,
}
impl RoutingTable {
/// New routing table interface
pub fn new() -> Result<Self> {
let socket = routing_socket::RoutingSocket::new().map_err(Error::RoutingSocket)?;
Ok(Self { socket })
}
/// Receive the next message from the routing socket
pub async fn next_message(&mut self) -> Result<RouteSocketMessage> {
let mut buf = [0u8; 2048];
let bytes_read = loop {
match self.socket.recv_msg(&mut buf).await {
Ok(bytes_read) => break bytes_read,
Err(error) if error.is_shutdown() => {
log::debug!("Recreating shut down socket");
self.socket =
routing_socket::RoutingSocket::new().map_err(Error::RoutingSocket)?;
}
Err(error) => return Err(Error::RoutingSocket(error)),
}
};
let msg_buf = &buf[0..bytes_read];
data::RouteSocketMessage::parse_message(msg_buf).map_err(Error::InvalidMessage)
}
/// Add route to the routing table
pub async fn add_route(&mut self, message: &RouteMessage) -> Result<AddResult> {
if let Ok(Some(destination)) = message.destination_ip() {
if Some(destination.ip()) == message.gateway_ip() {
// Workaround that allows us to reach a wg peer on our router.
// If we don't do this, adding the route fails due to errno 49
// ("Can't assign requested address").
log::warn!("Ignoring route because the destination equals its gateway");
return Ok(AddResult::AlreadyExists);
}
}
log::trace!("Add route: {message:?}");
let msg = self
.alter_routing_table(message, MessageType::RTM_ADD)
.await;
match msg {
Ok(RouteSocketMessage::AddRoute(_route)) => Ok(AddResult::Ok),
Err(Error::Send(routing_socket::Error::Write(err)))
if err.kind() == io::ErrorKind::AlreadyExists =>
{
Ok(AddResult::AlreadyExists)
}
Ok(anything_else) => {
log::error!("Unexpected route message: {anything_else:?}");
Err(Error::UnexpectedMessageType(
Box::new(anything_else),
MessageType::RTM_ADD,
))
}
Err(err) => Err(err),
}
}
async fn alter_routing_table(
&mut self,
message: &RouteMessage,
message_type: MessageType,
) -> Result<RouteSocketMessage> {
let result = self.socket.send_route_message(message, message_type).await;
match result {
Ok(response) => {
data::RouteSocketMessage::parse_message(&response).map_err(Error::InvalidMessage)
}
Err(routing_socket::Error::Write(err)) if err.kind() == io::ErrorKind::NotFound => {
Err(Error::RouteNotFound)
}
Err(routing_socket::Error::Write(err))
if [Some(libc::ENETUNREACH), Some(libc::ESRCH)].contains(&err.raw_os_error()) =>
{
Err(Error::Unreachable)
}
Err(err) => Err(Error::Send(err)),
}
}
/// Delete route from the routing table
pub async fn delete_route(&mut self, message: &RouteMessage) -> Result<()> {
log::trace!("Delete route: {message:?}");
let response = self
.alter_routing_table(message, MessageType::RTM_DELETE)
.await?;
match response {
RouteSocketMessage::DeleteRoute(route) if route.errno() == 0 => Ok(()),
RouteSocketMessage::DeleteRoute(route) if route.errno() != 0 => {
Err(Error::Deletion(route))
}
anything_else => Err(Error::UnexpectedMessageType(
Box::new(anything_else),
MessageType::RTM_DELETE,
)),
}
}
/// Get route from the routing table
pub async fn get_route(
&mut self,
message: &RouteMessage,
) -> Result<Option<data::RouteMessage>> {
let response = self
.socket
.send_route_message(message, MessageType::RTM_GET)
.await;
let response = match response {
Ok(response) => response,
Err(routing_socket::Error::Write(err)) => {
if let Some(err) = err.raw_os_error() {
if [libc::ENETUNREACH, libc::ESRCH].contains(&err) {
return Ok(None);
}
}
return Err(Error::RoutingSocket(routing_socket::Error::Write(err)));
}
Err(other_err) => {
return Err(Error::RoutingSocket(other_err));
}
};
match data::RouteSocketMessage::parse_message(&response).map_err(Error::InvalidMessage)? {
data::RouteSocketMessage::GetRoute(route) => Ok(Some(route)),
unexpected_route_message => Err(Error::UnexpectedMessageType(
Box::new(unexpected_route_message),
MessageType::RTM_GET,
)),
}
}
}
|