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