#[cfg(any(
bsd,
linux_android,
solarish,
target_os = "haiku",
target_os = "fuchsia",
target_os = "aix",
))] #[cfg(feature = "net")] pubuseself::datalink::LinkAddr; #[cfg(any(linux_android, apple_targets))] pubuseself::vsock::VsockAddr; usesuper::sa_family_t; usecrate::errno::Errno; #[cfg(linux_android)] usecrate::sys::socket::addr::alg::AlgAddr; #[cfg(linux_android)] usecrate::sys::socket::addr::netlink::NetlinkAddr; #[cfg(all(feature = "ioctl", apple_targets))] usecrate::sys::socket::addr::sys_control::SysControlAddr; usecrate::{NixPath, Result}; use cfg_if::cfg_if; use memoffset::offset_of; use std::convert::TryInto; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; use std::net::{Ipv4Addr, Ipv6Addr}; use std::os::unix::ffi::OsStrExt; use std::path::Path; use std::{fmt, mem, net, ptr, slice};
/// Convert a std::net::Ipv4Addr into the libc form. #[cfg(feature = "net")] pub(crate) constfn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr {
libc::in_addr {
s_addr: u32::from_ne_bytes(addr.octets()),
}
}
/// Convert a std::net::Ipv6Addr into the libc form. #[cfg(feature = "net")] pub(crate) constfn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
libc::in6_addr {
s6_addr: addr.octets(),
}
}
/// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) /// /// # References /// /// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) // Should this be u8? #[repr(i32)] #[non_exhaustive] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pubenum AddressFamily { /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html))
Unix = libc::AF_UNIX, /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html))
Inet = libc::AF_INET, /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html))
Inet6 = libc::AF_INET6, /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(linux_android)]
Netlink = libc::AF_NETLINK, /// Kernel interface for interacting with the routing table #[cfg(not(any(linux_android, target_os = "redox")))]
Route = libc::PF_ROUTE, /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
Packet = libc::AF_PACKET, /// KEXT Controls and Notifications #[cfg(apple_targets)]
System = libc::AF_SYSTEM, /// Amateur radio AX.25 protocol #[cfg(linux_android)]
Ax25 = libc::AF_AX25, /// IPX - Novell protocols #[cfg(not(any(target_os = "aix", target_os = "redox")))]
Ipx = libc::AF_IPX, /// AppleTalk #[cfg(not(target_os = "redox"))]
AppleTalk = libc::AF_APPLETALK, /// AX.25 packet layer protocol. /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) #[cfg(linux_android)]
NetRom = libc::AF_NETROM, /// Can't be used for creating sockets; mostly used for bridge /// links in /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) /// protocol commands. #[cfg(linux_android)]
Bridge = libc::AF_BRIDGE, /// Access to raw ATM PVCs #[cfg(linux_android)]
AtmPvc = libc::AF_ATMPVC, /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) #[cfg(linux_android)]
X25 = libc::AF_X25, /// RATS (Radio Amateur Telecommunications Society) Open /// Systems environment (ROSE) AX.25 packet layer protocol. /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) #[cfg(linux_android)]
Rose = libc::AF_ROSE, /// DECet protocol sockets. #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
Decnet = libc::AF_DECnet, /// Reserved for "802.2LLC project"; never used. #[cfg(linux_android)]
NetBeui = libc::AF_NETBEUI, /// This was a short-lived (between Linux 2.1.30 and /// 2.1.99pre2) protocol family for firewall upcalls. #[cfg(linux_android)]
Security = libc::AF_SECURITY, /// Key management protocol. #[cfg(linux_android)]
Key = libc::AF_KEY, #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(linux_android)]
Ash = libc::AF_ASH, /// Acorn Econet protocol #[cfg(linux_android)]
Econet = libc::AF_ECONET, /// Access to ATM Switched Virtual Circuits #[cfg(linux_android)]
AtmSvc = libc::AF_ATMSVC, /// Reliable Datagram Sockets (RDS) protocol #[cfg(linux_android)]
Rds = libc::AF_RDS, /// IBM SNA #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
Sna = libc::AF_SNA, /// Socket interface over IrDA #[cfg(linux_android)]
Irda = libc::AF_IRDA, /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) #[cfg(linux_android)]
Pppox = libc::AF_PPPOX, /// Legacy protocol for wide area network (WAN) connectivity that was used /// by Sangoma WAN cards #[cfg(linux_android)]
Wanpipe = libc::AF_WANPIPE, /// Logical link control (IEEE 802.2 LLC) protocol #[cfg(linux_android)]
Llc = libc::AF_LLC, /// InfiniBand native addressing #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
Ib = libc::AF_IB, /// Multiprotocol Label Switching #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
Mpls = libc::AF_MPLS, /// Controller Area Network automotive bus protocol #[cfg(linux_android)]
Can = libc::AF_CAN, /// TIPC, "cluster domain sockets" protocol #[cfg(linux_android)]
Tipc = libc::AF_TIPC, /// Bluetooth low-level socket protocol #[cfg(not(any(
target_os = "aix",
solarish,
apple_targets,
target_os = "hurd",
target_os = "redox",
)))]
Bluetooth = libc::AF_BLUETOOTH, /// IUCV (inter-user communication vehicle) z/VM protocol for /// hypervisor-guest interaction #[cfg(linux_android)]
Iucv = libc::AF_IUCV, /// Rx, Andrew File System remote procedure call protocol #[cfg(linux_android)]
RxRpc = libc::AF_RXRPC, /// New "modular ISDN" driver interface protocol #[cfg(not(any(
target_os = "aix",
solarish,
target_os = "haiku",
target_os = "hurd",
target_os = "redox",
)))]
Isdn = libc::AF_ISDN, /// Nokia cellular modem IPC/RPC interface #[cfg(linux_android)]
Phonet = libc::AF_PHONET, /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol #[cfg(linux_android)]
Ieee802154 = libc::AF_IEEE802154, /// Ericsson's Communication CPU to Application CPU interface (CAIF) /// protocol. #[cfg(linux_android)]
Caif = libc::AF_CAIF, /// Interface to kernel crypto API #[cfg(linux_android)]
Alg = libc::AF_ALG, /// Near field communication #[cfg(target_os = "linux")]
Nfc = libc::AF_NFC, /// VMWare VSockets protocol for hypervisor-guest interaction. #[cfg(any(linux_android, apple_targets))]
Vsock = libc::AF_VSOCK, /// ARPANet IMP addresses #[cfg(bsd)]
ImpLink = libc::AF_IMPLINK, /// PUP protocols, e.g. BSP #[cfg(bsd)]
Pup = libc::AF_PUP, /// MIT CHAOS protocols #[cfg(bsd)]
Chaos = libc::AF_CHAOS, /// Novell and Xerox protocol #[cfg(any(apple_targets, netbsdlike))]
Ns = libc::AF_NS, #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(bsd)]
Iso = libc::AF_ISO, /// Bell Labs virtual circuit switch ? #[cfg(bsd)]
Datakit = libc::AF_DATAKIT, /// CCITT protocols, X.25 etc #[cfg(bsd)]
Ccitt = libc::AF_CCITT, /// DEC Direct data link interface #[cfg(bsd)]
Dli = libc::AF_DLI, #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(bsd)]
Lat = libc::AF_LAT, /// NSC Hyperchannel #[cfg(bsd)]
Hylink = libc::AF_HYLINK, /// Link layer interface #[cfg(any(bsd, solarish))]
Link = libc::AF_LINK, /// connection-oriented IP, aka ST II #[cfg(bsd)]
Coip = libc::AF_COIP, /// Computer Network Technology #[cfg(bsd)]
Cnt = libc::AF_CNT, /// Native ATM access #[cfg(bsd)]
Natm = libc::AF_NATM, /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) #[cfg(linux_android)]
Unspec = libc::AF_UNSPEC,
}
impl AddressFamily { /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from /// the `sa_family` field of a `sockaddr`. /// /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet /// and System. Returns None for unsupported or unknown address families. pubconstfn from_i32(family: i32) -> Option<AddressFamily> { match family {
libc::AF_UNIX => Some(AddressFamily::Unix),
libc::AF_INET => Some(AddressFamily::Inet),
libc::AF_INET6 => Some(AddressFamily::Inet6), #[cfg(linux_android)]
libc::AF_NETLINK => Some(AddressFamily::Netlink), #[cfg(apple_targets)]
libc::AF_SYSTEM => Some(AddressFamily::System), #[cfg(not(any(linux_android, target_os = "redox")))]
libc::PF_ROUTE => Some(AddressFamily::Route), #[cfg(linux_android)]
libc::AF_PACKET => Some(AddressFamily::Packet), #[cfg(any(bsd, solarish))]
libc::AF_LINK => Some(AddressFamily::Link), #[cfg(any(linux_android, apple_targets))]
libc::AF_VSOCK => Some(AddressFamily::Vsock),
_ => None,
}
}
}
/// A wrapper around `sockaddr_un`. #[derive(Clone, Copy, Debug)] #[repr(C)] pubstruct UnixAddr { // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts
sun: libc::sockaddr_un, /// The length of the valid part of `sun`, including the sun_family field /// but excluding any trailing nul. // On the BSDs, this field is built into sun #[cfg(not(any(bsd, target_os = "haiku", target_os = "hurd")))]
sun_len: u8,
}
// linux man page unix(7) says there are 3 kinds of unix socket: // pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 // unnamed: addrlen = sizeof(sa_family_t) // abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))] // // what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path) #[derive(PartialEq, Eq, Hash)] enum UnixAddrKind<'a> {
Pathname(&'a Path),
Unnamed, #[cfg(linux_android)] Abstract(&'a [u8]),
} impl<'a> UnixAddrKind<'a> { /// Safety: sun & sun_len must be valid #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms unsafefn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self {
assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); let path_len =
sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); if path_len == 0 { returnSelf::Unnamed;
} #[cfg(linux_android)] if sun.sun_path[0] == 0 { let name = unsafe {
slice::from_raw_parts(
sun.sun_path.as_ptr().add(1).cast(),
path_len - 1,
)
}; returnSelf::Abstract(name);
} let pathname = unsafe {
slice::from_raw_parts(sun.sun_path.as_ptr().cast(), path_len)
}; if pathname.last() == Some(&0) { // A trailing NUL is not considered part of the path, and it does // not need to be included in the addrlen passed to functions like // bind(). However, Linux adds a trailing NUL, even if one was not // originally present, when returning addrs from functions like // getsockname() (the BSDs do not do that). So we need to filter // out any trailing NUL here, so sockaddrs can round-trip through // the kernel and still compare equal. Self::Pathname(Path::new(OsStr::from_bytes(
&pathname[0..pathname.len() - 1],
)))
} else { Self::Pathname(Path::new(OsStr::from_bytes(pathname)))
}
}
}
impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pubfn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
path.with_nix_path(|cstr| unsafe { letmut ret = libc::sockaddr_un {
sun_family: AddressFamily::Unix as sa_family_t,
..mem::zeroed()
};
let bytes = cstr.to_bytes();
if bytes.len() >= ret.sun_path.len() { return Err(Errno::ENAMETOOLONG);
}
let sun_len = (bytes.len()
+ offset_of!(libc::sockaddr_un, sun_path))
.try_into()
.unwrap();
/// Create a new `sockaddr_un` representing an address in the "abstract namespace". /// /// The leading nul byte for the abstract namespace is automatically added; /// thus the input `path` is expected to be the bare name, not NUL-prefixed. /// This is a Linux-specific extension, primarily used to allow chrooted /// processes to communicate with processes having a different filesystem view. #[cfg(linux_android)] #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pubfn new_abstract(path: &[u8]) -> Result<UnixAddr> { unsafe { letmut ret = libc::sockaddr_un {
sun_family: AddressFamily::Unix as sa_family_t,
..mem::zeroed()
};
if path.len() >= ret.sun_path.len() { return Err(Errno::ENAMETOOLONG);
} let sun_len =
(path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path))
.try_into()
.unwrap();
// Abstract addresses are represented by sun_path[0] == // b'\0', so copy starting one byte in.
ptr::copy_nonoverlapping(
path.as_ptr(),
ret.sun_path.as_mut_ptr().offset(1).cast(),
path.len(),
);
Ok(UnixAddr::from_raw_parts(ret, sun_len))
}
}
/// Create a new `sockaddr_un` representing an "unnamed" unix socket address. #[cfg(linux_android)] pubfn new_unnamed() -> UnixAddr { let ret = libc::sockaddr_un {
sun_family: AddressFamily::Unix as sa_family_t,
..unsafe { mem::zeroed() }
};
let sun_len: u8 =
offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap();
/// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` /// is the size of the valid portion of the struct, excluding any trailing /// NUL. /// /// # Safety /// This pair of sockaddr_un & sun_len must be a valid unix addr, which /// means: /// - sun_len >= offset_of(sockaddr_un, sun_path) /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) /// - if this is a unix addr with a pathname, sun.sun_path is a /// fs path, not necessarily nul-terminated. pub(crate) unsafefn from_raw_parts(
sun: libc::sockaddr_un,
sun_len: u8,
) -> UnixAddr {
cfg_if! { if#[cfg(any(linux_android,
target_os = "fuchsia",
solarish,
target_os = "redox",
))]
{
UnixAddr { sun, sun_len }
} else {
assert_eq!(sun_len, sun.sun_len);
UnixAddr {sun}
}
}
}
fn kind(&self) -> UnixAddrKind<'_> { // SAFETY: our sockaddr is always valid because of the invariant on the struct unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) }
}
/// If this address represents a filesystem path, return that path. pubfn path(&self) -> Option<&Path> { matchself.kind() {
UnixAddrKind::Pathname(path) => Some(path),
_ => None,
}
}
/// If this address represents an abstract socket, return its name. /// /// For abstract sockets only the bare name is returned, without the /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. #[cfg(linux_android)] pubfn as_abstract(&self) -> Option<&[u8]> { matchself.kind() {
UnixAddrKind::Abstract(name) => Some(name),
_ => None,
}
}
/// Check if this address is an "unnamed" unix socket address. #[cfg(linux_android)] #[inline] pubfn is_unnamed(&self) -> bool {
matches!(self.kind(), UnixAddrKind::Unnamed)
}
/// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` #[inline] pubfn path_len(&self) -> usize { self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path)
} /// Returns a pointer to the raw `sockaddr_un` struct #[inline] pubfn as_ptr(&self) -> *const libc::sockaddr_un {
&self.sun
} /// Returns a mutable pointer to the raw `sockaddr_un` struct #[inline] pubfn as_mut_ptr(&mutself) -> *mut libc::sockaddr_un {
&mutself.sun
}
unsafefn from_raw(
addr: *const libc::sockaddr,
len: Option<libc::socklen_t>,
) -> Option<Self> where Self: Sized,
{ iflet Some(l) = len { if (l as usize) < offset_of!(libc::sockaddr_un, sun_path)
|| l > u8::MAX as libc::socklen_t
{ return None;
}
} ifunsafe { (*addr).sa_family as i32 != libc::AF_UNIX } { return None;
} letmut su: libc::sockaddr_un = unsafe { mem::zeroed() }; let sup = &mut su as *mut libc::sockaddr_un as *mut u8;
cfg_if! { if#[cfg(any(linux_android,
target_os = "fuchsia",
solarish,
target_os = "redox",
))] { let su_len = len.unwrap_or(
mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
);
} else { let su_len = unsafe { len.unwrap_or((*addr).sa_len as libc::socklen_t) };
}
} unsafe { ptr::copy(addr as *const u8, sup, su_len as usize) };
Some(unsafe { Self::from_raw_parts(su, su_len as u8) })
}
fn size() -> libc::socklen_t where Self: Sized,
{
mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
}
unsafefn set_length(
&mutself,
new_length: usize,
) -> std::result::Result<(), SocketAddressLengthNotDynamic> { // `new_length` is only used on some platforms, so it must be provided even when not used #![allow(unused_variables)]
cfg_if! { if#[cfg(any(linux_android,
target_os = "fuchsia",
solarish,
target_os = "redox",
))] { self.sun_len = new_length as u8;
}
};
Ok(())
}
}
/// Anything that, in C, can be cast back and forth to `sockaddr`. /// /// Most implementors also implement `AsRef<libc::XXX>` to access their /// inner type read-only. #[allow(clippy::len_without_is_empty)] pubtrait SockaddrLike: private::SockaddrLikePriv { /// Returns a raw pointer to the inner structure. Useful for FFI. fn as_ptr(&self) -> *const libc::sockaddr { selfas *constSelfas *const libc::sockaddr
}
/// Unsafe constructor from a variable length source /// /// Some C APIs from provide `len`, and others do not. If it's provided it /// will be validated. If not, it will be guessed based on the family. /// /// # Arguments /// /// - `addr`: raw pointer to something that can be cast to a /// `libc::sockaddr`. For example, `libc::sockaddr_in`, /// `libc::sockaddr_in6`, etc. /// - `len`: For fixed-width types like `sockaddr_in`, it will be /// validated if present and ignored if not. For variable-width /// types it is required and must be the total length of valid /// data. For example, if `addr` points to a /// named `sockaddr_un`, then `len` must be the length of the /// structure up to but not including the trailing NUL. /// /// # Safety /// /// `addr` must be valid for the specific type of sockaddr. `len`, if /// present, must not exceed the length of valid data in `addr`. unsafefn from_raw(
addr: *const libc::sockaddr,
len: Option<libc::socklen_t>,
) -> Option<Self> where Self: Sized;
/// Return the address family of this socket /// /// # Examples /// One common use is to match on the family of a union type, like this: /// ``` /// # use nix::sys::socket::*; /// # use std::os::unix::io::AsRawFd; /// let fd = socket(AddressFamily::Inet, SockType::Stream, /// SockFlag::empty(), None).unwrap(); /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).unwrap(); /// match ss.family().unwrap() { /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), /// _ => println!("Unexpected address family") /// } /// ``` fn family(&self) -> Option<AddressFamily> { // Safe since all implementors have a sa_family field at the same // address, and they're all repr(C)
AddressFamily::from_i32(unsafe {
(*(selfas *constSelfas *const libc::sockaddr)).sa_family as i32
})
}
cfg_if! { if#[cfg(bsd)] { /// Return the length of valid data in the sockaddr structure. /// /// For fixed-size sockaddrs, this should be the size of the /// structure. But for variable-sized types like [`UnixAddr`] it /// may be less. fn len(&self) -> libc::socklen_t { // Safe since all implementors have a sa_len field at the same // address, and they're all repr(transparent). // Robust for all implementors. unsafe {
(*(selfas *constSelfas *const libc::sockaddr)).sa_len
}.into()
}
} else { /// Return the length of valid data in the sockaddr structure. /// /// For fixed-size sockaddrs, this should be the size of the /// structure. But for variable-sized types like [`UnixAddr`] it /// may be less. fn len(&self) -> libc::socklen_t { // No robust default implementation is possible without an // sa_len field. Implementors with a variable size must // override this method.
mem::size_of_val(self) as libc::socklen_t
}
}
}
/// Return the available space in the structure fn size() -> libc::socklen_t where Self: Sized,
{
mem::size_of::<Self>() as libc::socklen_t
}
/// Set the length of this socket address /// /// This method may only be called on socket addresses whose lengths are dynamic, and it /// returns an error if called on a type whose length is static. /// /// # Safety /// /// `new_length` must be a valid length for this type of address. Specifically, reads of that /// length from `self` must be valid. #[doc(hidden)] unsafefn set_length(
&mutself,
_new_length: usize,
) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
Err(SocketAddressLengthNotDynamic)
}
}
/// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically /// fixed. #[derive(Copy, Clone, Debug)] pubstruct SocketAddressLengthNotDynamic; impl fmt::Display for SocketAddressLengthNotDynamic { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Attempted to set length on socket whose length is statically fixed")
}
} impl std::error::Error for SocketAddressLengthNotDynamic {}
/// `()` can be used in place of a real Sockaddr when no address is expected, /// for example for a field of `Option<S> where S: SockaddrLike`. // If this RFC ever stabilizes, then ! will be a better choice. // https://github.com/rust-lang/rust/issues/35121 impl SockaddrLike for () { fn as_ptr(&self) -> *const libc::sockaddr {
ptr::null()
}
#[cfg(feature = "net")] impl SockaddrIn { /// Returns the IP address associated with this socket address, in native /// endian. pubconstfn ip(&self) -> net::Ipv4Addr { let bytes = self.0.sin_addr.s_addr.to_ne_bytes(); let (a, b, c, d) = (bytes[0], bytes[1], bytes[2], bytes[3]);
Ipv4Addr::new(a, b, c, d)
}
/// Creates a new socket address from IPv4 octets and a port number. pubfn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { Self(libc::sockaddr_in { #[cfg(any(
bsd,
target_os = "aix",
target_os = "haiku",
target_os = "hurd"
))]
sin_len: Self::size() as u8,
sin_family: AddressFamily::Inet as sa_family_t,
sin_port: u16::to_be(port),
sin_addr: libc::in_addr {
s_addr: u32::from_ne_bytes([a, b, c, d]),
},
sin_zero: unsafe { mem::zeroed() },
})
}
/// Returns the port number associated with this socket address, in native /// endian. pubconstfn port(&self) -> u16 {
u16::from_be(self.0.sin_port)
}
}
#[cfg(feature = "net")] impl private::SockaddrLikePriv for SockaddrIn {} #[cfg(feature = "net")] impl SockaddrLike for SockaddrIn { unsafefn from_raw(
addr: *const libc::sockaddr,
len: Option<libc::socklen_t>,
) -> Option<Self> where Self: Sized,
{ iflet Some(l) = len { if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t { return None;
}
} ifunsafe { (*addr).sa_family as i32 != libc::AF_INET } { return None;
}
Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
}
}
#[cfg(feature = "net")] impl SockaddrIn6 { /// Returns the flow information associated with this address. pubconstfn flowinfo(&self) -> u32 { self.0.sin6_flowinfo
}
/// Returns the IP address associated with this socket address. pubconstfn ip(&self) -> net::Ipv6Addr { let bytes = self.0.sin6_addr.s6_addr; let (a, b, c, d, e, f, g, h) = (
((bytes[0] as u16) << 8) | bytes[1] as u16,
((bytes[2] as u16) << 8) | bytes[3] as u16,
((bytes[4] as u16) << 8) | bytes[5] as u16,
((bytes[6] as u16) << 8) | bytes[7] as u16,
((bytes[8] as u16) << 8) | bytes[9] as u16,
((bytes[10] as u16) << 8) | bytes[11] as u16,
((bytes[12] as u16) << 8) | bytes[13] as u16,
((bytes[14] as u16) << 8) | bytes[15] as u16,
);
Ipv6Addr::new(a, b, c, d, e, f, g, h)
}
/// Returns the port number associated with this socket address, in native /// endian. pubconstfn port(&self) -> u16 {
u16::from_be(self.0.sin6_port)
}
/// Returns the scope ID associated with this address. pubconstfn scope_id(&self) -> u32 { self.0.sin6_scope_id
}
}
#[cfg(feature = "net")] impl fmt::Display for SockaddrIn6 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // These things are really hard to display properly. Easier to let std // do it. let std = net::SocketAddrV6::new( self.ip(), self.port(), self.flowinfo(), self.scope_id(),
);
std.fmt(f)
}
}
#[cfg(feature = "net")] impl From<net::SocketAddrV6> for SockaddrIn6 { fn from(addr: net::SocketAddrV6) -> Self { #[allow(clippy::needless_update)] // It isn't needless on Illumos Self(libc::sockaddr_in6 { #[cfg(any(
bsd,
target_os = "haiku",
target_os = "hermit",
target_os = "hurd"
))]
sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8,
sin6_family: AddressFamily::Inet6 as sa_family_t,
sin6_port: addr.port().to_be(), // network byte order
sin6_addr: ipv6addr_to_libc(addr.ip()),
sin6_flowinfo: addr.flowinfo(), // host byte order
sin6_scope_id: addr.scope_id(), // host byte order
..unsafe { mem::zeroed() }
})
}
}
/// A container for any sockaddr type /// /// Just like C's `sockaddr_storage`, this type is large enough to hold any type /// of sockaddr. It can be used as an argument with functions like /// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is /// a union, it can be safely accessed through the `as_*` methods. /// /// # Example /// ``` /// # use nix::sys::socket::*; /// # use std::str::FromStr; /// # use std::os::unix::io::AsRawFd; /// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); /// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), /// None).unwrap(); /// bind(fd.as_raw_fd(), &localhost).expect("bind"); /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).expect("getsockname"); /// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); /// ``` #[derive(Clone, Copy, Eq)] #[repr(C)] pub union SockaddrStorage { #[cfg(linux_android)]
alg: AlgAddr, #[cfg(all(
feature = "net",
not(any(target_os = "hurd", target_os = "redox"))
))] #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
dl: LinkAddr, #[cfg(linux_android)]
nl: NetlinkAddr, #[cfg(all(feature = "ioctl", apple_targets))] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
sctl: SysControlAddr, #[cfg(feature = "net")]
sin: SockaddrIn, #[cfg(feature = "net")]
sin6: SockaddrIn6,
ss: libc::sockaddr_storage,
su: UnixAddr, #[cfg(any(linux_android, apple_targets))]
vsock: VsockAddr,
} impl private::SockaddrLikePriv for SockaddrStorage {} impl SockaddrLike for SockaddrStorage { unsafefn from_raw(
addr: *const libc::sockaddr,
l: Option<libc::socklen_t>,
) -> Option<Self> where Self: Sized,
{ if addr.is_null() { return None;
} iflet Some(len) = l { let ulen = len as usize; if ulen < offset_of!(libc::sockaddr, sa_data)
|| ulen > mem::size_of::<libc::sockaddr_storage>()
{
None
} else { letmut ss: libc::sockaddr_storage = unsafe { mem::zeroed() }; let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; unsafe { ptr::copy(addr as *const u8, ssp, len as usize) }; #[cfg(any(
linux_android,
target_os = "fuchsia",
solarish,
))] if i32::from(ss.ss_family) == libc::AF_UNIX { // Safe because we UnixAddr is strictly smaller than // SockaddrStorage, and we just initialized the structure. unsafe {
(*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr))
.sun_len = len as u8;
}
}
Some(Self { ss })
}
} else { // If length is not available and addr is of a fixed-length type, // copy it. If addr is of a variable length type and len is not // available, then there's nothing we can do. matchunsafe { (*addr).sa_family as i32 } { #[cfg(linux_android)]
libc::AF_ALG => unsafe {
AlgAddr::from_raw(addr, l).map(|alg| Self { alg })
}, #[cfg(feature = "net")]
libc::AF_INET => unsafe {
SockaddrIn::from_raw(addr, l).map(|sin| Self { sin })
}, #[cfg(feature = "net")]
libc::AF_INET6 => unsafe {
SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 })
}, #[cfg(any(bsd, solarish, target_os = "haiku"))] #[cfg(feature = "net")]
libc::AF_LINK => unsafe {
LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
}, #[cfg(linux_android)]
libc::AF_NETLINK => unsafe {
NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl })
}, #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")]
libc::AF_PACKET => unsafe {
LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
}, #[cfg(all(feature = "ioctl", apple_targets))]
libc::AF_SYSTEM => unsafe {
SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl })
}, #[cfg(any(linux_android, apple_targets))]
libc::AF_VSOCK => unsafe {
VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock })
},
_ => None,
}
}
}
#[cfg(any(linux_android, target_os = "fuchsia", solarish))] fn len(&self) -> libc::socklen_t { matchself.as_unix_addr() { // The UnixAddr type knows its own length
Some(ua) => ua.len(), // For all else, we're just a boring SockaddrStorage
None => mem::size_of_val(self) as libc::socklen_t,
}
}
macro_rules! accessors {
(
$fname:ident,
$fname_mut:ident,
$sockty:ty,
$family:expr,
$libc_ty:ty,
$field:ident) => { /// Safely and falliably downcast to an immutable reference pubfn $fname(&self) -> Option<&$sockty> { ifself.family() == Some($family)
&& self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t
{ // Safe because family and len are validated
Some(unsafe { &self.$field })
} else {
None
}
}
/// Safely and falliably downcast to a mutable reference pubfn $fname_mut(&mutself) -> Option<&mut$sockty> { ifself.family() == Some($family)
&& self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t
{ // Safe because family and len are validated
Some(unsafe { &mutself.$field })
} else {
None
}
}
};
}
impl SockaddrStorage { /// Downcast to an immutable `[UnixAddr]` reference. pubfn as_unix_addr(&self) -> Option<&UnixAddr> {
cfg_if! { if#[cfg(any(linux_android,
target_os = "fuchsia",
solarish,
))]
{ let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; // Safe because UnixAddr is strictly smaller than // sockaddr_storage, and we're fully initialized let len = unsafe {
(*(p as *const UnixAddr )).sun_len as usize
};
} else { let len = self.len() as usize;
}
} // Sanity checks ifself.family() != Some(AddressFamily::Unix)
|| len < offset_of!(libc::sockaddr_un, sun_path)
|| len > mem::size_of::<libc::sockaddr_un>()
{
None
} else {
Some(unsafe { &self.su })
}
}
/// Downcast to a mutable `[UnixAddr]` reference. pubfn as_unix_addr_mut(&mutself) -> Option<&mut UnixAddr> {
cfg_if! { if#[cfg(any(linux_android,
target_os = "fuchsia",
solarish,
))]
{ let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; // Safe because UnixAddr is strictly smaller than // sockaddr_storage, and we're fully initialized let len = unsafe {
(*(p as *const UnixAddr )).sun_len as usize
};
} else { let len = self.len() as usize;
}
} // Sanity checks ifself.family() != Some(AddressFamily::Unix)
|| len < offset_of!(libc::sockaddr_un, sun_path)
|| len > mem::size_of::<libc::sockaddr_un>()
{
None
} else {
Some(unsafe { &mutself.su })
}
}
impl fmt::Debug for SockaddrStorage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SockaddrStorage") // Safe because sockaddr_storage has the least specific // field types
.field("ss", unsafe { &self.ss })
.finish()
}
}
pub(super) mod private { pubtrait SockaddrLikePriv { /// Returns a mutable raw pointer to the inner structure. /// /// # Safety /// /// This method is technically safe, but modifying the inner structure's /// `family` or `len` fields may result in violating Nix's invariants. /// It is best to use this method only with foreign functions that do /// not change the sockaddr type. fn as_mut_ptr(&mutself) -> *mut libc::sockaddr { selfas *mutSelfas *mut libc::sockaddr
}
}
}
#[cfg(linux_android)] pubmod netlink { usesuper::*; usecrate::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_nl}; use std::{fmt, mem};
/// Address for the Linux kernel user interface device. /// /// # References /// /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pubstruct NetlinkAddr(pub(insuper::super) sockaddr_nl);
impl NetlinkAddr { /// Construct a new socket address from its port ID and multicast groups /// mask. pubfn new(pid: u32, groups: u32) -> NetlinkAddr { letmut addr: sockaddr_nl = unsafe { mem::zeroed() };
addr.nl_family = AddressFamily::Netlink as sa_family_t;
addr.nl_pid = pid;
addr.nl_groups = groups;
NetlinkAddr(addr)
}
/// Return the socket's port ID. pubconstfn pid(&self) -> u32 { self.0.nl_pid
}
/// Return the socket's multicast groups mask pubconstfn groups(&self) -> u32 { self.0.nl_groups
}
}
impl private::SockaddrLikePriv for NetlinkAddr {} impl SockaddrLike for NetlinkAddr { unsafefn from_raw(
addr: *const libc::sockaddr,
len: Option<libc::socklen_t>,
) -> Option<Self> where Self: Sized,
{ iflet Some(l) = len { if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t { return None;
}
} ifunsafe { (*addr).sa_family as i32 != libc::AF_NETLINK } { return None;
}
Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
}
}
#[cfg(linux_android)] pubmod alg { usesuper::*; use libc::{sockaddr_alg, AF_ALG}; use std::ffi::CStr; use std::hash::{Hash, Hasher}; use std::{fmt, mem, str};
/// Socket address for the Linux kernel crypto API #[derive(Copy, Clone)] #[repr(transparent)] pubstruct AlgAddr(pub(insuper::super) sockaddr_alg);
impl private::SockaddrLikePriv for AlgAddr {} impl SockaddrLike for AlgAddr { unsafefn from_raw(
addr: *const libc::sockaddr,
l: Option<libc::socklen_t>,
) -> Option<Self> where Self: Sized,
{ iflet Some(l) = l { if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t
{ return None;
}
} ifunsafe { (*addr).sa_family as i32 != libc::AF_ALG } { return None;
}
Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
}
}
impl SysControlAddr { /// Construct a new `SysControlAddr` from its kernel unique identifier /// and unit number. pubconstfn new(id: u32, unit: u32) -> SysControlAddr { let addr = libc::sockaddr_ctl {
sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar,
sc_family: AddressFamily::System as c_uchar,
ss_sysaddr: libc::AF_SYS_CONTROL as u16,
sc_id: id,
sc_unit: unit,
sc_reserved: [0; 5]
};
SysControlAddr(addr)
}
/// Construct a new `SysControlAddr` from its human readable name and /// unit number. pubfn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { if name.len() > MAX_KCTL_NAME { return Err(Errno::ENAMETOOLONG);
}
impl LinkAddr { /// interface index, if != 0, system given index for interface #[cfg(not(target_os = "haiku"))] pubfn ifindex(&self) -> usize { self.0.sdl_index as usize
}
/// MAC address start position pubfn nlen(&self) -> usize { self.0.sdl_nlen as usize
}
/// link level address length pubfn alen(&self) -> usize { self.0.sdl_alen as usize
}
/// link layer selector length #[cfg(not(target_os = "haiku"))] pubfn slen(&self) -> usize { self.0.sdl_slen as usize
}
/// if link level address length == 0, /// or `sdl_data` not be larger. pubfn is_empty(&self) -> bool { let nlen = self.nlen(); let alen = self.alen(); let data_len = self.0.sdl_data.len();
alen == 0 || nlen + alen >= data_len
}
/// Physical-layer address (MAC) // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] pubfn addr(&self) -> Option<[u8; 6]> { let nlen = self.nlen(); let data = self.0.sdl_data;
ifself.is_empty() {
None
} else {
Some([
data[nlen] as u8,
data[nlen + 1] as u8,
data[nlen + 2] as u8,
data[nlen + 3] as u8,
data[nlen + 4] as u8,
data[nlen + 5] as u8,
])
}
}
}
/// VSOCK Address /// /// The address for AF_VSOCK socket is defined as a combination of a /// 32-bit Context Identifier (CID) and a 32-bit port number. impl VsockAddr { /// Construct a `VsockAddr` from its raw fields. pubfn new(cid: u32, port: u32) -> VsockAddr { letmut addr: sockaddr_vm = unsafe { mem::zeroed() };
addr.svm_family = AddressFamily::Vsock as sa_family_t;
addr.svm_cid = cid;
addr.svm_port = port;
#[cfg(apple_targets)]
{
addr.svm_len = std::mem::size_of::<sockaddr_vm>() as u8;
}
VsockAddr(addr)
}
#[test] fn test_ipv4addr_to_libc() { let s = std::net::Ipv4Addr::new(1, 2, 3, 4); let l = ipv4addr_to_libc(s);
assert_eq!(l.s_addr, u32::to_be(0x01020304));
}
#[test] fn test_ipv6addr_to_libc() { let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); let l = ipv6addr_to_libc(&s);
assert_eq!(
l.s6_addr,
[0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8]
);
}
}
#[cfg(not(any(target_os = "hurd", target_os = "redox")))] #[allow(clippy::cast_ptr_alignment)] mod link { #[cfg(any(apple_targets, solarish))] usesuper::super::super::socklen_t; usesuper::*;
/// Don't panic when trying to display an empty datalink address #[cfg(bsd)] #[test] fn test_datalink_display() { usesuper::super::LinkAddr; use std::mem;
#[test] fn ip() { let s = "127.0.0.1:8082"; let ip = SockaddrIn::from_str(s).unwrap().ip();
assert_eq!("127.0.0.1", format!("{ip}"));
}
}
mod sockaddr_in6 { usesuper::*; use std::str::FromStr;
#[test] fn display() { let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; let addr = SockaddrIn6::from_str(s).unwrap();
assert_eq!(s, format!("{addr}"));
}
#[test] fn ip() { let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; let ip = SockaddrIn6::from_str(s).unwrap().ip();
assert_eq!("1234:5678:90ab:cdef::1111:2222", format!("{ip}"));
}
#[test] // Ensure that we can convert to-and-from std::net variants without change. fn to_and_from() { let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; letmut nix_sin6 = SockaddrIn6::from_str(s).unwrap();
nix_sin6.0.sin6_flowinfo = 0x12345678;
nix_sin6.0.sin6_scope_id = 0x9abcdef0;
let std_sin6: std::net::SocketAddrV6 = nix_sin6.into();
assert_eq!(nix_sin6, std_sin6.into());
}
}
mod sockaddr_storage { usesuper::*;
#[test] fn from_sockaddr_un_named() { let ua = UnixAddr::new("/var/run/mysock").unwrap(); let ptr = ua.as_ptr().cast(); let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
.unwrap();
assert_eq!(ss.len(), ua.len());
}
#[cfg(linux_android)] #[test] fn from_sockaddr_un_abstract_named() { let name = String::from("nix\0abstract\0test"); let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); let ptr = ua.as_ptr().cast(); let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
.unwrap();
assert_eq!(ss.len(), ua.len());
}
#[cfg(linux_android)] #[test] fn from_sockaddr_un_abstract_unnamed() { let ua = UnixAddr::new_unnamed(); let ptr = ua.as_ptr().cast(); let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
.unwrap();
assert_eq!(ss.len(), ua.len());
}
}
mod unixaddr { usesuper::*;
#[cfg(linux_android)] #[test] fn abstract_sun_path() { let name = String::from("nix\0abstract\0test"); let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.36Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.