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
87pub 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 pub fn new() -> Result<Self, io::Error> {
124 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 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 pub fn name(&self) -> &CStr {
176 &self.name
177 }
178
179 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 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 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 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 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 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}