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