use std::mem::size_of;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use libc::{in_addr, in6_addr};
use ffi::*;
use ffi::netlink_family::*;
use sys::*;
#[derive(Debug)]
pub struct Diag {
pub family: u8,
pub src: SocketAddr,
pub dst: SocketAddr,
pub state: u8,
pub info: Option<tcp_info>,
}
pub fn diag(req: &mut inet_diag_req_v2) -> Result<Vec<Diag>, Error> {
let sock = Socket::new(NETLINK_SOCK_DIAG)?;
let mut hdr = nlmsghdr {
nlmsg_len: nlmsg_length(size_of::<inet_diag_req_v2>() as u32),
nlmsg_type: SOCK_DIAG_BY_FAMILY,
nlmsg_flags: NLM_F_REQUEST | NLM_F_DUMP,
.. Default::default()
};
sock.send(&mut [as_iovec(&mut hdr), as_iovec(req)])?;
sock.recv(|msg: &inet_diag_msg, mut tail: Attrs| {
let (src, dst) = addrs(msg);
let mut diag = Diag {
family: msg.idiag_family,
src: src,
dst: dst,
state: msg.idiag_state,
info: None,
};
while let Some((head, data)) = tail.next::<rtattr>() {
if head.rta_type == INET_DIAG_INFO {
diag.info = Some(*data.cast());
}
}
Ok(diag)
})
}
fn addrs(d: &inet_diag_msg) -> (SocketAddr, SocketAddr) {
unsafe fn addrs_v4(id: &inet_diag_sockid) -> (SocketAddr, SocketAddr) {
let src = (*(&id.idiag_src as *const _ as *const in_addr)).s_addr.to_be();
let dst = (*(&id.idiag_dst as *const _ as *const in_addr)).s_addr.to_be();
let src = SocketAddr::new(IpAddr::V4(Ipv4Addr::from(src)), id.idiag_sport.to_be());
let dst = SocketAddr::new(IpAddr::V4(Ipv4Addr::from(dst)), id.idiag_dport.to_be());
(src, dst)
}
unsafe fn addrs_v6(id: &inet_diag_sockid) -> (SocketAddr, SocketAddr) {
let src = (*(&id.idiag_src as *const _ as *const in6_addr)).s6_addr;
let dst = (*(&id.idiag_dst as *const _ as *const in6_addr)).s6_addr;
let src = SocketAddr::new(IpAddr::V6(Ipv6Addr::from(src)), id.idiag_sport.to_be());
let dst = SocketAddr::new(IpAddr::V6(Ipv6Addr::from(dst)), id.idiag_dport.to_be());
(src, dst)
}
match d.idiag_family {
AF_INET => unsafe { addrs_v4(&d.id) },
AF_INET6 => unsafe { addrs_v6(&d.id) },
_ => unreachable!(),
}
}