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