1use std::net::IpAddr;
4
5use futures_util::{
6 future::{self, Either},
7 stream::{Stream, StreamExt, TryStreamExt},
8 FutureExt,
9};
10use netlink_packet_core::{NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};
11use netlink_packet_route::{
12 address::{AddressAttribute, AddressMessage},
13 RouteNetlinkMessage,
14};
15
16use crate::{try_rtnl, Error, Handle};
17
18pub struct AddressGetRequest {
19 handle: Handle,
20 message: AddressMessage,
21 filter_builder: AddressFilterBuilder,
22}
23
24impl AddressGetRequest {
25 pub(crate) fn new(handle: Handle) -> Self {
26 AddressGetRequest {
27 handle,
28 message: AddressMessage::default(),
29 filter_builder: AddressFilterBuilder::new(),
30 }
31 }
32
33 pub fn message_mut(&mut self) -> &mut AddressMessage {
34 &mut self.message
35 }
36
37 pub fn execute(self) -> impl Stream<Item = Result<AddressMessage, Error>> {
38 let AddressGetRequest {
39 mut handle,
40 message,
41 filter_builder,
42 } = self;
43
44 let mut req =
45 NetlinkMessage::from(RouteNetlinkMessage::GetAddress(message));
46 req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;
47
48 let filter = filter_builder.build();
49 match handle.request(req) {
50 Ok(response) => Either::Left(
51 response
52 .map(move |msg| {
53 Ok(try_rtnl!(msg, RouteNetlinkMessage::NewAddress))
54 })
55 .try_filter(move |msg| future::ready(filter(msg))),
56 ),
57 Err(e) => Either::Right(
58 future::err::<AddressMessage, Error>(e).into_stream(),
59 ),
60 }
61 }
62
63 pub fn set_link_index_filter(mut self, index: u32) -> Self {
65 self.filter_builder.index = Some(index);
66 self
67 }
68
69 pub fn set_prefix_length_filter(mut self, prefix: u8) -> Self {
71 self.filter_builder.prefix_len = Some(prefix);
72 self
73 }
74
75 pub fn set_address_filter(mut self, address: IpAddr) -> Self {
77 self.filter_builder.address = Some(address);
78 self
79 }
80}
81
82#[derive(Default)]
89struct AddressFilterBuilder {
90 index: Option<u32>,
91 address: Option<IpAddr>,
92 prefix_len: Option<u8>,
93}
94
95impl AddressFilterBuilder {
96 fn new() -> Self {
97 Default::default()
98 }
99
100 fn build(self) -> impl Fn(&AddressMessage) -> bool {
101 use AddressAttribute::*;
102
103 move |msg: &AddressMessage| {
104 if let Some(index) = self.index {
105 if msg.header.index != index {
106 return false;
107 }
108 }
109
110 if let Some(prefix_len) = self.prefix_len {
111 if msg.header.prefix_len != prefix_len {
112 return false;
113 }
114 }
115
116 if let Some(address) = self.address {
117 for nla in msg.attributes.iter() {
118 if let Address(x) | Local(x) = nla {
119 if x == &address {
120 return true;
121 }
122 } else if let Multicast(x) | Anycast(x) = nla {
123 if IpAddr::V6(*x) == address {
124 return true;
125 }
126 }
127 }
128 return false;
129 }
130 true
131 }
132 }
133}