xref: /drstd/src/std/os/unix/net/addr.rs (revision 9670759b785600bf6315e4173e46a602f16add7a)
1 use crate::std::ffi::OsStr;
2 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
3 use crate::std::os::net::linux_ext;
4 use crate::std::os::unix::ffi::OsStrExt;
5 use crate::std::path::Path;
6 use crate::std::sealed::Sealed;
7 use crate::std::sys::cvt;
8 use crate::std::{fmt, io, mem, ptr};
9 use dlibc;
10 
11 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
12 // #[cfg(not(unix))]
13 // #[allow(non_camel_case_types)]
14 // mod libc {
15 //     pub use dlibc::c_int;
16 //     pub type socklen_t = u32;
17 //     pub struct sockaddr;
18 //     #[derive(Clone)]
19 //     pub struct sockaddr_un;
20 // }
21 
sun_path_offset(addr: &dlibc::sockaddr_un) -> usize22 fn sun_path_offset(addr: &dlibc::sockaddr_un) -> usize {
23     // Work with an actual instance of the type since using a null pointer is UB
24     let base = (addr as *const dlibc::sockaddr_un).addr();
25     let path = (&addr.sun_path as *const dlibc::c_char).addr();
26     path - base
27 }
28 
sockaddr_un(path: &Path) -> io::Result<(dlibc::sockaddr_un, dlibc::socklen_t)>29 pub(super) fn sockaddr_un(path: &Path) -> io::Result<(dlibc::sockaddr_un, dlibc::socklen_t)> {
30     // SAFETY: All zeros is a valid representation for `sockaddr_un`.
31     let mut addr: dlibc::sockaddr_un = unsafe { mem::zeroed() };
32     addr.sun_family = dlibc::AF_UNIX as dlibc::sa_family_t;
33 
34     let bytes = path.as_os_str().as_bytes();
35 
36     if bytes.contains(&0) {
37         return Err(io::const_io_error!(
38             io::ErrorKind::InvalidInput,
39             "paths must not contain interior null bytes",
40         ));
41     }
42 
43     if bytes.len() >= addr.sun_path.len() {
44         return Err(io::const_io_error!(
45             io::ErrorKind::InvalidInput,
46             "path must be shorter than SUN_LEN",
47         ));
48     }
49     // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
50     // both point to valid memory.
51     // NOTE: We zeroed the memory above, so the path is already null
52     // terminated.
53     unsafe {
54         ptr::copy_nonoverlapping(
55             bytes.as_ptr(),
56             addr.sun_path.as_mut_ptr().cast(),
57             bytes.len(),
58         )
59     };
60 
61     let mut len = sun_path_offset(&addr) + bytes.len();
62     match bytes.get(0) {
63         Some(&0) | None => {}
64         Some(_) => len += 1,
65     }
66     Ok((addr, len as dlibc::socklen_t))
67 }
68 
69 enum AddressKind<'a> {
70     Unnamed,
71     Pathname(&'a Path),
72     Abstract(&'a [u8]),
73 }
74 
75 /// An address associated with a Unix socket.
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// use std::os::unix::net::UnixListener;
81 ///
82 /// let socket = match UnixListener::bind("/tmp/sock") {
83 ///     Ok(sock) => sock,
84 ///     Err(e) => {
85 ///         println!("Couldn't bind: {e:?}");
86 ///         return
87 ///     }
88 /// };
89 /// let addr = socket.local_addr().expect("Couldn't get local address");
90 /// ```
91 #[derive(Clone)]
92 pub struct SocketAddr {
93     pub(super) addr: dlibc::sockaddr_un,
94     pub(super) len: dlibc::socklen_t,
95 }
96 
97 impl SocketAddr {
new<F>(f: F) -> io::Result<SocketAddr> where F: FnOnce(*mut dlibc::sockaddr, *mut dlibc::socklen_t) -> dlibc::c_int,98     pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
99     where
100         F: FnOnce(*mut dlibc::sockaddr, *mut dlibc::socklen_t) -> dlibc::c_int,
101     {
102         unsafe {
103             let mut addr: dlibc::sockaddr_un = mem::zeroed();
104             let mut len = mem::size_of::<dlibc::sockaddr_un>() as dlibc::socklen_t;
105             cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
106             SocketAddr::from_parts(addr, len)
107         }
108     }
109 
from_parts( addr: dlibc::sockaddr_un, mut len: dlibc::socklen_t, ) -> io::Result<SocketAddr>110     pub(super) fn from_parts(
111         addr: dlibc::sockaddr_un,
112         mut len: dlibc::socklen_t,
113     ) -> io::Result<SocketAddr> {
114         if len == 0 {
115             // When there is a datagram from unnamed unix socket
116             // linux returns zero bytes of address
117             len = sun_path_offset(&addr) as dlibc::socklen_t; // i.e., zero-length address
118         } else if addr.sun_family != dlibc::AF_UNIX as dlibc::sa_family_t {
119             return Err(io::const_io_error!(
120                 io::ErrorKind::InvalidInput,
121                 "file descriptor did not correspond to a Unix socket",
122             ));
123         }
124 
125         Ok(SocketAddr { addr, len })
126     }
127 
128     /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
129     ///
130     /// # Errors
131     ///
132     /// Returns an error if the path is longer than `SUN_LEN` or if it contains
133     /// NULL bytes.
134     ///
135     /// # Examples
136     ///
137     /// ```
138     /// use std::os::unix::net::SocketAddr;
139     /// use std::path::Path;
140     ///
141     /// # fn main() -> std::io::Result<()> {
142     /// let address = SocketAddr::from_pathname("/path/to/socket")?;
143     /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
144     /// # Ok(())
145     /// # }
146     /// ```
147     ///
148     /// Creating a `SocketAddr` with a NULL byte results in an error.
149     ///
150     /// ```
151     /// use std::os::unix::net::SocketAddr;
152     ///
153     /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
154     /// ```
from_pathname<P>(path: P) -> io::Result<SocketAddr> where P: AsRef<Path>,155     pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
156     where
157         P: AsRef<Path>,
158     {
159         sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
160     }
161 
162     /// Returns `true` if the address is unnamed.
163     ///
164     /// # Examples
165     ///
166     /// A named address:
167     ///
168     /// ```no_run
169     /// use std::os::unix::net::UnixListener;
170     ///
171     /// fn main() -> std::io::Result<()> {
172     ///     let socket = UnixListener::bind("/tmp/sock")?;
173     ///     let addr = socket.local_addr().expect("Couldn't get local address");
174     ///     assert_eq!(addr.is_unnamed(), false);
175     ///     Ok(())
176     /// }
177     /// ```
178     ///
179     /// An unnamed address:
180     ///
181     /// ```
182     /// use std::os::unix::net::UnixDatagram;
183     ///
184     /// fn main() -> std::io::Result<()> {
185     ///     let socket = UnixDatagram::unbound()?;
186     ///     let addr = socket.local_addr().expect("Couldn't get local address");
187     ///     assert_eq!(addr.is_unnamed(), true);
188     ///     Ok(())
189     /// }
190     /// ```
191     #[must_use]
is_unnamed(&self) -> bool192     pub fn is_unnamed(&self) -> bool {
193         matches!(self.address(), AddressKind::Unnamed)
194     }
195 
196     /// Returns the contents of this address if it is a `pathname` address.
197     ///
198     /// # Examples
199     ///
200     /// With a pathname:
201     ///
202     /// ```no_run
203     /// use std::os::unix::net::UnixListener;
204     /// use std::path::Path;
205     ///
206     /// fn main() -> std::io::Result<()> {
207     ///     let socket = UnixListener::bind("/tmp/sock")?;
208     ///     let addr = socket.local_addr().expect("Couldn't get local address");
209     ///     assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
210     ///     Ok(())
211     /// }
212     /// ```
213     ///
214     /// Without a pathname:
215     ///
216     /// ```
217     /// use std::os::unix::net::UnixDatagram;
218     ///
219     /// fn main() -> std::io::Result<()> {
220     ///     let socket = UnixDatagram::unbound()?;
221     ///     let addr = socket.local_addr().expect("Couldn't get local address");
222     ///     assert_eq!(addr.as_pathname(), None);
223     ///     Ok(())
224     /// }
225     /// ```
226     #[must_use]
as_pathname(&self) -> Option<&Path>227     pub fn as_pathname(&self) -> Option<&Path> {
228         if let AddressKind::Pathname(path) = self.address() {
229             Some(path)
230         } else {
231             None
232         }
233     }
234 
address(&self) -> AddressKind<'_>235     fn address(&self) -> AddressKind<'_> {
236         let len = self.len as usize - sun_path_offset(&self.addr);
237         let path = unsafe { mem::transmute::<&[dlibc::c_char], &[u8]>(&self.addr.sun_path) };
238 
239         // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
240         if len == 0
241             || (cfg!(not(any(target_os = "linux", target_os = "android")))
242                 && self.addr.sun_path[0] == 0)
243         {
244             AddressKind::Unnamed
245         } else if self.addr.sun_path[0] == 0 {
246             AddressKind::Abstract(&path[1..len])
247         } else {
248             AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
249         }
250     }
251 }
252 
253 impl Sealed for SocketAddr {}
254 
255 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
256 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
257 impl linux_ext::addr::SocketAddrExt for SocketAddr {
as_abstract_name(&self) -> Option<&[u8]>258     fn as_abstract_name(&self) -> Option<&[u8]> {
259         if let AddressKind::Abstract(name) = self.address() {
260             Some(name)
261         } else {
262             None
263         }
264     }
265 
from_abstract_name<N>(name: N) -> crate::std::io::Result<Self> where N: AsRef<[u8]>,266     fn from_abstract_name<N>(name: N) -> crate::std::io::Result<Self>
267     where
268         N: AsRef<[u8]>,
269     {
270         let name = name.as_ref();
271         unsafe {
272             let mut addr: dlibc::sockaddr_un = mem::zeroed();
273             addr.sun_family = dlibc::AF_UNIX as dlibc::sa_family_t;
274 
275             if name.len() + 1 > addr.sun_path.len() {
276                 return Err(io::const_io_error!(
277                     io::ErrorKind::InvalidInput,
278                     "abstract socket name must be shorter than SUN_LEN",
279                 ));
280             }
281 
282             crate::std::ptr::copy_nonoverlapping(
283                 name.as_ptr(),
284                 addr.sun_path.as_mut_ptr().add(1) as *mut u8,
285                 name.len(),
286             );
287             let len = (sun_path_offset(&addr) + 1 + name.len()) as dlibc::socklen_t;
288             SocketAddr::from_parts(addr, len)
289         }
290     }
291 }
292 
293 impl fmt::Debug for SocketAddr {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result294     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
295         match self.address() {
296             AddressKind::Unnamed => write!(fmt, "(unnamed)"),
297             AddressKind::Abstract(name) => write!(fmt, "\"{}\" (abstract)", name.escape_ascii()),
298             AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
299         }
300     }
301 }
302