1 | #[cfg (any( |
2 | bsd, |
3 | linux_android, |
4 | solarish, |
5 | target_os = "haiku" , |
6 | target_os = "fuchsia" , |
7 | target_os = "aix" , |
8 | ))] |
9 | #[cfg (feature = "net" )] |
10 | pub use self::datalink::LinkAddr; |
11 | #[cfg (any(linux_android, apple_targets))] |
12 | pub use self::vsock::VsockAddr; |
13 | use super::sa_family_t; |
14 | use crate::errno::Errno; |
15 | #[cfg (linux_android)] |
16 | use crate::sys::socket::addr::alg::AlgAddr; |
17 | #[cfg (linux_android)] |
18 | use crate::sys::socket::addr::netlink::NetlinkAddr; |
19 | #[cfg (all(feature = "ioctl" , apple_targets))] |
20 | use crate::sys::socket::addr::sys_control::SysControlAddr; |
21 | use crate::{NixPath, Result}; |
22 | use cfg_if::cfg_if; |
23 | use memoffset::offset_of; |
24 | use std::convert::TryInto; |
25 | use std::ffi::OsStr; |
26 | use std::hash::{Hash, Hasher}; |
27 | use std::net::{Ipv4Addr, Ipv6Addr}; |
28 | use std::os::unix::ffi::OsStrExt; |
29 | use std::path::Path; |
30 | use std::{fmt, mem, net, ptr, slice}; |
31 | |
32 | /// Convert a std::net::Ipv4Addr into the libc form. |
33 | #[cfg (feature = "net" )] |
34 | pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { |
35 | libc::in_addr { |
36 | s_addr: u32::from_ne_bytes(addr.octets()), |
37 | } |
38 | } |
39 | |
40 | /// Convert a std::net::Ipv6Addr into the libc form. |
41 | #[cfg (feature = "net" )] |
42 | pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { |
43 | libc::in6_addr { |
44 | s6_addr: addr.octets(), |
45 | } |
46 | } |
47 | |
48 | /// These constants specify the protocol family to be used |
49 | /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) |
50 | /// |
51 | /// # References |
52 | /// |
53 | /// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) |
54 | // Should this be u8? |
55 | #[repr (i32)] |
56 | #[non_exhaustive ] |
57 | #[derive (Copy, Clone, PartialEq, Eq, Debug, Hash)] |
58 | pub enum AddressFamily { |
59 | /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html)) |
60 | Unix = libc::AF_UNIX, |
61 | /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html)) |
62 | Inet = libc::AF_INET, |
63 | /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html)) |
64 | Inet6 = libc::AF_INET6, |
65 | /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) |
66 | #[cfg (linux_android)] |
67 | Netlink = libc::AF_NETLINK, |
68 | /// Kernel interface for interacting with the routing table |
69 | #[cfg (not(any(linux_android, target_os = "redox" )))] |
70 | Route = libc::PF_ROUTE, |
71 | /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) |
72 | #[cfg (any(linux_android, solarish, target_os = "fuchsia" ))] |
73 | Packet = libc::AF_PACKET, |
74 | /// KEXT Controls and Notifications |
75 | #[cfg (apple_targets)] |
76 | System = libc::AF_SYSTEM, |
77 | /// Amateur radio AX.25 protocol |
78 | #[cfg (linux_android)] |
79 | Ax25 = libc::AF_AX25, |
80 | /// IPX - Novell protocols |
81 | #[cfg (not(any(target_os = "aix" , target_os = "redox" )))] |
82 | Ipx = libc::AF_IPX, |
83 | /// AppleTalk |
84 | #[cfg (not(target_os = "redox" ))] |
85 | AppleTalk = libc::AF_APPLETALK, |
86 | /// AX.25 packet layer protocol. |
87 | /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) |
88 | #[cfg (linux_android)] |
89 | NetRom = libc::AF_NETROM, |
90 | /// Can't be used for creating sockets; mostly used for bridge |
91 | /// links in |
92 | /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) |
93 | /// protocol commands. |
94 | #[cfg (linux_android)] |
95 | Bridge = libc::AF_BRIDGE, |
96 | /// Access to raw ATM PVCs |
97 | #[cfg (linux_android)] |
98 | AtmPvc = libc::AF_ATMPVC, |
99 | /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) |
100 | #[cfg (linux_android)] |
101 | X25 = libc::AF_X25, |
102 | /// RATS (Radio Amateur Telecommunications Society) Open |
103 | /// Systems environment (ROSE) AX.25 packet layer protocol. |
104 | /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) |
105 | #[cfg (linux_android)] |
106 | Rose = libc::AF_ROSE, |
107 | /// DECet protocol sockets. |
108 | #[cfg (not(any(target_os = "haiku" , target_os = "redox" )))] |
109 | Decnet = libc::AF_DECnet, |
110 | /// Reserved for "802.2LLC project"; never used. |
111 | #[cfg (linux_android)] |
112 | NetBeui = libc::AF_NETBEUI, |
113 | /// This was a short-lived (between Linux 2.1.30 and |
114 | /// 2.1.99pre2) protocol family for firewall upcalls. |
115 | #[cfg (linux_android)] |
116 | Security = libc::AF_SECURITY, |
117 | /// Key management protocol. |
118 | #[cfg (linux_android)] |
119 | Key = libc::AF_KEY, |
120 | #[allow (missing_docs)] // Not documented anywhere that I can find |
121 | #[cfg (linux_android)] |
122 | Ash = libc::AF_ASH, |
123 | /// Acorn Econet protocol |
124 | #[cfg (linux_android)] |
125 | Econet = libc::AF_ECONET, |
126 | /// Access to ATM Switched Virtual Circuits |
127 | #[cfg (linux_android)] |
128 | AtmSvc = libc::AF_ATMSVC, |
129 | /// Reliable Datagram Sockets (RDS) protocol |
130 | #[cfg (linux_android)] |
131 | Rds = libc::AF_RDS, |
132 | /// IBM SNA |
133 | #[cfg (not(any(target_os = "haiku" , target_os = "redox" )))] |
134 | Sna = libc::AF_SNA, |
135 | /// Socket interface over IrDA |
136 | #[cfg (linux_android)] |
137 | Irda = libc::AF_IRDA, |
138 | /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) |
139 | #[cfg (linux_android)] |
140 | Pppox = libc::AF_PPPOX, |
141 | /// Legacy protocol for wide area network (WAN) connectivity that was used |
142 | /// by Sangoma WAN cards |
143 | #[cfg (linux_android)] |
144 | Wanpipe = libc::AF_WANPIPE, |
145 | /// Logical link control (IEEE 802.2 LLC) protocol |
146 | #[cfg (linux_android)] |
147 | Llc = libc::AF_LLC, |
148 | /// InfiniBand native addressing |
149 | #[cfg (all(target_os = "linux" , not(target_env = "uclibc" )))] |
150 | Ib = libc::AF_IB, |
151 | /// Multiprotocol Label Switching |
152 | #[cfg (all(target_os = "linux" , not(target_env = "uclibc" )))] |
153 | Mpls = libc::AF_MPLS, |
154 | /// Controller Area Network automotive bus protocol |
155 | #[cfg (linux_android)] |
156 | Can = libc::AF_CAN, |
157 | /// TIPC, "cluster domain sockets" protocol |
158 | #[cfg (linux_android)] |
159 | Tipc = libc::AF_TIPC, |
160 | /// Bluetooth low-level socket protocol |
161 | #[cfg (not(any( |
162 | target_os = "aix" , |
163 | solarish, |
164 | apple_targets, |
165 | target_os = "hurd" , |
166 | target_os = "redox" , |
167 | )))] |
168 | Bluetooth = libc::AF_BLUETOOTH, |
169 | /// IUCV (inter-user communication vehicle) z/VM protocol for |
170 | /// hypervisor-guest interaction |
171 | #[cfg (linux_android)] |
172 | Iucv = libc::AF_IUCV, |
173 | /// Rx, Andrew File System remote procedure call protocol |
174 | #[cfg (linux_android)] |
175 | RxRpc = libc::AF_RXRPC, |
176 | /// New "modular ISDN" driver interface protocol |
177 | #[cfg (not(any( |
178 | target_os = "aix" , |
179 | solarish, |
180 | target_os = "haiku" , |
181 | target_os = "hurd" , |
182 | target_os = "redox" , |
183 | )))] |
184 | Isdn = libc::AF_ISDN, |
185 | /// Nokia cellular modem IPC/RPC interface |
186 | #[cfg (linux_android)] |
187 | Phonet = libc::AF_PHONET, |
188 | /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol |
189 | #[cfg (linux_android)] |
190 | Ieee802154 = libc::AF_IEEE802154, |
191 | /// Ericsson's Communication CPU to Application CPU interface (CAIF) |
192 | /// protocol. |
193 | #[cfg (linux_android)] |
194 | Caif = libc::AF_CAIF, |
195 | /// Interface to kernel crypto API |
196 | #[cfg (linux_android)] |
197 | Alg = libc::AF_ALG, |
198 | /// Near field communication |
199 | #[cfg (target_os = "linux" )] |
200 | Nfc = libc::AF_NFC, |
201 | /// VMWare VSockets protocol for hypervisor-guest interaction. |
202 | #[cfg (any(linux_android, apple_targets))] |
203 | Vsock = libc::AF_VSOCK, |
204 | /// ARPANet IMP addresses |
205 | #[cfg (bsd)] |
206 | ImpLink = libc::AF_IMPLINK, |
207 | /// PUP protocols, e.g. BSP |
208 | #[cfg (bsd)] |
209 | Pup = libc::AF_PUP, |
210 | /// MIT CHAOS protocols |
211 | #[cfg (bsd)] |
212 | Chaos = libc::AF_CHAOS, |
213 | /// Novell and Xerox protocol |
214 | #[cfg (any(apple_targets, netbsdlike))] |
215 | Ns = libc::AF_NS, |
216 | #[allow (missing_docs)] // Not documented anywhere that I can find |
217 | #[cfg (bsd)] |
218 | Iso = libc::AF_ISO, |
219 | /// Bell Labs virtual circuit switch ? |
220 | #[cfg (bsd)] |
221 | Datakit = libc::AF_DATAKIT, |
222 | /// CCITT protocols, X.25 etc |
223 | #[cfg (bsd)] |
224 | Ccitt = libc::AF_CCITT, |
225 | /// DEC Direct data link interface |
226 | #[cfg (bsd)] |
227 | Dli = libc::AF_DLI, |
228 | #[allow (missing_docs)] // Not documented anywhere that I can find |
229 | #[cfg (bsd)] |
230 | Lat = libc::AF_LAT, |
231 | /// NSC Hyperchannel |
232 | #[cfg (bsd)] |
233 | Hylink = libc::AF_HYLINK, |
234 | /// Link layer interface |
235 | #[cfg (any(bsd, solarish))] |
236 | Link = libc::AF_LINK, |
237 | /// connection-oriented IP, aka ST II |
238 | #[cfg (bsd)] |
239 | Coip = libc::AF_COIP, |
240 | /// Computer Network Technology |
241 | #[cfg (bsd)] |
242 | Cnt = libc::AF_CNT, |
243 | /// Native ATM access |
244 | #[cfg (bsd)] |
245 | Natm = libc::AF_NATM, |
246 | /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) |
247 | #[cfg (linux_android)] |
248 | Unspec = libc::AF_UNSPEC, |
249 | } |
250 | |
251 | impl AddressFamily { |
252 | /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from |
253 | /// the `sa_family` field of a `sockaddr`. |
254 | /// |
255 | /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet |
256 | /// and System. Returns None for unsupported or unknown address families. |
257 | pub const fn from_i32(family: i32) -> Option<AddressFamily> { |
258 | match family { |
259 | libc::AF_UNIX => Some(AddressFamily::Unix), |
260 | libc::AF_INET => Some(AddressFamily::Inet), |
261 | libc::AF_INET6 => Some(AddressFamily::Inet6), |
262 | #[cfg (linux_android)] |
263 | libc::AF_NETLINK => Some(AddressFamily::Netlink), |
264 | #[cfg (apple_targets)] |
265 | libc::AF_SYSTEM => Some(AddressFamily::System), |
266 | #[cfg (not(any(linux_android, target_os = "redox" )))] |
267 | libc::PF_ROUTE => Some(AddressFamily::Route), |
268 | #[cfg (linux_android)] |
269 | libc::AF_PACKET => Some(AddressFamily::Packet), |
270 | #[cfg (any(bsd, solarish))] |
271 | libc::AF_LINK => Some(AddressFamily::Link), |
272 | #[cfg (any(linux_android, apple_targets))] |
273 | libc::AF_VSOCK => Some(AddressFamily::Vsock), |
274 | _ => None, |
275 | } |
276 | } |
277 | } |
278 | |
279 | /// A wrapper around `sockaddr_un`. |
280 | #[derive (Clone, Copy, Debug)] |
281 | #[repr (C)] |
282 | pub struct UnixAddr { |
283 | // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts |
284 | sun: libc::sockaddr_un, |
285 | /// The length of the valid part of `sun`, including the sun_family field |
286 | /// but excluding any trailing nul. |
287 | // On the BSDs, this field is built into sun |
288 | #[cfg (not(any(bsd, target_os = "haiku" , target_os = "hurd" )))] |
289 | sun_len: u8, |
290 | } |
291 | |
292 | // linux man page unix(7) says there are 3 kinds of unix socket: |
293 | // pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 |
294 | // unnamed: addrlen = sizeof(sa_family_t) |
295 | // abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))] |
296 | // |
297 | // what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path) |
298 | #[derive (PartialEq, Eq, Hash)] |
299 | enum UnixAddrKind<'a> { |
300 | Pathname(&'a Path), |
301 | Unnamed, |
302 | #[cfg (linux_android)] |
303 | Abstract(&'a [u8]), |
304 | } |
305 | impl<'a> UnixAddrKind<'a> { |
306 | /// Safety: sun & sun_len must be valid |
307 | #[allow (clippy::unnecessary_cast)] // Not unnecessary on all platforms |
308 | unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { |
309 | assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); |
310 | let path_len = |
311 | sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); |
312 | if path_len == 0 { |
313 | return Self::Unnamed; |
314 | } |
315 | #[cfg (linux_android)] |
316 | if sun.sun_path[0] == 0 { |
317 | let name = unsafe { |
318 | slice::from_raw_parts( |
319 | sun.sun_path.as_ptr().add(1).cast(), |
320 | path_len - 1, |
321 | ) |
322 | }; |
323 | return Self::Abstract(name); |
324 | } |
325 | let pathname = unsafe { |
326 | slice::from_raw_parts(sun.sun_path.as_ptr().cast(), path_len) |
327 | }; |
328 | if pathname.last() == Some(&0) { |
329 | // A trailing NUL is not considered part of the path, and it does |
330 | // not need to be included in the addrlen passed to functions like |
331 | // bind(). However, Linux adds a trailing NUL, even if one was not |
332 | // originally present, when returning addrs from functions like |
333 | // getsockname() (the BSDs do not do that). So we need to filter |
334 | // out any trailing NUL here, so sockaddrs can round-trip through |
335 | // the kernel and still compare equal. |
336 | Self::Pathname(Path::new(OsStr::from_bytes( |
337 | &pathname[0..pathname.len() - 1], |
338 | ))) |
339 | } else { |
340 | Self::Pathname(Path::new(OsStr::from_bytes(pathname))) |
341 | } |
342 | } |
343 | } |
344 | |
345 | impl UnixAddr { |
346 | /// Create a new sockaddr_un representing a filesystem path. |
347 | #[allow (clippy::unnecessary_cast)] // Not unnecessary on all platforms |
348 | pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> { |
349 | path.with_nix_path(|cstr| unsafe { |
350 | let mut ret = libc::sockaddr_un { |
351 | sun_family: AddressFamily::Unix as sa_family_t, |
352 | ..mem::zeroed() |
353 | }; |
354 | |
355 | let bytes = cstr.to_bytes(); |
356 | |
357 | if bytes.len() >= ret.sun_path.len() { |
358 | return Err(Errno::ENAMETOOLONG); |
359 | } |
360 | |
361 | let sun_len = (bytes.len() |
362 | + offset_of!(libc::sockaddr_un, sun_path)) |
363 | .try_into() |
364 | .unwrap(); |
365 | |
366 | #[cfg (any(bsd, target_os = "haiku" , target_os = "hurd" ))] |
367 | { |
368 | ret.sun_len = sun_len; |
369 | } |
370 | ptr::copy_nonoverlapping( |
371 | bytes.as_ptr(), |
372 | ret.sun_path.as_mut_ptr().cast(), |
373 | bytes.len(), |
374 | ); |
375 | |
376 | Ok(UnixAddr::from_raw_parts(ret, sun_len)) |
377 | })? |
378 | } |
379 | |
380 | /// Create a new `sockaddr_un` representing an address in the "abstract namespace". |
381 | /// |
382 | /// The leading nul byte for the abstract namespace is automatically added; |
383 | /// thus the input `path` is expected to be the bare name, not NUL-prefixed. |
384 | /// This is a Linux-specific extension, primarily used to allow chrooted |
385 | /// processes to communicate with processes having a different filesystem view. |
386 | #[cfg (linux_android)] |
387 | #[allow (clippy::unnecessary_cast)] // Not unnecessary on all platforms |
388 | pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> { |
389 | unsafe { |
390 | let mut ret = libc::sockaddr_un { |
391 | sun_family: AddressFamily::Unix as sa_family_t, |
392 | ..mem::zeroed() |
393 | }; |
394 | |
395 | if path.len() >= ret.sun_path.len() { |
396 | return Err(Errno::ENAMETOOLONG); |
397 | } |
398 | let sun_len = |
399 | (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path)) |
400 | .try_into() |
401 | .unwrap(); |
402 | |
403 | // Abstract addresses are represented by sun_path[0] == |
404 | // b'\0', so copy starting one byte in. |
405 | ptr::copy_nonoverlapping( |
406 | path.as_ptr(), |
407 | ret.sun_path.as_mut_ptr().offset(1).cast(), |
408 | path.len(), |
409 | ); |
410 | |
411 | Ok(UnixAddr::from_raw_parts(ret, sun_len)) |
412 | } |
413 | } |
414 | |
415 | /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. |
416 | #[cfg (linux_android)] |
417 | pub fn new_unnamed() -> UnixAddr { |
418 | let ret = libc::sockaddr_un { |
419 | sun_family: AddressFamily::Unix as sa_family_t, |
420 | ..unsafe { mem::zeroed() } |
421 | }; |
422 | |
423 | let sun_len: u8 = |
424 | offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); |
425 | |
426 | unsafe { UnixAddr::from_raw_parts(ret, sun_len) } |
427 | } |
428 | |
429 | /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` |
430 | /// is the size of the valid portion of the struct, excluding any trailing |
431 | /// NUL. |
432 | /// |
433 | /// # Safety |
434 | /// This pair of sockaddr_un & sun_len must be a valid unix addr, which |
435 | /// means: |
436 | /// - sun_len >= offset_of(sockaddr_un, sun_path) |
437 | /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) |
438 | /// - if this is a unix addr with a pathname, sun.sun_path is a |
439 | /// fs path, not necessarily nul-terminated. |
440 | pub(crate) unsafe fn from_raw_parts( |
441 | sun: libc::sockaddr_un, |
442 | sun_len: u8, |
443 | ) -> UnixAddr { |
444 | cfg_if! { |
445 | if #[cfg(any(linux_android, |
446 | target_os = "fuchsia" , |
447 | solarish, |
448 | target_os = "redox" , |
449 | ))] |
450 | { |
451 | UnixAddr { sun, sun_len } |
452 | } else { |
453 | assert_eq!(sun_len, sun.sun_len); |
454 | UnixAddr {sun} |
455 | } |
456 | } |
457 | } |
458 | |
459 | fn kind(&self) -> UnixAddrKind<'_> { |
460 | // SAFETY: our sockaddr is always valid because of the invariant on the struct |
461 | unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) } |
462 | } |
463 | |
464 | /// If this address represents a filesystem path, return that path. |
465 | pub fn path(&self) -> Option<&Path> { |
466 | match self.kind() { |
467 | UnixAddrKind::Pathname(path) => Some(path), |
468 | _ => None, |
469 | } |
470 | } |
471 | |
472 | /// If this address represents an abstract socket, return its name. |
473 | /// |
474 | /// For abstract sockets only the bare name is returned, without the |
475 | /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. |
476 | #[cfg (linux_android)] |
477 | pub fn as_abstract(&self) -> Option<&[u8]> { |
478 | match self.kind() { |
479 | UnixAddrKind::Abstract(name) => Some(name), |
480 | _ => None, |
481 | } |
482 | } |
483 | |
484 | /// Check if this address is an "unnamed" unix socket address. |
485 | #[cfg (linux_android)] |
486 | #[inline ] |
487 | pub fn is_unnamed(&self) -> bool { |
488 | matches!(self.kind(), UnixAddrKind::Unnamed) |
489 | } |
490 | |
491 | /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` |
492 | #[inline ] |
493 | pub fn path_len(&self) -> usize { |
494 | self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path) |
495 | } |
496 | /// Returns a pointer to the raw `sockaddr_un` struct |
497 | #[inline ] |
498 | pub fn as_ptr(&self) -> *const libc::sockaddr_un { |
499 | &self.sun |
500 | } |
501 | /// Returns a mutable pointer to the raw `sockaddr_un` struct |
502 | #[inline ] |
503 | pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un { |
504 | &mut self.sun |
505 | } |
506 | |
507 | fn sun_len(&self) -> u8 { |
508 | cfg_if! { |
509 | if #[cfg(any(linux_android, |
510 | target_os = "fuchsia" , |
511 | solarish, |
512 | target_os = "redox" , |
513 | ))] |
514 | { |
515 | self.sun_len |
516 | } else { |
517 | self.sun.sun_len |
518 | } |
519 | } |
520 | } |
521 | } |
522 | |
523 | impl private::SockaddrLikePriv for UnixAddr {} |
524 | impl SockaddrLike for UnixAddr { |
525 | #[cfg (any( |
526 | linux_android, |
527 | target_os = "fuchsia" , |
528 | solarish, |
529 | target_os = "redox" |
530 | ))] |
531 | fn len(&self) -> libc::socklen_t { |
532 | self.sun_len.into() |
533 | } |
534 | |
535 | unsafe fn from_raw( |
536 | addr: *const libc::sockaddr, |
537 | len: Option<libc::socklen_t>, |
538 | ) -> Option<Self> |
539 | where |
540 | Self: Sized, |
541 | { |
542 | if let Some(l) = len { |
543 | if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) |
544 | || l > u8::MAX as libc::socklen_t |
545 | { |
546 | return None; |
547 | } |
548 | } |
549 | if unsafe { (*addr).sa_family as i32 != libc::AF_UNIX } { |
550 | return None; |
551 | } |
552 | let mut su: libc::sockaddr_un = unsafe { mem::zeroed() }; |
553 | let sup = &mut su as *mut libc::sockaddr_un as *mut u8; |
554 | cfg_if! { |
555 | if #[cfg(any(linux_android, |
556 | target_os = "fuchsia" , |
557 | solarish, |
558 | target_os = "redox" , |
559 | ))] { |
560 | let su_len = len.unwrap_or( |
561 | mem::size_of::<libc::sockaddr_un>() as libc::socklen_t |
562 | ); |
563 | } else { |
564 | let su_len = unsafe { len.unwrap_or((*addr).sa_len as libc::socklen_t) }; |
565 | } |
566 | } |
567 | unsafe { ptr::copy(addr as *const u8, sup, su_len as usize) }; |
568 | Some(unsafe { Self::from_raw_parts(su, su_len as u8) }) |
569 | } |
570 | |
571 | fn size() -> libc::socklen_t |
572 | where |
573 | Self: Sized, |
574 | { |
575 | mem::size_of::<libc::sockaddr_un>() as libc::socklen_t |
576 | } |
577 | |
578 | unsafe fn set_length( |
579 | &mut self, |
580 | new_length: usize, |
581 | ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { |
582 | // `new_length` is only used on some platforms, so it must be provided even when not used |
583 | #![allow (unused_variables)] |
584 | cfg_if! { |
585 | if #[cfg(any(linux_android, |
586 | target_os = "fuchsia" , |
587 | solarish, |
588 | target_os = "redox" , |
589 | ))] { |
590 | self.sun_len = new_length as u8; |
591 | } |
592 | }; |
593 | Ok(()) |
594 | } |
595 | } |
596 | |
597 | impl AsRef<libc::sockaddr_un> for UnixAddr { |
598 | fn as_ref(&self) -> &libc::sockaddr_un { |
599 | &self.sun |
600 | } |
601 | } |
602 | |
603 | #[cfg (linux_android)] |
604 | fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { |
605 | use fmt::Write; |
606 | f.write_str(data:"@ \"" )?; |
607 | for &b: u8 in abs { |
608 | use fmt::Display; |
609 | char::from(b).escape_default().fmt(f)?; |
610 | } |
611 | f.write_char('"' )?; |
612 | Ok(()) |
613 | } |
614 | |
615 | impl fmt::Display for UnixAddr { |
616 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
617 | match self.kind() { |
618 | UnixAddrKind::Pathname(path: &Path) => path.display().fmt(f), |
619 | UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>" ), |
620 | #[cfg (linux_android)] |
621 | UnixAddrKind::Abstract(name: &[u8]) => fmt_abstract(abs:name, f), |
622 | } |
623 | } |
624 | } |
625 | |
626 | impl PartialEq for UnixAddr { |
627 | fn eq(&self, other: &UnixAddr) -> bool { |
628 | self.kind() == other.kind() |
629 | } |
630 | } |
631 | |
632 | impl Eq for UnixAddr {} |
633 | |
634 | impl Hash for UnixAddr { |
635 | fn hash<H: Hasher>(&self, s: &mut H) { |
636 | self.kind().hash(state:s) |
637 | } |
638 | } |
639 | |
640 | /// Anything that, in C, can be cast back and forth to `sockaddr`. |
641 | /// |
642 | /// Most implementors also implement `AsRef<libc::XXX>` to access their |
643 | /// inner type read-only. |
644 | #[allow (clippy::len_without_is_empty)] |
645 | pub trait SockaddrLike: private::SockaddrLikePriv { |
646 | /// Returns a raw pointer to the inner structure. Useful for FFI. |
647 | fn as_ptr(&self) -> *const libc::sockaddr { |
648 | self as *const Self as *const libc::sockaddr |
649 | } |
650 | |
651 | /// Unsafe constructor from a variable length source |
652 | /// |
653 | /// Some C APIs from provide `len`, and others do not. If it's provided it |
654 | /// will be validated. If not, it will be guessed based on the family. |
655 | /// |
656 | /// # Arguments |
657 | /// |
658 | /// - `addr`: raw pointer to something that can be cast to a |
659 | /// `libc::sockaddr`. For example, `libc::sockaddr_in`, |
660 | /// `libc::sockaddr_in6`, etc. |
661 | /// - `len`: For fixed-width types like `sockaddr_in`, it will be |
662 | /// validated if present and ignored if not. For variable-width |
663 | /// types it is required and must be the total length of valid |
664 | /// data. For example, if `addr` points to a |
665 | /// named `sockaddr_un`, then `len` must be the length of the |
666 | /// structure up to but not including the trailing NUL. |
667 | /// |
668 | /// # Safety |
669 | /// |
670 | /// `addr` must be valid for the specific type of sockaddr. `len`, if |
671 | /// present, must not exceed the length of valid data in `addr`. |
672 | unsafe fn from_raw( |
673 | addr: *const libc::sockaddr, |
674 | len: Option<libc::socklen_t>, |
675 | ) -> Option<Self> |
676 | where |
677 | Self: Sized; |
678 | |
679 | /// Return the address family of this socket |
680 | /// |
681 | /// # Examples |
682 | /// One common use is to match on the family of a union type, like this: |
683 | /// ``` |
684 | /// # use nix::sys::socket::*; |
685 | /// # use std::os::unix::io::AsRawFd; |
686 | /// let fd = socket(AddressFamily::Inet, SockType::Stream, |
687 | /// SockFlag::empty(), None).unwrap(); |
688 | /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).unwrap(); |
689 | /// match ss.family().unwrap() { |
690 | /// AddressFamily::Inet => println!("{}" , ss.as_sockaddr_in().unwrap()), |
691 | /// AddressFamily::Inet6 => println!("{}" , ss.as_sockaddr_in6().unwrap()), |
692 | /// _ => println!("Unexpected address family" ) |
693 | /// } |
694 | /// ``` |
695 | fn family(&self) -> Option<AddressFamily> { |
696 | // Safe since all implementors have a sa_family field at the same |
697 | // address, and they're all repr(C) |
698 | AddressFamily::from_i32(unsafe { |
699 | (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 |
700 | }) |
701 | } |
702 | |
703 | cfg_if! { |
704 | if #[cfg(bsd)] { |
705 | /// Return the length of valid data in the sockaddr structure. |
706 | /// |
707 | /// For fixed-size sockaddrs, this should be the size of the |
708 | /// structure. But for variable-sized types like [`UnixAddr`] it |
709 | /// may be less. |
710 | fn len(&self) -> libc::socklen_t { |
711 | // Safe since all implementors have a sa_len field at the same |
712 | // address, and they're all repr(transparent). |
713 | // Robust for all implementors. |
714 | unsafe { |
715 | (*(self as *const Self as *const libc::sockaddr)).sa_len |
716 | }.into() |
717 | } |
718 | } else { |
719 | /// Return the length of valid data in the sockaddr structure. |
720 | /// |
721 | /// For fixed-size sockaddrs, this should be the size of the |
722 | /// structure. But for variable-sized types like [`UnixAddr`] it |
723 | /// may be less. |
724 | fn len(&self) -> libc::socklen_t { |
725 | // No robust default implementation is possible without an |
726 | // sa_len field. Implementors with a variable size must |
727 | // override this method. |
728 | mem::size_of_val(self) as libc::socklen_t |
729 | } |
730 | } |
731 | } |
732 | |
733 | /// Return the available space in the structure |
734 | fn size() -> libc::socklen_t |
735 | where |
736 | Self: Sized, |
737 | { |
738 | mem::size_of::<Self>() as libc::socklen_t |
739 | } |
740 | |
741 | /// Set the length of this socket address |
742 | /// |
743 | /// This method may only be called on socket addresses whose lengths are dynamic, and it |
744 | /// returns an error if called on a type whose length is static. |
745 | /// |
746 | /// # Safety |
747 | /// |
748 | /// `new_length` must be a valid length for this type of address. Specifically, reads of that |
749 | /// length from `self` must be valid. |
750 | #[doc (hidden)] |
751 | unsafe fn set_length( |
752 | &mut self, |
753 | _new_length: usize, |
754 | ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { |
755 | Err(SocketAddressLengthNotDynamic) |
756 | } |
757 | } |
758 | |
759 | /// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically |
760 | /// fixed. |
761 | #[derive (Copy, Clone, Debug)] |
762 | pub struct SocketAddressLengthNotDynamic; |
763 | impl fmt::Display for SocketAddressLengthNotDynamic { |
764 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
765 | f.write_str(data:"Attempted to set length on socket whose length is statically fixed" ) |
766 | } |
767 | } |
768 | impl std::error::Error for SocketAddressLengthNotDynamic {} |
769 | |
770 | impl private::SockaddrLikePriv for () { |
771 | fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { |
772 | ptr::null_mut() |
773 | } |
774 | } |
775 | |
776 | /// `()` can be used in place of a real Sockaddr when no address is expected, |
777 | /// for example for a field of `Option<S> where S: SockaddrLike`. |
778 | // If this RFC ever stabilizes, then ! will be a better choice. |
779 | // https://github.com/rust-lang/rust/issues/35121 |
780 | impl SockaddrLike for () { |
781 | fn as_ptr(&self) -> *const libc::sockaddr { |
782 | ptr::null() |
783 | } |
784 | |
785 | unsafe fn from_raw( |
786 | _: *const libc::sockaddr, |
787 | _: Option<libc::socklen_t>, |
788 | ) -> Option<Self> |
789 | where |
790 | Self: Sized, |
791 | { |
792 | None |
793 | } |
794 | |
795 | fn family(&self) -> Option<AddressFamily> { |
796 | None |
797 | } |
798 | |
799 | fn len(&self) -> libc::socklen_t { |
800 | 0 |
801 | } |
802 | } |
803 | |
804 | /// An IPv4 socket address |
805 | #[cfg (feature = "net" )] |
806 | #[repr (transparent)] |
807 | #[derive (Clone, Copy, Debug, Eq, Hash, PartialEq)] |
808 | pub struct SockaddrIn(libc::sockaddr_in); |
809 | |
810 | #[cfg (feature = "net" )] |
811 | impl SockaddrIn { |
812 | /// Returns the IP address associated with this socket address, in native |
813 | /// endian. |
814 | pub const fn ip(&self) -> net::Ipv4Addr { |
815 | let bytes = self.0.sin_addr.s_addr.to_ne_bytes(); |
816 | let (a, b, c, d) = (bytes[0], bytes[1], bytes[2], bytes[3]); |
817 | Ipv4Addr::new(a, b, c, d) |
818 | } |
819 | |
820 | /// Creates a new socket address from IPv4 octets and a port number. |
821 | pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { |
822 | Self(libc::sockaddr_in { |
823 | #[cfg (any( |
824 | bsd, |
825 | target_os = "aix" , |
826 | target_os = "haiku" , |
827 | target_os = "hurd" |
828 | ))] |
829 | sin_len: Self::size() as u8, |
830 | sin_family: AddressFamily::Inet as sa_family_t, |
831 | sin_port: u16::to_be(port), |
832 | sin_addr: libc::in_addr { |
833 | s_addr: u32::from_ne_bytes([a, b, c, d]), |
834 | }, |
835 | sin_zero: unsafe { mem::zeroed() }, |
836 | }) |
837 | } |
838 | |
839 | /// Returns the port number associated with this socket address, in native |
840 | /// endian. |
841 | pub const fn port(&self) -> u16 { |
842 | u16::from_be(self.0.sin_port) |
843 | } |
844 | } |
845 | |
846 | #[cfg (feature = "net" )] |
847 | impl private::SockaddrLikePriv for SockaddrIn {} |
848 | #[cfg (feature = "net" )] |
849 | impl SockaddrLike for SockaddrIn { |
850 | unsafe fn from_raw( |
851 | addr: *const libc::sockaddr, |
852 | len: Option<libc::socklen_t>, |
853 | ) -> Option<Self> |
854 | where |
855 | Self: Sized, |
856 | { |
857 | if let Some(l) = len { |
858 | if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t { |
859 | return None; |
860 | } |
861 | } |
862 | if unsafe { (*addr).sa_family as i32 != libc::AF_INET } { |
863 | return None; |
864 | } |
865 | Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) |
866 | } |
867 | } |
868 | |
869 | #[cfg (feature = "net" )] |
870 | impl AsRef<libc::sockaddr_in> for SockaddrIn { |
871 | fn as_ref(&self) -> &libc::sockaddr_in { |
872 | &self.0 |
873 | } |
874 | } |
875 | |
876 | #[cfg (feature = "net" )] |
877 | impl fmt::Display for SockaddrIn { |
878 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
879 | let ne = u32::from_be(self.0.sin_addr.s_addr); |
880 | let port = u16::from_be(self.0.sin_port); |
881 | write!( |
882 | f, |
883 | "{}.{}.{}.{}:{}" , |
884 | ne >> 24, |
885 | (ne >> 16) & 0xFF, |
886 | (ne >> 8) & 0xFF, |
887 | ne & 0xFF, |
888 | port |
889 | ) |
890 | } |
891 | } |
892 | |
893 | #[cfg (feature = "net" )] |
894 | impl From<net::SocketAddrV4> for SockaddrIn { |
895 | fn from(addr: net::SocketAddrV4) -> Self { |
896 | Self(libc::sockaddr_in { |
897 | #[cfg (any( |
898 | bsd, |
899 | target_os = "haiku" , |
900 | target_os = "hermit" , |
901 | target_os = "hurd" |
902 | ))] |
903 | sin_len: mem::size_of::<libc::sockaddr_in>() as u8, |
904 | sin_family: AddressFamily::Inet as sa_family_t, |
905 | sin_port: addr.port().to_be(), // network byte order |
906 | sin_addr: ipv4addr_to_libc(*addr.ip()), |
907 | ..unsafe { mem::zeroed() } |
908 | }) |
909 | } |
910 | } |
911 | |
912 | #[cfg (feature = "net" )] |
913 | impl From<SockaddrIn> for net::SocketAddrV4 { |
914 | fn from(addr: SockaddrIn) -> Self { |
915 | net::SocketAddrV4::new( |
916 | net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()), |
917 | u16::from_be(addr.0.sin_port), |
918 | ) |
919 | } |
920 | } |
921 | |
922 | #[cfg (feature = "net" )] |
923 | impl From<SockaddrIn> for libc::sockaddr_in { |
924 | fn from(sin: SockaddrIn) -> libc::sockaddr_in { |
925 | sin.0 |
926 | } |
927 | } |
928 | #[cfg (feature = "net" )] |
929 | impl From<libc::sockaddr_in> for SockaddrIn { |
930 | fn from(sin: libc::sockaddr_in) -> SockaddrIn { |
931 | SockaddrIn(sin) |
932 | } |
933 | } |
934 | |
935 | #[cfg (feature = "net" )] |
936 | impl std::str::FromStr for SockaddrIn { |
937 | type Err = net::AddrParseError; |
938 | |
939 | fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { |
940 | net::SocketAddrV4::from_str(s).map(SockaddrIn::from) |
941 | } |
942 | } |
943 | |
944 | /// An IPv6 socket address |
945 | #[cfg (feature = "net" )] |
946 | #[repr (transparent)] |
947 | #[derive (Clone, Copy, Debug, Eq, Hash, PartialEq)] |
948 | pub struct SockaddrIn6(libc::sockaddr_in6); |
949 | |
950 | #[cfg (feature = "net" )] |
951 | impl SockaddrIn6 { |
952 | /// Returns the flow information associated with this address. |
953 | pub const fn flowinfo(&self) -> u32 { |
954 | self.0.sin6_flowinfo |
955 | } |
956 | |
957 | /// Returns the IP address associated with this socket address. |
958 | pub const fn ip(&self) -> net::Ipv6Addr { |
959 | let bytes = self.0.sin6_addr.s6_addr; |
960 | let (a, b, c, d, e, f, g, h) = ( |
961 | ((bytes[0] as u16) << 8) | bytes[1] as u16, |
962 | ((bytes[2] as u16) << 8) | bytes[3] as u16, |
963 | ((bytes[4] as u16) << 8) | bytes[5] as u16, |
964 | ((bytes[6] as u16) << 8) | bytes[7] as u16, |
965 | ((bytes[8] as u16) << 8) | bytes[9] as u16, |
966 | ((bytes[10] as u16) << 8) | bytes[11] as u16, |
967 | ((bytes[12] as u16) << 8) | bytes[13] as u16, |
968 | ((bytes[14] as u16) << 8) | bytes[15] as u16, |
969 | ); |
970 | Ipv6Addr::new(a, b, c, d, e, f, g, h) |
971 | } |
972 | |
973 | /// Returns the port number associated with this socket address, in native |
974 | /// endian. |
975 | pub const fn port(&self) -> u16 { |
976 | u16::from_be(self.0.sin6_port) |
977 | } |
978 | |
979 | /// Returns the scope ID associated with this address. |
980 | pub const fn scope_id(&self) -> u32 { |
981 | self.0.sin6_scope_id |
982 | } |
983 | } |
984 | |
985 | #[cfg (feature = "net" )] |
986 | impl From<SockaddrIn6> for libc::sockaddr_in6 { |
987 | fn from(sin6: SockaddrIn6) -> libc::sockaddr_in6 { |
988 | sin6.0 |
989 | } |
990 | } |
991 | |
992 | #[cfg (feature = "net" )] |
993 | impl From<libc::sockaddr_in6> for SockaddrIn6 { |
994 | fn from(sin6: libc::sockaddr_in6) -> SockaddrIn6 { |
995 | SockaddrIn6(sin6) |
996 | } |
997 | } |
998 | |
999 | #[cfg (feature = "net" )] |
1000 | impl private::SockaddrLikePriv for SockaddrIn6 {} |
1001 | #[cfg (feature = "net" )] |
1002 | impl SockaddrLike for SockaddrIn6 { |
1003 | unsafe fn from_raw( |
1004 | addr: *const libc::sockaddr, |
1005 | len: Option<libc::socklen_t>, |
1006 | ) -> Option<Self> |
1007 | where |
1008 | Self: Sized, |
1009 | { |
1010 | if let Some(l) = len { |
1011 | if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t { |
1012 | return None; |
1013 | } |
1014 | } |
1015 | if unsafe { (*addr).sa_family as i32 != libc::AF_INET6 } { |
1016 | return None; |
1017 | } |
1018 | Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) |
1019 | } |
1020 | } |
1021 | |
1022 | #[cfg (feature = "net" )] |
1023 | impl AsRef<libc::sockaddr_in6> for SockaddrIn6 { |
1024 | fn as_ref(&self) -> &libc::sockaddr_in6 { |
1025 | &self.0 |
1026 | } |
1027 | } |
1028 | |
1029 | #[cfg (feature = "net" )] |
1030 | impl fmt::Display for SockaddrIn6 { |
1031 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1032 | // These things are really hard to display properly. Easier to let std |
1033 | // do it. |
1034 | let std = net::SocketAddrV6::new( |
1035 | self.ip(), |
1036 | self.port(), |
1037 | self.flowinfo(), |
1038 | self.scope_id(), |
1039 | ); |
1040 | std.fmt(f) |
1041 | } |
1042 | } |
1043 | |
1044 | #[cfg (feature = "net" )] |
1045 | impl From<net::SocketAddrV6> for SockaddrIn6 { |
1046 | fn from(addr: net::SocketAddrV6) -> Self { |
1047 | #[allow (clippy::needless_update)] // It isn't needless on Illumos |
1048 | Self(libc::sockaddr_in6 { |
1049 | #[cfg (any( |
1050 | bsd, |
1051 | target_os = "haiku" , |
1052 | target_os = "hermit" , |
1053 | target_os = "hurd" |
1054 | ))] |
1055 | sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, |
1056 | sin6_family: AddressFamily::Inet6 as sa_family_t, |
1057 | sin6_port: addr.port().to_be(), // network byte order |
1058 | sin6_addr: ipv6addr_to_libc(addr.ip()), |
1059 | sin6_flowinfo: addr.flowinfo(), // host byte order |
1060 | sin6_scope_id: addr.scope_id(), // host byte order |
1061 | ..unsafe { mem::zeroed() } |
1062 | }) |
1063 | } |
1064 | } |
1065 | |
1066 | #[cfg (feature = "net" )] |
1067 | impl From<SockaddrIn6> for net::SocketAddrV6 { |
1068 | fn from(addr: SockaddrIn6) -> Self { |
1069 | net::SocketAddrV6::new( |
1070 | net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), |
1071 | u16::from_be(addr.0.sin6_port), |
1072 | addr.0.sin6_flowinfo, |
1073 | addr.0.sin6_scope_id, |
1074 | ) |
1075 | } |
1076 | } |
1077 | |
1078 | #[cfg (feature = "net" )] |
1079 | impl std::str::FromStr for SockaddrIn6 { |
1080 | type Err = net::AddrParseError; |
1081 | |
1082 | fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { |
1083 | net::SocketAddrV6::from_str(s).map(SockaddrIn6::from) |
1084 | } |
1085 | } |
1086 | |
1087 | /// A container for any sockaddr type |
1088 | /// |
1089 | /// Just like C's `sockaddr_storage`, this type is large enough to hold any type |
1090 | /// of sockaddr. It can be used as an argument with functions like |
1091 | /// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is |
1092 | /// a union, it can be safely accessed through the `as_*` methods. |
1093 | /// |
1094 | /// # Example |
1095 | /// ``` |
1096 | /// # use nix::sys::socket::*; |
1097 | /// # use std::str::FromStr; |
1098 | /// # use std::os::unix::io::AsRawFd; |
1099 | /// let localhost = SockaddrIn::from_str("127.0.0.1:8081" ).unwrap(); |
1100 | /// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), |
1101 | /// None).unwrap(); |
1102 | /// bind(fd.as_raw_fd(), &localhost).expect("bind" ); |
1103 | /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).expect("getsockname" ); |
1104 | /// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); |
1105 | /// ``` |
1106 | #[derive (Clone, Copy, Eq)] |
1107 | #[repr (C)] |
1108 | pub union SockaddrStorage { |
1109 | #[cfg (linux_android)] |
1110 | alg: AlgAddr, |
1111 | #[cfg (all( |
1112 | feature = "net" , |
1113 | not(any(target_os = "hurd" , target_os = "redox" )) |
1114 | ))] |
1115 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
1116 | dl: LinkAddr, |
1117 | #[cfg (linux_android)] |
1118 | nl: NetlinkAddr, |
1119 | #[cfg (all(feature = "ioctl" , apple_targets))] |
1120 | #[cfg_attr (docsrs, doc(cfg(feature = "ioctl" )))] |
1121 | sctl: SysControlAddr, |
1122 | #[cfg (feature = "net" )] |
1123 | sin: SockaddrIn, |
1124 | #[cfg (feature = "net" )] |
1125 | sin6: SockaddrIn6, |
1126 | ss: libc::sockaddr_storage, |
1127 | su: UnixAddr, |
1128 | #[cfg (any(linux_android, apple_targets))] |
1129 | vsock: VsockAddr, |
1130 | } |
1131 | impl private::SockaddrLikePriv for SockaddrStorage {} |
1132 | impl SockaddrLike for SockaddrStorage { |
1133 | unsafe fn from_raw( |
1134 | addr: *const libc::sockaddr, |
1135 | l: Option<libc::socklen_t>, |
1136 | ) -> Option<Self> |
1137 | where |
1138 | Self: Sized, |
1139 | { |
1140 | if addr.is_null() { |
1141 | return None; |
1142 | } |
1143 | if let Some(len) = l { |
1144 | let ulen = len as usize; |
1145 | if ulen < offset_of!(libc::sockaddr, sa_data) |
1146 | || ulen > mem::size_of::<libc::sockaddr_storage>() |
1147 | { |
1148 | None |
1149 | } else { |
1150 | let mut ss: libc::sockaddr_storage = unsafe { mem::zeroed() }; |
1151 | let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; |
1152 | unsafe { ptr::copy(addr as *const u8, ssp, len as usize) }; |
1153 | #[cfg (any( |
1154 | linux_android, |
1155 | target_os = "fuchsia" , |
1156 | solarish, |
1157 | ))] |
1158 | if i32::from(ss.ss_family) == libc::AF_UNIX { |
1159 | // Safe because we UnixAddr is strictly smaller than |
1160 | // SockaddrStorage, and we just initialized the structure. |
1161 | unsafe { |
1162 | (*(&mut ss as *mut libc::sockaddr_storage |
1163 | as *mut UnixAddr)) |
1164 | .sun_len = len as u8; |
1165 | } |
1166 | } |
1167 | Some(Self { ss }) |
1168 | } |
1169 | } else { |
1170 | // If length is not available and addr is of a fixed-length type, |
1171 | // copy it. If addr is of a variable length type and len is not |
1172 | // available, then there's nothing we can do. |
1173 | match unsafe { (*addr).sa_family as i32 } { |
1174 | #[cfg (linux_android)] |
1175 | libc::AF_ALG => unsafe { |
1176 | AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) |
1177 | }, |
1178 | #[cfg (feature = "net" )] |
1179 | libc::AF_INET => unsafe { |
1180 | SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) |
1181 | }, |
1182 | #[cfg (feature = "net" )] |
1183 | libc::AF_INET6 => unsafe { |
1184 | SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 }) |
1185 | }, |
1186 | #[cfg (any(bsd, solarish, target_os = "haiku" ))] |
1187 | #[cfg (feature = "net" )] |
1188 | libc::AF_LINK => unsafe { |
1189 | LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) |
1190 | }, |
1191 | #[cfg (linux_android)] |
1192 | libc::AF_NETLINK => unsafe { |
1193 | NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) |
1194 | }, |
1195 | #[cfg (any(linux_android, target_os = "fuchsia" ))] |
1196 | #[cfg (feature = "net" )] |
1197 | libc::AF_PACKET => unsafe { |
1198 | LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) |
1199 | }, |
1200 | #[cfg (all(feature = "ioctl" , apple_targets))] |
1201 | libc::AF_SYSTEM => unsafe { |
1202 | SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) |
1203 | }, |
1204 | #[cfg (any(linux_android, apple_targets))] |
1205 | libc::AF_VSOCK => unsafe { |
1206 | VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) |
1207 | }, |
1208 | _ => None, |
1209 | } |
1210 | } |
1211 | } |
1212 | |
1213 | #[cfg (any(linux_android, target_os = "fuchsia" , solarish))] |
1214 | fn len(&self) -> libc::socklen_t { |
1215 | match self.as_unix_addr() { |
1216 | // The UnixAddr type knows its own length |
1217 | Some(ua) => ua.len(), |
1218 | // For all else, we're just a boring SockaddrStorage |
1219 | None => mem::size_of_val(self) as libc::socklen_t, |
1220 | } |
1221 | } |
1222 | |
1223 | unsafe fn set_length( |
1224 | &mut self, |
1225 | new_length: usize, |
1226 | ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { |
1227 | match self.as_unix_addr_mut() { |
1228 | Some(addr) => unsafe { addr.set_length(new_length) }, |
1229 | None => Err(SocketAddressLengthNotDynamic), |
1230 | } |
1231 | } |
1232 | } |
1233 | |
1234 | macro_rules! accessors { |
1235 | ( |
1236 | $fname:ident, |
1237 | $fname_mut:ident, |
1238 | $sockty:ty, |
1239 | $family:expr, |
1240 | $libc_ty:ty, |
1241 | $field:ident) => { |
1242 | /// Safely and falliably downcast to an immutable reference |
1243 | pub fn $fname(&self) -> Option<&$sockty> { |
1244 | if self.family() == Some($family) |
1245 | && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t |
1246 | { |
1247 | // Safe because family and len are validated |
1248 | Some(unsafe { &self.$field }) |
1249 | } else { |
1250 | None |
1251 | } |
1252 | } |
1253 | |
1254 | /// Safely and falliably downcast to a mutable reference |
1255 | pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { |
1256 | if self.family() == Some($family) |
1257 | && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t |
1258 | { |
1259 | // Safe because family and len are validated |
1260 | Some(unsafe { &mut self.$field }) |
1261 | } else { |
1262 | None |
1263 | } |
1264 | } |
1265 | }; |
1266 | } |
1267 | |
1268 | impl SockaddrStorage { |
1269 | /// Downcast to an immutable `[UnixAddr]` reference. |
1270 | pub fn as_unix_addr(&self) -> Option<&UnixAddr> { |
1271 | cfg_if! { |
1272 | if #[cfg(any(linux_android, |
1273 | target_os = "fuchsia" , |
1274 | solarish, |
1275 | ))] |
1276 | { |
1277 | let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; |
1278 | // Safe because UnixAddr is strictly smaller than |
1279 | // sockaddr_storage, and we're fully initialized |
1280 | let len = unsafe { |
1281 | (*(p as *const UnixAddr )).sun_len as usize |
1282 | }; |
1283 | } else { |
1284 | let len = self.len() as usize; |
1285 | } |
1286 | } |
1287 | // Sanity checks |
1288 | if self.family() != Some(AddressFamily::Unix) |
1289 | || len < offset_of!(libc::sockaddr_un, sun_path) |
1290 | || len > mem::size_of::<libc::sockaddr_un>() |
1291 | { |
1292 | None |
1293 | } else { |
1294 | Some(unsafe { &self.su }) |
1295 | } |
1296 | } |
1297 | |
1298 | /// Downcast to a mutable `[UnixAddr]` reference. |
1299 | pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> { |
1300 | cfg_if! { |
1301 | if #[cfg(any(linux_android, |
1302 | target_os = "fuchsia" , |
1303 | solarish, |
1304 | ))] |
1305 | { |
1306 | let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; |
1307 | // Safe because UnixAddr is strictly smaller than |
1308 | // sockaddr_storage, and we're fully initialized |
1309 | let len = unsafe { |
1310 | (*(p as *const UnixAddr )).sun_len as usize |
1311 | }; |
1312 | } else { |
1313 | let len = self.len() as usize; |
1314 | } |
1315 | } |
1316 | // Sanity checks |
1317 | if self.family() != Some(AddressFamily::Unix) |
1318 | || len < offset_of!(libc::sockaddr_un, sun_path) |
1319 | || len > mem::size_of::<libc::sockaddr_un>() |
1320 | { |
1321 | None |
1322 | } else { |
1323 | Some(unsafe { &mut self.su }) |
1324 | } |
1325 | } |
1326 | |
1327 | #[cfg (linux_android)] |
1328 | accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, |
1329 | AddressFamily::Alg, libc::sockaddr_alg, alg} |
1330 | |
1331 | #[cfg (any(linux_android, target_os = "fuchsia" ))] |
1332 | #[cfg (feature = "net" )] |
1333 | accessors! { |
1334 | as_link_addr, as_link_addr_mut, LinkAddr, |
1335 | AddressFamily::Packet, libc::sockaddr_ll, dl} |
1336 | |
1337 | #[cfg (any(bsd, solarish))] |
1338 | #[cfg (feature = "net" )] |
1339 | accessors! { |
1340 | as_link_addr, as_link_addr_mut, LinkAddr, |
1341 | AddressFamily::Link, libc::sockaddr_dl, dl} |
1342 | |
1343 | #[cfg (feature = "net" )] |
1344 | accessors! { |
1345 | as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, |
1346 | AddressFamily::Inet, libc::sockaddr_in, sin} |
1347 | |
1348 | #[cfg (feature = "net" )] |
1349 | accessors! { |
1350 | as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, |
1351 | AddressFamily::Inet6, libc::sockaddr_in6, sin6} |
1352 | |
1353 | #[cfg (linux_android)] |
1354 | accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, |
1355 | AddressFamily::Netlink, libc::sockaddr_nl, nl} |
1356 | |
1357 | #[cfg (all(feature = "ioctl" , apple_targets))] |
1358 | #[cfg_attr (docsrs, doc(cfg(feature = "ioctl" )))] |
1359 | accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, |
1360 | AddressFamily::System, libc::sockaddr_ctl, sctl} |
1361 | |
1362 | #[cfg (any(linux_android, apple_targets))] |
1363 | accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, |
1364 | AddressFamily::Vsock, libc::sockaddr_vm, vsock} |
1365 | } |
1366 | |
1367 | impl fmt::Debug for SockaddrStorage { |
1368 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1369 | f&mut DebugStruct<'_, '_>.debug_struct("SockaddrStorage" ) |
1370 | // Safe because sockaddr_storage has the least specific |
1371 | // field types |
1372 | .field(name:"ss" , value:unsafe { &self.ss }) |
1373 | .finish() |
1374 | } |
1375 | } |
1376 | |
1377 | impl fmt::Display for SockaddrStorage { |
1378 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1379 | unsafe { |
1380 | match self.ss.ss_family as i32 { |
1381 | #[cfg (linux_android)] |
1382 | libc::AF_ALG => self.alg.fmt(f), |
1383 | #[cfg (feature = "net" )] |
1384 | libc::AF_INET => self.sin.fmt(f), |
1385 | #[cfg (feature = "net" )] |
1386 | libc::AF_INET6 => self.sin6.fmt(f), |
1387 | #[cfg (any(bsd, solarish))] |
1388 | #[cfg (feature = "net" )] |
1389 | libc::AF_LINK => self.dl.fmt(f), |
1390 | #[cfg (linux_android)] |
1391 | libc::AF_NETLINK => self.nl.fmt(f), |
1392 | #[cfg (any(linux_android, target_os = "fuchsia" ))] |
1393 | #[cfg (feature = "net" )] |
1394 | libc::AF_PACKET => self.dl.fmt(f), |
1395 | #[cfg (apple_targets)] |
1396 | #[cfg (feature = "ioctl" )] |
1397 | libc::AF_SYSTEM => self.sctl.fmt(f), |
1398 | libc::AF_UNIX => self.su.fmt(f), |
1399 | #[cfg (any(linux_android, apple_targets))] |
1400 | libc::AF_VSOCK => self.vsock.fmt(f), |
1401 | _ => "<Address family unspecified>" .fmt(f), |
1402 | } |
1403 | } |
1404 | } |
1405 | } |
1406 | |
1407 | #[cfg (feature = "net" )] |
1408 | impl From<net::SocketAddrV4> for SockaddrStorage { |
1409 | fn from(s: net::SocketAddrV4) -> Self { |
1410 | unsafe { |
1411 | let mut ss: Self = mem::zeroed(); |
1412 | ss.sin = SockaddrIn::from(s); |
1413 | ss |
1414 | } |
1415 | } |
1416 | } |
1417 | |
1418 | #[cfg (feature = "net" )] |
1419 | impl From<net::SocketAddrV6> for SockaddrStorage { |
1420 | fn from(s: net::SocketAddrV6) -> Self { |
1421 | unsafe { |
1422 | let mut ss: Self = mem::zeroed(); |
1423 | ss.sin6 = SockaddrIn6::from(s); |
1424 | ss |
1425 | } |
1426 | } |
1427 | } |
1428 | |
1429 | #[cfg (feature = "net" )] |
1430 | impl From<net::SocketAddr> for SockaddrStorage { |
1431 | fn from(s: net::SocketAddr) -> Self { |
1432 | match s { |
1433 | net::SocketAddr::V4(sa4) => Self::from(sa4), |
1434 | net::SocketAddr::V6(sa6) => Self::from(sa6), |
1435 | } |
1436 | } |
1437 | } |
1438 | |
1439 | impl Hash for SockaddrStorage { |
1440 | fn hash<H: Hasher>(&self, s: &mut H) { |
1441 | unsafe { |
1442 | match self.ss.ss_family as i32 { |
1443 | #[cfg (linux_android)] |
1444 | libc::AF_ALG => self.alg.hash(s), |
1445 | #[cfg (feature = "net" )] |
1446 | libc::AF_INET => self.sin.hash(s), |
1447 | #[cfg (feature = "net" )] |
1448 | libc::AF_INET6 => self.sin6.hash(s), |
1449 | #[cfg (any(bsd, solarish))] |
1450 | #[cfg (feature = "net" )] |
1451 | libc::AF_LINK => self.dl.hash(s), |
1452 | #[cfg (linux_android)] |
1453 | libc::AF_NETLINK => self.nl.hash(s), |
1454 | #[cfg (any(linux_android, target_os = "fuchsia" ))] |
1455 | #[cfg (feature = "net" )] |
1456 | libc::AF_PACKET => self.dl.hash(s), |
1457 | #[cfg (apple_targets)] |
1458 | #[cfg (feature = "ioctl" )] |
1459 | libc::AF_SYSTEM => self.sctl.hash(s), |
1460 | libc::AF_UNIX => self.su.hash(s), |
1461 | #[cfg (any(linux_android, apple_targets))] |
1462 | libc::AF_VSOCK => self.vsock.hash(s), |
1463 | _ => self.ss.hash(s), |
1464 | } |
1465 | } |
1466 | } |
1467 | } |
1468 | |
1469 | impl PartialEq for SockaddrStorage { |
1470 | fn eq(&self, other: &Self) -> bool { |
1471 | unsafe { |
1472 | match (self.ss.ss_family as i32, other.ss.ss_family as i32) { |
1473 | #[cfg (linux_android)] |
1474 | (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, |
1475 | #[cfg (feature = "net" )] |
1476 | (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, |
1477 | #[cfg (feature = "net" )] |
1478 | (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, |
1479 | #[cfg (any(bsd, solarish))] |
1480 | #[cfg (feature = "net" )] |
1481 | (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, |
1482 | #[cfg (linux_android)] |
1483 | (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, |
1484 | #[cfg (any(linux_android, target_os = "fuchsia" ))] |
1485 | #[cfg (feature = "net" )] |
1486 | (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, |
1487 | #[cfg (apple_targets)] |
1488 | #[cfg (feature = "ioctl" )] |
1489 | (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, |
1490 | (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, |
1491 | #[cfg (any(linux_android, apple_targets))] |
1492 | (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, |
1493 | _ => false, |
1494 | } |
1495 | } |
1496 | } |
1497 | } |
1498 | |
1499 | pub(super) mod private { |
1500 | pub trait SockaddrLikePriv { |
1501 | /// Returns a mutable raw pointer to the inner structure. |
1502 | /// |
1503 | /// # Safety |
1504 | /// |
1505 | /// This method is technically safe, but modifying the inner structure's |
1506 | /// `family` or `len` fields may result in violating Nix's invariants. |
1507 | /// It is best to use this method only with foreign functions that do |
1508 | /// not change the sockaddr type. |
1509 | fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { |
1510 | self as *mut Self as *mut libc::sockaddr |
1511 | } |
1512 | } |
1513 | } |
1514 | |
1515 | #[cfg (linux_android)] |
1516 | pub mod netlink { |
1517 | use super::*; |
1518 | use crate::sys::socket::addr::AddressFamily; |
1519 | use libc::{sa_family_t, sockaddr_nl}; |
1520 | use std::{fmt, mem}; |
1521 | |
1522 | /// Address for the Linux kernel user interface device. |
1523 | /// |
1524 | /// # References |
1525 | /// |
1526 | /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) |
1527 | #[derive (Copy, Clone, Debug, Eq, Hash, PartialEq)] |
1528 | #[repr (transparent)] |
1529 | pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); |
1530 | |
1531 | impl NetlinkAddr { |
1532 | /// Construct a new socket address from its port ID and multicast groups |
1533 | /// mask. |
1534 | pub fn new(pid: u32, groups: u32) -> NetlinkAddr { |
1535 | let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; |
1536 | addr.nl_family = AddressFamily::Netlink as sa_family_t; |
1537 | addr.nl_pid = pid; |
1538 | addr.nl_groups = groups; |
1539 | |
1540 | NetlinkAddr(addr) |
1541 | } |
1542 | |
1543 | /// Return the socket's port ID. |
1544 | pub const fn pid(&self) -> u32 { |
1545 | self.0.nl_pid |
1546 | } |
1547 | |
1548 | /// Return the socket's multicast groups mask |
1549 | pub const fn groups(&self) -> u32 { |
1550 | self.0.nl_groups |
1551 | } |
1552 | } |
1553 | |
1554 | impl private::SockaddrLikePriv for NetlinkAddr {} |
1555 | impl SockaddrLike for NetlinkAddr { |
1556 | unsafe fn from_raw( |
1557 | addr: *const libc::sockaddr, |
1558 | len: Option<libc::socklen_t>, |
1559 | ) -> Option<Self> |
1560 | where |
1561 | Self: Sized, |
1562 | { |
1563 | if let Some(l) = len { |
1564 | if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t { |
1565 | return None; |
1566 | } |
1567 | } |
1568 | if unsafe { (*addr).sa_family as i32 != libc::AF_NETLINK } { |
1569 | return None; |
1570 | } |
1571 | Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) |
1572 | } |
1573 | } |
1574 | |
1575 | impl AsRef<libc::sockaddr_nl> for NetlinkAddr { |
1576 | fn as_ref(&self) -> &libc::sockaddr_nl { |
1577 | &self.0 |
1578 | } |
1579 | } |
1580 | |
1581 | impl fmt::Display for NetlinkAddr { |
1582 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1583 | write!(f, "pid: {} groups: {}" , self.pid(), self.groups()) |
1584 | } |
1585 | } |
1586 | } |
1587 | |
1588 | #[cfg (linux_android)] |
1589 | pub mod alg { |
1590 | use super::*; |
1591 | use libc::{sockaddr_alg, AF_ALG}; |
1592 | use std::ffi::CStr; |
1593 | use std::hash::{Hash, Hasher}; |
1594 | use std::{fmt, mem, str}; |
1595 | |
1596 | /// Socket address for the Linux kernel crypto API |
1597 | #[derive (Copy, Clone)] |
1598 | #[repr (transparent)] |
1599 | pub struct AlgAddr(pub(in super::super) sockaddr_alg); |
1600 | |
1601 | impl private::SockaddrLikePriv for AlgAddr {} |
1602 | impl SockaddrLike for AlgAddr { |
1603 | unsafe fn from_raw( |
1604 | addr: *const libc::sockaddr, |
1605 | l: Option<libc::socklen_t>, |
1606 | ) -> Option<Self> |
1607 | where |
1608 | Self: Sized, |
1609 | { |
1610 | if let Some(l) = l { |
1611 | if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t |
1612 | { |
1613 | return None; |
1614 | } |
1615 | } |
1616 | if unsafe { (*addr).sa_family as i32 != libc::AF_ALG } { |
1617 | return None; |
1618 | } |
1619 | Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) |
1620 | } |
1621 | } |
1622 | |
1623 | impl AsRef<libc::sockaddr_alg> for AlgAddr { |
1624 | fn as_ref(&self) -> &libc::sockaddr_alg { |
1625 | &self.0 |
1626 | } |
1627 | } |
1628 | |
1629 | // , PartialEq, Eq, Debug, Hash |
1630 | impl PartialEq for AlgAddr { |
1631 | fn eq(&self, other: &Self) -> bool { |
1632 | let (inner, other) = (self.0, other.0); |
1633 | ( |
1634 | inner.salg_family, |
1635 | &inner.salg_type[..], |
1636 | inner.salg_feat, |
1637 | inner.salg_mask, |
1638 | &inner.salg_name[..], |
1639 | ) == ( |
1640 | other.salg_family, |
1641 | &other.salg_type[..], |
1642 | other.salg_feat, |
1643 | other.salg_mask, |
1644 | &other.salg_name[..], |
1645 | ) |
1646 | } |
1647 | } |
1648 | |
1649 | impl Eq for AlgAddr {} |
1650 | |
1651 | impl Hash for AlgAddr { |
1652 | fn hash<H: Hasher>(&self, s: &mut H) { |
1653 | let inner = self.0; |
1654 | ( |
1655 | inner.salg_family, |
1656 | &inner.salg_type[..], |
1657 | inner.salg_feat, |
1658 | inner.salg_mask, |
1659 | &inner.salg_name[..], |
1660 | ) |
1661 | .hash(s); |
1662 | } |
1663 | } |
1664 | |
1665 | impl AlgAddr { |
1666 | /// Construct an `AF_ALG` socket from its cipher name and type. |
1667 | pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { |
1668 | let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; |
1669 | addr.salg_family = AF_ALG as u16; |
1670 | addr.salg_type[..alg_type.len()] |
1671 | .copy_from_slice(alg_type.to_string().as_bytes()); |
1672 | addr.salg_name[..alg_name.len()] |
1673 | .copy_from_slice(alg_name.to_string().as_bytes()); |
1674 | |
1675 | AlgAddr(addr) |
1676 | } |
1677 | |
1678 | /// Return the socket's cipher type, for example `hash` or `aead`. |
1679 | pub fn alg_type(&self) -> &CStr { |
1680 | unsafe { CStr::from_ptr(self.0.salg_type.as_ptr().cast()) } |
1681 | } |
1682 | |
1683 | /// Return the socket's cipher name, for example `sha1`. |
1684 | pub fn alg_name(&self) -> &CStr { |
1685 | unsafe { CStr::from_ptr(self.0.salg_name.as_ptr().cast()) } |
1686 | } |
1687 | } |
1688 | |
1689 | impl fmt::Display for AlgAddr { |
1690 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1691 | write!( |
1692 | f, |
1693 | "type: {} alg: {}" , |
1694 | self.alg_name().to_string_lossy(), |
1695 | self.alg_type().to_string_lossy() |
1696 | ) |
1697 | } |
1698 | } |
1699 | |
1700 | impl fmt::Debug for AlgAddr { |
1701 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1702 | fmt::Display::fmt(self, f) |
1703 | } |
1704 | } |
1705 | } |
1706 | |
1707 | feature! { |
1708 | #![feature = "ioctl" ] |
1709 | #[cfg (apple_targets)] |
1710 | pub mod sys_control { |
1711 | use crate::sys::socket::addr::AddressFamily; |
1712 | use libc::{self, c_uchar}; |
1713 | use std::{fmt, mem, ptr}; |
1714 | use std::os::unix::io::RawFd; |
1715 | use crate::{Errno, Result}; |
1716 | use super::{private, SockaddrLike}; |
1717 | |
1718 | // FIXME: Move type into `libc` |
1719 | #[repr (C)] |
1720 | #[derive (Clone, Copy)] |
1721 | #[allow (missing_debug_implementations)] |
1722 | pub struct ctl_ioc_info { |
1723 | pub ctl_id: u32, |
1724 | pub ctl_name: [c_uchar; MAX_KCTL_NAME], |
1725 | } |
1726 | |
1727 | const CTL_IOC_MAGIC: u8 = b'N' ; |
1728 | const CTL_IOC_INFO: u8 = 3; |
1729 | const MAX_KCTL_NAME: usize = 96; |
1730 | |
1731 | ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); |
1732 | |
1733 | /// Apple system control socket |
1734 | /// |
1735 | /// # References |
1736 | /// |
1737 | /// <https://developer.apple.com/documentation/kernel/sockaddr_ctl> |
1738 | #[derive (Clone, Copy, Debug, Eq, Hash, PartialEq)] |
1739 | #[repr (transparent)] |
1740 | pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); |
1741 | |
1742 | impl private::SockaddrLikePriv for SysControlAddr {} |
1743 | impl SockaddrLike for SysControlAddr { |
1744 | unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) |
1745 | -> Option<Self> where Self: Sized |
1746 | { |
1747 | if let Some(l) = len { |
1748 | if l != mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t { |
1749 | return None; |
1750 | } |
1751 | } |
1752 | if unsafe { (*addr).sa_family as i32 != libc::AF_SYSTEM } { |
1753 | return None; |
1754 | } |
1755 | Some(Self(unsafe { ptr::read_unaligned(addr as *const _) } )) |
1756 | } |
1757 | } |
1758 | |
1759 | impl AsRef<libc::sockaddr_ctl> for SysControlAddr { |
1760 | fn as_ref(&self) -> &libc::sockaddr_ctl { |
1761 | &self.0 |
1762 | } |
1763 | } |
1764 | |
1765 | impl SysControlAddr { |
1766 | /// Construct a new `SysControlAddr` from its kernel unique identifier |
1767 | /// and unit number. |
1768 | pub const fn new(id: u32, unit: u32) -> SysControlAddr { |
1769 | let addr = libc::sockaddr_ctl { |
1770 | sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar, |
1771 | sc_family: AddressFamily::System as c_uchar, |
1772 | ss_sysaddr: libc::AF_SYS_CONTROL as u16, |
1773 | sc_id: id, |
1774 | sc_unit: unit, |
1775 | sc_reserved: [0; 5] |
1776 | }; |
1777 | |
1778 | SysControlAddr(addr) |
1779 | } |
1780 | |
1781 | /// Construct a new `SysControlAddr` from its human readable name and |
1782 | /// unit number. |
1783 | pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { |
1784 | if name.len() > MAX_KCTL_NAME { |
1785 | return Err(Errno::ENAMETOOLONG); |
1786 | } |
1787 | |
1788 | let mut ctl_name = [0; MAX_KCTL_NAME]; |
1789 | ctl_name[..name.len()].clone_from_slice(name.as_bytes()); |
1790 | let mut info = ctl_ioc_info { ctl_id: 0, ctl_name }; |
1791 | |
1792 | unsafe { ctl_info(sockfd, &mut info)?; } |
1793 | |
1794 | Ok(SysControlAddr::new(info.ctl_id, unit)) |
1795 | } |
1796 | |
1797 | /// Return the kernel unique identifier |
1798 | pub const fn id(&self) -> u32 { |
1799 | self.0.sc_id |
1800 | } |
1801 | |
1802 | /// Return the kernel controller private unit number. |
1803 | pub const fn unit(&self) -> u32 { |
1804 | self.0.sc_unit |
1805 | } |
1806 | } |
1807 | |
1808 | impl fmt::Display for SysControlAddr { |
1809 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1810 | fmt::Debug::fmt(self, f) |
1811 | } |
1812 | } |
1813 | } |
1814 | } |
1815 | |
1816 | #[cfg (any(linux_android, target_os = "fuchsia" ))] |
1817 | mod datalink { |
1818 | feature! { |
1819 | #![feature = "net" ] |
1820 | use super::{fmt, mem, private, ptr, SockaddrLike}; |
1821 | |
1822 | /// Hardware Address |
1823 | #[derive (Clone, Copy, Debug, Eq, Hash, PartialEq)] |
1824 | #[repr (transparent)] |
1825 | pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); |
1826 | |
1827 | impl LinkAddr { |
1828 | /// Physical-layer protocol |
1829 | pub fn protocol(&self) -> u16 { |
1830 | self.0.sll_protocol |
1831 | } |
1832 | |
1833 | /// Interface number |
1834 | pub fn ifindex(&self) -> usize { |
1835 | self.0.sll_ifindex as usize |
1836 | } |
1837 | |
1838 | /// ARP hardware type |
1839 | pub fn hatype(&self) -> u16 { |
1840 | self.0.sll_hatype |
1841 | } |
1842 | |
1843 | /// Packet type |
1844 | pub fn pkttype(&self) -> u8 { |
1845 | self.0.sll_pkttype |
1846 | } |
1847 | |
1848 | /// Length of MAC address |
1849 | pub fn halen(&self) -> usize { |
1850 | self.0.sll_halen as usize |
1851 | } |
1852 | |
1853 | /// Physical-layer address (MAC) |
1854 | // Returns an Option just for cross-platform compatibility |
1855 | pub fn addr(&self) -> Option<[u8; 6]> { |
1856 | Some([ |
1857 | self.0.sll_addr[0], |
1858 | self.0.sll_addr[1], |
1859 | self.0.sll_addr[2], |
1860 | self.0.sll_addr[3], |
1861 | self.0.sll_addr[4], |
1862 | self.0.sll_addr[5], |
1863 | ]) |
1864 | } |
1865 | } |
1866 | |
1867 | impl fmt::Display for LinkAddr { |
1868 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1869 | if let Some(addr) = self.addr() { |
1870 | write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}" , |
1871 | addr[0], |
1872 | addr[1], |
1873 | addr[2], |
1874 | addr[3], |
1875 | addr[4], |
1876 | addr[5]) |
1877 | } else { |
1878 | Ok(()) |
1879 | } |
1880 | } |
1881 | } |
1882 | impl private::SockaddrLikePriv for LinkAddr {} |
1883 | impl SockaddrLike for LinkAddr { |
1884 | unsafe fn from_raw(addr: *const libc::sockaddr, |
1885 | len: Option<libc::socklen_t>) |
1886 | -> Option<Self> where Self: Sized |
1887 | { |
1888 | if let Some(l) = len { |
1889 | if l != mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t { |
1890 | return None; |
1891 | } |
1892 | } |
1893 | if unsafe { (*addr).sa_family as i32 != libc::AF_PACKET } { |
1894 | return None; |
1895 | } |
1896 | Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) |
1897 | } |
1898 | } |
1899 | |
1900 | impl AsRef<libc::sockaddr_ll> for LinkAddr { |
1901 | fn as_ref(&self) -> &libc::sockaddr_ll { |
1902 | &self.0 |
1903 | } |
1904 | } |
1905 | |
1906 | } |
1907 | } |
1908 | |
1909 | #[cfg (any(bsd, solarish, target_os = "haiku" , target_os = "aix" ))] |
1910 | mod datalink { |
1911 | feature! { |
1912 | #![feature = "net" ] |
1913 | use super::{fmt, mem, private, ptr, SockaddrLike}; |
1914 | |
1915 | /// Hardware Address |
1916 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
1917 | #[repr(transparent)] |
1918 | pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); |
1919 | |
1920 | impl LinkAddr { |
1921 | /// interface index, if != 0, system given index for interface |
1922 | #[cfg(not(target_os = "haiku" ))] |
1923 | pub fn ifindex(&self) -> usize { |
1924 | self.0.sdl_index as usize |
1925 | } |
1926 | |
1927 | /// Datalink type |
1928 | #[cfg(not(target_os = "haiku" ))] |
1929 | pub fn datalink_type(&self) -> u8 { |
1930 | self.0.sdl_type |
1931 | } |
1932 | |
1933 | /// MAC address start position |
1934 | pub fn nlen(&self) -> usize { |
1935 | self.0.sdl_nlen as usize |
1936 | } |
1937 | |
1938 | /// link level address length |
1939 | pub fn alen(&self) -> usize { |
1940 | self.0.sdl_alen as usize |
1941 | } |
1942 | |
1943 | /// link layer selector length |
1944 | #[cfg(not(target_os = "haiku" ))] |
1945 | pub fn slen(&self) -> usize { |
1946 | self.0.sdl_slen as usize |
1947 | } |
1948 | |
1949 | /// if link level address length == 0, |
1950 | /// or `sdl_data` not be larger. |
1951 | pub fn is_empty(&self) -> bool { |
1952 | let nlen = self.nlen(); |
1953 | let alen = self.alen(); |
1954 | let data_len = self.0.sdl_data.len(); |
1955 | |
1956 | alen == 0 || nlen + alen >= data_len |
1957 | } |
1958 | |
1959 | /// Physical-layer address (MAC) |
1960 | // The cast is not unnecessary on all platforms. |
1961 | #[allow(clippy::unnecessary_cast)] |
1962 | pub fn addr(&self) -> Option<[u8; 6]> { |
1963 | let nlen = self.nlen(); |
1964 | let data = self.0.sdl_data; |
1965 | |
1966 | if self.is_empty() { |
1967 | None |
1968 | } else { |
1969 | Some([ |
1970 | data[nlen] as u8, |
1971 | data[nlen + 1] as u8, |
1972 | data[nlen + 2] as u8, |
1973 | data[nlen + 3] as u8, |
1974 | data[nlen + 4] as u8, |
1975 | data[nlen + 5] as u8, |
1976 | ]) |
1977 | } |
1978 | } |
1979 | } |
1980 | |
1981 | impl fmt::Display for LinkAddr { |
1982 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1983 | if let Some(addr) = self.addr() { |
1984 | write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}" , |
1985 | addr[0], |
1986 | addr[1], |
1987 | addr[2], |
1988 | addr[3], |
1989 | addr[4], |
1990 | addr[5]) |
1991 | } else { |
1992 | Ok(()) |
1993 | } |
1994 | } |
1995 | } |
1996 | impl private::SockaddrLikePriv for LinkAddr {} |
1997 | impl SockaddrLike for LinkAddr { |
1998 | unsafe fn from_raw(addr: *const libc::sockaddr, |
1999 | len: Option<libc::socklen_t>) |
2000 | -> Option<Self> where Self: Sized |
2001 | { |
2002 | if let Some(l) = len { |
2003 | if l != mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t { |
2004 | return None; |
2005 | } |
2006 | } |
2007 | if unsafe { (*addr).sa_family as i32 != libc::AF_LINK } { |
2008 | return None; |
2009 | } |
2010 | Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) |
2011 | } |
2012 | } |
2013 | |
2014 | impl AsRef<libc::sockaddr_dl> for LinkAddr { |
2015 | fn as_ref(&self) -> &libc::sockaddr_dl { |
2016 | &self.0 |
2017 | } |
2018 | } |
2019 | } |
2020 | } |
2021 | |
2022 | #[cfg (any(linux_android, apple_targets))] |
2023 | pub mod vsock { |
2024 | use super::*; |
2025 | use crate::sys::socket::addr::AddressFamily; |
2026 | use libc::{sa_family_t, sockaddr_vm}; |
2027 | use std::hash::{Hash, Hasher}; |
2028 | use std::{fmt, mem}; |
2029 | |
2030 | /// Socket address for VMWare VSockets protocol |
2031 | /// |
2032 | /// # References |
2033 | /// |
2034 | /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html) |
2035 | #[derive (Copy, Clone)] |
2036 | #[repr (transparent)] |
2037 | pub struct VsockAddr(pub(in super::super) sockaddr_vm); |
2038 | |
2039 | impl private::SockaddrLikePriv for VsockAddr {} |
2040 | impl SockaddrLike for VsockAddr { |
2041 | unsafe fn from_raw( |
2042 | addr: *const libc::sockaddr, |
2043 | len: Option<libc::socklen_t>, |
2044 | ) -> Option<Self> |
2045 | where |
2046 | Self: Sized, |
2047 | { |
2048 | if let Some(l) = len { |
2049 | if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t { |
2050 | return None; |
2051 | } |
2052 | } |
2053 | if unsafe { (*addr).sa_family as i32 != libc::AF_VSOCK } { |
2054 | return None; |
2055 | } |
2056 | unsafe { Some(Self(ptr::read_unaligned(addr as *const _))) } |
2057 | } |
2058 | } |
2059 | |
2060 | impl AsRef<libc::sockaddr_vm> for VsockAddr { |
2061 | fn as_ref(&self) -> &libc::sockaddr_vm { |
2062 | &self.0 |
2063 | } |
2064 | } |
2065 | |
2066 | impl PartialEq for VsockAddr { |
2067 | #[cfg (linux_android)] |
2068 | fn eq(&self, other: &Self) -> bool { |
2069 | let (inner, other) = (self.0, other.0); |
2070 | (inner.svm_family, inner.svm_cid, inner.svm_port) |
2071 | == (other.svm_family, other.svm_cid, other.svm_port) |
2072 | } |
2073 | #[cfg (apple_targets)] |
2074 | fn eq(&self, other: &Self) -> bool { |
2075 | let (inner, other) = (self.0, other.0); |
2076 | ( |
2077 | inner.svm_family, |
2078 | inner.svm_cid, |
2079 | inner.svm_port, |
2080 | inner.svm_len, |
2081 | ) == ( |
2082 | other.svm_family, |
2083 | other.svm_cid, |
2084 | other.svm_port, |
2085 | inner.svm_len, |
2086 | ) |
2087 | } |
2088 | } |
2089 | |
2090 | impl Eq for VsockAddr {} |
2091 | |
2092 | impl Hash for VsockAddr { |
2093 | #[cfg (linux_android)] |
2094 | fn hash<H: Hasher>(&self, s: &mut H) { |
2095 | let inner = self.0; |
2096 | (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); |
2097 | } |
2098 | #[cfg (apple_targets)] |
2099 | fn hash<H: Hasher>(&self, s: &mut H) { |
2100 | let inner = self.0; |
2101 | ( |
2102 | inner.svm_family, |
2103 | inner.svm_cid, |
2104 | inner.svm_port, |
2105 | inner.svm_len, |
2106 | ) |
2107 | .hash(s); |
2108 | } |
2109 | } |
2110 | |
2111 | /// VSOCK Address |
2112 | /// |
2113 | /// The address for AF_VSOCK socket is defined as a combination of a |
2114 | /// 32-bit Context Identifier (CID) and a 32-bit port number. |
2115 | impl VsockAddr { |
2116 | /// Construct a `VsockAddr` from its raw fields. |
2117 | pub fn new(cid: u32, port: u32) -> VsockAddr { |
2118 | let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; |
2119 | addr.svm_family = AddressFamily::Vsock as sa_family_t; |
2120 | addr.svm_cid = cid; |
2121 | addr.svm_port = port; |
2122 | |
2123 | #[cfg (apple_targets)] |
2124 | { |
2125 | addr.svm_len = std::mem::size_of::<sockaddr_vm>() as u8; |
2126 | } |
2127 | VsockAddr(addr) |
2128 | } |
2129 | |
2130 | /// Context Identifier (CID) |
2131 | pub fn cid(&self) -> u32 { |
2132 | self.0.svm_cid |
2133 | } |
2134 | |
2135 | /// Port number |
2136 | pub fn port(&self) -> u32 { |
2137 | self.0.svm_port |
2138 | } |
2139 | } |
2140 | |
2141 | impl fmt::Display for VsockAddr { |
2142 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
2143 | write!(f, "cid: {} port: {}" , self.cid(), self.port()) |
2144 | } |
2145 | } |
2146 | |
2147 | impl fmt::Debug for VsockAddr { |
2148 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
2149 | fmt::Display::fmt(self, f) |
2150 | } |
2151 | } |
2152 | } |
2153 | |
2154 | #[cfg (test)] |
2155 | mod tests { |
2156 | use super::*; |
2157 | |
2158 | mod types { |
2159 | use super::*; |
2160 | |
2161 | #[test ] |
2162 | fn test_ipv4addr_to_libc() { |
2163 | let s = std::net::Ipv4Addr::new(1, 2, 3, 4); |
2164 | let l = ipv4addr_to_libc(s); |
2165 | assert_eq!(l.s_addr, u32::to_be(0x01020304)); |
2166 | } |
2167 | |
2168 | #[test ] |
2169 | fn test_ipv6addr_to_libc() { |
2170 | let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); |
2171 | let l = ipv6addr_to_libc(&s); |
2172 | assert_eq!( |
2173 | l.s6_addr, |
2174 | [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8] |
2175 | ); |
2176 | } |
2177 | } |
2178 | |
2179 | #[cfg (not(any(target_os = "hurd" , target_os = "redox" )))] |
2180 | #[allow (clippy::cast_ptr_alignment)] |
2181 | mod link { |
2182 | #[cfg (any(apple_targets, solarish))] |
2183 | use super::super::super::socklen_t; |
2184 | use super::*; |
2185 | |
2186 | /// Don't panic when trying to display an empty datalink address |
2187 | #[cfg (bsd)] |
2188 | #[test ] |
2189 | fn test_datalink_display() { |
2190 | use super::super::LinkAddr; |
2191 | use std::mem; |
2192 | |
2193 | let la = LinkAddr(libc::sockaddr_dl { |
2194 | sdl_len: 56, |
2195 | sdl_family: 18, |
2196 | sdl_index: 5, |
2197 | sdl_type: 24, |
2198 | sdl_nlen: 3, |
2199 | sdl_alen: 0, |
2200 | sdl_slen: 0, |
2201 | ..unsafe { mem::zeroed() } |
2202 | }); |
2203 | format!("{la}" ); |
2204 | } |
2205 | |
2206 | #[cfg (all( |
2207 | any(linux_android, target_os = "fuchsia" ), |
2208 | target_endian = "little" |
2209 | ))] |
2210 | #[test ] |
2211 | fn linux_loopback() { |
2212 | #[repr (align(2))] |
2213 | struct Raw([u8; 20]); |
2214 | |
2215 | let bytes = Raw([ |
2216 | 17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0, |
2217 | ]); |
2218 | let sa = bytes.0.as_ptr().cast(); |
2219 | let len = None; |
2220 | let sock_addr = |
2221 | unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); |
2222 | assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); |
2223 | match sock_addr.as_link_addr() { |
2224 | Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])), |
2225 | None => panic!("Can't unwrap sockaddr storage" ), |
2226 | } |
2227 | } |
2228 | |
2229 | #[cfg (apple_targets)] |
2230 | #[test ] |
2231 | fn macos_loopback() { |
2232 | let bytes = |
2233 | [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; |
2234 | let sa = bytes.as_ptr().cast(); |
2235 | let len = Some(bytes.len() as socklen_t); |
2236 | let sock_addr = |
2237 | unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); |
2238 | assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); |
2239 | match sock_addr.as_link_addr() { |
2240 | Some(dl) => { |
2241 | assert!(dl.addr().is_none()); |
2242 | } |
2243 | None => panic!("Can't unwrap sockaddr storage" ), |
2244 | } |
2245 | } |
2246 | |
2247 | #[cfg (apple_targets)] |
2248 | #[test ] |
2249 | fn macos_tap() { |
2250 | let bytes = [ |
2251 | 20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, |
2252 | 76, -80, |
2253 | ]; |
2254 | let ptr = bytes.as_ptr(); |
2255 | let sa = ptr as *const libc::sockaddr; |
2256 | let len = Some(bytes.len() as socklen_t); |
2257 | |
2258 | let sock_addr = |
2259 | unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; |
2260 | assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); |
2261 | match sock_addr.as_link_addr() { |
2262 | Some(dl) => { |
2263 | assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176])) |
2264 | } |
2265 | None => panic!("Can't unwrap sockaddr storage" ), |
2266 | } |
2267 | } |
2268 | |
2269 | #[cfg (solarish)] |
2270 | #[test ] |
2271 | fn solarish_tap() { |
2272 | let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; |
2273 | let ptr = bytes.as_ptr(); |
2274 | let sa = ptr as *const libc::sockaddr; |
2275 | let len = Some(bytes.len() as socklen_t); |
2276 | let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }; |
2277 | |
2278 | assert!(_sock_addr.is_some()); |
2279 | |
2280 | let sock_addr = _sock_addr.unwrap(); |
2281 | |
2282 | assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); |
2283 | |
2284 | assert_eq!( |
2285 | sock_addr.as_link_addr().unwrap().addr(), |
2286 | Some([24u8, 101, 144, 221, 76, 176]) |
2287 | ); |
2288 | } |
2289 | |
2290 | #[test ] |
2291 | fn size() { |
2292 | #[cfg (any(bsd, target_os = "aix" , solarish, target_os = "haiku" ))] |
2293 | let l = mem::size_of::<libc::sockaddr_dl>(); |
2294 | #[cfg (any(linux_android, target_os = "fuchsia" ))] |
2295 | let l = mem::size_of::<libc::sockaddr_ll>(); |
2296 | assert_eq!(LinkAddr::size() as usize, l); |
2297 | } |
2298 | } |
2299 | |
2300 | mod sockaddr_in { |
2301 | use super::*; |
2302 | use std::str::FromStr; |
2303 | |
2304 | #[test ] |
2305 | fn display() { |
2306 | let s = "127.0.0.1:8080" ; |
2307 | let addr = SockaddrIn::from_str(s).unwrap(); |
2308 | assert_eq!(s, format!("{addr}" )); |
2309 | } |
2310 | |
2311 | #[test ] |
2312 | fn size() { |
2313 | assert_eq!( |
2314 | mem::size_of::<libc::sockaddr_in>(), |
2315 | SockaddrIn::size() as usize |
2316 | ); |
2317 | } |
2318 | |
2319 | #[test ] |
2320 | fn ip() { |
2321 | let s = "127.0.0.1:8082" ; |
2322 | let ip = SockaddrIn::from_str(s).unwrap().ip(); |
2323 | assert_eq!("127.0.0.1" , format!("{ip}" )); |
2324 | } |
2325 | } |
2326 | |
2327 | mod sockaddr_in6 { |
2328 | use super::*; |
2329 | use std::str::FromStr; |
2330 | |
2331 | #[test ] |
2332 | fn display() { |
2333 | let s = "[1234:5678:90ab:cdef::1111:2222]:8080" ; |
2334 | let addr = SockaddrIn6::from_str(s).unwrap(); |
2335 | assert_eq!(s, format!("{addr}" )); |
2336 | } |
2337 | |
2338 | #[test ] |
2339 | fn size() { |
2340 | assert_eq!( |
2341 | mem::size_of::<libc::sockaddr_in6>(), |
2342 | SockaddrIn6::size() as usize |
2343 | ); |
2344 | } |
2345 | |
2346 | #[test ] |
2347 | fn ip() { |
2348 | let s = "[1234:5678:90ab:cdef::1111:2222]:8080" ; |
2349 | let ip = SockaddrIn6::from_str(s).unwrap().ip(); |
2350 | assert_eq!("1234:5678:90ab:cdef::1111:2222" , format!("{ip}" )); |
2351 | } |
2352 | |
2353 | #[test ] |
2354 | // Ensure that we can convert to-and-from std::net variants without change. |
2355 | fn to_and_from() { |
2356 | let s = "[1234:5678:90ab:cdef::1111:2222]:8080" ; |
2357 | let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap(); |
2358 | nix_sin6.0.sin6_flowinfo = 0x12345678; |
2359 | nix_sin6.0.sin6_scope_id = 0x9abcdef0; |
2360 | |
2361 | let std_sin6: std::net::SocketAddrV6 = nix_sin6.into(); |
2362 | assert_eq!(nix_sin6, std_sin6.into()); |
2363 | } |
2364 | } |
2365 | |
2366 | mod sockaddr_storage { |
2367 | use super::*; |
2368 | |
2369 | #[test ] |
2370 | fn from_sockaddr_un_named() { |
2371 | let ua = UnixAddr::new("/var/run/mysock" ).unwrap(); |
2372 | let ptr = ua.as_ptr().cast(); |
2373 | let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } |
2374 | .unwrap(); |
2375 | assert_eq!(ss.len(), ua.len()); |
2376 | } |
2377 | |
2378 | #[cfg (linux_android)] |
2379 | #[test ] |
2380 | fn from_sockaddr_un_abstract_named() { |
2381 | let name = String::from("nix \0abstract \0test" ); |
2382 | let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); |
2383 | let ptr = ua.as_ptr().cast(); |
2384 | let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } |
2385 | .unwrap(); |
2386 | assert_eq!(ss.len(), ua.len()); |
2387 | } |
2388 | |
2389 | #[cfg (linux_android)] |
2390 | #[test ] |
2391 | fn from_sockaddr_un_abstract_unnamed() { |
2392 | let ua = UnixAddr::new_unnamed(); |
2393 | let ptr = ua.as_ptr().cast(); |
2394 | let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } |
2395 | .unwrap(); |
2396 | assert_eq!(ss.len(), ua.len()); |
2397 | } |
2398 | } |
2399 | |
2400 | mod unixaddr { |
2401 | use super::*; |
2402 | |
2403 | #[cfg (linux_android)] |
2404 | #[test ] |
2405 | fn abstract_sun_path() { |
2406 | let name = String::from("nix \0abstract \0test" ); |
2407 | let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); |
2408 | |
2409 | let sun_path1 = |
2410 | unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; |
2411 | let sun_path2 = [ |
2412 | 0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, |
2413 | 116, 101, 115, 116, |
2414 | ]; |
2415 | assert_eq!(sun_path1, sun_path2); |
2416 | } |
2417 | |
2418 | #[test ] |
2419 | fn size() { |
2420 | assert_eq!( |
2421 | mem::size_of::<libc::sockaddr_un>(), |
2422 | UnixAddr::size() as usize |
2423 | ); |
2424 | } |
2425 | } |
2426 | } |
2427 | |