Skip to content

Commit 9026d5f

Browse files
committed
Merge sockaddr_storage_to_addr and SockAddr::from_raw_sockaddr
1 parent 460842a commit 9026d5f

File tree

4 files changed

+190
-219
lines changed

4 files changed

+190
-219
lines changed

src/ifaddrs.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ use std::iter::Iterator;
99
use std::mem;
1010
use std::option::Option;
1111

12-
use crate::{Result, Errno};
13-
use crate::sys::socket::SockAddr;
1412
use crate::net::if_::*;
13+
use crate::sys::socket::SockAddr;
14+
use crate::{Errno, Result};
1515

1616
/// Describes a single address for an interface as returned by `getifaddrs`.
1717
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
@@ -46,8 +46,31 @@ impl InterfaceAddress {
4646
/// Create an `InterfaceAddress` from the libc struct.
4747
fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
4848
let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
49-
let address = unsafe { SockAddr::from_raw_sockaddr(info.ifa_addr) };
50-
let netmask = unsafe { SockAddr::from_raw_sockaddr(info.ifa_netmask) };
49+
let get_sockaddr = |sa: *const libc::sockaddr| {
50+
if sa.is_null() {
51+
return None;
52+
}
53+
// TODO: there's gotta be a better way to do this but this is basically
54+
// what the man pages recommend
55+
let len = match unsafe { (*sa).sa_family } as _ {
56+
libc::AF_INET => mem::size_of::<libc::sockaddr_in>(),
57+
libc::AF_INET6 => mem::size_of::<libc::sockaddr_in6>(),
58+
#[cfg(any(
59+
target_os = "android",
60+
target_os = "linux",
61+
target_os = "illumos",
62+
target_os = "fuchsia",
63+
target_os = "solaris"
64+
))]
65+
libc::AF_PACKET => mem::size_of::<libc::sockaddr_in>(),
66+
#[cfg(any(target_os = "android", target_os = "linux"))]
67+
libc::AF_NETLINK => mem::size_of::<libc::sockaddr_nl>(),
68+
_ => return None,
69+
};
70+
unsafe { SockAddr::from_raw_sockaddr(sa, len) }.ok()
71+
};
72+
let address = get_sockaddr(info.ifa_addr);
73+
let netmask = get_sockaddr(info.ifa_netmask);
5174
let mut addr = InterfaceAddress {
5275
interface_name: ifname.to_string_lossy().to_string(),
5376
flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
@@ -59,9 +82,9 @@ impl InterfaceAddress {
5982

6083
let ifu = get_ifu_from_sockaddr(info);
6184
if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) {
62-
addr.destination = unsafe { SockAddr::from_raw_sockaddr(ifu) };
85+
addr.destination = get_sockaddr(ifu);
6386
} else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) {
64-
addr.broadcast = unsafe { SockAddr::from_raw_sockaddr(ifu) };
87+
addr.broadcast = get_sockaddr(ifu);
6588
}
6689

6790
addr
@@ -127,9 +150,10 @@ pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
127150
let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit();
128151
unsafe {
129152
Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| {
153+
let addrs = addrs.assume_init();
130154
InterfaceAddressIterator {
131-
base: addrs.assume_init(),
132-
next: addrs.assume_init(),
155+
base: addrs,
156+
next: addrs,
133157
}
134158
})
135159
}

src/sys/socket/addr.rs

Lines changed: 133 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,41 @@ pub use self::datalink::LinkAddr;
2929
#[cfg(any(target_os = "android", target_os = "linux"))]
3030
pub use self::vsock::VsockAddr;
3131

32-
/// These constants specify the protocol family to be used
33-
/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
34-
#[repr(i32)]
35-
#[non_exhaustive]
36-
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
37-
pub enum AddressFamily {
32+
macro_rules! address_family_enum {
33+
($($(#[doc = $doc:tt])* $(#[cfg($cfg:meta)])* $Variant:ident = $constant:path),* $(,)?) => {
34+
/// These constants specify the protocol family to be used
35+
/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
36+
#[repr(i32)]
37+
#[non_exhaustive]
38+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
39+
pub enum AddressFamily {
40+
$(
41+
$(#[doc = $doc])*
42+
$(#[cfg($cfg)])*
43+
$Variant = $constant,
44+
)*
45+
}
46+
47+
impl AddressFamily {
48+
/// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
49+
/// the `sa_family` field of a `sockaddr`.
50+
///
51+
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
52+
/// and System. Returns None for unsupported or unknown address families.
53+
pub const fn from_i32(family: i32) -> Option<AddressFamily> {
54+
match family {
55+
$(
56+
$(#[cfg($cfg)])*
57+
$constant => Some(AddressFamily::$Variant),
58+
)*
59+
_ => None
60+
}
61+
}
62+
}
63+
};
64+
}
65+
66+
address_family_enum! {
3867
/// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html))
3968
Unix = libc::AF_UNIX,
4069
/// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html))
@@ -231,38 +260,6 @@ pub enum AddressFamily {
231260
Unspec = libc::AF_UNSPEC,
232261
}
233262

234-
impl AddressFamily {
235-
/// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
236-
/// the `sa_family` field of a `sockaddr`.
237-
///
238-
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
239-
/// and System. Returns None for unsupported or unknown address families.
240-
pub const fn from_i32(family: i32) -> Option<AddressFamily> {
241-
match family {
242-
libc::AF_UNIX => Some(AddressFamily::Unix),
243-
libc::AF_INET => Some(AddressFamily::Inet),
244-
libc::AF_INET6 => Some(AddressFamily::Inet6),
245-
#[cfg(any(target_os = "android", target_os = "linux"))]
246-
libc::AF_NETLINK => Some(AddressFamily::Netlink),
247-
#[cfg(any(target_os = "macos", target_os = "macos"))]
248-
libc::AF_SYSTEM => Some(AddressFamily::System),
249-
#[cfg(any(target_os = "android", target_os = "linux"))]
250-
libc::AF_PACKET => Some(AddressFamily::Packet),
251-
#[cfg(any(target_os = "dragonfly",
252-
target_os = "freebsd",
253-
target_os = "ios",
254-
target_os = "macos",
255-
target_os = "netbsd",
256-
target_os = "illumos",
257-
target_os = "openbsd"))]
258-
libc::AF_LINK => Some(AddressFamily::Link),
259-
#[cfg(any(target_os = "android", target_os = "linux"))]
260-
libc::AF_VSOCK => Some(AddressFamily::Vsock),
261-
_ => None
262-
}
263-
}
264-
}
265-
266263
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
267264
pub enum InetAddr {
268265
V4(libc::sockaddr_in),
@@ -515,7 +512,7 @@ impl fmt::Display for Ipv6Addr {
515512
}
516513

517514
/// A wrapper around `sockaddr_un`.
518-
#[derive(Clone, Copy, Debug)]
515+
#[derive(Clone, Copy)]
519516
pub struct UnixAddr {
520517
// INVARIANT: sun & path_len are valid as defined by docs for from_raw_parts
521518
sun: libc::sockaddr_un,
@@ -660,6 +657,20 @@ impl UnixAddr {
660657
}
661658
}
662659

660+
impl fmt::Debug for UnixAddr {
661+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
662+
match self.kind() {
663+
UnixAddrKind::Pathname(path) => path.fmt(f),
664+
UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"),
665+
#[cfg(any(target_os = "android", target_os = "linux"))]
666+
UnixAddrKind::Abstract(name) => {
667+
write!(f, "@{:?}", String::from_utf8_lossy(name))
668+
}
669+
}
670+
}
671+
672+
}
673+
663674
impl fmt::Display for UnixAddr {
664675
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
665676
match self.kind() {
@@ -774,58 +785,86 @@ impl SockAddr {
774785
format!("{}", self)
775786
}
776787

777-
/// Creates a `SockAddr` struct from libc's sockaddr.
788+
/// Return the appropriate `SockAddr` type from a `sockaddr` of a certain size.
778789
///
779-
/// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
780-
/// Returns None for unsupported families.
790+
/// In C this would usually be done by casting. The `len` argument
791+
/// should be the number of bytes in the `sockaddr` that are actually
792+
/// allocated and valid. It must be at least as large as all the useful parts
793+
/// of the structure. Note that in the case of a `sockaddr_un`, `len` should
794+
/// include the terminating null.
781795
///
782796
/// # Safety
783-
///
784-
/// unsafe because it takes a raw pointer as argument. The caller must
785-
/// ensure that the pointer is valid.
786-
#[cfg(not(target_os = "fuchsia"))]
787-
pub unsafe fn from_raw_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
788-
if addr.is_null() {
789-
None
790-
} else {
791-
match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
792-
Some(AddressFamily::Unix) => None,
793-
Some(AddressFamily::Inet) => Some(SockAddr::Inet(
794-
InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
795-
Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
796-
InetAddr::V6(*(addr as *const libc::sockaddr_in6)))),
797-
#[cfg(any(target_os = "android", target_os = "linux"))]
798-
Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
799-
NetlinkAddr(*(addr as *const libc::sockaddr_nl)))),
800-
#[cfg(any(target_os = "ios", target_os = "macos"))]
801-
Some(AddressFamily::System) => Some(SockAddr::SysControl(
802-
SysControlAddr(*(addr as *const libc::sockaddr_ctl)))),
803-
#[cfg(any(target_os = "android", target_os = "linux"))]
804-
Some(AddressFamily::Packet) => Some(SockAddr::Link(
805-
LinkAddr(*(addr as *const libc::sockaddr_ll)))),
806-
#[cfg(any(target_os = "dragonfly",
807-
target_os = "freebsd",
808-
target_os = "ios",
809-
target_os = "macos",
810-
target_os = "netbsd",
811-
target_os = "illumos",
812-
target_os = "openbsd"))]
813-
Some(AddressFamily::Link) => {
814-
let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl));
815-
if ether_addr.is_empty() {
816-
None
817-
} else {
818-
Some(SockAddr::Link(ether_addr))
819-
}
820-
},
821-
#[cfg(any(target_os = "android", target_os = "linux"))]
822-
Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(
823-
VsockAddr(*(addr as *const libc::sockaddr_vm)))),
824-
// Other address families are currently not supported and simply yield a None
825-
// entry instead of a proper conversion to a `SockAddr`.
826-
Some(_) | None => None,
797+
/// `addr` must be a valid, non-null pointer, and `len` should describe the
798+
/// number of bytes within `*addr` that are initialized and represent data.
799+
pub unsafe fn from_raw_sockaddr(addr: *const libc::sockaddr, len: usize) -> Result<SockAddr> {
800+
let af = (*addr).sa_family;
801+
if len < mem::size_of_val(&af) {
802+
return Err(Error::from(Errno::ENOTCONN));
803+
}
804+
805+
let af = AddressFamily::from_i32(af.into()).ok_or(Errno::EAFNOSUPPORT)?;
806+
match af {
807+
AddressFamily::Inet => {
808+
use libc::sockaddr_in;
809+
assert!(len as usize >= mem::size_of::<sockaddr_in>());
810+
let sin = *(addr as *const sockaddr_in);
811+
Ok(SockAddr::Inet(InetAddr::V4(sin)))
812+
}
813+
AddressFamily::Inet6 => {
814+
use libc::sockaddr_in6;
815+
assert!(len as usize >= mem::size_of::<sockaddr_in6>());
816+
let sin6 = *(addr as *const sockaddr_in6);
817+
Ok(SockAddr::Inet(InetAddr::V6(sin6)))
827818
}
819+
AddressFamily::Unix => {
820+
use libc::sockaddr_un;
821+
let pathlen = len - offset_of!(sockaddr_un, sun_path);
822+
let sun = *(addr as *const sockaddr_un);
823+
Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, pathlen)))
824+
}
825+
#[cfg(any(target_os = "android", target_os = "linux"))]
826+
AddressFamily::Packet => {
827+
// Don't assert anything about the size.
828+
// Apparently the Linux kernel can return smaller sizes when
829+
// the value in the last element of sockaddr_ll (`sll_addr`) is
830+
// smaller than the declared size of that field
831+
let sll = *(addr as *const libc::sockaddr_ll);
832+
Ok(SockAddr::Link(LinkAddr(sll)))
833+
}
834+
#[cfg(any(target_os = "android", target_os = "linux"))]
835+
AddressFamily::Netlink => {
836+
let snl = *(addr as *const libc::sockaddr_nl);
837+
Ok(SockAddr::Netlink(NetlinkAddr(snl)))
838+
}
839+
#[cfg(any(target_os = "android", target_os = "linux"))]
840+
AddressFamily::Alg => {
841+
let salg = *(addr as *const libc::sockaddr_alg);
842+
Ok(SockAddr::Alg(AlgAddr(salg)))
843+
}
844+
#[cfg(any(target_os = "android", target_os = "linux"))]
845+
AddressFamily::Vsock => {
846+
let svm = *(addr as *const libc::sockaddr_vm);
847+
Ok(SockAddr::Vsock(VsockAddr(svm)))
848+
}
849+
#[cfg(any(target_os = "dragonfly",
850+
target_os = "freebsd",
851+
target_os = "ios",
852+
target_os = "macos",
853+
target_os = "netbsd",
854+
target_os = "illumos",
855+
target_os = "openbsd"))]
856+
AddressFamily::Link => {
857+
let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl));
858+
Ok(SockAddr::Link(ether_addr))
859+
}
860+
#[cfg(any(target_os = "ios", target_os = "macos"))]
861+
AddressFamily::System => {
862+
let sctl = SysControlAddr(*(addr as *const libc::sockaddr_ctl));
863+
Ok(SockAddr::SysControl(sctl))
864+
}
865+
_ => Err(Errno::EAFNOSUPPORT),
828866
}
867+
829868
}
830869

831870
/// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
@@ -1363,8 +1402,12 @@ mod tests {
13631402
fn test_macos_loopback_datalink_addr() {
13641403
let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
13651404
let sa = bytes.as_ptr() as *const libc::sockaddr;
1366-
let _sock_addr = unsafe { SockAddr::from_raw_sockaddr(sa) };
1367-
assert!(_sock_addr.is_none());
1405+
let sock_addr = unsafe { SockAddr::from_raw_sockaddr(sa, bytes.len()).unwrap() };
1406+
if let SockAddr::Link(link_addr) = sock_addr {
1407+
assert!(link_addr.is_empty())
1408+
} else {
1409+
panic!("bad family")
1410+
}
13681411
}
13691412

13701413
#[cfg(any(target_os = "dragonfly",
@@ -1378,11 +1421,7 @@ mod tests {
13781421
let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80];
13791422
let ptr = bytes.as_ptr();
13801423
let sa = ptr as *const libc::sockaddr;
1381-
let _sock_addr = unsafe { SockAddr::from_raw_sockaddr(sa) };
1382-
1383-
assert!(_sock_addr.is_some());
1384-
1385-
let sock_addr = _sock_addr.unwrap();
1424+
let sock_addr = unsafe { SockAddr::from_raw_sockaddr(sa, bytes.len()).unwrap() };
13861425

13871426
assert_eq!(sock_addr.family(), AddressFamily::Link);
13881427

@@ -1400,11 +1439,7 @@ mod tests {
14001439
let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176];
14011440
let ptr = bytes.as_ptr();
14021441
let sa = ptr as *const libc::sockaddr;
1403-
let _sock_addr = unsafe { SockAddr::from_raw_sockaddr(sa) };
1404-
1405-
assert!(_sock_addr.is_some());
1406-
1407-
let sock_addr = _sock_addr.unwrap();
1442+
let sock_addr = unsafe { SockAddr::from_raw_sockaddr(sa, bytes.len()).unwrap() };
14081443

14091444
assert_eq!(sock_addr.family(), AddressFamily::Link);
14101445

0 commit comments

Comments
 (0)