• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::io;
6 use std::mem::size_of;
7 use std::net::SocketAddrV4;
8 use std::net::SocketAddrV6;
9 use std::os::unix::ffi::OsStrExt;
10 use std::os::unix::net::UnixDatagram;
11 use std::os::unix::net::UnixListener;
12 use std::os::unix::net::UnixStream;
13 use std::path::Path;
14 use std::ptr::null_mut;
15 
16 use libc::c_int;
17 use libc::c_void;
18 use libc::close;
19 use libc::fcntl;
20 use libc::in6_addr;
21 use libc::in_addr;
22 use libc::sa_family_t;
23 use libc::setsockopt;
24 use libc::sockaddr_in;
25 use libc::sockaddr_in6;
26 use libc::socklen_t;
27 use libc::AF_INET;
28 use libc::AF_INET6;
29 use libc::FD_CLOEXEC;
30 use libc::F_SETFD;
31 use libc::SOCK_STREAM;
32 use libc::SOL_SOCKET;
33 use libc::SO_NOSIGPIPE;
34 
35 use crate::unix::net::socket;
36 use crate::unix::net::socketpair;
37 use crate::unix::net::sun_path_offset;
38 use crate::unix::net::InetVersion;
39 use crate::unix::net::TcpSocket;
40 use crate::AsRawDescriptor;
41 use crate::FromRawDescriptor;
42 use crate::SafeDescriptor;
43 use crate::ScmSocket;
44 use crate::UnixSeqpacket;
45 use crate::UnixSeqpacketListener;
46 
47 macro_rules! ScmSocketTryFrom {
48     ($name:ident) => {
49         impl TryFrom<$name> for ScmSocket<$name> {
50             type Error = io::Error;
51 
52             fn try_from(socket: $name) -> io::Result<Self> {
53                 let set = 1;
54                 let set_ptr = &set as *const c_int as *const c_void;
55                 let size = size_of::<c_int>() as socklen_t;
56                 // SAFETY:  because we are taking ownership of the file descriptor, and `set_ptr`
57                 // has at least `size` data available.
58                 let res = unsafe {
59                     setsockopt(
60                         socket.as_raw_descriptor(),
61                         SOL_SOCKET,
62                         SO_NOSIGPIPE,
63                         set_ptr,
64                         size,
65                     )
66                 };
67                 if res < 0 {
68                     Err(io::Error::last_os_error())
69                 } else {
70                     Ok(ScmSocket { socket })
71                 }
72             }
73         }
74     };
75 }
76 
77 ScmSocketTryFrom!(UnixDatagram);
78 ScmSocketTryFrom!(UnixListener);
79 ScmSocketTryFrom!(UnixSeqpacket);
80 ScmSocketTryFrom!(UnixStream);
81 
sockaddrv4_to_lib_c(s: &SocketAddrV4) -> sockaddr_in82 pub(crate) fn sockaddrv4_to_lib_c(s: &SocketAddrV4) -> sockaddr_in {
83     sockaddr_in {
84         sin_family: AF_INET as sa_family_t,
85         sin_port: s.port().to_be(),
86         sin_addr: in_addr {
87             s_addr: u32::from_ne_bytes(s.ip().octets()),
88         },
89         sin_zero: [0; 8],
90         sin_len: size_of::<sockaddr_in>() as u8,
91     }
92 }
93 
sockaddrv6_to_lib_c(s: &SocketAddrV6) -> sockaddr_in694 pub(crate) fn sockaddrv6_to_lib_c(s: &SocketAddrV6) -> sockaddr_in6 {
95     sockaddr_in6 {
96         sin6_family: AF_INET6 as sa_family_t,
97         sin6_port: s.port().to_be(),
98         sin6_flowinfo: 0,
99         sin6_addr: in6_addr {
100             s6_addr: s.ip().octets(),
101         },
102         sin6_scope_id: 0,
103         sin6_len: size_of::<sockaddr_in6>() as u8,
104     }
105 }
106 
cloexec_or_close<Raw: AsRawDescriptor>(raw: Raw) -> io::Result<Raw>107 fn cloexec_or_close<Raw: AsRawDescriptor>(raw: Raw) -> io::Result<Raw> {
108     // SAFETY: `raw` owns a file descriptor, there are no actions with memory. This potentially
109     // races with `fork()` calls in other threads, but on MacOS it's the best we have.
110     let res = unsafe { fcntl(raw.as_raw_descriptor(), F_SETFD, FD_CLOEXEC) };
111     if res >= 0 {
112         Ok(raw)
113     } else {
114         let err = io::Error::last_os_error();
115         // SAFETY: `raw` owns this file descriptor.
116         unsafe { close(raw.as_raw_descriptor()) };
117         Err(err)
118     }
119 }
120 
121 // Return `sockaddr_un` for a given `path`
sockaddr_un<P: AsRef<Path>>( path: P, ) -> io::Result<(libc::sockaddr_un, libc::socklen_t)>122 pub(in crate::sys) fn sockaddr_un<P: AsRef<Path>>(
123     path: P,
124 ) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
125     let mut addr = libc::sockaddr_un {
126         sun_family: libc::AF_UNIX as libc::sa_family_t,
127         sun_path: std::array::from_fn(|_| 0),
128         sun_len: 0,
129     };
130 
131     // Check if the input path is valid. Since
132     // * The pathname in sun_path should be null-terminated.
133     // * The length of the pathname, including the terminating null byte, should not exceed the size
134     //   of sun_path.
135     //
136     // and our input is a `Path`, we only need to check
137     // * If the string size of `Path` should less than sizeof(sun_path)
138     // and make sure `sun_path` ends with '\0' by initialized the sun_path with zeros.
139     //
140     // Empty path name is valid since abstract socket address has sun_paht[0] = '\0'
141     let bytes = path.as_ref().as_os_str().as_bytes();
142     if bytes.len() >= addr.sun_path.len() {
143         return Err(io::Error::new(
144             io::ErrorKind::InvalidInput,
145             "Input path size should be less than the length of sun_path.",
146         ));
147     };
148 
149     // Copy data from `path` to `addr.sun_path`
150     for (dst, src) in addr.sun_path.iter_mut().zip(bytes) {
151         *dst = *src as libc::c_char;
152     }
153 
154     // The addrlen argument that describes the enclosing sockaddr_un structure
155     // should have a value of at least:
156     //
157     //     offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1
158     //
159     // or, more simply, addrlen can be specified as sizeof(struct sockaddr_un).
160     addr.sun_len = sun_path_offset() as u8 + bytes.len() as u8 + 1;
161     Ok((addr, addr.sun_len as libc::socklen_t))
162 }
163 
164 impl TcpSocket {
new(inet_version: InetVersion) -> io::Result<Self>165     pub fn new(inet_version: InetVersion) -> io::Result<Self> {
166         Ok(TcpSocket {
167             inet_version,
168             descriptor: cloexec_or_close(socket(
169                 Into::<sa_family_t>::into(inet_version) as libc::c_int,
170                 SOCK_STREAM,
171                 0,
172             )?)?,
173         })
174     }
175 }
176 
177 impl UnixSeqpacket {
178     /// Creates a pair of connected `SOCK_SEQPACKET` sockets.
179     ///
180     /// Both returned file descriptors have the `CLOEXEC` flag set.
pair() -> io::Result<(UnixSeqpacket, UnixSeqpacket)>181     pub fn pair() -> io::Result<(UnixSeqpacket, UnixSeqpacket)> {
182         let (fd0, fd1) = socketpair(libc::AF_UNIX, libc::SOCK_SEQPACKET, 0)?;
183         let (s0, s1) = (UnixSeqpacket::from(fd0), UnixSeqpacket::from(fd1));
184         Ok((cloexec_or_close(s0)?, cloexec_or_close(s1)?))
185     }
186 }
187 
188 impl UnixSeqpacketListener {
189     /// Blocks for and accepts a new incoming connection and returns the socket associated with that
190     /// connection.
191     ///
192     /// The returned socket has the close-on-exec flag set.
accept(&self) -> io::Result<UnixSeqpacket>193     pub fn accept(&self) -> io::Result<UnixSeqpacket> {
194         // SAFETY: we own this fd and the kernel will not write to null pointers.
195         let fd = unsafe { libc::accept(self.as_raw_descriptor(), null_mut(), null_mut()) };
196         match fd {
197             -1 => Err(io::Error::last_os_error()),
198             fd => {
199                 // SAFETY: we checked the return value of accept. Therefore, the return value
200                 // must be a valid socket.
201                 let safe_desc = unsafe { SafeDescriptor::from_raw_descriptor(fd) };
202                 Ok(UnixSeqpacket::from(cloexec_or_close(safe_desc)?))
203             }
204         }
205     }
206 }
207