1 //! Socket options as used by `setsockopt` and `getsockopt`.
2 use cfg_if::cfg_if;
3 use super::{GetSockOpt, SetSockOpt};
4 use crate::Result;
5 use crate::errno::Errno;
6 use crate::sys::time::TimeVal;
7 use libc::{self, c_int, c_void, socklen_t};
8 use std::mem::{
9     self,
10     MaybeUninit
11 };
12 use std::os::unix::io::RawFd;
13 use std::ffi::{OsStr, OsString};
14 #[cfg(target_family = "unix")]
15 use std::os::unix::ffi::OsStrExt;
16 
17 // Constants
18 // TCP_CA_NAME_MAX isn't defined in user space include files
19 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
20 const TCP_CA_NAME_MAX: usize = 16;
21 
22 /// Helper for implementing `SetSockOpt` for a given socket option. See
23 /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
24 ///
25 /// This macro aims to help implementing `SetSockOpt` for different socket options that accept
26 /// different kinds of data to be used with `setsockopt`.
27 ///
28 /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
29 /// you are implementing represents a simple type.
30 ///
31 /// # Arguments
32 ///
33 /// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
34 /// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
35 ///    (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
36 ///    and more. Please refer to your system manual for more options. Will be passed as the second
37 ///    argument (`level`) to the `setsockopt` call.
38 /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
39 ///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
40 ///    to the `setsockopt` call.
41 /// * Type of the value that you are going to set.
42 /// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
43 ///    `bool`, `SetUsize` for `usize`, etc.).
44 macro_rules! setsockopt_impl {
45     ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
46         impl SetSockOpt for $name {
47             type Val = $ty;
48 
49             fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
50                 unsafe {
51                     let setter: $setter = Set::new(val);
52 
53                     let res = libc::setsockopt(fd, $level, $flag,
54                                                setter.ffi_ptr(),
55                                                setter.ffi_len());
56                     Errno::result(res).map(drop)
57                 }
58             }
59         }
60     }
61 }
62 
63 /// Helper for implementing `GetSockOpt` for a given socket option. See
64 /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
65 ///
66 /// This macro aims to help implementing `GetSockOpt` for different socket options that accept
67 /// different kinds of data to be use with `getsockopt`.
68 ///
69 /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
70 /// you are implementing represents a simple type.
71 ///
72 /// # Arguments
73 ///
74 /// * Name of the type you want to implement `GetSockOpt` for.
75 /// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`),  *ip
76 ///    protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),  and more. Please refer
77 ///    to your system manual for more options. Will be passed as the second argument (`level`) to
78 ///    the `getsockopt` call.
79 /// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
80 ///    `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
81 ///    the `getsockopt` call.
82 /// * Type of the value that you are going to get.
83 /// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
84 ///    `bool`, `GetUsize` for `usize`, etc.).
85 macro_rules! getsockopt_impl {
86     ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
87         impl GetSockOpt for $name {
88             type Val = $ty;
89 
90             fn get(&self, fd: RawFd) -> Result<$ty> {
91                 unsafe {
92                     let mut getter: $getter = Get::uninit();
93 
94                     let res = libc::getsockopt(fd, $level, $flag,
95                                                getter.ffi_ptr(),
96                                                getter.ffi_len());
97                     Errno::result(res)?;
98 
99                     Ok(getter.assume_init())
100                 }
101             }
102         }
103     }
104 }
105 
106 /// Helper to generate the sockopt accessors. See
107 /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
108 /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
109 ///
110 /// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
111 /// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
112 ///
113 /// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
114 /// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
115 ///
116 /// # Arguments
117 ///
118 /// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
119 ///    both of them.
120 /// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
121 /// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
122 ///    (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
123 ///    and more. Please refer to your system manual for more options. Will be passed as the second
124 ///    argument (`level`) to the `getsockopt`/`setsockopt` call.
125 /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
126 ///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
127 ///    to the `setsockopt`/`getsockopt` call.
128 /// * `$ty:ty`: type of the value that will be get/set.
129 /// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
130 /// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
131 macro_rules! sockopt_impl {
132     ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
133         sockopt_impl!($(#[$attr])*
134                       $name, GetOnly, $level, $flag, bool, GetBool);
135     };
136 
137     ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
138         sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8);
139     };
140 
141     ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
142     {
143         sockopt_impl!($(#[$attr])*
144                       $name, GetOnly, $level, $flag, usize, GetUsize);
145     };
146 
147     ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
148         sockopt_impl!($(#[$attr])*
149                       $name, SetOnly, $level, $flag, bool, SetBool);
150     };
151 
152     ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
153         sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8);
154     };
155 
156     ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
157     {
158         sockopt_impl!($(#[$attr])*
159                       $name, SetOnly, $level, $flag, usize, SetUsize);
160     };
161 
162     ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
163         sockopt_impl!($(#[$attr])*
164                       $name, Both, $level, $flag, bool, GetBool, SetBool);
165     };
166 
167     ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
168         sockopt_impl!($(#[$attr])*
169                       $name, Both, $level, $flag, u8, GetU8, SetU8);
170     };
171 
172     ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
173         sockopt_impl!($(#[$attr])*
174                       $name, Both, $level, $flag, usize, GetUsize, SetUsize);
175     };
176 
177     ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
178      OsString<$array:ty>) =>
179     {
180         sockopt_impl!($(#[$attr])*
181                       $name, Both, $level, $flag, OsString, GetOsString<$array>,
182                       SetOsString);
183     };
184 
185     /*
186      * Matchers with generic getter types must be placed at the end, so
187      * they'll only match _after_ specialized matchers fail
188      */
189     ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
190     {
191         sockopt_impl!($(#[$attr])*
192                       $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
193     };
194 
195     ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
196      $getter:ty) =>
197     {
198         $(#[$attr])*
199         #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
200         pub struct $name;
201 
202         getsockopt_impl!($name, $level, $flag, $ty, $getter);
203     };
204 
205     ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
206     {
207         sockopt_impl!($(#[$attr])*
208                       $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
209     };
210 
211     ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
212      $setter:ty) =>
213     {
214         $(#[$attr])*
215         #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
216         pub struct $name;
217 
218         setsockopt_impl!($name, $level, $flag, $ty, $setter);
219     };
220 
221     ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty,
222      $getter:ty, $setter:ty) =>
223     {
224         $(#[$attr])*
225         #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
226         pub struct $name;
227 
228         setsockopt_impl!($name, $level, $flag, $ty, $setter);
229         getsockopt_impl!($name, $level, $flag, $ty, $getter);
230     };
231 
232     ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
233         sockopt_impl!($(#[$attr])*
234                       $name, Both, $level, $flag, $ty, GetStruct<$ty>,
235                       SetStruct<$ty>);
236     };
237 }
238 
239 /*
240  *
241  * ===== Define sockopts =====
242  *
243  */
244 
245 sockopt_impl!(
246     /// Enables local address reuse
247     ReuseAddr, Both, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool
248 );
249 #[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
250 sockopt_impl!(
251     /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an
252     /// identical socket address.
253     ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
254 sockopt_impl!(
255     /// Under most circumstances, TCP sends data when it is presented; when
256     /// outstanding data has not yet been acknowledged, it gathers small amounts
257     /// of output to be sent in a single packet once an acknowledgement is
258     /// received.  For a small number of clients, such as window systems that
259     /// send a stream of mouse events which receive no replies, this
260     /// packetization may cause significant delays.  The boolean option
261     /// TCP_NODELAY defeats this algorithm.
262     TcpNoDelay, Both, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
263 sockopt_impl!(
264     /// When enabled,  a close(2) or shutdown(2) will not return until all
265     /// queued messages for the socket have been successfully sent or the
266     /// linger timeout has been reached.
267     Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
268 sockopt_impl!(
269     /// Join a multicast group
270     IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP,
271     super::IpMembershipRequest);
272 sockopt_impl!(
273     /// Leave a multicast group.
274     IpDropMembership, SetOnly, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP,
275     super::IpMembershipRequest);
276 cfg_if! {
277     if #[cfg(any(target_os = "android", target_os = "linux"))] {
278         sockopt_impl!(
279             /// Join an IPv6 multicast group.
280             Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
281         sockopt_impl!(
282             /// Leave an IPv6 multicast group.
283             Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
284     } else if #[cfg(any(target_os = "dragonfly",
285                         target_os = "freebsd",
286                         target_os = "illumos",
287                         target_os = "ios",
288                         target_os = "macos",
289                         target_os = "netbsd",
290                         target_os = "openbsd",
291                         target_os = "solaris"))] {
292         sockopt_impl!(
293             /// Join an IPv6 multicast group.
294             Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6,
295             libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
296         sockopt_impl!(
297             /// Leave an IPv6 multicast group.
298             Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6,
299             libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
300     }
301 }
302 sockopt_impl!(
303     /// Set or read the time-to-live value of outgoing multicast packets for
304     /// this socket.
305     IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
306 sockopt_impl!(
307     /// Set or read a boolean integer argument that determines whether sent
308     /// multicast packets should be looped back to the local sockets.
309     IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
310 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
311 sockopt_impl!(
312     /// If enabled, this boolean option allows binding to an IP address that
313     /// is nonlocal or does not (yet) exist.
314     IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool);
315 sockopt_impl!(
316     /// Specify the receiving timeout until reporting an error.
317     ReceiveTimeout, Both, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
318 sockopt_impl!(
319     /// Specify the sending timeout until reporting an error.
320     SendTimeout, Both, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
321 sockopt_impl!(
322     /// Set or get the broadcast flag.
323     Broadcast, Both, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
324 sockopt_impl!(
325     /// If this option is enabled, out-of-band data is directly placed into
326     /// the receive data stream.
327     OobInline, Both, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
328 sockopt_impl!(
329     /// Get and clear the pending socket error.
330     SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32);
331 sockopt_impl!(
332     /// Enable sending of keep-alive messages on connection-oriented sockets.
333     KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
334 #[cfg(any(
335         target_os = "dragonfly",
336         target_os = "freebsd",
337         target_os = "macos",
338         target_os = "ios"
339 ))]
340 sockopt_impl!(
341     /// Get the credentials of the peer process of a connected unix domain
342     /// socket.
343     LocalPeerCred, GetOnly, 0, libc::LOCAL_PEERCRED, super::XuCred);
344 #[cfg(any(target_os = "android", target_os = "linux"))]
345 sockopt_impl!(
346     /// Return the credentials of the foreign process connected to this socket.
347     PeerCredentials, GetOnly, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
348 #[cfg(any(target_os = "ios",
349           target_os = "macos"))]
350 sockopt_impl!(
351     /// Specify the amount of time, in seconds, that the connection must be idle
352     /// before keepalive probes (if enabled) are sent.
353     TcpKeepAlive, Both, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
354 #[cfg(any(target_os = "android",
355           target_os = "dragonfly",
356           target_os = "freebsd",
357           target_os = "linux",
358           target_os = "nacl"))]
359 sockopt_impl!(
360     /// The time (in seconds) the connection needs to remain idle before TCP
361     /// starts sending keepalive probes
362     TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
363 cfg_if! {
364     if #[cfg(any(target_os = "android", target_os = "linux"))] {
365         sockopt_impl!(
366             /// The maximum segment size for outgoing TCP packets.
367             TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
368     } else {
369         sockopt_impl!(
370             /// The maximum segment size for outgoing TCP packets.
371             TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
372     }
373 }
374 #[cfg(not(target_os = "openbsd"))]
375 sockopt_impl!(
376     /// The maximum number of keepalive probes TCP should send before
377     /// dropping the connection.
378     TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
379 #[cfg(any(target_os = "android",
380           target_os = "fuchsia",
381           target_os = "linux"))]
382 sockopt_impl!(
383     #[allow(missing_docs)]
384     // Not documented by Linux!
385     TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32);
386 #[cfg(not(target_os = "openbsd"))]
387 sockopt_impl!(
388     /// The time (in seconds) between individual keepalive probes.
389     TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
390 #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
391 sockopt_impl!(
392     /// Specifies the maximum amount of time in milliseconds that transmitted
393     /// data may remain unacknowledged before TCP will forcibly close the
394     /// corresponding connection
395     TcpUserTimeout, Both, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32);
396 sockopt_impl!(
397     /// Sets or gets the maximum socket receive buffer in bytes.
398     RcvBuf, Both, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
399 sockopt_impl!(
400     /// Sets or gets the maximum socket send buffer in bytes.
401     SndBuf, Both, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
402 #[cfg(any(target_os = "android", target_os = "linux"))]
403 sockopt_impl!(
404     /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can
405     /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be
406     /// overridden.
407     RcvBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
408 #[cfg(any(target_os = "android", target_os = "linux"))]
409 sockopt_impl!(
410     /// Using this socket option, a privileged (`CAP_NET_ADMIN`)  process can
411     /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be
412     /// overridden.
413     SndBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
414 sockopt_impl!(
415     /// Gets the socket type as an integer.
416     SockType, GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
417 sockopt_impl!(
418     /// Returns a value indicating whether or not this socket has been marked to
419     /// accept connections with `listen(2)`.
420     AcceptConn, GetOnly, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
421 #[cfg(any(target_os = "android", target_os = "linux"))]
422 sockopt_impl!(
423     /// Bind this socket to a particular device like “eth0”.
424     BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>);
425 #[cfg(any(target_os = "android", target_os = "linux"))]
426 sockopt_impl!(
427     #[allow(missing_docs)]
428     // Not documented by Linux!
429     OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
430 #[cfg(any(target_os = "android", target_os = "linux"))]
431 sockopt_impl!(
432     #[allow(missing_docs)]
433     // Not documented by Linux!
434     Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6);
435 sockopt_impl!(
436     /// Enable or disable the receiving of the `SO_TIMESTAMP` control message.
437     ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
438 #[cfg(all(target_os = "linux"))]
439 sockopt_impl!(
440     /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message.
441     ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool);
442 #[cfg(any(target_os = "android", target_os = "linux"))]
443 sockopt_impl!(
444     /// Setting this boolean option enables transparent proxying on this socket.
445     IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
446 #[cfg(target_os = "openbsd")]
447 sockopt_impl!(
448     /// Allows the socket to be bound to addresses which are not local to the
449     /// machine, so it can be used to make a transparent proxy.
450     BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
451 #[cfg(target_os = "freebsd")]
452 sockopt_impl!(
453     /// Can `bind(2)` to any address, even one not bound to any available
454     /// network interface in the system.
455     BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
456 #[cfg(target_os = "linux")]
457 sockopt_impl!(
458     /// Set the mark for each packet sent through this socket (similar to the
459     /// netfilter MARK target but socket-based).
460     Mark, Both, libc::SOL_SOCKET, libc::SO_MARK, u32);
461 #[cfg(any(target_os = "android", target_os = "linux"))]
462 sockopt_impl!(
463     /// Enable or disable the receiving of the `SCM_CREDENTIALS` control
464     /// message.
465     PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
466 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
467 sockopt_impl!(
468     /// This option allows the caller to set the TCP congestion control
469     /// algorithm to be used,  on a per-socket basis.
470     TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
471 #[cfg(any(
472     target_os = "android",
473     target_os = "ios",
474     target_os = "linux",
475     target_os = "macos",
476     target_os = "netbsd",
477 ))]
478 sockopt_impl!(
479     /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo
480     /// structure that supplies some information about the incoming packet.
481     Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
482 #[cfg(any(
483     target_os = "android",
484     target_os = "freebsd",
485     target_os = "ios",
486     target_os = "linux",
487     target_os = "macos",
488     target_os = "netbsd",
489     target_os = "openbsd",
490 ))]
491 sockopt_impl!(
492     /// Set delivery of the `IPV6_PKTINFO` control message on incoming
493     /// datagrams.
494     Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
495 #[cfg(any(
496     target_os = "freebsd",
497     target_os = "ios",
498     target_os = "macos",
499     target_os = "netbsd",
500     target_os = "openbsd",
501 ))]
502 sockopt_impl!(
503     /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to
504     /// the interface on which the packet was received.
505     Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
506 #[cfg(any(
507     target_os = "freebsd",
508     target_os = "ios",
509     target_os = "macos",
510     target_os = "netbsd",
511     target_os = "openbsd",
512 ))]
513 sockopt_impl!(
514     /// The `recvmsg(2)` call will return the destination IP address for a UDP
515     /// datagram.
516     Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
517 #[cfg(target_os = "linux")]
518 sockopt_impl!(
519     #[allow(missing_docs)]
520     // Not documented by Linux!
521     UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
522 #[cfg(target_os = "linux")]
523 sockopt_impl!(
524     #[allow(missing_docs)]
525     // Not documented by Linux!
526     UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
527 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
528 sockopt_impl!(
529     /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should
530     /// be attached to received skbs indicating the number of packets dropped by
531     /// the socket since its creation.
532     RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int);
533 sockopt_impl!(
534     /// The socket is restricted to sending and receiving IPv6 packets only.
535     Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool);
536 #[cfg(any(target_os = "android", target_os = "linux"))]
537 sockopt_impl!(
538     /// Enable extended reliable error message passing.
539     Ipv4RecvErr, Both, libc::IPPROTO_IP, libc::IP_RECVERR, bool);
540 #[cfg(any(target_os = "android", target_os = "linux"))]
541 sockopt_impl!(
542     /// Control receiving of asynchronous error options.
543     Ipv6RecvErr, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVERR, bool);
544 #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
545 sockopt_impl!(
546     /// Set or retrieve the current time-to-live field that is used in every
547     /// packet sent from this socket.
548     Ipv4Ttl, Both, libc::IPPROTO_IP, libc::IP_TTL, libc::c_int);
549 #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
550 sockopt_impl!(
551     /// Set the unicast hop limit for the socket.
552     Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int);
553 
554 #[allow(missing_docs)]
555 // Not documented by Linux!
556 #[cfg(any(target_os = "android", target_os = "linux"))]
557 #[derive(Copy, Clone, Debug)]
558 pub struct AlgSetAeadAuthSize;
559 
560 // ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
561 // See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
562 #[cfg(any(target_os = "android", target_os = "linux"))]
563 impl SetSockOpt for AlgSetAeadAuthSize {
564     type Val = usize;
565 
set(&self, fd: RawFd, val: &usize) -> Result<()>566     fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
567         unsafe {
568             let res = libc::setsockopt(fd,
569                                        libc::SOL_ALG,
570                                        libc::ALG_SET_AEAD_AUTHSIZE,
571                                        ::std::ptr::null(),
572                                        *val as libc::socklen_t);
573             Errno::result(res).map(drop)
574         }
575     }
576 }
577 
578 #[allow(missing_docs)]
579 // Not documented by Linux!
580 #[cfg(any(target_os = "android", target_os = "linux"))]
581 #[derive(Clone, Debug)]
582 pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
583 
584 #[cfg(any(target_os = "android", target_os = "linux"))]
585 impl<T> Default for AlgSetKey<T> {
default() -> Self586     fn default() -> Self {
587         AlgSetKey(Default::default())
588     }
589 }
590 
591 #[cfg(any(target_os = "android", target_os = "linux"))]
592 impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
593     type Val = T;
594 
set(&self, fd: RawFd, val: &T) -> Result<()>595     fn set(&self, fd: RawFd, val: &T) -> Result<()> {
596         unsafe {
597             let res = libc::setsockopt(fd,
598                                        libc::SOL_ALG,
599                                        libc::ALG_SET_KEY,
600                                        val.as_ref().as_ptr() as *const _,
601                                        val.as_ref().len() as libc::socklen_t);
602             Errno::result(res).map(drop)
603         }
604     }
605 }
606 
607 /*
608  *
609  * ===== Accessor helpers =====
610  *
611  */
612 
613 /// Helper trait that describes what is expected from a `GetSockOpt` getter.
614 trait Get<T> {
615     /// Returns an uninitialized value.
uninit() -> Self616     fn uninit() -> Self;
617     /// Returns a pointer to the stored value. This pointer will be passed to the system's
618     /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
ffi_ptr(&mut self) -> *mut c_void619     fn ffi_ptr(&mut self) -> *mut c_void;
620     /// Returns length of the stored value. This pointer will be passed to the system's
621     /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
ffi_len(&mut self) -> *mut socklen_t622     fn ffi_len(&mut self) -> *mut socklen_t;
623     /// Returns the hopefully initialized inner value.
assume_init(self) -> T624     unsafe fn assume_init(self) -> T;
625 }
626 
627 /// Helper trait that describes what is expected from a `SetSockOpt` setter.
628 trait Set<'a, T> {
629     /// Initialize the setter with a given value.
new(val: &'a T) -> Self630     fn new(val: &'a T) -> Self;
631     /// Returns a pointer to the stored value. This pointer will be passed to the system's
632     /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
ffi_ptr(&self) -> *const c_void633     fn ffi_ptr(&self) -> *const c_void;
634     /// Returns length of the stored value. This pointer will be passed to the system's
635     /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
ffi_len(&self) -> socklen_t636     fn ffi_len(&self) -> socklen_t;
637 }
638 
639 /// Getter for an arbitrary `struct`.
640 struct GetStruct<T> {
641     len: socklen_t,
642     val: MaybeUninit<T>,
643 }
644 
645 impl<T> Get<T> for GetStruct<T> {
uninit() -> Self646     fn uninit() -> Self {
647         GetStruct {
648             len: mem::size_of::<T>() as socklen_t,
649             val: MaybeUninit::uninit(),
650         }
651     }
652 
ffi_ptr(&mut self) -> *mut c_void653     fn ffi_ptr(&mut self) -> *mut c_void {
654         self.val.as_mut_ptr() as *mut c_void
655     }
656 
ffi_len(&mut self) -> *mut socklen_t657     fn ffi_len(&mut self) -> *mut socklen_t {
658         &mut self.len
659     }
660 
assume_init(self) -> T661     unsafe fn assume_init(self) -> T {
662         assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
663         self.val.assume_init()
664     }
665 }
666 
667 /// Setter for an arbitrary `struct`.
668 struct SetStruct<'a, T: 'static> {
669     ptr: &'a T,
670 }
671 
672 impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
new(ptr: &'a T) -> SetStruct<'a, T>673     fn new(ptr: &'a T) -> SetStruct<'a, T> {
674         SetStruct { ptr }
675     }
676 
ffi_ptr(&self) -> *const c_void677     fn ffi_ptr(&self) -> *const c_void {
678         self.ptr as *const T as *const c_void
679     }
680 
ffi_len(&self) -> socklen_t681     fn ffi_len(&self) -> socklen_t {
682         mem::size_of::<T>() as socklen_t
683     }
684 }
685 
686 /// Getter for a boolean value.
687 struct GetBool {
688     len: socklen_t,
689     val: MaybeUninit<c_int>,
690 }
691 
692 impl Get<bool> for GetBool {
uninit() -> Self693     fn uninit() -> Self {
694         GetBool {
695             len: mem::size_of::<c_int>() as socklen_t,
696             val: MaybeUninit::uninit(),
697         }
698     }
699 
ffi_ptr(&mut self) -> *mut c_void700     fn ffi_ptr(&mut self) -> *mut c_void {
701         self.val.as_mut_ptr() as *mut c_void
702     }
703 
ffi_len(&mut self) -> *mut socklen_t704     fn ffi_len(&mut self) -> *mut socklen_t {
705         &mut self.len
706     }
707 
assume_init(self) -> bool708     unsafe fn assume_init(self) -> bool {
709         assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
710         self.val.assume_init() != 0
711     }
712 }
713 
714 /// Setter for a boolean value.
715 struct SetBool {
716     val: c_int,
717 }
718 
719 impl<'a> Set<'a, bool> for SetBool {
new(val: &'a bool) -> SetBool720     fn new(val: &'a bool) -> SetBool {
721         SetBool { val: if *val { 1 } else { 0 } }
722     }
723 
ffi_ptr(&self) -> *const c_void724     fn ffi_ptr(&self) -> *const c_void {
725         &self.val as *const c_int as *const c_void
726     }
727 
ffi_len(&self) -> socklen_t728     fn ffi_len(&self) -> socklen_t {
729         mem::size_of::<c_int>() as socklen_t
730     }
731 }
732 
733 /// Getter for an `u8` value.
734 struct GetU8 {
735     len: socklen_t,
736     val: MaybeUninit<u8>,
737 }
738 
739 impl Get<u8> for GetU8 {
uninit() -> Self740     fn uninit() -> Self {
741         GetU8 {
742             len: mem::size_of::<u8>() as socklen_t,
743             val: MaybeUninit::uninit(),
744         }
745     }
746 
ffi_ptr(&mut self) -> *mut c_void747     fn ffi_ptr(&mut self) -> *mut c_void {
748         self.val.as_mut_ptr() as *mut c_void
749     }
750 
ffi_len(&mut self) -> *mut socklen_t751     fn ffi_len(&mut self) -> *mut socklen_t {
752         &mut self.len
753     }
754 
assume_init(self) -> u8755     unsafe fn assume_init(self) -> u8 {
756         assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
757         self.val.assume_init()
758     }
759 }
760 
761 /// Setter for an `u8` value.
762 struct SetU8 {
763     val: u8,
764 }
765 
766 impl<'a> Set<'a, u8> for SetU8 {
new(val: &'a u8) -> SetU8767     fn new(val: &'a u8) -> SetU8 {
768         SetU8 { val: *val as u8 }
769     }
770 
ffi_ptr(&self) -> *const c_void771     fn ffi_ptr(&self) -> *const c_void {
772         &self.val as *const u8 as *const c_void
773     }
774 
ffi_len(&self) -> socklen_t775     fn ffi_len(&self) -> socklen_t {
776         mem::size_of::<c_int>() as socklen_t
777     }
778 }
779 
780 /// Getter for an `usize` value.
781 struct GetUsize {
782     len: socklen_t,
783     val: MaybeUninit<c_int>,
784 }
785 
786 impl Get<usize> for GetUsize {
uninit() -> Self787     fn uninit() -> Self {
788         GetUsize {
789             len: mem::size_of::<c_int>() as socklen_t,
790             val: MaybeUninit::uninit(),
791         }
792     }
793 
ffi_ptr(&mut self) -> *mut c_void794     fn ffi_ptr(&mut self) -> *mut c_void {
795         self.val.as_mut_ptr() as *mut c_void
796     }
797 
ffi_len(&mut self) -> *mut socklen_t798     fn ffi_len(&mut self) -> *mut socklen_t {
799         &mut self.len
800     }
801 
assume_init(self) -> usize802     unsafe fn assume_init(self) -> usize {
803         assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
804         self.val.assume_init() as usize
805     }
806 }
807 
808 /// Setter for an `usize` value.
809 struct SetUsize {
810     val: c_int,
811 }
812 
813 impl<'a> Set<'a, usize> for SetUsize {
new(val: &'a usize) -> SetUsize814     fn new(val: &'a usize) -> SetUsize {
815         SetUsize { val: *val as c_int }
816     }
817 
ffi_ptr(&self) -> *const c_void818     fn ffi_ptr(&self) -> *const c_void {
819         &self.val as *const c_int as *const c_void
820     }
821 
ffi_len(&self) -> socklen_t822     fn ffi_len(&self) -> socklen_t {
823         mem::size_of::<c_int>() as socklen_t
824     }
825 }
826 
827 /// Getter for a `OsString` value.
828 struct GetOsString<T: AsMut<[u8]>> {
829     len: socklen_t,
830     val: MaybeUninit<T>,
831 }
832 
833 impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
uninit() -> Self834     fn uninit() -> Self {
835         GetOsString {
836             len: mem::size_of::<T>() as socklen_t,
837             val: MaybeUninit::uninit(),
838         }
839     }
840 
ffi_ptr(&mut self) -> *mut c_void841     fn ffi_ptr(&mut self) -> *mut c_void {
842         self.val.as_mut_ptr() as *mut c_void
843     }
844 
ffi_len(&mut self) -> *mut socklen_t845     fn ffi_len(&mut self) -> *mut socklen_t {
846         &mut self.len
847     }
848 
assume_init(self) -> OsString849     unsafe fn assume_init(self) -> OsString {
850         let len = self.len as usize;
851         let mut v = self.val.assume_init();
852         OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
853     }
854 }
855 
856 /// Setter for a `OsString` value.
857 struct SetOsString<'a> {
858     val: &'a OsStr,
859 }
860 
861 impl<'a> Set<'a, OsString> for SetOsString<'a> {
new(val: &'a OsString) -> SetOsString862     fn new(val: &'a OsString) -> SetOsString {
863         SetOsString { val: val.as_os_str() }
864     }
865 
ffi_ptr(&self) -> *const c_void866     fn ffi_ptr(&self) -> *const c_void {
867         self.val.as_bytes().as_ptr() as *const c_void
868     }
869 
ffi_len(&self) -> socklen_t870     fn ffi_len(&self) -> socklen_t {
871         self.val.len() as socklen_t
872     }
873 }
874 
875 
876 #[cfg(test)]
877 mod test {
878     #[cfg(any(target_os = "android", target_os = "linux"))]
879     #[test]
can_get_peercred_on_unix_socket()880     fn can_get_peercred_on_unix_socket() {
881         use super::super::*;
882 
883         let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
884         let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
885         let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
886         assert_eq!(a_cred, b_cred);
887         assert!(a_cred.pid() != 0);
888     }
889 
890     #[test]
is_socket_type_unix()891     fn is_socket_type_unix() {
892         use super::super::*;
893         use crate::unistd::close;
894 
895         let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
896         let a_type = getsockopt(a, super::SockType).unwrap();
897         assert_eq!(a_type, SockType::Stream);
898         close(a).unwrap();
899         close(b).unwrap();
900     }
901 
902     #[test]
is_socket_type_dgram()903     fn is_socket_type_dgram() {
904         use super::super::*;
905         use crate::unistd::close;
906 
907         let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
908         let s_type = getsockopt(s, super::SockType).unwrap();
909         assert_eq!(s_type, SockType::Datagram);
910         close(s).unwrap();
911     }
912 
913     #[cfg(any(target_os = "freebsd",
914               target_os = "linux",
915               target_os = "nacl"))]
916     #[test]
can_get_listen_on_tcp_socket()917     fn can_get_listen_on_tcp_socket() {
918         use super::super::*;
919         use crate::unistd::close;
920 
921         let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
922         let s_listening = getsockopt(s, super::AcceptConn).unwrap();
923         assert!(!s_listening);
924         listen(s, 10).unwrap();
925         let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
926         assert!(s_listening2);
927         close(s).unwrap();
928     }
929 
930 }
931