Skip to content

Commit 06b35ea

Browse files
committed
Add AF_VSOCK based SocketAddr
This is necessary in order to connect to AF_VSOCK sockets, or listen on the AF_VSOCK socket type. Signed-off-by: John Nunley <dev@notgull.net>
1 parent 3f36950 commit 06b35ea

File tree

8 files changed

+423
-3
lines changed

8 files changed

+423
-3
lines changed

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ rustc-std-workspace-alloc = { version = "1.0.0", optional = true } # not aliased
3333
# libc backend can be selected via adding `--cfg=rustix_use_libc` to
3434
# `RUSTFLAGS` or enabling the `use-libc` cargo feature.
3535
[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]
36-
linux-raw-sys = { version = "0.11.0", default-features = false, features = ["auxvec", "general", "errno", "ioctl", "no_std", "elf"] }
36+
linux-raw-sys = { git = "https://github.com/forkgull/linux-raw-sys", branch = "notgull/vsock", default-features = false, features = ["auxvec", "general", "errno", "ioctl", "no_std", "elf"] }
3737
libc_errno = { package = "errno", version = "0.3.10", default-features = false, optional = true }
3838
libc = { version = "0.2.177", default-features = false, optional = true }
3939

@@ -50,7 +50,7 @@ libc = { version = "0.2.177", default-features = false }
5050
# Some syscalls do not have libc wrappers, such as in `io_uring`. For these,
5151
# the libc backend uses the linux-raw-sys ABI and `libc::syscall`.
5252
[target.'cfg(all(any(target_os = "linux"), 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]
53-
linux-raw-sys = { version = "0.11.0", default-features = false, features = ["general", "ioctl", "no_std"] }
53+
linux-raw-sys = { git = "https://github.com/forkgull/linux-raw-sys", branch = "notgull/vsock", default-features = false, features = ["general", "ioctl", "no_std"] }
5454

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

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

137137
# Enable `rustix::thread::*`.
138138
thread = ["linux-raw-sys/prctl"]

src/backend/libc/net/read_sockaddr.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use crate::io::Errno;
1111
use crate::net::addr::SocketAddrLen;
1212
#[cfg(linux_kernel)]
1313
use crate::net::netlink::SocketAddrNetlink;
14+
#[cfg(any(linux_kernel, apple))]
15+
use crate::net::vsock::SocketAddrVSock;
1416
#[cfg(target_os = "linux")]
1517
use crate::net::xdp::{SocketAddrXdp, SocketAddrXdpFlags};
1618
use crate::net::{AddressFamily, Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrV4, SocketAddrV6};
@@ -262,3 +264,15 @@ pub(crate) fn read_sockaddr_netlink(addr: &SocketAddrAny) -> Result<SocketAddrNe
262264
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_nl>() };
263265
Ok(SocketAddrNetlink::new(decode.nl_pid, decode.nl_groups))
264266
}
267+
268+
#[cfg(any(linux_kernel, apple))]
269+
#[inline]
270+
pub(crate) fn read_sockaddr_vsock(addr: &SocketAddrAny) -> Result<SocketAddrVSock, Errno> {
271+
if addr.address_family() != AddressFamily::VSOCK {
272+
return Err(Errno::AFNOSUPPORT);
273+
}
274+
275+
assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_vm>());
276+
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_vm>() };
277+
Ok(SocketAddrVSock::new(decode.svm_cid, decode.svm_port))
278+
}

src/backend/linux_raw/c.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ pub(crate) use linux_raw_sys::{
105105
TCP_QUICKACK, TCP_THIN_LINEAR_TIMEOUTS, TCP_USER_TIMEOUT,
106106
},
107107
netlink::*,
108+
vm_sockets::sockaddr_vm,
108109
xdp::{
109110
sockaddr_xdp, xdp_desc, xdp_mmap_offsets, xdp_mmap_offsets_v1, xdp_options,
110111
xdp_ring_offset, xdp_ring_offset_v1, xdp_statistics, xdp_statistics_v1, xdp_umem_reg,

src/backend/linux_raw/net/read_sockaddr.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::backend::c;
66
use crate::io::Errno;
77
use crate::net::addr::SocketAddrLen;
88
use crate::net::netlink::SocketAddrNetlink;
9+
use crate::net::vsock::SocketAddrVSock;
910
#[cfg(target_os = "linux")]
1011
use crate::net::xdp::{SocketAddrXdp, SocketAddrXdpFlags};
1112
use crate::net::{
@@ -153,3 +154,14 @@ pub(crate) fn read_sockaddr_netlink(addr: &SocketAddrAny) -> Result<SocketAddrNe
153154
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_nl>() };
154155
Ok(SocketAddrNetlink::new(decode.nl_pid, decode.nl_groups))
155156
}
157+
158+
#[inline]
159+
pub(crate) fn read_sockaddr_vsock(addr: &SocketAddrAny) -> Result<SocketAddrVSock, Errno> {
160+
if addr.address_family() != AddressFamily::VSOCK {
161+
return Err(Errno::AFNOSUPPORT);
162+
}
163+
164+
assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_vm>());
165+
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_vm>() };
166+
Ok(SocketAddrVSock::new(decode.svm_cid, decode.svm_port))
167+
}

src/net/socket_addr_any.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ impl fmt::Debug for SocketAddrAny {
225225
return addr.fmt(f);
226226
}
227227
}
228+
#[cfg(any(linux_kernel, apple))]
229+
AddressFamily::VSOCK => {
230+
if let Ok(addr) = crate::net::vsock::SocketAddrVSock::try_from(self.clone()) {
231+
return addr.fmt(f);
232+
}
233+
}
228234
_ => {}
229235
}
230236

src/net/types.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,6 +2081,105 @@ pub mod xdp {
20812081
pub const XSK_UNALIGNED_BUF_ADDR_MASK: u64 = c::XSK_UNALIGNED_BUF_ADDR_MASK;
20822082
}
20832083

2084+
/// `AF_VSOCK` and related types.
2085+
#[cfg(any(linux_kernel, apple))]
2086+
pub mod vsock {
2087+
use crate::backend::net::read_sockaddr::read_sockaddr_vsock;
2088+
use crate::net::addr::{call_with_sockaddr, SocketAddrArg, SocketAddrLen, SocketAddrOpaque};
2089+
use crate::net::SocketAddrAny;
2090+
2091+
use super::c;
2092+
use core::mem;
2093+
2094+
/// A VSock socket address.
2095+
///
2096+
/// Used to bind to a VSock socket. Not ABI compatible with `sockadr_vm`.
2097+
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
2098+
pub struct SocketAddrVSock {
2099+
/// The Context IDentifier (CID) to connect to.
2100+
cid: u32,
2101+
/// The port to connect to.
2102+
port: u32,
2103+
}
2104+
2105+
impl SocketAddrVSock {
2106+
/// Construct a new VSock address.
2107+
#[inline]
2108+
pub const fn new(cid: u32, port: u32) -> Self {
2109+
Self { cid, port }
2110+
}
2111+
2112+
/// Context IDentifier (CID), referring to the VM to connect to.
2113+
#[inline]
2114+
pub fn cid(&self) -> u32 {
2115+
self.cid
2116+
}
2117+
2118+
/// Set the context identifier.
2119+
#[inline]
2120+
pub fn set_cid(&mut self, cid: u32) {
2121+
self.cid = cid;
2122+
}
2123+
2124+
/// Port to connect to.
2125+
#[inline]
2126+
pub fn port(&self) -> u32 {
2127+
self.port
2128+
}
2129+
2130+
/// Set the port to connect to.
2131+
#[inline]
2132+
pub fn set_port(&mut self, port: u32) {
2133+
self.port = port;
2134+
}
2135+
}
2136+
2137+
#[allow(unsafe_code)]
2138+
// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which
2139+
// handles calling `f` with the needed preconditions.
2140+
unsafe impl SocketAddrArg for SocketAddrVSock {
2141+
unsafe fn with_sockaddr<R>(
2142+
&self,
2143+
f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
2144+
) -> R {
2145+
let addr = c::sockaddr_vm {
2146+
svm_family: c::AF_VSOCK as _,
2147+
svm_cid: self.cid,
2148+
svm_port: self.port,
2149+
..mem::zeroed()
2150+
};
2151+
2152+
call_with_sockaddr(&addr, f)
2153+
}
2154+
}
2155+
2156+
impl From<SocketAddrVSock> for SocketAddrAny {
2157+
#[inline]
2158+
fn from(from: SocketAddrVSock) -> Self {
2159+
from.as_any()
2160+
}
2161+
}
2162+
2163+
impl TryFrom<SocketAddrAny> for SocketAddrVSock {
2164+
type Error = crate::io::Errno;
2165+
2166+
fn try_from(addr: SocketAddrAny) -> Result<Self, Self::Error> {
2167+
read_sockaddr_vsock(&addr)
2168+
}
2169+
}
2170+
2171+
/// CID to connect to any host.
2172+
pub const VMADDR_CID_ANY: u32 = 0xFFFFFFFF;
2173+
/// CID to connect to the hypervisor.
2174+
pub const VMADDR_CID_HYPERVISOR: u32 = 0;
2175+
/// CID to connect to the local host.
2176+
pub const VMADDR_CID_LOCAL: u32 = 1;
2177+
/// CID to connect to the host.
2178+
pub const VMADDR_CID_HOST: u32 = 2;
2179+
/// Connect to any port.
2180+
pub const VMADDR_PORT_ANY: u32 = 0xFFFFFFFF;
2181+
}
2182+
20842183
/// UNIX credentials of socket peer, for use with [`get_socket_peercred`]
20852184
/// [`SendAncillaryMessage::ScmCredentials`] and
20862185
/// [`RecvAncillaryMessage::ScmCredentials`].

tests/net/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod unix;
2323
mod unix_alloc;
2424
mod v4;
2525
mod v6;
26+
mod vsock;
2627

2728
#[cfg(windows)]
2829
mod windows {

0 commit comments

Comments
 (0)