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