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(data:"@\"")?;
1078 for &b: u8 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) => 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: &[u8]) => fmt_abstract(abs: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(state: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(data:"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&mut DebugStruct<'_, '_>.debug_struct("SockaddrStorage")
1844 // Safe because sockaddr_storage has the least specific
1845 // field types
1846 .field(name:"ss", value: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}
3292