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