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