1use std::iter::Iterator;
10use std::net::SocketAddr;
11use std::option::Option;
12
13use crate::raw_socket::interface_iterator::InterfaceIterator;
14
15#[derive(Clone, Copy, PartialEq, Eq)]
16pub struct InterfaceName {
17 bytes: [u8; libc::IFNAMSIZ],
18}
19
20impl std::ops::Deref for InterfaceName {
21 type Target = [u8];
22
23 fn deref(&self) -> &Self::Target {
24 self.bytes.as_slice()
25 }
26}
27
28impl<'de> serde::Deserialize<'de> for InterfaceName {
29 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
30 where
31 D: serde::Deserializer<'de>,
32 {
33 use std::str::FromStr;
34 use InterfaceNameParseError::*;
35
36 let name: String = serde::Deserialize::deserialize(deserializer)?;
37
38 match Self::from_str(&name) {
39 Ok(v) => Ok(v),
40 Err(Empty) => Err(serde::de::Error::custom("interface name empty")),
41 Err(TooLong) => Err(serde::de::Error::custom("interface name too long")),
42 }
43 }
44}
45
46#[derive(Debug)]
47pub enum InterfaceNameParseError {
48 Empty,
49 TooLong,
50}
51
52impl std::str::FromStr for InterfaceName {
53 type Err = InterfaceNameParseError;
54
55 fn from_str(name: &str) -> Result<Self, Self::Err> {
56 if name.is_empty() {
57 return Err(InterfaceNameParseError::Empty);
58 }
59
60 let mut it = name.bytes();
61 let bytes = std::array::from_fn(|_| it.next().unwrap_or_default());
62
63 if it.next().is_some() {
64 Err(InterfaceNameParseError::TooLong)
65 } else {
66 Ok(InterfaceName { bytes })
67 }
68 }
69}
70
71impl InterfaceName {
72 pub const DEFAULT: Option<Self> = None;
73
74 #[cfg(test)]
75 pub const LOOPBACK: Self = Self {
76 bytes: *b"lo\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
77 };
78
79 #[cfg(test)]
80 pub const INVALID: Self = Self {
81 bytes: *b"123412341234123\0",
82 };
83
84 pub fn as_str(&self) -> &str {
85 std::str::from_utf8(self.bytes.as_slice())
86 .unwrap_or_default()
87 .trim_end_matches('\0')
88 }
89
90 pub fn as_cstr(&self) -> &std::ffi::CStr {
91 let first_null = self.bytes.iter().position(|b| *b == 0).unwrap();
96 std::ffi::CStr::from_bytes_with_nul(&self.bytes[..=first_null]).unwrap()
97 }
98
99 pub fn to_ifr_name(self) -> [libc::c_char; libc::IFNAMSIZ] {
100 let mut it = self.bytes.iter().copied();
101 [0; libc::IFNAMSIZ].map(|_| it.next().unwrap_or(0) as libc::c_char)
102 }
103
104 pub fn from_socket_addr(local_addr: SocketAddr) -> std::io::Result<Option<Self>> {
105 let matches_inferface = |interface: &InterfaceData| match interface.socket_addr {
106 None => false,
107 Some(address) => address.ip() == local_addr.ip(),
108 };
109
110 match InterfaceIterator::new()?.find(matches_inferface) {
111 Some(interface) => Ok(Some(interface.name)),
112 None => Ok(None),
113 }
114 }
115}
116
117impl std::fmt::Debug for InterfaceName {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 f.debug_tuple("InterfaceName")
120 .field(&self.as_str())
121 .finish()
122 }
123}
124
125impl std::fmt::Display for InterfaceName {
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 self.as_str().fmt(f)
128 }
129}
130
131pub fn sockaddr_storage_to_socket_addr(
132 sockaddr_storage: &libc::sockaddr_storage,
133) -> Option<SocketAddr> {
134 unsafe { sockaddr_to_socket_addr(sockaddr_storage as *const _ as *const libc::sockaddr) }
138}
139
140pub unsafe fn sockaddr_to_socket_addr(sockaddr: *const libc::sockaddr) -> Option<SocketAddr> {
150 match unsafe { (*sockaddr).sa_family as libc::c_int } {
155 libc::AF_INET => {
156 let inaddr: libc::sockaddr_in =
159 unsafe { std::ptr::read_unaligned(sockaddr as *const libc::sockaddr_in) };
160
161 let socketaddr = std::net::SocketAddrV4::new(
162 std::net::Ipv4Addr::from(inaddr.sin_addr.s_addr.to_ne_bytes()),
163 u16::from_be_bytes(inaddr.sin_port.to_ne_bytes()),
164 );
165
166 Some(std::net::SocketAddr::V4(socketaddr))
167 }
168 libc::AF_INET6 => {
169 let inaddr: libc::sockaddr_in6 =
172 unsafe { std::ptr::read_unaligned(sockaddr as *const libc::sockaddr_in6) };
173
174 let sin_addr = inaddr.sin6_addr.s6_addr;
175 let segment_bytes: [u8; 16] =
176 unsafe { std::ptr::read_unaligned(&sin_addr as *const _ as *const _) };
177
178 let socketaddr = std::net::SocketAddrV6::new(
179 std::net::Ipv6Addr::from(segment_bytes),
180 u16::from_be_bytes(inaddr.sin6_port.to_ne_bytes()),
181 inaddr.sin6_flowinfo, inaddr.sin6_scope_id,
183 );
184
185 Some(std::net::SocketAddr::V6(socketaddr))
186 }
187 _ => None,
188 }
189}
190
191pub struct InterfaceData {
192 pub name: InterfaceName,
193 pub mac: Option<[u8; 6]>,
194 pub socket_addr: Option<SocketAddr>,
195}
196
197#[cfg(test)]
198mod tests {
199 use std::net::{IpAddr, Ipv4Addr, SocketAddr};
200
201 use super::*;
202
203 #[test]
204 fn find_interface() {
205 let socket = std::net::UdpSocket::bind("127.0.0.1:8014").unwrap();
206 let name = InterfaceName::from_socket_addr(socket.local_addr().unwrap()).unwrap();
207
208 assert!(name.is_some());
209 }
210
211 #[test]
212 fn find_interface_ipv6() {
213 let socket = std::net::UdpSocket::bind("::1:8015").unwrap();
214 let name = InterfaceName::from_socket_addr(socket.local_addr().unwrap()).unwrap();
215
216 assert!(name.is_some());
217 }
218
219 #[test]
220 fn decode_socket_addr_v4() {
221 let sockaddr = libc::sockaddr {
222 sa_family: libc::AF_INET as libc::sa_family_t,
223 sa_data: [0, 0, 127, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
224 #[cfg(any(target_os = "macos", target_os = "freebsd"))]
225 sa_len: 14u8,
226 };
227
228 let socket_addr = unsafe { sockaddr_to_socket_addr(&sockaddr) }.unwrap();
229
230 assert_eq!(
231 socket_addr,
232 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0)
233 );
234
235 let sockaddr = libc::sockaddr {
238 sa_family: libc::AF_INET as libc::sa_family_t,
239 sa_data: [0, 42, -84 as _, 23, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
240 #[cfg(any(target_os = "macos", target_os = "freebsd"))]
241 sa_len: 14u8,
242 };
243
244 let socket_addr = unsafe { sockaddr_to_socket_addr(&sockaddr) }.unwrap();
245
246 assert_eq!(
247 socket_addr,
248 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 23, 0, 1)), 42)
249 );
250 }
251
252 #[test]
253 fn decode_socket_addr_v6() {
254 let raw = [
255 0x20, 0x01, 0x08, 0x88, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x02,
257 ];
258
259 let sockaddr = libc::sockaddr_in6 {
260 sin6_family: libc::AF_INET6 as libc::sa_family_t,
261 sin6_port: u16::from_ne_bytes([0, 32]),
262 sin6_flowinfo: 0,
263 sin6_addr: libc::in6_addr { s6_addr: raw },
264 sin6_scope_id: 0,
265 #[cfg(any(target_os = "macos", target_os = "freebsd"))]
266 sin6_len: 14u8,
267 };
268
269 let socket_addr =
270 unsafe { sockaddr_to_socket_addr(&sockaddr as *const _ as *const _) }.unwrap();
271
272 assert_eq!(socket_addr, "[2001:888:0:2::2]:32".parse().unwrap());
273 }
274}