Skip to main content

ip_nlroute/addr/
flush.rs

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        // Collect addresses to delete from this round.
57        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                //TODO: is there any point to this check?
69                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}