use super::sa_family_t; use {Error, Result, NixPath}; use errno::Errno; use libc; use std::{fmt, hash, mem, net, ptr, slice}; use std::ffi::OsStr; use std::path::Path; use std::os::unix::ffi::OsStrExt; #[cfg(any(target_os = "android", target_os = "linux"))] use ::sys::socket::addr::netlink::NetlinkAddr; #[cfg(any(target_os = "android", target_os = "linux"))] use ::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 ::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; /// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) #[repr(i32)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum AddressFamily { /// Local communication (see [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html)) Unix = libc::AF_UNIX, /// IPv4 Internet protocols (see [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html)) Inet = libc::AF_INET, /// IPv6 Internet protocols (see [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html)) Inet6 = libc::AF_INET6, /// Kernel user interface device (see [`netlink(7)`](http://man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] Netlink = libc::AF_NETLINK, /// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] Packet = libc::AF_PACKET, /// KEXT Controls and Notifications #[cfg(any(target_os = "ios", target_os = "macos"))] System = libc::AF_SYSTEM, /// Amateur radio AX.25 protocol #[cfg(any(target_os = "android", target_os = "linux"))] Ax25 = libc::AF_AX25, /// IPX - Novell protocols Ipx = libc::AF_IPX, /// AppleTalk 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, /// Access to raw ATM PVCs #[cfg(any(target_os = "android", target_os = "linux"))] AtmPvc = libc::AF_ATMPVC, /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](http://man7.org/linux/man-pages/man7/x25.7.html)) #[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, /// Interface to kernel crypto API #[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, /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) #[cfg(any(target_os = "android", target_os = "linux"))] 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. pub fn from_i32(family: i32) -> Option { 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), _ => None } } } #[derive(Copy)] 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(), // network byte order 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(), // network byte order sin6_addr: Ipv6Addr::from_std(addr.ip()).0, sin6_flowinfo: addr.flowinfo(), // host byte order sin6_scope_id: addr.scope_id(), // host byte order .. 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() } }) } } } /// Gets the IP address associated with this socket address. 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)), } } /// Gets the port number associated with this socket address 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 PartialEq for InetAddr { fn eq(&self, other: &InetAddr) -> bool { match (*self, *other) { (InetAddr::V4(ref a), InetAddr::V4(ref b)) => { a.sin_port == b.sin_port && a.sin_addr.s_addr == b.sin_addr.s_addr } (InetAddr::V6(ref a), InetAddr::V6(ref b)) => { a.sin6_port == b.sin6_port && a.sin6_addr.s6_addr == b.sin6_addr.s6_addr && a.sin6_flowinfo == b.sin6_flowinfo && a.sin6_scope_id == b.sin6_scope_id } _ => false, } } } impl Eq for InetAddr { } impl hash::Hash for InetAddr { fn hash(&self, s: &mut H) { match *self { InetAddr::V4(ref a) => { ( a.sin_family, a.sin_port, a.sin_addr.s_addr ).hash(s) } InetAddr::V6(ref a) => { ( a.sin6_family, a.sin6_port, &a.sin6_addr.s6_addr, a.sin6_flowinfo, a.sin6_scope_id ).hash(s) } } } } impl Clone for InetAddr { fn clone(&self) -> InetAddr { *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()), } } } impl fmt::Debug for InetAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } /* * * ===== IpAddr ===== * */ #[derive(Clone, Copy)] pub enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), } impl IpAddr { /// Create a new IpAddr that contains an IPv4 address. /// /// The result will represent the IP address a.b.c.d pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { IpAddr::V4(Ipv4Addr::new(a, b, c, d)) } /// Create a new IpAddr that contains an IPv6 address. /// /// The result will represent the IP address a:b:c:d:e:f 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) } } } impl fmt::Debug for IpAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } /* * * ===== Ipv4Addr ===== * */ #[derive(Copy)] pub struct Ipv4Addr(pub libc::in_addr); impl Ipv4Addr { pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { let ip = (((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | ((d as u32) << 0)).to_be(); Ipv4Addr(libc::in_addr { s_addr: ip }) } 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 PartialEq for Ipv4Addr { fn eq(&self, other: &Ipv4Addr) -> bool { self.0.s_addr == other.0.s_addr } } impl Eq for Ipv4Addr { } impl hash::Hash for Ipv4Addr { fn hash(&self, s: &mut H) { let saddr = self.0.s_addr; saddr.hash(s) } } impl Clone for Ipv4Addr { fn clone(&self) -> Ipv4Addr { *self } } 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]) } } impl fmt::Debug for Ipv4Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } /* * * ===== Ipv6Addr ===== * */ #[derive(Clone, Copy)] pub struct Ipv6Addr(pub libc::in6_addr); // Note that IPv6 addresses are stored in big endian order on all architectures. // See https://tools.ietf.org/html/rfc1700 or consult your favorite search // engine. 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 { pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()}; in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h); Ipv6Addr(in6_addr_var) } 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]) } /// Return the eight 16-bit segments that make up this address 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) } } impl fmt::Debug for Ipv6Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } /* * * ===== UnixAddr ===== * */ /// A wrapper around `sockaddr_un`. /// /// This also tracks the length of `sun_path` address (excluding /// a terminating null), because it may not be null-terminated. For example, /// unconnected and Linux abstract sockets are never null-terminated, and POSIX /// does not require that `sun_len` include the terminating null even for normal /// sockets. Note that the actual sockaddr length is greater by /// `offset_of!(libc::sockaddr_un, sun_path)` #[derive(Copy)] pub struct UnixAddr(pub libc::sockaddr_un, pub usize); impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. pub fn new(path: &P) -> Result { 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())) } })? } /// Create a new `sockaddr_un` representing an address in the "abstract namespace". /// /// The leading null byte for the abstract namespace is automatically added; /// thus the input `path` is expected to be the bare name, not null-prefixed. /// This is a Linux-specific extension, primarily used to allow chrooted /// processes to communicate with processes having a different filesystem view. #[cfg(any(target_os = "android", target_os = "linux"))] pub fn new_abstract(path: &[u8]) -> Result { 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)); } // 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) 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) } } /// If this address represents a filesystem path, return that path. pub fn path(&self) -> Option<&Path> { if self.1 == 0 || self.0.sun_path[0] == 0 { // unnamed or abstract None } else { let p = self.sun_path(); // POSIX only requires that `sun_len` be at least long enough to // contain the pathname, and it need not be null-terminated. So we // need to create a string that is the shorter of the // null-terminated length or the full length. let ptr = &self.0.sun_path as *const libc::c_char; let reallen = unsafe { libc::strnlen(ptr, p.len()) }; Some(Path::new(::from_bytes(&p[..reallen]))) } } /// If this address represents an abstract socket, return its name. /// /// For abstract sockets only the bare name is returned, without the /// leading null byte. `None` is returned for unnamed or path-backed sockets. #[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 { // unnamed or filesystem path None } } } impl PartialEq for UnixAddr { fn eq(&self, other: &UnixAddr) -> bool { self.sun_path() == other.sun_path() } } impl Eq for UnixAddr { } impl hash::Hash for UnixAddr { fn hash(&self, s: &mut H) { ( self.0.sun_family, self.sun_path() ).hash(s) } } impl Clone for UnixAddr { fn clone(&self) -> UnixAddr { *self } } impl fmt::Display for UnixAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.1 == 0 { f.write_str("") } 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 fmt::Debug for UnixAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } /* * * ===== Sock addr ===== * */ /// Represents a socket address #[derive(Copy, Debug)] 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), /// Datalink address (MAC) #[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) } impl SockAddr { pub fn new_inet(addr: InetAddr) -> SockAddr { SockAddr::Inet(addr) } pub fn new_unix(path: &P) -> Result { 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 { SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a)) } 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 } } pub fn to_str(&self) -> String { format!("{}", self) } /// Creates a `SockAddr` struct from libc's sockaddr. /// /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System. /// Returns None for unsupported families. pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option { if addr.is_null() { None } else { match AddressFamily::from_i32((*addr).sa_family as i32) { 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)) } }, // Other address families are currently not supported and simply yield a None // entry instead of a proper conversion to a `SockAddr`. Some(_) | None => None, } } } /// Conversion from nix's SockAddr type to the underlying libc sockaddr type. /// /// This is useful for interfacing with other libc functions that don't yet have nix wrappers. /// Returns a reference to the underlying data type (as a sockaddr reference) along /// with the size of the actual data type. sockaddr is commonly used as a proxy for /// a superclass as C doesn't support inheritance, so many functions that take /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back. pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) { match *self { SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::() as libc::socklen_t), SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::() as libc::socklen_t), SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (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)) => (mem::transmute(sa), mem::size_of::() as libc::socklen_t), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::() as libc::socklen_t), #[cfg(any(target_os = "ios", target_os = "macos"))] SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::() as libc::socklen_t), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::() 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 ether_addr)) => (mem::transmute(ether_addr), mem::size_of::() as libc::socklen_t), } } } impl PartialEq for SockAddr { fn eq(&self, other: &SockAddr) -> bool { match (*self, *other) { (SockAddr::Inet(ref a), SockAddr::Inet(ref b)) => { a == b } (SockAddr::Unix(ref a), SockAddr::Unix(ref b)) => { a == b } #[cfg(any(target_os = "android", target_os = "linux"))] (SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => { a == b } #[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 a), SockAddr::Link(ref b)) => { a == b } _ => false, } } } impl Eq for SockAddr { } impl hash::Hash for SockAddr { fn hash(&self, s: &mut H) { match *self { SockAddr::Inet(ref a) => a.hash(s), SockAddr::Unix(ref a) => a.hash(s), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Netlink(ref a) => a.hash(s), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Alg(ref a) => a.hash(s), #[cfg(any(target_os = "ios", target_os = "macos"))] SockAddr::SysControl(ref a) => a.hash(s), #[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.hash(s) } } } impl Clone for SockAddr { fn clone(&self) -> SockAddr { *self } } 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(any(target_os = "android", target_os = "linux"))] pub mod netlink { use ::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_nl}; use std::{fmt, mem}; use std::hash::{Hash, Hasher}; #[derive(Copy, Clone)] pub struct NetlinkAddr(pub sockaddr_nl); // , PartialEq, Eq, Debug, Hash impl PartialEq for NetlinkAddr { fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); (inner.nl_family, inner.nl_pid, inner.nl_groups) == (other.nl_family, other.nl_pid, other.nl_groups) } } impl Eq for NetlinkAddr {} impl Hash for NetlinkAddr { fn hash(&self, s: &mut H) { let inner = self.0; (inner.nl_family, inner.nl_pid, inner.nl_groups).hash(s); } } 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()) } } impl fmt::Debug for NetlinkAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } } #[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); // , PartialEq, Eq, Debug, Hash 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(&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 ::sys::socket::addr::AddressFamily; use libc::{self, c_uchar, uint16_t, uint32_t}; use std::{fmt, mem}; use std::hash::{Hash, Hasher}; use std::os::unix::io::RawFd; use {Errno, Error, Result}; #[repr(C)] pub struct ctl_ioc_info { pub ctl_id: uint32_t, 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); #[derive(Copy, Clone)] #[repr(C)] pub struct SysControlAddr(pub libc::sockaddr_ctl); impl PartialEq for SysControlAddr { fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); (inner.sc_id, inner.sc_unit) == (other.sc_id, other.sc_unit) } } impl Eq for SysControlAddr {} impl Hash for SysControlAddr { fn hash(&self, s: &mut H) { let inner = self.0; (inner.sc_id, inner.sc_unit).hash(s); } } impl SysControlAddr { pub fn new(id: u32, unit: u32) -> SysControlAddr { let addr = libc::sockaddr_ctl { sc_len: mem::size_of::() as c_uchar, sc_family: AddressFamily::System as c_uchar, ss_sysaddr: libc::AF_SYS_CONTROL as uint16_t, sc_id: id, sc_unit: unit, sc_reserved: [0; 5] }; SysControlAddr(addr) } pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result { 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: 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) } } impl fmt::Debug for SysControlAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SysControlAddr") .field("sc_len", &self.0.sc_len) .field("sc_family", &self.0.sc_family) .field("ss_sysaddr", &self.0.ss_sysaddr) .field("sc_id", &self.0.sc_id) .field("sc_unit", &self.0.sc_unit) .finish() } } } #[cfg(any(target_os = "android", target_os = "linux"))] mod datalink { use super::{libc, hash, fmt, AddressFamily}; /// Hardware Address #[derive(Clone, Copy)] pub struct LinkAddr(pub libc::sockaddr_ll); impl LinkAddr { /// Always AF_PACKET pub fn family(&self) -> AddressFamily { assert_eq!(self.0.sll_family as i32, libc::AF_PACKET); AddressFamily::Packet } /// Physical-layer protocol pub fn protocol(&self) -> u16 { self.0.sll_protocol } /// Interface number pub fn ifindex(&self) -> usize { self.0.sll_ifindex as usize } /// ARP hardware type pub fn hatype(&self) -> u16 { self.0.sll_hatype } /// Packet type pub fn pkttype(&self) -> u8 { self.0.sll_pkttype } /// Length of MAC address pub fn halen(&self) -> usize { self.0.sll_halen as usize } /// Physical-layer address (MAC) pub fn addr(&self) -> [u8; 6] { let a = self.0.sll_addr[0] as u8; let b = self.0.sll_addr[1] as u8; let c = self.0.sll_addr[2] as u8; let d = self.0.sll_addr[3] as u8; let e = self.0.sll_addr[4] as u8; let f = self.0.sll_addr[5] as u8; [a, b, c, d, e, f] } } impl Eq for LinkAddr {} impl PartialEq for LinkAddr { fn eq(&self, other: &Self) -> bool { let (a, b) = (self.0, other.0); (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype, a.sll_pkttype, a.sll_halen, a.sll_addr) == (b.sll_family, b.sll_protocol, b.sll_ifindex, b.sll_hatype, b.sll_pkttype, b.sll_halen, b.sll_addr) } } impl hash::Hash for LinkAddr { fn hash(&self, s: &mut H) { let a = self.0; (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype, a.sll_pkttype, a.sll_halen, a.sll_addr).hash(s); } } 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]) } } impl fmt::Debug for LinkAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } } #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] mod datalink { use super::{libc, hash, fmt, AddressFamily}; /// Hardware Address #[derive(Clone, Copy)] pub struct LinkAddr(pub libc::sockaddr_dl); impl LinkAddr { /// Total length of sockaddr pub fn len(&self) -> usize { self.0.sdl_len as usize } /// always == AF_LINK pub fn family(&self) -> AddressFamily { assert_eq!(self.0.sdl_family as i32, libc::AF_LINK); AddressFamily::Link } /// interface index, if != 0, system given index for interface pub fn ifindex(&self) -> usize { self.0.sdl_index as usize } /// Datalink type pub fn datalink_type(&self) -> u8 { self.0.sdl_type } // MAC address start position pub fn nlen(&self) -> usize { self.0.sdl_nlen as usize } /// link level address length pub fn alen(&self) -> usize { self.0.sdl_alen as usize } /// link layer selector length pub fn slen(&self) -> usize { self.0.sdl_slen as usize } /// if link level address length == 0, /// or `sdl_data` not be larger. pub fn is_empty(&self) -> bool { let nlen = self.nlen(); let alen = self.alen(); let data_len = self.0.sdl_data.len(); if alen > 0 && nlen + alen < data_len { false } else { true } } /// Physical-layer address (MAC) pub fn addr(&self) -> [u8; 6] { let nlen = self.nlen(); let data = self.0.sdl_data; assert!(!self.is_empty()); let a = data[nlen] as u8; let b = data[nlen + 1] as u8; let c = data[nlen + 2] as u8; let d = data[nlen + 3] as u8; let e = data[nlen + 4] as u8; let f = data[nlen + 5] as u8; [a, b, c, d, e, f] } } impl Eq for LinkAddr {} impl PartialEq for LinkAddr { #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] fn eq(&self, other: &Self) -> bool { let (a, b) = (self.0, other.0); (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]) == (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen, b.sdl_alen, b.sdl_slen, &b.sdl_data[..]) } #[cfg(target_os = "dragonfly")] fn eq(&self, other: &Self) -> bool { let (a, b) = (self.0, other.0); (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route) == (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen, b.sdl_alen, b.sdl_slen, b.sdl_data, b.sdl_rcf, b.sdl_route) } } impl hash::Hash for LinkAddr { #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] fn hash(&self, s: &mut H) { let a = self.0; (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]).hash(s); } #[cfg(target_os = "dragonfly")] fn hash(&self, s: &mut H) { let a = self.0; (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route).hash(s); } } 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]) } } impl fmt::Debug for LinkAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } } #[cfg(test)] mod tests { #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", 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!() } }; } }