1use super::Interface;
2use super::MacAddr;
3use crate::gateway;
4use crate::interface::InterfaceType;
5use crate::ip::{Ipv4Net, Ipv6Net};
6use crate::sys;
7use libc;
8use std::ffi::{CStr, CString};
9use std::mem::{self, MaybeUninit};
10use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
11use std::os::raw::c_char;
12use std::str::from_utf8_unchecked;
13
14#[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd"))]
15pub fn interfaces() -> Vec<Interface> {
16 let mut interfaces: Vec<Interface> = unix_interfaces();
17 let local_ip: IpAddr = match super::get_local_ipaddr() {
18 Some(local_ip) => local_ip,
19 None => return interfaces,
20 };
21 for iface in &mut interfaces {
22 match local_ip {
23 IpAddr::V4(local_ipv4) => {
24 if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
25 match gateway::unix::get_default_gateway(iface.name.clone()) {
26 Ok(gateway) => {
27 iface.gateway = Some(gateway);
28 }
29 Err(_) => {}
30 }
31 }
32 }
33 IpAddr::V6(local_ipv6) => {
34 if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
35 match gateway::unix::get_default_gateway(iface.name.clone()) {
36 Ok(gateway) => {
37 iface.gateway = Some(gateway);
38 }
39 Err(_) => {}
40 }
41 }
42 }
43 }
44 }
45 interfaces
46}
47
48#[cfg(any(target_os = "macos", target_os = "ios"))]
49pub fn interfaces() -> Vec<Interface> {
50 use super::macos;
51
52 let type_map = macos::get_if_type_map();
53 let mut interfaces: Vec<Interface> = unix_interfaces();
54 let local_ip: IpAddr = match super::get_local_ipaddr() {
55 Some(local_ip) => local_ip,
56 None => return interfaces,
57 };
58 for iface in &mut interfaces {
59 iface.if_type = *type_map.get(&iface.name).unwrap_or(&InterfaceType::Unknown);
60 match local_ip {
61 IpAddr::V4(local_ipv4) => {
62 if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
63 match gateway::macos::get_default_gateway(iface.name.clone()) {
64 Ok(gateway) => {
65 iface.gateway = Some(gateway);
66 }
67 Err(_) => {}
68 }
69 }
70 }
71 IpAddr::V6(local_ipv6) => {
72 if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
73 match gateway::macos::get_default_gateway(iface.name.clone()) {
74 Ok(gateway) => {
75 iface.gateway = Some(gateway);
76 }
77 Err(_) => {}
78 }
79 }
80 }
81 }
82 }
83 interfaces
84}
85
86#[cfg(any(target_os = "linux", target_os = "android"))]
87pub fn interfaces() -> Vec<Interface> {
88 use super::linux;
89
90 let mut interfaces: Vec<Interface> = unix_interfaces();
91 let local_ip: IpAddr = match super::get_local_ipaddr() {
92 Some(local_ip) => local_ip,
93 None => return interfaces,
94 };
95 for iface in &mut interfaces {
96 iface.if_type = linux::get_interface_type(iface.name.clone());
97 let if_speed: Option<u64> = linux::get_interface_speed(iface.name.clone());
98 iface.transmit_speed = if_speed;
99 iface.receive_speed = if_speed;
100 match local_ip {
101 IpAddr::V4(local_ipv4) => {
102 if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
103 match gateway::linux::get_default_gateway(iface.name.clone()) {
104 Ok(gateway) => {
105 iface.gateway = Some(gateway);
106 }
107 Err(_) => {}
108 }
109 }
110 }
111 IpAddr::V6(local_ipv6) => {
112 if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
113 match gateway::linux::get_default_gateway(iface.name.clone()) {
114 Ok(gateway) => {
115 iface.gateway = Some(gateway);
116 }
117 Err(_) => {}
118 }
119 }
120 }
121 }
122 }
123 interfaces
124}
125
126#[cfg(any(target_os = "linux", target_os = "android"))]
127pub(super) fn sockaddr_to_network_addr(
128 sa: *mut libc::sockaddr,
129) -> (Option<MacAddr>, Option<IpAddr>) {
130 use std::net::SocketAddr;
131
132 unsafe {
133 if sa.is_null() {
134 (None, None)
135 } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
136 let sll: *const libc::sockaddr_ll = mem::transmute(sa);
137 let mac = MacAddr(
138 (*sll).sll_addr[0],
139 (*sll).sll_addr[1],
140 (*sll).sll_addr[2],
141 (*sll).sll_addr[3],
142 (*sll).sll_addr[4],
143 (*sll).sll_addr[5],
144 );
145
146 (Some(mac), None)
147 } else {
148 let addr =
149 sys::sockaddr_to_addr(mem::transmute(sa), mem::size_of::<libc::sockaddr_storage>());
150
151 match addr {
152 Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
153 Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
154 Err(_) => (None, None),
155 }
156 }
157 }
158}
159
160#[cfg(any(
161 target_os = "openbsd",
162 target_os = "freebsd",
163 target_os = "netbsd",
164 target_os = "macos",
165 target_os = "ios"
166))]
167fn sockaddr_to_network_addr(sa: *mut libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
168 use std::net::SocketAddr;
169
170 unsafe {
171 if sa.is_null() {
172 (None, None)
173 } else if (*sa).sa_family as libc::c_int == libc::AF_LINK {
174 let nlen: i8 = (*sa).sa_data[3];
175 let alen: i8 = (*sa).sa_data[4];
176 if alen > 0 && alen as u8 + nlen as u8 + 8 <= (*sa).sa_len {
177 let ptr = (*sa).sa_data.as_mut_ptr();
178 let extended =
179 std::slice::from_raw_parts_mut(ptr, 6 + nlen as usize + alen as usize);
180
181 let mac = MacAddr(
182 extended[6 + nlen as usize] as u8,
183 extended[6 + nlen as usize + 1] as u8,
184 extended[6 + nlen as usize + 2] as u8,
185 extended[6 + nlen as usize + 3] as u8,
186 extended[6 + nlen as usize + 4] as u8,
187 extended[6 + nlen as usize + 5] as u8,
188 );
189 return (Some(mac), None);
190 }
191 (None, None)
192 } else {
193 let addr =
194 sys::sockaddr_to_addr(mem::transmute(sa), mem::size_of::<libc::sockaddr_storage>());
195
196 match addr {
197 Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
198 Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
199 Err(_) => (None, None),
200 }
201 }
202 }
203}
204
205#[cfg(target_os = "android")]
206pub fn unix_interfaces() -> Vec<Interface> {
207 use super::android;
208
209 if let Some((getifaddrs, freeifaddrs)) = android::get_libc_ifaddrs() {
210 return unix_interfaces_inner(getifaddrs, freeifaddrs);
211 }
212
213 android::netlink::unix_interfaces()
214}
215
216#[cfg(not(target_os = "android"))]
217pub fn unix_interfaces() -> Vec<Interface> {
218 unix_interfaces_inner(libc::getifaddrs, libc::freeifaddrs)
219}
220
221fn unix_interfaces_inner(
222 getifaddrs: unsafe extern "C" fn(*mut *mut libc::ifaddrs) -> libc::c_int,
223 freeifaddrs: unsafe extern "C" fn(*mut libc::ifaddrs),
224) -> Vec<Interface> {
225 let mut ifaces: Vec<Interface> = vec![];
226 let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit();
227 if unsafe { getifaddrs(addrs.as_mut_ptr()) } != 0 {
228 return ifaces;
229 }
230 let addrs = unsafe { addrs.assume_init() };
231 let mut addr = addrs;
232 while !addr.is_null() {
233 let addr_ref: &libc::ifaddrs = unsafe { &*addr };
234 let c_str = addr_ref.ifa_name as *const c_char;
235 let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() };
236 let name = unsafe { from_utf8_unchecked(bytes).to_owned() };
237 let (mac, ip) = sockaddr_to_network_addr(addr_ref.ifa_addr as *mut libc::sockaddr);
238 let (_, netmask) = sockaddr_to_network_addr(addr_ref.ifa_netmask as *mut libc::sockaddr);
239 let mut ini_ipv4: Vec<Ipv4Net> = vec![];
240 let mut ini_ipv6: Vec<Ipv6Net> = vec![];
241 if let Some(ip) = ip {
242 match ip {
243 IpAddr::V4(ipv4) => {
244 let netmask: Ipv4Addr = match netmask {
245 Some(netmask) => match netmask {
246 IpAddr::V4(netmask) => netmask,
247 IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
248 },
249 None => Ipv4Addr::UNSPECIFIED,
250 };
251 let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
252 ini_ipv4.push(ipv4_net);
253 }
254 IpAddr::V6(ipv6) => {
255 let netmask: Ipv6Addr = match netmask {
256 Some(netmask) => match netmask {
257 IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
258 IpAddr::V6(netmask) => netmask,
259 },
260 None => Ipv6Addr::UNSPECIFIED,
261 };
262 let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
263 ini_ipv6.push(ipv6_net);
264 }
265 }
266 }
267 let interface: Interface = Interface {
268 index: 0,
269 name: name.clone(),
270 friendly_name: None,
271 description: None,
272 if_type: InterfaceType::Unknown,
273 mac_addr: mac.clone(),
274 ipv4: ini_ipv4,
275 ipv6: ini_ipv6,
276 flags: addr_ref.ifa_flags,
277 transmit_speed: None,
278 receive_speed: None,
279 gateway: None,
280 };
281 let mut found: bool = false;
282 for iface in &mut ifaces {
283 if name == iface.name {
284 if let Some(mac) = mac.clone() {
285 iface.mac_addr = Some(mac);
286 }
287 if let Some(ip) = ip {
288 match ip {
289 IpAddr::V4(ipv4) => {
290 let netmask: Ipv4Addr = match netmask {
291 Some(netmask) => match netmask {
292 IpAddr::V4(netmask) => netmask,
293 IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
294 },
295 None => Ipv4Addr::UNSPECIFIED,
296 };
297 let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
298 iface.ipv4.push(ipv4_net);
299 }
300 IpAddr::V6(ipv6) => {
301 let netmask: Ipv6Addr = match netmask {
302 Some(netmask) => match netmask {
303 IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
304 IpAddr::V6(netmask) => netmask,
305 },
306 None => Ipv6Addr::UNSPECIFIED,
307 };
308 let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
309 iface.ipv6.push(ipv6_net);
310 }
311 }
312 }
313 found = true;
314 }
315 }
316 if !found {
317 ifaces.push(interface);
318 }
319 addr = addr_ref.ifa_next;
320 }
321 unsafe {
322 freeifaddrs(addrs);
323 }
324 for iface in &mut ifaces {
325 let name = CString::new(iface.name.as_bytes()).unwrap();
326 unsafe {
327 iface.index = libc::if_nametoindex(name.as_ptr());
328 }
329 }
330 ifaces
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336 #[test]
337 fn test_unix_interfaces() {
338 let interfaces = interfaces();
339 for interface in interfaces {
340 println!("{:#?}", interface);
341 }
342 }
343}