netsim_embed_machine/
iface.rs

1use netsim_embed_core::Ipv4Route;
2use std::ffi::{CStr, CString};
3use std::io::{self, Read, Write};
4use std::mem;
5use std::net::Ipv4Addr;
6use std::os::unix::io::{AsRawFd, RawFd};
7
8mod ioctl {
9    use ioctl_sys::*;
10    use libc::*;
11    use std::ffi::CStr;
12    use std::net::Ipv4Addr;
13
14    #[repr(C)]
15    #[derive(Clone, Copy)]
16    pub struct ifreq {
17        pub ifr_ifrn: __ifreq_ifr_ifrn,
18        pub ifr_ifru: __ifreq_ifr_ifru,
19    }
20
21    impl ifreq {
22        pub fn new(name: &CStr) -> Self {
23            unsafe {
24                let mut req: Self = std::mem::zeroed();
25                std::ptr::copy_nonoverlapping(
26                    name.as_ptr(),
27                    req.ifr_ifrn.ifrn_name.as_mut_ptr() as *mut _,
28                    name.to_bytes().len(),
29                );
30                req
31            }
32        }
33
34        pub fn set_ifru_addr(&mut self, ipv4_addr: Ipv4Addr) {
35            unsafe {
36                let addr = &mut self.ifr_ifru.ifru_addr as *mut libc::sockaddr;
37                let addr = &mut *(addr as *mut libc::sockaddr_in);
38                addr.sin_family = libc::AF_INET as libc::sa_family_t;
39                addr.sin_port = 0;
40                addr.sin_addr.s_addr = u32::from(ipv4_addr).to_be();
41            }
42        }
43    }
44
45    #[repr(C)]
46    #[derive(Clone, Copy)]
47    pub union __ifreq_ifr_ifrn {
48        pub ifrn_name: [c_char; IFNAMSIZ],
49    }
50
51    #[repr(C)]
52    #[derive(Clone, Copy)]
53    pub union __ifreq_ifr_ifru {
54        pub ifru_addr: sockaddr,
55        pub ifru_dstaddr: sockaddr,
56        pub ifru_broadaddr: sockaddr,
57        pub ifru_netmask: sockaddr,
58        pub ifru_hwaddr: sockaddr,
59        pub ifru_flags: c_short,
60        pub ifru_ivalue: c_int,
61        pub ifru_mtu: c_int,
62        pub ifru: ifmap,
63        pub ifru_slave: [c_char; IFNAMSIZ],
64        pub ifru_newname: [c_char; IFNAMSIZ],
65        pub ifru_data: *mut c_void,
66    }
67
68    #[repr(C)]
69    #[derive(Debug, Clone, Copy)]
70    pub struct ifmap {
71        pub mem_start: c_ulong,
72        pub mem_end: c_ulong,
73        pub base_addr: c_ushort,
74        pub irq: c_uchar,
75        pub dma: c_uchar,
76        pub port: c_uchar,
77    }
78
79    ioctl!(bad read siocgifflags with 0x8913; ifreq);
80    ioctl!(bad write siocsifflags with 0x8914; ifreq);
81    ioctl!(bad write siocsifaddr with 0x8916; ifreq);
82    ioctl!(bad write siocsifnetmask with 0x891c; ifreq);
83    ioctl!(write tunsetiff with b'T', 202; libc::c_int);
84    ioctl!(write tunsetoffload with b'T', 208; libc::c_int);
85}
86
87/// See: https://www.kernel.org/doc/Documentation/networking/tuntap.txt
88pub struct Iface {
89    name: CString,
90    fd: RawFd,
91}
92
93impl AsRawFd for Iface {
94    fn as_raw_fd(&self) -> RawFd {
95        self.fd
96    }
97}
98
99impl Drop for Iface {
100    fn drop(&mut self) {
101        let _ = unsafe { libc::close(self.as_raw_fd()) };
102    }
103}
104
105impl Read for Iface {
106    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
107        self.recv(buf)
108    }
109}
110
111impl Write for Iface {
112    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
113        self.send(buf)
114    }
115
116    fn flush(&mut self) -> io::Result<()> {
117        Ok(())
118    }
119}
120
121impl Iface {
122    /// Creates a new virtual network interface.
123    pub fn new() -> Result<Self, io::Error> {
124        // create loopback interface
125        unsafe {
126            let fd = errno!(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0))?;
127            let lo = CString::new("lo")?;
128
129            let mut req = ioctl::ifreq::new(&lo);
130            req.set_ifru_addr(Ipv4Addr::LOCALHOST);
131
132            if let Err(err) = errno!(ioctl::siocsifaddr(fd, &req)) {
133                let _ = libc::close(fd);
134                return Err(err);
135            }
136
137            let mut req = ioctl::ifreq::new(&lo);
138            req.ifr_ifru.ifru_flags |=
139                libc::IFF_UP as i16 | libc::IFF_LOOPBACK as i16 | libc::IFF_RUNNING as i16;
140
141            let res = errno!(ioctl::siocsifflags(fd, &req));
142            let _ = libc::close(fd);
143            res?;
144        }
145        // create tun interface
146        unsafe {
147            let fd = loop {
148                match errno!(libc::open(
149                    b"/dev/net/tun\0".as_ptr() as *const _,
150                    libc::O_RDWR
151                )) {
152                    Ok(fd) => break fd,
153                    Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
154                    Err(err) => return Err(err),
155                }
156            };
157
158            let mut req: ioctl::ifreq = mem::zeroed();
159            req.ifr_ifru.ifru_flags = libc::IFF_TUN as i16 | libc::IFF_NO_PI as i16;
160
161            errno!(ioctl::tunsetiff(fd, &mut req as *mut _ as *mut _))?;
162
163            let name = CStr::from_ptr(&req.ifr_ifrn.ifrn_name as *const _).to_owned();
164
165            errno!(ioctl::tunsetoffload(
166                fd,
167                0x01 as *const libc::c_void as *const _
168            ))?;
169
170            Ok(Self { name, fd })
171        }
172    }
173
174    /// Returns the name of the iface.
175    pub fn name(&self) -> &CStr {
176        &self.name
177    }
178
179    /// Receives a packet.
180    pub fn recv(&self, buf: &mut [u8]) -> Result<usize, io::Error> {
181        Ok(unsafe {
182            errno!(libc::read(
183                self.as_raw_fd(),
184                buf.as_mut_ptr() as *mut _,
185                buf.len()
186            ))? as _
187        })
188    }
189
190    /// Sends a packet.
191    pub fn send(&self, buf: &[u8]) -> Result<usize, io::Error> {
192        Ok(unsafe {
193            errno!(libc::write(
194                self.as_raw_fd(),
195                buf.as_ptr() as *mut _,
196                buf.len()
197            ))? as _
198        })
199    }
200
201    /// Set an interface IPv4 address and netmask.
202    pub fn set_ipv4_addr(&self, ipv4_addr: Ipv4Addr, netmask_bits: u8) -> Result<(), io::Error> {
203        unsafe {
204            let fd = errno!(libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0))?;
205            let mut req = ioctl::ifreq::new(self.name());
206            req.set_ifru_addr(ipv4_addr);
207
208            if let Err(err) = errno!(ioctl::siocsifaddr(fd, &req)) {
209                let _ = libc::close(fd);
210                return Err(err);
211            }
212
213            let netmask = Ipv4Addr::from(!((!0u32) >> netmask_bits));
214            req.set_ifru_addr(netmask);
215
216            let res = errno!(ioctl::siocsifnetmask(fd, &req));
217            let _ = libc::close(fd);
218            res?;
219            Ok(())
220        }
221    }
222
223    /// Put an interface up.
224    pub fn put_up(&self) -> Result<(), io::Error> {
225        unsafe {
226            let fd = errno!(libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0))?;
227            let mut req = ioctl::ifreq::new(self.name());
228
229            if let Err(err) = errno!(ioctl::siocgifflags(fd, &mut req)) {
230                let _ = libc::close(fd);
231                return Err(err);
232            }
233
234            req.ifr_ifru.ifru_flags |= libc::IFF_UP as i16 | libc::IFF_RUNNING as i16;
235
236            let res = errno!(ioctl::siocsifflags(fd, &req));
237            let _ = libc::close(fd);
238            res?;
239            Ok(())
240        }
241    }
242
243    /// Put an interface down.
244    pub fn put_down(&self) -> Result<(), io::Error> {
245        unsafe {
246            let fd = errno!(libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0))?;
247            let mut req = ioctl::ifreq::new(self.name());
248
249            if let Err(err) = errno!(ioctl::siocgifflags(fd, &mut req)) {
250                let _ = libc::close(fd);
251                return Err(err);
252            }
253
254            req.ifr_ifru.ifru_flags &= !(libc::IFF_UP as i16);
255
256            let res = errno!(ioctl::siocsifflags(fd, &req));
257            let _ = libc::close(fd);
258            res?;
259            Ok(())
260        }
261    }
262
263    /// Adds an ipv4 route.
264    pub fn add_ipv4_route(&self, route: Ipv4Route) -> Result<(), io::Error> {
265        unsafe {
266            let fd = errno!(libc::socket(
267                libc::PF_INET,
268                libc::SOCK_DGRAM,
269                libc::IPPROTO_IP,
270            ))?;
271
272            let mut rtentry: libc::rtentry = mem::zeroed();
273
274            let rt_dst = &mut *(&mut rtentry.rt_dst as *mut _ as *mut libc::sockaddr_in);
275            rt_dst.sin_family = libc::AF_INET as u16;
276            rt_dst.sin_addr = libc::in_addr {
277                s_addr: u32::from(route.dest().base_addr()).to_be(),
278            };
279
280            let rt_genmask = &mut *(&mut rtentry.rt_genmask as *mut _ as *mut libc::sockaddr_in);
281            rt_genmask.sin_family = libc::AF_INET as u16;
282            rt_genmask.sin_addr = libc::in_addr {
283                s_addr: u32::from(route.dest().netmask()).to_be(),
284            };
285
286            rtentry.rt_flags = libc::RTF_UP;
287
288            if let Some(gateway_addr) = route.gateway() {
289                let rt_gateway =
290                    &mut *(&mut rtentry.rt_gateway as *mut _ as *mut libc::sockaddr_in);
291                rt_gateway.sin_family = libc::AF_INET as u16;
292                rt_gateway.sin_addr = libc::in_addr {
293                    s_addr: u32::from(gateway_addr).to_be(),
294                };
295
296                rtentry.rt_flags |= libc::RTF_GATEWAY;
297            }
298
299            rtentry.rt_dev = self.name.as_ptr() as *mut _;
300
301            if let Err(err) = errno!(libc::ioctl(fd, libc::SIOCADDRT, &rtentry)) {
302                let _ = libc::close(fd);
303                return Err(err);
304            }
305
306            Ok(())
307        }
308    }
309}