1use crate::platform::unix::{Fd, Tun};
2use crate::platform::DeviceImpl;
3use bytes::buf::UninitSlice;
4#[cfg(any(
5 all(target_os = "linux", not(target_env = "ohos")),
6 target_os = "macos",
7 target_os = "freebsd",
8 target_os = "openbsd",
9 target_os = "netbsd",
10))]
11use libc::{AF_INET, AF_INET6, SOCK_DGRAM};
12use std::io;
13use std::io::{IoSlice, IoSliceMut};
14use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
15
16impl FromRawFd for DeviceImpl {
17 unsafe fn from_raw_fd(fd: RawFd) -> Self {
27 DeviceImpl::from_fd(fd).expect(
29 "Failed to create device from file descriptor. \
30 The provided fd must be a valid, open file descriptor \
31 for a TUN/TAP device.",
32 )
33 }
34}
35impl AsRawFd for DeviceImpl {
36 fn as_raw_fd(&self) -> RawFd {
37 self.tun.as_raw_fd()
38 }
39}
40impl AsFd for DeviceImpl {
41 fn as_fd(&self) -> BorrowedFd<'_> {
42 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
43 }
44}
45#[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
46impl std::os::unix::io::IntoRawFd for DeviceImpl {
47 fn into_raw_fd(self) -> RawFd {
48 self.tun.into_raw_fd()
49 }
50}
51impl DeviceImpl {
52 pub(crate) unsafe fn from_fd(fd: RawFd) -> io::Result<Self> {
55 let tun = Fd::new_unchecked(fd);
56 DeviceImpl::from_tun(Tun::new(tun))
57 }
58 pub(crate) unsafe fn borrow_raw(fd: RawFd) -> io::Result<Self> {
64 let tun = Fd::new_unchecked_with_borrow(fd, true);
65 DeviceImpl::from_tun(Tun::new(tun))
66 }
67 pub(crate) fn is_nonblocking(&self) -> io::Result<bool> {
68 self.tun.is_nonblocking()
69 }
70 pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
72 self.tun.set_nonblocking(nonblocking)
73 }
74
75 #[inline]
77 pub(crate) fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
78 self.tun.recv(buf)
79 }
80 #[inline]
81 #[allow(dead_code)]
82 pub(crate) fn recv_uninit(&self, buf: &mut UninitSlice) -> io::Result<usize> {
83 self.tun.recv_uninit(buf)
84 }
85 #[inline]
86 pub(crate) fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
87 self.tun.recv_vectored(bufs)
88 }
89
90 #[inline]
92 pub(crate) fn send(&self, buf: &[u8]) -> io::Result<usize> {
93 self.tun.send(buf)
94 }
95 #[inline]
96 pub(crate) fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
97 self.tun.send_vectored(bufs)
98 }
99 #[cfg(feature = "interruptible")]
100 pub(crate) fn read_interruptible(
101 &self,
102 buf: &mut [u8],
103 event: &crate::InterruptEvent,
104 timeout: Option<std::time::Duration>,
105 ) -> io::Result<usize> {
106 self.tun.read_interruptible(buf, event, timeout)
107 }
108 #[cfg(feature = "interruptible")]
109 pub(crate) fn readv_interruptible(
110 &self,
111 bufs: &mut [IoSliceMut<'_>],
112 event: &crate::InterruptEvent,
113 timeout: Option<std::time::Duration>,
114 ) -> io::Result<usize> {
115 self.tun.readv_interruptible(bufs, event, timeout)
116 }
117 #[cfg(feature = "interruptible")]
118 #[inline]
119 pub(crate) fn wait_readable_interruptible(
120 &self,
121 event: &crate::InterruptEvent,
122 timeout: Option<std::time::Duration>,
123 ) -> io::Result<()> {
124 self.tun.wait_readable_interruptible(event, timeout)
125 }
126 #[cfg(feature = "interruptible")]
127 pub(crate) fn write_interruptible(
128 &self,
129 buf: &[u8],
130 event: &crate::InterruptEvent,
131 ) -> io::Result<usize> {
132 self.tun.write_interruptible(buf, event)
133 }
134 #[cfg(feature = "interruptible")]
135 #[inline]
136 pub(crate) fn writev_interruptible(
137 &self,
138 bufs: &[IoSlice<'_>],
139 event: &crate::InterruptEvent,
140 ) -> io::Result<usize> {
141 self.tun.writev_interruptible(bufs, event)
142 }
143 #[cfg(feature = "interruptible")]
144 #[inline]
145 pub(crate) fn wait_writable_interruptible(
146 &self,
147 event: &crate::InterruptEvent,
148 ) -> io::Result<()> {
149 self.tun.wait_writable_interruptible(event)
150 }
151}
152#[cfg(any(
153 all(target_os = "linux", not(target_env = "ohos")),
154 target_os = "macos",
155 target_os = "freebsd",
156 target_os = "openbsd",
157 target_os = "netbsd",
158))]
159impl DeviceImpl {
160 pub fn if_index(&self) -> io::Result<u32> {
166 let _guard = self.op_lock.read().unwrap();
167 self.if_index_impl()
168 }
169 pub(crate) fn if_index_impl(&self) -> io::Result<u32> {
170 let if_name = std::ffi::CString::new(self.name_impl()?)?;
171 unsafe { Ok(libc::if_nametoindex(if_name.as_ptr())) }
172 }
173 pub fn addresses(&self) -> io::Result<Vec<std::net::IpAddr>> {
179 Ok(crate::platform::get_if_addrs_by_name(self.name_impl()?)?
180 .iter()
181 .filter_map(|v| v.address.ip_addr())
182 .collect())
183 }
184}
185#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos",))]
186impl DeviceImpl {
187 pub fn ignore_packet_info(&self) -> bool {
198 let _guard = self.op_lock.read().unwrap();
199 self.tun.ignore_packet_info()
200 }
201 pub fn set_ignore_packet_info(&self, ign: bool) {
213 let _guard = self.op_lock.write().unwrap();
214 self.tun.set_ignore_packet_info(ign)
215 }
216}
217#[cfg(any(
218 all(target_os = "linux", not(target_env = "ohos")),
219 target_os = "freebsd",
220 target_os = "openbsd",
221 target_os = "netbsd",
222))]
223pub(crate) unsafe fn ctl() -> io::Result<Fd> {
224 Fd::new(libc::socket(AF_INET, SOCK_DGRAM | libc::SOCK_CLOEXEC, 0))
225}
226#[cfg(target_os = "macos")]
227pub(crate) unsafe fn ctl() -> io::Result<Fd> {
228 let fd = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
229 _ = fd.set_cloexec();
230 Ok(fd)
231}
232#[cfg(any(
233 all(target_os = "linux", not(target_env = "ohos")),
234 target_os = "freebsd",
235 target_os = "openbsd",
236 target_os = "netbsd",
237))]
238pub(crate) unsafe fn ctl_v6() -> io::Result<Fd> {
239 Fd::new(libc::socket(AF_INET6, SOCK_DGRAM | libc::SOCK_CLOEXEC, 0))
240}
241#[cfg(target_os = "macos")]
242pub(crate) unsafe fn ctl_v6() -> io::Result<Fd> {
243 let fd = Fd::new(libc::socket(AF_INET6, SOCK_DGRAM, 0))?;
244 _ = fd.set_cloexec();
245 Ok(fd)
246}
247
248#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",))]
251pub(crate) unsafe fn copy_device_name(name: &str, dest: *mut libc::c_char, max_len: usize) {
252 use std::ptr;
253 let copy_len = name.len().min(max_len - 1);
254 ptr::copy_nonoverlapping(name.as_ptr() as *const libc::c_char, dest, copy_len);
255}