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