|
| 1 | +use std::io; |
| 2 | + |
| 3 | +#[cfg(not(target_os = "linux"))] |
| 4 | +fn main() { |
| 5 | + println!("This example works only on Linux!"); |
| 6 | +} |
| 7 | + |
| 8 | +#[cfg(target_os = "linux")] |
| 9 | +fn main() -> io::Result<()> { |
| 10 | + use netlink_packet_core::{NetlinkHeader, NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST}; |
| 11 | + use netlink_packet_route::{rtnl::link::nlas::Nla, LinkMessage, NetlinkPayload, RtnlMessage}; |
| 12 | + use netlink_sys::{Protocol, Socket, SocketAddr}; |
| 13 | + use smol::Async; |
| 14 | + use std::process; |
| 15 | + |
| 16 | + fn align(len: usize) -> usize { |
| 17 | + const RTA_ALIGNTO: usize = 4; |
| 18 | + |
| 19 | + ((len)+RTA_ALIGNTO-1) & !(RTA_ALIGNTO-1) |
| 20 | + } |
| 21 | + |
| 22 | + smol::run(async { |
| 23 | + let mut socket = Socket::new(Protocol::Route)?; |
| 24 | + socket.bind(&SocketAddr::new(process::id(), 1))?; |
| 25 | + let mut socket = Async::new(socket)?; |
| 26 | + |
| 27 | + let mut packet = NetlinkMessage { |
| 28 | + header: NetlinkHeader { |
| 29 | + sequence_number: 1, |
| 30 | + flags: NLM_F_DUMP | NLM_F_REQUEST, |
| 31 | + ..Default::default() |
| 32 | + }, |
| 33 | + payload: RtnlMessage::GetLink(LinkMessage::default()).into(), |
| 34 | + }; |
| 35 | + packet.finalize(); |
| 36 | + |
| 37 | + let mut buf = vec![0; packet.header.length as usize]; |
| 38 | + packet.serialize(&mut buf[..]); |
| 39 | + socket.write_with_mut(|sock| sock.send(&buf, 0)).await?; |
| 40 | + |
| 41 | + 'out: loop { |
| 42 | + let mut buf = [0; 4096]; |
| 43 | + let mut cursor = 0; |
| 44 | + |
| 45 | + let (count, _) = socket |
| 46 | + .read_with_mut(|sock| sock.recv_from(&mut buf, 0)) |
| 47 | + .await?; |
| 48 | + loop { |
| 49 | + if cursor >= count { |
| 50 | + break; |
| 51 | + } |
| 52 | + let msg_len = { |
| 53 | + let mut len_buf = [0; 4]; |
| 54 | + len_buf.copy_from_slice(&buf[cursor..cursor + 4]); |
| 55 | + u32::from_ne_bytes(len_buf) as usize |
| 56 | + }; |
| 57 | + let msg_len = align(msg_len); |
| 58 | + let reply = NetlinkMessage::<RtnlMessage>::deserialize(&buf[cursor..cursor + msg_len]) |
| 59 | + .expect("Failed to deserialize message"); |
| 60 | + match reply.payload { |
| 61 | + NetlinkPayload::InnerMessage(RtnlMessage::NewLink(link)) => { |
| 62 | + let name = link |
| 63 | + .nlas |
| 64 | + .iter() |
| 65 | + .filter_map(|nla| match nla { |
| 66 | + Nla::IfName(name) => Some(name.clone()), |
| 67 | + _ => None, |
| 68 | + }) |
| 69 | + .next() |
| 70 | + .unwrap(); |
| 71 | + println!("{}: {}", link.header.index, name); |
| 72 | + } |
| 73 | + _ => { |
| 74 | + break 'out; |
| 75 | + } |
| 76 | + } |
| 77 | + cursor += msg_len; |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + Ok(()) |
| 82 | + }) |
| 83 | +} |
0 commit comments