]> code.octet-stream.net Git - netwatcher/blob - src/watch_linux.rs
4e4049b8856ba87dece34d25677f1116c49ae7a5
[netwatcher] / src / watch_linux.rs
1 use std::os::fd::AsRawFd;
2 use std::os::fd::OwnedFd;
3
4 use nix::libc::nlmsghdr;
5 use nix::libc::RTMGRP_IPV4_IFADDR;
6 use nix::libc::RTMGRP_IPV6_IFADDR;
7 use nix::libc::RTMGRP_LINK;
8 use nix::sys::socket::bind;
9 use nix::sys::socket::recv;
10 use nix::sys::socket::socket;
11 use nix::sys::socket::AddressFamily;
12 use nix::sys::socket::MsgFlags;
13 use nix::sys::socket::NetlinkAddr;
14 use nix::sys::socket::SockFlag;
15 use nix::sys::socket::SockProtocol;
16 use nix::sys::socket::SockType;
17
18 use crate::Error;
19 use crate::Update;
20
21 pub(crate) struct WatchHandle {
22 // PROBLEM: close() doesn't cancel recv() for a netlink socket
23 sockfd: OwnedFd,
24 }
25
26 pub(crate) fn watch_interfaces<F: FnMut(Update) + 'static>(
27 callback: F,
28 ) -> Result<WatchHandle, Error> {
29 let sockfd = start_watcher_thread(callback)?;
30 Ok(WatchHandle { sockfd })
31 }
32
33 fn start_watcher_thread<F: FnMut(Update) + 'static>(callback: F) -> Result<OwnedFd, Error> {
34 let sockfd = socket(AddressFamily::Netlink, SockType::Raw, SockFlag::empty(), Some(SockProtocol::NetlinkRoute))
35 .map_err(|_| Error::Internal)?; // TODO: proper errors
36 let sa_nl = NetlinkAddr::new(0, (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR) as u32);
37 bind(sockfd.as_raw_fd(), &sa_nl).map_err(|_| Error::Internal)?; // TODO: proper errors
38 let fd = sockfd.as_raw_fd();
39 println!("netlink socket on fd {}", fd);
40
41 std::thread::spawn(move || {
42 println!("watch thread running");
43 let mut buf = [0u8; 4096];
44 // recvmsg?
45 while let Ok(n) = recv(fd, &mut buf, MsgFlags::empty()) {
46 println!("something on the netlink socket: {} bytes", n);
47 let nlmsg_ptr = &buf as *const _ as *const nlmsghdr;
48 let nlmsg = unsafe { &*nlmsg_ptr };
49 // Right conventionally there's some trick here involving macros NLMSG_OK
50 // I can presumably do this using NetlinkGeneric too
51 // It's unclear whether this is worse or not - need to know what those macros do
52 }
53 println!("netlink recv thread terminating");
54 });
55
56 Ok(sockfd)
57 }