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 _ => return Err(Errno::Inval),
278 },
279 expires_at: match route.expires_at.tag {
280 OptionTag::None => None,
281 OptionTag::Some => Some(Duration::from_nanos(route.expires_at.u)),
282 _ => return Err(Errno::Inval),
283 },
284 })
285}
286
287pub(crate) fn write_route<M: MemorySize>(
288 memory: &MemoryView,
289 ptr: WasmPtr<Route, M>,
290 route: IpRoute,
291) -> Result<(), Errno> {
292 let cidr = {
293 let p = route.cidr.prefix;
294 match route.cidr.ip {
295 IpAddr::V4(ip) => {
296 let o = ip.octets();
297 __wasi_cidr_t {
298 tag: Addressfamily::Inet4,
299 _padding: 0,
300 u: __wasi_cidr_u {
301 octs: [
302 o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
303 ],
304 },
305 }
306 }
307 IpAddr::V6(ip) => {
308 let o = ip.octets();
309 __wasi_cidr_t {
310 tag: Addressfamily::Inet6,
311 _padding: 0,
312 u: __wasi_cidr_u {
313 octs: [
314 o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10],
315 o[11], o[12], o[13], o[14], o[15], p,
316 ],
317 },
318 }
319 }
320 }
321 };
322 let via_router = match route.via_router {
323 IpAddr::V4(ip) => {
324 let o = ip.octets();
325 __wasi_addr_t {
326 tag: Addressfamily::Inet4,
327 _padding: 0,
328 u: __wasi_addr_u {
329 octs: [o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
330 },
331 }
332 }
333 IpAddr::V6(ip) => {
334 let o = ip.octets();
335 __wasi_addr_t {
336 tag: Addressfamily::Inet6,
337 _padding: 0,
338 u: __wasi_addr_u { octs: o },
339 }
340 }
341 };
342 let preferred_until = match route.preferred_until {
343 None => OptionTimestamp {
344 tag: OptionTag::None,
345 u: 0,
346 },
347 Some(u) => OptionTimestamp {
348 tag: OptionTag::Some,
349 u: u.as_nanos() as u64,
350 },
351 };
352 let expires_at = match route.expires_at {
353 None => OptionTimestamp {
354 tag: OptionTag::None,
355 u: 0,
356 },
357 Some(u) => OptionTimestamp {
358 tag: OptionTag::Some,
359 u: u.as_nanos() as u64,
360 },
361 };
362
363 let route = Route {
364 cidr,
365 via_router,
366 preferred_until,
367 expires_at,
368 };
369
370 let route_ptr = ptr.deref(memory);
371 route_ptr.write(route).map_err(crate::mem_error_to_wasi)?;
372 Ok(())
373}
374
375pub fn net_error_into_wasi_err(net_error: NetworkError) -> Errno {
376 match net_error {
377 NetworkError::InvalidFd => Errno::Badf,
378 NetworkError::AlreadyExists => Errno::Exist,
379 NetworkError::Lock => Errno::Io,
380 NetworkError::IOError => Errno::Io,
381 NetworkError::AddressInUse => Errno::Addrinuse,
382 NetworkError::AddressNotAvailable => Errno::Addrnotavail,
383 NetworkError::BrokenPipe => Errno::Pipe,
384 NetworkError::ConnectionAborted => Errno::Connaborted,
385 NetworkError::ConnectionRefused => Errno::Connrefused,
386 NetworkError::ConnectionReset => Errno::Connreset,
387 NetworkError::Interrupted => Errno::Intr,
388 NetworkError::InvalidData => Errno::Io,
389 NetworkError::InvalidInput => Errno::Inval,
390 NetworkError::NotConnected => Errno::Notconn,
391 NetworkError::NoDevice => Errno::Nodev,
392 NetworkError::PermissionDenied => Errno::Perm,
393 NetworkError::TimedOut => Errno::Timedout,
394 NetworkError::UnexpectedEof => Errno::Proto,
395 NetworkError::WouldBlock => Errno::Again,
396 NetworkError::WriteZero => Errno::Nospc,
397 NetworkError::TooManyOpenFiles => Errno::Mfile,
398 NetworkError::InsufficientMemory => Errno::Nomem,
399 NetworkError::Unsupported => Errno::Notsup,
400 NetworkError::UnknownError => Errno::Io,
401 }
402}