1use std::{
2 mem::transmute,
3 net::{IpAddr, Ipv4Addr, Ipv6Addr},
4 time::Duration,
5};
6
7use virtual_net::{IpCidr, IpRoute, NetworkError};
8use wasmer::{MemoryView, WasmPtr};
9use wasmer_types::MemorySize;
10use wasmer_wasix_types::{
11 types::{
12 __wasi_addr_ip4_t, __wasi_addr_ip6_t, __wasi_addr_port_t, __wasi_addr_port_u,
13 __wasi_addr_t, __wasi_addr_u, __wasi_cidr_t, __wasi_cidr_u, OptionTag, OptionTimestamp,
14 Route,
15 },
16 wasi::{Addressfamily, Errno},
17};
18
19pub mod socket;
20
21#[allow(dead_code)]
22pub(crate) fn read_ip<M: MemorySize>(
23 memory: &MemoryView,
24 ptr: WasmPtr<__wasi_addr_t, M>,
25) -> Result<IpAddr, Errno> {
26 let addr_ptr = ptr.deref(memory);
27 let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?;
28
29 let o = addr.u.octs;
30 Ok(match addr.tag {
31 Addressfamily::Inet4 => IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])),
32 Addressfamily::Inet6 => {
33 let [a, b, c, d, e, f, g, h] = unsafe { transmute::<[u8; 16], [u16; 8]>(o) };
34 IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
35 }
36 _ => return Err(Errno::Inval),
37 })
38}
39
40pub(crate) fn read_ip_v4<M: MemorySize>(
41 memory: &MemoryView,
42 ptr: WasmPtr<__wasi_addr_ip4_t, M>,
43) -> Result<Ipv4Addr, Errno> {
44 let addr_ptr = ptr.deref(memory);
45 let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?;
46
47 let o = addr.octs;
48 Ok(Ipv4Addr::new(o[0], o[1], o[2], o[3]))
49}
50
51pub(crate) fn read_ip_v6<M: MemorySize>(
52 memory: &MemoryView,
53 ptr: WasmPtr<__wasi_addr_ip6_t, M>,
54) -> Result<Ipv6Addr, Errno> {
55 let addr_ptr = ptr.deref(memory);
56 let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?;
57
58 let [a, b, c, d, e, f, g, h] = unsafe { transmute::<[u8; 16], [u16; 8]>(addr.segs) };
59 Ok(Ipv6Addr::new(a, b, c, d, e, f, g, h))
60}
61
62pub fn write_ip<M: MemorySize>(
63 memory: &MemoryView,
64 ptr: WasmPtr<__wasi_addr_t, M>,
65 ip: IpAddr,
66) -> Result<(), Errno> {
67 let ip = match ip {
68 IpAddr::V4(ip) => {
69 let o = ip.octets();
70 __wasi_addr_t {
71 tag: Addressfamily::Inet4,
72 _padding: 0,
73 u: __wasi_addr_u {
74 octs: [o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
75 },
76 }
77 }
78 IpAddr::V6(ip) => {
79 let o = ip.octets();
80 __wasi_addr_t {
81 tag: Addressfamily::Inet6,
82 _padding: 0,
83 u: __wasi_addr_u { octs: o },
84 }
85 }
86 };
87
88 let addr_ptr = ptr.deref(memory);
89 addr_ptr.write(ip).map_err(crate::mem_error_to_wasi)?;
90 Ok(())
91}
92
93#[allow(dead_code)]
94pub(crate) fn read_cidr<M: MemorySize>(
95 memory: &MemoryView,
96 ptr: WasmPtr<__wasi_cidr_t, M>,
97) -> Result<IpCidr, Errno> {
98 let addr_ptr = ptr.deref(memory);
99 let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?;
100
101 let o = addr.u.octs;
102 Ok(match addr.tag {
103 Addressfamily::Inet4 => IpCidr {
104 ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])),
105 prefix: o[4],
106 },
107 Addressfamily::Inet6 => {
108 let [a, b, c, d, e, f, g, h] = {
109 let o = [
110 o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11],
111 o[12], o[13], o[14], o[15],
112 ];
113 unsafe { transmute::<[u8; 16], [u16; 8]>(o) }
114 };
115 IpCidr {
116 ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)),
117 prefix: o[16],
118 }
119 }
120 _ => return Err(Errno::Inval),
121 })
122}
123
124#[allow(dead_code)]
125pub(crate) fn write_cidr<M: MemorySize>(
126 memory: &MemoryView,
127 ptr: WasmPtr<__wasi_cidr_t, M>,
128 cidr: IpCidr,
129) -> Result<(), Errno> {
130 let p = cidr.prefix;
131 let cidr = match cidr.ip {
132 IpAddr::V4(ip) => {
133 let o = ip.octets();
134 __wasi_cidr_t {
135 tag: Addressfamily::Inet4,
136 _padding: 0,
137 u: __wasi_cidr_u {
138 octs: [
139 o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
140 ],
141 },
142 }
143 }
144 IpAddr::V6(ip) => {
145 let o = ip.octets();
146 __wasi_cidr_t {
147 tag: Addressfamily::Inet6,
148 _padding: 0,
149 u: __wasi_cidr_u {
150 octs: [
151 o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11],
152 o[12], o[13], o[14], o[15], p,
153 ],
154 },
155 }
156 }
157 };
158
159 let addr_ptr = ptr.deref(memory);
160 addr_ptr.write(cidr).map_err(crate::mem_error_to_wasi)?;
161 Ok(())
162}
163
164pub(crate) fn read_ip_port<M: MemorySize>(
165 memory: &MemoryView,
166 ptr: WasmPtr<__wasi_addr_port_t, M>,
167) -> Result<(IpAddr, u16), Errno> {
168 let addr_ptr = ptr.deref(memory);
169 let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?;
170 let o = addr.u.octs;
171 Ok(match addr.tag {
172 Addressfamily::Inet4 => {
173 let port = u16::from_ne_bytes([o[0], o[1]]);
174 (IpAddr::V4(Ipv4Addr::new(o[2], o[3], o[4], o[5])), port)
175 }
176 Addressfamily::Inet6 => {
177 let octets: [u8; 16] = o[2..18].try_into().unwrap();
178 (
179 IpAddr::V6(Ipv6Addr::from(octets)),
180 u16::from_ne_bytes([o[0], o[1]]),
181 )
182 }
183 _ => {
184 tracing::debug!("invalid address family ({})", addr.tag as u8);
185 return Err(Errno::Inval);
186 }
187 })
188}
189
190#[allow(dead_code)]
191pub(crate) fn write_ip_port<M: MemorySize>(
192 memory: &MemoryView,
193 ptr: WasmPtr<__wasi_addr_port_t, M>,
194 ip: IpAddr,
195 port: u16,
196) -> Result<(), Errno> {
197 let p = port.to_be_bytes();
198 let ipport = match ip {
199 IpAddr::V4(ip) => {
200 let o = ip.octets();
201 __wasi_addr_port_t {
202 tag: Addressfamily::Inet4,
203 _padding: 0,
204 u: __wasi_addr_port_u {
205 octs: [
206 p[0], p[1], o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
207 ],
208 },
209 }
210 }
211 IpAddr::V6(ip) => {
212 let o = ip.octets();
213 __wasi_addr_port_t {
214 tag: Addressfamily::Inet6,
215 _padding: 0,
216 u: __wasi_addr_port_u {
217 octs: [
218 p[0], p[1], o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9],
219 o[10], o[11], o[12], o[13], o[14], o[15],
220 ],
221 },
222 }
223 }
224 };
225
226 let addr_ptr = ptr.deref(memory);
227 addr_ptr.write(ipport).map_err(crate::mem_error_to_wasi)?;
228 Ok(())
229}
230
231#[allow(dead_code)]
232pub(crate) fn read_route<M: MemorySize>(
233 memory: &MemoryView,
234 ptr: WasmPtr<Route, M>,
235) -> Result<IpRoute, Errno> {
236 let route_ptr = ptr.deref(memory);
237 let route = route_ptr.read().map_err(crate::mem_error_to_wasi)?;
238
239 Ok(IpRoute {
240 cidr: {
241 let o = route.cidr.u.octs;
242 match route.cidr.tag {
243 Addressfamily::Inet4 => IpCidr {
244 ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])),
245 prefix: o[4],
246 },
247 Addressfamily::Inet6 => {
248 let [a, b, c, d, e, f, g, h] = {
249 let o = [
250 o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10],
251 o[11], o[12], o[13], o[14], o[15],
252 ];
253 unsafe { transmute::<[u8; 16], [u16; 8]>(o) }
254 };
255 IpCidr {
256 ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)),
257 prefix: o[16],
258 }
259 }
260 _ => return Err(Errno::Inval),
261 }
262 },
263 via_router: {
264 let o = route.via_router.u.octs;
265 match route.via_router.tag {
266 Addressfamily::Inet4 => IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])),
267 Addressfamily::Inet6 => {
268 let [a, b, c, d, e, f, g, h] = unsafe { transmute::<[u8; 16], [u16; 8]>(o) };
269 IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
270 }
271 _ => return Err(Errno::Inval),
272 }
273 },
274 preferred_until: match route.preferred_until.tag {
275 OptionTag::None => None,
276 OptionTag::Some => Some(Duration::from_nanos(route.preferred_until.u)),
277 },
278 expires_at: match route.expires_at.tag {
279 OptionTag::None => None,
280 OptionTag::Some => Some(Duration::from_nanos(route.expires_at.u)),
281 },
282 })
283}
284
285pub(crate) fn write_route<M: MemorySize>(
286 memory: &MemoryView,
287 ptr: WasmPtr<Route, M>,
288 route: IpRoute,
289) -> Result<(), Errno> {
290 let cidr = {
291 let p = route.cidr.prefix;
292 match route.cidr.ip {
293 IpAddr::V4(ip) => {
294 let o = ip.octets();
295 __wasi_cidr_t {
296 tag: Addressfamily::Inet4,
297 _padding: 0,
298 u: __wasi_cidr_u {
299 octs: [
300 o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
301 ],
302 },
303 }
304 }
305 IpAddr::V6(ip) => {
306 let o = ip.octets();
307 __wasi_cidr_t {
308 tag: Addressfamily::Inet6,
309 _padding: 0,
310 u: __wasi_cidr_u {
311 octs: [
312 o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10],
313 o[11], o[12], o[13], o[14], o[15], p,
314 ],
315 },
316 }
317 }
318 }
319 };
320 let via_router = match route.via_router {
321 IpAddr::V4(ip) => {
322 let o = ip.octets();
323 __wasi_addr_t {
324 tag: Addressfamily::Inet4,
325 _padding: 0,
326 u: __wasi_addr_u {
327 octs: [o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
328 },
329 }
330 }
331 IpAddr::V6(ip) => {
332 let o = ip.octets();
333 __wasi_addr_t {
334 tag: Addressfamily::Inet6,
335 _padding: 0,
336 u: __wasi_addr_u { octs: o },
337 }
338 }
339 };
340 let preferred_until = match route.preferred_until {
341 None => OptionTimestamp {
342 tag: OptionTag::None,
343 u: 0,
344 },
345 Some(u) => OptionTimestamp {
346 tag: OptionTag::Some,
347 u: u.as_nanos() as u64,
348 },
349 };
350 let expires_at = match route.expires_at {
351 None => OptionTimestamp {
352 tag: OptionTag::None,
353 u: 0,
354 },
355 Some(u) => OptionTimestamp {
356 tag: OptionTag::Some,
357 u: u.as_nanos() as u64,
358 },
359 };
360
361 let route = Route {
362 cidr,
363 via_router,
364 preferred_until,
365 expires_at,
366 };
367
368 let route_ptr = ptr.deref(memory);
369 route_ptr.write(route).map_err(crate::mem_error_to_wasi)?;
370 Ok(())
371}
372
373pub fn net_error_into_wasi_err(net_error: NetworkError) -> Errno {
374 match net_error {
375 NetworkError::InvalidFd => Errno::Badf,
376 NetworkError::AlreadyExists => Errno::Exist,
377 NetworkError::Lock => Errno::Io,
378 NetworkError::IOError => Errno::Io,
379 NetworkError::AddressInUse => Errno::Addrinuse,
380 NetworkError::AddressNotAvailable => Errno::Addrnotavail,
381 NetworkError::BrokenPipe => Errno::Pipe,
382 NetworkError::ConnectionAborted => Errno::Connaborted,
383 NetworkError::ConnectionRefused => Errno::Connrefused,
384 NetworkError::ConnectionReset => Errno::Connreset,
385 NetworkError::Interrupted => Errno::Intr,
386 NetworkError::InvalidData => Errno::Io,
387 NetworkError::InvalidInput => Errno::Inval,
388 NetworkError::NotConnected => Errno::Notconn,
389 NetworkError::NoDevice => Errno::Nodev,
390 NetworkError::PermissionDenied => Errno::Perm,
391 NetworkError::TimedOut => Errno::Timedout,
392 NetworkError::UnexpectedEof => Errno::Proto,
393 NetworkError::WouldBlock => Errno::Again,
394 NetworkError::WriteZero => Errno::Nospc,
395 NetworkError::TooManyOpenFiles => Errno::Mfile,
396 NetworkError::InsufficientMemory => Errno::Nomem,
397 NetworkError::Unsupported => Errno::Notsup,
398 NetworkError::UnknownError => Errno::Io,
399 }
400}