summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/test/sys/test_sockopt.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
commit8dd16259287f58f9273002717ec4d27e97127719 (patch)
tree3863e62a53829a84037444beab3abd4ed9dfc7d0 /third_party/rust/nix/test/sys/test_sockopt.rs
parentReleasing progress-linux version 126.0.1-1~progress7.99u1. (diff)
downloadfirefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz
firefox-8dd16259287f58f9273002717ec4d27e97127719.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nix/test/sys/test_sockopt.rs')
-rw-r--r--third_party/rust/nix/test/sys/test_sockopt.rs454
1 files changed, 418 insertions, 36 deletions
diff --git a/third_party/rust/nix/test/sys/test_sockopt.rs b/third_party/rust/nix/test/sys/test_sockopt.rs
index 0e34917325..a99d4e39ed 100644
--- a/third_party/rust/nix/test/sys/test_sockopt.rs
+++ b/third_party/rust/nix/test/sys/test_sockopt.rs
@@ -1,14 +1,14 @@
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
use crate::*;
use nix::sys::socket::{
getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag,
SockProtocol, SockType,
};
use rand::{thread_rng, Rng};
-use std::os::unix::io::AsRawFd;
+use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))]
+#[cfg(freebsdlike)]
#[test]
pub fn test_local_peercred_seqpacket() {
use nix::{
@@ -29,12 +29,7 @@ pub fn test_local_peercred_seqpacket() {
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
}
-#[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "macos",
- target_os = "ios"
-))]
+#[cfg(any(freebsdlike, apple_targets))]
#[test]
pub fn test_local_peercred_stream() {
use nix::{
@@ -55,7 +50,7 @@ pub fn test_local_peercred_stream() {
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
}
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
#[test]
pub fn test_local_peer_pid() {
use nix::sys::socket::socketpair;
@@ -108,15 +103,42 @@ fn test_so_buf() {
assert!(actual >= bufsize);
}
+#[cfg(target_os = "freebsd")]
+#[test]
+fn test_so_listen_q_limit() {
+ use nix::sys::socket::{bind, listen, Backlog, SockaddrIn};
+ use std::net::SocketAddrV4;
+ use std::str::FromStr;
+
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:4004").unwrap();
+ let sock_addr = SockaddrIn::from(std_sa);
+
+ let rsock = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+ let pre_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
+ assert_eq!(pre_limit, 0);
+ listen(&rsock, Backlog::new(42).unwrap()).unwrap();
+ let post_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
+ assert_eq!(post_limit, 42);
+}
+
#[test]
fn test_so_tcp_maxseg() {
- use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn};
+ use nix::sys::socket::{
+ accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
+ };
use nix::unistd::write;
use std::net::SocketAddrV4;
use std::str::FromStr;
- let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
- let sock_addr = SockaddrIn::from(std_sa);
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
+ let mut sock_addr = SockaddrIn::from(std_sa);
let rsock = socket(
AddressFamily::Inet,
@@ -126,13 +148,14 @@ fn test_so_tcp_maxseg() {
)
.unwrap();
bind(rsock.as_raw_fd(), &sock_addr).unwrap();
- listen(&rsock, 10).unwrap();
+ sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
+ listen(&rsock, Backlog::new(10).unwrap()).unwrap();
let initial = getsockopt(&rsock, sockopt::TcpMaxSeg).unwrap();
// Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
// platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
// than 700
cfg_if! {
- if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ if #[cfg(linux_android)] {
let segsize: u32 = 873;
assert!(initial < segsize);
setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
@@ -151,12 +174,13 @@ fn test_so_tcp_maxseg() {
.unwrap();
connect(ssock.as_raw_fd(), &sock_addr).unwrap();
let rsess = accept(rsock.as_raw_fd()).unwrap();
- write(rsess, b"hello").unwrap();
+ let rsess = unsafe { OwnedFd::from_raw_fd(rsess) };
+ write(&rsess, b"hello").unwrap();
let actual = getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap();
// Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
// TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
cfg_if! {
- if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ if #[cfg(linux_android)] {
assert!((segsize - 100) <= actual);
assert!(actual <= segsize);
} else {
@@ -181,11 +205,10 @@ fn test_so_type() {
/// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket
/// types. Regression test for https://github.com/nix-rust/nix/issues/1819
-#[cfg(any(target_os = "android", target_os = "linux",))]
+#[cfg(linux_android)]
#[test]
fn test_so_type_unknown() {
use nix::errno::Errno;
- use std::os::unix::io::{FromRawFd, OwnedFd};
require_capability!("test_so_type", CAP_NET_RAW);
let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
@@ -229,7 +252,7 @@ fn test_tcp_congestion() {
}
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
fn test_bindtodevice() {
skip_if_not_root!("test_bindtodevice");
@@ -259,12 +282,7 @@ fn test_so_tcp_keepalive() {
setsockopt(&fd, sockopt::KeepAlive, &true).unwrap();
assert!(getsockopt(&fd, sockopt::KeepAlive).unwrap());
- #[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "linux"
- ))]
+ #[cfg(any(linux_android, freebsdlike))]
{
let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap();
setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
@@ -281,14 +299,14 @@ fn test_so_tcp_keepalive() {
}
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[cfg_attr(qemu, ignore)]
fn test_get_mtu() {
use nix::sys::socket::{bind, connect, SockaddrIn};
use std::net::SocketAddrV4;
use std::str::FromStr;
- let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap();
let usock = socket(
@@ -308,7 +326,7 @@ fn test_get_mtu() {
}
#[test]
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
fn test_ttl_opts() {
let fd4 = socket(
AddressFamily::Inet,
@@ -331,7 +349,48 @@ fn test_ttl_opts() {
}
#[test]
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
+fn test_multicast_ttl_opts_ipv4() {
+ let fd4 = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd4, sockopt::IpMulticastTtl, &2)
+ .expect("setting ipmulticastttl on an inet socket should succeed");
+}
+
+#[test]
+#[cfg(linux_android)]
+fn test_multicast_ttl_opts_ipv6() {
+ let fd6 = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd6, sockopt::IpMulticastTtl, &2)
+ .expect("setting ipmulticastttl on an inet6 socket should succeed");
+}
+
+#[test]
+fn test_ipv6_multicast_hops() {
+ let fd6 = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd6, sockopt::Ipv6MulticastHops, &7)
+ .expect("setting ipv6multicasthops on an inet6 socket should succeed");
+}
+
+#[test]
+#[cfg(apple_targets)]
fn test_dontfrag_opts() {
let fd4 = socket(
AddressFamily::Inet,
@@ -361,12 +420,7 @@ fn test_dontfrag_opts() {
}
#[test]
-#[cfg(any(
- target_os = "android",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
-))]
+#[cfg(any(linux_android, apple_targets))]
// Disable the test under emulation because it fails in Cirrus-CI. Lack
// of QEMU support is suspected.
#[cfg_attr(qemu, ignore)]
@@ -446,3 +500,331 @@ fn test_ipv6_tclass() {
setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap();
assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class);
}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_receive_timestamp() {
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+ assert!(getsockopt(&fd, sockopt::ReceiveTimestamp).unwrap());
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_realtime_micro() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(
+ &fd,
+ sockopt::TsClock,
+ &SocketTimestamp::SO_TS_REALTIME_MICRO,
+ )
+ .unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_REALTIME_MICRO
+ );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_bintime() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_BINTIME).unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_BINTIME
+ );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_realtime() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_REALTIME)
+ .unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_REALTIME
+ );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_monotonic() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_MONOTONIC)
+ .unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_MONOTONIC
+ );
+}
+
+#[test]
+#[cfg(linux_android)]
+// Disable the test under emulation because it fails with ENOPROTOOPT in CI
+// on cross target. Lack of QEMU support is suspected.
+#[cfg_attr(qemu, ignore)]
+fn test_ip_bind_address_no_port() {
+ let fd = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ setsockopt(&fd, sockopt::IpBindAddressNoPort, &true).expect(
+ "setting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ );
+ assert!(getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
+ "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ ));
+ setsockopt(&fd, sockopt::IpBindAddressNoPort, &false).expect(
+ "unsetting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ );
+ assert!(!getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
+ "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ ));
+}
+
+#[test]
+#[cfg(linux_android)]
+fn test_tcp_fast_open_connect() {
+ let fd = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ setsockopt(&fd, sockopt::TcpFastOpenConnect, &true).expect(
+ "setting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ );
+ assert!(getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
+ "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ ));
+ setsockopt(&fd, sockopt::TcpFastOpenConnect, &false).expect(
+ "unsetting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ );
+ assert!(!getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
+ "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ ));
+}
+
+#[cfg(linux_android)]
+#[test]
+fn can_get_peercred_on_unix_socket() {
+ use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
+
+ let (a, b) = socketpair(
+ AddressFamily::Unix,
+ SockType::Stream,
+ None,
+ SockFlag::empty(),
+ )
+ .unwrap();
+ let a_cred = getsockopt(&a, sockopt::PeerCredentials).unwrap();
+ let b_cred = getsockopt(&b, sockopt::PeerCredentials).unwrap();
+ assert_eq!(a_cred, b_cred);
+ assert_ne!(a_cred.pid(), 0);
+}
+
+#[test]
+fn is_socket_type_unix() {
+ use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
+
+ let (a, _b) = socketpair(
+ AddressFamily::Unix,
+ SockType::Stream,
+ None,
+ SockFlag::empty(),
+ )
+ .unwrap();
+ let a_type = getsockopt(&a, sockopt::SockType).unwrap();
+ assert_eq!(a_type, SockType::Stream);
+}
+
+#[test]
+fn is_socket_type_dgram() {
+ use nix::sys::socket::{
+ getsockopt, sockopt, AddressFamily, SockFlag, SockType,
+ };
+
+ let s = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ let s_type = getsockopt(&s, sockopt::SockType).unwrap();
+ assert_eq!(s_type, SockType::Datagram);
+}
+
+#[cfg(any(target_os = "freebsd", target_os = "linux"))]
+#[test]
+fn can_get_listen_on_tcp_socket() {
+ use nix::sys::socket::{
+ getsockopt, listen, socket, sockopt, AddressFamily, Backlog, SockFlag,
+ SockType,
+ };
+
+ let s = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ let s_listening = getsockopt(&s, sockopt::AcceptConn).unwrap();
+ assert!(!s_listening);
+ listen(&s, Backlog::new(10).unwrap()).unwrap();
+ let s_listening2 = getsockopt(&s, sockopt::AcceptConn).unwrap();
+ assert!(s_listening2);
+}
+
+#[cfg(target_os = "linux")]
+// Some architectures running under cross don't support `setsockopt(SOL_TCP, TCP_ULP)`
+// because the cross image is based on Ubuntu 16.04 which predates TCP ULP support
+// (it was added in kernel v4.13 released in 2017). For these architectures,
+// the `setsockopt(SOL_TCP, TCP_ULP, "tls", sizeof("tls"))` call succeeds
+// but the subsequent `setsockopt(SOL_TLS, TLS_TX, ...)` call fails with `ENOPROTOOPT`.
+// It's as if the first `setsockopt` call enabled some other option, not `TCP_ULP`.
+// For example, `strace` says:
+//
+// [pid 813] setsockopt(4, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0
+//
+// It's not clear why `setsockopt(SOL_TCP, TCP_ULP)` succeeds if the container image libc doesn't support it,
+// but in any case we can't run the test on such an architecture, so skip it.
+#[cfg_attr(qemu, ignore)]
+#[test]
+fn test_ktls() {
+ use nix::sys::socket::{
+ accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
+ };
+ use std::net::SocketAddrV4;
+ use std::str::FromStr;
+
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
+ let mut sock_addr = SockaddrIn::from(std_sa);
+
+ let rsock = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+ sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
+ listen(&rsock, Backlog::new(10).unwrap()).unwrap();
+
+ let ssock = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ connect(ssock.as_raw_fd(), &sock_addr).unwrap();
+
+ let _rsess = accept(rsock.as_raw_fd()).unwrap();
+
+ match setsockopt(&ssock, sockopt::TcpUlp::default(), b"tls") {
+ Ok(()) => (),
+
+ // TLS ULP is not enabled, so we can't test kTLS.
+ Err(nix::Error::ENOENT) => skip!("TLS ULP is not enabled"),
+
+ Err(err) => panic!("{err:?}"),
+ }
+
+ // In real life we would do a TLS handshake and extract the protocol version and secrets.
+ // For this test we just make some up.
+
+ let tx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
+ info: libc::tls_crypto_info {
+ version: libc::TLS_1_2_VERSION,
+ cipher_type: libc::TLS_CIPHER_AES_GCM_128,
+ },
+ iv: *b"\x04\x05\x06\x07\x08\x09\x0a\x0b",
+ key: *b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ salt: *b"\x00\x01\x02\x03",
+ rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
+ });
+ setsockopt(&ssock, sockopt::TcpTlsTx, &tx)
+ .expect("setting TLS_TX after enabling TLS ULP should succeed");
+
+ let rx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
+ info: libc::tls_crypto_info {
+ version: libc::TLS_1_2_VERSION,
+ cipher_type: libc::TLS_CIPHER_AES_GCM_128,
+ },
+ iv: *b"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb",
+ key: *b"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
+ salt: *b"\xf0\xf1\xf2\xf3",
+ rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
+ });
+ match setsockopt(&ssock, sockopt::TcpTlsRx, &rx) {
+ Ok(()) => (),
+ Err(nix::Error::ENOPROTOOPT) => {
+ // TLS_TX was added in v4.13 and TLS_RX in v4.17, so we appear to be between that range.
+ // It's good enough that TLS_TX worked, so let the test succeed.
+ }
+ Err(err) => panic!("{err:?}"),
+ }
+}