nix/sys/socket/
addr.rs

1#[cfg(any(
2    target_os = "android",
3    target_os = "dragonfly",
4    target_os = "freebsd",
5    target_os = "ios",
6    target_os = "linux",
7    target_os = "macos",
8    target_os = "illumos",
9    target_os = "netbsd",
10    target_os = "openbsd",
11    target_os = "haiku",
12    target_os = "fuchsia"
13))]
14#[cfg(feature = "net")]
15pub use self::datalink::LinkAddr;
16#[cfg(any(target_os = "android", target_os = "linux"))]
17pub use self::vsock::VsockAddr;
18use super::sa_family_t;
19use crate::errno::Errno;
20#[cfg(any(target_os = "android", target_os = "linux"))]
21use crate::sys::socket::addr::alg::AlgAddr;
22#[cfg(any(target_os = "android", target_os = "linux"))]
23use crate::sys::socket::addr::netlink::NetlinkAddr;
24#[cfg(all(
25    feature = "ioctl",
26    any(target_os = "ios", target_os = "macos")
27))]
28use crate::sys::socket::addr::sys_control::SysControlAddr;
29use crate::{NixPath, Result};
30use cfg_if::cfg_if;
31use memoffset::offset_of;
32use std::convert::TryInto;
33use std::ffi::OsStr;
34use std::hash::{Hash, Hasher};
35use std::os::unix::ffi::OsStrExt;
36#[cfg(any(target_os = "ios", target_os = "macos"))]
37use std::os::unix::io::RawFd;
38use std::path::Path;
39use std::{fmt, mem, net, ptr, slice};
40
41/// Convert a std::net::Ipv4Addr into the libc form.
42#[cfg(feature = "net")]
43pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr {
44    libc::in_addr {
45        s_addr: u32::from_ne_bytes(addr.octets())
46    }
47}
48
49/// Convert a std::net::Ipv6Addr into the libc form.
50#[cfg(feature = "net")]
51pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
52    libc::in6_addr {
53        s6_addr: addr.octets()
54    }
55}
56
57/// These constants specify the protocol family to be used
58/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
59///
60/// # References
61///
62/// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html)
63// Should this be u8?
64#[repr(i32)]
65#[non_exhaustive]
66#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
67pub enum AddressFamily {
68    /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html))
69    Unix = libc::AF_UNIX,
70    /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html))
71    Inet = libc::AF_INET,
72    /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html))
73    Inet6 = libc::AF_INET6,
74    /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html))
75    #[cfg(any(target_os = "android", target_os = "linux"))]
76    #[cfg_attr(docsrs, doc(cfg(all())))]
77    Netlink = libc::AF_NETLINK,
78    /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html))
79    #[cfg(any(
80        target_os = "android",
81        target_os = "linux",
82        target_os = "illumos",
83        target_os = "fuchsia",
84        target_os = "solaris"
85    ))]
86    #[cfg_attr(docsrs, doc(cfg(all())))]
87    Packet = libc::AF_PACKET,
88    /// KEXT Controls and Notifications
89    #[cfg(any(target_os = "ios", target_os = "macos"))]
90    #[cfg_attr(docsrs, doc(cfg(all())))]
91    System = libc::AF_SYSTEM,
92    /// Amateur radio AX.25 protocol
93    #[cfg(any(target_os = "android", target_os = "linux"))]
94    #[cfg_attr(docsrs, doc(cfg(all())))]
95    Ax25 = libc::AF_AX25,
96    /// IPX - Novell protocols
97    Ipx = libc::AF_IPX,
98    /// AppleTalk
99    AppleTalk = libc::AF_APPLETALK,
100    /// AX.25 packet layer protocol.
101    /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/))
102    #[cfg(any(target_os = "android", target_os = "linux"))]
103    #[cfg_attr(docsrs, doc(cfg(all())))]
104    NetRom = libc::AF_NETROM,
105    /// Can't be used for creating sockets; mostly used for bridge
106    /// links in
107    /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html)
108    /// protocol commands.
109    #[cfg(any(target_os = "android", target_os = "linux"))]
110    #[cfg_attr(docsrs, doc(cfg(all())))]
111    Bridge = libc::AF_BRIDGE,
112    /// Access to raw ATM PVCs
113    #[cfg(any(target_os = "android", target_os = "linux"))]
114    #[cfg_attr(docsrs, doc(cfg(all())))]
115    AtmPvc = libc::AF_ATMPVC,
116    /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html))
117    #[cfg(any(target_os = "android", target_os = "linux"))]
118    #[cfg_attr(docsrs, doc(cfg(all())))]
119    X25 = libc::AF_X25,
120    /// RATS (Radio Amateur Telecommunications Society) Open
121    /// Systems environment (ROSE) AX.25 packet layer protocol.
122    /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/))
123    #[cfg(any(target_os = "android", target_os = "linux"))]
124    #[cfg_attr(docsrs, doc(cfg(all())))]
125    Rose = libc::AF_ROSE,
126    /// DECet protocol sockets.
127    #[cfg(not(target_os = "haiku"))]
128    Decnet = libc::AF_DECnet,
129    /// Reserved for "802.2LLC project"; never used.
130    #[cfg(any(target_os = "android", target_os = "linux"))]
131    #[cfg_attr(docsrs, doc(cfg(all())))]
132    NetBeui = libc::AF_NETBEUI,
133    /// This was a short-lived (between Linux 2.1.30 and
134    /// 2.1.99pre2) protocol family for firewall upcalls.
135    #[cfg(any(target_os = "android", target_os = "linux"))]
136    #[cfg_attr(docsrs, doc(cfg(all())))]
137    Security = libc::AF_SECURITY,
138    /// Key management protocol.
139    #[cfg(any(target_os = "android", target_os = "linux"))]
140    #[cfg_attr(docsrs, doc(cfg(all())))]
141    Key = libc::AF_KEY,
142    #[allow(missing_docs)] // Not documented anywhere that I can find
143    #[cfg(any(target_os = "android", target_os = "linux"))]
144    #[cfg_attr(docsrs, doc(cfg(all())))]
145    Ash = libc::AF_ASH,
146    /// Acorn Econet protocol
147    #[cfg(any(target_os = "android", target_os = "linux"))]
148    #[cfg_attr(docsrs, doc(cfg(all())))]
149    Econet = libc::AF_ECONET,
150    /// Access to ATM Switched Virtual Circuits
151    #[cfg(any(target_os = "android", target_os = "linux"))]
152    #[cfg_attr(docsrs, doc(cfg(all())))]
153    AtmSvc = libc::AF_ATMSVC,
154    /// Reliable Datagram Sockets (RDS) protocol
155    #[cfg(any(target_os = "android", target_os = "linux"))]
156    #[cfg_attr(docsrs, doc(cfg(all())))]
157    Rds = libc::AF_RDS,
158    /// IBM SNA
159    #[cfg(not(target_os = "haiku"))]
160    Sna = libc::AF_SNA,
161    /// Socket interface over IrDA
162    #[cfg(any(target_os = "android", target_os = "linux"))]
163    #[cfg_attr(docsrs, doc(cfg(all())))]
164    Irda = libc::AF_IRDA,
165    /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE)
166    #[cfg(any(target_os = "android", target_os = "linux"))]
167    #[cfg_attr(docsrs, doc(cfg(all())))]
168    Pppox = libc::AF_PPPOX,
169    /// Legacy protocol for wide area network (WAN) connectivity that was used
170    /// by Sangoma WAN cards
171    #[cfg(any(target_os = "android", target_os = "linux"))]
172    #[cfg_attr(docsrs, doc(cfg(all())))]
173    Wanpipe = libc::AF_WANPIPE,
174    /// Logical link control (IEEE 802.2 LLC) protocol
175    #[cfg(any(target_os = "android", target_os = "linux"))]
176    #[cfg_attr(docsrs, doc(cfg(all())))]
177    Llc = libc::AF_LLC,
178    /// InfiniBand native addressing
179    #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
180    #[cfg_attr(docsrs, doc(cfg(all())))]
181    Ib = libc::AF_IB,
182    /// Multiprotocol Label Switching
183    #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
184    #[cfg_attr(docsrs, doc(cfg(all())))]
185    Mpls = libc::AF_MPLS,
186    /// Controller Area Network automotive bus protocol
187    #[cfg(any(target_os = "android", target_os = "linux"))]
188    #[cfg_attr(docsrs, doc(cfg(all())))]
189    Can = libc::AF_CAN,
190    /// TIPC, "cluster domain sockets" protocol
191    #[cfg(any(target_os = "android", target_os = "linux"))]
192    #[cfg_attr(docsrs, doc(cfg(all())))]
193    Tipc = libc::AF_TIPC,
194    /// Bluetooth low-level socket protocol
195    #[cfg(not(any(
196        target_os = "illumos",
197        target_os = "ios",
198        target_os = "macos",
199        target_os = "solaris"
200    )))]
201    #[cfg_attr(docsrs, doc(cfg(all())))]
202    Bluetooth = libc::AF_BLUETOOTH,
203    /// IUCV (inter-user communication vehicle) z/VM protocol for
204    /// hypervisor-guest interaction
205    #[cfg(any(target_os = "android", target_os = "linux"))]
206    #[cfg_attr(docsrs, doc(cfg(all())))]
207    Iucv = libc::AF_IUCV,
208    /// Rx, Andrew File System remote procedure call protocol
209    #[cfg(any(target_os = "android", target_os = "linux"))]
210    #[cfg_attr(docsrs, doc(cfg(all())))]
211    RxRpc = libc::AF_RXRPC,
212    /// New "modular ISDN" driver interface protocol
213    #[cfg(not(any(
214        target_os = "illumos",
215        target_os = "solaris",
216        target_os = "haiku"
217    )))]
218    #[cfg_attr(docsrs, doc(cfg(all())))]
219    Isdn = libc::AF_ISDN,
220    /// Nokia cellular modem IPC/RPC interface
221    #[cfg(any(target_os = "android", target_os = "linux"))]
222    #[cfg_attr(docsrs, doc(cfg(all())))]
223    Phonet = libc::AF_PHONET,
224    /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol
225    #[cfg(any(target_os = "android", target_os = "linux"))]
226    #[cfg_attr(docsrs, doc(cfg(all())))]
227    Ieee802154 = libc::AF_IEEE802154,
228    /// Ericsson's Communication CPU to Application CPU interface (CAIF)
229    /// protocol.
230    #[cfg(any(target_os = "android", target_os = "linux"))]
231    #[cfg_attr(docsrs, doc(cfg(all())))]
232    Caif = libc::AF_CAIF,
233    /// Interface to kernel crypto API
234    #[cfg(any(target_os = "android", target_os = "linux"))]
235    #[cfg_attr(docsrs, doc(cfg(all())))]
236    Alg = libc::AF_ALG,
237    /// Near field communication
238    #[cfg(target_os = "linux")]
239    #[cfg_attr(docsrs, doc(cfg(all())))]
240    Nfc = libc::AF_NFC,
241    /// VMWare VSockets protocol for hypervisor-guest interaction.
242    #[cfg(any(target_os = "android", target_os = "linux"))]
243    #[cfg_attr(docsrs, doc(cfg(all())))]
244    Vsock = libc::AF_VSOCK,
245    /// ARPANet IMP addresses
246    #[cfg(any(
247        target_os = "dragonfly",
248        target_os = "freebsd",
249        target_os = "ios",
250        target_os = "macos",
251        target_os = "netbsd",
252        target_os = "openbsd"
253    ))]
254    #[cfg_attr(docsrs, doc(cfg(all())))]
255    ImpLink = libc::AF_IMPLINK,
256    /// PUP protocols, e.g. BSP
257    #[cfg(any(
258        target_os = "dragonfly",
259        target_os = "freebsd",
260        target_os = "ios",
261        target_os = "macos",
262        target_os = "netbsd",
263        target_os = "openbsd"
264    ))]
265    #[cfg_attr(docsrs, doc(cfg(all())))]
266    Pup = libc::AF_PUP,
267    /// MIT CHAOS protocols
268    #[cfg(any(
269        target_os = "dragonfly",
270        target_os = "freebsd",
271        target_os = "ios",
272        target_os = "macos",
273        target_os = "netbsd",
274        target_os = "openbsd"
275    ))]
276    #[cfg_attr(docsrs, doc(cfg(all())))]
277    Chaos = libc::AF_CHAOS,
278    /// Novell and Xerox protocol
279    #[cfg(any(
280        target_os = "ios",
281        target_os = "macos",
282        target_os = "netbsd",
283        target_os = "openbsd"
284    ))]
285    #[cfg_attr(docsrs, doc(cfg(all())))]
286    Ns = libc::AF_NS,
287    #[allow(missing_docs)] // Not documented anywhere that I can find
288    #[cfg(any(
289        target_os = "dragonfly",
290        target_os = "freebsd",
291        target_os = "ios",
292        target_os = "macos",
293        target_os = "netbsd",
294        target_os = "openbsd"
295    ))]
296    #[cfg_attr(docsrs, doc(cfg(all())))]
297    Iso = libc::AF_ISO,
298    /// Bell Labs virtual circuit switch ?
299    #[cfg(any(
300        target_os = "dragonfly",
301        target_os = "freebsd",
302        target_os = "ios",
303        target_os = "macos",
304        target_os = "netbsd",
305        target_os = "openbsd"
306    ))]
307    #[cfg_attr(docsrs, doc(cfg(all())))]
308    Datakit = libc::AF_DATAKIT,
309    /// CCITT protocols, X.25 etc
310    #[cfg(any(
311        target_os = "dragonfly",
312        target_os = "freebsd",
313        target_os = "ios",
314        target_os = "macos",
315        target_os = "netbsd",
316        target_os = "openbsd"
317    ))]
318    #[cfg_attr(docsrs, doc(cfg(all())))]
319    Ccitt = libc::AF_CCITT,
320    /// DEC Direct data link interface
321    #[cfg(any(
322        target_os = "dragonfly",
323        target_os = "freebsd",
324        target_os = "ios",
325        target_os = "macos",
326        target_os = "netbsd",
327        target_os = "openbsd"
328    ))]
329    #[cfg_attr(docsrs, doc(cfg(all())))]
330    Dli = libc::AF_DLI,
331    #[allow(missing_docs)] // Not documented anywhere that I can find
332    #[cfg(any(
333        target_os = "dragonfly",
334        target_os = "freebsd",
335        target_os = "ios",
336        target_os = "macos",
337        target_os = "netbsd",
338        target_os = "openbsd"
339    ))]
340    #[cfg_attr(docsrs, doc(cfg(all())))]
341    Lat = libc::AF_LAT,
342    /// NSC Hyperchannel
343    #[cfg(any(
344        target_os = "dragonfly",
345        target_os = "freebsd",
346        target_os = "ios",
347        target_os = "macos",
348        target_os = "netbsd",
349        target_os = "openbsd"
350    ))]
351    #[cfg_attr(docsrs, doc(cfg(all())))]
352    Hylink = libc::AF_HYLINK,
353    /// Link layer interface
354    #[cfg(any(
355        target_os = "dragonfly",
356        target_os = "freebsd",
357        target_os = "ios",
358        target_os = "macos",
359        target_os = "illumos",
360        target_os = "netbsd",
361        target_os = "openbsd"
362    ))]
363    #[cfg_attr(docsrs, doc(cfg(all())))]
364    Link = libc::AF_LINK,
365    /// connection-oriented IP, aka ST II
366    #[cfg(any(
367        target_os = "dragonfly",
368        target_os = "freebsd",
369        target_os = "ios",
370        target_os = "macos",
371        target_os = "netbsd",
372        target_os = "openbsd"
373    ))]
374    #[cfg_attr(docsrs, doc(cfg(all())))]
375    Coip = libc::AF_COIP,
376    /// Computer Network Technology
377    #[cfg(any(
378        target_os = "dragonfly",
379        target_os = "freebsd",
380        target_os = "ios",
381        target_os = "macos",
382        target_os = "netbsd",
383        target_os = "openbsd"
384    ))]
385    #[cfg_attr(docsrs, doc(cfg(all())))]
386    Cnt = libc::AF_CNT,
387    /// Native ATM access
388    #[cfg(any(
389        target_os = "dragonfly",
390        target_os = "freebsd",
391        target_os = "ios",
392        target_os = "macos",
393        target_os = "netbsd",
394        target_os = "openbsd"
395    ))]
396    #[cfg_attr(docsrs, doc(cfg(all())))]
397    Natm = libc::AF_NATM,
398    /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
399    #[cfg(any(target_os = "android", target_os = "linux"))]
400    #[cfg_attr(docsrs, doc(cfg(all())))]
401    Unspec = libc::AF_UNSPEC,
402}
403
404impl AddressFamily {
405    /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
406    /// the `sa_family` field of a `sockaddr`.
407    ///
408    /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
409    /// and System. Returns None for unsupported or unknown address families.
410    pub const fn from_i32(family: i32) -> Option<AddressFamily> {
411        match family {
412            libc::AF_UNIX => Some(AddressFamily::Unix),
413            libc::AF_INET => Some(AddressFamily::Inet),
414            libc::AF_INET6 => Some(AddressFamily::Inet6),
415            #[cfg(any(target_os = "android", target_os = "linux"))]
416            libc::AF_NETLINK => Some(AddressFamily::Netlink),
417            #[cfg(any(target_os = "macos", target_os = "macos"))]
418            libc::AF_SYSTEM => Some(AddressFamily::System),
419            #[cfg(any(target_os = "android", target_os = "linux"))]
420            libc::AF_PACKET => Some(AddressFamily::Packet),
421            #[cfg(any(
422                target_os = "dragonfly",
423                target_os = "freebsd",
424                target_os = "ios",
425                target_os = "macos",
426                target_os = "netbsd",
427                target_os = "illumos",
428                target_os = "openbsd"
429            ))]
430            libc::AF_LINK => Some(AddressFamily::Link),
431            #[cfg(any(target_os = "android", target_os = "linux"))]
432            libc::AF_VSOCK => Some(AddressFamily::Vsock),
433            _ => None,
434        }
435    }
436}
437
438feature! {
439#![feature = "net"]
440
441#[deprecated(
442    since = "0.24.0",
443    note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead"
444)]
445#[allow(missing_docs)]  // Since they're all deprecated anyway
446#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
447pub enum InetAddr {
448    V4(libc::sockaddr_in),
449    V6(libc::sockaddr_in6),
450}
451
452#[allow(missing_docs)]  // It's deprecated anyway
453#[allow(deprecated)]
454impl InetAddr {
455    #[allow(clippy::needless_update)]   // It isn't needless on all OSes
456    pub fn from_std(std: &net::SocketAddr) -> InetAddr {
457        match *std {
458            net::SocketAddr::V4(ref addr) => {
459                InetAddr::V4(libc::sockaddr_in {
460                    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
461                              target_os = "haiku", target_os = "hermit",
462                              target_os = "ios", target_os = "macos",
463                              target_os = "netbsd", target_os = "openbsd"))]
464                    sin_len: mem::size_of::<libc::sockaddr_in>() as u8,
465                    sin_family: AddressFamily::Inet as sa_family_t,
466                    sin_port: addr.port().to_be(),  // network byte order
467                    sin_addr: Ipv4Addr::from_std(addr.ip()).0,
468                    .. unsafe { mem::zeroed() }
469                })
470            }
471            net::SocketAddr::V6(ref addr) => {
472                InetAddr::V6(libc::sockaddr_in6 {
473                    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
474                              target_os = "haiku", target_os = "hermit",
475                              target_os = "ios", target_os = "macos",
476                              target_os = "netbsd", target_os = "openbsd"))]
477                    sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8,
478                    sin6_family: AddressFamily::Inet6 as sa_family_t,
479                    sin6_port: addr.port().to_be(),  // network byte order
480                    sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
481                    sin6_flowinfo: addr.flowinfo(),  // host byte order
482                    sin6_scope_id: addr.scope_id(),  // host byte order
483                    .. unsafe { mem::zeroed() }
484                })
485            }
486        }
487    }
488
489    #[allow(clippy::needless_update)]   // It isn't needless on all OSes
490    pub fn new(ip: IpAddr, port: u16) -> InetAddr {
491        match ip {
492            IpAddr::V4(ref ip) => {
493                InetAddr::V4(libc::sockaddr_in {
494                    sin_family: AddressFamily::Inet as sa_family_t,
495                    sin_port: port.to_be(),
496                    sin_addr: ip.0,
497                    .. unsafe { mem::zeroed() }
498                })
499            }
500            IpAddr::V6(ref ip) => {
501                InetAddr::V6(libc::sockaddr_in6 {
502                    sin6_family: AddressFamily::Inet6 as sa_family_t,
503                    sin6_port: port.to_be(),
504                    sin6_addr: ip.0,
505                    .. unsafe { mem::zeroed() }
506                })
507            }
508        }
509    }
510    /// Gets the IP address associated with this socket address.
511    pub const fn ip(&self) -> IpAddr {
512        match *self {
513            InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
514            InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
515        }
516    }
517
518    /// Gets the port number associated with this socket address
519    pub const fn port(&self) -> u16 {
520        match *self {
521            InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
522            InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
523        }
524    }
525
526    pub fn to_std(&self) -> net::SocketAddr {
527        match *self {
528            InetAddr::V4(ref sa) => net::SocketAddr::V4(
529                net::SocketAddrV4::new(
530                    Ipv4Addr(sa.sin_addr).to_std(),
531                    self.port())),
532            InetAddr::V6(ref sa) => net::SocketAddr::V6(
533                net::SocketAddrV6::new(
534                    Ipv6Addr(sa.sin6_addr).to_std(),
535                    self.port(),
536                    sa.sin6_flowinfo,
537                    sa.sin6_scope_id)),
538        }
539    }
540
541    #[deprecated(since = "0.23.0", note = "use .to_string() instead")]
542    pub fn to_str(&self) -> String {
543        format!("{}", self)
544    }
545}
546
547#[allow(deprecated)]
548impl fmt::Display for InetAddr {
549    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550        match *self {
551            InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
552            InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
553        }
554    }
555}
556
557/*
558 *
559 * ===== IpAddr =====
560 *
561 */
562#[allow(missing_docs)]  // Since they're all deprecated anyway
563#[allow(deprecated)]
564#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
565#[deprecated(
566    since = "0.24.0",
567    note = "Use std::net::IpAddr instead"
568)]
569pub enum IpAddr {
570    V4(Ipv4Addr),
571    V6(Ipv6Addr),
572}
573
574#[allow(deprecated)]
575#[allow(missing_docs)]  // Since they're all deprecated anyway
576impl IpAddr {
577    /// Create a new IpAddr that contains an IPv4 address.
578    ///
579    /// The result will represent the IP address a.b.c.d
580    pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
581        IpAddr::V4(Ipv4Addr::new(a, b, c, d))
582    }
583
584    /// Create a new IpAddr that contains an IPv6 address.
585    ///
586    /// The result will represent the IP address a:b:c:d:e:f
587    #[allow(clippy::many_single_char_names)]
588    #[allow(clippy::too_many_arguments)]
589    pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
590        IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
591    }
592
593    pub fn from_std(std: &net::IpAddr) -> IpAddr {
594        match *std {
595            net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
596            net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
597        }
598    }
599
600    pub const fn to_std(&self) -> net::IpAddr {
601        match *self {
602            IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
603            IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
604        }
605    }
606}
607
608#[allow(deprecated)]
609impl fmt::Display for IpAddr {
610    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
611        match *self {
612            IpAddr::V4(ref v4) => v4.fmt(f),
613            IpAddr::V6(ref v6) => v6.fmt(f)
614        }
615    }
616}
617
618/*
619 *
620 * ===== Ipv4Addr =====
621 *
622 */
623
624#[deprecated(
625    since = "0.24.0",
626    note = "Use std::net::Ipv4Addr instead"
627)]
628#[allow(missing_docs)]  // Since they're all deprecated anyway
629#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
630#[repr(transparent)]
631pub struct Ipv4Addr(pub libc::in_addr);
632
633#[allow(deprecated)]
634#[allow(missing_docs)]  // Since they're all deprecated anyway
635impl Ipv4Addr {
636    #[allow(clippy::identity_op)]   // More readable this way
637    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
638        let ip = (((a as u32) << 24) |
639                  ((b as u32) << 16) |
640                  ((c as u32) <<  8) |
641                  ((d as u32) <<  0)).to_be();
642
643        Ipv4Addr(libc::in_addr { s_addr: ip })
644    }
645
646    // Use pass by reference for symmetry with Ipv6Addr::from_std
647    #[allow(clippy::trivially_copy_pass_by_ref)]
648    pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
649        let bits = std.octets();
650        Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
651    }
652
653    pub const fn any() -> Ipv4Addr {
654        Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
655    }
656
657    pub const fn octets(self) -> [u8; 4] {
658        let bits = u32::from_be(self.0.s_addr);
659        [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
660    }
661
662    pub const fn to_std(self) -> net::Ipv4Addr {
663        let bits = self.octets();
664        net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
665    }
666}
667
668#[allow(deprecated)]
669impl fmt::Display for Ipv4Addr {
670    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
671        let octets = self.octets();
672        write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
673    }
674}
675
676/*
677 *
678 * ===== Ipv6Addr =====
679 *
680 */
681
682#[deprecated(
683    since = "0.24.0",
684    note = "Use std::net::Ipv6Addr instead"
685)]
686#[allow(missing_docs)]  // Since they're all deprecated anyway
687#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
688#[repr(transparent)]
689pub struct Ipv6Addr(pub libc::in6_addr);
690
691// Note that IPv6 addresses are stored in big endian order on all architectures.
692// See https://tools.ietf.org/html/rfc1700 or consult your favorite search
693// engine.
694
695macro_rules! to_u8_array {
696    ($($num:ident),*) => {
697        [ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
698    }
699}
700
701macro_rules! to_u16_array {
702    ($slf:ident, $($first:expr, $second:expr),*) => {
703        [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
704    }
705}
706
707#[allow(deprecated)]
708#[allow(missing_docs)]  // Since they're all deprecated anyway
709impl Ipv6Addr {
710    #[allow(clippy::many_single_char_names)]
711    #[allow(clippy::too_many_arguments)]
712    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
713        Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)})
714    }
715
716    pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
717        let s = std.segments();
718        Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
719    }
720
721    /// Return the eight 16-bit segments that make up this address
722    pub const fn segments(&self) -> [u16; 8] {
723        to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
724    }
725
726    pub const fn to_std(&self) -> net::Ipv6Addr {
727        let s = self.segments();
728        net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
729    }
730}
731
732#[allow(deprecated)]
733impl fmt::Display for Ipv6Addr {
734    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
735        self.to_std().fmt(fmt)
736    }
737}
738}
739
740/// A wrapper around `sockaddr_un`.
741#[derive(Clone, Copy, Debug)]
742#[repr(C)]
743pub struct UnixAddr {
744    // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts
745    sun: libc::sockaddr_un,
746    /// The length of the valid part of `sun`, including the sun_family field
747    /// but excluding any trailing nul.
748    // On the BSDs, this field is built into sun
749    #[cfg(any(
750        target_os = "android",
751        target_os = "fuchsia",
752        target_os = "illumos",
753        target_os = "linux"
754    ))]
755    sun_len: u8,
756}
757
758// linux man page unix(7) says there are 3 kinds of unix socket:
759// pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1
760// unnamed: addrlen = sizeof(sa_family_t)
761// abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))]
762//
763// what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path)
764#[derive(PartialEq, Eq, Hash)]
765enum UnixAddrKind<'a> {
766    Pathname(&'a Path),
767    Unnamed,
768    #[cfg(any(target_os = "android", target_os = "linux"))]
769    Abstract(&'a [u8]),
770}
771impl<'a> UnixAddrKind<'a> {
772    /// Safety: sun & sun_len must be valid
773    #[allow(clippy::unnecessary_cast)]   // Not unnecessary on all platforms
774    unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self {
775        assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path));
776        let path_len =
777            sun_len as usize - offset_of!(libc::sockaddr_un, sun_path);
778        if path_len == 0 {
779            return Self::Unnamed;
780        }
781        #[cfg(any(target_os = "android", target_os = "linux"))]
782        if sun.sun_path[0] == 0 {
783            let name = slice::from_raw_parts(
784                sun.sun_path.as_ptr().add(1) as *const u8,
785                path_len - 1,
786            );
787            return Self::Abstract(name);
788        }
789        let pathname =
790            slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len);
791        if pathname.last() == Some(&0) {
792            // A trailing NUL is not considered part of the path, and it does
793            // not need to be included in the addrlen passed to functions like
794            // bind().  However, Linux adds a trailing NUL, even if one was not
795            // originally present, when returning addrs from functions like
796            // getsockname() (the BSDs do not do that).  So we need to filter
797            // out any trailing NUL here, so sockaddrs can round-trip through
798            // the kernel and still compare equal.
799            Self::Pathname(Path::new(OsStr::from_bytes(
800                &pathname[0..pathname.len() - 1],
801            )))
802        } else {
803            Self::Pathname(Path::new(OsStr::from_bytes(pathname)))
804        }
805    }
806}
807
808impl UnixAddr {
809    /// Create a new sockaddr_un representing a filesystem path.
810    #[allow(clippy::unnecessary_cast)]   // Not unnecessary on all platforms
811    pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
812        path.with_nix_path(|cstr| unsafe {
813            let mut ret = libc::sockaddr_un {
814                sun_family: AddressFamily::Unix as sa_family_t,
815                ..mem::zeroed()
816            };
817
818            let bytes = cstr.to_bytes();
819
820            if bytes.len() >= ret.sun_path.len() {
821                return Err(Errno::ENAMETOOLONG);
822            }
823
824            let sun_len = (bytes.len()
825                + offset_of!(libc::sockaddr_un, sun_path))
826            .try_into()
827            .unwrap();
828
829            #[cfg(any(
830                target_os = "dragonfly",
831                target_os = "freebsd",
832                target_os = "ios",
833                target_os = "macos",
834                target_os = "netbsd",
835                target_os = "openbsd"
836            ))]
837            {
838                ret.sun_len = sun_len;
839            }
840            ptr::copy_nonoverlapping(
841                bytes.as_ptr(),
842                ret.sun_path.as_mut_ptr() as *mut u8,
843                bytes.len(),
844            );
845
846            Ok(UnixAddr::from_raw_parts(ret, sun_len))
847        })?
848    }
849
850    /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
851    ///
852    /// The leading nul byte for the abstract namespace is automatically added;
853    /// thus the input `path` is expected to be the bare name, not NUL-prefixed.
854    /// This is a Linux-specific extension, primarily used to allow chrooted
855    /// processes to communicate with processes having a different filesystem view.
856    #[cfg(any(target_os = "android", target_os = "linux"))]
857    #[cfg_attr(docsrs, doc(cfg(all())))]
858    #[allow(clippy::unnecessary_cast)]   // Not unnecessary on all platforms
859    pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
860        unsafe {
861            let mut ret = libc::sockaddr_un {
862                sun_family: AddressFamily::Unix as sa_family_t,
863                ..mem::zeroed()
864            };
865
866            if path.len() >= ret.sun_path.len() {
867                return Err(Errno::ENAMETOOLONG);
868            }
869            let sun_len =
870                (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path))
871                    .try_into()
872                    .unwrap();
873
874            // Abstract addresses are represented by sun_path[0] ==
875            // b'\0', so copy starting one byte in.
876            ptr::copy_nonoverlapping(
877                path.as_ptr(),
878                ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
879                path.len(),
880            );
881
882            Ok(UnixAddr::from_raw_parts(ret, sun_len))
883        }
884    }
885
886    /// Create a new `sockaddr_un` representing an "unnamed" unix socket address.
887    #[cfg(any(target_os = "android", target_os = "linux"))]
888    #[cfg_attr(docsrs, doc(cfg(all())))]
889    pub fn new_unnamed() -> UnixAddr {
890        let ret = libc::sockaddr_un {
891            sun_family: AddressFamily::Unix as sa_family_t,
892            .. unsafe { mem::zeroed() }
893        };
894
895        let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap();
896
897        unsafe { UnixAddr::from_raw_parts(ret, sun_len) }
898    }
899
900    /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len`
901    /// is the size of the valid portion of the struct, excluding any trailing
902    /// NUL.
903    ///
904    /// # Safety
905    /// This pair of sockaddr_un & sun_len must be a valid unix addr, which
906    /// means:
907    /// - sun_len >= offset_of(sockaddr_un, sun_path)
908    /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path)
909    /// - if this is a unix addr with a pathname, sun.sun_path is a
910    ///   fs path, not necessarily nul-terminated.
911    pub(crate) unsafe fn from_raw_parts(
912        sun: libc::sockaddr_un,
913        sun_len: u8,
914    ) -> UnixAddr {
915        cfg_if! {
916            if #[cfg(any(target_os = "android",
917                     target_os = "fuchsia",
918                     target_os = "illumos",
919                     target_os = "linux"
920                ))]
921            {
922                UnixAddr { sun, sun_len }
923            } else {
924                assert_eq!(sun_len, sun.sun_len);
925                UnixAddr {sun}
926            }
927        }
928    }
929
930    fn kind(&self) -> UnixAddrKind<'_> {
931        // SAFETY: our sockaddr is always valid because of the invariant on the struct
932        unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) }
933    }
934
935    /// If this address represents a filesystem path, return that path.
936    pub fn path(&self) -> Option<&Path> {
937        match self.kind() {
938            UnixAddrKind::Pathname(path) => Some(path),
939            _ => None,
940        }
941    }
942
943    /// If this address represents an abstract socket, return its name.
944    ///
945    /// For abstract sockets only the bare name is returned, without the
946    /// leading NUL byte. `None` is returned for unnamed or path-backed sockets.
947    #[cfg(any(target_os = "android", target_os = "linux"))]
948    #[cfg_attr(docsrs, doc(cfg(all())))]
949    pub fn as_abstract(&self) -> Option<&[u8]> {
950        match self.kind() {
951            UnixAddrKind::Abstract(name) => Some(name),
952            _ => None,
953        }
954    }
955
956    /// Check if this address is an "unnamed" unix socket address.
957    #[cfg(any(target_os = "android", target_os = "linux"))]
958    #[cfg_attr(docsrs, doc(cfg(all())))]
959    #[inline]
960    pub fn is_unnamed(&self) -> bool {
961        matches!(self.kind(), UnixAddrKind::Unnamed)
962    }
963
964    /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
965    #[inline]
966    pub fn path_len(&self) -> usize {
967        self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path)
968    }
969    /// Returns a pointer to the raw `sockaddr_un` struct
970    #[inline]
971    pub fn as_ptr(&self) -> *const libc::sockaddr_un {
972        &self.sun
973    }
974    /// Returns a mutable pointer to the raw `sockaddr_un` struct
975    #[inline]
976    pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un {
977        &mut self.sun
978    }
979
980    fn sun_len(&self) -> u8 {
981        cfg_if! {
982            if #[cfg(any(target_os = "android",
983                     target_os = "fuchsia",
984                     target_os = "illumos",
985                     target_os = "linux"
986                ))]
987            {
988                self.sun_len
989            } else {
990                self.sun.sun_len
991            }
992        }
993    }
994}
995
996impl private::SockaddrLikePriv for UnixAddr {}
997impl SockaddrLike for UnixAddr {
998    #[cfg(any(
999        target_os = "android",
1000        target_os = "fuchsia",
1001        target_os = "illumos",
1002        target_os = "linux"
1003    ))]
1004    fn len(&self) -> libc::socklen_t {
1005        self.sun_len.into()
1006    }
1007
1008    unsafe fn from_raw(
1009        addr: *const libc::sockaddr,
1010        len: Option<libc::socklen_t>,
1011    ) -> Option<Self>
1012    where
1013        Self: Sized,
1014    {
1015        if let Some(l) = len {
1016            if (l as usize) < offset_of!(libc::sockaddr_un, sun_path)
1017                || l > u8::MAX as libc::socklen_t
1018            {
1019                return None;
1020            }
1021        }
1022        if (*addr).sa_family as i32 != libc::AF_UNIX {
1023            return None;
1024        }
1025        let mut su: libc::sockaddr_un = mem::zeroed();
1026        let sup = &mut su as *mut libc::sockaddr_un as *mut u8;
1027        cfg_if! {
1028            if #[cfg(any(target_os = "android",
1029                         target_os = "fuchsia",
1030                         target_os = "illumos",
1031                         target_os = "linux"
1032                ))] {
1033                let su_len = len.unwrap_or(
1034                    mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
1035                );
1036            } else {
1037                let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t);
1038            }
1039        };
1040        ptr::copy(addr as *const u8, sup, su_len as usize);
1041        Some(Self::from_raw_parts(su, su_len as u8))
1042    }
1043
1044    fn size() -> libc::socklen_t
1045    where
1046        Self: Sized,
1047    {
1048        mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
1049    }
1050
1051    unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
1052        // `new_length` is only used on some platforms, so it must be provided even when not used
1053        #![allow(unused_variables)]
1054        cfg_if! {
1055            if #[cfg(any(target_os = "android",
1056                         target_os = "fuchsia",
1057                         target_os = "illumos",
1058                         target_os = "linux",
1059                         target_os = "redox",
1060                ))] {
1061                self.sun_len = new_length as u8;
1062            }
1063        };
1064        Ok(())
1065    }
1066}
1067
1068impl AsRef<libc::sockaddr_un> for UnixAddr {
1069    fn as_ref(&self) -> &libc::sockaddr_un {
1070        &self.sun
1071    }
1072}
1073
1074#[cfg(any(target_os = "android", target_os = "linux"))]
1075fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
1076    use fmt::Write;
1077    f.write_str("@\"")?;
1078    for &b in abs {
1079        use fmt::Display;
1080        char::from(b).escape_default().fmt(f)?;
1081    }
1082    f.write_char('"')?;
1083    Ok(())
1084}
1085
1086impl fmt::Display for UnixAddr {
1087    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1088        match self.kind() {
1089            UnixAddrKind::Pathname(path) => path.display().fmt(f),
1090            UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"),
1091            #[cfg(any(target_os = "android", target_os = "linux"))]
1092            UnixAddrKind::Abstract(name) => fmt_abstract(name, f),
1093        }
1094    }
1095}
1096
1097impl PartialEq for UnixAddr {
1098    fn eq(&self, other: &UnixAddr) -> bool {
1099        self.kind() == other.kind()
1100    }
1101}
1102
1103impl Eq for UnixAddr {}
1104
1105impl Hash for UnixAddr {
1106    fn hash<H: Hasher>(&self, s: &mut H) {
1107        self.kind().hash(s)
1108    }
1109}
1110
1111/// Anything that, in C, can be cast back and forth to `sockaddr`.
1112///
1113/// Most implementors also implement `AsRef<libc::XXX>` to access their
1114/// inner type read-only.
1115#[allow(clippy::len_without_is_empty)]
1116pub trait SockaddrLike: private::SockaddrLikePriv {
1117    /// Returns a raw pointer to the inner structure.  Useful for FFI.
1118    fn as_ptr(&self) -> *const libc::sockaddr {
1119        self as *const Self as *const libc::sockaddr
1120    }
1121
1122    /// Unsafe constructor from a variable length source
1123    ///
1124    /// Some C APIs from provide `len`, and others do not.  If it's provided it
1125    /// will be validated.  If not, it will be guessed based on the family.
1126    ///
1127    /// # Arguments
1128    ///
1129    /// - `addr`:   raw pointer to something that can be cast to a
1130    ///             `libc::sockaddr`. For example, `libc::sockaddr_in`,
1131    ///             `libc::sockaddr_in6`, etc.
1132    /// - `len`:    For fixed-width types like `sockaddr_in`, it will be
1133    ///             validated if present and ignored if not.  For variable-width
1134    ///             types it is required and must be the total length of valid
1135    ///             data.  For example, if `addr` points to a
1136    ///             named `sockaddr_un`, then `len` must be the length of the
1137    ///             structure up to but not including the trailing NUL.
1138    ///
1139    /// # Safety
1140    ///
1141    /// `addr` must be valid for the specific type of sockaddr.  `len`, if
1142    /// present, must not exceed the length of valid data in `addr`.
1143    unsafe fn from_raw(
1144        addr: *const libc::sockaddr,
1145        len: Option<libc::socklen_t>,
1146    ) -> Option<Self>
1147    where
1148        Self: Sized;
1149
1150    /// Return the address family of this socket
1151    ///
1152    /// # Examples
1153    /// One common use is to match on the family of a union type, like this:
1154    /// ```
1155    /// # use nix::sys::socket::*;
1156    /// let fd = socket(AddressFamily::Inet, SockType::Stream,
1157    ///     SockFlag::empty(), None).unwrap();
1158    /// let ss: SockaddrStorage = getsockname(fd).unwrap();
1159    /// match ss.family().unwrap() {
1160    ///     AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()),
1161    ///     AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()),
1162    ///     _ => println!("Unexpected address family")
1163    /// }
1164    /// ```
1165    fn family(&self) -> Option<AddressFamily> {
1166        // Safe since all implementors have a sa_family field at the same
1167        // address, and they're all repr(C)
1168        AddressFamily::from_i32(unsafe {
1169            (*(self as *const Self as *const libc::sockaddr)).sa_family as i32
1170        })
1171    }
1172
1173    cfg_if! {
1174        if #[cfg(any(target_os = "dragonfly",
1175                  target_os = "freebsd",
1176                  target_os = "ios",
1177                  target_os = "macos",
1178                  target_os = "netbsd",
1179                  target_os = "openbsd"))] {
1180            /// Return the length of valid data in the sockaddr structure.
1181            ///
1182            /// For fixed-size sockaddrs, this should be the size of the
1183            /// structure.  But for variable-sized types like [`UnixAddr`] it
1184            /// may be less.
1185            fn len(&self) -> libc::socklen_t {
1186                // Safe since all implementors have a sa_len field at the same
1187                // address, and they're all repr(transparent).
1188                // Robust for all implementors.
1189                unsafe {
1190                    (*(self as *const Self as *const libc::sockaddr)).sa_len
1191                }.into()
1192            }
1193        } else {
1194            /// Return the length of valid data in the sockaddr structure.
1195            ///
1196            /// For fixed-size sockaddrs, this should be the size of the
1197            /// structure.  But for variable-sized types like [`UnixAddr`] it
1198            /// may be less.
1199            fn len(&self) -> libc::socklen_t {
1200                // No robust default implementation is possible without an
1201                // sa_len field.  Implementors with a variable size must
1202                // override this method.
1203                mem::size_of_val(self) as libc::socklen_t
1204            }
1205        }
1206    }
1207
1208    /// Return the available space in the structure
1209    fn size() -> libc::socklen_t
1210    where
1211        Self: Sized,
1212    {
1213        mem::size_of::<Self>() as libc::socklen_t
1214    }
1215
1216    /// Set the length of this socket address
1217    ///
1218    /// This method may only be called on socket addresses whose lengths are dynamic, and it
1219    /// returns an error if called on a type whose length is static.
1220    ///
1221    /// # Safety
1222    ///
1223    /// `new_length` must be a valid length for this type of address. Specifically, reads of that
1224    /// length from `self` must be valid.
1225    #[doc(hidden)]
1226    unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
1227        Err(SocketAddressLengthNotDynamic)
1228    }
1229}
1230
1231/// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically
1232/// fixed.
1233#[derive(Copy, Clone, Debug)]
1234pub struct SocketAddressLengthNotDynamic;
1235impl fmt::Display for SocketAddressLengthNotDynamic {
1236    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1237        f.write_str("Attempted to set length on socket whose length is statically fixed")
1238    }
1239}
1240impl std::error::Error for SocketAddressLengthNotDynamic {}
1241
1242impl private::SockaddrLikePriv for () {
1243    fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
1244        ptr::null_mut()
1245    }
1246}
1247
1248/// `()` can be used in place of a real Sockaddr when no address is expected,
1249/// for example for a field of `Option<S> where S: SockaddrLike`.
1250// If this RFC ever stabilizes, then ! will be a better choice.
1251// https://github.com/rust-lang/rust/issues/35121
1252impl SockaddrLike for () {
1253    fn as_ptr(&self) -> *const libc::sockaddr {
1254        ptr::null()
1255    }
1256
1257    unsafe fn from_raw(
1258        _: *const libc::sockaddr,
1259        _: Option<libc::socklen_t>,
1260    ) -> Option<Self>
1261    where
1262        Self: Sized,
1263    {
1264        None
1265    }
1266
1267    fn family(&self) -> Option<AddressFamily> {
1268        None
1269    }
1270
1271    fn len(&self) -> libc::socklen_t {
1272        0
1273    }
1274}
1275
1276/// An IPv4 socket address
1277#[cfg(feature = "net")]
1278#[repr(transparent)]
1279#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1280pub struct SockaddrIn(libc::sockaddr_in);
1281
1282#[cfg(feature = "net")]
1283impl SockaddrIn {
1284    /// Returns the IP address associated with this socket address, in native
1285    /// endian.
1286    pub const fn ip(&self) -> libc::in_addr_t {
1287        u32::from_be(self.0.sin_addr.s_addr)
1288    }
1289
1290    /// Creates a new socket address from IPv4 octets and a port number.
1291    pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self {
1292        Self(libc::sockaddr_in {
1293            #[cfg(any(
1294                target_os = "dragonfly",
1295                target_os = "freebsd",
1296                target_os = "ios",
1297                target_os = "macos",
1298                target_os = "netbsd",
1299                target_os = "haiku",
1300                target_os = "openbsd"
1301            ))]
1302            sin_len: Self::size() as u8,
1303            sin_family: AddressFamily::Inet as sa_family_t,
1304            sin_port: u16::to_be(port),
1305            sin_addr: libc::in_addr {
1306                s_addr: u32::from_ne_bytes([a, b, c, d]),
1307            },
1308            sin_zero: unsafe { mem::zeroed() },
1309        })
1310    }
1311
1312    /// Returns the port number associated with this socket address, in native
1313    /// endian.
1314    pub const fn port(&self) -> u16 {
1315        u16::from_be(self.0.sin_port)
1316    }
1317}
1318
1319#[cfg(feature = "net")]
1320impl private::SockaddrLikePriv for SockaddrIn {}
1321#[cfg(feature = "net")]
1322impl SockaddrLike for SockaddrIn {
1323    unsafe fn from_raw(
1324        addr: *const libc::sockaddr,
1325        len: Option<libc::socklen_t>,
1326    ) -> Option<Self>
1327    where
1328        Self: Sized,
1329    {
1330        if let Some(l) = len {
1331            if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t {
1332                return None;
1333            }
1334        }
1335        if (*addr).sa_family as i32 != libc::AF_INET {
1336            return None;
1337        }
1338        Some(Self(ptr::read_unaligned(addr as *const _)))
1339    }
1340}
1341
1342#[cfg(feature = "net")]
1343impl AsRef<libc::sockaddr_in> for SockaddrIn {
1344    fn as_ref(&self) -> &libc::sockaddr_in {
1345        &self.0
1346    }
1347}
1348
1349#[cfg(feature = "net")]
1350impl fmt::Display for SockaddrIn {
1351    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1352        let ne = u32::from_be(self.0.sin_addr.s_addr);
1353        let port = u16::from_be(self.0.sin_port);
1354        write!(
1355            f,
1356            "{}.{}.{}.{}:{}",
1357            ne >> 24,
1358            (ne >> 16) & 0xFF,
1359            (ne >> 8) & 0xFF,
1360            ne & 0xFF,
1361            port
1362        )
1363    }
1364}
1365
1366#[cfg(feature = "net")]
1367impl From<net::SocketAddrV4> for SockaddrIn {
1368    fn from(addr: net::SocketAddrV4) -> Self {
1369        Self(libc::sockaddr_in {
1370            #[cfg(any(
1371                target_os = "dragonfly",
1372                target_os = "freebsd",
1373                target_os = "haiku",
1374                target_os = "hermit",
1375                target_os = "ios",
1376                target_os = "macos",
1377                target_os = "netbsd",
1378                target_os = "openbsd"
1379            ))]
1380            sin_len: mem::size_of::<libc::sockaddr_in>() as u8,
1381            sin_family: AddressFamily::Inet as sa_family_t,
1382            sin_port: addr.port().to_be(), // network byte order
1383            sin_addr: ipv4addr_to_libc(*addr.ip()),
1384            ..unsafe { mem::zeroed() }
1385        })
1386    }
1387}
1388
1389#[cfg(feature = "net")]
1390impl From<SockaddrIn> for net::SocketAddrV4 {
1391    fn from(addr: SockaddrIn) -> Self {
1392        net::SocketAddrV4::new(
1393            net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()),
1394            u16::from_be(addr.0.sin_port),
1395        )
1396    }
1397}
1398
1399#[cfg(feature = "net")]
1400impl std::str::FromStr for SockaddrIn {
1401    type Err = net::AddrParseError;
1402
1403    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1404        net::SocketAddrV4::from_str(s).map(SockaddrIn::from)
1405    }
1406}
1407
1408/// An IPv6 socket address
1409#[cfg(feature = "net")]
1410#[repr(transparent)]
1411#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1412pub struct SockaddrIn6(libc::sockaddr_in6);
1413
1414#[cfg(feature = "net")]
1415impl SockaddrIn6 {
1416    /// Returns the flow information associated with this address.
1417    pub const fn flowinfo(&self) -> u32 {
1418        self.0.sin6_flowinfo
1419    }
1420
1421    /// Returns the IP address associated with this socket address.
1422    pub fn ip(&self) -> net::Ipv6Addr {
1423        net::Ipv6Addr::from(self.0.sin6_addr.s6_addr)
1424    }
1425
1426    /// Returns the port number associated with this socket address, in native
1427    /// endian.
1428    pub const fn port(&self) -> u16 {
1429        u16::from_be(self.0.sin6_port)
1430    }
1431
1432    /// Returns the scope ID associated with this address.
1433    pub const fn scope_id(&self) -> u32 {
1434        self.0.sin6_scope_id
1435    }
1436}
1437
1438#[cfg(feature = "net")]
1439impl private::SockaddrLikePriv for SockaddrIn6 {}
1440#[cfg(feature = "net")]
1441impl SockaddrLike for SockaddrIn6 {
1442    unsafe fn from_raw(
1443        addr: *const libc::sockaddr,
1444        len: Option<libc::socklen_t>,
1445    ) -> Option<Self>
1446    where
1447        Self: Sized,
1448    {
1449        if let Some(l) = len {
1450            if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t {
1451                return None;
1452            }
1453        }
1454        if (*addr).sa_family as i32 != libc::AF_INET6 {
1455            return None;
1456        }
1457        Some(Self(ptr::read_unaligned(addr as *const _)))
1458    }
1459}
1460
1461#[cfg(feature = "net")]
1462impl AsRef<libc::sockaddr_in6> for SockaddrIn6 {
1463    fn as_ref(&self) -> &libc::sockaddr_in6 {
1464        &self.0
1465    }
1466}
1467
1468#[cfg(feature = "net")]
1469impl fmt::Display for SockaddrIn6 {
1470    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1471        // These things are really hard to display properly.  Easier to let std
1472        // do it.
1473        let std = net::SocketAddrV6::new(
1474            self.ip(),
1475            self.port(),
1476            self.flowinfo(),
1477            self.scope_id(),
1478        );
1479        std.fmt(f)
1480    }
1481}
1482
1483#[cfg(feature = "net")]
1484impl From<net::SocketAddrV6> for SockaddrIn6 {
1485    fn from(addr: net::SocketAddrV6) -> Self {
1486        #[allow(clippy::needless_update)] // It isn't needless on Illumos
1487        Self(libc::sockaddr_in6 {
1488            #[cfg(any(
1489                target_os = "dragonfly",
1490                target_os = "freebsd",
1491                target_os = "haiku",
1492                target_os = "hermit",
1493                target_os = "ios",
1494                target_os = "macos",
1495                target_os = "netbsd",
1496                target_os = "openbsd"
1497            ))]
1498            sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8,
1499            sin6_family: AddressFamily::Inet6 as sa_family_t,
1500            sin6_port: addr.port().to_be(), // network byte order
1501            sin6_addr: ipv6addr_to_libc(addr.ip()),
1502            sin6_flowinfo: addr.flowinfo(), // host byte order
1503            sin6_scope_id: addr.scope_id(), // host byte order
1504            ..unsafe { mem::zeroed() }
1505        })
1506    }
1507}
1508
1509#[cfg(feature = "net")]
1510impl From<SockaddrIn6> for net::SocketAddrV6 {
1511    fn from(addr: SockaddrIn6) -> Self {
1512        net::SocketAddrV6::new(
1513            net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr),
1514            u16::from_be(addr.0.sin6_port),
1515            addr.0.sin6_flowinfo,
1516            addr.0.sin6_scope_id,
1517        )
1518    }
1519}
1520
1521#[cfg(feature = "net")]
1522impl std::str::FromStr for SockaddrIn6 {
1523    type Err = net::AddrParseError;
1524
1525    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1526        net::SocketAddrV6::from_str(s).map(SockaddrIn6::from)
1527    }
1528}
1529
1530/// A container for any sockaddr type
1531///
1532/// Just like C's `sockaddr_storage`, this type is large enough to hold any type
1533/// of sockaddr.  It can be used as an argument with functions like
1534/// [`bind`](super::bind) and [`getsockname`](super::getsockname).  Though it is
1535/// a union, it can be safely accessed through the `as_*` methods.
1536///
1537/// # Example
1538/// ```
1539/// # use nix::sys::socket::*;
1540/// # use std::str::FromStr;
1541/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap();
1542/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(),
1543///     None).unwrap();
1544/// bind(fd, &localhost).expect("bind");
1545/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname");
1546/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap());
1547/// ```
1548#[derive(Clone, Copy, Eq)]
1549#[repr(C)]
1550pub union SockaddrStorage {
1551    #[cfg(any(target_os = "android", target_os = "linux"))]
1552    #[cfg_attr(docsrs, doc(cfg(all())))]
1553    alg: AlgAddr,
1554    #[cfg(feature = "net")]
1555    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1556    dl: LinkAddr,
1557    #[cfg(any(target_os = "android", target_os = "linux"))]
1558    nl: NetlinkAddr,
1559    #[cfg(all(
1560        feature = "ioctl",
1561        any(target_os = "ios", target_os = "macos")
1562    ))]
1563    #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
1564    sctl: SysControlAddr,
1565    #[cfg(feature = "net")]
1566    sin: SockaddrIn,
1567    #[cfg(feature = "net")]
1568    sin6: SockaddrIn6,
1569    ss: libc::sockaddr_storage,
1570    su: UnixAddr,
1571    #[cfg(any(target_os = "android", target_os = "linux"))]
1572    #[cfg_attr(docsrs, doc(cfg(all())))]
1573    vsock: VsockAddr,
1574}
1575impl private::SockaddrLikePriv for SockaddrStorage {}
1576impl SockaddrLike for SockaddrStorage {
1577    unsafe fn from_raw(
1578        addr: *const libc::sockaddr,
1579        l: Option<libc::socklen_t>,
1580    ) -> Option<Self>
1581    where
1582        Self: Sized,
1583    {
1584        if addr.is_null() {
1585            return None;
1586        }
1587        if let Some(len) = l {
1588            let ulen = len as usize;
1589            if ulen < offset_of!(libc::sockaddr, sa_data)
1590                || ulen > mem::size_of::<libc::sockaddr_storage>()
1591            {
1592                None
1593            } else {
1594                let mut ss: libc::sockaddr_storage = mem::zeroed();
1595                let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8;
1596                ptr::copy(addr as *const u8, ssp, len as usize);
1597                #[cfg(any(
1598                    target_os = "android",
1599                    target_os = "fuchsia",
1600                    target_os = "illumos",
1601                    target_os = "linux"
1602                ))]
1603                if i32::from(ss.ss_family) == libc::AF_UNIX {
1604                    // Safe because we UnixAddr is strictly smaller than
1605                    // SockaddrStorage, and we just initialized the structure.
1606                    (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8;
1607                }
1608                Some(Self { ss })
1609            }
1610        } else {
1611            // If length is not available and addr is of a fixed-length type,
1612            // copy it.  If addr is of a variable length type and len is not
1613            // available, then there's nothing we can do.
1614            match (*addr).sa_family as i32 {
1615                #[cfg(any(target_os = "android", target_os = "linux"))]
1616                libc::AF_ALG => {
1617                    AlgAddr::from_raw(addr, l).map(|alg| Self { alg })
1618                }
1619                #[cfg(feature = "net")]
1620                libc::AF_INET => {
1621                    SockaddrIn::from_raw(addr, l).map(|sin| Self { sin })
1622                }
1623                #[cfg(feature = "net")]
1624                libc::AF_INET6 => {
1625                    SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 })
1626                }
1627                #[cfg(any(
1628                    target_os = "dragonfly",
1629                    target_os = "freebsd",
1630                    target_os = "ios",
1631                    target_os = "macos",
1632                    target_os = "illumos",
1633                    target_os = "netbsd",
1634                    target_os = "haiku",
1635                    target_os = "openbsd"
1636                ))]
1637                #[cfg(feature = "net")]
1638                libc::AF_LINK => {
1639                    LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
1640                }
1641                #[cfg(any(target_os = "android", target_os = "linux"))]
1642                libc::AF_NETLINK => {
1643                    NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl })
1644                }
1645                #[cfg(any(
1646                    target_os = "android",
1647                    target_os = "fuchsia",
1648                    target_os = "linux"
1649                ))]
1650                #[cfg(feature = "net")]
1651                libc::AF_PACKET => {
1652                    LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
1653                }
1654                #[cfg(all(
1655                    feature = "ioctl",
1656                    any(target_os = "ios", target_os = "macos")
1657                ))]
1658                libc::AF_SYSTEM => {
1659                    SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl })
1660                }
1661                #[cfg(any(target_os = "android", target_os = "linux"))]
1662                libc::AF_VSOCK => {
1663                    VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock })
1664                }
1665                _ => None,
1666            }
1667        }
1668    }
1669
1670    #[cfg(any(
1671        target_os = "android",
1672        target_os = "fuchsia",
1673        target_os = "illumos",
1674        target_os = "linux"
1675    ))]
1676    fn len(&self) -> libc::socklen_t {
1677        match self.as_unix_addr() {
1678            // The UnixAddr type knows its own length
1679            Some(ua) => ua.len(),
1680            // For all else, we're just a boring SockaddrStorage
1681            None => mem::size_of_val(self) as libc::socklen_t
1682        }
1683    }
1684
1685    unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
1686        match self.as_unix_addr_mut() {
1687            Some(addr) => {
1688                addr.set_length(new_length)
1689            },
1690            None => Err(SocketAddressLengthNotDynamic),
1691        }
1692    }
1693}
1694
1695macro_rules! accessors {
1696    (
1697        $fname:ident,
1698        $fname_mut:ident,
1699        $sockty:ty,
1700        $family:expr,
1701        $libc_ty:ty,
1702        $field:ident) => {
1703        /// Safely and falliably downcast to an immutable reference
1704        pub fn $fname(&self) -> Option<&$sockty> {
1705            if self.family() == Some($family)
1706                && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t
1707            {
1708                // Safe because family and len are validated
1709                Some(unsafe { &self.$field })
1710            } else {
1711                None
1712            }
1713        }
1714
1715        /// Safely and falliably downcast to a mutable reference
1716        pub fn $fname_mut(&mut self) -> Option<&mut $sockty> {
1717            if self.family() == Some($family)
1718                && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t
1719            {
1720                // Safe because family and len are validated
1721                Some(unsafe { &mut self.$field })
1722            } else {
1723                None
1724            }
1725        }
1726    };
1727}
1728
1729impl SockaddrStorage {
1730    /// Downcast to an immutable `[UnixAddr]` reference.
1731    pub fn as_unix_addr(&self) -> Option<&UnixAddr> {
1732        cfg_if! {
1733            if #[cfg(any(target_os = "android",
1734                     target_os = "fuchsia",
1735                     target_os = "illumos",
1736                     target_os = "linux"
1737                ))]
1738            {
1739                let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1740                // Safe because UnixAddr is strictly smaller than
1741                // sockaddr_storage, and we're fully initialized
1742                let len = unsafe {
1743                    (*(p as *const UnixAddr )).sun_len as usize
1744                };
1745            } else {
1746                let len = self.len() as usize;
1747            }
1748        }
1749        // Sanity checks
1750        if self.family() != Some(AddressFamily::Unix) ||
1751           len < offset_of!(libc::sockaddr_un, sun_path) ||
1752           len > mem::size_of::<libc::sockaddr_un>() {
1753            None
1754        } else {
1755            Some(unsafe{&self.su})
1756        }
1757    }
1758
1759    /// Downcast to a mutable `[UnixAddr]` reference.
1760    pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> {
1761        cfg_if! {
1762            if #[cfg(any(target_os = "android",
1763                     target_os = "fuchsia",
1764                     target_os = "illumos",
1765                     target_os = "linux"
1766                ))]
1767            {
1768                let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1769                // Safe because UnixAddr is strictly smaller than
1770                // sockaddr_storage, and we're fully initialized
1771                let len = unsafe {
1772                    (*(p as *const UnixAddr )).sun_len as usize
1773                };
1774            } else {
1775                let len = self.len() as usize;
1776            }
1777        }
1778        // Sanity checks
1779        if self.family() != Some(AddressFamily::Unix) ||
1780           len < offset_of!(libc::sockaddr_un, sun_path) ||
1781           len > mem::size_of::<libc::sockaddr_un>() {
1782            None
1783        } else {
1784            Some(unsafe{&mut self.su})
1785        }
1786    }
1787
1788    #[cfg(any(target_os = "android", target_os = "linux"))]
1789    accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr,
1790    AddressFamily::Alg, libc::sockaddr_alg, alg}
1791
1792    #[cfg(any(
1793        target_os = "android",
1794        target_os = "fuchsia",
1795        target_os = "linux"
1796    ))]
1797    #[cfg(feature = "net")]
1798    accessors! {
1799    as_link_addr, as_link_addr_mut, LinkAddr,
1800    AddressFamily::Packet, libc::sockaddr_ll, dl}
1801
1802    #[cfg(any(
1803        target_os = "dragonfly",
1804        target_os = "freebsd",
1805        target_os = "ios",
1806        target_os = "macos",
1807        target_os = "illumos",
1808        target_os = "netbsd",
1809        target_os = "openbsd"
1810    ))]
1811    #[cfg(feature = "net")]
1812    accessors! {
1813    as_link_addr, as_link_addr_mut, LinkAddr,
1814    AddressFamily::Link, libc::sockaddr_dl, dl}
1815
1816    #[cfg(feature = "net")]
1817    accessors! {
1818    as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn,
1819    AddressFamily::Inet, libc::sockaddr_in, sin}
1820
1821    #[cfg(feature = "net")]
1822    accessors! {
1823    as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6,
1824    AddressFamily::Inet6, libc::sockaddr_in6, sin6}
1825
1826    #[cfg(any(target_os = "android", target_os = "linux"))]
1827    accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr,
1828    AddressFamily::Netlink, libc::sockaddr_nl, nl}
1829
1830    #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))]
1831    #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
1832    accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr,
1833    AddressFamily::System, libc::sockaddr_ctl, sctl}
1834
1835    #[cfg(any(target_os = "android", target_os = "linux"))]
1836    #[cfg_attr(docsrs, doc(cfg(all())))]
1837    accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr,
1838    AddressFamily::Vsock, libc::sockaddr_vm, vsock}
1839}
1840
1841impl fmt::Debug for SockaddrStorage {
1842    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1843        f.debug_struct("SockaddrStorage")
1844            // Safe because sockaddr_storage has the least specific
1845            // field types
1846            .field("ss", unsafe { &self.ss })
1847            .finish()
1848    }
1849}
1850
1851impl fmt::Display for SockaddrStorage {
1852    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1853        unsafe {
1854            match self.ss.ss_family as i32 {
1855                #[cfg(any(target_os = "android", target_os = "linux"))]
1856                libc::AF_ALG => self.alg.fmt(f),
1857                #[cfg(feature = "net")]
1858                libc::AF_INET => self.sin.fmt(f),
1859                #[cfg(feature = "net")]
1860                libc::AF_INET6 => self.sin6.fmt(f),
1861                #[cfg(any(
1862                    target_os = "dragonfly",
1863                    target_os = "freebsd",
1864                    target_os = "ios",
1865                    target_os = "macos",
1866                    target_os = "illumos",
1867                    target_os = "netbsd",
1868                    target_os = "openbsd"
1869                ))]
1870                #[cfg(feature = "net")]
1871                libc::AF_LINK => self.dl.fmt(f),
1872                #[cfg(any(target_os = "android", target_os = "linux"))]
1873                libc::AF_NETLINK => self.nl.fmt(f),
1874                #[cfg(any(
1875                    target_os = "android",
1876                    target_os = "linux",
1877                    target_os = "fuchsia"
1878                ))]
1879                #[cfg(feature = "net")]
1880                libc::AF_PACKET => self.dl.fmt(f),
1881                #[cfg(any(target_os = "ios", target_os = "macos"))]
1882                #[cfg(feature = "ioctl")]
1883                libc::AF_SYSTEM => self.sctl.fmt(f),
1884                libc::AF_UNIX => self.su.fmt(f),
1885                #[cfg(any(target_os = "android", target_os = "linux"))]
1886                libc::AF_VSOCK => self.vsock.fmt(f),
1887                _ => "<Address family unspecified>".fmt(f),
1888            }
1889        }
1890    }
1891}
1892
1893#[cfg(feature = "net")]
1894impl From<net::SocketAddrV4> for SockaddrStorage {
1895    fn from(s: net::SocketAddrV4) -> Self {
1896        unsafe {
1897            let mut ss: Self = mem::zeroed();
1898            ss.sin = SockaddrIn::from(s);
1899            ss
1900        }
1901    }
1902}
1903
1904#[cfg(feature = "net")]
1905impl From<net::SocketAddrV6> for SockaddrStorage {
1906    fn from(s: net::SocketAddrV6) -> Self {
1907        unsafe {
1908            let mut ss: Self = mem::zeroed();
1909            ss.sin6 = SockaddrIn6::from(s);
1910            ss
1911        }
1912    }
1913}
1914
1915#[cfg(feature = "net")]
1916impl From<net::SocketAddr> for SockaddrStorage {
1917    fn from(s: net::SocketAddr) -> Self {
1918        match s {
1919            net::SocketAddr::V4(sa4) => Self::from(sa4),
1920            net::SocketAddr::V6(sa6) => Self::from(sa6),
1921        }
1922    }
1923}
1924
1925impl Hash for SockaddrStorage {
1926    fn hash<H: Hasher>(&self, s: &mut H) {
1927        unsafe {
1928            match self.ss.ss_family as i32 {
1929                #[cfg(any(target_os = "android", target_os = "linux"))]
1930                libc::AF_ALG => self.alg.hash(s),
1931                #[cfg(feature = "net")]
1932                libc::AF_INET => self.sin.hash(s),
1933                #[cfg(feature = "net")]
1934                libc::AF_INET6 => self.sin6.hash(s),
1935                #[cfg(any(
1936                    target_os = "dragonfly",
1937                    target_os = "freebsd",
1938                    target_os = "ios",
1939                    target_os = "macos",
1940                    target_os = "illumos",
1941                    target_os = "netbsd",
1942                    target_os = "openbsd"
1943                ))]
1944                #[cfg(feature = "net")]
1945                libc::AF_LINK => self.dl.hash(s),
1946                #[cfg(any(target_os = "android", target_os = "linux"))]
1947                libc::AF_NETLINK => self.nl.hash(s),
1948                #[cfg(any(
1949                    target_os = "android",
1950                    target_os = "linux",
1951                    target_os = "fuchsia"
1952                ))]
1953                #[cfg(feature = "net")]
1954                libc::AF_PACKET => self.dl.hash(s),
1955                #[cfg(any(target_os = "ios", target_os = "macos"))]
1956                #[cfg(feature = "ioctl")]
1957                libc::AF_SYSTEM => self.sctl.hash(s),
1958                libc::AF_UNIX => self.su.hash(s),
1959                #[cfg(any(target_os = "android", target_os = "linux"))]
1960                libc::AF_VSOCK => self.vsock.hash(s),
1961                _ => self.ss.hash(s),
1962            }
1963        }
1964    }
1965}
1966
1967impl PartialEq for SockaddrStorage {
1968    fn eq(&self, other: &Self) -> bool {
1969        unsafe {
1970            match (self.ss.ss_family as i32, other.ss.ss_family as i32) {
1971                #[cfg(any(target_os = "android", target_os = "linux"))]
1972                (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg,
1973                #[cfg(feature = "net")]
1974                (libc::AF_INET, libc::AF_INET) => self.sin == other.sin,
1975                #[cfg(feature = "net")]
1976                (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6,
1977                #[cfg(any(
1978                    target_os = "dragonfly",
1979                    target_os = "freebsd",
1980                    target_os = "ios",
1981                    target_os = "macos",
1982                    target_os = "illumos",
1983                    target_os = "netbsd",
1984                    target_os = "openbsd"
1985                ))]
1986                #[cfg(feature = "net")]
1987                (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl,
1988                #[cfg(any(target_os = "android", target_os = "linux"))]
1989                (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl,
1990                #[cfg(any(
1991                    target_os = "android",
1992                    target_os = "fuchsia",
1993                    target_os = "linux"
1994                ))]
1995                #[cfg(feature = "net")]
1996                (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl,
1997                #[cfg(any(target_os = "ios", target_os = "macos"))]
1998                #[cfg(feature = "ioctl")]
1999                (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl,
2000                (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su,
2001                #[cfg(any(target_os = "android", target_os = "linux"))]
2002                (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock,
2003                _ => false,
2004            }
2005        }
2006    }
2007}
2008
2009pub(super) mod private {
2010    pub trait SockaddrLikePriv {
2011        /// Returns a mutable raw pointer to the inner structure.
2012        ///
2013        /// # Safety
2014        ///
2015        /// This method is technically safe, but modifying the inner structure's
2016        /// `family` or `len` fields may result in violating Nix's invariants.
2017        /// It is best to use this method only with foreign functions that do
2018        /// not change the sockaddr type.
2019        fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
2020            self as *mut Self as *mut libc::sockaddr
2021        }
2022    }
2023}
2024
2025/// Represents a socket address
2026#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2027#[deprecated(
2028    since = "0.24.0",
2029    note = "use SockaddrLike or SockaddrStorage instead"
2030)]
2031#[allow(missing_docs)] // Since they're all deprecated anyway
2032#[allow(deprecated)]
2033#[non_exhaustive]
2034pub enum SockAddr {
2035    #[cfg(feature = "net")]
2036    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
2037    Inet(InetAddr),
2038    Unix(UnixAddr),
2039    #[cfg(any(target_os = "android", target_os = "linux"))]
2040    #[cfg_attr(docsrs, doc(cfg(all())))]
2041    Netlink(NetlinkAddr),
2042    #[cfg(any(target_os = "android", target_os = "linux"))]
2043    #[cfg_attr(docsrs, doc(cfg(all())))]
2044    Alg(AlgAddr),
2045    #[cfg(all(
2046        feature = "ioctl",
2047        any(target_os = "ios", target_os = "macos")
2048    ))]
2049    #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
2050    SysControl(SysControlAddr),
2051    /// Datalink address (MAC)
2052    #[cfg(any(
2053        target_os = "android",
2054        target_os = "dragonfly",
2055        target_os = "freebsd",
2056        target_os = "ios",
2057        target_os = "linux",
2058        target_os = "macos",
2059        target_os = "illumos",
2060        target_os = "netbsd",
2061        target_os = "openbsd"
2062    ))]
2063    #[cfg(feature = "net")]
2064    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
2065    Link(LinkAddr),
2066    #[cfg(any(target_os = "android", target_os = "linux"))]
2067    #[cfg_attr(docsrs, doc(cfg(all())))]
2068    Vsock(VsockAddr),
2069}
2070
2071#[allow(missing_docs)] // Since they're all deprecated anyway
2072#[allow(deprecated)]
2073impl SockAddr {
2074    feature! {
2075    #![feature = "net"]
2076    pub fn new_inet(addr: InetAddr) -> SockAddr {
2077        SockAddr::Inet(addr)
2078    }
2079    }
2080
2081    pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
2082        Ok(SockAddr::Unix(UnixAddr::new(path)?))
2083    }
2084
2085    #[cfg(any(target_os = "android", target_os = "linux"))]
2086    #[cfg_attr(docsrs, doc(cfg(all())))]
2087    pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
2088        SockAddr::Netlink(NetlinkAddr::new(pid, groups))
2089    }
2090
2091    #[cfg(any(target_os = "android", target_os = "linux"))]
2092    #[cfg_attr(docsrs, doc(cfg(all())))]
2093    pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
2094        SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
2095    }
2096
2097    feature! {
2098    #![feature = "ioctl"]
2099    #[cfg(any(target_os = "ios", target_os = "macos"))]
2100    pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
2101        SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl)
2102    }
2103    }
2104
2105    #[cfg(any(target_os = "android", target_os = "linux"))]
2106    #[cfg_attr(docsrs, doc(cfg(all())))]
2107    pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
2108        SockAddr::Vsock(VsockAddr::new(cid, port))
2109    }
2110
2111    pub fn family(&self) -> AddressFamily {
2112        match *self {
2113            #[cfg(feature = "net")]
2114            SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
2115            #[cfg(feature = "net")]
2116            SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
2117            SockAddr::Unix(..) => AddressFamily::Unix,
2118            #[cfg(any(target_os = "android", target_os = "linux"))]
2119            SockAddr::Netlink(..) => AddressFamily::Netlink,
2120            #[cfg(any(target_os = "android", target_os = "linux"))]
2121            SockAddr::Alg(..) => AddressFamily::Alg,
2122            #[cfg(all(
2123                feature = "ioctl",
2124                any(target_os = "ios", target_os = "macos")
2125            ))]
2126            SockAddr::SysControl(..) => AddressFamily::System,
2127            #[cfg(any(target_os = "android", target_os = "linux"))]
2128            #[cfg(feature = "net")]
2129            SockAddr::Link(..) => AddressFamily::Packet,
2130            #[cfg(any(
2131                target_os = "dragonfly",
2132                target_os = "freebsd",
2133                target_os = "ios",
2134                target_os = "macos",
2135                target_os = "netbsd",
2136                target_os = "illumos",
2137                target_os = "openbsd"
2138            ))]
2139            #[cfg(feature = "net")]
2140            SockAddr::Link(..) => AddressFamily::Link,
2141            #[cfg(any(target_os = "android", target_os = "linux"))]
2142            SockAddr::Vsock(..) => AddressFamily::Vsock,
2143        }
2144    }
2145
2146    #[deprecated(since = "0.23.0", note = "use .to_string() instead")]
2147    pub fn to_str(&self) -> String {
2148        format!("{}", self)
2149    }
2150
2151    /// Creates a `SockAddr` struct from libc's sockaddr.
2152    ///
2153    /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
2154    /// Returns None for unsupported families.
2155    ///
2156    /// # Safety
2157    ///
2158    /// unsafe because it takes a raw pointer as argument.  The caller must
2159    /// ensure that the pointer is valid.
2160    #[cfg(not(target_os = "fuchsia"))]
2161    #[cfg(feature = "net")]
2162    pub(crate) unsafe fn from_libc_sockaddr(
2163        addr: *const libc::sockaddr,
2164    ) -> Option<SockAddr> {
2165        if addr.is_null() {
2166            None
2167        } else {
2168            match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
2169                Some(AddressFamily::Unix) => None,
2170                #[cfg(feature = "net")]
2171                Some(AddressFamily::Inet) => Some(SockAddr::Inet(
2172                    InetAddr::V4(ptr::read_unaligned(addr as *const _)),
2173                )),
2174                #[cfg(feature = "net")]
2175                Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
2176                    InetAddr::V6(ptr::read_unaligned(addr as *const _)),
2177                )),
2178                #[cfg(any(target_os = "android", target_os = "linux"))]
2179                Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
2180                    NetlinkAddr(ptr::read_unaligned(addr as *const _)),
2181                )),
2182                #[cfg(all(
2183                    feature = "ioctl",
2184                    any(target_os = "ios", target_os = "macos")
2185                ))]
2186                Some(AddressFamily::System) => Some(SockAddr::SysControl(
2187                    SysControlAddr(ptr::read_unaligned(addr as *const _)),
2188                )),
2189                #[cfg(any(target_os = "android", target_os = "linux"))]
2190                #[cfg(feature = "net")]
2191                Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr(
2192                    ptr::read_unaligned(addr as *const _),
2193                ))),
2194                #[cfg(any(
2195                    target_os = "dragonfly",
2196                    target_os = "freebsd",
2197                    target_os = "ios",
2198                    target_os = "macos",
2199                    target_os = "netbsd",
2200                    target_os = "illumos",
2201                    target_os = "openbsd"
2202                ))]
2203                #[cfg(feature = "net")]
2204                Some(AddressFamily::Link) => {
2205                    let ether_addr =
2206                        LinkAddr(ptr::read_unaligned(addr as *const _));
2207                    if ether_addr.is_empty() {
2208                        None
2209                    } else {
2210                        Some(SockAddr::Link(ether_addr))
2211                    }
2212                }
2213                #[cfg(any(target_os = "android", target_os = "linux"))]
2214                Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr(
2215                    ptr::read_unaligned(addr as *const _),
2216                ))),
2217                // Other address families are currently not supported and simply yield a None
2218                // entry instead of a proper conversion to a `SockAddr`.
2219                Some(_) | None => None,
2220            }
2221        }
2222    }
2223
2224    /// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
2225    ///
2226    /// This is useful for interfacing with other libc functions that don't yet have nix wrappers.
2227    /// Returns a reference to the underlying data type (as a sockaddr reference) along
2228    /// with the size of the actual data type. sockaddr is commonly used as a proxy for
2229    /// a superclass as C doesn't support inheritance, so many functions that take
2230    /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
2231    pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
2232        match *self {
2233            #[cfg(feature = "net")]
2234            SockAddr::Inet(InetAddr::V4(ref addr)) => (
2235                // This cast is always allowed in C
2236                unsafe {
2237                    &*(addr as *const libc::sockaddr_in
2238                        as *const libc::sockaddr)
2239                },
2240                mem::size_of_val(addr) as libc::socklen_t,
2241            ),
2242            #[cfg(feature = "net")]
2243            SockAddr::Inet(InetAddr::V6(ref addr)) => (
2244                // This cast is always allowed in C
2245                unsafe {
2246                    &*(addr as *const libc::sockaddr_in6
2247                        as *const libc::sockaddr)
2248                },
2249                mem::size_of_val(addr) as libc::socklen_t,
2250            ),
2251            SockAddr::Unix(ref unix_addr) => (
2252                // This cast is always allowed in C
2253                unsafe {
2254                    &*(&unix_addr.sun as *const libc::sockaddr_un
2255                        as *const libc::sockaddr)
2256                },
2257                unix_addr.sun_len() as libc::socklen_t,
2258            ),
2259            #[cfg(any(target_os = "android", target_os = "linux"))]
2260            SockAddr::Netlink(NetlinkAddr(ref sa)) => (
2261                // This cast is always allowed in C
2262                unsafe {
2263                    &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr)
2264                },
2265                mem::size_of_val(sa) as libc::socklen_t,
2266            ),
2267            #[cfg(any(target_os = "android", target_os = "linux"))]
2268            SockAddr::Alg(AlgAddr(ref sa)) => (
2269                // This cast is always allowed in C
2270                unsafe {
2271                    &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr)
2272                },
2273                mem::size_of_val(sa) as libc::socklen_t,
2274            ),
2275            #[cfg(all(
2276                feature = "ioctl",
2277                any(target_os = "ios", target_os = "macos")
2278            ))]
2279            SockAddr::SysControl(SysControlAddr(ref sa)) => (
2280                // This cast is always allowed in C
2281                unsafe {
2282                    &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr)
2283                },
2284                mem::size_of_val(sa) as libc::socklen_t,
2285            ),
2286            #[cfg(any(target_os = "android", target_os = "linux"))]
2287            #[cfg(feature = "net")]
2288            SockAddr::Link(LinkAddr(ref addr)) => (
2289                // This cast is always allowed in C
2290                unsafe {
2291                    &*(addr as *const libc::sockaddr_ll
2292                        as *const libc::sockaddr)
2293                },
2294                mem::size_of_val(addr) as libc::socklen_t,
2295            ),
2296            #[cfg(any(
2297                target_os = "dragonfly",
2298                target_os = "freebsd",
2299                target_os = "ios",
2300                target_os = "macos",
2301                target_os = "illumos",
2302                target_os = "netbsd",
2303                target_os = "openbsd"
2304            ))]
2305            #[cfg(feature = "net")]
2306            SockAddr::Link(LinkAddr(ref addr)) => (
2307                // This cast is always allowed in C
2308                unsafe {
2309                    &*(addr as *const libc::sockaddr_dl
2310                        as *const libc::sockaddr)
2311                },
2312                mem::size_of_val(addr) as libc::socklen_t,
2313            ),
2314            #[cfg(any(target_os = "android", target_os = "linux"))]
2315            SockAddr::Vsock(VsockAddr(ref sa)) => (
2316                // This cast is always allowed in C
2317                unsafe {
2318                    &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr)
2319                },
2320                mem::size_of_val(sa) as libc::socklen_t,
2321            ),
2322        }
2323    }
2324}
2325
2326#[allow(deprecated)]
2327impl fmt::Display for SockAddr {
2328    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2329        match *self {
2330            #[cfg(feature = "net")]
2331            SockAddr::Inet(ref inet) => inet.fmt(f),
2332            SockAddr::Unix(ref unix) => unix.fmt(f),
2333            #[cfg(any(target_os = "android", target_os = "linux"))]
2334            SockAddr::Netlink(ref nl) => nl.fmt(f),
2335            #[cfg(any(target_os = "android", target_os = "linux"))]
2336            SockAddr::Alg(ref nl) => nl.fmt(f),
2337            #[cfg(all(
2338                feature = "ioctl",
2339                any(target_os = "ios", target_os = "macos")
2340            ))]
2341            SockAddr::SysControl(ref sc) => sc.fmt(f),
2342            #[cfg(any(
2343                target_os = "android",
2344                target_os = "dragonfly",
2345                target_os = "freebsd",
2346                target_os = "ios",
2347                target_os = "linux",
2348                target_os = "macos",
2349                target_os = "netbsd",
2350                target_os = "illumos",
2351                target_os = "openbsd"
2352            ))]
2353            #[cfg(feature = "net")]
2354            SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
2355            #[cfg(any(target_os = "android", target_os = "linux"))]
2356            SockAddr::Vsock(ref svm) => svm.fmt(f),
2357        }
2358    }
2359}
2360
2361#[cfg(not(target_os = "fuchsia"))]
2362#[cfg(feature = "net")]
2363#[allow(deprecated)]
2364impl private::SockaddrLikePriv for SockAddr {}
2365#[cfg(not(target_os = "fuchsia"))]
2366#[cfg(feature = "net")]
2367#[allow(deprecated)]
2368impl SockaddrLike for SockAddr {
2369    unsafe fn from_raw(
2370        addr: *const libc::sockaddr,
2371        _len: Option<libc::socklen_t>,
2372    ) -> Option<Self> {
2373        Self::from_libc_sockaddr(addr)
2374    }
2375}
2376
2377#[cfg(any(target_os = "android", target_os = "linux"))]
2378#[cfg_attr(docsrs, doc(cfg(all())))]
2379pub mod netlink {
2380    use super::*;
2381    use crate::sys::socket::addr::AddressFamily;
2382    use libc::{sa_family_t, sockaddr_nl};
2383    use std::{fmt, mem};
2384
2385    /// Address for the Linux kernel user interface device.
2386    ///
2387    /// # References
2388    ///
2389    /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html)
2390    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
2391    #[repr(transparent)]
2392    pub struct NetlinkAddr(pub(in super::super) sockaddr_nl);
2393
2394    impl NetlinkAddr {
2395        /// Construct a new socket address from its port ID and multicast groups
2396        /// mask.
2397        pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
2398            let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
2399            addr.nl_family = AddressFamily::Netlink as sa_family_t;
2400            addr.nl_pid = pid;
2401            addr.nl_groups = groups;
2402
2403            NetlinkAddr(addr)
2404        }
2405
2406        /// Return the socket's port ID.
2407        pub const fn pid(&self) -> u32 {
2408            self.0.nl_pid
2409        }
2410
2411        /// Return the socket's multicast groups mask
2412        pub const fn groups(&self) -> u32 {
2413            self.0.nl_groups
2414        }
2415    }
2416
2417    impl private::SockaddrLikePriv for NetlinkAddr {}
2418    impl SockaddrLike for NetlinkAddr {
2419        unsafe fn from_raw(
2420            addr: *const libc::sockaddr,
2421            len: Option<libc::socklen_t>,
2422        ) -> Option<Self>
2423        where
2424            Self: Sized,
2425        {
2426            if let Some(l) = len {
2427                if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t {
2428                    return None;
2429                }
2430            }
2431            if (*addr).sa_family as i32 != libc::AF_NETLINK {
2432                return None;
2433            }
2434            Some(Self(ptr::read_unaligned(addr as *const _)))
2435        }
2436    }
2437
2438    impl AsRef<libc::sockaddr_nl> for NetlinkAddr {
2439        fn as_ref(&self) -> &libc::sockaddr_nl {
2440            &self.0
2441        }
2442    }
2443
2444    impl fmt::Display for NetlinkAddr {
2445        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2446            write!(f, "pid: {} groups: {}", self.pid(), self.groups())
2447        }
2448    }
2449}
2450
2451#[cfg(any(target_os = "android", target_os = "linux"))]
2452#[cfg_attr(docsrs, doc(cfg(all())))]
2453pub mod alg {
2454    use super::*;
2455    use libc::{c_char, sockaddr_alg, AF_ALG};
2456    use std::ffi::CStr;
2457    use std::hash::{Hash, Hasher};
2458    use std::{fmt, mem, str};
2459
2460    /// Socket address for the Linux kernel crypto API
2461    #[derive(Copy, Clone)]
2462    #[repr(transparent)]
2463    pub struct AlgAddr(pub(in super::super) sockaddr_alg);
2464
2465    impl private::SockaddrLikePriv for AlgAddr {}
2466    impl SockaddrLike for AlgAddr {
2467        unsafe fn from_raw(
2468            addr: *const libc::sockaddr,
2469            l: Option<libc::socklen_t>,
2470        ) -> Option<Self>
2471        where
2472            Self: Sized,
2473        {
2474            if let Some(l) = l {
2475                if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t
2476                {
2477                    return None;
2478                }
2479            }
2480            if (*addr).sa_family as i32 != libc::AF_ALG {
2481                return None;
2482            }
2483            Some(Self(ptr::read_unaligned(addr as *const _)))
2484        }
2485    }
2486
2487    impl AsRef<libc::sockaddr_alg> for AlgAddr {
2488        fn as_ref(&self) -> &libc::sockaddr_alg {
2489            &self.0
2490        }
2491    }
2492
2493    // , PartialEq, Eq, Debug, Hash
2494    impl PartialEq for AlgAddr {
2495        fn eq(&self, other: &Self) -> bool {
2496            let (inner, other) = (self.0, other.0);
2497            (
2498                inner.salg_family,
2499                &inner.salg_type[..],
2500                inner.salg_feat,
2501                inner.salg_mask,
2502                &inner.salg_name[..],
2503            ) == (
2504                other.salg_family,
2505                &other.salg_type[..],
2506                other.salg_feat,
2507                other.salg_mask,
2508                &other.salg_name[..],
2509            )
2510        }
2511    }
2512
2513    impl Eq for AlgAddr {}
2514
2515    impl Hash for AlgAddr {
2516        fn hash<H: Hasher>(&self, s: &mut H) {
2517            let inner = self.0;
2518            (
2519                inner.salg_family,
2520                &inner.salg_type[..],
2521                inner.salg_feat,
2522                inner.salg_mask,
2523                &inner.salg_name[..],
2524            )
2525                .hash(s);
2526        }
2527    }
2528
2529    impl AlgAddr {
2530        /// Construct an `AF_ALG` socket from its cipher name and type.
2531        pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr {
2532            let mut addr: sockaddr_alg = unsafe { mem::zeroed() };
2533            addr.salg_family = AF_ALG as u16;
2534            addr.salg_type[..alg_type.len()]
2535                .copy_from_slice(alg_type.to_string().as_bytes());
2536            addr.salg_name[..alg_name.len()]
2537                .copy_from_slice(alg_name.to_string().as_bytes());
2538
2539            AlgAddr(addr)
2540        }
2541
2542        /// Return the socket's cipher type, for example `hash` or `aead`.
2543        pub fn alg_type(&self) -> &CStr {
2544            unsafe {
2545                CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char)
2546            }
2547        }
2548
2549        /// Return the socket's cipher name, for example `sha1`.
2550        pub fn alg_name(&self) -> &CStr {
2551            unsafe {
2552                CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char)
2553            }
2554        }
2555    }
2556
2557    impl fmt::Display for AlgAddr {
2558        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2559            write!(
2560                f,
2561                "type: {} alg: {}",
2562                self.alg_name().to_string_lossy(),
2563                self.alg_type().to_string_lossy()
2564            )
2565        }
2566    }
2567
2568    impl fmt::Debug for AlgAddr {
2569        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2570            fmt::Display::fmt(self, f)
2571        }
2572    }
2573}
2574
2575feature! {
2576#![feature = "ioctl"]
2577#[cfg(any(target_os = "ios", target_os = "macos"))]
2578pub mod sys_control {
2579    use crate::sys::socket::addr::AddressFamily;
2580    use libc::{self, c_uchar};
2581    use std::{fmt, mem, ptr};
2582    use std::os::unix::io::RawFd;
2583    use crate::{Errno, Result};
2584    use super::{private, SockaddrLike};
2585
2586    // FIXME: Move type into `libc`
2587    #[repr(C)]
2588    #[derive(Clone, Copy)]
2589    #[allow(missing_debug_implementations)]
2590    pub struct ctl_ioc_info {
2591        pub ctl_id: u32,
2592        pub ctl_name: [c_uchar; MAX_KCTL_NAME],
2593    }
2594
2595    const CTL_IOC_MAGIC: u8 = b'N';
2596    const CTL_IOC_INFO: u8 = 3;
2597    const MAX_KCTL_NAME: usize = 96;
2598
2599    ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
2600
2601    /// Apple system control socket
2602    ///
2603    /// # References
2604    ///
2605    /// <https://developer.apple.com/documentation/kernel/sockaddr_ctl>
2606    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2607    #[repr(transparent)]
2608    pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl);
2609
2610    impl private::SockaddrLikePriv for SysControlAddr {}
2611    impl SockaddrLike for SysControlAddr {
2612        unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>)
2613            -> Option<Self> where Self: Sized
2614        {
2615            if let Some(l) = len {
2616                if l != mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t {
2617                    return None;
2618                }
2619            }
2620            if (*addr).sa_family as i32 != libc::AF_SYSTEM {
2621                return None;
2622            }
2623            Some(Self(ptr::read_unaligned(addr as *const _)))
2624        }
2625    }
2626
2627    impl AsRef<libc::sockaddr_ctl> for SysControlAddr {
2628        fn as_ref(&self) -> &libc::sockaddr_ctl {
2629            &self.0
2630        }
2631    }
2632
2633    impl SysControlAddr {
2634        /// Construct a new `SysControlAddr` from its kernel unique identifier
2635        /// and unit number.
2636        pub const fn new(id: u32, unit: u32) -> SysControlAddr {
2637            let addr = libc::sockaddr_ctl {
2638                sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar,
2639                sc_family: AddressFamily::System as c_uchar,
2640                ss_sysaddr: libc::AF_SYS_CONTROL as u16,
2641                sc_id: id,
2642                sc_unit: unit,
2643                sc_reserved: [0; 5]
2644            };
2645
2646            SysControlAddr(addr)
2647        }
2648
2649        /// Construct a new `SysControlAddr` from its human readable name and
2650        /// unit number.
2651        pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
2652            if name.len() > MAX_KCTL_NAME {
2653                return Err(Errno::ENAMETOOLONG);
2654            }
2655
2656            let mut ctl_name = [0; MAX_KCTL_NAME];
2657            ctl_name[..name.len()].clone_from_slice(name.as_bytes());
2658            let mut info = ctl_ioc_info { ctl_id: 0, ctl_name };
2659
2660            unsafe { ctl_info(sockfd, &mut info)?; }
2661
2662            Ok(SysControlAddr::new(info.ctl_id, unit))
2663        }
2664
2665        /// Return the kernel unique identifier
2666        pub const fn id(&self) -> u32 {
2667            self.0.sc_id
2668        }
2669
2670        /// Return the kernel controller private unit number.
2671        pub const fn unit(&self) -> u32 {
2672            self.0.sc_unit
2673        }
2674    }
2675
2676    impl fmt::Display for SysControlAddr {
2677        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2678            fmt::Debug::fmt(self, f)
2679        }
2680    }
2681}
2682}
2683
2684#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
2685#[cfg_attr(docsrs, doc(cfg(all())))]
2686mod datalink {
2687    feature! {
2688    #![feature = "net"]
2689    use super::{fmt, mem, private, ptr, SockaddrLike};
2690
2691    /// Hardware Address
2692    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2693    #[repr(transparent)]
2694    pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll);
2695
2696    impl LinkAddr {
2697        /// Physical-layer protocol
2698        pub fn protocol(&self) -> u16 {
2699            self.0.sll_protocol
2700        }
2701
2702        /// Interface number
2703        pub fn ifindex(&self) -> usize {
2704            self.0.sll_ifindex as usize
2705        }
2706
2707        /// ARP hardware type
2708        pub fn hatype(&self) -> u16 {
2709            self.0.sll_hatype
2710        }
2711
2712        /// Packet type
2713        pub fn pkttype(&self) -> u8 {
2714            self.0.sll_pkttype
2715        }
2716
2717        /// Length of MAC address
2718        pub fn halen(&self) -> usize {
2719            self.0.sll_halen as usize
2720        }
2721
2722        /// Physical-layer address (MAC)
2723        // Returns an Option just for cross-platform compatibility
2724        pub fn addr(&self) -> Option<[u8; 6]> {
2725            Some([
2726                self.0.sll_addr[0],
2727                self.0.sll_addr[1],
2728                self.0.sll_addr[2],
2729                self.0.sll_addr[3],
2730                self.0.sll_addr[4],
2731                self.0.sll_addr[5],
2732            ])
2733        }
2734    }
2735
2736    impl fmt::Display for LinkAddr {
2737        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2738            if let Some(addr) = self.addr() {
2739                write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
2740                    addr[0],
2741                    addr[1],
2742                    addr[2],
2743                    addr[3],
2744                    addr[4],
2745                    addr[5])
2746            } else {
2747                Ok(())
2748            }
2749        }
2750    }
2751    impl private::SockaddrLikePriv for LinkAddr {}
2752    impl SockaddrLike for LinkAddr {
2753        unsafe fn from_raw(addr: *const libc::sockaddr,
2754                           len: Option<libc::socklen_t>)
2755            -> Option<Self> where Self: Sized
2756        {
2757            if let Some(l) = len {
2758                if l != mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t {
2759                    return None;
2760                }
2761            }
2762            if (*addr).sa_family as i32 != libc::AF_PACKET {
2763                return None;
2764            }
2765            Some(Self(ptr::read_unaligned(addr as *const _)))
2766        }
2767    }
2768
2769    impl AsRef<libc::sockaddr_ll> for LinkAddr {
2770        fn as_ref(&self) -> &libc::sockaddr_ll {
2771            &self.0
2772        }
2773    }
2774
2775    }
2776}
2777
2778#[cfg(any(
2779    target_os = "dragonfly",
2780    target_os = "freebsd",
2781    target_os = "ios",
2782    target_os = "macos",
2783    target_os = "illumos",
2784    target_os = "netbsd",
2785    target_os = "haiku",
2786    target_os = "openbsd"
2787))]
2788#[cfg_attr(docsrs, doc(cfg(all())))]
2789mod datalink {
2790    feature! {
2791    #![feature = "net"]
2792    use super::{fmt, mem, private, ptr, SockaddrLike};
2793
2794    /// Hardware Address
2795    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2796    #[repr(transparent)]
2797    pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl);
2798
2799    impl LinkAddr {
2800        /// interface index, if != 0, system given index for interface
2801        #[cfg(not(target_os = "haiku"))]
2802        pub fn ifindex(&self) -> usize {
2803            self.0.sdl_index as usize
2804        }
2805
2806        /// Datalink type
2807        #[cfg(not(target_os = "haiku"))]
2808        pub fn datalink_type(&self) -> u8 {
2809            self.0.sdl_type
2810        }
2811
2812        /// MAC address start position
2813        pub fn nlen(&self) -> usize {
2814            self.0.sdl_nlen as usize
2815        }
2816
2817        /// link level address length
2818        pub fn alen(&self) -> usize {
2819            self.0.sdl_alen as usize
2820        }
2821
2822        /// link layer selector length
2823        #[cfg(not(target_os = "haiku"))]
2824        pub fn slen(&self) -> usize {
2825            self.0.sdl_slen as usize
2826        }
2827
2828        /// if link level address length == 0,
2829        /// or `sdl_data` not be larger.
2830        pub fn is_empty(&self) -> bool {
2831            let nlen = self.nlen();
2832            let alen = self.alen();
2833            let data_len = self.0.sdl_data.len();
2834
2835            alen == 0 || nlen + alen >= data_len
2836        }
2837
2838        /// Physical-layer address (MAC)
2839        // The cast is not unnecessary on all platforms.
2840        #[allow(clippy::unnecessary_cast)]
2841        pub fn addr(&self) -> Option<[u8; 6]> {
2842            let nlen = self.nlen();
2843            let data = self.0.sdl_data;
2844
2845            if self.is_empty() {
2846                None
2847            } else {
2848                Some([
2849                    data[nlen] as u8,
2850                    data[nlen + 1] as u8,
2851                    data[nlen + 2] as u8,
2852                    data[nlen + 3] as u8,
2853                    data[nlen + 4] as u8,
2854                    data[nlen + 5] as u8,
2855                ])
2856            }
2857        }
2858    }
2859
2860    impl fmt::Display for LinkAddr {
2861        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2862            if let Some(addr) = self.addr() {
2863                write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
2864                    addr[0],
2865                    addr[1],
2866                    addr[2],
2867                    addr[3],
2868                    addr[4],
2869                    addr[5])
2870            } else {
2871                Ok(())
2872            }
2873        }
2874    }
2875    impl private::SockaddrLikePriv for LinkAddr {}
2876    impl SockaddrLike for LinkAddr {
2877        unsafe fn from_raw(addr: *const libc::sockaddr,
2878                           len: Option<libc::socklen_t>)
2879            -> Option<Self> where Self: Sized
2880        {
2881            if let Some(l) = len {
2882                if l != mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t {
2883                    return None;
2884                }
2885            }
2886            if (*addr).sa_family as i32 != libc::AF_LINK {
2887                return None;
2888            }
2889            Some(Self(ptr::read_unaligned(addr as *const _)))
2890        }
2891    }
2892
2893    impl AsRef<libc::sockaddr_dl> for LinkAddr {
2894        fn as_ref(&self) -> &libc::sockaddr_dl {
2895            &self.0
2896        }
2897    }
2898    }
2899}
2900
2901#[cfg(any(target_os = "android", target_os = "linux"))]
2902#[cfg_attr(docsrs, doc(cfg(all())))]
2903pub mod vsock {
2904    use super::*;
2905    use crate::sys::socket::addr::AddressFamily;
2906    use libc::{sa_family_t, sockaddr_vm};
2907    use std::hash::{Hash, Hasher};
2908    use std::{fmt, mem};
2909
2910    /// Socket address for VMWare VSockets protocol
2911    ///
2912    /// # References
2913    ///
2914    /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html)
2915    #[derive(Copy, Clone)]
2916    #[repr(transparent)]
2917    pub struct VsockAddr(pub(in super::super) sockaddr_vm);
2918
2919    impl private::SockaddrLikePriv for VsockAddr {}
2920    impl SockaddrLike for VsockAddr {
2921        unsafe fn from_raw(
2922            addr: *const libc::sockaddr,
2923            len: Option<libc::socklen_t>,
2924        ) -> Option<Self>
2925        where
2926            Self: Sized,
2927        {
2928            if let Some(l) = len {
2929                if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t {
2930                    return None;
2931                }
2932            }
2933            if (*addr).sa_family as i32 != libc::AF_VSOCK {
2934                return None;
2935            }
2936            Some(Self(ptr::read_unaligned(addr as *const _)))
2937        }
2938    }
2939
2940    impl AsRef<libc::sockaddr_vm> for VsockAddr {
2941        fn as_ref(&self) -> &libc::sockaddr_vm {
2942            &self.0
2943        }
2944    }
2945
2946    impl PartialEq for VsockAddr {
2947        fn eq(&self, other: &Self) -> bool {
2948            let (inner, other) = (self.0, other.0);
2949            (inner.svm_family, inner.svm_cid, inner.svm_port)
2950                == (other.svm_family, other.svm_cid, other.svm_port)
2951        }
2952    }
2953
2954    impl Eq for VsockAddr {}
2955
2956    impl Hash for VsockAddr {
2957        fn hash<H: Hasher>(&self, s: &mut H) {
2958            let inner = self.0;
2959            (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s);
2960        }
2961    }
2962
2963    /// VSOCK Address
2964    ///
2965    /// The address for AF_VSOCK socket is defined as a combination of a
2966    /// 32-bit Context Identifier (CID) and a 32-bit port number.
2967    impl VsockAddr {
2968        /// Construct a `VsockAddr` from its raw fields.
2969        pub fn new(cid: u32, port: u32) -> VsockAddr {
2970            let mut addr: sockaddr_vm = unsafe { mem::zeroed() };
2971            addr.svm_family = AddressFamily::Vsock as sa_family_t;
2972            addr.svm_cid = cid;
2973            addr.svm_port = port;
2974
2975            VsockAddr(addr)
2976        }
2977
2978        /// Context Identifier (CID)
2979        pub fn cid(&self) -> u32 {
2980            self.0.svm_cid
2981        }
2982
2983        /// Port number
2984        pub fn port(&self) -> u32 {
2985            self.0.svm_port
2986        }
2987    }
2988
2989    impl fmt::Display for VsockAddr {
2990        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2991            write!(f, "cid: {} port: {}", self.cid(), self.port())
2992        }
2993    }
2994
2995    impl fmt::Debug for VsockAddr {
2996        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2997            fmt::Display::fmt(self, f)
2998        }
2999    }
3000}
3001
3002#[cfg(test)]
3003mod tests {
3004    use super::*;
3005
3006    mod types {
3007        use super::*;
3008
3009        #[test]
3010        fn test_ipv4addr_to_libc() {
3011            let s = std::net::Ipv4Addr::new(1, 2, 3, 4);
3012            let l = ipv4addr_to_libc(s);
3013            assert_eq!(l.s_addr, u32::to_be(0x01020304));
3014        }
3015
3016        #[test]
3017        fn test_ipv6addr_to_libc() {
3018            let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8);
3019            let l = ipv6addr_to_libc(&s);
3020            assert_eq!(
3021                l.s6_addr,
3022                [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8]
3023            );
3024        }
3025    }
3026
3027    mod link {
3028        #![allow(clippy::cast_ptr_alignment)]
3029
3030        #[cfg(any(
3031            target_os = "ios",
3032            target_os = "macos",
3033            target_os = "illumos"
3034        ))]
3035        use super::super::super::socklen_t;
3036        use super::*;
3037
3038        /// Don't panic when trying to display an empty datalink address
3039        #[cfg(any(
3040            target_os = "dragonfly",
3041            target_os = "freebsd",
3042            target_os = "ios",
3043            target_os = "macos",
3044            target_os = "netbsd",
3045            target_os = "openbsd"
3046        ))]
3047        #[test]
3048        fn test_datalink_display() {
3049            use super::super::LinkAddr;
3050            use std::mem;
3051
3052            let la = LinkAddr(libc::sockaddr_dl {
3053                sdl_len: 56,
3054                sdl_family: 18,
3055                sdl_index: 5,
3056                sdl_type: 24,
3057                sdl_nlen: 3,
3058                sdl_alen: 0,
3059                sdl_slen: 0,
3060                ..unsafe { mem::zeroed() }
3061            });
3062            format!("{}", la);
3063        }
3064
3065        #[cfg(all(
3066            any(
3067                target_os = "android",
3068                target_os = "fuchsia",
3069                target_os = "linux"
3070            ),
3071            target_endian = "little"
3072        ))]
3073        #[test]
3074        fn linux_loopback() {
3075            #[repr(align(2))]
3076            struct Raw([u8; 20]);
3077
3078            let bytes = Raw([
3079                17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0,
3080            ]);
3081            let sa = bytes.0.as_ptr() as *const libc::sockaddr;
3082            let len = None;
3083            let sock_addr =
3084                unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap();
3085            assert_eq!(sock_addr.family(), Some(AddressFamily::Packet));
3086            match sock_addr.as_link_addr() {
3087                Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])),
3088                None => panic!("Can't unwrap sockaddr storage"),
3089            }
3090        }
3091
3092        #[cfg(any(target_os = "ios", target_os = "macos"))]
3093        #[test]
3094        fn macos_loopback() {
3095            let bytes =
3096                [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
3097            let sa = bytes.as_ptr() as *const libc::sockaddr;
3098            let len = Some(bytes.len() as socklen_t);
3099            let sock_addr =
3100                unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap();
3101            assert_eq!(sock_addr.family(), Some(AddressFamily::Link));
3102            match sock_addr.as_link_addr() {
3103                Some(dl) => {
3104                    assert!(dl.addr().is_none());
3105                }
3106                None => panic!("Can't unwrap sockaddr storage"),
3107            }
3108        }
3109
3110        #[cfg(any(target_os = "ios", target_os = "macos"))]
3111        #[test]
3112        fn macos_tap() {
3113            let bytes = [
3114                20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35,
3115                76, -80,
3116            ];
3117            let ptr = bytes.as_ptr();
3118            let sa = ptr as *const libc::sockaddr;
3119            let len = Some(bytes.len() as socklen_t);
3120
3121            let sock_addr =
3122                unsafe { SockaddrStorage::from_raw(sa, len).unwrap() };
3123            assert_eq!(sock_addr.family(), Some(AddressFamily::Link));
3124            match sock_addr.as_link_addr() {
3125                Some(dl) => {
3126                    assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176]))
3127                }
3128                None => panic!("Can't unwrap sockaddr storage"),
3129            }
3130        }
3131
3132        #[cfg(target_os = "illumos")]
3133        #[test]
3134        fn illumos_tap() {
3135            let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176];
3136            let ptr = bytes.as_ptr();
3137            let sa = ptr as *const libc::sockaddr;
3138            let len = Some(bytes.len() as socklen_t);
3139            let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) };
3140
3141            assert!(_sock_addr.is_some());
3142
3143            let sock_addr = _sock_addr.unwrap();
3144
3145            assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link);
3146
3147            assert_eq!(
3148                sock_addr.as_link_addr().unwrap().addr(),
3149                Some([24u8, 101, 144, 221, 76, 176])
3150            );
3151        }
3152
3153        #[test]
3154        fn size() {
3155            #[cfg(any(
3156                target_os = "dragonfly",
3157                target_os = "freebsd",
3158                target_os = "ios",
3159                target_os = "macos",
3160                target_os = "netbsd",
3161                target_os = "illumos",
3162                target_os = "openbsd",
3163                target_os = "haiku"
3164            ))]
3165            let l = mem::size_of::<libc::sockaddr_dl>();
3166            #[cfg(any(
3167                target_os = "android",
3168                target_os = "fuchsia",
3169                target_os = "linux"
3170            ))]
3171            let l = mem::size_of::<libc::sockaddr_ll>();
3172            assert_eq!(LinkAddr::size() as usize, l);
3173        }
3174    }
3175
3176    mod sockaddr_in {
3177        use super::*;
3178        use std::str::FromStr;
3179
3180        #[test]
3181        fn display() {
3182            let s = "127.0.0.1:8080";
3183            let addr = SockaddrIn::from_str(s).unwrap();
3184            assert_eq!(s, format!("{}", addr));
3185        }
3186
3187        #[test]
3188        fn size() {
3189            assert_eq!(
3190                mem::size_of::<libc::sockaddr_in>(),
3191                SockaddrIn::size() as usize
3192            );
3193        }
3194    }
3195
3196    mod sockaddr_in6 {
3197        use super::*;
3198        use std::str::FromStr;
3199
3200        #[test]
3201        fn display() {
3202            let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
3203            let addr = SockaddrIn6::from_str(s).unwrap();
3204            assert_eq!(s, format!("{}", addr));
3205        }
3206
3207        #[test]
3208        fn size() {
3209            assert_eq!(
3210                mem::size_of::<libc::sockaddr_in6>(),
3211                SockaddrIn6::size() as usize
3212            );
3213        }
3214
3215        #[test]
3216        // Ensure that we can convert to-and-from std::net variants without change.
3217        fn to_and_from() {
3218            let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
3219            let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap();
3220            nix_sin6.0.sin6_flowinfo = 0x12345678;
3221            nix_sin6.0.sin6_scope_id = 0x9abcdef0;
3222
3223            let std_sin6 : std::net::SocketAddrV6 = nix_sin6.into();
3224            assert_eq!(nix_sin6, std_sin6.into());
3225        }
3226    }
3227
3228    mod sockaddr_storage {
3229        use super::*;
3230
3231        #[test]
3232        fn from_sockaddr_un_named() {
3233            let ua = UnixAddr::new("/var/run/mysock").unwrap();
3234            let ptr = ua.as_ptr() as *const libc::sockaddr;
3235            let ss = unsafe {
3236                SockaddrStorage::from_raw(ptr, Some(ua.len()))
3237            }.unwrap();
3238            assert_eq!(ss.len(), ua.len());
3239        }
3240
3241        #[cfg(any(target_os = "android", target_os = "linux"))]
3242        #[test]
3243        fn from_sockaddr_un_abstract_named() {
3244            let name = String::from("nix\0abstract\0test");
3245            let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap();
3246            let ptr = ua.as_ptr() as *const libc::sockaddr;
3247            let ss = unsafe {
3248                SockaddrStorage::from_raw(ptr, Some(ua.len()))
3249            }.unwrap();
3250            assert_eq!(ss.len(), ua.len());
3251        }
3252
3253        #[cfg(any(target_os = "android", target_os = "linux"))]
3254        #[test]
3255        fn from_sockaddr_un_abstract_unnamed() {
3256            let ua = UnixAddr::new_unnamed();
3257            let ptr = ua.as_ptr() as *const libc::sockaddr;
3258            let ss = unsafe {
3259                SockaddrStorage::from_raw(ptr, Some(ua.len()))
3260            }.unwrap();
3261            assert_eq!(ss.len(), ua.len());
3262        }
3263    }
3264
3265    mod unixaddr {
3266        use super::*;
3267
3268        #[cfg(any(target_os = "android", target_os = "linux"))]
3269        #[test]
3270        fn abstract_sun_path() {
3271            let name = String::from("nix\0abstract\0test");
3272            let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
3273
3274            let sun_path1 =
3275                unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] };
3276            let sun_path2 = [
3277                0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0,
3278                116, 101, 115, 116,
3279            ];
3280            assert_eq!(sun_path1, sun_path2);
3281        }
3282
3283        #[test]
3284        fn size() {
3285            assert_eq!(
3286                mem::size_of::<libc::sockaddr_un>(),
3287                UnixAddr::size() as usize
3288            );
3289        }
3290    }
3291}