wasmer_wasix/net/
mod.rs

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}