• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[cfg(any(target_os = "android", target_os = "linux"))]
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 
9 // NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
10 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",))]
11 #[test]
test_local_peercred_seqpacket()12 pub fn test_local_peercred_seqpacket() {
13     use nix::{
14         sys::socket::socketpair,
15         unistd::{Gid, Uid},
16     };
17 
18     let (fd1, _fd2) = socketpair(
19         AddressFamily::Unix,
20         SockType::SeqPacket,
21         None,
22         SockFlag::empty(),
23     )
24     .unwrap();
25     let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
26     assert_eq!(xucred.version(), 0);
27     assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
28     assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
29 }
30 
31 #[cfg(any(
32     target_os = "dragonfly",
33     target_os = "freebsd",
34     target_os = "macos",
35     target_os = "ios"
36 ))]
37 #[test]
test_local_peercred_stream()38 pub fn test_local_peercred_stream() {
39     use nix::{
40         sys::socket::socketpair,
41         unistd::{Gid, Uid},
42     };
43 
44     let (fd1, _fd2) = socketpair(
45         AddressFamily::Unix,
46         SockType::Stream,
47         None,
48         SockFlag::empty(),
49     )
50     .unwrap();
51     let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
52     assert_eq!(xucred.version(), 0);
53     assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
54     assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
55 }
56 
57 #[cfg(target_os = "linux")]
58 #[test]
is_so_mark_functional()59 fn is_so_mark_functional() {
60     use nix::sys::socket::sockopt;
61 
62     require_capability!("is_so_mark_functional", CAP_NET_ADMIN);
63 
64     let s = socket(
65         AddressFamily::Inet,
66         SockType::Stream,
67         SockFlag::empty(),
68         None,
69     )
70     .unwrap();
71     setsockopt(s, sockopt::Mark, &1337).unwrap();
72     let mark = getsockopt(s, sockopt::Mark).unwrap();
73     assert_eq!(mark, 1337);
74 }
75 
76 #[test]
test_so_buf()77 fn test_so_buf() {
78     let fd = socket(
79         AddressFamily::Inet,
80         SockType::Datagram,
81         SockFlag::empty(),
82         SockProtocol::Udp,
83     )
84     .unwrap();
85     let bufsize: usize = thread_rng().gen_range(4096..131_072);
86     setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap();
87     let actual = getsockopt(fd, sockopt::SndBuf).unwrap();
88     assert!(actual >= bufsize);
89     setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap();
90     let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
91     assert!(actual >= bufsize);
92 }
93 
94 #[test]
test_so_tcp_maxseg()95 fn test_so_tcp_maxseg() {
96     use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn};
97     use nix::unistd::{close, write};
98     use std::net::SocketAddrV4;
99     use std::str::FromStr;
100 
101     let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
102     let sock_addr = SockaddrIn::from(std_sa);
103 
104     let rsock = socket(
105         AddressFamily::Inet,
106         SockType::Stream,
107         SockFlag::empty(),
108         SockProtocol::Tcp,
109     )
110     .unwrap();
111     bind(rsock, &sock_addr).unwrap();
112     listen(rsock, 10).unwrap();
113     let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap();
114     // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
115     // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
116     // than 700
117     cfg_if! {
118         if #[cfg(any(target_os = "android", target_os = "linux"))] {
119             let segsize: u32 = 873;
120             assert!(initial < segsize);
121             setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
122         } else {
123             assert!(initial < 700);
124         }
125     }
126 
127     // Connect and check the MSS that was advertised
128     let ssock = socket(
129         AddressFamily::Inet,
130         SockType::Stream,
131         SockFlag::empty(),
132         SockProtocol::Tcp,
133     )
134     .unwrap();
135     connect(ssock, &sock_addr).unwrap();
136     let rsess = accept(rsock).unwrap();
137     write(rsess, b"hello").unwrap();
138     let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap();
139     // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
140     // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
141     cfg_if! {
142         if #[cfg(any(target_os = "android", target_os = "linux"))] {
143             assert!((segsize - 100) <= actual);
144             assert!(actual <= segsize);
145         } else {
146             assert!(initial < actual);
147             assert!(536 < actual);
148         }
149     }
150     close(rsock).unwrap();
151     close(ssock).unwrap();
152 }
153 
154 #[test]
test_so_type()155 fn test_so_type() {
156     let sockfd = socket(
157         AddressFamily::Inet,
158         SockType::Stream,
159         SockFlag::empty(),
160         None,
161     )
162     .unwrap();
163 
164     assert_eq!(Ok(SockType::Stream), getsockopt(sockfd, sockopt::SockType));
165 }
166 
167 /// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket
168 /// types.  Regression test for https://github.com/nix-rust/nix/issues/1819
169 #[cfg(any(target_os = "android", target_os = "linux",))]
170 #[test]
test_so_type_unknown()171 fn test_so_type_unknown() {
172     use nix::errno::Errno;
173 
174     require_capability!("test_so_type", CAP_NET_RAW);
175     let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
176     assert!(sockfd >= 0, "Error opening socket: {}", nix::Error::last());
177 
178     assert_eq!(Err(Errno::EINVAL), getsockopt(sockfd, sockopt::SockType));
179 }
180 
181 // The CI doesn't supported getsockopt and setsockopt on emulated processors.
182 // It's believed that a QEMU issue, the tests run ok on a fully emulated system.
183 // Current CI just run the binary with QEMU but the Kernel remains the same as the host.
184 // So the syscall doesn't work properly unless the kernel is also emulated.
185 #[test]
186 #[cfg(all(
187     any(target_arch = "x86", target_arch = "x86_64"),
188     any(target_os = "freebsd", target_os = "linux")
189 ))]
test_tcp_congestion()190 fn test_tcp_congestion() {
191     use std::ffi::OsString;
192 
193     let fd = socket(
194         AddressFamily::Inet,
195         SockType::Stream,
196         SockFlag::empty(),
197         None,
198     )
199     .unwrap();
200 
201     let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
202     setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
203 
204     setsockopt(
205         fd,
206         sockopt::TcpCongestion,
207         &OsString::from("tcp_congestion_does_not_exist"),
208     )
209     .unwrap_err();
210 
211     assert_eq!(getsockopt(fd, sockopt::TcpCongestion).unwrap(), val);
212 }
213 
214 #[test]
215 #[cfg(any(target_os = "android", target_os = "linux"))]
test_bindtodevice()216 fn test_bindtodevice() {
217     skip_if_not_root!("test_bindtodevice");
218 
219     let fd = socket(
220         AddressFamily::Inet,
221         SockType::Stream,
222         SockFlag::empty(),
223         None,
224     )
225     .unwrap();
226 
227     let val = getsockopt(fd, sockopt::BindToDevice).unwrap();
228     setsockopt(fd, sockopt::BindToDevice, &val).unwrap();
229 
230     assert_eq!(getsockopt(fd, sockopt::BindToDevice).unwrap(), val);
231 }
232 
233 #[test]
test_so_tcp_keepalive()234 fn test_so_tcp_keepalive() {
235     let fd = socket(
236         AddressFamily::Inet,
237         SockType::Stream,
238         SockFlag::empty(),
239         SockProtocol::Tcp,
240     )
241     .unwrap();
242     setsockopt(fd, sockopt::KeepAlive, &true).unwrap();
243     assert!(getsockopt(fd, sockopt::KeepAlive).unwrap());
244 
245     #[cfg(any(
246         target_os = "android",
247         target_os = "dragonfly",
248         target_os = "freebsd",
249         target_os = "linux"
250     ))]
251     {
252         let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap();
253         setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
254         assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
255 
256         let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap();
257         setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
258         assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1);
259 
260         let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap();
261         setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
262         assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
263     }
264 }
265 
266 #[test]
267 #[cfg(any(target_os = "android", target_os = "linux"))]
268 #[cfg_attr(qemu, ignore)]
test_get_mtu()269 fn test_get_mtu() {
270     use nix::sys::socket::{bind, connect, SockaddrIn};
271     use std::net::SocketAddrV4;
272     use std::str::FromStr;
273 
274     let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
275     let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap();
276 
277     let usock = socket(
278         AddressFamily::Inet,
279         SockType::Datagram,
280         SockFlag::empty(),
281         SockProtocol::Udp,
282     )
283     .unwrap();
284 
285     // Bind and initiate connection
286     bind(usock, &SockaddrIn::from(std_sa)).unwrap();
287     connect(usock, &SockaddrIn::from(std_sb)).unwrap();
288 
289     // Loopback connections have 2^16 - the maximum - MTU
290     assert_eq!(getsockopt(usock, sockopt::IpMtu), Ok(u16::MAX as i32))
291 }
292 
293 #[test]
294 #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
test_ttl_opts()295 fn test_ttl_opts() {
296     let fd4 = socket(
297         AddressFamily::Inet,
298         SockType::Datagram,
299         SockFlag::empty(),
300         None,
301     )
302     .unwrap();
303     setsockopt(fd4, sockopt::Ipv4Ttl, &1)
304         .expect("setting ipv4ttl on an inet socket should succeed");
305     let fd6 = socket(
306         AddressFamily::Inet6,
307         SockType::Datagram,
308         SockFlag::empty(),
309         None,
310     )
311     .unwrap();
312     setsockopt(fd6, sockopt::Ipv6Ttl, &1)
313         .expect("setting ipv6ttl on an inet6 socket should succeed");
314 }
315 
316 #[test]
317 #[cfg(any(target_os = "ios", target_os = "macos"))]
test_dontfrag_opts()318 fn test_dontfrag_opts() {
319     let fd4 = socket(
320         AddressFamily::Inet,
321         SockType::Stream,
322         SockFlag::empty(),
323         SockProtocol::Tcp,
324     )
325     .unwrap();
326     setsockopt(fd4, sockopt::IpDontFrag, &true)
327         .expect("setting IP_DONTFRAG on an inet stream socket should succeed");
328     setsockopt(fd4, sockopt::IpDontFrag, &false).expect(
329         "unsetting IP_DONTFRAG on an inet stream socket should succeed",
330     );
331     let fd4d = socket(
332         AddressFamily::Inet,
333         SockType::Datagram,
334         SockFlag::empty(),
335         None,
336     )
337     .unwrap();
338     setsockopt(fd4d, sockopt::IpDontFrag, &true).expect(
339         "setting IP_DONTFRAG on an inet datagram socket should succeed",
340     );
341     setsockopt(fd4d, sockopt::IpDontFrag, &false).expect(
342         "unsetting IP_DONTFRAG on an inet datagram socket should succeed",
343     );
344 }
345 
346 #[test]
347 #[cfg(any(
348     target_os = "android",
349     target_os = "ios",
350     target_os = "linux",
351     target_os = "macos",
352 ))]
353 // Disable the test under emulation because it fails in Cirrus-CI.  Lack
354 // of QEMU support is suspected.
355 #[cfg_attr(qemu, ignore)]
test_v6dontfrag_opts()356 fn test_v6dontfrag_opts() {
357     let fd6 = socket(
358         AddressFamily::Inet6,
359         SockType::Stream,
360         SockFlag::empty(),
361         SockProtocol::Tcp,
362     )
363     .unwrap();
364     setsockopt(fd6, sockopt::Ipv6DontFrag, &true).expect(
365         "setting IPV6_DONTFRAG on an inet6 stream socket should succeed",
366     );
367     setsockopt(fd6, sockopt::Ipv6DontFrag, &false).expect(
368         "unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed",
369     );
370     let fd6d = socket(
371         AddressFamily::Inet6,
372         SockType::Datagram,
373         SockFlag::empty(),
374         None,
375     )
376     .unwrap();
377     setsockopt(fd6d, sockopt::Ipv6DontFrag, &true).expect(
378         "setting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
379     );
380     setsockopt(fd6d, sockopt::Ipv6DontFrag, &false).expect(
381         "unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
382     );
383 }
384 
385 #[test]
386 #[cfg(target_os = "linux")]
test_so_priority()387 fn test_so_priority() {
388     let fd = socket(
389         AddressFamily::Inet,
390         SockType::Stream,
391         SockFlag::empty(),
392         SockProtocol::Tcp,
393     )
394     .unwrap();
395     let priority = 3;
396     setsockopt(fd, sockopt::Priority, &priority).unwrap();
397     assert_eq!(getsockopt(fd, sockopt::Priority).unwrap(), priority);
398 }
399 
400 #[test]
401 #[cfg(target_os = "linux")]
test_ip_tos()402 fn test_ip_tos() {
403     let fd = socket(
404         AddressFamily::Inet,
405         SockType::Stream,
406         SockFlag::empty(),
407         SockProtocol::Tcp,
408     )
409     .unwrap();
410     let tos = 0x80; // CS4
411     setsockopt(fd, sockopt::IpTos, &tos).unwrap();
412     assert_eq!(getsockopt(fd, sockopt::IpTos).unwrap(), tos);
413 }
414 
415 #[test]
416 #[cfg(target_os = "linux")]
417 // Disable the test under emulation because it fails in Cirrus-CI.  Lack
418 // of QEMU support is suspected.
419 #[cfg_attr(qemu, ignore)]
test_ipv6_tclass()420 fn test_ipv6_tclass() {
421     let fd = socket(
422         AddressFamily::Inet6,
423         SockType::Stream,
424         SockFlag::empty(),
425         SockProtocol::Tcp,
426     )
427     .unwrap();
428     let class = 0x80; // CS4
429     setsockopt(fd, sockopt::Ipv6TClass, &class).unwrap();
430     assert_eq!(getsockopt(fd, sockopt::Ipv6TClass).unwrap(), class);
431 }
432