1 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
2 | use crate::*; |
3 | use libc::c_char; |
4 | use nix::sys::socket::{getsockname, AddressFamily, UnixAddr}; |
5 | use std::collections::hash_map::DefaultHasher; |
6 | use std::hash::{Hash, Hasher}; |
7 | use std::net::{SocketAddrV4, SocketAddrV6}; |
8 | use std::os::unix::io::{AsRawFd, RawFd}; |
9 | use std::path::Path; |
10 | use std::slice; |
11 | use std::str::FromStr; |
12 | |
13 | #[cfg (target_os = "linux" )] |
14 | #[cfg_attr (qemu, ignore)] |
15 | #[test] |
16 | pub fn test_timestamping() { |
17 | use nix::sys::socket::{ |
18 | recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, |
19 | ControlMessageOwned, MsgFlags, SockFlag, SockType, SockaddrIn, |
20 | TimestampingFlag, |
21 | }; |
22 | use std::io::{IoSlice, IoSliceMut}; |
23 | |
24 | let sock_addr = SockaddrIn::from_str("127.0.0.1:6790" ).unwrap(); |
25 | |
26 | let ssock = socket( |
27 | AddressFamily::Inet, |
28 | SockType::Datagram, |
29 | SockFlag::empty(), |
30 | None, |
31 | ) |
32 | .expect("send socket failed" ); |
33 | |
34 | let rsock = socket( |
35 | AddressFamily::Inet, |
36 | SockType::Datagram, |
37 | SockFlag::empty(), |
38 | None, |
39 | ) |
40 | .unwrap(); |
41 | nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap(); |
42 | |
43 | setsockopt(&rsock, Timestamping, &TimestampingFlag::all()).unwrap(); |
44 | |
45 | let sbuf = [0u8; 2048]; |
46 | let mut rbuf = [0u8; 2048]; |
47 | let flags = MsgFlags::empty(); |
48 | let iov1 = [IoSlice::new(&sbuf)]; |
49 | let mut iov2 = [IoSliceMut::new(&mut rbuf)]; |
50 | |
51 | let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); |
52 | sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); |
53 | let recv = |
54 | recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags) |
55 | .unwrap(); |
56 | |
57 | let mut ts = None; |
58 | for c in recv.cmsgs() { |
59 | if let ControlMessageOwned::ScmTimestampsns(timestamps) = c { |
60 | ts = Some(timestamps.system); |
61 | } |
62 | } |
63 | let ts = ts.expect("ScmTimestampns is present" ); |
64 | let sys_time = |
65 | ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME) |
66 | .unwrap(); |
67 | let diff = if ts > sys_time { |
68 | ts - sys_time |
69 | } else { |
70 | sys_time - ts |
71 | }; |
72 | assert!(std::time::Duration::from(diff).as_secs() < 60); |
73 | } |
74 | |
75 | #[test] |
76 | pub fn test_path_to_sock_addr() { |
77 | let path = "/foo/bar" ; |
78 | let actual = Path::new(path); |
79 | let addr = UnixAddr::new(actual).unwrap(); |
80 | |
81 | let expect: &[c_char] = unsafe { |
82 | slice::from_raw_parts(path.as_ptr() as *const c_char, path.len()) |
83 | }; |
84 | assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect); |
85 | |
86 | assert_eq!(addr.path(), Some(actual)); |
87 | } |
88 | |
89 | fn calculate_hash<T: Hash>(t: &T) -> u64 { |
90 | let mut s = DefaultHasher::new(); |
91 | t.hash(&mut s); |
92 | s.finish() |
93 | } |
94 | |
95 | #[test] |
96 | pub fn test_addr_equality_path() { |
97 | let path = "/foo/bar" ; |
98 | let actual = Path::new(path); |
99 | let addr1 = UnixAddr::new(actual).unwrap(); |
100 | let mut addr2 = addr1; |
101 | |
102 | unsafe { (*addr2.as_mut_ptr()).sun_path[10] = 127 }; |
103 | |
104 | assert_eq!(addr1, addr2); |
105 | assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); |
106 | } |
107 | |
108 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
109 | #[test] |
110 | pub fn test_abstract_sun_path_too_long() { |
111 | let name = String::from("nix \0abstract \0tesnix \0abstract \0tesnix \0abstract \0tesnix \0abstract \0tesnix \0abstract \0testttttnix \0abstract \0test \0make \0sure \0this \0is \0long \0enough" ); |
112 | let addr = UnixAddr::new_abstract(name.as_bytes()); |
113 | addr.expect_err("assertion failed" ); |
114 | } |
115 | |
116 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
117 | #[test] |
118 | pub fn test_addr_equality_abstract() { |
119 | let name = String::from("nix \0abstract \0test" ); |
120 | let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap(); |
121 | let mut addr2 = addr1; |
122 | |
123 | assert_eq!(addr1, addr2); |
124 | assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); |
125 | |
126 | unsafe { (*addr2.as_mut_ptr()).sun_path[17] = 127 }; |
127 | assert_ne!(addr1, addr2); |
128 | assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2)); |
129 | } |
130 | |
131 | // Test getting/setting abstract addresses (without unix socket creation) |
132 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
133 | #[test] |
134 | pub fn test_abstract_uds_addr() { |
135 | let empty = String::new(); |
136 | let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); |
137 | let sun_path: [u8; 0] = []; |
138 | assert_eq!(addr.as_abstract(), Some(&sun_path[..])); |
139 | |
140 | let name = String::from("nix \0abstract \0test" ); |
141 | let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); |
142 | let sun_path = [ |
143 | 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, |
144 | 115, 116, |
145 | ]; |
146 | assert_eq!(addr.as_abstract(), Some(&sun_path[..])); |
147 | assert_eq!(addr.path(), None); |
148 | |
149 | // Internally, name is null-prefixed (abstract namespace) |
150 | assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0); |
151 | } |
152 | |
153 | // Test getting an unnamed address (without unix socket creation) |
154 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
155 | #[test] |
156 | pub fn test_unnamed_uds_addr() { |
157 | use crate::nix::sys::socket::SockaddrLike; |
158 | |
159 | let addr = UnixAddr::new_unnamed(); |
160 | |
161 | assert!(addr.is_unnamed()); |
162 | assert_eq!(addr.len(), 2); |
163 | assert!(addr.path().is_none()); |
164 | assert_eq!(addr.path_len(), 0); |
165 | |
166 | assert!(addr.as_abstract().is_none()); |
167 | } |
168 | |
169 | #[test] |
170 | pub fn test_getsockname() { |
171 | use nix::sys::socket::bind; |
172 | use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType}; |
173 | |
174 | let tempdir = tempfile::tempdir().unwrap(); |
175 | let sockname = tempdir.path().join("sock" ); |
176 | let sock = socket( |
177 | AddressFamily::Unix, |
178 | SockType::Stream, |
179 | SockFlag::empty(), |
180 | None, |
181 | ) |
182 | .expect("socket failed" ); |
183 | let sockaddr = UnixAddr::new(&sockname).unwrap(); |
184 | bind(sock.as_raw_fd(), &sockaddr).expect("bind failed" ); |
185 | assert_eq!( |
186 | sockaddr, |
187 | getsockname(sock.as_raw_fd()).expect("getsockname failed" ) |
188 | ); |
189 | } |
190 | |
191 | #[test] |
192 | pub fn test_socketpair() { |
193 | use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType}; |
194 | use nix::unistd::{read, write}; |
195 | |
196 | let (fd1, fd2) = socketpair( |
197 | AddressFamily::Unix, |
198 | SockType::Stream, |
199 | None, |
200 | SockFlag::empty(), |
201 | ) |
202 | .unwrap(); |
203 | write(fd1.as_raw_fd(), b"hello" ).unwrap(); |
204 | let mut buf = [0; 5]; |
205 | read(fd2.as_raw_fd(), &mut buf).unwrap(); |
206 | |
207 | assert_eq!(&buf[..], b"hello" ); |
208 | } |
209 | |
210 | #[test] |
211 | pub fn test_recvmsg_sockaddr_un() { |
212 | use nix::sys::socket::{ |
213 | self, bind, socket, AddressFamily, MsgFlags, SockFlag, SockType, |
214 | }; |
215 | |
216 | let tempdir = tempfile::tempdir().unwrap(); |
217 | let sockname = tempdir.path().join("sock" ); |
218 | let sock = socket( |
219 | AddressFamily::Unix, |
220 | SockType::Datagram, |
221 | SockFlag::empty(), |
222 | None, |
223 | ) |
224 | .expect("socket failed" ); |
225 | let sockaddr = UnixAddr::new(&sockname).unwrap(); |
226 | bind(sock.as_raw_fd(), &sockaddr).expect("bind failed" ); |
227 | |
228 | // Send a message |
229 | let send_buffer = "hello" .as_bytes(); |
230 | if let Err(e) = socket::sendmsg( |
231 | sock.as_raw_fd(), |
232 | &[std::io::IoSlice::new(send_buffer)], |
233 | &[], |
234 | MsgFlags::empty(), |
235 | Some(&sockaddr), |
236 | ) { |
237 | crate::skip!("Couldn't send ({e:?}), so skipping test" ); |
238 | } |
239 | |
240 | // Receive the message |
241 | let mut recv_buffer = [0u8; 32]; |
242 | let mut iov = [std::io::IoSliceMut::new(&mut recv_buffer)]; |
243 | let received = |
244 | socket::recvmsg(sock.as_raw_fd(), &mut iov, None, MsgFlags::empty()) |
245 | .unwrap(); |
246 | // Check the address in the received message |
247 | assert_eq!(sockaddr, received.address.unwrap()); |
248 | } |
249 | |
250 | #[test] |
251 | pub fn test_std_conversions() { |
252 | use nix::sys::socket::*; |
253 | |
254 | let std_sa = SocketAddrV4::from_str("127.0.0.1:6789" ).unwrap(); |
255 | let sock_addr = SockaddrIn::from(std_sa); |
256 | assert_eq!(std_sa, sock_addr.into()); |
257 | |
258 | let std_sa = SocketAddrV6::from_str("[::1]:6000" ).unwrap(); |
259 | let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); |
260 | assert_eq!(std_sa, sock_addr.into()); |
261 | } |
262 | |
263 | mod recvfrom { |
264 | use super::*; |
265 | use nix::sys::socket::*; |
266 | use nix::{errno::Errno, Result}; |
267 | use std::thread; |
268 | |
269 | const MSG: &[u8] = b"Hello, World!" ; |
270 | |
271 | fn sendrecv<Fs, Fr>( |
272 | rsock: RawFd, |
273 | ssock: RawFd, |
274 | f_send: Fs, |
275 | mut f_recv: Fr, |
276 | ) -> Option<SockaddrStorage> |
277 | where |
278 | Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static, |
279 | Fr: FnMut(usize, Option<SockaddrStorage>), |
280 | { |
281 | let mut buf: [u8; 13] = [0u8; 13]; |
282 | let mut l = 0; |
283 | let mut from = None; |
284 | |
285 | let send_thread = thread::spawn(move || { |
286 | let mut l = 0; |
287 | while l < std::mem::size_of_val(MSG) { |
288 | l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap(); |
289 | } |
290 | }); |
291 | |
292 | while l < std::mem::size_of_val(MSG) { |
293 | let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap(); |
294 | f_recv(len, from_); |
295 | from = from_; |
296 | l += len; |
297 | } |
298 | assert_eq!(&buf, MSG); |
299 | send_thread.join().unwrap(); |
300 | from |
301 | } |
302 | |
303 | #[test] |
304 | pub fn stream() { |
305 | let (fd2, fd1) = socketpair( |
306 | AddressFamily::Unix, |
307 | SockType::Stream, |
308 | None, |
309 | SockFlag::empty(), |
310 | ) |
311 | .unwrap(); |
312 | // Ignore from for stream sockets |
313 | let _ = sendrecv(fd1.as_raw_fd(), fd2.as_raw_fd(), send, |_, _| {}); |
314 | } |
315 | |
316 | #[test] |
317 | pub fn udp() { |
318 | let std_sa = SocketAddrV4::from_str("127.0.0.1:6789" ).unwrap(); |
319 | let sock_addr = SockaddrIn::from(std_sa); |
320 | let rsock = socket( |
321 | AddressFamily::Inet, |
322 | SockType::Datagram, |
323 | SockFlag::empty(), |
324 | None, |
325 | ) |
326 | .unwrap(); |
327 | bind(rsock.as_raw_fd(), &sock_addr).unwrap(); |
328 | let ssock = socket( |
329 | AddressFamily::Inet, |
330 | SockType::Datagram, |
331 | SockFlag::empty(), |
332 | None, |
333 | ) |
334 | .expect("send socket failed" ); |
335 | let from = sendrecv( |
336 | rsock.as_raw_fd(), |
337 | ssock.as_raw_fd(), |
338 | move |s, m, flags| sendto(s.as_raw_fd(), m, &sock_addr, flags), |
339 | |_, _| {}, |
340 | ); |
341 | // UDP sockets should set the from address |
342 | assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); |
343 | } |
344 | |
345 | #[cfg (target_os = "linux" )] |
346 | mod udp_offload { |
347 | use super::*; |
348 | use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment}; |
349 | use std::io::IoSlice; |
350 | |
351 | #[test] |
352 | // Disable the test under emulation because it fails in Cirrus-CI. Lack |
353 | // of QEMU support is suspected. |
354 | #[cfg_attr (qemu, ignore)] |
355 | pub fn gso() { |
356 | require_kernel_version!(udp_offload::gso, ">= 4.18" ); |
357 | |
358 | // In this test, we send the data and provide a GSO segment size. |
359 | // Since we are sending the buffer of size 13, six UDP packets |
360 | // with size 2 and two UDP packet with size 1 will be sent. |
361 | let segment_size: u16 = 2; |
362 | |
363 | let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791); |
364 | let rsock = socket( |
365 | AddressFamily::Inet, |
366 | SockType::Datagram, |
367 | SockFlag::empty(), |
368 | None, |
369 | ) |
370 | .unwrap(); |
371 | |
372 | setsockopt(&rsock, UdpGsoSegment, &(segment_size as _)) |
373 | .expect("setsockopt UDP_SEGMENT failed" ); |
374 | |
375 | bind(rsock.as_raw_fd(), &sock_addr).unwrap(); |
376 | let ssock = socket( |
377 | AddressFamily::Inet, |
378 | SockType::Datagram, |
379 | SockFlag::empty(), |
380 | None, |
381 | ) |
382 | .expect("send socket failed" ); |
383 | |
384 | let mut num_packets_received: i32 = 0; |
385 | |
386 | sendrecv( |
387 | rsock.as_raw_fd(), |
388 | ssock.as_raw_fd(), |
389 | move |s, m, flags| { |
390 | let iov = [IoSlice::new(m)]; |
391 | let cmsg = ControlMessage::UdpGsoSegments(&segment_size); |
392 | sendmsg( |
393 | s.as_raw_fd(), |
394 | &iov, |
395 | &[cmsg], |
396 | flags, |
397 | Some(&sock_addr), |
398 | ) |
399 | }, |
400 | { |
401 | let num_packets_received_ref = &mut num_packets_received; |
402 | |
403 | move |len, _| { |
404 | // check that we receive UDP packets with payload size |
405 | // less or equal to segment size |
406 | assert!(len <= segment_size as usize); |
407 | *num_packets_received_ref += 1; |
408 | } |
409 | }, |
410 | ); |
411 | |
412 | // Buffer size is 13, we will receive six packets of size 2, |
413 | // and one packet of size 1. |
414 | assert_eq!(7, num_packets_received); |
415 | } |
416 | |
417 | #[test] |
418 | // Disable the test on emulated platforms because it fails in Cirrus-CI. |
419 | // Lack of QEMU support is suspected. |
420 | #[cfg_attr (qemu, ignore)] |
421 | pub fn gro() { |
422 | require_kernel_version!(udp_offload::gro, ">= 5.3" ); |
423 | |
424 | // It's hard to guarantee receiving GRO packets. Just checking |
425 | // that `setsockopt` doesn't fail with error |
426 | |
427 | let rsock = socket( |
428 | AddressFamily::Inet, |
429 | SockType::Datagram, |
430 | SockFlag::empty(), |
431 | None, |
432 | ) |
433 | .unwrap(); |
434 | |
435 | setsockopt(&rsock, UdpGroSegment, &true) |
436 | .expect("setsockopt UDP_GRO failed" ); |
437 | } |
438 | } |
439 | |
440 | #[cfg (any( |
441 | target_os = "linux" , |
442 | target_os = "android" , |
443 | target_os = "freebsd" , |
444 | target_os = "netbsd" , |
445 | ))] |
446 | #[test] |
447 | pub fn udp_sendmmsg() { |
448 | use std::io::IoSlice; |
449 | |
450 | let std_sa = SocketAddrV4::from_str("127.0.0.1:6793" ).unwrap(); |
451 | let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794" ).unwrap(); |
452 | let sock_addr = SockaddrIn::from(std_sa); |
453 | let sock_addr2 = SockaddrIn::from(std_sa2); |
454 | |
455 | let rsock = socket( |
456 | AddressFamily::Inet, |
457 | SockType::Datagram, |
458 | SockFlag::empty(), |
459 | None, |
460 | ) |
461 | .unwrap(); |
462 | bind(rsock.as_raw_fd(), &sock_addr).unwrap(); |
463 | let ssock = socket( |
464 | AddressFamily::Inet, |
465 | SockType::Datagram, |
466 | SockFlag::empty(), |
467 | None, |
468 | ) |
469 | .expect("send socket failed" ); |
470 | |
471 | let from = sendrecv( |
472 | rsock.as_raw_fd(), |
473 | ssock.as_raw_fd(), |
474 | move |s, m, flags| { |
475 | let batch_size = 15; |
476 | let mut iovs = Vec::with_capacity(1 + batch_size); |
477 | let mut addrs = Vec::with_capacity(1 + batch_size); |
478 | let mut data = MultiHeaders::preallocate(1 + batch_size, None); |
479 | let iov = IoSlice::new(m); |
480 | // first chunk: |
481 | iovs.push([iov]); |
482 | addrs.push(Some(sock_addr)); |
483 | |
484 | for _ in 0..batch_size { |
485 | iovs.push([iov]); |
486 | addrs.push(Some(sock_addr2)); |
487 | } |
488 | |
489 | let res = sendmmsg(s, &mut data, &iovs, addrs, [], flags)?; |
490 | let mut sent_messages = 0; |
491 | let mut sent_bytes = 0; |
492 | for item in res { |
493 | sent_messages += 1; |
494 | sent_bytes += item.bytes; |
495 | } |
496 | // |
497 | assert_eq!(sent_messages, iovs.len()); |
498 | assert_eq!(sent_bytes, sent_messages * m.len()); |
499 | Ok(sent_messages) |
500 | }, |
501 | |_, _| {}, |
502 | ); |
503 | // UDP sockets should set the from address |
504 | assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); |
505 | } |
506 | |
507 | #[cfg (any( |
508 | target_os = "linux" , |
509 | target_os = "android" , |
510 | target_os = "freebsd" , |
511 | target_os = "netbsd" , |
512 | ))] |
513 | #[test] |
514 | pub fn udp_recvmmsg() { |
515 | use nix::sys::socket::{recvmmsg, MsgFlags}; |
516 | use std::io::IoSliceMut; |
517 | |
518 | const NUM_MESSAGES_SENT: usize = 2; |
519 | const DATA: [u8; 2] = [1, 2]; |
520 | |
521 | let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798" ).unwrap(); |
522 | let sock_addr = SockaddrIn::from(inet_addr); |
523 | |
524 | let rsock = socket( |
525 | AddressFamily::Inet, |
526 | SockType::Datagram, |
527 | SockFlag::empty(), |
528 | None, |
529 | ) |
530 | .unwrap(); |
531 | bind(rsock.as_raw_fd(), &sock_addr).unwrap(); |
532 | let ssock = socket( |
533 | AddressFamily::Inet, |
534 | SockType::Datagram, |
535 | SockFlag::empty(), |
536 | None, |
537 | ) |
538 | .expect("send socket failed" ); |
539 | |
540 | let send_thread = thread::spawn(move || { |
541 | for _ in 0..NUM_MESSAGES_SENT { |
542 | sendto( |
543 | ssock.as_raw_fd(), |
544 | &DATA[..], |
545 | &sock_addr, |
546 | MsgFlags::empty(), |
547 | ) |
548 | .unwrap(); |
549 | } |
550 | }); |
551 | |
552 | let mut msgs = std::collections::LinkedList::new(); |
553 | |
554 | // Buffers to receive exactly `NUM_MESSAGES_SENT` messages |
555 | let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT]; |
556 | msgs.extend( |
557 | receive_buffers |
558 | .iter_mut() |
559 | .map(|buf| [IoSliceMut::new(&mut buf[..])]), |
560 | ); |
561 | |
562 | let mut data = |
563 | MultiHeaders::<SockaddrIn>::preallocate(msgs.len(), None); |
564 | |
565 | let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg( |
566 | rsock.as_raw_fd(), |
567 | &mut data, |
568 | msgs.iter(), |
569 | MsgFlags::empty(), |
570 | None, |
571 | ) |
572 | .expect("recvmmsg" ) |
573 | .collect(); |
574 | assert_eq!(res.len(), DATA.len()); |
575 | |
576 | for RecvMsg { address, bytes, .. } in res.into_iter() { |
577 | assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); |
578 | assert_eq!(DATA.len(), bytes); |
579 | } |
580 | |
581 | for buf in &receive_buffers { |
582 | assert_eq!(&buf[..DATA.len()], DATA); |
583 | } |
584 | |
585 | send_thread.join().unwrap(); |
586 | } |
587 | |
588 | #[cfg (any( |
589 | target_os = "linux" , |
590 | target_os = "android" , |
591 | target_os = "freebsd" , |
592 | target_os = "netbsd" , |
593 | ))] |
594 | #[test] |
595 | pub fn udp_recvmmsg_dontwait_short_read() { |
596 | use nix::sys::socket::{recvmmsg, MsgFlags}; |
597 | use std::io::IoSliceMut; |
598 | |
599 | const NUM_MESSAGES_SENT: usize = 2; |
600 | const DATA: [u8; 4] = [1, 2, 3, 4]; |
601 | |
602 | let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799" ).unwrap(); |
603 | let sock_addr = SockaddrIn::from(inet_addr); |
604 | |
605 | let rsock = socket( |
606 | AddressFamily::Inet, |
607 | SockType::Datagram, |
608 | SockFlag::empty(), |
609 | None, |
610 | ) |
611 | .unwrap(); |
612 | bind(rsock.as_raw_fd(), &sock_addr).unwrap(); |
613 | let ssock = socket( |
614 | AddressFamily::Inet, |
615 | SockType::Datagram, |
616 | SockFlag::empty(), |
617 | None, |
618 | ) |
619 | .expect("send socket failed" ); |
620 | |
621 | let send_thread = thread::spawn(move || { |
622 | for _ in 0..NUM_MESSAGES_SENT { |
623 | sendto( |
624 | ssock.as_raw_fd(), |
625 | &DATA[..], |
626 | &sock_addr, |
627 | MsgFlags::empty(), |
628 | ) |
629 | .unwrap(); |
630 | } |
631 | }); |
632 | // Ensure we've sent all the messages before continuing so `recvmmsg` |
633 | // will return right away |
634 | send_thread.join().unwrap(); |
635 | |
636 | let mut msgs = std::collections::LinkedList::new(); |
637 | |
638 | // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg` |
639 | // will return when there are fewer than requested messages in the |
640 | // kernel buffers when using `MSG_DONTWAIT`. |
641 | let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; |
642 | msgs.extend( |
643 | receive_buffers |
644 | .iter_mut() |
645 | .map(|buf| [IoSliceMut::new(&mut buf[..])]), |
646 | ); |
647 | |
648 | let mut data = MultiHeaders::<SockaddrIn>::preallocate( |
649 | NUM_MESSAGES_SENT + 2, |
650 | None, |
651 | ); |
652 | |
653 | let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg( |
654 | rsock.as_raw_fd(), |
655 | &mut data, |
656 | msgs.iter(), |
657 | MsgFlags::MSG_DONTWAIT, |
658 | None, |
659 | ) |
660 | .expect("recvmmsg" ) |
661 | .collect(); |
662 | assert_eq!(res.len(), NUM_MESSAGES_SENT); |
663 | |
664 | for RecvMsg { address, bytes, .. } in res.into_iter() { |
665 | assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); |
666 | assert_eq!(DATA.len(), bytes); |
667 | } |
668 | |
669 | for buf in &receive_buffers[..NUM_MESSAGES_SENT] { |
670 | assert_eq!(&buf[..DATA.len()], DATA); |
671 | } |
672 | } |
673 | |
674 | #[test] |
675 | pub fn udp_inet6() { |
676 | let addr = std::net::Ipv6Addr::from_str("::1" ).unwrap(); |
677 | let rport = 6789; |
678 | let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0); |
679 | let raddr = SockaddrIn6::from(rstd_sa); |
680 | let sport = 6790; |
681 | let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0); |
682 | let saddr = SockaddrIn6::from(sstd_sa); |
683 | let rsock = socket( |
684 | AddressFamily::Inet6, |
685 | SockType::Datagram, |
686 | SockFlag::empty(), |
687 | None, |
688 | ) |
689 | .expect("receive socket failed" ); |
690 | match bind(rsock.as_raw_fd(), &raddr) { |
691 | Err(Errno::EADDRNOTAVAIL) => { |
692 | println!("IPv6 not available, skipping test." ); |
693 | return; |
694 | } |
695 | Err(e) => panic!("bind: {e}" ), |
696 | Ok(()) => (), |
697 | } |
698 | let ssock = socket( |
699 | AddressFamily::Inet6, |
700 | SockType::Datagram, |
701 | SockFlag::empty(), |
702 | None, |
703 | ) |
704 | .expect("send socket failed" ); |
705 | bind(ssock.as_raw_fd(), &saddr).unwrap(); |
706 | let from = sendrecv( |
707 | rsock.as_raw_fd(), |
708 | ssock.as_raw_fd(), |
709 | move |s, m, flags| sendto(s.as_raw_fd(), m, &raddr, flags), |
710 | |_, _| {}, |
711 | ); |
712 | assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap()); |
713 | let osent_addr = from.unwrap(); |
714 | let sent_addr = osent_addr.as_sockaddr_in6().unwrap(); |
715 | assert_eq!(sent_addr.ip(), addr); |
716 | assert_eq!(sent_addr.port(), sport); |
717 | } |
718 | } |
719 | |
720 | // Test error handling of our recvmsg wrapper |
721 | #[test] |
722 | pub fn test_recvmsg_ebadf() { |
723 | use nix::errno::Errno; |
724 | use nix::sys::socket::{recvmsg, MsgFlags}; |
725 | use std::io::IoSliceMut; |
726 | |
727 | let mut buf = [0u8; 5]; |
728 | let mut iov = [IoSliceMut::new(&mut buf[..])]; |
729 | |
730 | let fd = -1; // Bad file descriptor |
731 | let r = recvmsg::<()>(fd.as_raw_fd(), &mut iov, None, MsgFlags::empty()); |
732 | |
733 | assert_eq!(r.err().unwrap(), Errno::EBADF); |
734 | } |
735 | |
736 | // Disable the test on emulated platforms due to a bug in QEMU versions < |
737 | // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 |
738 | #[cfg_attr (qemu, ignore)] |
739 | #[test] |
740 | pub fn test_scm_rights() { |
741 | use nix::sys::socket::{ |
742 | recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, |
743 | ControlMessageOwned, MsgFlags, SockFlag, SockType, |
744 | }; |
745 | use nix::unistd::{close, pipe, read, write}; |
746 | use std::io::{IoSlice, IoSliceMut}; |
747 | |
748 | let (fd1, fd2) = socketpair( |
749 | AddressFamily::Unix, |
750 | SockType::Stream, |
751 | None, |
752 | SockFlag::empty(), |
753 | ) |
754 | .unwrap(); |
755 | let (r, w) = pipe().unwrap(); |
756 | let mut received_r: Option<RawFd> = None; |
757 | |
758 | { |
759 | let iov = [IoSlice::new(b"hello" )]; |
760 | let fds = [r]; |
761 | let cmsg = ControlMessage::ScmRights(&fds); |
762 | assert_eq!( |
763 | sendmsg::<()>( |
764 | fd1.as_raw_fd(), |
765 | &iov, |
766 | &[cmsg], |
767 | MsgFlags::empty(), |
768 | None |
769 | ) |
770 | .unwrap(), |
771 | 5 |
772 | ); |
773 | close(r).unwrap(); |
774 | } |
775 | |
776 | { |
777 | let mut buf = [0u8; 5]; |
778 | |
779 | let mut iov = [IoSliceMut::new(&mut buf[..])]; |
780 | let mut cmsgspace = cmsg_space!([RawFd; 1]); |
781 | let msg = recvmsg::<()>( |
782 | fd2.as_raw_fd(), |
783 | &mut iov, |
784 | Some(&mut cmsgspace), |
785 | MsgFlags::empty(), |
786 | ) |
787 | .unwrap(); |
788 | |
789 | for cmsg in msg.cmsgs() { |
790 | if let ControlMessageOwned::ScmRights(fd) = cmsg { |
791 | assert_eq!(received_r, None); |
792 | assert_eq!(fd.len(), 1); |
793 | received_r = Some(fd[0]); |
794 | } else { |
795 | panic!("unexpected cmsg" ); |
796 | } |
797 | } |
798 | assert_eq!(msg.bytes, 5); |
799 | assert!(!msg |
800 | .flags |
801 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
802 | } |
803 | |
804 | let received_r = received_r.expect("Did not receive passed fd" ); |
805 | // Ensure that the received file descriptor works |
806 | write(w.as_raw_fd(), b"world" ).unwrap(); |
807 | let mut buf = [0u8; 5]; |
808 | read(received_r.as_raw_fd(), &mut buf).unwrap(); |
809 | assert_eq!(&buf[..], b"world" ); |
810 | close(received_r).unwrap(); |
811 | close(w).unwrap(); |
812 | } |
813 | |
814 | // Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross |
815 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
816 | #[cfg_attr (qemu, ignore)] |
817 | #[test] |
818 | pub fn test_af_alg_cipher() { |
819 | use nix::sys::socket::sockopt::AlgSetKey; |
820 | use nix::sys::socket::{ |
821 | accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, |
822 | ControlMessage, MsgFlags, SockFlag, SockType, |
823 | }; |
824 | use nix::unistd::read; |
825 | use std::io::IoSlice; |
826 | |
827 | skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352" ); |
828 | // Travis's seccomp profile blocks AF_ALG |
829 | // https://docs.docker.com/engine/security/seccomp/ |
830 | skip_if_seccomp!(test_af_alg_cipher); |
831 | |
832 | let alg_type = "skcipher" ; |
833 | let alg_name = "ctr-aes-aesni" ; |
834 | // 256-bits secret key |
835 | let key = vec![0u8; 32]; |
836 | // 16-bytes IV |
837 | let iv_len = 16; |
838 | let iv = vec![1u8; iv_len]; |
839 | // 256-bytes plain payload |
840 | let payload_len = 256; |
841 | let payload = vec![2u8; payload_len]; |
842 | |
843 | let sock = socket( |
844 | AddressFamily::Alg, |
845 | SockType::SeqPacket, |
846 | SockFlag::empty(), |
847 | None, |
848 | ) |
849 | .expect("socket failed" ); |
850 | |
851 | let sockaddr = AlgAddr::new(alg_type, alg_name); |
852 | bind(sock.as_raw_fd(), &sockaddr).expect("bind failed" ); |
853 | |
854 | assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name); |
855 | assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type); |
856 | |
857 | setsockopt(&sock, AlgSetKey::default(), &key).expect("setsockopt" ); |
858 | let session_socket = accept(sock.as_raw_fd()).expect("accept failed" ); |
859 | |
860 | let msgs = [ |
861 | ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), |
862 | ControlMessage::AlgSetIv(iv.as_slice()), |
863 | ]; |
864 | let iov = IoSlice::new(&payload); |
865 | sendmsg::<()>( |
866 | session_socket.as_raw_fd(), |
867 | &[iov], |
868 | &msgs, |
869 | MsgFlags::empty(), |
870 | None, |
871 | ) |
872 | .expect("sendmsg encrypt" ); |
873 | |
874 | // allocate buffer for encrypted data |
875 | let mut encrypted = vec![0u8; payload_len]; |
876 | let num_bytes = |
877 | read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt" ); |
878 | assert_eq!(num_bytes, payload_len); |
879 | |
880 | let iov = IoSlice::new(&encrypted); |
881 | |
882 | let iv = vec![1u8; iv_len]; |
883 | |
884 | let msgs = [ |
885 | ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), |
886 | ControlMessage::AlgSetIv(iv.as_slice()), |
887 | ]; |
888 | sendmsg::<()>( |
889 | session_socket.as_raw_fd(), |
890 | &[iov], |
891 | &msgs, |
892 | MsgFlags::empty(), |
893 | None, |
894 | ) |
895 | .expect("sendmsg decrypt" ); |
896 | |
897 | // allocate buffer for decrypted data |
898 | let mut decrypted = vec![0u8; payload_len]; |
899 | let num_bytes = |
900 | read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt" ); |
901 | |
902 | assert_eq!(num_bytes, payload_len); |
903 | assert_eq!(decrypted, payload); |
904 | } |
905 | |
906 | // Disable the test on emulated platforms due to not enabled support of AF_ALG |
907 | // in QEMU from rust cross |
908 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
909 | #[cfg_attr (qemu, ignore)] |
910 | #[test] |
911 | pub fn test_af_alg_aead() { |
912 | use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT}; |
913 | use nix::fcntl::{fcntl, FcntlArg, OFlag}; |
914 | use nix::sys::socket::sockopt::{AlgSetAeadAuthSize, AlgSetKey}; |
915 | use nix::sys::socket::{ |
916 | accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, |
917 | ControlMessage, MsgFlags, SockFlag, SockType, |
918 | }; |
919 | use nix::unistd::read; |
920 | use std::io::IoSlice; |
921 | |
922 | skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352" ); |
923 | // Travis's seccomp profile blocks AF_ALG |
924 | // https://docs.docker.com/engine/security/seccomp/ |
925 | skip_if_seccomp!(test_af_alg_aead); |
926 | |
927 | let auth_size = 4usize; |
928 | let assoc_size = 16u32; |
929 | |
930 | let alg_type = "aead" ; |
931 | let alg_name = "gcm(aes)" ; |
932 | // 256-bits secret key |
933 | let key = vec![0u8; 32]; |
934 | // 12-bytes IV |
935 | let iv_len = 12; |
936 | let iv = vec![1u8; iv_len]; |
937 | // 256-bytes plain payload |
938 | let payload_len = 256; |
939 | let mut payload = |
940 | vec![2u8; payload_len + (assoc_size as usize) + auth_size]; |
941 | |
942 | for i in 0..assoc_size { |
943 | payload[i as usize] = 10; |
944 | } |
945 | |
946 | let len = payload.len(); |
947 | |
948 | for i in 0..auth_size { |
949 | payload[len - 1 - i] = 0; |
950 | } |
951 | |
952 | let sock = socket( |
953 | AddressFamily::Alg, |
954 | SockType::SeqPacket, |
955 | SockFlag::empty(), |
956 | None, |
957 | ) |
958 | .expect("socket failed" ); |
959 | |
960 | let sockaddr = AlgAddr::new(alg_type, alg_name); |
961 | bind(sock.as_raw_fd(), &sockaddr).expect("bind failed" ); |
962 | |
963 | setsockopt(&sock, AlgSetAeadAuthSize, &auth_size) |
964 | .expect("setsockopt AlgSetAeadAuthSize" ); |
965 | setsockopt(&sock, AlgSetKey::default(), &key) |
966 | .expect("setsockopt AlgSetKey" ); |
967 | let session_socket = accept(sock.as_raw_fd()).expect("accept failed" ); |
968 | |
969 | let msgs = [ |
970 | ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT), |
971 | ControlMessage::AlgSetIv(iv.as_slice()), |
972 | ControlMessage::AlgSetAeadAssoclen(&assoc_size), |
973 | ]; |
974 | |
975 | let iov = IoSlice::new(&payload); |
976 | sendmsg::<()>( |
977 | session_socket.as_raw_fd(), |
978 | &[iov], |
979 | &msgs, |
980 | MsgFlags::empty(), |
981 | None, |
982 | ) |
983 | .expect("sendmsg encrypt" ); |
984 | |
985 | // allocate buffer for encrypted data |
986 | let mut encrypted = |
987 | vec![0u8; (assoc_size as usize) + payload_len + auth_size]; |
988 | let num_bytes = |
989 | read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt" ); |
990 | assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize)); |
991 | |
992 | for i in 0..assoc_size { |
993 | encrypted[i as usize] = 10; |
994 | } |
995 | |
996 | let iov = IoSlice::new(&encrypted); |
997 | |
998 | let iv = vec![1u8; iv_len]; |
999 | |
1000 | let session_socket = accept(sock.as_raw_fd()).expect("accept failed" ); |
1001 | |
1002 | let msgs = [ |
1003 | ControlMessage::AlgSetOp(&ALG_OP_DECRYPT), |
1004 | ControlMessage::AlgSetIv(iv.as_slice()), |
1005 | ControlMessage::AlgSetAeadAssoclen(&assoc_size), |
1006 | ]; |
1007 | sendmsg::<()>( |
1008 | session_socket.as_raw_fd(), |
1009 | &[iov], |
1010 | &msgs, |
1011 | MsgFlags::empty(), |
1012 | None, |
1013 | ) |
1014 | .expect("sendmsg decrypt" ); |
1015 | |
1016 | // allocate buffer for decrypted data |
1017 | let mut decrypted = |
1018 | vec![0u8; payload_len + (assoc_size as usize) + auth_size]; |
1019 | // Starting with kernel 4.9, the interface changed slightly such that the |
1020 | // authentication tag memory is only needed in the output buffer for encryption |
1021 | // and in the input buffer for decryption. |
1022 | // Do not block on read, as we may have fewer bytes than buffer size |
1023 | fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)) |
1024 | .expect("fcntl non_blocking" ); |
1025 | let num_bytes = |
1026 | read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt" ); |
1027 | |
1028 | assert!(num_bytes >= payload_len + (assoc_size as usize)); |
1029 | assert_eq!( |
1030 | decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], |
1031 | payload[(assoc_size as usize)..payload_len + (assoc_size as usize)] |
1032 | ); |
1033 | } |
1034 | |
1035 | // Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`. |
1036 | // This creates a (udp) socket bound to localhost, then sends a message to |
1037 | // itself but uses Ipv4PacketInfo to force the source address to be localhost. |
1038 | // |
1039 | // This would be a more interesting test if we could assume that the test host |
1040 | // has more than one IP address (since we could select a different address to |
1041 | // test from). |
1042 | #[cfg (any(target_os = "linux" , target_os = "macos" , target_os = "netbsd" ))] |
1043 | #[test] |
1044 | pub fn test_sendmsg_ipv4packetinfo() { |
1045 | use cfg_if::cfg_if; |
1046 | use nix::sys::socket::{ |
1047 | bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, |
1048 | SockFlag, SockType, SockaddrIn, |
1049 | }; |
1050 | use std::io::IoSlice; |
1051 | |
1052 | let sock = socket( |
1053 | AddressFamily::Inet, |
1054 | SockType::Datagram, |
1055 | SockFlag::empty(), |
1056 | None, |
1057 | ) |
1058 | .expect("socket failed" ); |
1059 | |
1060 | let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000); |
1061 | |
1062 | bind(sock.as_raw_fd(), &sock_addr).expect("bind failed" ); |
1063 | |
1064 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
1065 | let iov = [IoSlice::new(&slice)]; |
1066 | |
1067 | cfg_if! { |
1068 | if #[cfg(target_os = "netbsd" )] { |
1069 | let pi = libc::in_pktinfo { |
1070 | ipi_ifindex: 0, /* Unspecified interface */ |
1071 | ipi_addr: libc::in_addr { s_addr: 0 }, |
1072 | }; |
1073 | } else { |
1074 | let pi = libc::in_pktinfo { |
1075 | ipi_ifindex: 0, /* Unspecified interface */ |
1076 | ipi_addr: libc::in_addr { s_addr: 0 }, |
1077 | ipi_spec_dst: sock_addr.as_ref().sin_addr, |
1078 | }; |
1079 | } |
1080 | } |
1081 | |
1082 | let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; |
1083 | |
1084 | sendmsg( |
1085 | sock.as_raw_fd(), |
1086 | &iov, |
1087 | &cmsg, |
1088 | MsgFlags::empty(), |
1089 | Some(&sock_addr), |
1090 | ) |
1091 | .expect("sendmsg" ); |
1092 | } |
1093 | |
1094 | // Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`. |
1095 | // This creates a (udp) socket bound to ip6-localhost, then sends a message to |
1096 | // itself but uses Ipv6PacketInfo to force the source address to be |
1097 | // ip6-localhost. |
1098 | // |
1099 | // This would be a more interesting test if we could assume that the test host |
1100 | // has more than one IP address (since we could select a different address to |
1101 | // test from). |
1102 | #[cfg (any( |
1103 | target_os = "linux" , |
1104 | target_os = "macos" , |
1105 | target_os = "netbsd" , |
1106 | target_os = "freebsd" |
1107 | ))] |
1108 | #[test] |
1109 | pub fn test_sendmsg_ipv6packetinfo() { |
1110 | use nix::errno::Errno; |
1111 | use nix::sys::socket::{ |
1112 | bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, |
1113 | SockFlag, SockType, SockaddrIn6, |
1114 | }; |
1115 | use std::io::IoSlice; |
1116 | |
1117 | let sock = socket( |
1118 | AddressFamily::Inet6, |
1119 | SockType::Datagram, |
1120 | SockFlag::empty(), |
1121 | None, |
1122 | ) |
1123 | .expect("socket failed" ); |
1124 | |
1125 | let std_sa = SocketAddrV6::from_str("[::1]:6000" ).unwrap(); |
1126 | let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); |
1127 | |
1128 | if let Err(Errno::EADDRNOTAVAIL) = bind(sock.as_raw_fd(), &sock_addr) { |
1129 | println!("IPv6 not available, skipping test." ); |
1130 | return; |
1131 | } |
1132 | |
1133 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
1134 | let iov = [IoSlice::new(&slice)]; |
1135 | |
1136 | let pi = libc::in6_pktinfo { |
1137 | ipi6_ifindex: 0, /* Unspecified interface */ |
1138 | ipi6_addr: sock_addr.as_ref().sin6_addr, |
1139 | }; |
1140 | |
1141 | let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; |
1142 | |
1143 | sendmsg::<SockaddrIn6>( |
1144 | sock.as_raw_fd(), |
1145 | &iov, |
1146 | &cmsg, |
1147 | MsgFlags::empty(), |
1148 | Some(&sock_addr), |
1149 | ) |
1150 | .expect("sendmsg" ); |
1151 | } |
1152 | |
1153 | // Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This |
1154 | // creates a UDP socket bound to all local interfaces (0.0.0.0). It then |
1155 | // sends message to itself at 127.0.0.1 while explicitly specifying |
1156 | // 127.0.0.1 as the source address through an Ipv4SendSrcAddr |
1157 | // (IP_SENDSRCADDR) control message. |
1158 | // |
1159 | // Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg |
1160 | // returns EINVAL otherwise. (See FreeBSD's ip(4) man page.) |
1161 | #[cfg (any( |
1162 | target_os = "netbsd" , |
1163 | target_os = "freebsd" , |
1164 | target_os = "openbsd" , |
1165 | target_os = "dragonfly" , |
1166 | ))] |
1167 | #[test] |
1168 | pub fn test_sendmsg_ipv4sendsrcaddr() { |
1169 | use nix::sys::socket::{ |
1170 | bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, |
1171 | SockFlag, SockType, SockaddrIn, |
1172 | }; |
1173 | use std::io::IoSlice; |
1174 | |
1175 | let sock = socket( |
1176 | AddressFamily::Inet, |
1177 | SockType::Datagram, |
1178 | SockFlag::empty(), |
1179 | None, |
1180 | ) |
1181 | .expect("socket failed" ); |
1182 | |
1183 | let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0); |
1184 | bind(sock.as_raw_fd(), &unspec_sock_addr).expect("bind failed" ); |
1185 | let bound_sock_addr: SockaddrIn = getsockname(sock.as_raw_fd()).unwrap(); |
1186 | let localhost_sock_addr: SockaddrIn = |
1187 | SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port()); |
1188 | |
1189 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
1190 | let iov = [IoSlice::new(&slice)]; |
1191 | let cmsg = [ControlMessage::Ipv4SendSrcAddr( |
1192 | &localhost_sock_addr.as_ref().sin_addr, |
1193 | )]; |
1194 | |
1195 | sendmsg( |
1196 | sock.as_raw_fd(), |
1197 | &iov, |
1198 | &cmsg, |
1199 | MsgFlags::empty(), |
1200 | Some(&localhost_sock_addr), |
1201 | ) |
1202 | .expect("sendmsg" ); |
1203 | } |
1204 | |
1205 | /// Tests that passing multiple fds using a single `ControlMessage` works. |
1206 | // Disable the test on emulated platforms due to a bug in QEMU versions < |
1207 | // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 |
1208 | #[cfg_attr (qemu, ignore)] |
1209 | #[test] |
1210 | fn test_scm_rights_single_cmsg_multiple_fds() { |
1211 | use nix::sys::socket::{ |
1212 | recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags, |
1213 | }; |
1214 | use std::io::{IoSlice, IoSliceMut}; |
1215 | use std::os::unix::io::{AsRawFd, RawFd}; |
1216 | use std::os::unix::net::UnixDatagram; |
1217 | use std::thread; |
1218 | |
1219 | let (send, receive) = UnixDatagram::pair().unwrap(); |
1220 | let thread = thread::spawn(move || { |
1221 | let mut buf = [0u8; 8]; |
1222 | let mut iovec = [IoSliceMut::new(&mut buf)]; |
1223 | |
1224 | let mut space = cmsg_space!([RawFd; 2]); |
1225 | let msg = recvmsg::<()>( |
1226 | receive.as_raw_fd(), |
1227 | &mut iovec, |
1228 | Some(&mut space), |
1229 | MsgFlags::empty(), |
1230 | ) |
1231 | .unwrap(); |
1232 | assert!(!msg |
1233 | .flags |
1234 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
1235 | |
1236 | let mut cmsgs = msg.cmsgs(); |
1237 | match cmsgs.next() { |
1238 | Some(ControlMessageOwned::ScmRights(fds)) => { |
1239 | assert_eq!( |
1240 | fds.len(), |
1241 | 2, |
1242 | "unexpected fd count (expected 2 fds, got {})" , |
1243 | fds.len() |
1244 | ); |
1245 | } |
1246 | _ => panic!(), |
1247 | } |
1248 | assert!(cmsgs.next().is_none(), "unexpected control msg" ); |
1249 | |
1250 | assert_eq!(msg.bytes, 8); |
1251 | assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); |
1252 | }); |
1253 | |
1254 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
1255 | let iov = [IoSlice::new(&slice)]; |
1256 | let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout |
1257 | let cmsg = [ControlMessage::ScmRights(&fds)]; |
1258 | sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None) |
1259 | .unwrap(); |
1260 | thread.join().unwrap(); |
1261 | } |
1262 | |
1263 | // Verify `sendmsg` builds a valid `msghdr` when passing an empty |
1264 | // `cmsgs` argument. This should result in a msghdr with a nullptr |
1265 | // msg_control field and a msg_controllen of 0 when calling into the |
1266 | // raw `sendmsg`. |
1267 | #[test] |
1268 | pub fn test_sendmsg_empty_cmsgs() { |
1269 | use nix::sys::socket::{ |
1270 | recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag, |
1271 | SockType, |
1272 | }; |
1273 | use std::io::{IoSlice, IoSliceMut}; |
1274 | |
1275 | let (fd1, fd2) = socketpair( |
1276 | AddressFamily::Unix, |
1277 | SockType::Stream, |
1278 | None, |
1279 | SockFlag::empty(), |
1280 | ) |
1281 | .unwrap(); |
1282 | |
1283 | { |
1284 | let iov = [IoSlice::new(b"hello" )]; |
1285 | assert_eq!( |
1286 | sendmsg::<()>(fd1.as_raw_fd(), &iov, &[], MsgFlags::empty(), None) |
1287 | .unwrap(), |
1288 | 5 |
1289 | ); |
1290 | } |
1291 | |
1292 | { |
1293 | let mut buf = [0u8; 5]; |
1294 | let mut iov = [IoSliceMut::new(&mut buf[..])]; |
1295 | |
1296 | let mut cmsgspace = cmsg_space!([RawFd; 1]); |
1297 | let msg = recvmsg::<()>( |
1298 | fd2.as_raw_fd(), |
1299 | &mut iov, |
1300 | Some(&mut cmsgspace), |
1301 | MsgFlags::empty(), |
1302 | ) |
1303 | .unwrap(); |
1304 | |
1305 | for _ in msg.cmsgs() { |
1306 | panic!("unexpected cmsg" ); |
1307 | } |
1308 | assert!(!msg |
1309 | .flags |
1310 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
1311 | assert_eq!(msg.bytes, 5); |
1312 | } |
1313 | } |
1314 | |
1315 | #[cfg (any( |
1316 | target_os = "android" , |
1317 | target_os = "linux" , |
1318 | target_os = "freebsd" , |
1319 | target_os = "dragonfly" , |
1320 | ))] |
1321 | #[test] |
1322 | fn test_scm_credentials() { |
1323 | use nix::sys::socket::{ |
1324 | recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, |
1325 | ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials, |
1326 | }; |
1327 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1328 | use nix::sys::socket::{setsockopt, sockopt::PassCred}; |
1329 | use nix::unistd::{getgid, getpid, getuid}; |
1330 | use std::io::{IoSlice, IoSliceMut}; |
1331 | |
1332 | let (send, recv) = socketpair( |
1333 | AddressFamily::Unix, |
1334 | SockType::Stream, |
1335 | None, |
1336 | SockFlag::empty(), |
1337 | ) |
1338 | .unwrap(); |
1339 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1340 | setsockopt(&recv, PassCred, &true).unwrap(); |
1341 | |
1342 | { |
1343 | let iov = [IoSlice::new(b"hello" )]; |
1344 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1345 | let cred = UnixCredentials::new(); |
1346 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1347 | let cmsg = ControlMessage::ScmCredentials(&cred); |
1348 | #[cfg (any(target_os = "freebsd" , target_os = "dragonfly" ))] |
1349 | let cmsg = ControlMessage::ScmCreds; |
1350 | assert_eq!( |
1351 | sendmsg::<()>( |
1352 | send.as_raw_fd(), |
1353 | &iov, |
1354 | &[cmsg], |
1355 | MsgFlags::empty(), |
1356 | None |
1357 | ) |
1358 | .unwrap(), |
1359 | 5 |
1360 | ); |
1361 | } |
1362 | |
1363 | { |
1364 | let mut buf = [0u8; 5]; |
1365 | let mut iov = [IoSliceMut::new(&mut buf[..])]; |
1366 | |
1367 | let mut cmsgspace = cmsg_space!(UnixCredentials); |
1368 | let msg = recvmsg::<()>( |
1369 | recv.as_raw_fd(), |
1370 | &mut iov, |
1371 | Some(&mut cmsgspace), |
1372 | MsgFlags::empty(), |
1373 | ) |
1374 | .unwrap(); |
1375 | let mut received_cred = None; |
1376 | |
1377 | for cmsg in msg.cmsgs() { |
1378 | let cred = match cmsg { |
1379 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1380 | ControlMessageOwned::ScmCredentials(cred) => cred, |
1381 | #[cfg (any(target_os = "freebsd" , target_os = "dragonfly" ))] |
1382 | ControlMessageOwned::ScmCreds(cred) => cred, |
1383 | other => panic!("unexpected cmsg {other:?}" ), |
1384 | }; |
1385 | assert!(received_cred.is_none()); |
1386 | assert_eq!(cred.pid(), getpid().as_raw()); |
1387 | assert_eq!(cred.uid(), getuid().as_raw()); |
1388 | assert_eq!(cred.gid(), getgid().as_raw()); |
1389 | received_cred = Some(cred); |
1390 | } |
1391 | received_cred.expect("no creds received" ); |
1392 | assert_eq!(msg.bytes, 5); |
1393 | assert!(!msg |
1394 | .flags |
1395 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
1396 | } |
1397 | } |
1398 | |
1399 | /// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single |
1400 | /// `sendmsg` call. |
1401 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1402 | // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation |
1403 | // see https://bugs.launchpad.net/qemu/+bug/1781280 |
1404 | #[cfg_attr (qemu, ignore)] |
1405 | #[test] |
1406 | fn test_scm_credentials_and_rights() { |
1407 | let space = cmsg_space!(libc::ucred, RawFd); |
1408 | test_impl_scm_credentials_and_rights(space); |
1409 | } |
1410 | |
1411 | /// Ensure that passing a an oversized control message buffer to recvmsg |
1412 | /// still works. |
1413 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1414 | // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation |
1415 | // see https://bugs.launchpad.net/qemu/+bug/1781280 |
1416 | #[cfg_attr (qemu, ignore)] |
1417 | #[test] |
1418 | fn test_too_large_cmsgspace() { |
1419 | let space = vec![0u8; 1024]; |
1420 | test_impl_scm_credentials_and_rights(space); |
1421 | } |
1422 | |
1423 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1424 | fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { |
1425 | use libc::ucred; |
1426 | use nix::sys::socket::sockopt::PassCred; |
1427 | use nix::sys::socket::{ |
1428 | recvmsg, sendmsg, setsockopt, socketpair, ControlMessage, |
1429 | ControlMessageOwned, MsgFlags, SockFlag, SockType, |
1430 | }; |
1431 | use nix::unistd::{close, getgid, getpid, getuid, pipe, write}; |
1432 | use std::io::{IoSlice, IoSliceMut}; |
1433 | |
1434 | let (send, recv) = socketpair( |
1435 | AddressFamily::Unix, |
1436 | SockType::Stream, |
1437 | None, |
1438 | SockFlag::empty(), |
1439 | ) |
1440 | .unwrap(); |
1441 | setsockopt(&recv, PassCred, &true).unwrap(); |
1442 | |
1443 | let (r, w) = pipe().unwrap(); |
1444 | let mut received_r: Option<RawFd> = None; |
1445 | |
1446 | { |
1447 | let iov = [IoSlice::new(b"hello" )]; |
1448 | let cred = ucred { |
1449 | pid: getpid().as_raw(), |
1450 | uid: getuid().as_raw(), |
1451 | gid: getgid().as_raw(), |
1452 | } |
1453 | .into(); |
1454 | let fds = [r]; |
1455 | let cmsgs = [ |
1456 | ControlMessage::ScmCredentials(&cred), |
1457 | ControlMessage::ScmRights(&fds), |
1458 | ]; |
1459 | assert_eq!( |
1460 | sendmsg::<()>( |
1461 | send.as_raw_fd(), |
1462 | &iov, |
1463 | &cmsgs, |
1464 | MsgFlags::empty(), |
1465 | None |
1466 | ) |
1467 | .unwrap(), |
1468 | 5 |
1469 | ); |
1470 | close(r).unwrap(); |
1471 | } |
1472 | |
1473 | { |
1474 | let mut buf = [0u8; 5]; |
1475 | let mut iov = [IoSliceMut::new(&mut buf[..])]; |
1476 | let msg = recvmsg::<()>( |
1477 | recv.as_raw_fd(), |
1478 | &mut iov, |
1479 | Some(&mut space), |
1480 | MsgFlags::empty(), |
1481 | ) |
1482 | .unwrap(); |
1483 | let mut received_cred = None; |
1484 | |
1485 | assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs" ); |
1486 | |
1487 | for cmsg in msg.cmsgs() { |
1488 | match cmsg { |
1489 | ControlMessageOwned::ScmRights(fds) => { |
1490 | assert_eq!(received_r, None, "already received fd" ); |
1491 | assert_eq!(fds.len(), 1); |
1492 | received_r = Some(fds[0]); |
1493 | } |
1494 | ControlMessageOwned::ScmCredentials(cred) => { |
1495 | assert!(received_cred.is_none()); |
1496 | assert_eq!(cred.pid(), getpid().as_raw()); |
1497 | assert_eq!(cred.uid(), getuid().as_raw()); |
1498 | assert_eq!(cred.gid(), getgid().as_raw()); |
1499 | received_cred = Some(cred); |
1500 | } |
1501 | _ => panic!("unexpected cmsg" ), |
1502 | } |
1503 | } |
1504 | received_cred.expect("no creds received" ); |
1505 | assert_eq!(msg.bytes, 5); |
1506 | assert!(!msg |
1507 | .flags |
1508 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
1509 | } |
1510 | |
1511 | let received_r = received_r.expect("Did not receive passed fd" ); |
1512 | // Ensure that the received file descriptor works |
1513 | write(w.as_raw_fd(), b"world" ).unwrap(); |
1514 | let mut buf = [0u8; 5]; |
1515 | read(received_r.as_raw_fd(), &mut buf).unwrap(); |
1516 | assert_eq!(&buf[..], b"world" ); |
1517 | close(received_r).unwrap(); |
1518 | close(w).unwrap(); |
1519 | } |
1520 | |
1521 | // Test creating and using named unix domain sockets |
1522 | #[test] |
1523 | pub fn test_named_unixdomain() { |
1524 | use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; |
1525 | use nix::sys::socket::{SockFlag, SockType}; |
1526 | use nix::unistd::{read, write}; |
1527 | use std::thread; |
1528 | |
1529 | let tempdir = tempfile::tempdir().unwrap(); |
1530 | let sockname = tempdir.path().join("sock" ); |
1531 | let s1 = socket( |
1532 | AddressFamily::Unix, |
1533 | SockType::Stream, |
1534 | SockFlag::empty(), |
1535 | None, |
1536 | ) |
1537 | .expect("socket failed" ); |
1538 | let sockaddr = UnixAddr::new(&sockname).unwrap(); |
1539 | bind(s1.as_raw_fd(), &sockaddr).expect("bind failed" ); |
1540 | listen(&s1, 10).expect("listen failed" ); |
1541 | |
1542 | let thr = thread::spawn(move || { |
1543 | let s2 = socket( |
1544 | AddressFamily::Unix, |
1545 | SockType::Stream, |
1546 | SockFlag::empty(), |
1547 | None, |
1548 | ) |
1549 | .expect("socket failed" ); |
1550 | connect(s2.as_raw_fd(), &sockaddr).expect("connect failed" ); |
1551 | write(s2.as_raw_fd(), b"hello" ).expect("write failed" ); |
1552 | }); |
1553 | |
1554 | let s3 = accept(s1.as_raw_fd()).expect("accept failed" ); |
1555 | |
1556 | let mut buf = [0; 5]; |
1557 | read(s3.as_raw_fd(), &mut buf).unwrap(); |
1558 | thr.join().unwrap(); |
1559 | |
1560 | assert_eq!(&buf[..], b"hello" ); |
1561 | } |
1562 | |
1563 | // Test using unnamed unix domain addresses |
1564 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1565 | #[test] |
1566 | pub fn test_unnamed_unixdomain() { |
1567 | use nix::sys::socket::{getsockname, socketpair}; |
1568 | use nix::sys::socket::{SockFlag, SockType}; |
1569 | |
1570 | let (fd_1, _fd_2) = socketpair( |
1571 | AddressFamily::Unix, |
1572 | SockType::Stream, |
1573 | None, |
1574 | SockFlag::empty(), |
1575 | ) |
1576 | .expect("socketpair failed" ); |
1577 | |
1578 | let addr_1: UnixAddr = |
1579 | getsockname(fd_1.as_raw_fd()).expect("getsockname failed" ); |
1580 | assert!(addr_1.is_unnamed()); |
1581 | } |
1582 | |
1583 | // Test creating and using unnamed unix domain addresses for autobinding sockets |
1584 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1585 | #[test] |
1586 | pub fn test_unnamed_unixdomain_autobind() { |
1587 | use nix::sys::socket::{bind, getsockname, socket}; |
1588 | use nix::sys::socket::{SockFlag, SockType}; |
1589 | |
1590 | let fd = socket( |
1591 | AddressFamily::Unix, |
1592 | SockType::Stream, |
1593 | SockFlag::empty(), |
1594 | None, |
1595 | ) |
1596 | .expect("socket failed" ); |
1597 | |
1598 | // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the |
1599 | // socket is autobound to an abstract address" |
1600 | bind(fd.as_raw_fd(), &UnixAddr::new_unnamed()).expect("bind failed" ); |
1601 | |
1602 | let addr: UnixAddr = |
1603 | getsockname(fd.as_raw_fd()).expect("getsockname failed" ); |
1604 | let addr = addr.as_abstract().unwrap(); |
1605 | |
1606 | // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2 |
1607 | // (as of 2022-11) |
1608 | assert_eq!(addr.len(), 5); |
1609 | } |
1610 | |
1611 | // Test creating and using named system control sockets |
1612 | #[cfg (any(target_os = "macos" , target_os = "ios" ))] |
1613 | #[test] |
1614 | pub fn test_syscontrol() { |
1615 | use nix::errno::Errno; |
1616 | use nix::sys::socket::{ |
1617 | socket, SockFlag, SockProtocol, SockType, SysControlAddr, |
1618 | }; |
1619 | |
1620 | let fd = socket( |
1621 | AddressFamily::System, |
1622 | SockType::Datagram, |
1623 | SockFlag::empty(), |
1624 | SockProtocol::KextControl, |
1625 | ) |
1626 | .expect("socket failed" ); |
1627 | SysControlAddr::from_name(fd.as_raw_fd(), "com.apple.net.utun_control" , 0) |
1628 | .expect("resolving sys_control name failed" ); |
1629 | assert_eq!( |
1630 | SysControlAddr::from_name(fd.as_raw_fd(), "foo.bar.lol" , 0).err(), |
1631 | Some(Errno::ENOENT) |
1632 | ); |
1633 | |
1634 | // requires root privileges |
1635 | // connect(fd.as_raw_fd(), &sockaddr).expect("connect failed"); |
1636 | } |
1637 | |
1638 | #[cfg (any( |
1639 | target_os = "android" , |
1640 | target_os = "freebsd" , |
1641 | target_os = "ios" , |
1642 | target_os = "linux" , |
1643 | target_os = "macos" , |
1644 | target_os = "netbsd" , |
1645 | target_os = "openbsd" , |
1646 | ))] |
1647 | fn loopback_address( |
1648 | family: AddressFamily, |
1649 | ) -> Option<nix::ifaddrs::InterfaceAddress> { |
1650 | use nix::ifaddrs::getifaddrs; |
1651 | use nix::net::if_::*; |
1652 | use nix::sys::socket::SockaddrLike; |
1653 | use std::io; |
1654 | use std::io::Write; |
1655 | |
1656 | let mut addrs = match getifaddrs() { |
1657 | Ok(iter) => iter, |
1658 | Err(e) => { |
1659 | let stdioerr = io::stderr(); |
1660 | let mut handle = stdioerr.lock(); |
1661 | writeln!(handle, "getifaddrs: {e:?}" ).unwrap(); |
1662 | return None; |
1663 | } |
1664 | }; |
1665 | // return first address matching family |
1666 | addrs.find(|ifaddr| { |
1667 | ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) |
1668 | && ifaddr.address.as_ref().and_then(SockaddrLike::family) |
1669 | == Some(family) |
1670 | }) |
1671 | } |
1672 | |
1673 | #[cfg (any( |
1674 | target_os = "android" , |
1675 | target_os = "ios" , |
1676 | target_os = "linux" , |
1677 | target_os = "macos" , |
1678 | target_os = "netbsd" , |
1679 | ))] |
1680 | // qemu doesn't seem to be emulating this correctly in these architectures |
1681 | #[cfg_attr ( |
1682 | all( |
1683 | qemu, |
1684 | any( |
1685 | target_arch = "mips" , |
1686 | target_arch = "mips64" , |
1687 | target_arch = "powerpc64" , |
1688 | ) |
1689 | ), |
1690 | ignore |
1691 | )] |
1692 | #[test] |
1693 | pub fn test_recv_ipv4pktinfo() { |
1694 | use nix::net::if_::*; |
1695 | use nix::sys::socket::sockopt::Ipv4PacketInfo; |
1696 | use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; |
1697 | use nix::sys::socket::{getsockname, setsockopt, socket}; |
1698 | use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; |
1699 | use std::io::{IoSlice, IoSliceMut}; |
1700 | |
1701 | let lo_ifaddr = loopback_address(AddressFamily::Inet); |
1702 | let (lo_name, lo) = match lo_ifaddr { |
1703 | Some(ifaddr) => ( |
1704 | ifaddr.interface_name, |
1705 | ifaddr.address.expect("Expect IPv4 address on interface" ), |
1706 | ), |
1707 | None => return, |
1708 | }; |
1709 | let receive = socket( |
1710 | AddressFamily::Inet, |
1711 | SockType::Datagram, |
1712 | SockFlag::empty(), |
1713 | None, |
1714 | ) |
1715 | .expect("receive socket failed" ); |
1716 | bind(receive.as_raw_fd(), &lo).expect("bind failed" ); |
1717 | let sa: SockaddrIn = |
1718 | getsockname(receive.as_raw_fd()).expect("getsockname failed" ); |
1719 | setsockopt(&receive, Ipv4PacketInfo, &true).expect("setsockopt failed" ); |
1720 | |
1721 | { |
1722 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
1723 | let iov = [IoSlice::new(&slice)]; |
1724 | |
1725 | let send = socket( |
1726 | AddressFamily::Inet, |
1727 | SockType::Datagram, |
1728 | SockFlag::empty(), |
1729 | None, |
1730 | ) |
1731 | .expect("send socket failed" ); |
1732 | sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) |
1733 | .expect("sendmsg failed" ); |
1734 | } |
1735 | |
1736 | { |
1737 | let mut buf = [0u8; 8]; |
1738 | let mut iovec = [IoSliceMut::new(&mut buf)]; |
1739 | |
1740 | let mut space = cmsg_space!(libc::in_pktinfo); |
1741 | let msg = recvmsg::<()>( |
1742 | receive.as_raw_fd(), |
1743 | &mut iovec, |
1744 | Some(&mut space), |
1745 | MsgFlags::empty(), |
1746 | ) |
1747 | .expect("recvmsg failed" ); |
1748 | assert!(!msg |
1749 | .flags |
1750 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
1751 | |
1752 | let mut cmsgs = msg.cmsgs(); |
1753 | if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next() |
1754 | { |
1755 | let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex" ); |
1756 | assert_eq!( |
1757 | pktinfo.ipi_ifindex as libc::c_uint, i, |
1758 | "unexpected ifindex (expected {}, got {})" , |
1759 | i, pktinfo.ipi_ifindex |
1760 | ); |
1761 | } |
1762 | assert!(cmsgs.next().is_none(), "unexpected additional control msg" ); |
1763 | assert_eq!(msg.bytes, 8); |
1764 | assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); |
1765 | } |
1766 | } |
1767 | |
1768 | #[cfg (any( |
1769 | target_os = "freebsd" , |
1770 | target_os = "ios" , |
1771 | target_os = "macos" , |
1772 | target_os = "netbsd" , |
1773 | target_os = "openbsd" , |
1774 | ))] |
1775 | // qemu doesn't seem to be emulating this correctly in these architectures |
1776 | #[cfg_attr ( |
1777 | all( |
1778 | qemu, |
1779 | any( |
1780 | target_arch = "mips" , |
1781 | target_arch = "mips64" , |
1782 | target_arch = "powerpc64" , |
1783 | ) |
1784 | ), |
1785 | ignore |
1786 | )] |
1787 | #[test] |
1788 | pub fn test_recvif() { |
1789 | use nix::net::if_::*; |
1790 | use nix::sys::socket::sockopt::{Ipv4RecvDstAddr, Ipv4RecvIf}; |
1791 | use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; |
1792 | use nix::sys::socket::{getsockname, setsockopt, socket}; |
1793 | use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; |
1794 | use std::io::{IoSlice, IoSliceMut}; |
1795 | |
1796 | let lo_ifaddr = loopback_address(AddressFamily::Inet); |
1797 | let (lo_name, lo) = match lo_ifaddr { |
1798 | Some(ifaddr) => ( |
1799 | ifaddr.interface_name, |
1800 | ifaddr.address.expect("Expect IPv4 address on interface" ), |
1801 | ), |
1802 | None => return, |
1803 | }; |
1804 | let receive = socket( |
1805 | AddressFamily::Inet, |
1806 | SockType::Datagram, |
1807 | SockFlag::empty(), |
1808 | None, |
1809 | ) |
1810 | .expect("receive socket failed" ); |
1811 | bind(receive.as_raw_fd(), &lo).expect("bind failed" ); |
1812 | let sa: SockaddrIn = |
1813 | getsockname(receive.as_raw_fd()).expect("getsockname failed" ); |
1814 | setsockopt(&receive, Ipv4RecvIf, &true) |
1815 | .expect("setsockopt IP_RECVIF failed" ); |
1816 | setsockopt(&receive, Ipv4RecvDstAddr, &true) |
1817 | .expect("setsockopt IP_RECVDSTADDR failed" ); |
1818 | |
1819 | { |
1820 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
1821 | let iov = [IoSlice::new(&slice)]; |
1822 | |
1823 | let send = socket( |
1824 | AddressFamily::Inet, |
1825 | SockType::Datagram, |
1826 | SockFlag::empty(), |
1827 | None, |
1828 | ) |
1829 | .expect("send socket failed" ); |
1830 | sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) |
1831 | .expect("sendmsg failed" ); |
1832 | } |
1833 | |
1834 | { |
1835 | let mut buf = [0u8; 8]; |
1836 | let mut iovec = [IoSliceMut::new(&mut buf)]; |
1837 | let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); |
1838 | let msg = recvmsg::<()>( |
1839 | receive.as_raw_fd(), |
1840 | &mut iovec, |
1841 | Some(&mut space), |
1842 | MsgFlags::empty(), |
1843 | ) |
1844 | .expect("recvmsg failed" ); |
1845 | assert!(!msg |
1846 | .flags |
1847 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
1848 | assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs" ); |
1849 | |
1850 | let mut rx_recvif = false; |
1851 | let mut rx_recvdstaddr = false; |
1852 | for cmsg in msg.cmsgs() { |
1853 | match cmsg { |
1854 | ControlMessageOwned::Ipv4RecvIf(dl) => { |
1855 | rx_recvif = true; |
1856 | let i = if_nametoindex(lo_name.as_bytes()) |
1857 | .expect("if_nametoindex" ); |
1858 | assert_eq!( |
1859 | dl.sdl_index as libc::c_uint, i, |
1860 | "unexpected ifindex (expected {}, got {})" , |
1861 | i, dl.sdl_index |
1862 | ); |
1863 | } |
1864 | ControlMessageOwned::Ipv4RecvDstAddr(addr) => { |
1865 | rx_recvdstaddr = true; |
1866 | if let Some(sin) = lo.as_sockaddr_in() { |
1867 | assert_eq!(sin.as_ref().sin_addr.s_addr, |
1868 | addr.s_addr, |
1869 | "unexpected destination address (expected {}, got {})" , |
1870 | sin.as_ref().sin_addr.s_addr, |
1871 | addr.s_addr); |
1872 | } else { |
1873 | panic!("unexpected Sockaddr" ); |
1874 | } |
1875 | } |
1876 | _ => panic!("unexpected additional control msg" ), |
1877 | } |
1878 | } |
1879 | assert!(rx_recvif); |
1880 | assert!(rx_recvdstaddr); |
1881 | assert_eq!(msg.bytes, 8); |
1882 | assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); |
1883 | } |
1884 | } |
1885 | |
1886 | #[cfg (any(target_os = "android" , target_os = "freebsd" , target_os = "linux" ))] |
1887 | #[cfg_attr (qemu, ignore)] |
1888 | #[test] |
1889 | pub fn test_recvif_ipv4() { |
1890 | use nix::sys::socket::sockopt::Ipv4OrigDstAddr; |
1891 | use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; |
1892 | use nix::sys::socket::{getsockname, setsockopt, socket}; |
1893 | use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; |
1894 | use std::io::{IoSlice, IoSliceMut}; |
1895 | |
1896 | let lo_ifaddr = loopback_address(AddressFamily::Inet); |
1897 | let (_lo_name, lo) = match lo_ifaddr { |
1898 | Some(ifaddr) => ( |
1899 | ifaddr.interface_name, |
1900 | ifaddr.address.expect("Expect IPv4 address on interface" ), |
1901 | ), |
1902 | None => return, |
1903 | }; |
1904 | let receive = socket( |
1905 | AddressFamily::Inet, |
1906 | SockType::Datagram, |
1907 | SockFlag::empty(), |
1908 | None, |
1909 | ) |
1910 | .expect("receive socket failed" ); |
1911 | bind(receive.as_raw_fd(), &lo).expect("bind failed" ); |
1912 | let sa: SockaddrIn = |
1913 | getsockname(receive.as_raw_fd()).expect("getsockname failed" ); |
1914 | setsockopt(&receive, Ipv4OrigDstAddr, &true) |
1915 | .expect("setsockopt IP_ORIGDSTADDR failed" ); |
1916 | |
1917 | { |
1918 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
1919 | let iov = [IoSlice::new(&slice)]; |
1920 | |
1921 | let send = socket( |
1922 | AddressFamily::Inet, |
1923 | SockType::Datagram, |
1924 | SockFlag::empty(), |
1925 | None, |
1926 | ) |
1927 | .expect("send socket failed" ); |
1928 | sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) |
1929 | .expect("sendmsg failed" ); |
1930 | } |
1931 | |
1932 | { |
1933 | let mut buf = [0u8; 8]; |
1934 | let mut iovec = [IoSliceMut::new(&mut buf)]; |
1935 | let mut space = cmsg_space!(libc::sockaddr_in); |
1936 | let msg = recvmsg::<()>( |
1937 | receive.as_raw_fd(), |
1938 | &mut iovec, |
1939 | Some(&mut space), |
1940 | MsgFlags::empty(), |
1941 | ) |
1942 | .expect("recvmsg failed" ); |
1943 | assert!(!msg |
1944 | .flags |
1945 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
1946 | assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs" ); |
1947 | |
1948 | let mut rx_recvorigdstaddr = false; |
1949 | for cmsg in msg.cmsgs() { |
1950 | match cmsg { |
1951 | ControlMessageOwned::Ipv4OrigDstAddr(addr) => { |
1952 | rx_recvorigdstaddr = true; |
1953 | if let Some(sin) = lo.as_sockaddr_in() { |
1954 | assert_eq!(sin.as_ref().sin_addr.s_addr, |
1955 | addr.sin_addr.s_addr, |
1956 | "unexpected destination address (expected {}, got {})" , |
1957 | sin.as_ref().sin_addr.s_addr, |
1958 | addr.sin_addr.s_addr); |
1959 | } else { |
1960 | panic!("unexpected Sockaddr" ); |
1961 | } |
1962 | } |
1963 | _ => panic!("unexpected additional control msg" ), |
1964 | } |
1965 | } |
1966 | assert!(rx_recvorigdstaddr); |
1967 | assert_eq!(msg.bytes, 8); |
1968 | assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); |
1969 | } |
1970 | } |
1971 | |
1972 | #[cfg (any(target_os = "android" , target_os = "freebsd" , target_os = "linux" ))] |
1973 | #[cfg_attr (qemu, ignore)] |
1974 | #[test] |
1975 | pub fn test_recvif_ipv6() { |
1976 | use nix::sys::socket::sockopt::Ipv6OrigDstAddr; |
1977 | use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; |
1978 | use nix::sys::socket::{getsockname, setsockopt, socket}; |
1979 | use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; |
1980 | use std::io::{IoSlice, IoSliceMut}; |
1981 | |
1982 | let lo_ifaddr = loopback_address(AddressFamily::Inet6); |
1983 | let (_lo_name, lo) = match lo_ifaddr { |
1984 | Some(ifaddr) => ( |
1985 | ifaddr.interface_name, |
1986 | ifaddr.address.expect("Expect IPv6 address on interface" ), |
1987 | ), |
1988 | None => return, |
1989 | }; |
1990 | let receive = socket( |
1991 | AddressFamily::Inet6, |
1992 | SockType::Datagram, |
1993 | SockFlag::empty(), |
1994 | None, |
1995 | ) |
1996 | .expect("receive socket failed" ); |
1997 | bind(receive.as_raw_fd(), &lo).expect("bind failed" ); |
1998 | let sa: SockaddrIn6 = |
1999 | getsockname(receive.as_raw_fd()).expect("getsockname failed" ); |
2000 | setsockopt(&receive, Ipv6OrigDstAddr, &true) |
2001 | .expect("setsockopt IP_ORIGDSTADDR failed" ); |
2002 | |
2003 | { |
2004 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
2005 | let iov = [IoSlice::new(&slice)]; |
2006 | |
2007 | let send = socket( |
2008 | AddressFamily::Inet6, |
2009 | SockType::Datagram, |
2010 | SockFlag::empty(), |
2011 | None, |
2012 | ) |
2013 | .expect("send socket failed" ); |
2014 | sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) |
2015 | .expect("sendmsg failed" ); |
2016 | } |
2017 | |
2018 | { |
2019 | let mut buf = [0u8; 8]; |
2020 | let mut iovec = [IoSliceMut::new(&mut buf)]; |
2021 | let mut space = cmsg_space!(libc::sockaddr_in6); |
2022 | let msg = recvmsg::<()>( |
2023 | receive.as_raw_fd(), |
2024 | &mut iovec, |
2025 | Some(&mut space), |
2026 | MsgFlags::empty(), |
2027 | ) |
2028 | .expect("recvmsg failed" ); |
2029 | assert!(!msg |
2030 | .flags |
2031 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
2032 | assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs" ); |
2033 | |
2034 | let mut rx_recvorigdstaddr = false; |
2035 | for cmsg in msg.cmsgs() { |
2036 | match cmsg { |
2037 | ControlMessageOwned::Ipv6OrigDstAddr(addr) => { |
2038 | rx_recvorigdstaddr = true; |
2039 | if let Some(sin) = lo.as_sockaddr_in6() { |
2040 | assert_eq!(sin.as_ref().sin6_addr.s6_addr, |
2041 | addr.sin6_addr.s6_addr, |
2042 | "unexpected destination address (expected {:?}, got {:?})" , |
2043 | sin.as_ref().sin6_addr.s6_addr, |
2044 | addr.sin6_addr.s6_addr); |
2045 | } else { |
2046 | panic!("unexpected Sockaddr" ); |
2047 | } |
2048 | } |
2049 | _ => panic!("unexpected additional control msg" ), |
2050 | } |
2051 | } |
2052 | assert!(rx_recvorigdstaddr); |
2053 | assert_eq!(msg.bytes, 8); |
2054 | assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); |
2055 | } |
2056 | } |
2057 | |
2058 | #[cfg (any( |
2059 | target_os = "android" , |
2060 | target_os = "freebsd" , |
2061 | target_os = "ios" , |
2062 | target_os = "linux" , |
2063 | target_os = "macos" , |
2064 | target_os = "netbsd" , |
2065 | target_os = "openbsd" , |
2066 | ))] |
2067 | // qemu doesn't seem to be emulating this correctly in these architectures |
2068 | #[cfg_attr ( |
2069 | all( |
2070 | qemu, |
2071 | any( |
2072 | target_arch = "mips" , |
2073 | target_arch = "mips64" , |
2074 | target_arch = "powerpc64" , |
2075 | ) |
2076 | ), |
2077 | ignore |
2078 | )] |
2079 | #[test] |
2080 | pub fn test_recv_ipv6pktinfo() { |
2081 | use nix::net::if_::*; |
2082 | use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; |
2083 | use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; |
2084 | use nix::sys::socket::{getsockname, setsockopt, socket}; |
2085 | use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; |
2086 | use std::io::{IoSlice, IoSliceMut}; |
2087 | |
2088 | let lo_ifaddr = loopback_address(AddressFamily::Inet6); |
2089 | let (lo_name, lo) = match lo_ifaddr { |
2090 | Some(ifaddr) => ( |
2091 | ifaddr.interface_name, |
2092 | ifaddr.address.expect("Expect IPv6 address on interface" ), |
2093 | ), |
2094 | None => return, |
2095 | }; |
2096 | let receive = socket( |
2097 | AddressFamily::Inet6, |
2098 | SockType::Datagram, |
2099 | SockFlag::empty(), |
2100 | None, |
2101 | ) |
2102 | .expect("receive socket failed" ); |
2103 | bind(receive.as_raw_fd(), &lo).expect("bind failed" ); |
2104 | let sa: SockaddrIn6 = |
2105 | getsockname(receive.as_raw_fd()).expect("getsockname failed" ); |
2106 | setsockopt(&receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed" ); |
2107 | |
2108 | { |
2109 | let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; |
2110 | let iov = [IoSlice::new(&slice)]; |
2111 | |
2112 | let send = socket( |
2113 | AddressFamily::Inet6, |
2114 | SockType::Datagram, |
2115 | SockFlag::empty(), |
2116 | None, |
2117 | ) |
2118 | .expect("send socket failed" ); |
2119 | sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) |
2120 | .expect("sendmsg failed" ); |
2121 | } |
2122 | |
2123 | { |
2124 | let mut buf = [0u8; 8]; |
2125 | let mut iovec = [IoSliceMut::new(&mut buf)]; |
2126 | |
2127 | let mut space = cmsg_space!(libc::in6_pktinfo); |
2128 | let msg = recvmsg::<()>( |
2129 | receive.as_raw_fd(), |
2130 | &mut iovec, |
2131 | Some(&mut space), |
2132 | MsgFlags::empty(), |
2133 | ) |
2134 | .expect("recvmsg failed" ); |
2135 | assert!(!msg |
2136 | .flags |
2137 | .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); |
2138 | |
2139 | let mut cmsgs = msg.cmsgs(); |
2140 | if let Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) = cmsgs.next() |
2141 | { |
2142 | let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex" ); |
2143 | assert_eq!( |
2144 | pktinfo.ipi6_ifindex as libc::c_uint, i, |
2145 | "unexpected ifindex (expected {}, got {})" , |
2146 | i, pktinfo.ipi6_ifindex |
2147 | ); |
2148 | } |
2149 | assert!(cmsgs.next().is_none(), "unexpected additional control msg" ); |
2150 | assert_eq!(msg.bytes, 8); |
2151 | assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); |
2152 | } |
2153 | } |
2154 | |
2155 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
2156 | #[test] |
2157 | pub fn test_vsock() { |
2158 | use nix::sys::socket::SockaddrLike; |
2159 | use nix::sys::socket::{AddressFamily, VsockAddr}; |
2160 | use std::mem; |
2161 | |
2162 | let port: u32 = 3000; |
2163 | |
2164 | let addr_local = VsockAddr::new(libc::VMADDR_CID_LOCAL, port); |
2165 | assert_eq!(addr_local.cid(), libc::VMADDR_CID_LOCAL); |
2166 | assert_eq!(addr_local.port(), port); |
2167 | |
2168 | let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY); |
2169 | assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY); |
2170 | assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY); |
2171 | |
2172 | assert_ne!(addr_local, addr_any); |
2173 | assert_ne!(calculate_hash(&addr_local), calculate_hash(&addr_any)); |
2174 | |
2175 | let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port); |
2176 | let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port); |
2177 | assert_eq!(addr1, addr2); |
2178 | assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); |
2179 | |
2180 | let addr3 = unsafe { |
2181 | VsockAddr::from_raw( |
2182 | addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr, |
2183 | Some(mem::size_of::<libc::sockaddr_vm>().try_into().unwrap()), |
2184 | ) |
2185 | } |
2186 | .unwrap(); |
2187 | assert_eq!( |
2188 | addr3.as_ref().svm_family, |
2189 | AddressFamily::Vsock as libc::sa_family_t |
2190 | ); |
2191 | assert_eq!(addr3.as_ref().svm_cid, addr1.cid()); |
2192 | assert_eq!(addr3.as_ref().svm_port, addr1.port()); |
2193 | } |
2194 | |
2195 | #[cfg (target_os = "macos" )] |
2196 | #[test] |
2197 | pub fn test_vsock() { |
2198 | use nix::sys::socket::SockaddrLike; |
2199 | use nix::sys::socket::{AddressFamily, VsockAddr}; |
2200 | use std::mem; |
2201 | |
2202 | let port: u32 = 3000; |
2203 | |
2204 | // macOS doesn't have a VMADDR_CID_LOCAL, so test with host again |
2205 | let addr_host = VsockAddr::new(libc::VMADDR_CID_HOST, port); |
2206 | assert_eq!(addr_host.cid(), libc::VMADDR_CID_HOST); |
2207 | assert_eq!(addr_host.port(), port); |
2208 | |
2209 | let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY); |
2210 | assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY); |
2211 | assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY); |
2212 | |
2213 | assert_ne!(addr_host, addr_any); |
2214 | assert_ne!(calculate_hash(&addr_host), calculate_hash(&addr_any)); |
2215 | |
2216 | let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port); |
2217 | let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port); |
2218 | assert_eq!(addr1, addr2); |
2219 | assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); |
2220 | |
2221 | let addr3 = unsafe { |
2222 | VsockAddr::from_raw( |
2223 | addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr, |
2224 | Some(mem::size_of::<libc::sockaddr_vm>().try_into().unwrap()), |
2225 | ) |
2226 | } |
2227 | .unwrap(); |
2228 | assert_eq!( |
2229 | addr3.as_ref().svm_family, |
2230 | AddressFamily::Vsock as libc::sa_family_t |
2231 | ); |
2232 | let cid = addr3.as_ref().svm_cid; |
2233 | let port = addr3.as_ref().svm_port; |
2234 | assert_eq!(cid, addr1.cid()); |
2235 | assert_eq!(port, addr1.port()); |
2236 | } |
2237 | |
2238 | // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack |
2239 | // of QEMU support is suspected. |
2240 | #[cfg_attr (qemu, ignore)] |
2241 | #[cfg (target_os = "linux" )] |
2242 | #[test] |
2243 | fn test_recvmsg_timestampns() { |
2244 | use nix::sys::socket::*; |
2245 | use nix::sys::time::*; |
2246 | use std::io::{IoSlice, IoSliceMut}; |
2247 | use std::time::*; |
2248 | |
2249 | // Set up |
2250 | let message = "Ohayō!" .as_bytes(); |
2251 | let in_socket = socket( |
2252 | AddressFamily::Inet, |
2253 | SockType::Datagram, |
2254 | SockFlag::empty(), |
2255 | None, |
2256 | ) |
2257 | .unwrap(); |
2258 | setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); |
2259 | let localhost = SockaddrIn::new(127, 0, 0, 1, 0); |
2260 | bind(in_socket.as_raw_fd(), &localhost).unwrap(); |
2261 | let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap(); |
2262 | // Get initial time |
2263 | let time0 = SystemTime::now(); |
2264 | // Send the message |
2265 | let iov = [IoSlice::new(message)]; |
2266 | let flags = MsgFlags::empty(); |
2267 | let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address)) |
2268 | .unwrap(); |
2269 | assert_eq!(message.len(), l); |
2270 | // Receive the message |
2271 | let mut buffer = vec![0u8; message.len()]; |
2272 | let mut cmsgspace = nix::cmsg_space!(TimeSpec); |
2273 | |
2274 | let mut iov = [IoSliceMut::new(&mut buffer)]; |
2275 | let r = recvmsg::<()>( |
2276 | in_socket.as_raw_fd(), |
2277 | &mut iov, |
2278 | Some(&mut cmsgspace), |
2279 | flags, |
2280 | ) |
2281 | .unwrap(); |
2282 | let rtime = match r.cmsgs().next() { |
2283 | Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, |
2284 | Some(_) => panic!("Unexpected control message" ), |
2285 | None => panic!("No control message" ), |
2286 | }; |
2287 | // Check the final time |
2288 | let time1 = SystemTime::now(); |
2289 | // the packet's received timestamp should lie in-between the two system |
2290 | // times, unless the system clock was adjusted in the meantime. |
2291 | let rduration = |
2292 | Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); |
2293 | assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); |
2294 | assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); |
2295 | } |
2296 | |
2297 | // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack |
2298 | // of QEMU support is suspected. |
2299 | #[cfg_attr (qemu, ignore)] |
2300 | #[cfg (target_os = "linux" )] |
2301 | #[test] |
2302 | fn test_recvmmsg_timestampns() { |
2303 | use nix::sys::socket::*; |
2304 | use nix::sys::time::*; |
2305 | use std::io::{IoSlice, IoSliceMut}; |
2306 | use std::time::*; |
2307 | |
2308 | // Set up |
2309 | let message = "Ohayō!" .as_bytes(); |
2310 | let in_socket = socket( |
2311 | AddressFamily::Inet, |
2312 | SockType::Datagram, |
2313 | SockFlag::empty(), |
2314 | None, |
2315 | ) |
2316 | .unwrap(); |
2317 | setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); |
2318 | let localhost = SockaddrIn::from_str("127.0.0.1:0" ).unwrap(); |
2319 | bind(in_socket.as_raw_fd(), &localhost).unwrap(); |
2320 | let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap(); |
2321 | // Get initial time |
2322 | let time0 = SystemTime::now(); |
2323 | // Send the message |
2324 | let iov = [IoSlice::new(message)]; |
2325 | let flags = MsgFlags::empty(); |
2326 | let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address)) |
2327 | .unwrap(); |
2328 | assert_eq!(message.len(), l); |
2329 | // Receive the message |
2330 | let mut buffer = vec![0u8; message.len()]; |
2331 | let cmsgspace = nix::cmsg_space!(TimeSpec); |
2332 | let iov = vec![[IoSliceMut::new(&mut buffer)]]; |
2333 | let mut data = MultiHeaders::preallocate(1, Some(cmsgspace)); |
2334 | let r: Vec<RecvMsg<()>> = |
2335 | recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None) |
2336 | .unwrap() |
2337 | .collect(); |
2338 | let rtime = match r[0].cmsgs().next() { |
2339 | Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, |
2340 | Some(_) => panic!("Unexpected control message" ), |
2341 | None => panic!("No control message" ), |
2342 | }; |
2343 | // Check the final time |
2344 | let time1 = SystemTime::now(); |
2345 | // the packet's received timestamp should lie in-between the two system |
2346 | // times, unless the system clock was adjusted in the meantime. |
2347 | let rduration = |
2348 | Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); |
2349 | assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); |
2350 | assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); |
2351 | } |
2352 | |
2353 | // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack |
2354 | // of QEMU support is suspected. |
2355 | #[cfg_attr (qemu, ignore)] |
2356 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ))] |
2357 | #[test] |
2358 | fn test_recvmsg_rxq_ovfl() { |
2359 | use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl}; |
2360 | use nix::sys::socket::*; |
2361 | use nix::Error; |
2362 | use std::io::{IoSlice, IoSliceMut}; |
2363 | |
2364 | let message = [0u8; 2048]; |
2365 | let bufsize = message.len() * 2; |
2366 | |
2367 | let in_socket = socket( |
2368 | AddressFamily::Inet, |
2369 | SockType::Datagram, |
2370 | SockFlag::empty(), |
2371 | None, |
2372 | ) |
2373 | .unwrap(); |
2374 | let out_socket = socket( |
2375 | AddressFamily::Inet, |
2376 | SockType::Datagram, |
2377 | SockFlag::empty(), |
2378 | None, |
2379 | ) |
2380 | .unwrap(); |
2381 | |
2382 | let localhost = SockaddrIn::from_str("127.0.0.1:0" ).unwrap(); |
2383 | bind(in_socket.as_raw_fd(), &localhost).unwrap(); |
2384 | |
2385 | let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap(); |
2386 | connect(out_socket.as_raw_fd(), &address).unwrap(); |
2387 | |
2388 | // Set SO_RXQ_OVFL flag. |
2389 | setsockopt(&in_socket, RxqOvfl, &1).unwrap(); |
2390 | |
2391 | // Set the receiver buffer size to hold only 2 messages. |
2392 | setsockopt(&in_socket, RcvBuf, &bufsize).unwrap(); |
2393 | |
2394 | let mut drop_counter = 0; |
2395 | |
2396 | for _ in 0..2 { |
2397 | let iov = [IoSlice::new(&message)]; |
2398 | let flags = MsgFlags::empty(); |
2399 | |
2400 | // Send the 3 messages (the receiver buffer can only hold 2 messages) |
2401 | // to create an overflow. |
2402 | for _ in 0..3 { |
2403 | let l = sendmsg( |
2404 | out_socket.as_raw_fd(), |
2405 | &iov, |
2406 | &[], |
2407 | flags, |
2408 | Some(&address), |
2409 | ) |
2410 | .unwrap(); |
2411 | assert_eq!(message.len(), l); |
2412 | } |
2413 | |
2414 | // Receive the message and check the drop counter if any. |
2415 | loop { |
2416 | let mut buffer = vec![0u8; message.len()]; |
2417 | let mut cmsgspace = nix::cmsg_space!(u32); |
2418 | |
2419 | let mut iov = [IoSliceMut::new(&mut buffer)]; |
2420 | |
2421 | match recvmsg::<()>( |
2422 | in_socket.as_raw_fd(), |
2423 | &mut iov, |
2424 | Some(&mut cmsgspace), |
2425 | MsgFlags::MSG_DONTWAIT, |
2426 | ) { |
2427 | Ok(r) => { |
2428 | drop_counter = match r.cmsgs().next() { |
2429 | Some(ControlMessageOwned::RxqOvfl(drop_counter)) => { |
2430 | drop_counter |
2431 | } |
2432 | Some(_) => panic!("Unexpected control message" ), |
2433 | None => 0, |
2434 | }; |
2435 | } |
2436 | Err(Error::EAGAIN) => { |
2437 | break; |
2438 | } |
2439 | _ => { |
2440 | panic!("unknown recvmsg() error" ); |
2441 | } |
2442 | } |
2443 | } |
2444 | } |
2445 | |
2446 | // One packet lost. |
2447 | assert_eq!(drop_counter, 1); |
2448 | } |
2449 | |
2450 | #[cfg (any(target_os = "linux" , target_os = "android" ,))] |
2451 | mod linux_errqueue { |
2452 | use super::FromStr; |
2453 | use nix::sys::socket::*; |
2454 | use std::os::unix::io::AsRawFd; |
2455 | |
2456 | // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). |
2457 | // |
2458 | // Disable the test on QEMU because QEMU emulation of IP_RECVERR is broken (as documented on PR |
2459 | // #1514). |
2460 | #[cfg_attr (qemu, ignore)] |
2461 | #[test] |
2462 | fn test_recverr_v4() { |
2463 | #[repr (u8)] |
2464 | enum IcmpTypes { |
2465 | DestUnreach = 3, // ICMP_DEST_UNREACH |
2466 | } |
2467 | #[repr (u8)] |
2468 | enum IcmpUnreachCodes { |
2469 | PortUnreach = 3, // ICMP_PORT_UNREACH |
2470 | } |
2471 | |
2472 | test_recverr_impl::<sockaddr_in, _, _>( |
2473 | "127.0.0.1:6800" , |
2474 | AddressFamily::Inet, |
2475 | sockopt::Ipv4RecvErr, |
2476 | libc::SO_EE_ORIGIN_ICMP, |
2477 | IcmpTypes::DestUnreach as u8, |
2478 | IcmpUnreachCodes::PortUnreach as u8, |
2479 | // Closure handles protocol-specific testing and returns generic sock_extended_err for |
2480 | // protocol-independent test impl. |
2481 | |cmsg| { |
2482 | if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) = |
2483 | cmsg |
2484 | { |
2485 | if let Some(origin) = err_addr { |
2486 | // Validate that our network error originated from 127.0.0.1:0. |
2487 | assert_eq!(origin.sin_family, AddressFamily::Inet as _); |
2488 | assert_eq!( |
2489 | origin.sin_addr.s_addr, |
2490 | u32::from_be(0x7f000001) |
2491 | ); |
2492 | assert_eq!(origin.sin_port, 0); |
2493 | } else { |
2494 | panic!("Expected some error origin" ); |
2495 | } |
2496 | *ext_err |
2497 | } else { |
2498 | panic!("Unexpected control message {cmsg:?}" ); |
2499 | } |
2500 | }, |
2501 | ) |
2502 | } |
2503 | |
2504 | // Essentially the same test as v4. |
2505 | // |
2506 | // Disable the test on QEMU because QEMU emulation of IPV6_RECVERR is broken (as documented on |
2507 | // PR #1514). |
2508 | #[cfg_attr (qemu, ignore)] |
2509 | #[test] |
2510 | fn test_recverr_v6() { |
2511 | #[repr (u8)] |
2512 | enum IcmpV6Types { |
2513 | DestUnreach = 1, // ICMPV6_DEST_UNREACH |
2514 | } |
2515 | #[repr (u8)] |
2516 | enum IcmpV6UnreachCodes { |
2517 | PortUnreach = 4, // ICMPV6_PORT_UNREACH |
2518 | } |
2519 | |
2520 | test_recverr_impl::<sockaddr_in6, _, _>( |
2521 | "[::1]:6801" , |
2522 | AddressFamily::Inet6, |
2523 | sockopt::Ipv6RecvErr, |
2524 | libc::SO_EE_ORIGIN_ICMP6, |
2525 | IcmpV6Types::DestUnreach as u8, |
2526 | IcmpV6UnreachCodes::PortUnreach as u8, |
2527 | // Closure handles protocol-specific testing and returns generic sock_extended_err for |
2528 | // protocol-independent test impl. |
2529 | |cmsg| { |
2530 | if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) = |
2531 | cmsg |
2532 | { |
2533 | if let Some(origin) = err_addr { |
2534 | // Validate that our network error originated from localhost:0. |
2535 | assert_eq!( |
2536 | origin.sin6_family, |
2537 | AddressFamily::Inet6 as _ |
2538 | ); |
2539 | assert_eq!( |
2540 | origin.sin6_addr.s6_addr, |
2541 | std::net::Ipv6Addr::LOCALHOST.octets() |
2542 | ); |
2543 | assert_eq!(origin.sin6_port, 0); |
2544 | } else { |
2545 | panic!("Expected some error origin" ); |
2546 | } |
2547 | *ext_err |
2548 | } else { |
2549 | panic!("Unexpected control message {cmsg:?}" ); |
2550 | } |
2551 | }, |
2552 | ) |
2553 | } |
2554 | |
2555 | fn test_recverr_impl<SA, OPT, TESTF>( |
2556 | sa: &str, |
2557 | af: AddressFamily, |
2558 | opt: OPT, |
2559 | ee_origin: u8, |
2560 | ee_type: u8, |
2561 | ee_code: u8, |
2562 | testf: TESTF, |
2563 | ) where |
2564 | OPT: SetSockOpt<Val = bool>, |
2565 | TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err, |
2566 | { |
2567 | use nix::errno::Errno; |
2568 | use std::io::IoSliceMut; |
2569 | |
2570 | const MESSAGE_CONTENTS: &str = "ABCDEF" ; |
2571 | let std_sa = std::net::SocketAddr::from_str(sa).unwrap(); |
2572 | let sock_addr = SockaddrStorage::from(std_sa); |
2573 | let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None) |
2574 | .unwrap(); |
2575 | setsockopt(&sock, opt, &true).unwrap(); |
2576 | if let Err(e) = sendto( |
2577 | sock.as_raw_fd(), |
2578 | MESSAGE_CONTENTS.as_bytes(), |
2579 | &sock_addr, |
2580 | MsgFlags::empty(), |
2581 | ) { |
2582 | assert_eq!(e, Errno::EADDRNOTAVAIL); |
2583 | println!("{af:?} not available, skipping test." ); |
2584 | return; |
2585 | } |
2586 | |
2587 | let mut buf = [0u8; 8]; |
2588 | let mut iovec = [IoSliceMut::new(&mut buf)]; |
2589 | let mut cspace = cmsg_space!(libc::sock_extended_err, SA); |
2590 | |
2591 | let msg = recvmsg( |
2592 | sock.as_raw_fd(), |
2593 | &mut iovec, |
2594 | Some(&mut cspace), |
2595 | MsgFlags::MSG_ERRQUEUE, |
2596 | ) |
2597 | .unwrap(); |
2598 | // The sent message / destination associated with the error is returned: |
2599 | assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len()); |
2600 | // recvmsg(2): "The original destination address of the datagram that caused the error is |
2601 | // supplied via msg_name;" however, this is not literally true. E.g., an earlier version |
2602 | // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into |
2603 | // 127.0.0.1 (::1). |
2604 | assert_eq!(msg.address, Some(sock_addr)); |
2605 | |
2606 | // Check for expected control message. |
2607 | let ext_err = match msg.cmsgs().next() { |
2608 | Some(cmsg) => testf(&cmsg), |
2609 | None => panic!("No control message" ), |
2610 | }; |
2611 | |
2612 | assert_eq!(ext_err.ee_errno, libc::ECONNREFUSED as u32); |
2613 | assert_eq!(ext_err.ee_origin, ee_origin); |
2614 | // ip(7): ee_type and ee_code are set from the type and code fields of the ICMP (ICMPv6) |
2615 | // header. |
2616 | assert_eq!(ext_err.ee_type, ee_type); |
2617 | assert_eq!(ext_err.ee_code, ee_code); |
2618 | // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors. |
2619 | assert_eq!(ext_err.ee_info, 0); |
2620 | |
2621 | let bytes = msg.bytes; |
2622 | assert_eq!(&buf[..bytes], MESSAGE_CONTENTS.as_bytes()); |
2623 | } |
2624 | } |
2625 | |
2626 | // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack |
2627 | // of QEMU support is suspected. |
2628 | #[cfg_attr (qemu, ignore)] |
2629 | #[cfg (target_os = "linux" )] |
2630 | #[test] |
2631 | pub fn test_txtime() { |
2632 | use nix::sys::socket::{ |
2633 | bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage, |
2634 | MsgFlags, SockFlag, SockType, SockaddrIn, |
2635 | }; |
2636 | use nix::sys::time::TimeValLike; |
2637 | use nix::time::{clock_gettime, ClockId}; |
2638 | |
2639 | require_kernel_version!(test_txtime, ">= 5.8" ); |
2640 | |
2641 | let sock_addr = SockaddrIn::from_str("127.0.0.1:6802" ).unwrap(); |
2642 | |
2643 | let ssock = socket( |
2644 | AddressFamily::Inet, |
2645 | SockType::Datagram, |
2646 | SockFlag::empty(), |
2647 | None, |
2648 | ) |
2649 | .expect("send socket failed" ); |
2650 | |
2651 | let txtime_cfg = libc::sock_txtime { |
2652 | clockid: libc::CLOCK_MONOTONIC, |
2653 | flags: 0, |
2654 | }; |
2655 | setsockopt(&ssock, sockopt::TxTime, &txtime_cfg).unwrap(); |
2656 | |
2657 | let rsock = socket( |
2658 | AddressFamily::Inet, |
2659 | SockType::Datagram, |
2660 | SockFlag::empty(), |
2661 | None, |
2662 | ) |
2663 | .unwrap(); |
2664 | bind(rsock.as_raw_fd(), &sock_addr).unwrap(); |
2665 | |
2666 | let sbuf = [0u8; 2048]; |
2667 | let iov1 = [std::io::IoSlice::new(&sbuf)]; |
2668 | |
2669 | let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap(); |
2670 | let delay = std::time::Duration::from_secs(1).into(); |
2671 | let txtime = (now + delay).num_nanoseconds() as u64; |
2672 | |
2673 | let cmsg = ControlMessage::TxTime(&txtime); |
2674 | sendmsg( |
2675 | ssock.as_raw_fd(), |
2676 | &iov1, |
2677 | &[cmsg], |
2678 | MsgFlags::empty(), |
2679 | Some(&sock_addr), |
2680 | ) |
2681 | .unwrap(); |
2682 | |
2683 | let mut rbuf = [0u8; 2048]; |
2684 | let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)]; |
2685 | recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty()) |
2686 | .unwrap(); |
2687 | } |
2688 | |