• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::mem::{self, size_of, MaybeUninit};
2 use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
3 use std::{fmt, io};
4 
5 use crate::sys::{
6     sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
7     AF_INET6,
8 };
9 #[cfg(windows)]
10 use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH_u;
11 
12 /// The address of a socket.
13 ///
14 /// `SockAddr`s may be constructed directly to and from the standard library
15 /// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types.
16 #[derive(Clone)]
17 pub struct SockAddr {
18     storage: sockaddr_storage,
19     len: socklen_t,
20 }
21 
22 #[allow(clippy::len_without_is_empty)]
23 impl SockAddr {
24     /// Create a `SockAddr` from the underlying storage and its length.
25     ///
26     /// # Safety
27     ///
28     /// Caller must ensure that the address family and length match the type of
29     /// storage address. For example if `storage.ss_family` is set to `AF_INET`
30     /// the `storage` must be initialised as `sockaddr_in`, setting the content
31     /// and length appropriately.
32     ///
33     /// # Examples
34     ///
35     /// ```
36     /// # fn main() -> std::io::Result<()> {
37     /// # #[cfg(unix)] {
38     /// use std::io;
39     /// use std::mem;
40     /// use std::os::unix::io::AsRawFd;
41     ///
42     /// use socket2::{SockAddr, Socket, Domain, Type};
43     ///
44     /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
45     ///
46     /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
47     /// let mut addr_storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
48     /// let mut len = mem::size_of_val(&addr_storage) as libc::socklen_t;
49     ///
50     /// // The `getsockname(2)` system call will intiliase `storage` for
51     /// // us, setting `len` to the correct length.
52     /// let res = unsafe {
53     ///     libc::getsockname(
54     ///         socket.as_raw_fd(),
55     ///         (&mut addr_storage as *mut libc::sockaddr_storage).cast(),
56     ///         &mut len,
57     ///     )
58     /// };
59     /// if res == -1 {
60     ///     return Err(io::Error::last_os_error());
61     /// }
62     ///
63     /// let address = unsafe { SockAddr::new(addr_storage, len) };
64     /// # drop(address);
65     /// # }
66     /// # Ok(())
67     /// # }
68     /// ```
new(storage: sockaddr_storage, len: socklen_t) -> SockAddr69     pub const unsafe fn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr {
70         SockAddr { storage, len }
71     }
72 
73     /// Initialise a `SockAddr` by calling the function `init`.
74     ///
75     /// The type of the address storage and length passed to the function `init`
76     /// is OS/architecture specific.
77     ///
78     /// The address is zeroed before `init` is called and is thus valid to
79     /// dereference and read from. The length initialised to the maximum length
80     /// of the storage.
81     ///
82     /// # Safety
83     ///
84     /// Caller must ensure that the address family and length match the type of
85     /// storage address. For example if `storage.ss_family` is set to `AF_INET`
86     /// the `storage` must be initialised as `sockaddr_in`, setting the content
87     /// and length appropriately.
88     ///
89     /// # Examples
90     ///
91     /// ```
92     /// # fn main() -> std::io::Result<()> {
93     /// # #[cfg(unix)] {
94     /// use std::io;
95     /// use std::os::unix::io::AsRawFd;
96     ///
97     /// use socket2::{SockAddr, Socket, Domain, Type};
98     ///
99     /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
100     ///
101     /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
102     /// let (_, address) = unsafe {
103     ///     SockAddr::init(|addr_storage, len| {
104     ///         // The `getsockname(2)` system call will intiliase `storage` for
105     ///         // us, setting `len` to the correct length.
106     ///         if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 {
107     ///             Err(io::Error::last_os_error())
108     ///         } else {
109     ///             Ok(())
110     ///         }
111     ///     })
112     /// }?;
113     /// # drop(address);
114     /// # }
115     /// # Ok(())
116     /// # }
117     /// ```
init<F, T>(init: F) -> io::Result<(T, SockAddr)> where F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,118     pub unsafe fn init<F, T>(init: F) -> io::Result<(T, SockAddr)>
119     where
120         F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,
121     {
122         const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
123         // NOTE: `SockAddr::unix` depends on the storage being zeroed before
124         // calling `init`.
125         // NOTE: calling `recvfrom` with an empty buffer also depends on the
126         // storage being zeroed before calling `init` as the OS might not
127         // initialise it.
128         let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
129         let mut len = STORAGE_SIZE;
130         init(storage.as_mut_ptr(), &mut len).map(|res| {
131             debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
132             let addr = SockAddr {
133                 // Safety: zeroed-out `sockaddr_storage` is valid, caller must
134                 // ensure at least `len` bytes are valid.
135                 storage: storage.assume_init(),
136                 len,
137             };
138             (res, addr)
139         })
140     }
141 
142     /// Returns this address's family.
family(&self) -> sa_family_t143     pub const fn family(&self) -> sa_family_t {
144         self.storage.ss_family
145     }
146 
147     /// Returns the size of this address in bytes.
len(&self) -> socklen_t148     pub const fn len(&self) -> socklen_t {
149         self.len
150     }
151 
152     /// Returns a raw pointer to the address.
as_ptr(&self) -> *const sockaddr153     pub const fn as_ptr(&self) -> *const sockaddr {
154         &self.storage as *const _ as *const _
155     }
156 
157     /// Returns a raw pointer to the address storage.
158     #[cfg(all(unix, not(target_os = "redox")))]
as_storage_ptr(&self) -> *const sockaddr_storage159     pub(crate) const fn as_storage_ptr(&self) -> *const sockaddr_storage {
160         &self.storage
161     }
162 
163     /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4)
164     /// or `AF_INET6` (IPv6) family, otherwise returns `None`.
as_socket(&self) -> Option<SocketAddr>165     pub fn as_socket(&self) -> Option<SocketAddr> {
166         if self.storage.ss_family == AF_INET as sa_family_t {
167             // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
168             let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) };
169 
170             let ip = crate::sys::from_in_addr(addr.sin_addr);
171             let port = u16::from_be(addr.sin_port);
172             Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
173         } else if self.storage.ss_family == AF_INET6 as sa_family_t {
174             // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
175             let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) };
176 
177             let ip = crate::sys::from_in6_addr(addr.sin6_addr);
178             let port = u16::from_be(addr.sin6_port);
179             Some(SocketAddr::V6(SocketAddrV6::new(
180                 ip,
181                 port,
182                 addr.sin6_flowinfo,
183                 #[cfg(unix)]
184                 addr.sin6_scope_id,
185                 #[cfg(windows)]
186                 unsafe {
187                     *addr.u.sin6_scope_id()
188                 },
189             )))
190         } else {
191             None
192         }
193     }
194 
195     /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
196     /// family.
as_socket_ipv4(&self) -> Option<SocketAddrV4>197     pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
198         match self.as_socket() {
199             Some(SocketAddr::V4(addr)) => Some(addr),
200             _ => None,
201         }
202     }
203 
204     /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
205     /// family.
as_socket_ipv6(&self) -> Option<SocketAddrV6>206     pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
207         match self.as_socket() {
208             Some(SocketAddr::V6(addr)) => Some(addr),
209             _ => None,
210         }
211     }
212 }
213 
214 impl From<SocketAddr> for SockAddr {
from(addr: SocketAddr) -> SockAddr215     fn from(addr: SocketAddr) -> SockAddr {
216         match addr {
217             SocketAddr::V4(addr) => addr.into(),
218             SocketAddr::V6(addr) => addr.into(),
219         }
220     }
221 }
222 
223 impl From<SocketAddrV4> for SockAddr {
from(addr: SocketAddrV4) -> SockAddr224     fn from(addr: SocketAddrV4) -> SockAddr {
225         let sockaddr_in = sockaddr_in {
226             sin_family: AF_INET as sa_family_t,
227             sin_port: addr.port().to_be(),
228             sin_addr: crate::sys::to_in_addr(addr.ip()),
229             sin_zero: Default::default(),
230             #[cfg(any(
231                 target_os = "dragonfly",
232                 target_os = "freebsd",
233                 target_os = "haiku",
234                 target_os = "ios",
235                 target_os = "macos",
236                 target_os = "netbsd",
237                 target_os = "openbsd"
238             ))]
239             sin_len: 0,
240         };
241         let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
242         // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage`
243         unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) };
244         SockAddr {
245             storage: unsafe { storage.assume_init() },
246             len: mem::size_of::<sockaddr_in>() as socklen_t,
247         }
248     }
249 }
250 
251 impl From<SocketAddrV6> for SockAddr {
from(addr: SocketAddrV6) -> SockAddr252     fn from(addr: SocketAddrV6) -> SockAddr {
253         #[cfg(windows)]
254         let u = unsafe {
255             let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>();
256             *u.sin6_scope_id_mut() = addr.scope_id();
257             u
258         };
259 
260         let sockaddr_in6 = sockaddr_in6 {
261             sin6_family: AF_INET6 as sa_family_t,
262             sin6_port: addr.port().to_be(),
263             sin6_addr: crate::sys::to_in6_addr(addr.ip()),
264             sin6_flowinfo: addr.flowinfo(),
265             #[cfg(unix)]
266             sin6_scope_id: addr.scope_id(),
267             #[cfg(windows)]
268             u,
269             #[cfg(any(
270                 target_os = "dragonfly",
271                 target_os = "freebsd",
272                 target_os = "haiku",
273                 target_os = "ios",
274                 target_os = "macos",
275                 target_os = "netbsd",
276                 target_os = "openbsd"
277             ))]
278             sin6_len: 0,
279             #[cfg(any(target_os = "solaris", target_os = "illumos"))]
280             __sin6_src_id: 0,
281         };
282         let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
283         // Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage`
284         unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) };
285         SockAddr {
286             storage: unsafe { storage.assume_init() },
287             len: mem::size_of::<sockaddr_in6>() as socklen_t,
288         }
289     }
290 }
291 
292 impl fmt::Debug for SockAddr {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result293     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
294         let mut f = fmt.debug_struct("SockAddr");
295         #[cfg(any(
296             target_os = "dragonfly",
297             target_os = "freebsd",
298             target_os = "haiku",
299             target_os = "hermit",
300             target_os = "ios",
301             target_os = "macos",
302             target_os = "netbsd",
303             target_os = "openbsd",
304             target_os = "vxworks",
305         ))]
306         f.field("ss_len", &self.storage.ss_len);
307         f.field("ss_family", &self.storage.ss_family)
308             .field("len", &self.len)
309             .finish()
310     }
311 }
312 
313 #[test]
ipv4()314 fn ipv4() {
315     use std::net::Ipv4Addr;
316     let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
317     let addr = SockAddr::from(std);
318     assert_eq!(addr.family(), AF_INET as sa_family_t);
319     assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
320     assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
321     assert_eq!(addr.as_socket_ipv4(), Some(std));
322     assert!(addr.as_socket_ipv6().is_none());
323 
324     let addr = SockAddr::from(SocketAddr::from(std));
325     assert_eq!(addr.family(), AF_INET as sa_family_t);
326     assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
327     assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
328     assert_eq!(addr.as_socket_ipv4(), Some(std));
329     assert!(addr.as_socket_ipv6().is_none());
330 }
331 
332 #[test]
ipv6()333 fn ipv6() {
334     use std::net::Ipv6Addr;
335     let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
336     let addr = SockAddr::from(std);
337     assert_eq!(addr.family(), AF_INET6 as sa_family_t);
338     assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
339     assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
340     assert!(addr.as_socket_ipv4().is_none());
341     assert_eq!(addr.as_socket_ipv6(), Some(std));
342 
343     let addr = SockAddr::from(SocketAddr::from(std));
344     assert_eq!(addr.family(), AF_INET6 as sa_family_t);
345     assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
346     assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
347     assert!(addr.as_socket_ipv4().is_none());
348     assert_eq!(addr.as_socket_ipv6(), Some(std));
349 }
350