• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The BSD sockets API requires us to read the `ss_family` field before
2 //! we can interpret the rest of a `sockaddr` produced by the kernel.
3 #![allow(unsafe_code)]
4 
5 use super::super::c;
6 use crate::io;
7 use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6};
8 use alloc::vec::Vec;
9 use core::mem::size_of;
10 
11 // This must match the header of `sockaddr`.
12 #[repr(C)]
13 struct sockaddr_header {
14     ss_family: u16,
15 }
16 
17 /// Read the `ss_family` field from a socket address returned from the OS.
18 ///
19 /// # Safety
20 ///
21 /// `storage` must point to a valid socket address returned from the OS.
22 #[inline]
read_ss_family(storage: *const c::sockaddr) -> u1623 unsafe fn read_ss_family(storage: *const c::sockaddr) -> u16 {
24     // Assert that we know the layout of `sockaddr`.
25     let _ = c::sockaddr {
26         __storage: c::sockaddr_storage {
27             __bindgen_anon_1: linux_raw_sys::general::__kernel_sockaddr_storage__bindgen_ty_1 {
28                 __bindgen_anon_1:
29                     linux_raw_sys::general::__kernel_sockaddr_storage__bindgen_ty_1__bindgen_ty_1 {
30                         ss_family: 0_u16,
31                         __data: [0; 126_usize],
32                     },
33             },
34         },
35     };
36 
37     (*storage.cast::<sockaddr_header>()).ss_family
38 }
39 
40 /// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we
41 /// can test for `AF_UNSPEC` to test whether it was stored to.
42 #[inline]
initialize_family_to_unspec(storage: *mut c::sockaddr)43 pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr) {
44     (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _;
45 }
46 
47 /// Read a socket address encoded in a platform-specific format.
48 ///
49 /// # Safety
50 ///
51 /// `storage` must point to valid socket address storage.
read_sockaddr( storage: *const c::sockaddr, len: usize, ) -> io::Result<SocketAddrAny>52 pub(crate) unsafe fn read_sockaddr(
53     storage: *const c::sockaddr,
54     len: usize,
55 ) -> io::Result<SocketAddrAny> {
56     let offsetof_sun_path = super::addr::offsetof_sun_path();
57 
58     if len < size_of::<c::sa_family_t>() {
59         return Err(io::Errno::INVAL);
60     }
61     match read_ss_family(storage).into() {
62         c::AF_INET => {
63             if len < size_of::<c::sockaddr_in>() {
64                 return Err(io::Errno::INVAL);
65             }
66             let decode = *storage.cast::<c::sockaddr_in>();
67             Ok(SocketAddrAny::V4(SocketAddrV4::new(
68                 Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)),
69                 u16::from_be(decode.sin_port),
70             )))
71         }
72         c::AF_INET6 => {
73             if len < size_of::<c::sockaddr_in6>() {
74                 return Err(io::Errno::INVAL);
75             }
76             let decode = *storage.cast::<c::sockaddr_in6>();
77             Ok(SocketAddrAny::V6(SocketAddrV6::new(
78                 Ipv6Addr::from(decode.sin6_addr.in6_u.u6_addr8),
79                 u16::from_be(decode.sin6_port),
80                 u32::from_be(decode.sin6_flowinfo),
81                 decode.sin6_scope_id,
82             )))
83         }
84         c::AF_UNIX => {
85             if len < offsetof_sun_path {
86                 return Err(io::Errno::INVAL);
87             }
88             if len == offsetof_sun_path {
89                 Ok(SocketAddrAny::Unix(SocketAddrUnix::new(&[][..])?))
90             } else {
91                 let decode = *storage.cast::<c::sockaddr_un>();
92                 assert_eq!(
93                     decode.sun_path[len - 1 - offsetof_sun_path],
94                     b'\0' as c::c_char
95                 );
96                 Ok(SocketAddrAny::Unix(SocketAddrUnix::new(
97                     decode.sun_path[..len - 1 - offsetof_sun_path]
98                         .iter()
99                         .map(|c| *c as u8)
100                         .collect::<Vec<u8>>(),
101                 )?))
102             }
103         }
104         _ => Err(io::Errno::NOTSUP),
105     }
106 }
107 
108 /// Read a socket address returned from the OS.
109 ///
110 /// # Safety
111 ///
112 /// `storage` must point to a valid socket address returned from the OS.
maybe_read_sockaddr_os( storage: *const c::sockaddr, len: usize, ) -> Option<SocketAddrAny>113 pub(crate) unsafe fn maybe_read_sockaddr_os(
114     storage: *const c::sockaddr,
115     len: usize,
116 ) -> Option<SocketAddrAny> {
117     if len == 0 {
118         None
119     } else {
120         Some(read_sockaddr_os(storage, len))
121     }
122 }
123 
124 /// Read a socket address returned from the OS.
125 ///
126 /// # Safety
127 ///
128 /// `storage` must point to a valid socket address returned from the OS.
read_sockaddr_os(storage: *const c::sockaddr, len: usize) -> SocketAddrAny129 pub(crate) unsafe fn read_sockaddr_os(storage: *const c::sockaddr, len: usize) -> SocketAddrAny {
130     let offsetof_sun_path = super::addr::offsetof_sun_path();
131 
132     assert!(len >= size_of::<c::sa_family_t>());
133     match read_ss_family(storage).into() {
134         c::AF_INET => {
135             assert!(len >= size_of::<c::sockaddr_in>());
136             let decode = *storage.cast::<c::sockaddr_in>();
137             SocketAddrAny::V4(SocketAddrV4::new(
138                 Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)),
139                 u16::from_be(decode.sin_port),
140             ))
141         }
142         c::AF_INET6 => {
143             assert!(len >= size_of::<c::sockaddr_in6>());
144             let decode = *storage.cast::<c::sockaddr_in6>();
145             SocketAddrAny::V6(SocketAddrV6::new(
146                 Ipv6Addr::from(decode.sin6_addr.in6_u.u6_addr8),
147                 u16::from_be(decode.sin6_port),
148                 u32::from_be(decode.sin6_flowinfo),
149                 decode.sin6_scope_id,
150             ))
151         }
152         c::AF_UNIX => {
153             assert!(len >= offsetof_sun_path);
154             if len == offsetof_sun_path {
155                 SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap())
156             } else {
157                 let decode = *storage.cast::<c::sockaddr_un>();
158                 assert_eq!(
159                     decode.sun_path[len - 1 - offsetof_sun_path],
160                     b'\0' as c::c_char
161                 );
162                 SocketAddrAny::Unix(
163                     SocketAddrUnix::new(
164                         decode.sun_path[..len - 1 - offsetof_sun_path]
165                             .iter()
166                             .map(|c| *c as u8)
167                             .collect::<Vec<u8>>(),
168                     )
169                     .unwrap(),
170                 )
171             }
172         }
173         other => unimplemented!("{:?}", other),
174     }
175 }
176