use super::sa_family_t;
use crate::{Error, Result, NixPath};
use crate::errno::Errno;
use std::{fmt, mem, net, ptr, slice};
use std::ffi::OsStr;
use std::hash::{Hash, Hasher};
use std::path::Path;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(target_os = "android", target_os = "linux"))]
use crate::sys::socket::addr::netlink::NetlinkAddr;
#[cfg(any(target_os = "android", target_os = "linux"))]
use crate::sys::socket::addr::alg::AlgAddr;
#[cfg(any(target_os = "ios", target_os = "macos"))]
use std::os::unix::io::RawFd;
#[cfg(any(target_os = "ios", target_os = "macos"))]
use crate::sys::socket::addr::sys_control::SysControlAddr;
#[cfg(any(target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
pub use self::datalink::LinkAddr;
#[cfg(target_os = "linux")]
pub use self::vsock::VsockAddr;
#[repr(i32)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum AddressFamily {
Unix = libc::AF_UNIX,
Inet = libc::AF_INET,
Inet6 = libc::AF_INET6,
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink = libc::AF_NETLINK,
#[cfg(any(target_os = "android", target_os = "linux"))]
Packet = libc::AF_PACKET,
#[cfg(any(target_os = "ios", target_os = "macos"))]
System = libc::AF_SYSTEM,
#[cfg(any(target_os = "android", target_os = "linux"))]
Ax25 = libc::AF_AX25,
Ipx = libc::AF_IPX,
AppleTalk = libc::AF_APPLETALK,
#[cfg(any(target_os = "android", target_os = "linux"))]
NetRom = libc::AF_NETROM,
#[cfg(any(target_os = "android", target_os = "linux"))]
Bridge = libc::AF_BRIDGE,
#[cfg(any(target_os = "android", target_os = "linux"))]
AtmPvc = libc::AF_ATMPVC,
#[cfg(any(target_os = "android", target_os = "linux"))]
X25 = libc::AF_X25,
#[cfg(any(target_os = "android", target_os = "linux"))]
Rose = libc::AF_ROSE,
Decnet = libc::AF_DECnet,
#[cfg(any(target_os = "android", target_os = "linux"))]
NetBeui = libc::AF_NETBEUI,
#[cfg(any(target_os = "android", target_os = "linux"))]
Security = libc::AF_SECURITY,
#[cfg(any(target_os = "android", target_os = "linux"))]
Key = libc::AF_KEY,
#[cfg(any(target_os = "android", target_os = "linux"))]
Ash = libc::AF_ASH,
#[cfg(any(target_os = "android", target_os = "linux"))]
Econet = libc::AF_ECONET,
#[cfg(any(target_os = "android", target_os = "linux"))]
AtmSvc = libc::AF_ATMSVC,
#[cfg(any(target_os = "android", target_os = "linux"))]
Rds = libc::AF_RDS,
Sna = libc::AF_SNA,
#[cfg(any(target_os = "android", target_os = "linux"))]
Irda = libc::AF_IRDA,
#[cfg(any(target_os = "android", target_os = "linux"))]
Pppox = libc::AF_PPPOX,
#[cfg(any(target_os = "android", target_os = "linux"))]
Wanpipe = libc::AF_WANPIPE,
#[cfg(any(target_os = "android", target_os = "linux"))]
Llc = libc::AF_LLC,
#[cfg(target_os = "linux")]
Ib = libc::AF_IB,
#[cfg(target_os = "linux")]
Mpls = libc::AF_MPLS,
#[cfg(any(target_os = "android", target_os = "linux"))]
Can = libc::AF_CAN,
#[cfg(any(target_os = "android", target_os = "linux"))]
Tipc = libc::AF_TIPC,
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
Bluetooth = libc::AF_BLUETOOTH,
#[cfg(any(target_os = "android", target_os = "linux"))]
Iucv = libc::AF_IUCV,
#[cfg(any(target_os = "android", target_os = "linux"))]
RxRpc = libc::AF_RXRPC,
Isdn = libc::AF_ISDN,
#[cfg(any(target_os = "android", target_os = "linux"))]
Phonet = libc::AF_PHONET,
#[cfg(any(target_os = "android", target_os = "linux"))]
Ieee802154 = libc::AF_IEEE802154,
#[cfg(any(target_os = "android", target_os = "linux"))]
Caif = libc::AF_CAIF,
#[cfg(any(target_os = "android", target_os = "linux"))]
Alg = libc::AF_ALG,
#[cfg(target_os = "linux")]
Nfc = libc::AF_NFC,
#[cfg(target_os = "linux")]
Vsock = libc::AF_VSOCK,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
ImpLink = libc::AF_IMPLINK,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Pup = libc::AF_PUP,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Chaos = libc::AF_CHAOS,
#[cfg(any(target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Ns = libc::AF_NS,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Iso = libc::AF_ISO,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Datakit = libc::AF_DATAKIT,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Ccitt = libc::AF_CCITT,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Dli = libc::AF_DLI,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Lat = libc::AF_LAT,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Hylink = libc::AF_HYLINK,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Link = libc::AF_LINK,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Coip = libc::AF_COIP,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Cnt = libc::AF_CNT,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Natm = libc::AF_NATM,
#[cfg(any(target_os = "android", target_os = "linux"))]
Unspec = libc::AF_UNSPEC,
}
impl AddressFamily {
pub fn 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(any(target_os = "android", target_os = "linux"))]
libc::AF_NETLINK => Some(AddressFamily::Netlink),
#[cfg(any(target_os = "macos", target_os = "macos"))]
libc::AF_SYSTEM => Some(AddressFamily::System),
#[cfg(any(target_os = "android", target_os = "linux"))]
libc::AF_PACKET => Some(AddressFamily::Packet),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
libc::AF_LINK => Some(AddressFamily::Link),
#[cfg(target_os = "linux")]
libc::AF_VSOCK => Some(AddressFamily::Vsock),
_ => None
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum InetAddr {
V4(libc::sockaddr_in),
V6(libc::sockaddr_in6),
}
impl InetAddr {
pub fn from_std(std: &net::SocketAddr) -> InetAddr {
match *std {
net::SocketAddr::V4(ref addr) => {
InetAddr::V4(libc::sockaddr_in {
sin_family: AddressFamily::Inet as sa_family_t,
sin_port: addr.port().to_be(),
sin_addr: Ipv4Addr::from_std(addr.ip()).0,
.. unsafe { mem::zeroed() }
})
}
net::SocketAddr::V6(ref addr) => {
InetAddr::V6(libc::sockaddr_in6 {
sin6_family: AddressFamily::Inet6 as sa_family_t,
sin6_port: addr.port().to_be(),
sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
sin6_flowinfo: addr.flowinfo(),
sin6_scope_id: addr.scope_id(),
.. unsafe { mem::zeroed() }
})
}
}
}
pub fn new(ip: IpAddr, port: u16) -> InetAddr {
match ip {
IpAddr::V4(ref ip) => {
InetAddr::V4(libc::sockaddr_in {
sin_family: AddressFamily::Inet as sa_family_t,
sin_port: port.to_be(),
sin_addr: ip.0,
.. unsafe { mem::zeroed() }
})
}
IpAddr::V6(ref ip) => {
InetAddr::V6(libc::sockaddr_in6 {
sin6_family: AddressFamily::Inet6 as sa_family_t,
sin6_port: port.to_be(),
sin6_addr: ip.0,
.. unsafe { mem::zeroed() }
})
}
}
}
pub fn ip(&self) -> IpAddr {
match *self {
InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
}
}
pub fn port(&self) -> u16 {
match *self {
InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
}
}
pub fn to_std(&self) -> net::SocketAddr {
match *self {
InetAddr::V4(ref sa) => net::SocketAddr::V4(
net::SocketAddrV4::new(
Ipv4Addr(sa.sin_addr).to_std(),
self.port())),
InetAddr::V6(ref sa) => net::SocketAddr::V6(
net::SocketAddrV6::new(
Ipv6Addr(sa.sin6_addr).to_std(),
self.port(),
sa.sin6_flowinfo,
sa.sin6_scope_id)),
}
}
pub fn to_str(&self) -> String {
format!("{}", self)
}
}
impl fmt::Display for InetAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
impl IpAddr {
pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
IpAddr::V4(Ipv4Addr::new(a, b, c, d))
}
#[allow(clippy::many_single_char_names)]
#[allow(clippy::too_many_arguments)]
pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
}
pub fn from_std(std: &net::IpAddr) -> IpAddr {
match *std {
net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
}
}
pub fn to_std(&self) -> net::IpAddr {
match *self {
IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
}
}
}
impl fmt::Display for IpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
IpAddr::V4(ref v4) => v4.fmt(f),
IpAddr::V6(ref v6) => v6.fmt(f)
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Ipv4Addr(pub libc::in_addr);
impl Ipv4Addr {
#[allow(clippy::identity_op)]
pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
let ip = ((u32::from(a) << 24) |
(u32::from(b) << 16) |
(u32::from(c) << 8) |
(u32::from(d) << 0)).to_be();
Ipv4Addr(libc::in_addr { s_addr: ip })
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
let bits = std.octets();
Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
}
pub fn any() -> Ipv4Addr {
Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
}
pub fn octets(self) -> [u8; 4] {
let bits = u32::from_be(self.0.s_addr);
[(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
}
pub fn to_std(self) -> net::Ipv4Addr {
let bits = self.octets();
net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
}
}
impl fmt::Display for Ipv4Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let octets = self.octets();
write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Ipv6Addr(pub libc::in6_addr);
macro_rules! to_u8_array {
($($num:ident),*) => {
[ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
}
}
macro_rules! to_u16_array {
($slf:ident, $($first:expr, $second:expr),*) => {
[$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
}
}
impl Ipv6Addr {
#[allow(clippy::many_single_char_names)]
#[allow(clippy::too_many_arguments)]
pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)})
}
pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
let s = std.segments();
Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
}
pub fn segments(&self) -> [u16; 8] {
to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
}
pub fn to_std(&self) -> net::Ipv6Addr {
let s = self.segments();
net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
}
}
impl fmt::Display for Ipv6Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.to_std().fmt(fmt)
}
}
#[derive(Clone, Copy, Debug)]
pub struct UnixAddr(pub libc::sockaddr_un, pub usize);
impl UnixAddr {
pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
path.with_nix_path(|cstr| {
unsafe {
let mut 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(Error::Sys(Errno::ENAMETOOLONG));
}
ptr::copy_nonoverlapping(bytes.as_ptr(),
ret.sun_path.as_mut_ptr() as *mut u8,
bytes.len());
Ok(UnixAddr(ret, bytes.len()))
}
})?
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
unsafe {
let mut ret = libc::sockaddr_un {
sun_family: AddressFamily::Unix as sa_family_t,
.. mem::zeroed()
};
if path.len() + 1 > ret.sun_path.len() {
return Err(Error::Sys(Errno::ENAMETOOLONG));
}
ptr::copy_nonoverlapping(path.as_ptr(),
ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
path.len());
Ok(UnixAddr(ret, path.len() + 1))
}
}
fn sun_path(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.0.sun_path.as_ptr() as *const u8, self.1) }
}
pub fn path(&self) -> Option<&Path> {
if self.1 == 0 || self.0.sun_path[0] == 0 {
None
} else {
let p = self.sun_path();
let ptr = &self.0.sun_path as *const libc::c_char;
let reallen = unsafe { libc::strnlen(ptr, p.len()) };
Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub fn as_abstract(&self) -> Option<&[u8]> {
if self.1 >= 1 && self.0.sun_path[0] == 0 {
Some(&self.sun_path()[1..])
} else {
None
}
}
}
impl fmt::Display for UnixAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.1 == 0 {
f.write_str("<unbound UNIX socket>")
} else if let Some(path) = self.path() {
path.display().fmt(f)
} else {
let display = String::from_utf8_lossy(&self.sun_path()[1..]);
write!(f, "@{}", display)
}
}
}
impl PartialEq for UnixAddr {
fn eq(&self, other: &UnixAddr) -> bool {
self.sun_path() == other.sun_path()
}
}
impl Eq for UnixAddr {}
impl Hash for UnixAddr {
fn hash<H: Hasher>(&self, s: &mut H) {
( self.0.sun_family, self.sun_path() ).hash(s)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SockAddr {
Inet(InetAddr),
Unix(UnixAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink(NetlinkAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
Alg(AlgAddr),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SysControl(SysControlAddr),
#[cfg(any(target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Link(LinkAddr),
#[cfg(target_os = "linux")]
Vsock(VsockAddr),
}
impl SockAddr {
pub fn new_inet(addr: InetAddr) -> SockAddr {
SockAddr::Inet(addr)
}
pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
Ok(SockAddr::Unix(UnixAddr::new(path)?))
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
SockAddr::Netlink(NetlinkAddr::new(pid, groups))
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
}
#[cfg(target_os = "linux")]
pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
SockAddr::Vsock(VsockAddr::new(cid, port))
}
pub fn family(&self) -> AddressFamily {
match *self {
SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
SockAddr::Unix(..) => AddressFamily::Unix,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(..) => AddressFamily::Netlink,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(..) => AddressFamily::Alg,
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(..) => AddressFamily::System,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Link(..) => AddressFamily::Packet,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
SockAddr::Link(..) => AddressFamily::Link,
#[cfg(target_os = "linux")]
SockAddr::Vsock(..) => AddressFamily::Vsock,
}
}
pub fn to_str(&self) -> String {
format!("{}", self)
}
pub(crate) unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
if addr.is_null() {
None
} else {
match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
Some(AddressFamily::Unix) => None,
Some(AddressFamily::Inet) => Some(SockAddr::Inet(
InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
InetAddr::V6(*(addr as *const libc::sockaddr_in6)))),
#[cfg(any(target_os = "android", target_os = "linux"))]
Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
NetlinkAddr(*(addr as *const libc::sockaddr_nl)))),
#[cfg(any(target_os = "ios", target_os = "macos"))]
Some(AddressFamily::System) => Some(SockAddr::SysControl(
SysControlAddr(*(addr as *const libc::sockaddr_ctl)))),
#[cfg(any(target_os = "android", target_os = "linux"))]
Some(AddressFamily::Packet) => Some(SockAddr::Link(
LinkAddr(*(addr as *const libc::sockaddr_ll)))),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Some(AddressFamily::Link) => {
let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl));
if ether_addr.is_empty() {
None
} else {
Some(SockAddr::Link(ether_addr))
}
},
#[cfg(target_os = "linux")]
Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(
VsockAddr(*(addr as *const libc::sockaddr_vm)))),
Some(_) | None => None,
}
}
}
pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
match *self {
SockAddr::Inet(InetAddr::V4(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_in as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t
),
SockAddr::Inet(InetAddr::V6(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_in6 as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t
),
SockAddr::Unix(UnixAddr(ref addr, len)) => (
unsafe {
&*(addr as *const libc::sockaddr_un as *const libc::sockaddr)
},
(len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t
),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(NetlinkAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_nl as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t
),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(AlgAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_alg as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t
),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(SysControlAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t
),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Link(LinkAddr(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_ll as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t
),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
SockAddr::Link(LinkAddr(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_dl as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t
),
#[cfg(target_os = "linux")]
SockAddr::Vsock(VsockAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_vm as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t
),
}
}
}
impl fmt::Display for SockAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SockAddr::Inet(ref inet) => inet.fmt(f),
SockAddr::Unix(ref unix) => unix.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(ref sc) => sc.fmt(f),
#[cfg(any(target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
#[cfg(target_os = "linux")]
SockAddr::Vsock(ref svm) => svm.fmt(f),
}
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod netlink {
use crate::sys::socket::addr::AddressFamily;
use libc::{sa_family_t, sockaddr_nl};
use std::{fmt, mem};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct NetlinkAddr(pub sockaddr_nl);
impl NetlinkAddr {
pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
let mut 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)
}
pub fn pid(&self) -> u32 {
self.0.nl_pid
}
pub fn groups(&self) -> u32 {
self.0.nl_groups
}
}
impl fmt::Display for NetlinkAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pid: {} groups: {}", self.pid(), self.groups())
}
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod alg {
use libc::{AF_ALG, sockaddr_alg, c_char};
use std::{fmt, mem, str};
use std::hash::{Hash, Hasher};
use std::ffi::CStr;
#[derive(Copy, Clone)]
pub struct AlgAddr(pub sockaddr_alg);
impl PartialEq for AlgAddr {
fn eq(&self, other: &Self) -> bool {
let (inner, other) = (self.0, other.0);
(inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]) ==
(other.salg_family, &other.salg_type[..], other.salg_feat, other.salg_mask, &other.salg_name[..])
}
}
impl Eq for AlgAddr {}
impl Hash for AlgAddr {
fn hash<H: Hasher>(&self, s: &mut H) {
let inner = self.0;
(inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]).hash(s);
}
}
impl AlgAddr {
pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr {
let mut addr: sockaddr_alg = unsafe { mem::zeroed() };
addr.salg_family = AF_ALG as u16;
addr.salg_type[..alg_type.len()].copy_from_slice(alg_type.to_string().as_bytes());
addr.salg_name[..alg_name.len()].copy_from_slice(alg_name.to_string().as_bytes());
AlgAddr(addr)
}
pub fn alg_type(&self) -> &CStr {
unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) }
}
pub fn alg_name(&self) -> &CStr {
unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) }
}
}
impl fmt::Display for AlgAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "type: {} alg: {}",
self.alg_name().to_string_lossy(),
self.alg_type().to_string_lossy())
}
}
impl fmt::Debug for AlgAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub mod sys_control {
use crate::sys::socket::addr::AddressFamily;
use libc::{self, c_uchar};
use std::{fmt, mem};
use std::os::unix::io::RawFd;
use crate::{Errno, Error, Result};
#[repr(C)]
#[derive(Clone, Copy)]
#[allow(missing_debug_implementations)]
pub struct ctl_ioc_info {
pub ctl_id: u32,
pub ctl_name: [c_uchar; MAX_KCTL_NAME],
}
const CTL_IOC_MAGIC: u8 = 'N' as u8;
const CTL_IOC_INFO: u8 = 3;
const MAX_KCTL_NAME: usize = 96;
ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SysControlAddr(pub libc::sockaddr_ctl);
impl SysControlAddr {
pub fn 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)
}
pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
if name.len() > MAX_KCTL_NAME {
return Err(Error::Sys(Errno::ENAMETOOLONG));
}
let mut ctl_name = [0; MAX_KCTL_NAME];
ctl_name[..name.len()].clone_from_slice(name.as_bytes());
let mut info = ctl_ioc_info { ctl_id: 0, ctl_name };
unsafe { ctl_info(sockfd, &mut info)?; }
Ok(SysControlAddr::new(info.ctl_id, unit))
}
pub fn id(&self) -> u32 {
self.0.sc_id
}
pub fn unit(&self) -> u32 {
self.0.sc_unit
}
}
impl fmt::Display for SysControlAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
mod datalink {
use super::{fmt, AddressFamily};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct LinkAddr(pub libc::sockaddr_ll);
impl LinkAddr {
pub fn family(&self) -> AddressFamily {
assert_eq!(self.0.sll_family as i32, libc::AF_PACKET);
AddressFamily::Packet
}
pub fn protocol(&self) -> u16 {
self.0.sll_protocol
}
pub fn ifindex(&self) -> usize {
self.0.sll_ifindex as usize
}
pub fn hatype(&self) -> u16 {
self.0.sll_hatype
}
pub fn pkttype(&self) -> u8 {
self.0.sll_pkttype
}
pub fn halen(&self) -> usize {
self.0.sll_halen as usize
}
pub fn addr(&self) -> [u8; 6] {
[
self.0.sll_addr[0] as u8,
self.0.sll_addr[1] as u8,
self.0.sll_addr[2] as u8,
self.0.sll_addr[3] as u8,
self.0.sll_addr[4] as u8,
self.0.sll_addr[5] as u8,
]
}
}
impl fmt::Display for LinkAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr = self.addr();
write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
addr[0],
addr[1],
addr[2],
addr[3],
addr[4],
addr[5])
}
}
}
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
mod datalink {
use super::{fmt, AddressFamily};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct LinkAddr(pub libc::sockaddr_dl);
impl LinkAddr {
pub fn len(&self) -> usize {
self.0.sdl_len as usize
}
pub fn family(&self) -> AddressFamily {
assert_eq!(i32::from(self.0.sdl_family), libc::AF_LINK);
AddressFamily::Link
}
pub fn ifindex(&self) -> usize {
self.0.sdl_index as usize
}
pub fn datalink_type(&self) -> u8 {
self.0.sdl_type
}
pub fn nlen(&self) -> usize {
self.0.sdl_nlen as usize
}
pub fn alen(&self) -> usize {
self.0.sdl_alen as usize
}
pub fn slen(&self) -> usize {
self.0.sdl_slen as usize
}
pub fn 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
}
pub fn addr(&self) -> [u8; 6] {
let nlen = self.nlen();
let data = self.0.sdl_data;
assert!(!self.is_empty());
[
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,
]
}
}
impl fmt::Display for LinkAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr = self.addr();
write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
addr[0],
addr[1],
addr[2],
addr[3],
addr[4],
addr[5])
}
}
}
#[cfg(target_os = "linux")]
pub mod vsock {
use crate::sys::socket::addr::AddressFamily;
use libc::{sa_family_t, sockaddr_vm};
use std::{fmt, mem};
use std::hash::{Hash, Hasher};
#[derive(Copy, Clone)]
pub struct VsockAddr(pub sockaddr_vm);
impl PartialEq for VsockAddr {
fn eq(&self, other: &Self) -> bool {
let (inner, other) = (self.0, other.0);
(inner.svm_family, inner.svm_cid, inner.svm_port) ==
(other.svm_family, other.svm_cid, other.svm_port)
}
}
impl Eq for VsockAddr {}
impl Hash for VsockAddr {
fn hash<H: Hasher>(&self, s: &mut H) {
let inner = self.0;
(inner.svm_family, inner.svm_cid, inner.svm_port).hash(s);
}
}
impl VsockAddr {
pub fn new(cid: u32, port: u32) -> VsockAddr {
let mut addr: sockaddr_vm = unsafe { mem::zeroed() };
addr.svm_family = AddressFamily::Vsock as sa_family_t;
addr.svm_cid = cid;
addr.svm_port = port;
VsockAddr(addr)
}
pub fn cid(&self) -> u32 {
self.0.svm_cid
}
pub fn port(&self) -> u32 {
self.0.svm_port
}
}
impl fmt::Display for VsockAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "cid: {} port: {}", self.cid(), self.port())
}
}
impl fmt::Debug for VsockAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
}
#[cfg(test)]
mod tests {
#[cfg(any(target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
use super::*;
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
#[test]
fn test_macos_loopback_datalink_addr() {
let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
let sa = bytes.as_ptr() as *const libc::sockaddr;
let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
assert!(_sock_addr.is_none());
}
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
#[test]
fn test_macos_tap_datalink_addr() {
let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80];
let ptr = bytes.as_ptr();
let sa = ptr as *const libc::sockaddr;
let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
assert!(_sock_addr.is_some());
let sock_addr = _sock_addr.unwrap();
assert_eq!(sock_addr.family(), AddressFamily::Link);
match sock_addr {
SockAddr::Link(ether_addr) => {
assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]);
},
_ => { unreachable!() }
};
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn test_abstract_sun_path() {
let name = String::from("nix\0abstract\0test");
let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
let sun_path1 = addr.sun_path();
let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116];
assert_eq!(sun_path1.len(), sun_path2.len());
for i in 0..sun_path1.len() {
assert_eq!(sun_path1[i], sun_path2[i]);
}
}
}