Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ rustc-std-workspace-alloc = { version = "1.0.0", optional = true } # not aliased
# libc backend can be selected via adding `--cfg=rustix_use_libc` to
# `RUSTFLAGS` or enabling the `use-libc` cargo feature.
[target.'cfg(all(not(rustix_use_libc), not(miri), target_os = "linux", any(target_endian = "little", any(target_arch = "s390x", target_arch = "powerpc")), any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc"), all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "s390x"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"))))'.dependencies]
linux-raw-sys = { version = "0.11.0", default-features = false, features = ["auxvec", "general", "errno", "ioctl", "no_std", "elf"] }
linux-raw-sys = { version = "0.12.1", default-features = false, features = ["auxvec", "general", "errno", "ioctl", "no_std", "elf"] }
libc_errno = { package = "errno", version = "0.3.10", default-features = false, optional = true }
libc = { version = "0.2.177", default-features = false, optional = true }

Expand All @@ -50,7 +50,7 @@ libc = { version = "0.2.177", default-features = false }
# Some syscalls do not have libc wrappers, such as in `io_uring`. For these,
# the libc backend uses the linux-raw-sys ABI and `libc::syscall`.
[target.'cfg(all(any(target_os = "linux", target_os = "android"), any(rustix_use_libc, miri, not(all(target_os = "linux", any(target_endian = "little", any(target_arch = "s390x", target_arch = "powerpc")), any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc"), all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "s390x"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64")))))))'.dependencies]
linux-raw-sys = { version = "0.11.0", default-features = false, features = ["general", "ioctl", "no_std"] }
linux-raw-sys = { version = "0.12.1", default-features = false, features = ["general", "ioctl", "no_std"] }

# For the libc backend on Windows, use the Winsock API in windows-sys.
[target.'cfg(windows)'.dependencies.windows-sys]
Expand Down Expand Up @@ -132,7 +132,7 @@ io_uring = ["event", "fs", "net", "thread", "linux-raw-sys/io_uring"]
mount = []

# Enable `rustix::net::*`.
net = ["linux-raw-sys/net", "linux-raw-sys/netlink", "linux-raw-sys/if_ether", "linux-raw-sys/xdp"]
net = ["linux-raw-sys/net", "linux-raw-sys/netlink", "linux-raw-sys/if_ether", "linux-raw-sys/vm_sockets", "linux-raw-sys/xdp"]

# Enable `rustix::thread::*`.
thread = ["linux-raw-sys/prctl"]
Expand Down
14 changes: 14 additions & 0 deletions src/backend/libc/net/read_sockaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::io::Errno;
use crate::net::addr::SocketAddrLen;
#[cfg(linux_kernel)]
use crate::net::netlink::SocketAddrNetlink;
#[cfg(any(linux_kernel, apple))]
use crate::net::vsock::SocketAddrVSock;
#[cfg(target_os = "linux")]
use crate::net::xdp::{SocketAddrXdp, SocketAddrXdpFlags};
use crate::net::{AddressFamily, Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrV4, SocketAddrV6};
Expand Down Expand Up @@ -262,3 +264,15 @@ pub(crate) fn read_sockaddr_netlink(addr: &SocketAddrAny) -> Result<SocketAddrNe
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_nl>() };
Ok(SocketAddrNetlink::new(decode.nl_pid, decode.nl_groups))
}

#[cfg(any(linux_kernel, apple))]
#[inline]
pub(crate) fn read_sockaddr_vsock(addr: &SocketAddrAny) -> Result<SocketAddrVSock, Errno> {
if addr.address_family() != AddressFamily::VSOCK {
return Err(Errno::AFNOSUPPORT);
}

assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_vm>());
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_vm>() };
Ok(SocketAddrVSock::new(decode.svm_cid, decode.svm_port))
}
1 change: 1 addition & 0 deletions src/backend/linux_raw/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub(crate) use linux_raw_sys::{
TCP_QUICKACK, TCP_THIN_LINEAR_TIMEOUTS, TCP_USER_TIMEOUT,
},
netlink::*,
vm_sockets::sockaddr_vm,
xdp::{
sockaddr_xdp, xdp_desc, xdp_mmap_offsets, xdp_mmap_offsets_v1, xdp_options,
xdp_ring_offset, xdp_ring_offset_v1, xdp_statistics, xdp_statistics_v1, xdp_umem_reg,
Expand Down
17 changes: 17 additions & 0 deletions src/backend/linux_raw/net/read_sockaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::backend::c;
use crate::io::Errno;
use crate::net::addr::SocketAddrLen;
use crate::net::netlink::SocketAddrNetlink;
use crate::net::vsock::SocketAddrVSock;
#[cfg(target_os = "linux")]
use crate::net::xdp::{SocketAddrXdp, SocketAddrXdpFlags};
use crate::net::{
Expand Down Expand Up @@ -153,3 +154,19 @@ pub(crate) fn read_sockaddr_netlink(addr: &SocketAddrAny) -> Result<SocketAddrNe
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_nl>() };
Ok(SocketAddrNetlink::new(decode.nl_pid, decode.nl_groups))
}

#[inline]
pub(crate) fn read_sockaddr_vsock(addr: &SocketAddrAny) -> Result<SocketAddrVSock, Errno> {
if addr.address_family() != AddressFamily::VSOCK {
return Err(Errno::AFNOSUPPORT);
}

assert!(
addr.addr_len() as usize * 8 >= size_of::<c::sockaddr_vm>(),
"addr len ({}) >= sockaddr_vm len ({})",
addr.addr_len() as usize * 8,
size_of::<c::sockaddr_vm>()
);
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_vm>() };
Ok(SocketAddrVSock::new(decode.svm_cid, decode.svm_port))
}
6 changes: 6 additions & 0 deletions src/net/socket_addr_any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ impl fmt::Debug for SocketAddrAny {
return addr.fmt(f);
}
}
#[cfg(any(linux_kernel, apple))]
AddressFamily::VSOCK => {
if let Ok(addr) = crate::net::vsock::SocketAddrVSock::try_from(self.clone()) {
return addr.fmt(f);
}
}
_ => {}
}

Expand Down
99 changes: 99 additions & 0 deletions src/net/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2081,6 +2081,105 @@ pub mod xdp {
pub const XSK_UNALIGNED_BUF_ADDR_MASK: u64 = c::XSK_UNALIGNED_BUF_ADDR_MASK;
}

/// `AF_VSOCK` and related types.
#[cfg(any(linux_kernel, apple))]
pub mod vsock {
use crate::backend::net::read_sockaddr::read_sockaddr_vsock;
use crate::net::addr::{call_with_sockaddr, SocketAddrArg, SocketAddrLen, SocketAddrOpaque};
use crate::net::SocketAddrAny;

use super::c;
use core::mem;

/// A VSock socket address.
///
/// Used to bind to a VSock socket. Not ABI compatible with `sockadr_vm`.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
pub struct SocketAddrVSock {
/// The Context IDentifier (CID) to connect to.
cid: u32,
/// The port to connect to.
port: u32,
}

impl SocketAddrVSock {
/// Construct a new VSock address.
#[inline]
pub const fn new(cid: u32, port: u32) -> Self {
Self { cid, port }
}

/// Context IDentifier (CID), referring to the VM to connect to.
#[inline]
pub fn cid(&self) -> u32 {
self.cid
}

/// Set the context identifier.
#[inline]
pub fn set_cid(&mut self, cid: u32) {
self.cid = cid;
}

/// Port to connect to.
#[inline]
pub fn port(&self) -> u32 {
self.port
}

/// Set the port to connect to.
#[inline]
pub fn set_port(&mut self, port: u32) {
self.port = port;
}
}

#[allow(unsafe_code)]
// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which
// handles calling `f` with the needed preconditions.
unsafe impl SocketAddrArg for SocketAddrVSock {
unsafe fn with_sockaddr<R>(
&self,
f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
) -> R {
let addr = c::sockaddr_vm {
svm_family: c::AF_VSOCK as _,
svm_cid: self.cid,
svm_port: self.port,
..mem::zeroed()
};

call_with_sockaddr(&addr, f)
}
}

impl From<SocketAddrVSock> for SocketAddrAny {
#[inline]
fn from(from: SocketAddrVSock) -> Self {
from.as_any()
}
}

impl TryFrom<SocketAddrAny> for SocketAddrVSock {
type Error = crate::io::Errno;

fn try_from(addr: SocketAddrAny) -> Result<Self, Self::Error> {
read_sockaddr_vsock(&addr)
}
}

/// CID to connect to any host.
pub const VMADDR_CID_ANY: u32 = 0xFFFFFFFF;
/// CID to connect to the hypervisor.
pub const VMADDR_CID_HYPERVISOR: u32 = 0;
/// CID to connect to the local host.
pub const VMADDR_CID_LOCAL: u32 = 1;
/// CID to connect to the host.
pub const VMADDR_CID_HOST: u32 = 2;
/// Connect to any port.
pub const VMADDR_PORT_ANY: u32 = 0xFFFFFFFF;
}

/// UNIX credentials of socket peer, for use with [`get_socket_peercred`]
/// [`SendAncillaryMessage::ScmCredentials`] and
/// [`RecvAncillaryMessage::ScmCredentials`].
Expand Down
1 change: 1 addition & 0 deletions tests/net/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod unix;
mod unix_alloc;
mod v4;
mod v6;
mod vsock;

#[cfg(windows)]
mod windows {
Expand Down
Loading