1 #[cfg(linux_android)]
2 use crate::*;
3 use nix::sys::socket::{
4     getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag,
5     SockProtocol, SockType,
6 };
7 use rand::{thread_rng, Rng};
8 use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
9 
10 // NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
11 #[cfg(freebsdlike)]
12 #[test]
test_local_peercred_seqpacket()13 pub fn test_local_peercred_seqpacket() {
14     use nix::{
15         sys::socket::socketpair,
16         unistd::{Gid, Uid},
17     };
18 
19     let (fd1, _fd2) = socketpair(
20         AddressFamily::Unix,
21         SockType::SeqPacket,
22         None,
23         SockFlag::empty(),
24     )
25     .unwrap();
26     let xucred = getsockopt(&fd1, sockopt::LocalPeerCred).unwrap();
27     assert_eq!(xucred.version(), 0);
28     assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
29     assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
30 }
31 
32 #[cfg(any(freebsdlike, apple_targets))]
33 #[test]
test_local_peercred_stream()34 pub fn test_local_peercred_stream() {
35     use nix::{
36         sys::socket::socketpair,
37         unistd::{Gid, Uid},
38     };
39 
40     let (fd1, _fd2) = socketpair(
41         AddressFamily::Unix,
42         SockType::Stream,
43         None,
44         SockFlag::empty(),
45     )
46     .unwrap();
47     let xucred = getsockopt(&fd1, sockopt::LocalPeerCred).unwrap();
48     assert_eq!(xucred.version(), 0);
49     assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
50     assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
51 }
52 
53 #[cfg(apple_targets)]
54 #[test]
test_local_peer_pid()55 pub fn test_local_peer_pid() {
56     use nix::sys::socket::socketpair;
57 
58     let (fd1, _fd2) = socketpair(
59         AddressFamily::Unix,
60         SockType::Stream,
61         None,
62         SockFlag::empty(),
63     )
64     .unwrap();
65     let pid = getsockopt(&fd1, sockopt::LocalPeerPid).unwrap();
66     assert_eq!(pid, std::process::id() as _);
67 }
68 
69 #[cfg(target_os = "linux")]
70 #[test]
is_so_mark_functional()71 fn is_so_mark_functional() {
72     use nix::sys::socket::sockopt;
73 
74     require_capability!("is_so_mark_functional", CAP_NET_ADMIN);
75 
76     let s = socket(
77         AddressFamily::Inet,
78         SockType::Stream,
79         SockFlag::empty(),
80         None,
81     )
82     .unwrap();
83     setsockopt(&s, sockopt::Mark, &1337).unwrap();
84     let mark = getsockopt(&s, sockopt::Mark).unwrap();
85     assert_eq!(mark, 1337);
86 }
87 
88 #[test]
test_so_buf()89 fn test_so_buf() {
90     let fd = socket(
91         AddressFamily::Inet,
92         SockType::Datagram,
93         SockFlag::empty(),
94         SockProtocol::Udp,
95     )
96     .unwrap();
97     let bufsize: usize = thread_rng().gen_range(4096..131_072);
98     setsockopt(&fd, sockopt::SndBuf, &bufsize).unwrap();
99     let actual = getsockopt(&fd, sockopt::SndBuf).unwrap();
100     assert!(actual >= bufsize);
101     setsockopt(&fd, sockopt::RcvBuf, &bufsize).unwrap();
102     let actual = getsockopt(&fd, sockopt::RcvBuf).unwrap();
103     assert!(actual >= bufsize);
104 }
105 
106 #[cfg(target_os = "freebsd")]
107 #[test]
test_so_listen_q_limit()108 fn test_so_listen_q_limit() {
109     use nix::sys::socket::{bind, listen, Backlog, SockaddrIn};
110     use std::net::SocketAddrV4;
111     use std::str::FromStr;
112 
113     let std_sa = SocketAddrV4::from_str("127.0.0.1:4004").unwrap();
114     let sock_addr = SockaddrIn::from(std_sa);
115 
116     let rsock = socket(
117         AddressFamily::Inet,
118         SockType::Stream,
119         SockFlag::empty(),
120         SockProtocol::Tcp,
121     )
122     .unwrap();
123     bind(rsock.as_raw_fd(), &sock_addr).unwrap();
124     let pre_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
125     assert_eq!(pre_limit, 0);
126     listen(&rsock, Backlog::new(42).unwrap()).unwrap();
127     let post_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
128     assert_eq!(post_limit, 42);
129 }
130 
131 #[test]
test_so_tcp_maxseg()132 fn test_so_tcp_maxseg() {
133     use nix::sys::socket::{
134         accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
135     };
136     use nix::unistd::write;
137     use std::net::SocketAddrV4;
138     use std::str::FromStr;
139 
140     let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
141     let mut sock_addr = SockaddrIn::from(std_sa);
142 
143     let rsock = socket(
144         AddressFamily::Inet,
145         SockType::Stream,
146         SockFlag::empty(),
147         SockProtocol::Tcp,
148     )
149     .unwrap();
150     bind(rsock.as_raw_fd(), &sock_addr).unwrap();
151     sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
152     listen(&rsock, Backlog::new(10).unwrap()).unwrap();
153     let initial = getsockopt(&rsock, sockopt::TcpMaxSeg).unwrap();
154     // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
155     // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
156     // than 700
157     cfg_if! {
158         if #[cfg(linux_android)] {
159             let segsize: u32 = 873;
160             assert!(initial < segsize);
161             setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
162         } else {
163             assert!(initial < 700);
164         }
165     }
166 
167     // Connect and check the MSS that was advertised
168     let ssock = socket(
169         AddressFamily::Inet,
170         SockType::Stream,
171         SockFlag::empty(),
172         SockProtocol::Tcp,
173     )
174     .unwrap();
175     connect(ssock.as_raw_fd(), &sock_addr).unwrap();
176     let rsess = accept(rsock.as_raw_fd()).unwrap();
177     let rsess = unsafe { OwnedFd::from_raw_fd(rsess) };
178     write(&rsess, b"hello").unwrap();
179     let actual = getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap();
180     // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
181     // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
182     cfg_if! {
183         if #[cfg(linux_android)] {
184             assert!((segsize - 100) <= actual);
185             assert!(actual <= segsize);
186         } else {
187             assert!(initial < actual);
188             assert!(536 < actual);
189         }
190     }
191 }
192 
193 #[test]
test_so_type()194 fn test_so_type() {
195     let sockfd = socket(
196         AddressFamily::Inet,
197         SockType::Stream,
198         SockFlag::empty(),
199         None,
200     )
201     .unwrap();
202 
203     assert_eq!(Ok(SockType::Stream), getsockopt(&sockfd, sockopt::SockType));
204 }
205 
206 /// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket
207 /// types.  Regression test for https://github.com/nix-rust/nix/issues/1819
208 #[cfg(linux_android)]
209 #[test]
test_so_type_unknown()210 fn test_so_type_unknown() {
211     use nix::errno::Errno;
212 
213     require_capability!("test_so_type", CAP_NET_RAW);
214     let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
215     assert!(raw_fd >= 0, "Error opening socket: {}", nix::Error::last());
216     let sockfd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
217 
218     assert_eq!(Err(Errno::EINVAL), getsockopt(&sockfd, sockopt::SockType));
219 }
220 
221 // The CI doesn't supported getsockopt and setsockopt on emulated processors.
222 // It's believed that a QEMU issue, the tests run ok on a fully emulated system.
223 // Current CI just run the binary with QEMU but the Kernel remains the same as the host.
224 // So the syscall doesn't work properly unless the kernel is also emulated.
225 #[test]
226 #[cfg(all(
227     any(target_arch = "x86", target_arch = "x86_64"),
228     any(target_os = "freebsd", target_os = "linux")
229 ))]
test_tcp_congestion()230 fn test_tcp_congestion() {
231     use std::ffi::OsString;
232 
233     let fd = socket(
234         AddressFamily::Inet,
235         SockType::Stream,
236         SockFlag::empty(),
237         None,
238     )
239     .unwrap();
240 
241     let val = getsockopt(&fd, sockopt::TcpCongestion).unwrap();
242     setsockopt(&fd, sockopt::TcpCongestion, &val).unwrap();
243 
244     setsockopt(
245         &fd,
246         sockopt::TcpCongestion,
247         &OsString::from("tcp_congestion_does_not_exist"),
248     )
249     .unwrap_err();
250 
251     assert_eq!(getsockopt(&fd, sockopt::TcpCongestion).unwrap(), val);
252 }
253 
254 #[test]
255 #[cfg(linux_android)]
test_bindtodevice()256 fn test_bindtodevice() {
257     skip_if_not_root!("test_bindtodevice");
258 
259     let fd = socket(
260         AddressFamily::Inet,
261         SockType::Stream,
262         SockFlag::empty(),
263         None,
264     )
265     .unwrap();
266 
267     let val = getsockopt(&fd, sockopt::BindToDevice).unwrap();
268     setsockopt(&fd, sockopt::BindToDevice, &val).unwrap();
269 
270     assert_eq!(getsockopt(&fd, sockopt::BindToDevice).unwrap(), val);
271 }
272 
273 #[test]
test_so_tcp_keepalive()274 fn test_so_tcp_keepalive() {
275     let fd = socket(
276         AddressFamily::Inet,
277         SockType::Stream,
278         SockFlag::empty(),
279         SockProtocol::Tcp,
280     )
281     .unwrap();
282     setsockopt(&fd, sockopt::KeepAlive, &true).unwrap();
283     assert!(getsockopt(&fd, sockopt::KeepAlive).unwrap());
284 
285     #[cfg(any(linux_android, freebsdlike))]
286     {
287         let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap();
288         setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
289         assert_eq!(getsockopt(&fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
290 
291         let x = getsockopt(&fd, sockopt::TcpKeepCount).unwrap();
292         setsockopt(&fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
293         assert_eq!(getsockopt(&fd, sockopt::TcpKeepCount).unwrap(), x + 1);
294 
295         let x = getsockopt(&fd, sockopt::TcpKeepInterval).unwrap();
296         setsockopt(&fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
297         assert_eq!(getsockopt(&fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
298     }
299 }
300 
301 #[test]
302 #[cfg(linux_android)]
303 #[cfg_attr(qemu, ignore)]
test_get_mtu()304 fn test_get_mtu() {
305     use nix::sys::socket::{bind, connect, SockaddrIn};
306     use std::net::SocketAddrV4;
307     use std::str::FromStr;
308 
309     let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
310     let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap();
311 
312     let usock = socket(
313         AddressFamily::Inet,
314         SockType::Datagram,
315         SockFlag::empty(),
316         SockProtocol::Udp,
317     )
318     .unwrap();
319 
320     // Bind and initiate connection
321     bind(usock.as_raw_fd(), &SockaddrIn::from(std_sa)).unwrap();
322     connect(usock.as_raw_fd(), &SockaddrIn::from(std_sb)).unwrap();
323 
324     // Loopback connections have 2^16 - the maximum - MTU
325     assert_eq!(getsockopt(&usock, sockopt::IpMtu), Ok(u16::MAX as i32))
326 }
327 
328 #[test]
329 #[cfg(any(linux_android, target_os = "freebsd"))]
test_ttl_opts()330 fn test_ttl_opts() {
331     let fd4 = socket(
332         AddressFamily::Inet,
333         SockType::Datagram,
334         SockFlag::empty(),
335         None,
336     )
337     .unwrap();
338     setsockopt(&fd4, sockopt::Ipv4Ttl, &1)
339         .expect("setting ipv4ttl on an inet socket should succeed");
340     let fd6 = socket(
341         AddressFamily::Inet6,
342         SockType::Datagram,
343         SockFlag::empty(),
344         None,
345     )
346     .unwrap();
347     setsockopt(&fd6, sockopt::Ipv6Ttl, &1)
348         .expect("setting ipv6ttl on an inet6 socket should succeed");
349 }
350 
351 #[test]
352 #[cfg(any(linux_android, target_os = "freebsd"))]
test_multicast_ttl_opts_ipv4()353 fn test_multicast_ttl_opts_ipv4() {
354     let fd4 = socket(
355         AddressFamily::Inet,
356         SockType::Datagram,
357         SockFlag::empty(),
358         None,
359     )
360     .unwrap();
361     setsockopt(&fd4, sockopt::IpMulticastTtl, &2)
362         .expect("setting ipmulticastttl on an inet socket should succeed");
363 }
364 
365 #[test]
366 #[cfg(linux_android)]
test_multicast_ttl_opts_ipv6()367 fn test_multicast_ttl_opts_ipv6() {
368     let fd6 = socket(
369         AddressFamily::Inet6,
370         SockType::Datagram,
371         SockFlag::empty(),
372         None,
373     )
374     .unwrap();
375     setsockopt(&fd6, sockopt::IpMulticastTtl, &2)
376         .expect("setting ipmulticastttl on an inet6 socket should succeed");
377 }
378 
379 #[test]
test_ipv6_multicast_hops()380 fn test_ipv6_multicast_hops() {
381     let fd6 = socket(
382         AddressFamily::Inet6,
383         SockType::Datagram,
384         SockFlag::empty(),
385         None,
386     )
387     .unwrap();
388     setsockopt(&fd6, sockopt::Ipv6MulticastHops, &7)
389         .expect("setting ipv6multicasthops on an inet6 socket should succeed");
390 }
391 
392 #[test]
393 #[cfg(apple_targets)]
test_dontfrag_opts()394 fn test_dontfrag_opts() {
395     let fd4 = socket(
396         AddressFamily::Inet,
397         SockType::Stream,
398         SockFlag::empty(),
399         SockProtocol::Tcp,
400     )
401     .unwrap();
402     setsockopt(&fd4, sockopt::IpDontFrag, &true)
403         .expect("setting IP_DONTFRAG on an inet stream socket should succeed");
404     setsockopt(&fd4, sockopt::IpDontFrag, &false).expect(
405         "unsetting IP_DONTFRAG on an inet stream socket should succeed",
406     );
407     let fd4d = socket(
408         AddressFamily::Inet,
409         SockType::Datagram,
410         SockFlag::empty(),
411         None,
412     )
413     .unwrap();
414     setsockopt(&fd4d, sockopt::IpDontFrag, &true).expect(
415         "setting IP_DONTFRAG on an inet datagram socket should succeed",
416     );
417     setsockopt(&fd4d, sockopt::IpDontFrag, &false).expect(
418         "unsetting IP_DONTFRAG on an inet datagram socket should succeed",
419     );
420 }
421 
422 #[test]
423 #[cfg(any(linux_android, apple_targets))]
424 // Disable the test under emulation because it fails in Cirrus-CI.  Lack
425 // of QEMU support is suspected.
426 #[cfg_attr(qemu, ignore)]
test_v6dontfrag_opts()427 fn test_v6dontfrag_opts() {
428     let fd6 = socket(
429         AddressFamily::Inet6,
430         SockType::Stream,
431         SockFlag::empty(),
432         SockProtocol::Tcp,
433     )
434     .unwrap();
435     setsockopt(&fd6, sockopt::Ipv6DontFrag, &true).expect(
436         "setting IPV6_DONTFRAG on an inet6 stream socket should succeed",
437     );
438     setsockopt(&fd6, sockopt::Ipv6DontFrag, &false).expect(
439         "unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed",
440     );
441     let fd6d = socket(
442         AddressFamily::Inet6,
443         SockType::Datagram,
444         SockFlag::empty(),
445         None,
446     )
447     .unwrap();
448     setsockopt(&fd6d, sockopt::Ipv6DontFrag, &true).expect(
449         "setting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
450     );
451     setsockopt(&fd6d, sockopt::Ipv6DontFrag, &false).expect(
452         "unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
453     );
454 }
455 
456 #[test]
457 #[cfg(target_os = "linux")]
test_so_priority()458 fn test_so_priority() {
459     let fd = socket(
460         AddressFamily::Inet,
461         SockType::Stream,
462         SockFlag::empty(),
463         SockProtocol::Tcp,
464     )
465     .unwrap();
466     let priority = 3;
467     setsockopt(&fd, sockopt::Priority, &priority).unwrap();
468     assert_eq!(getsockopt(&fd, sockopt::Priority).unwrap(), priority);
469 }
470 
471 #[test]
472 #[cfg(target_os = "linux")]
test_ip_tos()473 fn test_ip_tos() {
474     let fd = socket(
475         AddressFamily::Inet,
476         SockType::Stream,
477         SockFlag::empty(),
478         SockProtocol::Tcp,
479     )
480     .unwrap();
481     let tos = 0x80; // CS4
482     setsockopt(&fd, sockopt::IpTos, &tos).unwrap();
483     assert_eq!(getsockopt(&fd, sockopt::IpTos).unwrap(), tos);
484 }
485 
486 #[test]
487 #[cfg(target_os = "linux")]
488 // Disable the test under emulation because it fails in Cirrus-CI.  Lack
489 // of QEMU support is suspected.
490 #[cfg_attr(qemu, ignore)]
test_ipv6_tclass()491 fn test_ipv6_tclass() {
492     let fd = socket(
493         AddressFamily::Inet6,
494         SockType::Stream,
495         SockFlag::empty(),
496         SockProtocol::Tcp,
497     )
498     .unwrap();
499     let class = 0x80; // CS4
500     setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap();
501     assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class);
502 }
503 
504 #[test]
505 #[cfg(target_os = "freebsd")]
test_receive_timestamp()506 fn test_receive_timestamp() {
507     let fd = socket(
508         AddressFamily::Inet6,
509         SockType::Datagram,
510         SockFlag::empty(),
511         None,
512     )
513     .unwrap();
514     setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
515     assert!(getsockopt(&fd, sockopt::ReceiveTimestamp).unwrap());
516 }
517 
518 #[test]
519 #[cfg(target_os = "freebsd")]
test_ts_clock_realtime_micro()520 fn test_ts_clock_realtime_micro() {
521     use nix::sys::socket::SocketTimestamp;
522 
523     let fd = socket(
524         AddressFamily::Inet6,
525         SockType::Datagram,
526         SockFlag::empty(),
527         None,
528     )
529     .unwrap();
530 
531     // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
532     setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
533 
534     setsockopt(
535         &fd,
536         sockopt::TsClock,
537         &SocketTimestamp::SO_TS_REALTIME_MICRO,
538     )
539     .unwrap();
540     assert_eq!(
541         getsockopt(&fd, sockopt::TsClock).unwrap(),
542         SocketTimestamp::SO_TS_REALTIME_MICRO
543     );
544 }
545 
546 #[test]
547 #[cfg(target_os = "freebsd")]
test_ts_clock_bintime()548 fn test_ts_clock_bintime() {
549     use nix::sys::socket::SocketTimestamp;
550 
551     let fd = socket(
552         AddressFamily::Inet6,
553         SockType::Datagram,
554         SockFlag::empty(),
555         None,
556     )
557     .unwrap();
558 
559     // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
560     setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
561 
562     setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_BINTIME).unwrap();
563     assert_eq!(
564         getsockopt(&fd, sockopt::TsClock).unwrap(),
565         SocketTimestamp::SO_TS_BINTIME
566     );
567 }
568 
569 #[test]
570 #[cfg(target_os = "freebsd")]
test_ts_clock_realtime()571 fn test_ts_clock_realtime() {
572     use nix::sys::socket::SocketTimestamp;
573 
574     let fd = socket(
575         AddressFamily::Inet6,
576         SockType::Datagram,
577         SockFlag::empty(),
578         None,
579     )
580     .unwrap();
581 
582     // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
583     setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
584 
585     setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_REALTIME)
586         .unwrap();
587     assert_eq!(
588         getsockopt(&fd, sockopt::TsClock).unwrap(),
589         SocketTimestamp::SO_TS_REALTIME
590     );
591 }
592 
593 #[test]
594 #[cfg(target_os = "freebsd")]
test_ts_clock_monotonic()595 fn test_ts_clock_monotonic() {
596     use nix::sys::socket::SocketTimestamp;
597 
598     let fd = socket(
599         AddressFamily::Inet6,
600         SockType::Datagram,
601         SockFlag::empty(),
602         None,
603     )
604     .unwrap();
605 
606     // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
607     setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
608 
609     setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_MONOTONIC)
610         .unwrap();
611     assert_eq!(
612         getsockopt(&fd, sockopt::TsClock).unwrap(),
613         SocketTimestamp::SO_TS_MONOTONIC
614     );
615 }
616 
617 #[test]
618 #[cfg(linux_android)]
619 // Disable the test under emulation because it fails with ENOPROTOOPT in CI
620 // on cross target. Lack of QEMU support is suspected.
621 #[cfg_attr(qemu, ignore)]
test_ip_bind_address_no_port()622 fn test_ip_bind_address_no_port() {
623     let fd = socket(
624         AddressFamily::Inet,
625         SockType::Stream,
626         SockFlag::empty(),
627         SockProtocol::Tcp,
628     )
629     .unwrap();
630     setsockopt(&fd, sockopt::IpBindAddressNoPort, &true).expect(
631         "setting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
632     );
633     assert!(getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
634         "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
635     ));
636     setsockopt(&fd, sockopt::IpBindAddressNoPort, &false).expect(
637         "unsetting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
638     );
639     assert!(!getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
640         "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
641     ));
642 }
643 
644 #[test]
645 #[cfg(linux_android)]
test_tcp_fast_open_connect()646 fn test_tcp_fast_open_connect() {
647     let fd = socket(
648         AddressFamily::Inet,
649         SockType::Stream,
650         SockFlag::empty(),
651         SockProtocol::Tcp,
652     )
653     .unwrap();
654     setsockopt(&fd, sockopt::TcpFastOpenConnect, &true).expect(
655         "setting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
656     );
657     assert!(getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
658         "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
659     ));
660     setsockopt(&fd, sockopt::TcpFastOpenConnect, &false).expect(
661         "unsetting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
662     );
663     assert!(!getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
664         "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
665     ));
666 }
667 
668 #[cfg(linux_android)]
669 #[test]
can_get_peercred_on_unix_socket()670 fn can_get_peercred_on_unix_socket() {
671     use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
672 
673     let (a, b) = socketpair(
674         AddressFamily::Unix,
675         SockType::Stream,
676         None,
677         SockFlag::empty(),
678     )
679     .unwrap();
680     let a_cred = getsockopt(&a, sockopt::PeerCredentials).unwrap();
681     let b_cred = getsockopt(&b, sockopt::PeerCredentials).unwrap();
682     assert_eq!(a_cred, b_cred);
683     assert_ne!(a_cred.pid(), 0);
684 }
685 
686 #[test]
is_socket_type_unix()687 fn is_socket_type_unix() {
688     use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
689 
690     let (a, _b) = socketpair(
691         AddressFamily::Unix,
692         SockType::Stream,
693         None,
694         SockFlag::empty(),
695     )
696     .unwrap();
697     let a_type = getsockopt(&a, sockopt::SockType).unwrap();
698     assert_eq!(a_type, SockType::Stream);
699 }
700 
701 #[test]
is_socket_type_dgram()702 fn is_socket_type_dgram() {
703     use nix::sys::socket::{
704         getsockopt, sockopt, AddressFamily, SockFlag, SockType,
705     };
706 
707     let s = socket(
708         AddressFamily::Inet,
709         SockType::Datagram,
710         SockFlag::empty(),
711         None,
712     )
713     .unwrap();
714     let s_type = getsockopt(&s, sockopt::SockType).unwrap();
715     assert_eq!(s_type, SockType::Datagram);
716 }
717 
718 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
719 #[test]
can_get_listen_on_tcp_socket()720 fn can_get_listen_on_tcp_socket() {
721     use nix::sys::socket::{
722         getsockopt, listen, socket, sockopt, AddressFamily, Backlog, SockFlag,
723         SockType,
724     };
725 
726     let s = socket(
727         AddressFamily::Inet,
728         SockType::Stream,
729         SockFlag::empty(),
730         None,
731     )
732     .unwrap();
733     let s_listening = getsockopt(&s, sockopt::AcceptConn).unwrap();
734     assert!(!s_listening);
735     listen(&s, Backlog::new(10).unwrap()).unwrap();
736     let s_listening2 = getsockopt(&s, sockopt::AcceptConn).unwrap();
737     assert!(s_listening2);
738 }
739 
740 #[cfg(target_os = "linux")]
741 // Some architectures running under cross don't support `setsockopt(SOL_TCP, TCP_ULP)`
742 // because the cross image is based on Ubuntu 16.04 which predates TCP ULP support
743 // (it was added in kernel v4.13 released in 2017). For these architectures,
744 // the `setsockopt(SOL_TCP, TCP_ULP, "tls", sizeof("tls"))` call succeeds
745 // but the subsequent `setsockopt(SOL_TLS, TLS_TX, ...)` call fails with `ENOPROTOOPT`.
746 // It's as if the first `setsockopt` call enabled some other option, not `TCP_ULP`.
747 // For example, `strace` says:
748 //
749 //     [pid   813] setsockopt(4, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0
750 //
751 // It's not clear why `setsockopt(SOL_TCP, TCP_ULP)` succeeds if the container image libc doesn't support it,
752 // but in any case we can't run the test on such an architecture, so skip it.
753 #[cfg_attr(qemu, ignore)]
754 #[test]
test_ktls()755 fn test_ktls() {
756     use nix::sys::socket::{
757         accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
758     };
759     use std::net::SocketAddrV4;
760     use std::str::FromStr;
761 
762     let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
763     let mut sock_addr = SockaddrIn::from(std_sa);
764 
765     let rsock = socket(
766         AddressFamily::Inet,
767         SockType::Stream,
768         SockFlag::empty(),
769         SockProtocol::Tcp,
770     )
771     .unwrap();
772     bind(rsock.as_raw_fd(), &sock_addr).unwrap();
773     sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
774     listen(&rsock, Backlog::new(10).unwrap()).unwrap();
775 
776     let ssock = socket(
777         AddressFamily::Inet,
778         SockType::Stream,
779         SockFlag::empty(),
780         SockProtocol::Tcp,
781     )
782     .unwrap();
783     connect(ssock.as_raw_fd(), &sock_addr).unwrap();
784 
785     let _rsess = accept(rsock.as_raw_fd()).unwrap();
786 
787     match setsockopt(&ssock, sockopt::TcpUlp::default(), b"tls") {
788         Ok(()) => (),
789 
790         // TLS ULP is not enabled, so we can't test kTLS.
791         Err(nix::Error::ENOENT) => skip!("TLS ULP is not enabled"),
792 
793         Err(err) => panic!("{err:?}"),
794     }
795 
796     // In real life we would do a TLS handshake and extract the protocol version and secrets.
797     // For this test we just make some up.
798 
799     let tx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
800         info: libc::tls_crypto_info {
801             version: libc::TLS_1_2_VERSION,
802             cipher_type: libc::TLS_CIPHER_AES_GCM_128,
803         },
804         iv: *b"\x04\x05\x06\x07\x08\x09\x0a\x0b",
805         key: *b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
806         salt: *b"\x00\x01\x02\x03",
807         rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
808     });
809     setsockopt(&ssock, sockopt::TcpTlsTx, &tx)
810         .expect("setting TLS_TX after enabling TLS ULP should succeed");
811 
812     let rx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
813         info: libc::tls_crypto_info {
814             version: libc::TLS_1_2_VERSION,
815             cipher_type: libc::TLS_CIPHER_AES_GCM_128,
816         },
817         iv: *b"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb",
818         key: *b"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
819         salt: *b"\xf0\xf1\xf2\xf3",
820         rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
821     });
822     match setsockopt(&ssock, sockopt::TcpTlsRx, &rx) {
823         Ok(()) => (),
824         Err(nix::Error::ENOPROTOOPT) => {
825             // TLS_TX was added in v4.13 and TLS_RX in v4.17, so we appear to be between that range.
826             // It's good enough that TLS_TX worked, so let the test succeed.
827         }
828         Err(err) => panic!("{err:?}"),
829     }
830 }
831