1use crate::addr::flush_response::AddrFlushResponse;
2#[cfg(all(target_os = "linux", feature = "netlink"))]
3use neli::{
4 consts::nl::NlmF,
5 consts::rtnl::{RtAddrFamily, RtScope, Rtm},
6 nl::NlPayload,
7 router::synchronous::NlRouterReceiverHandle,
8 rtnl::{Ifaddrmsg, IfaddrmsgBuilder},
9};
10#[cfg(all(target_os = "linux", feature = "netlink"))]
11use nix::net::if_::if_nametoindex;
12
13use crate::NetlinkRouteHandle;
14use crate::error::Error;
15
16pub struct AddrFlushRequest {
17 if_index: u32,
18}
19
20impl AddrFlushRequest {
21 #[cfg(not(all(target_os = "linux", feature = "netlink")))]
22 pub fn for_ifname(_ifname: &str) -> Result<Self, Error> {
23 Err(Error::NotImplemented)
24 }
25
26 #[cfg(all(target_os = "linux", feature = "netlink"))]
27 pub fn for_ifname(ifname: &str) -> Result<Self, Error> {
28 let if_index = if_nametoindex(ifname).map_err(|e| Error::InterfaceLookup {
29 ifname: ifname.to_owned(),
30 source: e,
31 })?;
32 Ok(AddrFlushRequest { if_index })
33 }
34
35 #[cfg(not(all(target_os = "linux", feature = "netlink")))]
36 pub fn send(&self, h: &mut NetlinkRouteHandle) -> Result<AddrFlushResponse, Error> {
37 Err(Error::NotImplemented)
38 }
39
40 #[cfg(all(target_os = "linux", feature = "netlink"))]
41 pub fn send(&self, h: &mut NetlinkRouteHandle) -> Result<AddrFlushResponse, Error> {
42 let mut addresses_flushed: usize = 0;
43
44 let ifaddrmsg = IfaddrmsgBuilder::default()
45 .ifa_family(RtAddrFamily::Inet)
46 .ifa_prefixlen(0)
47 .ifa_scope(RtScope::Universe)
48 .ifa_index(self.if_index)
49 .build()?;
50
51 let recv: NlRouterReceiverHandle<Rtm, Ifaddrmsg> = h
52 .rtnl
53 .send(Rtm::Getaddr, NlmF::DUMP, NlPayload::Payload(ifaddrmsg))
54 .map_err(|e| Error::Send(Box::new(e)))?;
55
56 let mut to_delete: Vec<Ifaddrmsg> = vec![];
58
59 for response in recv {
60 let header = response.map_err(|e| Error::Receive(Box::new(e)))?;
61 if let NlPayload::Payload(p) = header.nl_payload() {
62 if header.nl_type() != &Rtm::Newaddr {
63 return Err(Error::UnexpectedNlType {
64 expected: format!("{:?}", Rtm::Newaddr),
65 actual: format!("{:?}", header.nl_type()),
66 });
67 }
68 if *p.ifa_index() == self.if_index {
70 to_delete.push(p.clone());
71 } else {
72 return Err(Error::InvalidDataInResponse {
73 reason: "received ifindex violating filter",
74 });
75 }
76 }
77 }
78
79 for addr_msg in to_delete {
80 let recv: NlRouterReceiverHandle<Rtm, Ifaddrmsg> = h
81 .rtnl
82 .send(Rtm::Deladdr, NlmF::ACK, NlPayload::Payload(addr_msg))
83 .map_err(|e| Error::Send(Box::new(e)))?;
84
85 for response in recv {
86 response.map_err(|e| Error::Receive(Box::new(e)))?;
87 }
88
89 addresses_flushed += 1;
90 }
91
92 Ok(AddrFlushResponse { addresses_flushed })
93 }
94}