• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::hash::Hash;
2 use std::mem::{self, size_of, MaybeUninit};
3 use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
4 use std::path::Path;
5 use std::{fmt, io, ptr};
6 
7 #[cfg(windows)]
8 use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
9 
10 use crate::sys::{
11     c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
12     AF_INET6, AF_UNIX,
13 };
14 use crate::Domain;
15 
16 /// The address of a socket.
17 ///
18 /// `SockAddr`s may be constructed directly to and from the standard library
19 /// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types.
20 #[derive(Clone)]
21 pub struct SockAddr {
22     storage: sockaddr_storage,
23     len: socklen_t,
24 }
25 
26 #[allow(clippy::len_without_is_empty)]
27 impl SockAddr {
28     /// Create a `SockAddr` from the underlying storage and its length.
29     ///
30     /// # Safety
31     ///
32     /// Caller must ensure that the address family and length match the type of
33     /// storage address. For example if `storage.ss_family` is set to `AF_INET`
34     /// the `storage` must be initialised as `sockaddr_in`, setting the content
35     /// and length appropriately.
36     ///
37     /// # Examples
38     ///
39     /// ```
40     /// # fn main() -> std::io::Result<()> {
41     /// # #[cfg(unix)] {
42     /// use std::io;
43     /// use std::mem;
44     /// use std::os::unix::io::AsRawFd;
45     ///
46     /// use socket2::{SockAddr, Socket, Domain, Type};
47     ///
48     /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
49     ///
50     /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
51     /// let mut addr_storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
52     /// let mut len = mem::size_of_val(&addr_storage) as libc::socklen_t;
53     ///
54     /// // The `getsockname(2)` system call will intiliase `storage` for
55     /// // us, setting `len` to the correct length.
56     /// let res = unsafe {
57     ///     libc::getsockname(
58     ///         socket.as_raw_fd(),
59     ///         (&mut addr_storage as *mut libc::sockaddr_storage).cast(),
60     ///         &mut len,
61     ///     )
62     /// };
63     /// if res == -1 {
64     ///     return Err(io::Error::last_os_error());
65     /// }
66     ///
67     /// let address = unsafe { SockAddr::new(addr_storage, len) };
68     /// # drop(address);
69     /// # }
70     /// # Ok(())
71     /// # }
72     /// ```
new(storage: sockaddr_storage, len: socklen_t) -> SockAddr73     pub const unsafe fn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr {
74         SockAddr { storage, len }
75     }
76 
77     /// Initialise a `SockAddr` by calling the function `init`.
78     ///
79     /// The type of the address storage and length passed to the function `init`
80     /// is OS/architecture specific.
81     ///
82     /// The address is zeroed before `init` is called and is thus valid to
83     /// dereference and read from. The length initialised to the maximum length
84     /// of the storage.
85     ///
86     /// # Safety
87     ///
88     /// Caller must ensure that the address family and length match the type of
89     /// storage address. For example if `storage.ss_family` is set to `AF_INET`
90     /// the `storage` must be initialised as `sockaddr_in`, setting the content
91     /// and length appropriately.
92     ///
93     /// # Examples
94     ///
95     /// ```
96     /// # fn main() -> std::io::Result<()> {
97     /// # #[cfg(unix)] {
98     /// use std::io;
99     /// use std::os::unix::io::AsRawFd;
100     ///
101     /// use socket2::{SockAddr, Socket, Domain, Type};
102     ///
103     /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
104     ///
105     /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
106     /// let (_, address) = unsafe {
107     ///     SockAddr::try_init(|addr_storage, len| {
108     ///         // The `getsockname(2)` system call will intiliase `storage` for
109     ///         // us, setting `len` to the correct length.
110     ///         if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 {
111     ///             Err(io::Error::last_os_error())
112     ///         } else {
113     ///             Ok(())
114     ///         }
115     ///     })
116     /// }?;
117     /// # drop(address);
118     /// # }
119     /// # Ok(())
120     /// # }
121     /// ```
try_init<F, T>(init: F) -> io::Result<(T, SockAddr)> where F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,122     pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
123     where
124         F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,
125     {
126         const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
127         // NOTE: `SockAddr::unix` depends on the storage being zeroed before
128         // calling `init`.
129         // NOTE: calling `recvfrom` with an empty buffer also depends on the
130         // storage being zeroed before calling `init` as the OS might not
131         // initialise it.
132         let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
133         let mut len = STORAGE_SIZE;
134         init(storage.as_mut_ptr(), &mut len).map(|res| {
135             debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
136             let addr = SockAddr {
137                 // Safety: zeroed-out `sockaddr_storage` is valid, caller must
138                 // ensure at least `len` bytes are valid.
139                 storage: storage.assume_init(),
140                 len,
141             };
142             (res, addr)
143         })
144     }
145 
146     /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
147     ///
148     /// Returns an error if the path is longer than `SUN_LEN`.
unix<P>(path: P) -> io::Result<SockAddr> where P: AsRef<Path>,149     pub fn unix<P>(path: P) -> io::Result<SockAddr>
150     where
151         P: AsRef<Path>,
152     {
153         crate::sys::unix_sockaddr(path.as_ref())
154     }
155 
156     /// Set the length of the address.
157     ///
158     /// # Safety
159     ///
160     /// Caller must ensure that the address up to `length` bytes are properly
161     /// initialised.
set_length(&mut self, length: socklen_t)162     pub unsafe fn set_length(&mut self, length: socklen_t) {
163         self.len = length;
164     }
165 
166     /// Returns this address's family.
family(&self) -> sa_family_t167     pub const fn family(&self) -> sa_family_t {
168         self.storage.ss_family
169     }
170 
171     /// Returns this address's `Domain`.
domain(&self) -> Domain172     pub const fn domain(&self) -> Domain {
173         Domain(self.storage.ss_family as c_int)
174     }
175 
176     /// Returns the size of this address in bytes.
len(&self) -> socklen_t177     pub const fn len(&self) -> socklen_t {
178         self.len
179     }
180 
181     /// Returns a raw pointer to the address.
as_ptr(&self) -> *const sockaddr182     pub const fn as_ptr(&self) -> *const sockaddr {
183         ptr::addr_of!(self.storage).cast()
184     }
185 
186     /// Retuns the address as the storage.
as_storage(self) -> sockaddr_storage187     pub const fn as_storage(self) -> sockaddr_storage {
188         self.storage
189     }
190 
191     /// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise.
is_ipv4(&self) -> bool192     pub const fn is_ipv4(&self) -> bool {
193         self.storage.ss_family == AF_INET as sa_family_t
194     }
195 
196     /// Returns true if this address is in the `AF_INET6` (IPv6) family, false
197     /// otherwise.
is_ipv6(&self) -> bool198     pub const fn is_ipv6(&self) -> bool {
199         self.storage.ss_family == AF_INET6 as sa_family_t
200     }
201 
202     /// Returns true if this address is of a unix socket (for local interprocess communication),
203     /// i.e. it is from the `AF_UNIX` family, false otherwise.
is_unix(&self) -> bool204     pub fn is_unix(&self) -> bool {
205         self.storage.ss_family == AF_UNIX as sa_family_t
206     }
207 
208     /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4)
209     /// or `AF_INET6` (IPv6) family, otherwise returns `None`.
as_socket(&self) -> Option<SocketAddr>210     pub fn as_socket(&self) -> Option<SocketAddr> {
211         if self.storage.ss_family == AF_INET as sa_family_t {
212             // SAFETY: if the `ss_family` field is `AF_INET` then storage must
213             // be a `sockaddr_in`.
214             let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
215             let ip = crate::sys::from_in_addr(addr.sin_addr);
216             let port = u16::from_be(addr.sin_port);
217             Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
218         } else if self.storage.ss_family == AF_INET6 as sa_family_t {
219             // SAFETY: if the `ss_family` field is `AF_INET6` then storage must
220             // be a `sockaddr_in6`.
221             let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
222             let ip = crate::sys::from_in6_addr(addr.sin6_addr);
223             let port = u16::from_be(addr.sin6_port);
224             Some(SocketAddr::V6(SocketAddrV6::new(
225                 ip,
226                 port,
227                 addr.sin6_flowinfo,
228                 #[cfg(unix)]
229                 addr.sin6_scope_id,
230                 #[cfg(windows)]
231                 unsafe {
232                     addr.Anonymous.sin6_scope_id
233                 },
234             )))
235         } else {
236             None
237         }
238     }
239 
240     /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
241     /// family.
as_socket_ipv4(&self) -> Option<SocketAddrV4>242     pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
243         match self.as_socket() {
244             Some(SocketAddr::V4(addr)) => Some(addr),
245             _ => None,
246         }
247     }
248 
249     /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
250     /// family.
as_socket_ipv6(&self) -> Option<SocketAddrV6>251     pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
252         match self.as_socket() {
253             Some(SocketAddr::V6(addr)) => Some(addr),
254             _ => None,
255         }
256     }
257 
258     /// Returns the initialised storage bytes.
as_bytes(&self) -> &[u8]259     fn as_bytes(&self) -> &[u8] {
260         // SAFETY: `self.storage` is a C struct which can always be treated a
261         // slice of bytes. Furthermore, we ensure we don't read any unitialised
262         // bytes by using `self.len`.
263         unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
264     }
265 }
266 
267 impl From<SocketAddr> for SockAddr {
from(addr: SocketAddr) -> SockAddr268     fn from(addr: SocketAddr) -> SockAddr {
269         match addr {
270             SocketAddr::V4(addr) => addr.into(),
271             SocketAddr::V6(addr) => addr.into(),
272         }
273     }
274 }
275 
276 impl From<SocketAddrV4> for SockAddr {
from(addr: SocketAddrV4) -> SockAddr277     fn from(addr: SocketAddrV4) -> SockAddr {
278         // SAFETY: a `sockaddr_storage` of all zeros is valid.
279         let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
280         let len = {
281             let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
282             storage.sin_family = AF_INET as sa_family_t;
283             storage.sin_port = addr.port().to_be();
284             storage.sin_addr = crate::sys::to_in_addr(addr.ip());
285             storage.sin_zero = Default::default();
286             mem::size_of::<sockaddr_in>() as socklen_t
287         };
288         #[cfg(any(
289             target_os = "dragonfly",
290             target_os = "freebsd",
291             target_os = "haiku",
292             target_os = "hermit",
293             target_os = "ios",
294             target_os = "visionos",
295             target_os = "macos",
296             target_os = "netbsd",
297             target_os = "nto",
298             target_os = "openbsd",
299             target_os = "tvos",
300             target_os = "vxworks",
301             target_os = "watchos",
302         ))]
303         {
304             storage.ss_len = len as u8;
305         }
306         SockAddr { storage, len }
307     }
308 }
309 
310 impl From<SocketAddrV6> for SockAddr {
from(addr: SocketAddrV6) -> SockAddr311     fn from(addr: SocketAddrV6) -> SockAddr {
312         // SAFETY: a `sockaddr_storage` of all zeros is valid.
313         let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
314         let len = {
315             let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
316             storage.sin6_family = AF_INET6 as sa_family_t;
317             storage.sin6_port = addr.port().to_be();
318             storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
319             storage.sin6_flowinfo = addr.flowinfo();
320             #[cfg(unix)]
321             {
322                 storage.sin6_scope_id = addr.scope_id();
323             }
324             #[cfg(windows)]
325             {
326                 storage.Anonymous = SOCKADDR_IN6_0 {
327                     sin6_scope_id: addr.scope_id(),
328                 };
329             }
330             mem::size_of::<sockaddr_in6>() as socklen_t
331         };
332         #[cfg(any(
333             target_os = "dragonfly",
334             target_os = "freebsd",
335             target_os = "haiku",
336             target_os = "hermit",
337             target_os = "ios",
338             target_os = "visionos",
339             target_os = "macos",
340             target_os = "netbsd",
341             target_os = "nto",
342             target_os = "openbsd",
343             target_os = "tvos",
344             target_os = "vxworks",
345             target_os = "watchos",
346         ))]
347         {
348             storage.ss_len = len as u8;
349         }
350         SockAddr { storage, len }
351     }
352 }
353 
354 impl fmt::Debug for SockAddr {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result355     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
356         let mut f = fmt.debug_struct("SockAddr");
357         #[cfg(any(
358             target_os = "dragonfly",
359             target_os = "freebsd",
360             target_os = "haiku",
361             target_os = "hermit",
362             target_os = "ios",
363             target_os = "visionos",
364             target_os = "macos",
365             target_os = "netbsd",
366             target_os = "nto",
367             target_os = "openbsd",
368             target_os = "tvos",
369             target_os = "vxworks",
370             target_os = "watchos",
371         ))]
372         f.field("ss_len", &self.storage.ss_len);
373         f.field("ss_family", &self.storage.ss_family)
374             .field("len", &self.len)
375             .finish()
376     }
377 }
378 
379 impl PartialEq for SockAddr {
eq(&self, other: &Self) -> bool380     fn eq(&self, other: &Self) -> bool {
381         self.as_bytes() == other.as_bytes()
382     }
383 }
384 
385 impl Eq for SockAddr {}
386 
387 impl Hash for SockAddr {
hash<H: std::hash::Hasher>(&self, state: &mut H)388     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
389         self.as_bytes().hash(state);
390     }
391 }
392 
393 #[cfg(test)]
394 mod tests {
395     use super::*;
396 
397     #[test]
ipv4()398     fn ipv4() {
399         use std::net::Ipv4Addr;
400         let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
401         let addr = SockAddr::from(std);
402         assert!(addr.is_ipv4());
403         assert!(!addr.is_ipv6());
404         assert!(!addr.is_unix());
405         assert_eq!(addr.family(), AF_INET as sa_family_t);
406         assert_eq!(addr.domain(), Domain::IPV4);
407         assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
408         assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
409         assert_eq!(addr.as_socket_ipv4(), Some(std));
410         assert!(addr.as_socket_ipv6().is_none());
411 
412         let addr = SockAddr::from(SocketAddr::from(std));
413         assert_eq!(addr.family(), AF_INET as sa_family_t);
414         assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
415         assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
416         assert_eq!(addr.as_socket_ipv4(), Some(std));
417         assert!(addr.as_socket_ipv6().is_none());
418         #[cfg(unix)]
419         {
420             assert!(addr.as_pathname().is_none());
421             assert!(addr.as_abstract_namespace().is_none());
422         }
423     }
424 
425     #[test]
ipv6()426     fn ipv6() {
427         use std::net::Ipv6Addr;
428         let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
429         let addr = SockAddr::from(std);
430         assert!(addr.is_ipv6());
431         assert!(!addr.is_ipv4());
432         assert!(!addr.is_unix());
433         assert_eq!(addr.family(), AF_INET6 as sa_family_t);
434         assert_eq!(addr.domain(), Domain::IPV6);
435         assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
436         assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
437         assert!(addr.as_socket_ipv4().is_none());
438         assert_eq!(addr.as_socket_ipv6(), Some(std));
439 
440         let addr = SockAddr::from(SocketAddr::from(std));
441         assert_eq!(addr.family(), AF_INET6 as sa_family_t);
442         assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
443         assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
444         assert!(addr.as_socket_ipv4().is_none());
445         assert_eq!(addr.as_socket_ipv6(), Some(std));
446         #[cfg(unix)]
447         {
448             assert!(addr.as_pathname().is_none());
449             assert!(addr.as_abstract_namespace().is_none());
450         }
451     }
452 
453     #[test]
ipv4_eq()454     fn ipv4_eq() {
455         use std::net::Ipv4Addr;
456 
457         let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
458         let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
459 
460         test_eq(
461             SockAddr::from(std1),
462             SockAddr::from(std1),
463             SockAddr::from(std2),
464         );
465     }
466 
467     #[test]
ipv4_hash()468     fn ipv4_hash() {
469         use std::net::Ipv4Addr;
470 
471         let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
472         let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
473 
474         test_hash(
475             SockAddr::from(std1),
476             SockAddr::from(std1),
477             SockAddr::from(std2),
478         );
479     }
480 
481     #[test]
ipv6_eq()482     fn ipv6_eq() {
483         use std::net::Ipv6Addr;
484 
485         let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
486         let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
487 
488         test_eq(
489             SockAddr::from(std1),
490             SockAddr::from(std1),
491             SockAddr::from(std2),
492         );
493     }
494 
495     #[test]
ipv6_hash()496     fn ipv6_hash() {
497         use std::net::Ipv6Addr;
498 
499         let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
500         let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
501 
502         test_hash(
503             SockAddr::from(std1),
504             SockAddr::from(std1),
505             SockAddr::from(std2),
506         );
507     }
508 
509     #[test]
ipv4_ipv6_eq()510     fn ipv4_ipv6_eq() {
511         use std::net::Ipv4Addr;
512         use std::net::Ipv6Addr;
513 
514         let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
515         let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
516 
517         test_eq(
518             SockAddr::from(std1),
519             SockAddr::from(std1),
520             SockAddr::from(std2),
521         );
522 
523         test_eq(
524             SockAddr::from(std2),
525             SockAddr::from(std2),
526             SockAddr::from(std1),
527         );
528     }
529 
530     #[test]
ipv4_ipv6_hash()531     fn ipv4_ipv6_hash() {
532         use std::net::Ipv4Addr;
533         use std::net::Ipv6Addr;
534 
535         let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
536         let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
537 
538         test_hash(
539             SockAddr::from(std1),
540             SockAddr::from(std1),
541             SockAddr::from(std2),
542         );
543 
544         test_hash(
545             SockAddr::from(std2),
546             SockAddr::from(std2),
547             SockAddr::from(std1),
548         );
549     }
550 
551     #[allow(clippy::eq_op)] // allow a0 == a0 check
test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr)552     fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
553         assert!(a0 == a0);
554         assert!(a0 == a1);
555         assert!(a1 == a0);
556         assert!(a0 != b);
557         assert!(b != a0);
558     }
559 
test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr)560     fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
561         assert!(calculate_hash(&a0) == calculate_hash(&a0));
562         assert!(calculate_hash(&a0) == calculate_hash(&a1));
563         // technically unequal values can have the same hash, in this case x != z and both have different hashes
564         assert!(calculate_hash(&a0) != calculate_hash(&b));
565     }
566 
calculate_hash(x: &SockAddr) -> u64567     fn calculate_hash(x: &SockAddr) -> u64 {
568         use std::collections::hash_map::DefaultHasher;
569         use std::hash::Hasher;
570 
571         let mut hasher = DefaultHasher::new();
572         x.hash(&mut hasher);
573         hasher.finish()
574     }
575 }
576