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
use crate::{pcap_util, Error};
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

#[derive(Clone, Debug)]
pub struct Info {
    pub name: String,
    pub ips: Vec<IpAddr>,
}

impl Info {
    pub fn all() -> Result<Vec<Info>, Error> {
        let mut err_buf = vec![0u8 as std::os::raw::c_char; pcap_sys::PCAP_ERRBUF_SIZE as _];
        let mut device_result: *mut pcap_sys::pcap_if_t = std::ptr::null_mut();

        unsafe {
            let buf = std::mem::transmute::<
                &mut *mut pcap_sys::pcap_if_t,
                *mut *mut pcap_sys::pcap_if_t,
            >(&mut device_result);
            if 0 != pcap_sys::pcap_findalldevs(buf, err_buf.as_mut_ptr()) {
                let err: Vec<_> = err_buf.iter().map(|v| *v as u8).collect();
                let err_str =
                    std::ffi::CStr::from_bytes_with_nul(err.as_ref()).map_err(Error::FfiNul)?;
                let utf_str = err_str.to_str().map_err(Error::Utf8)?;
                return Err(Error::LibPcapError {
                    msg: utf_str.to_owned(),
                });
            }
        }

        let mut result = vec![];

        while device_result != std::ptr::null_mut() {
            let device_name_ptr = unsafe { (*device_result).name };
            let device_name = pcap_util::cstr_to_string(device_name_ptr)?;
            let mut device_addrs = unsafe { (*device_result).addresses };
            let mut addresses = vec![];
            while device_addrs != std::ptr::null_mut() {
                let addr = unsafe { (*device_addrs).addr };
                if addr != std::ptr::null_mut() {
                    let sockaddr = addr as *mut libc::sockaddr;
                    match unsafe { (*sockaddr).sa_family } as i32 {
                        libc::AF_INET => {
                            let ip_addr = unsafe {
                                let sock = sockaddr as *mut libc::sockaddr_in;
                                let sockaddr = (*sock).sin_addr.s_addr;
                                let sockaddr = mem::transmute::<u32, [u8; 4]>(sockaddr);
                                let sockaddr = Ipv4Addr::from(sockaddr);
                                sockaddr
                            };
                            addresses.push(IpAddr::V4(ip_addr));
                        }
                        libc::AF_INET6 => {
                            let ip_addr = unsafe {
                                let sock = sockaddr as *mut libc::sockaddr_in6;
                                let sockaddr = (*sock).sin6_addr.s6_addr;
                                let sockaddr = Ipv6Addr::from(sockaddr);
                                sockaddr
                            };
                            addresses.push(IpAddr::V6(ip_addr));
                        }
                        _ => {
                            //not a type we care about
                        }
                    }
                }
                device_addrs = unsafe { (*device_addrs).next };
            }
            result.push(Info {
                name: device_name,
                ips: addresses,
            });
            device_result = unsafe { (*device_result).next };
        }

        return Ok(result);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_info_all() {
        let infos = Info::all().expect("Failed to list");

        println!("Devices={:?}", infos);

        assert!(infos.is_empty() == false);
    }
}