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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Copyright (C) 2018 - Will Glozer. All rights reserved.

use std::convert::TryFrom;
use std::net::{IpAddr, SocketAddr};
use std::mem::transmute;
use crate::Message;
use crate::err::Invalid;
use crate::ffi::{AF_INET, AF_INET6, inet_diag_msg, tcp_info};
use crate::sys::Bytes;

#[derive(Debug)]
pub struct Diag<T = tcp_info> {
    pub family: u8,
    pub src:    SocketAddr,
    pub dst:    SocketAddr,
    pub state:  u8,
    pub info:   Option<T>,
}

pub fn diag(msg: &Message<inet_diag_msg>) -> Result<Diag, Invalid> {
    let src  = addr(msg.idiag_family, &msg.id.idiag_src, msg.id.idiag_sport)?;
    let dst  = addr(msg.idiag_family, &msg.id.idiag_dst, msg.id.idiag_dport)?;
    let info = msg.info();

    Ok(Diag {
        family: msg.idiag_family,
        src:    src,
        dst:    dst,
        state:  msg.idiag_state,
        info:   info,
    })
}

pub fn diag2<T: Bytes>(msg: Message<inet_diag_msg>) -> Result<Diag<T>, Invalid> {
    let src  = addr(msg.idiag_family, &msg.id.idiag_src, msg.id.idiag_sport)?;
    let dst  = addr(msg.idiag_family, &msg.id.idiag_dst, msg.id.idiag_dport)?;
    let info = msg.info();

    Ok(Diag {
        family: msg.idiag_family,
        src:    src,
        dst:    dst,
        state:  msg.idiag_state,
        info:   info,
    })
}

fn addr(family: u8, addr: &[u32; 4], port: u16) -> Result<SocketAddr, Invalid> {
    let octets: &[u8; 16] = unsafe { transmute(addr) };
    Ok(SocketAddr::new(match family {
        AF_INET  => IpAddr::from(<[u8;  4]>::try_from(&octets[..4])?),
        AF_INET6 => IpAddr::from(<[u8; 16]>::try_from(&octets[..])?),
        family   => return Err(Invalid::Family(family)),
    }, port.to_be()))
}