xref: /aosp_15_r20/tools/netsim/rust/libslirp-rs/src/libslirp_sys/mod.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
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(non_upper_case_globals)]
38 #![allow(non_camel_case_types)]
39 #![allow(non_snake_case)]
40 // TODO(b/203002625) - since rustc 1.53, bindgen causes UB warnings
41 // Remove this once bindgen figures out how to do this correctly
42 #![allow(deref_nullptr)]
43 
44 use std::convert::From;
45 use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
46 
47 #[cfg(target_os = "linux")]
48 include!("linux/bindings.rs");
49 
50 #[cfg(target_os = "macos")]
51 include!("macos/bindings.rs");
52 
53 #[cfg(target_os = "windows")]
54 include!("windows/bindings.rs");
55 
56 impl Default for sockaddr_storage {
57     /// Returns a zeroed `sockaddr_storage`.
58     ///
59     /// This is useful for uninitialied libslirp_config fields.
60     ///
61     /// This is safe because `sockaddr_storage` is a plain old data
62     /// type with no padding or invariants, and a zeroed
63     /// `sockaddr_storage` is a valid representation of "no address".
default() -> Self64     fn default() -> Self {
65         // Safety:
66         //  * sockaddr_storage is repr(C) and has no uninitialized padding bytes.
67         //  * Zeroing a sockaddr_storage is a valid initialization.
68         unsafe { std::mem::zeroed() }
69     }
70 }
71 
v4_ref(storage: &sockaddr_storage) -> &sockaddr_in72 fn v4_ref(storage: &sockaddr_storage) -> &sockaddr_in {
73     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in`.
74     // Neither types have any padding.
75     unsafe { &*(storage as *const sockaddr_storage as *const sockaddr_in) }
76 }
77 
v6_ref(storage: &sockaddr_storage) -> &sockaddr_in678 fn v6_ref(storage: &sockaddr_storage) -> &sockaddr_in6 {
79     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in6`.
80     // Neither types have any padding.
81     unsafe { &*(storage as *const sockaddr_storage as *const sockaddr_in6) }
82 }
83 
v4_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in84 fn v4_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in {
85     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in`.
86     // Neither types have any padding.
87     unsafe { &mut *(storage as *mut sockaddr_storage as *mut sockaddr_in) }
88 }
89 
v6_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in690 fn v6_mut(storage: &mut sockaddr_storage) -> &mut sockaddr_in6 {
91     // SAFETY: `sockaddr_storage` has size and alignment that is at least that of `sockaddr_in6`.
92     // Neither types have any padding.
93     unsafe { &mut *(storage as *mut sockaddr_storage as *mut sockaddr_in6) }
94 }
95 
96 // Type for libslirp poll bitfield mask SLIRP_POLL_nnn
97 
98 #[cfg(target_os = "linux")]
99 pub type SlirpPollType = _bindgen_ty_7;
100 
101 #[cfg(target_os = "macos")]
102 pub type SlirpPollType = _bindgen_ty_1;
103 
104 #[cfg(target_os = "windows")]
105 pub type SlirpPollType = _bindgen_ty_5;
106 
107 impl From<sockaddr_storage> for SocketAddr {
108     /// Converts a `sockaddr_storage` to a `SocketAddr`.
109     ///
110     /// This function safely converts a `sockaddr_storage` from the
111     /// `libslirp_sys` crate into a `std::net::SocketAddr`. It handles
112     /// both IPv4 and IPv6 addresses by checking the `ss_family` field
113     /// and casting the `sockaddr_storage` to the appropriate address
114     /// type (`sockaddr_in` or `sockaddr_in6`).
115     ///
116     /// # Panics
117     ///
118     /// This function will panic if the `ss_family` field of the
119     /// `sockaddr_storage` is not `AF_INET` or `AF_INET6`.
from(storage: sockaddr_storage) -> Self120     fn from(storage: sockaddr_storage) -> Self {
121         match storage.ss_family as u32 {
122             AF_INET => SocketAddr::V4((*v4_ref(&storage)).into()),
123             AF_INET6 => SocketAddr::V6((*v6_ref(&storage)).into()),
124             _ => panic!("Unsupported address family"),
125         }
126     }
127 }
128 
129 impl From<SocketAddr> for sockaddr_storage {
130     /// Converts a `SocketAddr` to a `sockaddr_storage`.
131     ///
132     /// This function safely converts a `std::net::SocketAddr` into a
133     /// `libslirp_sys::sockaddr_storage`. It handles both IPv4 and
134     /// IPv6 addresses by writing the appropriate data into the
135     /// `sockaddr_storage` structure.
136     ///
137     /// This conversion is useful when interacting with
138     /// libslirp_config that expect a `sockaddr_storage` type.
from(sockaddr: SocketAddr) -> Self139     fn from(sockaddr: SocketAddr) -> Self {
140         let mut storage = sockaddr_storage::default();
141 
142         match sockaddr {
143             SocketAddr::V4(addr) => *v4_mut(&mut storage) = addr.into(),
144             SocketAddr::V6(addr) => *v6_mut(&mut storage) = addr.into(),
145         }
146         storage
147     }
148 }
149 
150 impl From<in_addr> for u32 {
from(val: in_addr) -> Self151     fn from(val: in_addr) -> Self {
152         #[cfg(target_os = "windows")]
153         // SAFETY: This is safe because we are accessing a union field and
154         // all fields in the union have the same size.
155         unsafe {
156             val.S_un.S_addr
157         }
158 
159         #[cfg(any(target_os = "macos", target_os = "linux"))]
160         val.s_addr
161     }
162 }
163 
164 mod net {
165     /// Converts a value from host byte order to network byte order.
166     #[inline]
htonl(hostlong: u32) -> u32167     pub fn htonl(hostlong: u32) -> u32 {
168         hostlong.to_be()
169     }
170 
171     /// Converts a value from network byte order to host byte order.
172     #[inline]
ntohl(netlong: u32) -> u32173     pub fn ntohl(netlong: u32) -> u32 {
174         u32::from_be(netlong)
175     }
176 
177     /// Converts a value from host byte order to network byte order.
178     #[inline]
htons(hostshort: u16) -> u16179     pub fn htons(hostshort: u16) -> u16 {
180         hostshort.to_be()
181     }
182 
183     /// Converts a value from network byte order to host byte order.
184     #[inline]
ntohs(netshort: u16) -> u16185     pub fn ntohs(netshort: u16) -> u16 {
186         u16::from_be(netshort)
187     }
188 }
189 
190 impl From<Ipv4Addr> for in_addr {
from(item: Ipv4Addr) -> Self191     fn from(item: Ipv4Addr) -> Self {
192         #[cfg(target_os = "windows")]
193         return in_addr {
194             S_un: in_addr__bindgen_ty_1 { S_addr: std::os::raw::c_ulong::to_be(item.into()) },
195         };
196 
197         #[cfg(any(target_os = "macos", target_os = "linux"))]
198         return in_addr { s_addr: net::htonl(item.into()) };
199     }
200 }
201 
202 impl From<in6_addr> for Ipv6Addr {
from(item: in6_addr) -> Self203     fn from(item: in6_addr) -> Self {
204         // SAFETY: Access union field. This is safe because we are
205         // accessing the underlying byte array representation of the
206         // `in6_addr` struct on macOS and all variants have the same
207         // size.
208         #[cfg(target_os = "macos")]
209         return Ipv6Addr::from(unsafe { item.__u6_addr.__u6_addr8 });
210 
211         // SAFETY: Access union field. This is safe because we are
212         // accessing the underlying byte array representation of the
213         // `in6_addr` struct on Linux and all variants have the same
214         // size.
215         #[cfg(target_os = "linux")]
216         return Ipv6Addr::from(unsafe { item.__in6_u.__u6_addr8 });
217 
218         // SAFETY: Access union field. This is safe because we are
219         // accessing the underlying byte array representation of the
220         // `in6_addr` struct on Windows and all variants have the same
221         // size.
222         #[cfg(target_os = "windows")]
223         return Ipv6Addr::from(unsafe { item.u.Byte });
224     }
225 }
226 
227 impl From<Ipv6Addr> for in6_addr {
from(item: Ipv6Addr) -> Self228     fn from(item: Ipv6Addr) -> Self {
229         #[cfg(target_os = "macos")]
230         return in6_addr { __u6_addr: in6_addr__bindgen_ty_1 { __u6_addr8: item.octets() } };
231 
232         #[cfg(target_os = "linux")]
233         return in6_addr { __in6_u: in6_addr__bindgen_ty_1 { __u6_addr8: item.octets() } };
234 
235         #[cfg(target_os = "windows")]
236         return in6_addr { u: in6_addr__bindgen_ty_1 { Byte: item.octets() } };
237     }
238 }
239 
240 impl From<SocketAddrV4> for sockaddr_in {
from(item: SocketAddrV4) -> Self241     fn from(item: SocketAddrV4) -> Self {
242         #[cfg(target_os = "macos")]
243         return sockaddr_in {
244             sin_len: 16u8,
245             sin_family: AF_INET as u8,
246             sin_port: net::htons(item.port()),
247             sin_addr: (*item.ip()).into(),
248             sin_zero: [0; 8],
249         };
250 
251         #[cfg(any(target_os = "linux", target_os = "windows"))]
252         return sockaddr_in {
253             sin_family: AF_INET as u16,
254             sin_port: net::htons(item.port()),
255             sin_addr: (*item.ip()).into(),
256             sin_zero: [0; 8],
257         };
258     }
259 }
260 
261 impl From<sockaddr_in> for SocketAddrV4 {
from(item: sockaddr_in) -> Self262     fn from(item: sockaddr_in) -> Self {
263         SocketAddrV4::new(
264             Ipv4Addr::from(net::ntohl(item.sin_addr.into())),
265             net::ntohs(item.sin_port),
266         )
267     }
268 }
269 
270 impl From<sockaddr_in6> for SocketAddrV6 {
from(item: sockaddr_in6) -> Self271     fn from(item: sockaddr_in6) -> Self {
272         #[cfg(any(target_os = "linux", target_os = "macos"))]
273         return SocketAddrV6::new(
274             Ipv6Addr::from(item.sin6_addr),
275             net::ntohs(item.sin6_port),
276             net::ntohl(item.sin6_flowinfo),
277             item.sin6_scope_id,
278         );
279 
280         #[cfg(target_os = "windows")]
281         return SocketAddrV6::new(
282             Ipv6Addr::from(item.sin6_addr),
283             net::ntohs(item.sin6_port),
284             net::ntohl(item.sin6_flowinfo),
285             // SAFETY: This is safe because we are accessing a union
286             // field where all fields have the same size.
287             unsafe { item.__bindgen_anon_1.sin6_scope_id },
288         );
289     }
290 }
291 
292 impl From<SocketAddrV6> for sockaddr_in6 {
from(item: SocketAddrV6) -> Self293     fn from(item: SocketAddrV6) -> Self {
294         #[cfg(target_os = "windows")]
295         return sockaddr_in6 {
296             sin6_addr: (*item.ip()).into(),
297             sin6_family: AF_INET6 as u16,
298             sin6_port: net::htons(item.port()),
299             sin6_flowinfo: net::htonl(item.flowinfo()),
300             __bindgen_anon_1: sockaddr_in6__bindgen_ty_1 { sin6_scope_id: item.scope_id() },
301         };
302 
303         #[cfg(target_os = "macos")]
304         return sockaddr_in6 {
305             sin6_addr: (*item.ip()).into(),
306             sin6_family: AF_INET6 as u8,
307             sin6_port: net::htons(item.port()),
308             sin6_flowinfo: net::htonl(item.flowinfo()),
309             sin6_scope_id: item.scope_id(),
310             sin6_len: 16,
311         };
312 
313         #[cfg(target_os = "linux")]
314         return sockaddr_in6 {
315             sin6_addr: (*item.ip()).into(),
316             sin6_family: AF_INET6 as u16,
317             sin6_port: net::htons(item.port()),
318             sin6_flowinfo: net::htonl(item.flowinfo()),
319             sin6_scope_id: item.scope_id(),
320         };
321     }
322 }
323 
324 #[cfg(test)]
325 mod tests {
326     use super::*;
327     use std::mem;
328 
329     // This tests a bidirectional conversion between sockaddr_storage
330     // and SocketAddr
331     #[test]
test_sockaddr_storage()332     fn test_sockaddr_storage() {
333         let sockaddr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
334         let storage: sockaddr_storage = sockaddr.into();
335 
336         let sockaddr_from_storage: SocketAddr = storage.into();
337 
338         assert_eq!(sockaddr, sockaddr_from_storage);
339     }
340 
341     #[test]
test_sockaddr_storage_v6()342     fn test_sockaddr_storage_v6() {
343         let sockaddr = SocketAddr::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into(), 8080);
344         let storage: sockaddr_storage = sockaddr.into();
345 
346         let sockaddr_from_storage: SocketAddr = storage.into();
347 
348         assert_eq!(sockaddr, sockaddr_from_storage);
349     }
350 
351     #[test]
test_sockaddr_v6()352     fn test_sockaddr_v6() {
353         let sockaddr = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into(), 8080, 1, 2);
354         let in_v6: sockaddr_in6 = sockaddr.into();
355 
356         // Pointer to the sockaddr_in6 ip address raw octets
357         // SAFETY: this is safe because `sin6_addr` is type `in6_addr.`
358         let in_v6_ip_octets = unsafe {
359             std::slice::from_raw_parts(
360                 &in_v6.sin6_addr as *const _ as *const u8,
361                 mem::size_of::<in6_addr>(),
362             )
363         };
364         // Host order port and flowinfo
365         let in_v6_port = net::ntohs(in_v6.sin6_port);
366         let in_v6_flowinfo = net::ntohl(in_v6.sin6_flowinfo);
367 
368         // Compare ip, port, flowinfo after conversion from SocketAddrV6 -> sockaddr_in6
369         assert_eq!(sockaddr.port(), in_v6_port);
370         assert_eq!(sockaddr.ip().octets(), in_v6_ip_octets);
371         assert_eq!(sockaddr.flowinfo(), in_v6_flowinfo);
372 
373         // Effectively compares ip, port, flowinfo after conversion
374         // from sockaddr_in6 -> SocketAddrV6
375         let sockaddr_from: SocketAddrV6 = in_v6.into();
376         assert_eq!(sockaddr, sockaddr_from);
377     }
378 
379     #[test]
test_sockaddr_v4()380     fn test_sockaddr_v4() {
381         let sockaddr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
382         let in_v4: sockaddr_in = sockaddr.into();
383 
384         // Pointer to the sockaddr_in ip address raw octets
385         // SAFETY: this is safe because `sin_addr` is type `in_addr.`
386         let in_v4_ip_octets = unsafe {
387             std::slice::from_raw_parts(
388                 &in_v4.sin_addr as *const _ as *const u8,
389                 mem::size_of::<in_addr>(),
390             )
391         };
392         // Host order port
393         let in_v4_port = net::ntohs(in_v4.sin_port);
394 
395         // Compare ip and port after conversion from SocketAddrV4 -> sockaddr_in
396         assert_eq!(sockaddr.port(), in_v4_port);
397         assert_eq!(sockaddr.ip().octets(), in_v4_ip_octets);
398 
399         // Effectively compares ip and port after conversion from
400         // sockaddr_in -> SocketAddrV4
401         let sockaddr_from: SocketAddrV4 = in_v4.into();
402         assert_eq!(sockaddr, sockaddr_from);
403     }
404 }
405