network_interface/target/
linux.rs1use std::collections::HashMap;
2use std::net::{Ipv4Addr, Ipv6Addr};
3use std::slice::from_raw_parts;
4
5use libc::{
6 sockaddr_in, sockaddr_in6, strlen, AF_INET, AF_INET6, if_nametoindex, sockaddr_ll, AF_PACKET,
7};
8
9use crate::target::getifaddrs;
10use crate::{Error, NetworkInterface, NetworkInterfaceConfig, Result};
11use crate::utils::{ipv4_from_in_addr, ipv6_from_in6_addr, make_ipv4_netmask, make_ipv6_netmask};
12
13impl NetworkInterfaceConfig for NetworkInterface {
14 fn show() -> Result<Vec<NetworkInterface>> {
15 let mut network_interfaces: HashMap<String, NetworkInterface> = HashMap::new();
16
17 for netifa in getifaddrs()? {
18 let netifa_addr = netifa.ifa_addr;
19 let netifa_family = if netifa_addr.is_null() {
20 continue;
21 } else {
22 unsafe { (*netifa_addr).sa_family as i32 }
23 };
24
25 let mut network_interface = match netifa_family {
26 AF_PACKET => {
27 let name = make_netifa_name(&netifa)?;
28 let mac = make_mac_addrs(&netifa);
29 let index = netifa_index(&netifa);
30 NetworkInterface {
31 name,
32 addr: Vec::new(),
33 mac_addr: Some(mac),
34 index,
35 }
36 }
37 AF_INET => {
38 let socket_addr = netifa_addr as *mut sockaddr_in;
39 let internet_address = unsafe { (*socket_addr).sin_addr };
40 let name = make_netifa_name(&netifa)?;
41 let index = netifa_index(&netifa);
42 let netmask = make_ipv4_netmask(&netifa);
43 let addr = ipv4_from_in_addr(&internet_address)?;
44 let broadcast = make_ipv4_broadcast_addr(&netifa)?;
45 NetworkInterface::new_afinet(name.as_str(), addr, netmask, broadcast, index)
46 }
47 AF_INET6 => {
48 let socket_addr = netifa_addr as *mut sockaddr_in6;
49 let internet_address = unsafe { (*socket_addr).sin6_addr };
50 let name = make_netifa_name(&netifa)?;
51 let index = netifa_index(&netifa);
52 let netmask = make_ipv6_netmask(&netifa);
53 let addr = ipv6_from_in6_addr(&internet_address)?;
54 let broadcast = make_ipv6_broadcast_addr(&netifa)?;
55 NetworkInterface::new_afinet6(name.as_str(), addr, netmask, broadcast, index)
56 }
57 _ => continue,
58 };
59
60 network_interfaces
61 .entry(network_interface.name.clone())
62 .and_modify(|old| old.addr.append(&mut network_interface.addr))
63 .or_insert(network_interface);
64 }
65
66 Ok(network_interfaces.into_values().collect())
67 }
68}
69
70fn make_netifa_name(netifa: &libc::ifaddrs) -> Result<String> {
72 let data = netifa.ifa_name as *const libc::c_char;
73 let len = unsafe { strlen(data) };
74 let bytes_slice = unsafe { from_raw_parts(data as *const u8, len) };
75
76 match String::from_utf8(bytes_slice.to_vec()) {
77 Ok(s) => Ok(s),
78 Err(e) => Err(Error::ParseUtf8Error(e)),
79 }
80}
81
82fn make_ipv4_broadcast_addr(netifa: &libc::ifaddrs) -> Result<Option<Ipv4Addr>> {
89 let ifa_dstaddr = netifa.ifa_ifu;
90
91 if ifa_dstaddr.is_null() {
92 return Ok(None);
93 }
94
95 let socket_addr = ifa_dstaddr as *mut sockaddr_in;
96 let internet_address = unsafe { (*socket_addr).sin_addr };
97 let addr = ipv4_from_in_addr(&internet_address)?;
98
99 Ok(Some(addr))
100}
101
102fn make_ipv6_broadcast_addr(netifa: &libc::ifaddrs) -> Result<Option<Ipv6Addr>> {
109 let ifa_dstaddr = netifa.ifa_ifu;
110
111 if ifa_dstaddr.is_null() {
112 return Ok(None);
113 }
114
115 let socket_addr = ifa_dstaddr as *mut sockaddr_in6;
116 let internet_address = unsafe { (*socket_addr).sin6_addr };
117 let addr = ipv6_from_in6_addr(&internet_address)?;
118
119 Ok(Some(addr))
120}
121
122fn make_mac_addrs(netifa: &libc::ifaddrs) -> String {
123 let netifa_addr = netifa.ifa_addr;
124 let socket_addr = netifa_addr as *mut sockaddr_ll;
125 let mac_array = unsafe { (*socket_addr).sll_addr };
126 let addr_len = unsafe { (*socket_addr).sll_halen };
127 let real_addr_len = std::cmp::min(addr_len as usize, mac_array.len());
128 let mac_slice = unsafe { std::slice::from_raw_parts(mac_array.as_ptr(), real_addr_len) };
129
130 mac_slice
131 .iter()
132 .map(|x| format!("{:02x}", x))
133 .collect::<Vec<_>>()
134 .join(":")
135}
136
137fn netifa_index(netifa: &libc::ifaddrs) -> u32 {
143 let name = netifa.ifa_name as *const libc::c_char;
144
145 unsafe { if_nametoindex(name) }
146}