• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright 2024 Google, Inc.
2 //
3 //  Licensed under the Apache License, Version 2.0 (the "License");
4 //  you may not use this file except in compliance with the License.
5 //  You may obtain a copy of the License at:
6 //
7 //  http://www.apache.org/licenses/LICENSE-2.0
8 //
9 //  Unless required by applicable law or agreed to in writing, software
10 //  distributed under the License is distributed on an "AS IS" BASIS,
11 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 //  See the License for the specific language governing permissions and
13 //  limitations under the License.
14 
15 //! FFI bindings for libslirp library.
16 //!
17 //! This allows for easy integration of user-mode networking into Rust applications.
18 //!
19 //! It offers functionality for:
20 //!
21 //! - Converting C sockaddr_in and sockaddr_in6 to Rust types per OS
22 //! - Converting C sockaddr_storage type into the IPv6 and IPv4 variants
23 //!
24 //! # Example
25 //!
26 //! ```
27 //! use libslirp_rs::libslirp_sys::sockaddr_storage;
28 //! use std::net::Ipv4Addr;
29 //! use std::net::SocketAddr;
30 //!
31 //! let sockaddr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
32 //! let storage: sockaddr_storage = sockaddr.into();
33 //!
34 //! // Interact with the Slirp instance
35 //! ```
36 
37 #![allow(missing_docs)]
38 #![allow(clippy::missing_safety_doc)]
39 #![allow(unsafe_op_in_unsafe_fn)]
40 #![allow(non_upper_case_globals)]
41 #![allow(non_camel_case_types)]
42 #![allow(non_snake_case)]
43 // TODO(b/203002625) - since rustc 1.53, bindgen causes UB warnings
44 // Remove this once bindgen figures out how to do this correctly
45 #![allow(deref_nullptr)]
46 
47 use std::convert::From;
48 use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
49 
50 #[cfg(target_os = "linux")]
51 include!("linux/bindings.rs");
52 
53 #[cfg(target_os = "macos")]
54 include!("macos/bindings.rs");
55 
56 #[cfg(target_os = "windows")]
57 include!("windows/bindings.rs");
58 
59 impl Default for sockaddr_storage {
60     /// Returns a zeroed `sockaddr_storage`.
61     ///
62     /// This is useful for uninitialied libslirp_config fields.
63     ///
64     /// This is safe because `sockaddr_storage` is a plain old data
65     /// type with no padding or invariants, and a zeroed
66     /// `sockaddr_storage` is a valid representation of "no address".
default() -> Self67     fn default() -> Self {
68         // Safety:
69         //  * sockaddr_storage is repr(C) and has no uninitialized padding bytes.
70         //  * Zeroing a sockaddr_storage is a valid initialization.
71         unsafe { std::mem::zeroed() }
72     }
73 }
74 
v4_ref(storage: &sockaddr_storage) -> &sockaddr_in75 fn v4_ref(storage: &sockaddr_storage) -> &sockaddr_in {
76     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in`.
77     // Neither types have any padding.
78     unsafe { &*(storage as *const sockaddr_storage as *const sockaddr_in) }
79 }
80 
v6_ref(storage: &sockaddr_storage) -> &sockaddr_in681 fn v6_ref(storage: &sockaddr_storage) -> &sockaddr_in6 {
82     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in6`.
83     // Neither types have any padding.
84     unsafe { &*(storage as *const sockaddr_storage as *const sockaddr_in6) }
85 }
86 
v4_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in87 fn v4_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in {
88     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in`.
89     // Neither types have any padding.
90     unsafe { &mut *(storage as *mut sockaddr_storage as *mut sockaddr_in) }
91 }
92 
v6_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in693 fn v6_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in6 {
94     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in6`.
95     // Neither types have any padding.
96     unsafe { &mut *(storage as *mut sockaddr_storage as *mut sockaddr_in6) }
97 }
98 
99 // Type for libslirp poll bitfield mask SLIRP_POLL_nnn
100 
101 #[cfg(target_os = "linux")]
102 pub type SlirpPollType = _bindgen_ty_7;
103 
104 #[cfg(target_os = "macos")]
105 pub type SlirpPollType = _bindgen_ty_1;
106 
107 #[cfg(target_os = "windows")]
108 pub type SlirpPollType = _bindgen_ty_5;
109 
110 impl From<sockaddr_storage> for SocketAddr {
111     /// Converts a `sockaddr_storage` to a `SocketAddr`.
112     ///
113     /// This function safely converts a `sockaddr_storage` from the
114     /// `libslirp_sys` crate into a `std::net::SocketAddr`. It handles
115     /// both IPv4 and IPv6 addresses by checking the `ss_family` field
116     /// and casting the `sockaddr_storage` to the appropriate address
117     /// type (`sockaddr_in` or `sockaddr_in6`).
118     ///
119     /// # Panics
120     ///
121     /// This function will panic if the `ss_family` field of the
122     /// `sockaddr_storage` is not `AF_INET` or `AF_INET6`.
from(storage: sockaddr_storage) -> Self123     fn from(storage: sockaddr_storage) -> Self {
124         match storage.ss_family as u32 {
125             AF_INET => SocketAddr::V4((*v4_ref(&storage)).into()),
126             AF_INET6 => SocketAddr::V6((*v6_ref(&storage)).into()),
127             _ => panic!("Unsupported address family"),
128         }
129     }
130 }
131 
132 impl From<SocketAddr> for sockaddr_storage {
133     /// Converts a `SocketAddr` to a `sockaddr_storage`.
134     ///
135     /// This function safely converts a `std::net::SocketAddr` into a
136     /// `libslirp_sys::sockaddr_storage`. It handles both IPv4 and
137     /// IPv6 addresses by writing the appropriate data into the
138     /// `sockaddr_storage` structure.
139     ///
140     /// This conversion is useful when interacting with
141     /// libslirp_config that expect a `sockaddr_storage` type.
from(sockaddr: SocketAddr) -> Self142     fn from(sockaddr: SocketAddr) -> Self {
143         let mut storage = sockaddr_storage::default();
144 
145         match sockaddr {
146             SocketAddr::V4(addr) => *v4_mut(&mut storage) = addr.into(),
147             SocketAddr::V6(addr) => *v6_mut(&mut storage) = addr.into(),
148         }
149         storage
150     }
151 }
152 
153 impl From<in_addr> for u32 {
from(val: in_addr) -> Self154     fn from(val: in_addr) -> Self {
155         #[cfg(target_os = "windows")]
156         // SAFETY: This is safe because we are accessing a union field and
157         // all fields in the union have the same size.
158         unsafe {
159             val.S_un.S_addr
160         }
161 
162         #[cfg(any(target_os = "macos", target_os = "linux"))]
163         val.s_addr
164     }
165 }
166 
167 mod net {
168     /// Converts a value from host byte order to network byte order.
169     #[inline]
htonl(hostlong: u32) -> u32170     pub fn htonl(hostlong: u32) -> u32 {
171         hostlong.to_be()
172     }
173 
174     /// Converts a value from network byte order to host byte order.
175     #[inline]
ntohl(netlong: u32) -> u32176     pub fn ntohl(netlong: u32) -> u32 {
177         u32::from_be(netlong)
178     }
179 
180     /// Converts a value from host byte order to network byte order.
181     #[inline]
htons(hostshort: u16) -> u16182     pub fn htons(hostshort: u16) -> u16 {
183         hostshort.to_be()
184     }
185 
186     /// Converts a value from network byte order to host byte order.
187     #[inline]
ntohs(netshort: u16) -> u16188     pub fn ntohs(netshort: u16) -> u16 {
189         u16::from_be(netshort)
190     }
191 }
192 
193 impl From<Ipv4Addr> for in_addr {
from(item: Ipv4Addr) -> Self194     fn from(item: Ipv4Addr) -> Self {
195         #[cfg(target_os = "windows")]
196         return in_addr {
197             S_un: in_addr__bindgen_ty_1 { S_addr: std::os::raw::c_ulong::to_be(item.into()) },
198         };
199 
200         #[cfg(any(target_os = "macos", target_os = "linux"))]
201         return in_addr { s_addr: net::htonl(item.into()) };
202     }
203 }
204 
205 impl From<in6_addr> for Ipv6Addr {
from(item: in6_addr) -> Self206     fn from(item: in6_addr) -> Self {
207         // SAFETY: Access union field. This is safe because we are
208         // accessing the underlying byte array representation of the
209         // `in6_addr` struct on macOS and all variants have the same
210         // size.
211         #[cfg(target_os = "macos")]
212         return Ipv6Addr::from(unsafe { item.__u6_addr.__u6_addr8 });
213 
214         #[cfg(target_os = "linux")]
215         // SAFETY: Access union field. This is safe because we are
216         // accessing the underlying byte array representation of the
217         // `in6_addr` struct on Linux and all variants have the same
218         // size.
219         return Ipv6Addr::from(unsafe { item.__in6_u.__u6_addr8 });
220 
221         // SAFETY: Access union field. This is safe because we are
222         // accessing the underlying byte array representation of the
223         // `in6_addr` struct on Windows and all variants have the same
224         // size.
225         #[cfg(target_os = "windows")]
226         return Ipv6Addr::from(unsafe { item.u.Byte });
227     }
228 }
229 
230 impl From<Ipv6Addr> for in6_addr {
from(item: Ipv6Addr) -> Self231     fn from(item: Ipv6Addr) -> Self {
232         #[cfg(target_os = "macos")]
233         return in6_addr { __u6_addr: in6_addr__bindgen_ty_1 { __u6_addr8: item.octets() } };
234 
235         #[cfg(target_os = "linux")]
236         return in6_addr { __in6_u: in6_addr__bindgen_ty_1 { __u6_addr8: item.octets() } };
237 
238         #[cfg(target_os = "windows")]
239         return in6_addr { u: in6_addr__bindgen_ty_1 { Byte: item.octets() } };
240     }
241 }
242 
243 impl From<SocketAddrV4> for sockaddr_in {
from(item: SocketAddrV4) -> Self244     fn from(item: SocketAddrV4) -> Self {
245         #[cfg(target_os = "macos")]
246         return sockaddr_in {
247             sin_len: 16u8,
248             sin_family: AF_INET as u8,
249             sin_port: net::htons(item.port()),
250             sin_addr: (*item.ip()).into(),
251             sin_zero: [0; 8],
252         };
253 
254         #[cfg(any(target_os = "linux", target_os = "windows"))]
255         return sockaddr_in {
256             sin_family: AF_INET as u16,
257             sin_port: net::htons(item.port()),
258             sin_addr: (*item.ip()).into(),
259             sin_zero: [0; 8],
260         };
261     }
262 }
263 
264 impl From<sockaddr_in> for SocketAddrV4 {
from(item: sockaddr_in) -> Self265     fn from(item: sockaddr_in) -> Self {
266         SocketAddrV4::new(
267             Ipv4Addr::from(net::ntohl(item.sin_addr.into())),
268             net::ntohs(item.sin_port),
269         )
270     }
271 }
272 
273 impl From<sockaddr_in6> for SocketAddrV6 {
from(item: sockaddr_in6) -> Self274     fn from(item: sockaddr_in6) -> Self {
275         #[cfg(any(target_os = "linux", target_os = "macos"))]
276         return SocketAddrV6::new(
277             Ipv6Addr::from(item.sin6_addr),
278             net::ntohs(item.sin6_port),
279             net::ntohl(item.sin6_flowinfo),
280             item.sin6_scope_id,
281         );
282 
283         #[cfg(target_os = "windows")]
284         return SocketAddrV6::new(
285             Ipv6Addr::from(item.sin6_addr),
286             net::ntohs(item.sin6_port),
287             net::ntohl(item.sin6_flowinfo),
288             // SAFETY: This is safe because we are accessing a union
289             // field where all fields have the same size.
290             unsafe { item.__bindgen_anon_1.sin6_scope_id },
291         );
292     }
293 }
294 
295 impl From<SocketAddrV6> for sockaddr_in6 {
from(item: SocketAddrV6) -> Self296     fn from(item: SocketAddrV6) -> Self {
297         #[cfg(target_os = "windows")]
298         return sockaddr_in6 {
299             sin6_addr: (*item.ip()).into(),
300             sin6_family: AF_INET6 as u16,
301             sin6_port: net::htons(item.port()),
302             sin6_flowinfo: net::htonl(item.flowinfo()),
303             __bindgen_anon_1: sockaddr_in6__bindgen_ty_1 { sin6_scope_id: item.scope_id() },
304         };
305 
306         #[cfg(target_os = "macos")]
307         return sockaddr_in6 {
308             sin6_addr: (*item.ip()).into(),
309             sin6_family: AF_INET6 as u8,
310             sin6_port: net::htons(item.port()),
311             sin6_flowinfo: net::htonl(item.flowinfo()),
312             sin6_scope_id: item.scope_id(),
313             sin6_len: 16,
314         };
315 
316         #[cfg(target_os = "linux")]
317         return sockaddr_in6 {
318             sin6_addr: (*item.ip()).into(),
319             sin6_family: AF_INET6 as u16,
320             sin6_port: net::htons(item.port()),
321             sin6_flowinfo: net::htonl(item.flowinfo()),
322             sin6_scope_id: item.scope_id(),
323         };
324     }
325 }
326 
327 #[cfg(test)]
328 mod tests {
329     use super::*;
330     use std::mem;
331 
332     // This tests a bidirectional conversion between sockaddr_storage
333     // and SocketAddr
334     #[test]
test_sockaddr_storage()335     fn test_sockaddr_storage() {
336         let sockaddr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
337         let storage: sockaddr_storage = sockaddr.into();
338 
339         let sockaddr_from_storage: SocketAddr = storage.into();
340 
341         assert_eq!(sockaddr, sockaddr_from_storage);
342     }
343 
344     #[test]
test_sockaddr_storage_v6()345     fn test_sockaddr_storage_v6() {
346         let sockaddr = SocketAddr::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into(), 8080);
347         let storage: sockaddr_storage = sockaddr.into();
348 
349         let sockaddr_from_storage: SocketAddr = storage.into();
350 
351         assert_eq!(sockaddr, sockaddr_from_storage);
352     }
353 
354     #[test]
test_sockaddr_v6()355     fn test_sockaddr_v6() {
356         let sockaddr = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into(), 8080, 1, 2);
357         let in_v6: sockaddr_in6 = sockaddr.into();
358 
359         // Pointer to the sockaddr_in6 ip address raw octets
360         // SAFETY: this is safe because `sin6_addr` is type `in6_addr.`
361         let in_v6_ip_octets = unsafe {
362             std::slice::from_raw_parts(
363                 &in_v6.sin6_addr as *const _ as *const u8,
364                 mem::size_of::<in6_addr>(),
365             )
366         };
367         // Host order port and flowinfo
368         let in_v6_port = net::ntohs(in_v6.sin6_port);
369         let in_v6_flowinfo = net::ntohl(in_v6.sin6_flowinfo);
370 
371         // Compare ip, port, flowinfo after conversion from SocketAddrV6 -> sockaddr_in6
372         assert_eq!(sockaddr.port(), in_v6_port);
373         assert_eq!(sockaddr.ip().octets(), in_v6_ip_octets);
374         assert_eq!(sockaddr.flowinfo(), in_v6_flowinfo);
375 
376         // Effectively compares ip, port, flowinfo after conversion
377         // from sockaddr_in6 -> SocketAddrV6
378         let sockaddr_from: SocketAddrV6 = in_v6.into();
379         assert_eq!(sockaddr, sockaddr_from);
380     }
381 
382     #[test]
test_sockaddr_v4()383     fn test_sockaddr_v4() {
384         let sockaddr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
385         let in_v4: sockaddr_in = sockaddr.into();
386 
387         // Pointer to the sockaddr_in ip address raw octets
388         // SAFETY: this is safe because `sin_addr` is type `in_addr.`
389         let in_v4_ip_octets = unsafe {
390             std::slice::from_raw_parts(
391                 &in_v4.sin_addr as *const _ as *const u8,
392                 mem::size_of::<in_addr>(),
393             )
394         };
395         // Host order port
396         let in_v4_port = net::ntohs(in_v4.sin_port);
397 
398         // Compare ip and port after conversion from SocketAddrV4 -> sockaddr_in
399         assert_eq!(sockaddr.port(), in_v4_port);
400         assert_eq!(sockaddr.ip().octets(), in_v4_ip_octets);
401 
402         // Effectively compares ip and port after conversion from
403         // sockaddr_in -> SocketAddrV4
404         let sockaddr_from: SocketAddrV4 = in_v4.into();
405         assert_eq!(sockaddr, sockaddr_from);
406     }
407 }
408