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