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
use libc::{in_addr, sockaddr_storage};
use crate::{cerr, control_message::empty_msghdr, raw_socket::sockaddr_len};
use super::{control_message, RawSocket};
impl RawSocket {
pub(crate) fn so_timestamp(&self, options: u32) -> std::io::Result<()> {
// Documentation on the timestamping calls:
//
// - linux: https://www.kernel.org/doc/Documentation/networking/timestamping.txt
// - freebsd: https://man.freebsd.org/cgi/man.cgi?setsockopt
//
// SAFETY:
//
// - the socket is provided by (safe) rust, and will outlive the call
// - method is guaranteed to be a valid "name" argument
// - the options pointer outlives the call
// - the `option_len` corresponds with the options pointer
//
// Only some bits are valid to set in `options`, but setting invalid bits is
// perfectly safe
//
// > Setting other bit returns EINVAL and does not change the current state.
unsafe {
cerr(libc::setsockopt(
self.fd,
libc::SOL_SOCKET,
libc::SO_TIMESTAMP,
&options as *const _ as *const libc::c_void,
std::mem::size_of_val(&options) as libc::socklen_t,
))
}?;
if options != 0 {
let clock = libc::SO_TS_REALTIME as u32;
// Safety:
//
// - The socket is proviided by (safe) rust, and will outlive the call
// - method is guaranteed to be a valid "name" argument
// - clock outlives the call
// - option_len corresponds with the size of clock
unsafe {
cerr(libc::setsockopt(
self.fd,
libc::SOL_SOCKET,
libc::SO_TS_CLOCK,
&clock as *const _ as *const libc::c_void,
std::mem::size_of_val(&clock) as libc::socklen_t,
))
}?;
}
Ok(())
}
pub(crate) fn enable_destination_ipv4(&self) -> std::io::Result<()> {
// SAFETY:
//
// - the socket is provided by (safe) rust, and will outlive the call
// - method is guaranteed to be a valid "name" argument
// - the options pointer outlives the call
// - the `option_len` corresponds with the options pointer
unsafe {
cerr(libc::setsockopt(
self.fd,
libc::IPPROTO_IP,
libc::IP_RECVDSTADDR,
&(1 as libc::c_int) as *const _ as *const libc::c_void,
std::mem::size_of::<libc::c_int>() as libc::socklen_t,
))?;
}
Ok(())
}
pub(crate) fn send_from_v4(&self, msg: &[u8], _addr: in_addr) -> std::io::Result<()> {
// FreeBSD and similar don't support setting an IPv4 source address
// on connected sockets.
self.send(msg)
}
pub(crate) fn send_from_to_v4(
&self,
msg: &[u8],
from: in_addr,
to: sockaddr_storage,
) -> std::io::Result<()> {
let to_len = sockaddr_len(to);
let control_message = control_message(libc::IPPROTO_IP, libc::IP_SENDSRCADDR, from);
let mut iov = libc::iovec {
iov_base: msg.as_ptr() as *mut libc::c_void,
iov_len: msg.len(),
};
let mut msghdr = empty_msghdr();
msghdr.msg_name = &raw const to as *mut _;
msghdr.msg_namelen = to_len;
msghdr.msg_iov = &raw mut iov;
msghdr.msg_iovlen = 1;
msghdr.msg_control = control_message.as_ptr() as *mut _;
msghdr.msg_controllen = control_message.len() as _;
// Safety:
// msghdr is valid.
cerr(unsafe { libc::sendmsg(self.fd, &raw const msghdr, 0) } as _).map(|_| {})
}
}