summaryrefslogtreecommitdiffstats
path: root/src/netlink.rs
blob: 9e21dbc95564ee08cbb53c5c566478cf3b408319 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use std::net::IpAddr;

use futures::stream::TryStreamExt;
use netlink_packet_route::{
    neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourMessage, NeighbourState},
    route::RouteType,
};
use rtnetlink::{new_connection, IpVersion};
use tokio::sync::mpsc::Sender;

use crate::{Error, Result};

pub async fn neighbours(tx: Sender<IpAddr>) -> Result<()> {
    let (connection, handle, _) = new_connection().unwrap();
    tokio::spawn(connection);

    handle
        .neighbours()
        .get()
        .set_family(IpVersion::V4)
        .execute()
        .or_else(|err| async { Err(Error::from(err)) })
        .try_filter_map(|msg| async { Ok(filter(msg)) })
        .try_for_each(|ip_addr| {
            let tx = tx.clone();
            async move { Ok(tx.send(ip_addr).await?) }
        })
        .await
}

pub fn filter(msg: NeighbourMessage) -> Option<IpAddr> {
    if msg.header.state == NeighbourState::Failed || msg.header.kind != RouteType::Unicast {
        return None;
    }

    msg.attributes.into_iter().find_map(|attr| match attr {
        NeighbourAttribute::Destination(NeighbourAddress::Inet(ip)) => Some(ip.into()),
        NeighbourAttribute::Destination(NeighbourAddress::Inet6(ip)) => Some(ip.into()),
        _ => None,
    })
}