1use std::sync::Arc;
2
3use atomic_refcell::AtomicRefCell;
4use inet::{InetSocket, InetSocketRef, InetSocketRefMut};
5use linux_api::errno::Errno;
6use linux_api::ioctls::IoctlRequest;
7use linux_api::socket::Shutdown;
8use netlink::NetlinkSocket;
9use shadow_shim_helper_rs::syscall_types::ForeignPtr;
10use unix::UnixSocket;
11
12use crate::cshadow as c;
13use crate::host::descriptor::listener::{StateListenHandle, StateListenerFilter};
14use crate::host::descriptor::{
15 FileMode, FileSignals, FileState, FileStatus, OpenFile, SyscallResult,
16};
17use crate::host::memory_manager::MemoryManager;
18use crate::host::network::namespace::NetworkNamespace;
19use crate::host::syscall::io::IoVec;
20use crate::host::syscall::types::{ForeignArrayPtr, SyscallError};
21use crate::utility::HostTreePointer;
22use crate::utility::callback_queue::CallbackQueue;
23use crate::utility::sockaddr::SockaddrStorage;
24
25pub mod abstract_unix_ns;
26pub mod inet;
27pub mod netlink;
28pub mod unix;
29
30bitflags::bitflags! {
31 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
34 struct ShutdownFlags: u8 {
35 const READ = 0b00000001;
36 const WRITE = 0b00000010;
37 }
38}
39
40#[derive(Clone)]
41pub enum Socket {
42 Unix(Arc<AtomicRefCell<UnixSocket>>),
43 Inet(InetSocket),
44 Netlink(Arc<AtomicRefCell<NetlinkSocket>>),
45}
46
47impl Socket {
48 pub fn borrow(&self) -> SocketRef<'_> {
49 match self {
50 Self::Unix(f) => SocketRef::Unix(f.borrow()),
51 Self::Inet(f) => SocketRef::Inet(f.borrow()),
52 Self::Netlink(f) => SocketRef::Netlink(f.borrow()),
53 }
54 }
55
56 pub fn try_borrow(&self) -> Result<SocketRef<'_>, atomic_refcell::BorrowError> {
57 Ok(match self {
58 Self::Unix(f) => SocketRef::Unix(f.try_borrow()?),
59 Self::Inet(f) => SocketRef::Inet(f.try_borrow()?),
60 Self::Netlink(f) => SocketRef::Netlink(f.try_borrow()?),
61 })
62 }
63
64 pub fn borrow_mut(&self) -> SocketRefMut<'_> {
65 match self {
66 Self::Unix(f) => SocketRefMut::Unix(f.borrow_mut()),
67 Self::Inet(f) => SocketRefMut::Inet(f.borrow_mut()),
68 Self::Netlink(f) => SocketRefMut::Netlink(f.borrow_mut()),
69 }
70 }
71
72 pub fn try_borrow_mut(&self) -> Result<SocketRefMut<'_>, atomic_refcell::BorrowMutError> {
73 Ok(match self {
74 Self::Unix(f) => SocketRefMut::Unix(f.try_borrow_mut()?),
75 Self::Inet(f) => SocketRefMut::Inet(f.try_borrow_mut()?),
76 Self::Netlink(f) => SocketRefMut::Netlink(f.try_borrow_mut()?),
77 })
78 }
79
80 pub fn canonical_handle(&self) -> usize {
81 match self {
82 Self::Unix(f) => Arc::as_ptr(f) as usize,
83 Self::Inet(f) => f.canonical_handle(),
84 Self::Netlink(f) => Arc::as_ptr(f) as usize,
85 }
86 }
87
88 pub fn bind(
89 &self,
90 addr: Option<&SockaddrStorage>,
91 net_ns: &NetworkNamespace,
92 rng: impl rand::Rng,
93 ) -> Result<(), SyscallError> {
94 match self {
95 Self::Unix(socket) => UnixSocket::bind(socket, addr, net_ns, rng),
96 Self::Inet(socket) => InetSocket::bind(socket, addr, net_ns, rng),
97 Self::Netlink(socket) => NetlinkSocket::bind(socket, addr, net_ns, rng),
98 }
99 }
100
101 pub fn listen(
102 &self,
103 backlog: i32,
104 net_ns: &NetworkNamespace,
105 rng: impl rand::Rng,
106 cb_queue: &mut CallbackQueue,
107 ) -> Result<(), Errno> {
108 match self {
109 Self::Unix(socket) => UnixSocket::listen(socket, backlog, net_ns, rng, cb_queue),
110 Self::Inet(socket) => InetSocket::listen(socket, backlog, net_ns, rng, cb_queue),
111 Self::Netlink(socket) => NetlinkSocket::listen(socket, backlog, net_ns, rng, cb_queue),
112 }
113 }
114
115 pub fn connect(
116 &self,
117 addr: &SockaddrStorage,
118 net_ns: &NetworkNamespace,
119 rng: impl rand::Rng,
120 cb_queue: &mut CallbackQueue,
121 ) -> Result<(), SyscallError> {
122 match self {
123 Self::Unix(socket) => UnixSocket::connect(socket, addr, net_ns, rng, cb_queue),
124 Self::Inet(socket) => InetSocket::connect(socket, addr, net_ns, rng, cb_queue),
125 Self::Netlink(socket) => NetlinkSocket::connect(socket, addr, net_ns, rng, cb_queue),
126 }
127 }
128
129 pub fn sendmsg(
130 &self,
131 args: SendmsgArgs,
132 memory_manager: &mut MemoryManager,
133 net_ns: &NetworkNamespace,
134 rng: impl rand::Rng,
135 cb_queue: &mut CallbackQueue,
136 ) -> Result<libc::ssize_t, SyscallError> {
137 match self {
138 Self::Unix(socket) => {
139 UnixSocket::sendmsg(socket, args, memory_manager, net_ns, rng, cb_queue)
140 }
141 Self::Inet(socket) => {
142 InetSocket::sendmsg(socket, args, memory_manager, net_ns, rng, cb_queue)
143 }
144 Self::Netlink(socket) => {
145 NetlinkSocket::sendmsg(socket, args, memory_manager, net_ns, rng, cb_queue)
146 }
147 }
148 }
149
150 pub fn recvmsg(
151 &self,
152 args: RecvmsgArgs,
153 memory_manager: &mut MemoryManager,
154 cb_queue: &mut CallbackQueue,
155 ) -> Result<RecvmsgReturn, SyscallError> {
156 match self {
157 Self::Unix(socket) => UnixSocket::recvmsg(socket, args, memory_manager, cb_queue),
158 Self::Inet(socket) => InetSocket::recvmsg(socket, args, memory_manager, cb_queue),
159 Self::Netlink(socket) => NetlinkSocket::recvmsg(socket, args, memory_manager, cb_queue),
160 }
161 }
162}
163
164impl std::fmt::Debug for Socket {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 match self {
167 Self::Unix(_) => write!(f, "Unix")?,
168 Self::Inet(_) => write!(f, "Inet")?,
169 Self::Netlink(_) => write!(f, "Netlink")?,
170 }
171
172 if let Ok(file) = self.try_borrow() {
173 write!(
174 f,
175 "(state: {:?}, status: {:?})",
176 file.state(),
177 file.status()
178 )
179 } else {
180 write!(f, "(already borrowed)")
181 }
182 }
183}
184
185pub enum SocketRef<'a> {
186 Unix(atomic_refcell::AtomicRef<'a, UnixSocket>),
187 Inet(InetSocketRef<'a>),
188 Netlink(atomic_refcell::AtomicRef<'a, NetlinkSocket>),
189}
190
191pub enum SocketRefMut<'a> {
192 Unix(atomic_refcell::AtomicRefMut<'a, UnixSocket>),
193 Inet(InetSocketRefMut<'a>),
194 Netlink(atomic_refcell::AtomicRefMut<'a, NetlinkSocket>),
195}
196
197impl SocketRef<'_> {
199 enum_passthrough!(self, (), Unix, Inet, Netlink;
200 pub fn state(&self) -> FileState
201 );
202 enum_passthrough!(self, (), Unix, Inet, Netlink;
203 pub fn mode(&self) -> FileMode
204 );
205 enum_passthrough!(self, (), Unix, Inet, Netlink;
206 pub fn status(&self) -> FileStatus
207 );
208 enum_passthrough!(self, (), Unix, Inet, Netlink;
209 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
210 );
211 enum_passthrough!(self, (), Unix, Inet, Netlink;
212 pub fn has_open_file(&self) -> bool
213 );
214 enum_passthrough!(self, (), Unix, Inet, Netlink;
215 pub fn supports_sa_restart(&self) -> bool
216 );
217}
218
219impl SocketRef<'_> {
221 pub fn getpeername(&self) -> Result<Option<SockaddrStorage>, Errno> {
222 match self {
223 Self::Unix(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
224 Self::Inet(socket) => socket.getpeername(),
225 Self::Netlink(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
226 }
227 }
228
229 pub fn getsockname(&self) -> Result<Option<SockaddrStorage>, Errno> {
230 match self {
231 Self::Unix(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
232 Self::Inet(socket) => socket.getsockname(),
233 Self::Netlink(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
234 }
235 }
236
237 enum_passthrough!(self, (), Unix, Inet, Netlink;
238 pub fn address_family(&self) -> linux_api::socket::AddressFamily
239 );
240}
241
242impl SocketRefMut<'_> {
244 enum_passthrough!(self, (), Unix, Inet, Netlink;
245 pub fn state(&self) -> FileState
246 );
247 enum_passthrough!(self, (), Unix, Inet, Netlink;
248 pub fn mode(&self) -> FileMode
249 );
250 enum_passthrough!(self, (), Unix, Inet, Netlink;
251 pub fn status(&self) -> FileStatus
252 );
253 enum_passthrough!(self, (), Unix, Inet, Netlink;
254 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
255 );
256 enum_passthrough!(self, (off, whence), Unix, Inet, Netlink;
257 pub fn lseek(&mut self, off: linux_api::posix_types::kernel_off_t, whence: linux_api::unistd::LSeekWhence) -> Result<linux_api::posix_types::kernel_off_t, SyscallError>
258 );
259 enum_passthrough!(self, (), Unix, Inet, Netlink;
260 pub fn has_open_file(&self) -> bool
261 );
262 enum_passthrough!(self, (val), Unix, Inet, Netlink;
263 pub fn set_has_open_file(&mut self, val: bool)
264 );
265 enum_passthrough!(self, (), Unix, Inet, Netlink;
266 pub fn supports_sa_restart(&self) -> bool
267 );
268 enum_passthrough!(self, (cb_queue), Unix, Inet, Netlink;
269 pub fn close(&mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError>
270 );
271 enum_passthrough!(self, (status), Unix, Inet, Netlink;
272 pub fn set_status(&mut self, status: FileStatus)
273 );
274 enum_passthrough!(self, (request, arg_ptr, memory_manager), Unix, Inet, Netlink;
275 pub fn ioctl(&mut self, request: IoctlRequest, arg_ptr: ForeignPtr<()>, memory_manager: &mut MemoryManager) -> SyscallResult
276 );
277 enum_passthrough!(self, (monitoring_state, monitoring_signals, filter, notify_fn), Unix, Inet, Netlink;
278 pub fn add_listener(
279 &mut self,
280 monitoring_state: FileState,
281 monitoring_signals: FileSignals,
282 filter: StateListenerFilter,
283 notify_fn: impl Fn(FileState, FileState, FileSignals, &mut CallbackQueue) + Send + Sync + 'static,
284 ) -> StateListenHandle
285 );
286 enum_passthrough!(self, (ptr), Unix, Inet, Netlink;
287 pub fn add_legacy_listener(&mut self, ptr: HostTreePointer<c::StatusListener>)
288 );
289 enum_passthrough!(self, (ptr), Unix, Inet, Netlink;
290 pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener)
291 );
292 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), Unix, Inet, Netlink;
293 pub fn readv(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
294 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
295 );
296 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), Unix, Inet, Netlink;
297 pub fn writev(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
298 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
299 );
300}
301
302impl SocketRefMut<'_> {
304 pub fn getpeername(&self) -> Result<Option<SockaddrStorage>, Errno> {
305 match self {
306 Self::Unix(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
307 Self::Inet(socket) => socket.getpeername(),
308 Self::Netlink(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
309 }
310 }
311
312 pub fn getsockname(&self) -> Result<Option<SockaddrStorage>, Errno> {
313 match self {
314 Self::Unix(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
315 Self::Inet(socket) => socket.getsockname(),
316 Self::Netlink(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
317 }
318 }
319
320 enum_passthrough!(self, (), Unix, Inet, Netlink;
321 pub fn address_family(&self) -> linux_api::socket::AddressFamily
322 );
323
324 enum_passthrough!(self, (level, optname, optval_ptr, optlen, memory_manager, cb_queue), Unix, Inet, Netlink;
325 pub fn getsockopt(&mut self, level: libc::c_int, optname: libc::c_int, optval_ptr: ForeignPtr<()>,
326 optlen: libc::socklen_t, memory_manager: &mut MemoryManager, cb_queue: &mut CallbackQueue)
327 -> Result<libc::socklen_t, SyscallError>
328 );
329
330 enum_passthrough!(self, (level, optname, optval_ptr, optlen, memory_manager), Unix, Inet, Netlink;
331 pub fn setsockopt(&mut self, level: libc::c_int, optname: libc::c_int, optval_ptr: ForeignPtr<()>,
332 optlen: libc::socklen_t, memory_manager: &MemoryManager)
333 -> Result<(), SyscallError>
334 );
335
336 pub fn accept(
337 &mut self,
338 net_ns: &NetworkNamespace,
339 rng: impl rand::Rng,
340 cb_queue: &mut CallbackQueue,
341 ) -> Result<OpenFile, SyscallError> {
342 match self {
343 Self::Unix(socket) => socket.accept(net_ns, rng, cb_queue),
344 Self::Inet(socket) => socket.accept(net_ns, rng, cb_queue),
345 Self::Netlink(socket) => socket.accept(net_ns, rng, cb_queue),
346 }
347 }
348
349 enum_passthrough!(self, (how, cb_queue), Unix, Inet, Netlink;
350 pub fn shutdown(&mut self, how: Shutdown, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError>
351 );
352}
353
354impl std::fmt::Debug for SocketRef<'_> {
355 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
356 match self {
357 Self::Unix(_) => write!(f, "Unix")?,
358 Self::Inet(_) => write!(f, "Inet")?,
359 Self::Netlink(_) => write!(f, "Netlink")?,
360 }
361
362 write!(
363 f,
364 "(state: {:?}, status: {:?})",
365 self.state(),
366 self.status()
367 )
368 }
369}
370
371impl std::fmt::Debug for SocketRefMut<'_> {
372 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
373 match self {
374 Self::Unix(_) => write!(f, "Unix")?,
375 Self::Inet(_) => write!(f, "Inet")?,
376 Self::Netlink(_) => write!(f, "Netlink")?,
377 }
378
379 write!(
380 f,
381 "(state: {:?}, status: {:?})",
382 self.state(),
383 self.status()
384 )
385 }
386}
387
388pub struct SendmsgArgs<'a> {
390 pub addr: Option<SockaddrStorage>,
392 pub iovs: &'a [IoVec],
394 pub control_ptr: ForeignArrayPtr<u8>,
396 pub flags: libc::c_int,
398}
399
400pub struct RecvmsgArgs<'a> {
402 pub iovs: &'a [IoVec],
404 pub control_ptr: ForeignArrayPtr<u8>,
406 pub flags: libc::c_int,
408}
409
410pub struct RecvmsgReturn {
412 pub return_val: libc::ssize_t,
415 pub addr: Option<SockaddrStorage>,
417 pub msg_flags: libc::c_int,
419 pub control_len: libc::size_t,
421}