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