1#![allow(unreachable_patterns)]
2
3use std::io::{self, ErrorKind};
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
5
6use futures::TryStreamExt;
7
8use ftth_common::channel::{AsyncWorldClient, AsyncWorldServer};
9use netlink_packet_route::{
10 AddressFamily,
11 address::{AddressAttribute, AddressMessage},
12};
13
14pub(crate) type Client = AsyncWorldClient<RtnlAddressRequest, RtnlAddressResponse>;
15pub(crate) type Server = AsyncWorldServer<RtnlAddressRequest, RtnlAddressResponse>;
16
17#[derive(Debug, Clone, PartialEq)]
18#[non_exhaustive]
19pub enum RtnlAddressRequest {
20 Ipv4AddrsGet { if_id: u32 },
21 Ipv6AddrsGet { if_id: u32 },
22 Ipv4AddrSet { prefix: crate::Ipv4Net, if_id: u32 },
23 Ipv6AddrSet { prefix: crate::Ipv6Net, if_id: u32 },
24 Ipv4AddrDel { prefix: crate::Ipv4Net, if_id: u32 },
25 Ipv6AddrDel { prefix: crate::Ipv6Net, if_id: u32 },
26}
27
28#[derive(Debug, Clone, PartialEq)]
29#[non_exhaustive]
30pub enum RtnlAddressResponse {
31 Success,
32 Failed,
33 NotImplemented,
34 NotFound,
35 Ipv4Addrs(Vec<Ipv4Addr>),
36 Ipv6Addrs(Vec<Ipv6Addr>),
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct RtnlAddressClient {
41 client: Client,
42}
43
44impl RtnlAddressClient {
45 pub(crate) fn new(client: Client) -> Self {
46 Self { client }
47 }
48
49 pub fn ipv4_addrs_get(&self, if_id: Option<u32>) -> std::io::Result<Vec<Ipv4Addr>> {
50 let res = self.client.send_request(RtnlAddressRequest::Ipv4AddrsGet {
51 if_id: if_id.unwrap_or(0),
52 })?;
53 match res {
54 RtnlAddressResponse::Ipv4Addrs(addrs) => {
55 return Ok(addrs);
56 }
57 _ => {}
58 }
59 Err(std::io::Error::other("Failed to get IPv4 addresses"))
60 }
61
62 pub fn ipv6_addrs_get(&self, if_id: Option<u32>) -> std::io::Result<Vec<Ipv6Addr>> {
63 let res = self.client.send_request(RtnlAddressRequest::Ipv6AddrsGet {
64 if_id: if_id.unwrap_or(0),
65 })?;
66 match res {
67 RtnlAddressResponse::Ipv6Addrs(addrs) => {
68 return Ok(addrs);
69 }
70 _ => {}
71 }
72 Err(std::io::Error::other("Failed to get IPv6 addresses"))
73 }
74
75 pub fn ipv4_addr_set(&self, if_id: u32, prefix: crate::Ipv4Net) -> io::Result<()> {
76 let res = self
77 .client
78 .send_request(RtnlAddressRequest::Ipv4AddrSet { prefix, if_id })?;
79 handle_basic_response("IPv4 address set", res, false)
80 }
81
82 pub fn ipv6_addr_set(&self, if_id: u32, prefix: crate::Ipv6Net) -> io::Result<()> {
83 let res = self
84 .client
85 .send_request(RtnlAddressRequest::Ipv6AddrSet { prefix, if_id })?;
86 handle_basic_response("IPv6 address set", res, false)
87 }
88
89 pub fn ipv4_addr_del(&self, if_id: u32, prefix: crate::Ipv4Net) -> io::Result<()> {
90 let res = self
91 .client
92 .send_request(RtnlAddressRequest::Ipv4AddrDel { prefix, if_id })?;
93 handle_basic_response("IPv4 address delete", res, true)
94 }
95
96 pub fn ipv6_addr_del(&self, if_id: u32, prefix: crate::Ipv6Net) -> io::Result<()> {
97 let res = self
98 .client
99 .send_request(RtnlAddressRequest::Ipv6AddrDel { prefix, if_id })?;
100 handle_basic_response("IPv6 address delete", res, true)
101 }
102}
103
104fn build_ipv4_address_message(prefix: &crate::Ipv4Net, if_id: u32) -> AddressMessage {
105 let mut message = AddressMessage::default();
106 message.header.family = AddressFamily::Inet;
107 message.header.index = if_id;
108 message.header.prefix_len = prefix.prefix_len();
109
110 let addr = prefix.addr();
111 if !addr.is_multicast() {
112 message
113 .attributes
114 .push(AddressAttribute::Address(addr.into()));
115 message
116 .attributes
117 .push(AddressAttribute::Local(addr.into()));
118
119 let broadcast = if prefix.prefix_len() == 32 {
120 addr
121 } else {
122 let host_bits = 0xffff_ffff_u32 >> u32::from(prefix.prefix_len());
123 let ip_addr = u32::from(addr);
124 Ipv4Addr::from(ip_addr | host_bits)
125 };
126 message
127 .attributes
128 .push(AddressAttribute::Broadcast(broadcast));
129 }
130
131 message
132}
133
134fn build_ipv6_address_message(prefix: &crate::Ipv6Net, if_id: u32) -> AddressMessage {
135 let mut message = AddressMessage::default();
136 message.header.family = AddressFamily::Inet6;
137 message.header.index = if_id;
138 message.header.prefix_len = prefix.prefix_len();
139
140 let addr = prefix.addr();
141 if addr.is_multicast() {
142 message.attributes.push(AddressAttribute::Multicast(addr));
143 } else {
144 message
145 .attributes
146 .push(AddressAttribute::Address(addr.into()));
147 message
148 .attributes
149 .push(AddressAttribute::Local(addr.into()));
150 }
151
152 message
153}
154
155fn handle_basic_response(
156 operation: &str,
157 response: RtnlAddressResponse,
158 is_delete: bool,
159) -> io::Result<()> {
160 match response {
161 RtnlAddressResponse::Success => Ok(()),
162 RtnlAddressResponse::Failed => {
163 Err(io::Error::other(format!("{} request failed", operation)))
164 }
165 RtnlAddressResponse::NotImplemented => Err(io::Error::new(
166 ErrorKind::Unsupported,
167 format!("{} request is not implemented", operation),
168 )),
169 RtnlAddressResponse::NotFound => Err(io::Error::new(
170 ErrorKind::NotFound,
171 if is_delete {
172 format!("{} target not found", operation)
173 } else {
174 format!("{} not found", operation)
175 },
176 )),
177 unexpected => Err(io::Error::other(format!(
178 "{} returned unexpected response: {:?}",
179 operation, unexpected
180 ))),
181 }
182}
183
184pub(crate) async fn run_server(mut server: Server, handle: rtnetlink::AddressHandle) {
185 while let Some((req, respond)) = server.accept().await {
186 match req {
187 RtnlAddressRequest::Ipv4AddrsGet { if_id } => {
188 let if_index = if_id;
189 let mut addrs = Vec::new();
190 let mut req = handle.get();
191 if if_index != 0 {
192 req = req.set_link_index_filter(if_index);
193 }
194 let response = req.execute();
195
196 futures::pin_mut!(response);
197 while let Ok(Some(response)) = response.try_next().await {
198 if response.header.family != netlink_packet_route::AddressFamily::Inet {
199 continue;
200 }
201 for addr in response.attributes.iter() {
202 if let netlink_packet_route::address::AddressAttribute::Address(
203 std::net::IpAddr::V4(addr),
204 ) = addr
205 {
206 addrs.push(*addr);
207 }
208 }
209 }
210 respond(RtnlAddressResponse::Ipv4Addrs(addrs));
211 }
212 RtnlAddressRequest::Ipv6AddrsGet { if_id } => {
213 let if_index = if_id;
214 let mut addrs = Vec::new();
215 let mut req = handle.get();
216 if if_index != 0 {
217 req = req.set_link_index_filter(if_index);
218 }
219 let response = req.execute();
220
221 futures::pin_mut!(response);
222 while let Ok(Some(response)) = response.try_next().await {
223 if response.header.family != netlink_packet_route::AddressFamily::Inet6 {
224 continue;
225 }
226 for addr in response.attributes.iter() {
227 if let netlink_packet_route::address::AddressAttribute::Address(
228 std::net::IpAddr::V6(addr),
229 ) = addr
230 {
231 addrs.push(*addr);
232 }
233 }
234 }
235 respond(RtnlAddressResponse::Ipv6Addrs(addrs));
236 }
237 RtnlAddressRequest::Ipv4AddrSet { prefix, if_id } => {
238 if if_id == 0 {
239 respond(RtnlAddressResponse::Failed);
240 continue;
241 }
242
243 let addr = prefix.addr();
244 let prefix_len = prefix.prefix_len();
245 let result = handle
246 .add(if_id, IpAddr::V4(addr), prefix_len)
247 .execute()
248 .await;
249
250 match result {
251 Ok(()) => respond(RtnlAddressResponse::Success),
252 Err(rtnetlink::Error::NetlinkError(err_msg))
253 if err_msg.to_io().kind() == ErrorKind::AlreadyExists =>
254 {
255 respond(RtnlAddressResponse::Success);
256 }
257 Err(err) => {
258 log::warn!(
259 "Failed to add IPv4 address {}/{} on ifindex {}: {}",
260 addr,
261 prefix_len,
262 if_id,
263 err,
264 );
265 respond(RtnlAddressResponse::Failed);
266 }
267 }
268 }
269 RtnlAddressRequest::Ipv6AddrSet { prefix, if_id } => {
270 if if_id == 0 {
271 respond(RtnlAddressResponse::Failed);
272 continue;
273 }
274
275 let addr = prefix.addr();
276 let prefix_len = prefix.prefix_len();
277 let result = handle
278 .add(if_id, IpAddr::V6(addr), prefix_len)
279 .execute()
280 .await;
281
282 match result {
283 Ok(()) => respond(RtnlAddressResponse::Success),
284 Err(rtnetlink::Error::NetlinkError(err_msg))
285 if err_msg.to_io().kind() == ErrorKind::AlreadyExists =>
286 {
287 respond(RtnlAddressResponse::Success);
288 }
289 Err(err) => {
290 log::warn!(
291 "Failed to add IPv6 address {}/{} on ifindex {}: {}",
292 addr,
293 prefix_len,
294 if_id,
295 err,
296 );
297 respond(RtnlAddressResponse::Failed);
298 }
299 }
300 }
301 RtnlAddressRequest::Ipv4AddrDel { prefix, if_id } => {
302 if if_id == 0 {
303 respond(RtnlAddressResponse::Failed);
304 continue;
305 }
306
307 let addr = prefix.addr();
308 let prefix_len = prefix.prefix_len();
309 let message = build_ipv4_address_message(&prefix, if_id);
310
311 let result = handle.del(message).execute().await;
312
313 match result {
314 Ok(()) => respond(RtnlAddressResponse::Success),
315 Err(rtnetlink::Error::NetlinkError(err_msg)) => {
316 let io_err = err_msg.to_io();
317 if matches!(
318 io_err.kind(),
319 ErrorKind::AddrNotAvailable | ErrorKind::NotFound
320 ) {
321 respond(RtnlAddressResponse::NotFound);
322 } else {
323 log::warn!(
324 "Failed to delete IPv4 address {}/{} on ifindex {}: {}",
325 addr,
326 prefix_len,
327 if_id,
328 err_msg,
329 );
330 respond(RtnlAddressResponse::Failed);
331 }
332 }
333 Err(err) => {
334 log::warn!(
335 "Failed to delete IPv4 address {}/{} on ifindex {}: {}",
336 addr,
337 prefix_len,
338 if_id,
339 err,
340 );
341 respond(RtnlAddressResponse::Failed);
342 }
343 }
344 }
345 RtnlAddressRequest::Ipv6AddrDel { prefix, if_id } => {
346 if if_id == 0 {
347 respond(RtnlAddressResponse::Failed);
348 continue;
349 }
350
351 let addr = prefix.addr();
352 let prefix_len = prefix.prefix_len();
353 let message = build_ipv6_address_message(&prefix, if_id);
354
355 let result = handle.del(message).execute().await;
356
357 match result {
358 Ok(()) => respond(RtnlAddressResponse::Success),
359 Err(rtnetlink::Error::NetlinkError(err_msg)) => {
360 let io_err = err_msg.to_io();
361 if matches!(
362 io_err.kind(),
363 ErrorKind::AddrNotAvailable | ErrorKind::NotFound
364 ) {
365 respond(RtnlAddressResponse::NotFound);
366 } else {
367 log::warn!(
368 "Failed to delete IPv6 address {}/{} on ifindex {}: {}",
369 addr,
370 prefix_len,
371 if_id,
372 err_msg,
373 );
374 respond(RtnlAddressResponse::Failed);
375 }
376 }
377 Err(err) => {
378 log::warn!(
379 "Failed to delete IPv6 address {}/{} on ifindex {}: {}",
380 addr,
381 prefix_len,
382 if_id,
383 err,
384 );
385 respond(RtnlAddressResponse::Failed);
386 }
387 }
388 }
389 _ => respond(RtnlAddressResponse::NotImplemented),
390 }
391 }
392}