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