1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
use std::{
io::IoSliceMut,
os::fd::{AsRawFd, RawFd},
};
use libc::{c_void, sockaddr, sockaddr_storage};
use crate::{
cerr,
control_message::{
empty_msghdr, zeroed_sockaddr_storage, ControlMessage, ControlMessageIterator, MessageQueue,
},
};
#[cfg(target_os = "freebsd")]
mod freebsd;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "macos")]
mod macos;
// A struct providing safe wrappers around various socket api calls
#[derive(Debug, Hash)]
pub(crate) struct RawSocket {
fd: RawFd,
}
impl AsRawFd for RawSocket {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl RawSocket {
pub(crate) fn open(
domain: libc::c_int,
ty: libc::c_int,
protocol: libc::c_int,
) -> std::io::Result<Self> {
// Safety: libc::socket is always safe to call
Ok(RawSocket {
fd: cerr(unsafe { libc::socket(domain, ty, protocol) })?,
})
}
pub(crate) fn bind(&self, addr: sockaddr_storage) -> std::io::Result<()> {
// Per posix, it may be invalid to specify a length larger than that of the family.
let len = sockaddr_len(addr);
// Safety: socket is valid for the duration of the call, addr lives for the duration of
// the call and len is at most the length of addr.
cerr(unsafe { libc::bind(self.fd, &addr as *const _ as *const _, len) })?;
Ok(())
}
pub(crate) fn connect(&self, addr: sockaddr_storage) -> std::io::Result<()> {
// Per posix, it may be invalid to specify a length larger than that of the family.
let len = sockaddr_len(addr);
// Safety: socket is valid for the duration of the call, addr lives for the duration of
// the call and len is at most the length of addr.
cerr(unsafe { libc::connect(self.fd, &addr as *const _ as *const _, len) })?;
Ok(())
}
pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> std::io::Result<()> {
let nonblocking = nonblocking as libc::c_int;
// Safety: nonblocking lives for the duration of the call, and is 4 bytes long as expected for FIONBIO
cerr(unsafe { libc::ioctl(self.fd, libc::FIONBIO, &nonblocking) }).map(drop)
}
#[cfg(target_os = "linux")]
pub(crate) fn reuse_addr(&self) -> std::io::Result<()> {
let options = 1u32;
// Safety:
//
// the pointer argument is valid, the size is accurate
unsafe {
cerr(libc::setsockopt(
self.fd,
libc::SOL_SOCKET,
libc::SO_REUSEADDR,
&options as *const _ as *const libc::c_void,
std::mem::size_of_val(&options) as libc::socklen_t,
))?;
}
Ok(())
}
pub(crate) fn receive_message<'a>(
&self,
packet_buf: &mut [u8],
control_buf: &'a mut [u8],
queue: MessageQueue,
) -> std::io::Result<(
usize,
impl Iterator<Item = ControlMessage> + 'a,
sockaddr_storage,
)> {
let mut buf_slice = IoSliceMut::new(packet_buf);
let mut addr = zeroed_sockaddr_storage();
let mut mhdr = empty_msghdr();
mhdr.msg_control = control_buf.as_mut_ptr().cast::<libc::c_void>();
mhdr.msg_controllen = control_buf.len() as _;
mhdr.msg_iov = (&mut buf_slice as *mut IoSliceMut).cast::<libc::iovec>();
mhdr.msg_iovlen = 1;
mhdr.msg_flags = 0;
mhdr.msg_name = (&mut addr as *mut libc::sockaddr_storage).cast::<libc::c_void>();
mhdr.msg_namelen = std::mem::size_of::<libc::sockaddr_storage>() as u32;
let receive_flags = match queue {
MessageQueue::Normal => 0,
#[cfg(target_os = "linux")]
MessageQueue::Error => libc::MSG_ERRQUEUE,
};
// Safety:
// We have a mutable reference to the control buffer for the duration of the
// call, and controllen is also set to it's length.
// IoSliceMut is ABI compatible with iovec, and we only have 1 which matches
// iovlen msg_name is initialized to point to an owned sockaddr_storage and
// msg_namelen is the size of sockaddr_storage
// If one of the buffers is too small, recvmsg cuts off data at appropriate
// boundary
let received_bytes = loop {
match cerr(unsafe { libc::recvmsg(self.fd, &mut mhdr, receive_flags) } as _) {
Err(e) if std::io::ErrorKind::Interrupted == e.kind() => {
// retry when the recv was interrupted
continue;
}
Err(e) => return Err(e),
Ok(sent) => break sent as usize,
}
};
if mhdr.msg_flags & libc::MSG_TRUNC > 0 && !packet_buf.is_empty() {
tracing::debug!(
"truncated packet because it was larger than expected: {} bytes",
packet_buf.len(),
);
}
if mhdr.msg_flags & libc::MSG_CTRUNC > 0 {
tracing::debug!("truncated control messages");
}
// Clear out the fields for which we are giving up the reference
mhdr.msg_iov = std::ptr::null_mut();
mhdr.msg_iovlen = 0;
mhdr.msg_name = std::ptr::null_mut();
mhdr.msg_namelen = 0;
// Safety:
// recvmsg ensures that the control buffer contains
// a set of valid control messages and that controllen is
// the length these take up in the buffer.
Ok((
received_bytes,
unsafe { ControlMessageIterator::new(mhdr) },
addr,
))
}
pub(crate) fn send_to(&self, msg: &[u8], addr: sockaddr_storage) -> std::io::Result<()> {
// Per posix, it may be invalid to specify a length larger than that of the family.
let len = sockaddr_len(addr);
// Safety:
// the socket will outlive the call.
// msg points to a block of memory of length msg.len()
// addr points to a block of memory of length at least len
// with flags=0, the other arguments don't matter for safety
cerr(unsafe {
libc::sendto(
self.fd,
msg as *const _ as *const c_void,
msg.len(),
0,
&addr as *const _ as *const sockaddr,
len,
) as _
})?;
Ok(())
}
pub(crate) fn send(&self, msg: &[u8]) -> std::io::Result<()> {
// Safety:
// msg points to a block of memory of length msg.len()
// with flags=0, the other arguments don't matter for safety
cerr(unsafe { libc::send(self.fd, msg as *const _ as *const c_void, msg.len(), 0) as _ })?;
Ok(())
}
pub(crate) fn getsockname(&self) -> std::io::Result<sockaddr_storage> {
let mut addr = zeroed_sockaddr_storage();
let mut addr_len: libc::socklen_t = std::mem::size_of_val(&addr) as _;
// Safety:
// the socket will outlive the call.
// addr points to a block of memory of length addr_len
// addr_len will outlive the call.
cerr(unsafe {
libc::getsockname(
self.fd,
&mut addr as *mut _ as *mut _,
&mut addr_len as *mut _,
)
})?;
Ok(addr)
}
pub(crate) fn getpeername(&self) -> std::io::Result<sockaddr_storage> {
let mut addr = zeroed_sockaddr_storage();
let mut addr_len: libc::socklen_t = std::mem::size_of_val(&addr) as _;
// Safety:
// the socket will outlive the call.
// addr points to a block of memory of length addr_len
// addr_len will outlive the call.
cerr(unsafe {
libc::getpeername(
self.fd,
&mut addr as *mut _ as *mut _,
&mut addr_len as *mut _,
)
})?;
Ok(addr)
}
}
fn sockaddr_len(addr: sockaddr_storage) -> u32 {
let len: libc::socklen_t = std::mem::size_of_val(&addr) as _;
len.min(match addr.ss_family as _ {
libc::AF_INET => std::mem::size_of::<libc::sockaddr_in>() as _,
libc::AF_INET6 => std::mem::size_of::<libc::sockaddr_in6>() as _,
_ => len,
})
}
impl Drop for RawSocket {
fn drop(&mut self) {
// Safety: close is always safe to call on a file descriptor
unsafe { libc::close(self.fd) };
}
}