#![allow(non_camel_case_types)]
#[macro_use] extern crate enum_primitive;
extern crate netinfo;
use std::panic;
use std::ffi::CString;
use std::os::raw::*;
use std::mem;
use std::ptr::null_mut;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::time::Duration;
use netinfo::*;
use netinfo::error::Error as LibError;
use enum_primitive::FromPrimitive;
macro_rules! safe {
($($tty:tt)*) => (
{
let panic_result: Result<WrapperResult<()>, _> = std::panic::catch_unwind(|| {
$($tty)*
});
match panic_result {
Ok(closure_result) => ReturnCodes::from(closure_result) as ni_error_code,
Err(_) => ReturnCodes::UnknownError as ni_error_code,
}
}
);
}
macro_rules! check_ptr {
($($i:ident),+) => {
$(
if $i == null_mut() { return From::from(ReturnCodes::NullPointerArgument); }
)*
}
}
fn vec_to_ptr_len<T>(v: Vec<T>) -> (*mut T, usize) {
let mut b = v.into_boxed_slice();
let ptr = b.as_mut_ptr();
let len = b.len();
std::mem::forget(b);
(ptr, len)
}
unsafe fn ptr_len_to_vec<T>(ptr: *mut T, len: usize) -> Vec<T> {
Box::from_raw(std::slice::from_raw_parts_mut(ptr, len)).into_vec()
}
unsafe fn temp_box<T, A, F: FnOnce(&mut Box<T>) -> WrapperResult<A>>(ptr: *mut c_void, f: F) -> WrapperResult<A> {
let mut b = Box::from_raw(ptr as *mut T);
let res = f(&mut b);
mem::forget(b);
res
}
unsafe fn temp_vec<T, A, F: FnOnce(&mut Vec<T>) -> WrapperResult<A>>(ptr: *mut T, len: u32, f: F) -> WrapperResult<A> {
let mut v = ptr_len_to_vec::<T>(ptr, len as usize);
let res = f(&mut v);
mem::forget(v);
res
}
unsafe fn temp_vec_of_box_cloned<T: Clone, R>(vec_ptr: *mut *mut R, vec_len: u32) -> WrapperResult<Vec<T>> {
let mut vec: Vec<T> = Vec::new();
temp_vec(vec_ptr, vec_len, |vec_of_ptr_elem: &mut Vec<*mut R>| {
for &mut ptr_elem in vec_of_ptr_elem {
temp_box(ptr_elem as *mut c_void, |elem_box: &mut Box<T>| {
vec.push((**elem_box).clone());
Ok(())
})?;
};
Ok(())
})?;
Ok(vec)
}
type ni_netinfo = *mut c_void;
type ni_net_interface = *mut c_void;
type ni_net_statistics = *mut c_void;
type ni_error_code = i32;
type ni_boolean = u8;
type ni_pid = u64;
type ni_inout = u32;
type ni_transport_type = u32;
#[repr(C)]
#[derive(Debug)]
pub struct ni_mac_addr {
d: [u8; 6],
}
#[repr(C)]
#[derive(Debug)]
pub struct ni_ipv4_addr {
v4: [u8; 4],
}
#[repr(C)]
#[derive(Debug)]
pub struct ni_ipv6_addr {
v6: [u8; 16], }
enum_from_primitive!{
#[repr(C)]
#[derive(Clone, Copy)]
enum ni_inout_enum {
NETINFO_IOT_INCOMING = 0,
NETINFO_IOT_OUTGOING = 1,
}
}
enum_from_primitive!{
#[repr(C)]
#[derive(Clone, Copy)]
enum ni_transport_type_enum {
NETINFO_TT_TCP = 0,
NETINFO_TT_UDP = 1,
}
}
impl ni_transport_type_enum {
fn import(int: ni_transport_type) -> WrapperResult<ni_transport_type_enum> {
ni_transport_type_enum::from_u32(int).ok_or(WrapperError::InvalidTransportType)
}
fn to_netinfo_type(&self) -> netinfo::TransportType {
match *self {
ni_transport_type_enum::NETINFO_TT_TCP => { netinfo::TransportType::Tcp }
ni_transport_type_enum::NETINFO_TT_UDP => { netinfo::TransportType::Udp }
}
}
}
impl ni_inout_enum {
fn import(int: ni_inout) -> WrapperResult<ni_inout_enum> {
ni_inout_enum::from_u32(int).ok_or(WrapperError::InvalidInoutType)
}
fn to_netinfo_type(&self) -> netinfo::InoutType {
match *self {
ni_inout_enum::NETINFO_IOT_INCOMING => { netinfo::InoutType::Incoming }
ni_inout_enum::NETINFO_IOT_OUTGOING => { netinfo::InoutType::Outgoing }
}
}
}
impl From<MacAddr> for ni_mac_addr {
fn from(f: MacAddr) -> ni_mac_addr { let m = ni_mac_addr { d: f.into() }; m }
}
impl From<Ipv4Addr> for ni_ipv4_addr {
fn from(e: Ipv4Addr) -> ni_ipv4_addr { ni_ipv4_addr { v4: e.octets() } }
}
impl From<Ipv6Addr> for ni_ipv6_addr {
fn from(e: Ipv6Addr) -> ni_ipv6_addr { ni_ipv6_addr { v6: e.octets() } }
}
enum_from_primitive! {
enum ReturnCodes {
Ok = 0,
UnknownError = -1,
UnknownTypeFree = -2,
NullPointerArgument = -3,
ChannelCreationError = -4,
InvalidInoutType = -5,
InvalidTransportType = -6,
}
}
impl ReturnCodes {
fn desc(&self) -> &'static str {
match *self {
ReturnCodes::Ok => "return value does not indicate an error",
ReturnCodes::UnknownError => "unkown error",
ReturnCodes::UnknownTypeFree => "tried to free an unkown type",
ReturnCodes::NullPointerArgument => "invalid argument: null pointer",
ReturnCodes::ChannelCreationError => "could not create pcap channel... does program have permission to read traffic?",
ReturnCodes::InvalidInoutType => "invalid argument: unknown inout type",
ReturnCodes::InvalidTransportType => "invalid argument: unknown transport type",
}
}
}
impl From<ReturnCodes> for ni_error_code {
fn from(e: ReturnCodes) -> ni_error_code { e as ni_error_code }
}
#[derive(Debug)]
enum WrapperError {
NetinfoError(LibError),
InvalidTransportType,
InvalidInoutType,
}
type WrapperResult<T> = Result<T, WrapperError>;
impl From<LibError> for WrapperError {
fn from(e: LibError) -> WrapperError { WrapperError::NetinfoError(e) }
}
impl From<LibError> for ReturnCodes {
fn from(e: LibError) -> ReturnCodes {
use netinfo::error::ErrorKind as E;
match *e.kind() {
E::ChannelCreationError => ReturnCodes::ChannelCreationError,
_ => ReturnCodes::UnknownError }
}
}
impl From<WrapperError> for ReturnCodes {
fn from(e: WrapperError) -> ReturnCodes {
match e {
WrapperError::InvalidInoutType => ReturnCodes::InvalidInoutType,
WrapperError::InvalidTransportType => ReturnCodes::InvalidTransportType,
WrapperError::NetinfoError(netinfo_error) => ReturnCodes::from(netinfo_error),
}
}
}
impl From<WrapperResult<()>> for ReturnCodes {
fn from(e: WrapperResult<()>) -> ReturnCodes {
match e {
Ok(()) => ReturnCodes::Ok,
Err(wrapper_error) => ReturnCodes::from(wrapper_error),
}
}
}
#[no_mangle]
pub unsafe extern fn netinfo_list_net_interface(net_interfaces_array_out: *mut *mut ni_net_interface, num_net_interfaces_out: *mut u32) -> ni_error_code {
check_ptr!(net_interfaces_array_out, num_net_interfaces_out);
safe! {
let net_interfaces: Vec<ni_net_interface> = Netinfo::list_net_interfaces()?
.into_iter()
.map(|i| Box::into_raw(Box::new(i)) as ni_net_interface)
.collect();
write_vec_to_ptr_len32(net_interfaces, net_interfaces_array_out, num_net_interfaces_out);
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_int_get_name(i: ni_net_interface, name_out: *mut *mut u8, name_len_out: *mut u32) -> ni_error_code {
check_ptr!(name_out, name_len_out);
safe! {
temp_box(i, |i: &mut Box<NetworkInterface>| {
let name_chars: Vec<u8> = CString::new(i.as_ref().get_name().clone()).unwrap().into_bytes_with_nul();
write_vec_to_ptr_len32(name_chars, name_out, name_len_out);
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_free_string(s: *mut u8, len: u32) -> ni_error_code {
check_ptr!(s);
safe! {
mem::drop(ptr_len_to_vec::<u8>(s, len as usize));
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_int_get_index(i: ni_net_interface, index_out: *mut u32) -> ni_error_code {
check_ptr!(index_out);
safe! {
temp_box(i, |i: &mut Box<NetworkInterface>| {
*index_out = i.get_index();
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_int_get_mac(i: ni_net_interface, has_mac_out: *mut ni_boolean, mac_out: *mut ni_mac_addr) -> ni_error_code {
check_ptr!(has_mac_out, mac_out);
safe! {
temp_box(i, |i: &mut Box<NetworkInterface>| {
match i.get_mac() {
Some(mac) => {
*has_mac_out = 1;
*mac_out = From::from(mac);
}
None => { *has_mac_out = 0; }
}
Ok(())
})
}
}
unsafe fn write_vec_to_ptr_len32<T>(v: Vec<T>, ptr_out: *mut *mut T, len_out: *mut u32) {
let (ptr, len) = vec_to_ptr_len(v);
*ptr_out = ptr;
*len_out = len as u32;
}
#[no_mangle]
pub unsafe extern fn netinfo_int_get_ips(i: ni_net_interface, ip4_array_out: *mut *mut ni_ipv4_addr, num_ip4_out: *mut u32, ip6_array_out: *mut *mut ni_ipv6_addr, num_ip6_out: *mut u32) -> ni_error_code {
check_ptr!(ip4_array_out, num_ip4_out, ip6_array_out, num_ip6_out);
safe! {
temp_box(i, |i: &mut Box<NetworkInterface>| {
let mut ipv4_vec: Vec<ni_ipv4_addr> = Vec::new();
let mut ipv6_vec: Vec<ni_ipv6_addr> = Vec::new();
for ip in i.get_ips() {
match ip {
IpAddr::V4(ipv4) => { ipv4_vec.push(ipv4.into()); }
IpAddr::V6(ipv6) => { ipv6_vec.push(ipv6.into()); }
}
}
write_vec_to_ptr_len32(ipv4_vec, ip4_array_out, num_ip4_out);
write_vec_to_ptr_len32(ipv6_vec, ip6_array_out, num_ip6_out);
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_free_ip_arrays(ip4_array: *mut ni_ipv4_addr, len_ipv4: u32, ip6_array: *mut ni_ipv6_addr, len_ipv6: u32) -> ni_error_code {
safe! {
ptr_len_to_vec::<ni_ipv4_addr>(ip4_array, len_ipv4 as usize);
ptr_len_to_vec::<ni_ipv6_addr>(ip6_array, len_ipv6 as usize);
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_int_get_flags(i: ni_net_interface, flags_out: *mut u32) -> ni_error_code {
check_ptr!(flags_out);
safe! {
temp_box(i, |i: &mut Box<NetworkInterface>| {
*flags_out = i.get_flags();
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_free_net_interface_array(net_interfaces_array: *mut ni_net_interface, len: u32) -> ni_error_code {
safe! {
let vec1: Vec<ni_net_interface> = ptr_len_to_vec::<ni_net_interface>(net_interfaces_array, len as usize);
let vec2: Vec<Box<NetworkInterface>> = vec1.into_iter().map(|i| Box::from_raw(i as *mut NetworkInterface)).collect();
mem::drop(vec2);
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_init(interfaces: *mut ni_net_interface, num_net_interfaces: u32, n_out: *mut ni_netinfo) -> ni_error_code {
check_ptr!(interfaces, n_out);
safe! {
let real_interfaces: Vec<NetworkInterface> = temp_vec_of_box_cloned(interfaces, num_net_interfaces)?;
let netinfo_object: Netinfo = Netinfo::new(&real_interfaces[..])?;
*n_out = Box::into_raw(Box::new(netinfo_object)) as ni_netinfo;
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_get_net_statistics(n: ni_netinfo, ns: *mut ni_net_statistics) -> ni_error_code {
check_ptr!(n);
safe! {
temp_box(n, |netinfo: &mut Box<Netinfo>| {
let net_stat: NetStatistics = netinfo.get_net_statistics()?;
*ns = Box::into_raw(Box::new(net_stat)) as ni_net_statistics;
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_clear(n: ni_netinfo) -> ni_error_code {
check_ptr!(n);
safe! {
temp_box(n, |netinfo: &mut Box<Netinfo>| {
netinfo.clear()?;
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_start(n: ni_netinfo) -> ni_error_code {
check_ptr!(n);
safe! {
temp_box(n, |netinfo: &mut Box<Netinfo>| {
netinfo.start()?;
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stop(n: ni_netinfo) -> ni_error_code {
check_ptr!(n);
safe! {
temp_box(n, |netinfo: &mut Box<Netinfo>| {
netinfo.stop()?;
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_set_min_refresh_interval(n: ni_netinfo, activate_min_refresh_interval: ni_boolean, milliseconds: u32) -> ni_error_code {
check_ptr!(n);
safe! {
temp_box(n, |netinfo: &mut Box<Netinfo>| {
if activate_min_refresh_interval != 0 {
netinfo.set_min_refresh_interval(Some(Duration::from_millis(milliseconds as u64)))?;
} else {
netinfo.set_min_refresh_interval(None)?;
}
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_pop_thread_errors(n: ni_netinfo, worker_thread_errors: *mut *mut ni_error_code, num_errors: *mut u32) -> ni_error_code {
check_ptr!(n, worker_thread_errors, num_errors);
safe! {
temp_box(n, |netinfo: &mut Box<Netinfo>| {
let netinfo_errors = netinfo.pop_thread_errors()?;
let error_codes: Vec<ni_error_code> = netinfo_errors.into_iter().map(|e: LibError| ni_error_code::from(ReturnCodes::from(e))).collect();
write_vec_to_ptr_len32(error_codes, worker_thread_errors, num_errors);
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_free_thread_error_array(worker_thread_errors: *mut ni_error_code, num_errors: u32) -> ni_error_code {
safe! {
ptr_len_to_vec(worker_thread_errors, num_errors as usize);
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_free(n: ni_netinfo) -> ni_error_code {
check_ptr!(n);
safe! {
mem::drop(Box::from_raw(n as *mut Netinfo));
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stat_get_total_bytes(s: ni_net_statistics, bytes_out: *mut u64) -> ni_error_code {
check_ptr!(s, bytes_out);
safe! {
temp_box(s, |stat: &mut Box<NetStatistics>| {
*bytes_out = stat.get_total();
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stat_get_bytes_per_pid(s: ni_net_statistics, pid: ni_pid, bytes_out: *mut u64) -> ni_error_code {
check_ptr!(s, bytes_out);
safe! {
temp_box(s, |stat: &mut Box<NetStatistics>| {
*bytes_out = stat.get_bytes_by_pid(pid);
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stat_get_unassigned_bytes(s: ni_net_statistics, bytes_out: *mut u64) -> ni_error_code {
check_ptr!(s, bytes_out);
safe! {
temp_box(s, |stat: &mut Box<NetStatistics>| {
*bytes_out = stat.get_unassigned_bytes();
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stat_get_bytes_by_transport_type(s: ni_net_statistics, t: ni_transport_type, bytes_out: *mut u64) -> ni_error_code {
check_ptr!(s, bytes_out);
safe! {
temp_box(s, |stat: &mut Box<NetStatistics>| {
*bytes_out = stat.get_bytes_by_transport_type(ni_transport_type_enum::import(t)?.to_netinfo_type());
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stat_get_bytes_by_inout_type(s: ni_net_statistics, t: ni_inout, bytes_out: *mut u64) -> ni_error_code {
check_ptr!(s, bytes_out);
safe! {
temp_box(s, |stat: &mut Box<NetStatistics>| {
*bytes_out = stat.get_bytes_by_inout_type(ni_inout_enum::import(t)?.to_netinfo_type());
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stat_get_all_pids(s: ni_net_statistics, pid_array_out: *mut *mut ni_pid, num_pids_out: *mut u32) -> ni_error_code {
check_ptr!(s, pid_array_out, num_pids_out);
safe! {
temp_box(s, |stat: &mut Box<NetStatistics>| {
let vec: Vec<ni_pid> = stat.get_all_pids().into_iter().map(|pid| pid as ni_pid).collect();
write_vec_to_ptr_len32(vec, pid_array_out, num_pids_out);
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_free_pid_array(pid_array: *mut ni_pid, len: u32) -> ni_error_code {
safe! {
ptr_len_to_vec(pid_array, len as usize);
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_stat_get_bytes_per_attr(s: ni_net_statistics, pid_opt: *mut ni_pid, inout_opt: *mut ni_inout, tt_opt: *mut ni_transport_type, bytes_out: *mut u64) -> ni_error_code {
check_ptr!(s, bytes_out);
safe! {
temp_box(s, |stat: &mut Box<NetStatistics>| {
let pid_opt2: Option<u64> = if pid_opt == null_mut() { None } else { Some(*pid_opt) };
let inout_opt2: Option<InoutType> = if inout_opt == null_mut() { None } else { Some(ni_inout_enum::import(*inout_opt)?.to_netinfo_type()) };
let tt_opt2: Option<TransportType> = if tt_opt == null_mut() { None } else { Some(ni_transport_type_enum::import(*tt_opt)?.to_netinfo_type()) };
*bytes_out = stat.get_bytes_by_attr(pid_opt2, inout_opt2, tt_opt2);
Ok(())
})
}
}
#[no_mangle]
pub unsafe extern fn netinfo_free_stat(s: ni_net_statistics) -> ni_error_code {
check_ptr!(s);
safe! {
mem::drop(Box::from_raw(s as *mut NetStatistics));
Ok(())
}
}
#[no_mangle]
pub unsafe extern fn netinfo_get_error_description(error_code: ni_error_code) -> *const u8 {
let res = panic::catch_unwind(|| {
ReturnCodes::from_i32(error_code)
.map(|return_code| {
return_code.desc().as_ptr()
}).unwrap_or("unknown error code".as_ptr())
});
match res {
Ok(static_ptr) => static_ptr,
Err(_) => null_mut(),
}
}