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        },
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}