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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use libc;
use std::ffi::CStr;
use std::{mem, net, ptr};
use nix;
use nix::sys::socket;
use ffi;
#[derive(PartialEq, Eq, Debug)]
pub enum Kind {
Packet,
Ipv4,
Ipv6,
}
#[derive(PartialEq, Eq, Debug)]
pub enum NextHop {
Broadcast(net::SocketAddr),
Destination(net::SocketAddr),
}
#[derive(Debug)]
pub struct Interface {
pub name: String,
pub kind: Kind,
pub addr: Option<net::SocketAddr>,
pub mask: Option<net::SocketAddr>,
pub hop: Option<NextHop>,
}
impl Interface {
pub fn get_all () -> Result<Vec<Interface>, nix::errno::Errno> {
let mut ifap: *mut ffi::ifaddrs = unsafe { mem::zeroed() };
if unsafe { ffi::getifaddrs(&mut ifap as *mut _) } != 0 {
return Err(nix::errno::Errno::last());
}
let mut ret = Vec::new();
let mut cur: *mut ffi::ifaddrs = ifap;
while cur != ptr::null_mut() {
if let Some(iface) = convert_ifaddrs(cur) {
ret.push(iface);
}
cur = unsafe { (*cur).ifa_next };
}
unsafe { ffi::freeifaddrs(ifap) };
Ok(ret)
}
}
fn convert_ifaddrs (ifa: *mut ffi::ifaddrs) -> Option<Interface> {
let ifa = unsafe { &mut *ifa };
let name = match String::from_utf8(unsafe {
CStr::from_ptr(ifa.ifa_name)
}.to_bytes().to_vec()) {
Ok(x) => x,
Err(_) => return None,
};
let kind = if ifa.ifa_addr != ptr::null_mut() {
match unsafe { *ifa.ifa_addr }.sa_family as i32 {
ffi::AF_PACKET => Kind::Packet,
socket::AF_INET => Kind::Ipv4,
socket::AF_INET6 => Kind::Ipv6,
_ => return None,
}
} else {
return None;
};
let addr = ffi::convert_sockaddr(ifa.ifa_addr);
let mask = ffi::convert_sockaddr(ifa.ifa_netmask);
let hop = if ifa.ifa_flags & ffi::SIOCGIFFLAGS::IFF_BROADCAST as libc::c_uint == ffi::SIOCGIFFLAGS::IFF_BROADCAST as libc::c_uint {
match ffi::convert_sockaddr(ifa.ifa_ifu.ifu_broadaddr()) {
Some(x) => Some(NextHop::Broadcast(x)),
None => None,
}
} else {
match ffi::convert_sockaddr(ifa.ifa_ifu.ifu_dstaddr()) {
Some(x) => Some(NextHop::Destination(x)),
None => None,
}
};
Some(Interface {
name: name,
kind: kind,
addr: addr,
mask: mask,
hop: hop,
})
}