From 3c8fb5a74990a31d9f76f1eeafe2ff3725bd5cfc Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sun, 5 Nov 2023 23:18:25 +0800 Subject: [PATCH 01/44] clean code due to libc crate updated, ifreq struct added --- .github/workflows/rust.yml | 5 +-- src/platform/macos/device.rs | 36 +++++++++--------- src/platform/macos/sys.rs | 74 +----------------------------------- 3 files changed, 20 insertions(+), 95 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b92f5846..7fd4430e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,10 +1,7 @@ name: Push or PR on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] + [push, pull_request] env: CARGO_TERM_COLOR: always diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index 6af3336c..c0daf5ed 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -87,16 +87,16 @@ impl Device { return Err(io::Error::last_os_error().into()); } - let addr = sockaddr_ctl { + let addr = libc::sockaddr_ctl { sc_id: info.ctl_id, - sc_len: mem::size_of::() as _, + sc_len: mem::size_of::() as _, sc_family: AF_SYSTEM as _, ss_sysaddr: AF_SYS_CONTROL as _, sc_unit: id as c_uint, sc_reserved: [0; 5], }; - let address = &addr as *const sockaddr_ctl as *const sockaddr; + let address = &addr as *const libc::sockaddr_ctl as *const sockaddr; if libc::connect(tun.0, address, mem::size_of_val(&addr) as socklen_t) < 0 { return Err(io::Error::last_os_error().into()); } @@ -133,11 +133,11 @@ impl Device { /// Prepare a new request. /// # Safety - pub unsafe fn request(&self) -> ifreq { - let mut req: ifreq = mem::zeroed(); + pub unsafe fn request(&self) -> libc::ifreq { + let mut req: libc::ifreq = mem::zeroed(); ptr::copy_nonoverlapping( self.name.as_ptr() as *const c_char, - req.ifrn.name.as_mut_ptr(), + req.ifr_name.as_mut_ptr(), self.name.len(), ); @@ -228,9 +228,9 @@ impl D for Device { } if value { - req.ifru.flags |= (IFF_UP | IFF_RUNNING) as c_short; + req.ifr_ifru.ifru_flags |= (IFF_UP | IFF_RUNNING) as c_short; } else { - req.ifru.flags &= !(IFF_UP as c_short); + req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short); } if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 { @@ -249,14 +249,14 @@ impl D for Device { return Err(io::Error::last_os_error().into()); } - SockAddr::new(&req.ifru.addr).map(Into::into) + SockAddr::new(&req.ifr_ifru.ifru_addr).map(Into::into) } } fn set_address(&mut self, value: Ipv4Addr) -> Result<()> { unsafe { let mut req = self.request(); - req.ifru.addr = SockAddr::from(value).into(); + req.ifr_ifru.ifru_addr = SockAddr::from(value).into(); if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); @@ -274,14 +274,14 @@ impl D for Device { return Err(io::Error::last_os_error().into()); } - SockAddr::new(&req.ifru.dstaddr).map(Into::into) + SockAddr::new(&req.ifr_ifru.ifru_dstaddr).map(Into::into) } } fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> { unsafe { let mut req = self.request(); - req.ifru.dstaddr = SockAddr::from(value).into(); + req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into(); if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); @@ -299,14 +299,14 @@ impl D for Device { return Err(io::Error::last_os_error().into()); } - SockAddr::new(&req.ifru.broadaddr).map(Into::into) + SockAddr::new(&req.ifr_ifru.ifru_broadaddr).map(Into::into) } } fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> { unsafe { let mut req = self.request(); - req.ifru.broadaddr = SockAddr::from(value).into(); + req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into(); if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); @@ -324,14 +324,14 @@ impl D for Device { return Err(io::Error::last_os_error().into()); } - SockAddr::unchecked(&req.ifru.addr).map(Into::into) + SockAddr::unchecked(&req.ifr_ifru.ifru_addr).map(Into::into) } } fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> { unsafe { let mut req = self.request(); - req.ifru.addr = SockAddr::from(value).into(); + req.ifr_ifru.ifru_addr = SockAddr::from(value).into(); if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); @@ -349,14 +349,14 @@ impl D for Device { return Err(io::Error::last_os_error().into()); } - Ok(req.ifru.mtu) + Ok(req.ifr_ifru.ifru_mtu) } } fn set_mtu(&mut self, value: i32) -> Result<()> { unsafe { let mut req = self.request(); - req.ifru.mtu = value; + req.ifr_ifru.ifru_mtu = value; if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); diff --git a/src/platform/macos/sys.rs b/src/platform/macos/sys.rs index 94412cdc..35e1d009 100644 --- a/src/platform/macos/sys.rs +++ b/src/platform/macos/sys.rs @@ -15,7 +15,7 @@ //! Bindings to internal macOS stuff. use ioctl::*; -use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void, sockaddr, IFNAMSIZ}; +use libc::{c_char, c_uint, ifreq, sockaddr, IFNAMSIZ}; pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control"; @@ -27,78 +27,6 @@ pub struct ctl_info { pub ctl_name: [c_char; 96], } -#[allow(non_camel_case_types)] -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_ctl { - pub sc_len: c_char, - pub sc_family: c_char, - pub ss_sysaddr: c_ushort, - pub sc_id: c_uint, - pub sc_unit: c_uint, - pub sc_reserved: [c_uint; 5], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub union ifrn { - pub name: [c_char; IFNAMSIZ], -} - -#[allow(non_camel_case_types)] -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ifdevmtu { - pub current: c_int, - pub min: c_int, - pub max: c_int, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub union ifku { - pub ptr: *mut c_void, - pub value: c_int, -} - -#[allow(non_camel_case_types)] -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ifkpi { - pub module_id: c_uint, - pub type_: c_uint, - pub ifku: ifku, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub union ifru { - pub addr: sockaddr, - pub dstaddr: sockaddr, - pub broadaddr: sockaddr, - - pub flags: c_short, - pub metric: c_int, - pub mtu: c_int, - pub phys: c_int, - pub media: c_int, - pub intval: c_int, - pub data: *mut c_void, - pub devmtu: ifdevmtu, - pub wake_flags: c_uint, - pub route_refcnt: c_uint, - pub cap: [c_int; 2], - pub functional_type: c_uint, -} - -#[allow(non_camel_case_types)] -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ifreq { - pub ifrn: ifrn, - pub ifru: ifru, -} - #[allow(non_camel_case_types)] #[repr(C)] #[derive(Copy, Clone)] From dde692025bd6e7400a1c081809775577722d7767 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:17:22 +0800 Subject: [PATCH 02/44] refine macos device --- src/platform/macos/device.rs | 104 ++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index c0daf5ed..17f5bc87 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -38,14 +38,24 @@ use std::{ /// A TUN device using the TUN macOS driver. pub struct Device { - name: String, + name: Option, queue: Queue, - ctl: Fd, + ctl: Option, } impl Device { /// Create a new `Device` for the given `Configuration`. pub fn new(config: &Configuration) -> Result { + if let Some(fd) = config.raw_fd { + let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?; + let device = Device { + name: None, + queue: Queue { tun }, + ctl: None, + }; + return Ok(device); + } + let id = if let Some(name) = config.name.as_ref() { if name.len() > IFNAMSIZ { return Err(Error::NameTooLong); @@ -55,9 +65,9 @@ impl Device { return Err(Error::InvalidName); } - name[4..].parse::()? + 1u32 + name[4..].parse::()? + 1_u32 } else { - 0u32 + 0_u32 }; if config.layer.filter(|l| *l != Layer::L3).is_some() { @@ -110,12 +120,14 @@ impl Device { return Err(io::Error::last_os_error().into()); } - let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?; + let ctl = Some(Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?); Device { - name: CStr::from_ptr(name.as_ptr() as *const c_char) - .to_string_lossy() - .into(), + name: Some( + CStr::from_ptr(name.as_ptr() as *const c_char) + .to_string_lossy() + .into(), + ), queue: Queue { tun }, ctl, } @@ -133,32 +145,35 @@ impl Device { /// Prepare a new request. /// # Safety - pub unsafe fn request(&self) -> libc::ifreq { + pub unsafe fn request(&self) -> Result { + let name = self.name.as_ref().ok_or(Error::InvalidConfig)?; let mut req: libc::ifreq = mem::zeroed(); ptr::copy_nonoverlapping( - self.name.as_ptr() as *const c_char, + name.as_ptr() as *const c_char, req.ifr_name.as_mut_ptr(), - self.name.len(), + name.len(), ); - req + Ok(req) } /// Set the IPv4 alias of the device. pub fn set_alias(&mut self, addr: Ipv4Addr, broadaddr: Ipv4Addr, mask: Ipv4Addr) -> Result<()> { + let name = self.name.as_ref().ok_or(Error::InvalidConfig)?; + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { let mut req: ifaliasreq = mem::zeroed(); ptr::copy_nonoverlapping( - self.name.as_ptr() as *const c_char, + name.as_ptr() as *const c_char, req.ifran.as_mut_ptr(), - self.name.len(), + name.len(), ); req.addr = SockAddr::from(addr).into(); req.broadaddr = SockAddr::from(broadaddr).into(); req.mask = SockAddr::from(mask).into(); - if siocaifaddr(self.ctl.as_raw_fd(), &req) < 0 { + if siocaifaddr(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -211,7 +226,7 @@ impl D for Device { type Queue = Queue; fn name(&self) -> Result { - Ok(self.name.clone()) + self.name.as_ref().cloned().ok_or(Error::InvalidConfig) } // XXX: Cannot set interface name on Darwin. @@ -220,10 +235,11 @@ impl D for Device { } fn enabled(&mut self, value: bool) -> Result<()> { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; - if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 { + if siocgifflags(ctl.as_raw_fd(), &mut req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -233,7 +249,7 @@ impl D for Device { req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short); } - if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 { + if siocsifflags(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -242,10 +258,11 @@ impl D for Device { } fn address(&self) -> Result { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; - if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 { + if siocgifaddr(ctl.as_raw_fd(), &mut req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -254,11 +271,12 @@ impl D for Device { } fn set_address(&mut self, value: Ipv4Addr) -> Result<()> { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; req.ifr_ifru.ifru_addr = SockAddr::from(value).into(); - if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 { + if siocsifaddr(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -267,10 +285,11 @@ impl D for Device { } fn destination(&self) -> Result { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; - if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 { + if siocgifdstaddr(ctl.as_raw_fd(), &mut req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -279,11 +298,12 @@ impl D for Device { } fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into(); - if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 { + if siocsifdstaddr(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -292,10 +312,11 @@ impl D for Device { } fn broadcast(&self) -> Result { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; - if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 { + if siocgifbrdaddr(ctl.as_raw_fd(), &mut req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -304,11 +325,12 @@ impl D for Device { } fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into(); - if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 { + if siocsifbrdaddr(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -317,10 +339,11 @@ impl D for Device { } fn netmask(&self) -> Result { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; - if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 { + if siocgifnetmask(ctl.as_raw_fd(), &mut req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -329,11 +352,12 @@ impl D for Device { } fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; req.ifr_ifru.ifru_addr = SockAddr::from(value).into(); - if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 { + if siocsifnetmask(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -342,10 +366,11 @@ impl D for Device { } fn mtu(&self) -> Result { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; - if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 { + if siocgifmtu(ctl.as_raw_fd(), &mut req) < 0 { return Err(io::Error::last_os_error().into()); } @@ -354,11 +379,12 @@ impl D for Device { } fn set_mtu(&mut self, value: i32) -> Result<()> { + let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { - let mut req = self.request(); + let mut req = self.request()?; req.ifr_ifru.ifru_mtu = value; - if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 { + if siocsifmtu(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); } From 9d6c74963bcd7e231ed1b377cd4b6179c31c05ad Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:40:28 +0800 Subject: [PATCH 03/44] refactor device n queue --- src/async/win/device.rs | 128 +++++++++++++++++++++++---------- src/platform/windows/device.rs | 81 ++------------------- 2 files changed, 95 insertions(+), 114 deletions(-) diff --git a/src/async/win/device.rs b/src/async/win/device.rs index 8b67037d..2cb8afc3 100644 --- a/src/async/win/device.rs +++ b/src/async/win/device.rs @@ -15,7 +15,7 @@ use core::pin::Pin; use core::task::{Context, Poll}; use std::io; -use std::io::{Error, Write}; +use std::io::Error; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; @@ -26,12 +26,17 @@ use crate::r#async::codec::*; pub struct AsyncDevice { inner: Device, + session: WinSession, } impl AsyncDevice { /// Create a new `AsyncDevice` wrapping around a `Device`. pub fn new(device: Device) -> io::Result { - Ok(AsyncDevice { inner: device }) + let session = WinSession::new(device.queue.get_session())?; + Ok(AsyncDevice { + inner: device, + session, + }) } /// Returns a shared reference to the underlying Device object pub fn get_ref(&self) -> &Device { @@ -56,50 +61,41 @@ impl AsyncRead for AsyncDevice { cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll> { - let rbuf = buf.initialize_unfilled(); - match Pin::new(&mut self.inner).poll_read(cx, rbuf) { - Poll::Ready(Ok(n)) => { - buf.advance(n); - Poll::Ready(Ok(())) - } - Poll::Ready(Err(e)) => Poll::Ready(Err(e)), - Poll::Pending => Poll::Pending, - } + Pin::new(&mut self.session).poll_read(cx, buf) } } impl AsyncWrite for AsyncDevice { fn poll_write( mut self: Pin<&mut Self>, - _cx: &mut Context<'_>, + cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - match self.inner.write(buf) { - Ok(n) => Poll::Ready(Ok(n)), - Err(e) => Poll::Ready(Err(e)), - } + Pin::new(&mut self.session).poll_write(cx, buf) } - fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - match self.inner.flush() { - Ok(n) => Poll::Ready(Ok(n)), - Err(e) => Poll::Ready(Err(e)), - } + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.session).poll_flush(cx) } - fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.session).poll_shutdown(cx) } } pub struct AsyncQueue { inner: Queue, + session: WinSession, } impl AsyncQueue { /// Create a new `AsyncQueue` wrapping around a `Queue`. pub fn new(queue: Queue) -> io::Result { - Ok(AsyncQueue { inner: queue }) + let session = WinSession::new(queue.get_session())?; + Ok(AsyncQueue { + inner: queue, + session, + }) } /// Returns a shared reference to the underlying Queue object pub fn get_ref(&self) -> &Queue { @@ -124,29 +120,87 @@ impl AsyncRead for AsyncQueue { cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll> { - let rbuf = buf.initialize_unfilled(); - match Pin::new(&mut self.inner).poll_read(cx, rbuf) { - Poll::Ready(Ok(n)) => { - buf.advance(n); - Poll::Ready(Ok(())) - } - Poll::Ready(Err(e)) => Poll::Ready(Err(e)), - Poll::Pending => Poll::Pending, - } + Pin::new(&mut self.session).poll_read(cx, buf) } } impl AsyncWrite for AsyncQueue { fn poll_write( mut self: Pin<&mut Self>, - _cx: &mut Context<'_>, + cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - match self.inner.write(buf) { - Ok(n) => Poll::Ready(Ok(n)), - Err(e) => Poll::Ready(Err(e)), + Pin::new(&mut self.session).poll_write(cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.session).poll_flush(cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.session).poll_shutdown(cx) + } +} + +struct WinSession { + session: std::sync::Arc, + receiver: tokio::sync::mpsc::UnboundedReceiver>, + _task: std::thread::JoinHandle<()>, +} + +impl WinSession { + fn new(session: std::sync::Arc) -> Result { + let session_reader = session.clone(); + let (receiver_tx, receiver_rx) = tokio::sync::mpsc::unbounded_channel::>(); + let task = std::thread::spawn(move || loop { + match session_reader.receive_blocking() { + Ok(packet) => { + if let Err(err) = receiver_tx.send(packet.bytes().to_vec()) { + log::error!("{}", err); + } + } + Err(err) => { + log::info!("{}", err); + break; + } + } + }); + + Ok(WinSession { + session, + receiver: receiver_rx, + _task: task, + }) + } +} + +impl AsyncRead for WinSession { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + match std::task::ready!(self.receiver.poll_recv(cx)) { + Some(bytes) => { + buf.put_slice(&bytes); + std::task::Poll::Ready(Ok(())) + } + None => std::task::Poll::Ready(Ok(())), } } +} + +impl AsyncWrite for WinSession { + fn poll_write( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + let mut write_pack = self.session.allocate_send_packet(buf.len() as u16)?; + write_pack.bytes_mut().copy_from_slice(buf.as_ref()); + self.session.send_packet(write_pack); + std::task::Poll::Ready(Ok(buf.len())) + } fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index 53bee9e4..4e1463a9 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -14,11 +14,7 @@ use std::io::{self, Read, Write}; use std::net::{IpAddr, Ipv4Addr}; -use std::pin::Pin; -use std::sync::{Arc, Mutex}; -use std::task::{Context, Poll}; -use std::thread; -use std::vec::Vec; +use std::sync::Arc; use wintun::Session; @@ -28,7 +24,7 @@ use crate::error::*; /// A TUN device using the wintun driver. pub struct Device { - queue: Queue, + pub(crate) queue: Queue, mtu: usize, } @@ -54,7 +50,6 @@ impl Device { let mut device = Device { queue: Queue { session: Arc::new(session), - cached: Arc::new(Mutex::new(Vec::with_capacity(mtu))), }, mtu, }; @@ -64,14 +59,6 @@ impl Device { Ok(device) } - - pub fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - Pin::new(&mut self.queue).poll_read(cx, buf) - } } impl Read for Device { @@ -183,7 +170,6 @@ impl D for Device { fn set_mtu(&mut self, value: i32) -> Result<()> { self.mtu = value as usize; - self.queue.cached = Arc::new(Mutex::new(Vec::with_capacity(self.mtu))); Ok(()) } @@ -194,70 +180,11 @@ impl D for Device { pub struct Queue { session: Arc, - cached: Arc>>, } impl Queue { - pub fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - mut buf: &mut [u8], - ) -> Poll> { - { - let mut cached = self - .cached - .lock() - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; - if cached.len() > 0 { - let res = match io::copy(&mut cached.as_slice(), &mut buf) { - Ok(n) => Poll::Ready(Ok(n as usize)), - Err(e) => Poll::Ready(Err(e)), - }; - cached.clear(); - return res; - } - } - let reader_session = self.session.clone(); - match reader_session.try_receive() { - Err(e) => Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, e))), - Ok(Some(packet)) => match io::copy(&mut packet.bytes(), &mut buf) { - Ok(n) => Poll::Ready(Ok(n as usize)), - Err(e) => Poll::Ready(Err(e)), - }, - Ok(None) => { - let waker = cx.waker().clone(); - let cached = self.cached.clone(); - thread::spawn(move || { - match reader_session.receive_blocking() { - Ok(packet) => { - if let Ok(mut cached) = cached.lock() { - cached.extend_from_slice(packet.bytes()); - } else { - log::error!("cached lock error in wintun reciever thread, packet will be dropped"); - } - } - Err(e) => log::error!("receive_blocking error: {:?}", e), - } - waker.wake() - }); - Poll::Pending - } - } - } - - #[allow(dead_code)] - fn try_read(&mut self, mut buf: &mut [u8]) -> io::Result { - let reader_session = self.session.clone(); - match reader_session.try_receive() { - Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), - Ok(op) => match op { - None => Ok(0), - Some(packet) => match io::copy(&mut packet.bytes(), &mut buf) { - Ok(s) => Ok(s as usize), - Err(e) => Err(e), - }, - }, - } + pub fn get_session(&self) -> Arc { + self.session.clone() } } From 11d136ffa297eeb90f57a2b078b6b1a45b775f9c Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sat, 2 Dec 2023 18:16:24 +0800 Subject: [PATCH 04/44] add ablility to set device GUID for wintun --- examples/ping-tun.rs | 2 +- src/platform/windows/device.rs | 2 +- src/platform/windows/mod.rs | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/ping-tun.rs b/examples/ping-tun.rs index 98dc4fd3..ce914941 100644 --- a/examples/ping-tun.rs +++ b/examples/ping-tun.rs @@ -33,7 +33,7 @@ async fn main() -> Result<(), Box> { #[cfg(target_os = "windows")] config.platform(|config| { - config.initialize(); + config.initialize(Some(9099482345783245345345_u128)); }); let dev = tun::create_as_async(&config)?; diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index 4e1463a9..d39292d4 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -33,7 +33,7 @@ impl Device { pub fn new(config: &Configuration) -> Result { let wintun = unsafe { wintun::load()? }; let tun_name = config.name.as_deref().unwrap_or("wintun"); - let guid = Some(9099482345783245345345_u128); + let guid = config.platform.device_guid; let adapter = match wintun::Adapter::open(&wintun, tun_name) { Ok(a) => a, Err(_) => wintun::Adapter::create(&wintun, tun_name, tun_name, guid)?, diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs index d5d6c4c7..5eca4431 100644 --- a/src/platform/windows/mod.rs +++ b/src/platform/windows/mod.rs @@ -23,11 +23,14 @@ use crate::error::*; /// Windows-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct Configuration {} +pub struct Configuration { + pub(crate) device_guid: Option, +} impl Configuration { - pub fn initialize(&mut self) { + pub fn initialize(&mut self, device_guid: Option) { log::trace!("Windows configuration initialize"); + self.device_guid = device_guid; } } From e944758112d23a2199b0c8d8adf8ffc6a8c1e9f5 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:03:26 +0800 Subject: [PATCH 05/44] add apply_settings switch for Linux configutation --- README.md | 1 + examples/ping-tun.rs | 1 + examples/read-async.rs | 1 + examples/read.rs | 1 + src/platform/linux/device.rs | 4 +++- src/platform/linux/mod.rs | 18 +++++++++++++++++- 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7c468188..4961ff7e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ fn main() { #[cfg(target_os = "linux")] config.platform(|config| { config.packet_information(true); + config.apply_settings(true); }); let mut dev = tun::create(&config).unwrap(); diff --git a/examples/ping-tun.rs b/examples/ping-tun.rs index ce914941..1d56502e 100644 --- a/examples/ping-tun.rs +++ b/examples/ping-tun.rs @@ -29,6 +29,7 @@ async fn main() -> Result<(), Box> { #[cfg(target_os = "linux")] config.platform(|config| { config.packet_information(true); + config.apply_settings(true); }); #[cfg(target_os = "windows")] diff --git a/examples/read-async.rs b/examples/read-async.rs index 9fe9def6..a026ef31 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -27,6 +27,7 @@ async fn main() { #[cfg(target_os = "linux")] config.platform(|config| { config.packet_information(true); + config.apply_settings(true); }); let dev = tun::create_as_async(&config).unwrap(); diff --git a/examples/read.rs b/examples/read.rs index 5beda850..c534ba6f 100644 --- a/examples/read.rs +++ b/examples/read.rs @@ -26,6 +26,7 @@ fn main() -> Result<(), Box> { #[cfg(target_os = "linux")] config.platform(|config| { config.packet_information(true); + config.apply_settings(true); }); let mut dev = tun::create(&config)?; diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index 41ce0958..1655a5be 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -108,7 +108,9 @@ impl Device { Device { name, queues, ctl } }; - device.configure(config)?; + if config.platform.apply_settings { + device.configure(config)?; + } Ok(device) } diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 455a2791..20003113 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -23,9 +23,19 @@ use crate::configuration::Configuration as C; use crate::error::*; /// Linux-only interface configuration. -#[derive(Copy, Clone, Default, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Configuration { pub(crate) packet_information: bool, + pub(crate) apply_settings: bool, +} + +impl Default for Configuration { + fn default() -> Self { + Configuration { + packet_information: false, + apply_settings: true, + } + } } impl Configuration { @@ -35,6 +45,12 @@ impl Configuration { self.packet_information = value; self } + + /// Enable or disable to assign IP/netmask/destination etc. + pub fn apply_settings(&mut self, value: bool) -> &mut Self { + self.apply_settings = value; + self + } } /// Create a TUN device with the given name. From a74731b5f8c8fa19ed527ffed43b5f451850317f Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 11 Jan 2024 20:30:06 +0800 Subject: [PATCH 06/44] refine TunPacketCodec --- Cargo.toml | 2 +- README.md | 12 ++++++++---- src/async/codec.rs | 31 ++++++++++++++++++------------- src/error.rs | 9 +++++++++ 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e7353857..198d263f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ tokio-util = { version = "0.7", features = ["codec"], optional = true } ioctl = { version = "0.8", package = "ioctl-sys" } [target.'cfg(target_os = "windows")'.dependencies] -wintun = { version = "0.3", features = ["panic_on_unsent_packets"] } +wintun = { version = "0.4", features = ["panic_on_unsent_packets"] } [dev-dependencies] futures = "0.3" diff --git a/README.md b/README.md index 4961ff7e..2d95c24f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ -TUN interfaces [![Crates.io](https://img.shields.io/crates/v/tun.svg)](https://crates.io/crates/tun) ![tun](https://docs.rs/tun/badge.svg) ![WTFPL](http://img.shields.io/badge/license-WTFPL-blue.svg) +TUN interfaces ============== +[![Crates.io](https://img.shields.io/crates/v/tun.svg)](https://crates.io/crates/tun) +![tun](https://docs.rs/tun/badge.svg) +![WTFPL](http://img.shields.io/badge/license-WTFPL-blue.svg) + This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform. Usage @@ -8,7 +12,7 @@ First, add the following to your `Cargo.toml`: ```toml [dependencies] -tun = "0.6.1" +tun = "0.6" ``` Next, add this to your crate root: @@ -21,7 +25,7 @@ If you want to use the TUN interface with mio/tokio, you need to enable the `asy ```toml [dependencies] -tun = { version = "0.6.1", features = ["async"] } +tun = { version = "0.6", features = ["async"] } ``` Example @@ -58,7 +62,7 @@ fn main() { Platforms ========= -Not every platform is supported. +Recently, `tun` supports Linux, Android, macOS, iOS and Windows. Linux ----- diff --git a/src/async/codec.rs b/src/async/codec.rs index 07b2b55a..f81dd088 100644 --- a/src/async/codec.rs +++ b/src/async/codec.rs @@ -14,7 +14,6 @@ use std::io; -use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt}; use bytes::{BufMut, Bytes, BytesMut}; use tokio_util::codec::{Decoder, Encoder}; @@ -54,6 +53,7 @@ impl PacketProtocol { } #[cfg(target_os = "windows")] + #[allow(dead_code)] fn into_pi_field(self) -> Result { unimplemented!() } @@ -132,19 +132,24 @@ impl Encoder for TunPacketCodec { type Error = io::Error; fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { - dst.reserve(item.get_bytes().len() + 4); + dst.reserve(item.get_bytes().len() + if self.0 { 4 } else { 0 }); match item { - TunPacket(proto, bytes) if self.0 => { - // build the packet information header comprising of 2 u16 - // fields: flags and protocol. - let mut buf = Vec::::with_capacity(4); - - // flags is always 0 - buf.write_u16::(0)?; - // write the protocol as network byte order - buf.write_u16::(proto.into_pi_field()?)?; - - dst.put_slice(&buf); + TunPacket(_proto, bytes) if self.0 => { + #[cfg(unix)] + { + use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt}; + + // build the packet information header comprising of 2 u16 + // fields: flags and protocol. + let mut buf = Vec::::with_capacity(4); + + // flags is always 0 + buf.write_u16::(0)?; + // write the protocol as network byte order + buf.write_u16::(_proto.into_pi_field()?)?; + + dst.put_slice(&buf); + } dst.put(bytes); } TunPacket(_, bytes) => dst.put(bytes), diff --git a/src/error.rs b/src/error.rs index f71efefe..f6e9e53b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -54,4 +54,13 @@ pub enum Error { WintunError(#[from] wintun::Error), } +impl From for io::Error { + fn from(value: Error) -> Self { + match value { + Error::Io(err) => err, + _ => io::Error::new(io::ErrorKind::Other, value), + } + } +} + pub type Result = ::std::result::Result; From dbb63516cc999d539a33c3c456640967a6607c2a Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:59:57 +0800 Subject: [PATCH 07/44] beginning v2 --- Cargo.toml | 8 ++-- README.md | 78 +++++++++++++++++++----------------- examples/ping-tun.rs | 4 +- examples/read-async-codec.rs | 4 +- examples/read-async.rs | 4 +- examples/read.rs | 4 +- 6 files changed, 54 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 198d263f..5991ed3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] -name = "tun" -version = "0.6.1" +name = "tun2" +version = "0.6.2" edition = "2021" -authors = ["meh. "] +authors = ["meh. ", "@ssrlive"] license = "WTFPL" description = "TUN device creation and handling." -repository = "https://github.com/meh/rust-tun" +repository = "https://github.com/ssrlive/rust-tun" keywords = ["tun", "network", "tunnel", "bindings"] [dependencies] diff --git a/README.md b/README.md index 2d95c24f..e4e10a7b 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,38 @@ TUN interfaces ============== -[![Crates.io](https://img.shields.io/crates/v/tun.svg)](https://crates.io/crates/tun) -![tun](https://docs.rs/tun/badge.svg) +[![Crates.io](https://img.shields.io/crates/v/tun2.svg)](https://crates.io/crates/tun2) +![tun2](https://docs.rs/tun2/badge.svg) ![WTFPL](http://img.shields.io/badge/license-WTFPL-blue.svg) This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform. +> Since the original maintainer @meh is no longer interested in continuing to maintain +> [tun](https://crates.io/crates/tun), +> I (@ssrlive) created the [tun2](https://github.com/ssrlive/rust-tun) branch and +> continued to actively update. Welcome to any interested contributor. +> If you want to be a co-contributor and publisher of [tun2](https://crates.io/crates/tun2), +> please contact me in [issues](https://github.com/ssrlive/rust-tun/issues). +> +> For me, a submitted PR has not been reviewed for a long time, +> cannot be merged to the main branch, and cannot be published. +> It is like a patient who has not been sutured on the operating table for a long time. +> This is a bad experience. +> I believe that many people feel the same. + Usage ----- First, add the following to your `Cargo.toml`: ```toml [dependencies] -tun = "0.6" -``` - -Next, add this to your crate root: - -```rust -extern crate tun; +tun2 = "0.6" ``` If you want to use the TUN interface with mio/tokio, you need to enable the `async` feature: ```toml [dependencies] -tun = { version = "0.6", features = ["async"] } +tun2 = { version = "0.6", features = ["async"] } ``` Example @@ -36,37 +43,36 @@ packets from it. ```rust use std::io::Read; -extern crate tun; - fn main() { - let mut config = tun::Configuration::default(); - config.address((10, 0, 0, 1)) - .netmask((255, 255, 255, 0)) - .up(); - - #[cfg(target_os = "linux")] - config.platform(|config| { - config.packet_information(true); - config.apply_settings(true); - }); - - let mut dev = tun::create(&config).unwrap(); - let mut buf = [0; 4096]; - - loop { - let amount = dev.read(&mut buf).unwrap(); - println!("{:?}", &buf[0 .. amount]); - } + let mut config = tun2::Configuration::default(); + config + .address((10, 0, 0, 1)) + .netmask((255, 255, 255, 0)) + .up(); + + #[cfg(target_os = "linux")] + config.platform(|config| { + config.packet_information(true); + config.apply_settings(true); + }); + + let mut dev = tun2::create(&config).unwrap(); + let mut buf = [0; 4096]; + + loop { + let amount = dev.read(&mut buf).unwrap(); + println!("{:?}", &buf[0..amount]); + } } ``` Platforms ========= -Recently, `tun` supports Linux, Android, macOS, iOS and Windows. +Recently, `tun2` supports Linux, Android, macOS, iOS and Windows. Linux ----- -You will need the `tun` module to be loaded and root is required to create +You will need the `tun2` module to be loaded and root is required to create interfaces. macOS @@ -77,9 +83,9 @@ It just works, but you have to set up routing manually. For example: iOS ---- -You can pass the file descriptor of the TUN device to `rust-tun` to create the interface. +You can pass the file descriptor of the TUN device to `tun2` to create the interface. -Here is an example to create the TUN device on iOS and pass the `fd` to `rust-tun`: +Here is an example to create the TUN device on iOS and pass the `fd` to `tun2`: ```swift // Swift class PacketTunnelProvider: NEPacketTunnelProvider { @@ -101,9 +107,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider { pub extern "C" fn start_tun(fd: std::os::raw::c_int) { let mut rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { - let mut cfg = tun::Configuration::default(); + let mut cfg = tun2::Configuration::default(); cfg.raw_fd(fd); - let mut tun = tun::create_as_async(&cfg).unwrap(); + let mut tun = tun2::create_as_async(&cfg).unwrap(); let mut framed = tun.into_framed(); while let Some(packet) = framed.next().await { ... diff --git a/examples/ping-tun.rs b/examples/ping-tun.rs index 1d56502e..3e216429 100644 --- a/examples/ping-tun.rs +++ b/examples/ping-tun.rs @@ -14,7 +14,7 @@ use futures::{SinkExt, StreamExt}; use packet::{builder::Builder, icmp, ip, Packet}; -use tun::{self, Configuration, TunPacket}; +use tun2::{self, Configuration, TunPacket}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -37,7 +37,7 @@ async fn main() -> Result<(), Box> { config.initialize(Some(9099482345783245345345_u128)); }); - let dev = tun::create_as_async(&config)?; + let dev = tun2::create_as_async(&config)?; let mut framed = dev.into_framed(); diff --git a/examples/read-async-codec.rs b/examples/read-async-codec.rs index 211ab502..9c36d7ff 100644 --- a/examples/read-async-codec.rs +++ b/examples/read-async-codec.rs @@ -41,14 +41,14 @@ impl Decoder for IPPacketCodec { #[tokio::main] async fn main() { - let mut config = tun::Configuration::default(); + let mut config = tun2::Configuration::default(); config .address((10, 0, 0, 1)) .netmask((255, 255, 255, 0)) .up(); - let dev = tun::create_as_async(&config).unwrap(); + let dev = tun2::create_as_async(&config).unwrap(); let mut stream = FramedRead::new(dev, IPPacketCodec); diff --git a/examples/read-async.rs b/examples/read-async.rs index a026ef31..34ca6433 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -17,7 +17,7 @@ use packet::ip::Packet; #[tokio::main] async fn main() { - let mut config = tun::Configuration::default(); + let mut config = tun2::Configuration::default(); config .address((10, 0, 0, 1)) @@ -30,7 +30,7 @@ async fn main() { config.apply_settings(true); }); - let dev = tun::create_as_async(&config).unwrap(); + let dev = tun2::create_as_async(&config).unwrap(); let mut stream = dev.into_framed(); diff --git a/examples/read.rs b/examples/read.rs index c534ba6f..173f3b91 100644 --- a/examples/read.rs +++ b/examples/read.rs @@ -15,7 +15,7 @@ use std::io::Read; fn main() -> Result<(), Box> { - let mut config = tun::Configuration::default(); + let mut config = tun2::Configuration::default(); config .address((10, 0, 0, 9)) @@ -29,7 +29,7 @@ fn main() -> Result<(), Box> { config.apply_settings(true); }); - let mut dev = tun::create(&config)?; + let mut dev = tun2::create(&config)?; let mut buf = [0; 4096]; loop { From 05df46c46c23bf790e00aada8662076dcce49fa9 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sat, 13 Jan 2024 20:02:20 +0800 Subject: [PATCH 08/44] refine packet_information --- src/async/codec.rs | 4 ++-- src/async/device.rs | 9 +++++---- src/platform/linux/device.rs | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/async/codec.rs b/src/async/codec.rs index f81dd088..52ab762a 100644 --- a/src/async/codec.rs +++ b/src/async/codec.rs @@ -95,8 +95,8 @@ pub struct TunPacketCodec(bool, i32); impl TunPacketCodec { /// Create a new `TunPacketCodec` specifying whether the underlying /// tunnel Device has enabled the packet information header. - pub fn new(pi: bool, mtu: i32) -> TunPacketCodec { - TunPacketCodec(pi, mtu) + pub fn new(packet_information: bool, mtu: i32) -> TunPacketCodec { + TunPacketCodec(packet_information, mtu) } } diff --git a/src/async/device.rs b/src/async/device.rs index 5ac89fdb..54967ccf 100644 --- a/src/async/device.rs +++ b/src/async/device.rs @@ -51,8 +51,9 @@ impl AsyncDevice { /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) pub fn into_framed(mut self) -> Framed { - let pi = self.get_mut().has_packet_information(); - let codec = TunPacketCodec::new(pi, self.inner.get_ref().mtu().unwrap_or(1504)); + let packet_information = self.get_mut().has_packet_information(); + let mtu = self.inner.get_ref().mtu().unwrap_or(1504); + let codec = TunPacketCodec::new(packet_information, mtu); Framed::new(self, codec) } } @@ -147,8 +148,8 @@ impl AsyncQueue { /// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface) pub fn into_framed(mut self) -> Framed { - let pi = self.get_mut().has_packet_information(); - let codec = TunPacketCodec::new(pi, 1504); + let packet_information = self.get_mut().has_packet_information(); + let codec = TunPacketCodec::new(packet_information, 1504); Framed::new(self, codec) } } diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index 1655a5be..fa4cf973 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -96,7 +96,7 @@ impl Device { queues.push(Queue { tun, - pi_enabled: config.platform.packet_information, + packet_information: config.platform.packet_information, }); } @@ -401,12 +401,12 @@ impl IntoRawFd for Device { pub struct Queue { tun: Fd, - pi_enabled: bool, + packet_information: bool, } impl Queue { pub fn has_packet_information(&mut self) -> bool { - self.pi_enabled + self.packet_information } pub fn set_nonblock(&self) -> io::Result<()> { From ee80e99e6eec88ed09b38373910e0f94ce0425c0 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 16 Jan 2024 21:35:37 +0800 Subject: [PATCH 09/44] cargo config.toml --- .cargo/config.toml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..df5b7070 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,9 @@ +[registries.crates-io] +protocol = "sparse" + +[build] +# target = ["x86_64-unknown-linux-gnu"] +# target = ["aarch64-linux-android"] +# target = ["aarch64-apple-ios"] +# target = ["x86_64-pc-windows-msvc"] +# target = ["x86_64-apple-darwin"] From b1d0c56813a9ab254b230e2c7319c273dd834ed4 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:38:36 +0800 Subject: [PATCH 10/44] refine cargo.toml --- Cargo.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5991ed3a..1eca2257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,18 +29,20 @@ wintun = { version = "0.4", features = ["panic_on_unsent_packets"] } [dev-dependencies] futures = "0.3" packet = "0.1" +tokio = { version = "1", features = ["rt-multi-thread"] } [features] +default = [] async = ["tokio", "tokio-util", "bytes", "byteorder", "futures-core"] [[example]] name = "read-async" -required-features = ["async", "tokio/rt-multi-thread"] +required-features = ["async"] [[example]] name = "read-async-codec" -required-features = ["async", "tokio/rt-multi-thread"] +required-features = ["async"] [[example]] name = "ping-tun" -required-features = ["async", "tokio/rt-multi-thread"] +required-features = ["async"] From 51e2553d5cf47aee9bd7cdbe3e476bee5c59f1f0 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 17 Jan 2024 12:15:40 +0800 Subject: [PATCH 11/44] refine code --- Cargo.toml | 2 +- src/error.rs | 12 +++++------- src/lib.rs | 22 ++-------------------- src/platform/linux/device.rs | 2 +- 4 files changed, 9 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1eca2257..ad5ed530 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ thiserror = "1" tokio = { version = "1", features = ["net", "macros"], optional = true } tokio-util = { version = "0.7", features = ["codec"], optional = true } -[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] +[target.'cfg(unix)'.dependencies] ioctl = { version = "0.8", package = "ioctl-sys" } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/src/error.rs b/src/error.rs index f6e9e53b..c4b78dd0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,8 +12,6 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::{ffi, io, num}; - #[derive(thiserror::Error, Debug)] pub enum Error { #[error("invalid configuration")] @@ -41,24 +39,24 @@ pub enum Error { InvalidQueuesNumber, #[error(transparent)] - Io(#[from] io::Error), + Io(#[from] std::io::Error), #[error(transparent)] - Nul(#[from] ffi::NulError), + Nul(#[from] std::ffi::NulError), #[error(transparent)] - ParseNum(#[from] num::ParseIntError), + ParseNum(#[from] std::num::ParseIntError), #[cfg(target_os = "windows")] #[error(transparent)] WintunError(#[from] wintun::Error), } -impl From for io::Error { +impl From for std::io::Error { fn from(value: Error) -> Self { match value { Error::Io(err) => err, - _ => io::Error::new(io::ErrorKind::Other, value), + _ => std::io::Error::new(std::io::ErrorKind::Other, value), } } } diff --git a/src/lib.rs b/src/lib.rs index ec662831..4e73fbf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,27 +27,9 @@ pub use crate::configuration::{Configuration, Layer}; pub mod platform; pub use crate::platform::create; -#[cfg(all( - feature = "async", - any( - target_os = "windows", - target_os = "linux", - target_os = "macos", - target_os = "ios", - target_os = "android" - ) -))] +#[cfg(feature = "async")] pub mod r#async; -#[cfg(all( - feature = "async", - any( - target_os = "windows", - target_os = "linux", - target_os = "macos", - target_os = "ios", - target_os = "android" - ) -))] +#[cfg(feature = "async")] pub use r#async::*; pub fn configure() -> Configuration { diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index fa4cf973..126dee90 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -96,7 +96,7 @@ impl Device { queues.push(Queue { tun, - packet_information: config.platform.packet_information, + packet_information, }); } From 30614578bb13a6d6f813c5508c7a8b2740c01888 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Wed, 17 Jan 2024 13:41:10 +0800 Subject: [PATCH 12/44] eliminate redundantcopy --- Cargo.toml | 2 +- src/address.rs | 20 ++++++++++---------- src/platform/macos/device.rs | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad5ed530..57dd7edb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2" -version = "0.6.2" +version = "0.6.3" edition = "2021" authors = ["meh. ", "@ssrlive"] diff --git a/src/address.rs b/src/address.rs index 3ecc17ea..704bc0ab 100644 --- a/src/address.rs +++ b/src/address.rs @@ -61,13 +61,13 @@ impl<'a> IntoAddress for &'a str { impl IntoAddress for String { fn into_address(&self) -> Result { - (**self).into_address() + self.as_str().into_address() } } impl<'a> IntoAddress for &'a String { fn into_address(&self) -> Result { - (**self).into_address() + self.as_str().into_address() } } @@ -79,14 +79,14 @@ impl IntoAddress for Ipv4Addr { impl<'a> IntoAddress for &'a Ipv4Addr { fn into_address(&self) -> Result { - (**self).into_address() + (*self).into_address() } } impl IntoAddress for IpAddr { fn into_address(&self) -> Result { - match *self { - IpAddr::V4(ref value) => Ok(*value), + match self { + IpAddr::V4(value) => Ok(*value), IpAddr::V6(_) => Err(Error::InvalidAddress), } @@ -95,7 +95,7 @@ impl IntoAddress for IpAddr { impl<'a> IntoAddress for &'a IpAddr { fn into_address(&self) -> Result { - (**self).into_address() + (*self).into_address() } } @@ -107,14 +107,14 @@ impl IntoAddress for SocketAddrV4 { impl<'a> IntoAddress for &'a SocketAddrV4 { fn into_address(&self) -> Result { - (**self).into_address() + (*self).into_address() } } impl IntoAddress for SocketAddr { fn into_address(&self) -> Result { - match *self { - SocketAddr::V4(ref value) => Ok(*value.ip()), + match self { + SocketAddr::V4(value) => Ok(*value.ip()), SocketAddr::V6(_) => Err(Error::InvalidAddress), } @@ -123,6 +123,6 @@ impl IntoAddress for SocketAddr { impl<'a> IntoAddress for &'a SocketAddr { fn into_address(&self) -> Result { - (**self).into_address() + (*self).into_address() } } diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index 17f5bc87..bbfd1ad7 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -184,7 +184,7 @@ impl Device { /// Split the interface into a `Reader` and `Writer`. pub fn split(self) -> (posix::Reader, posix::Writer) { let fd = Arc::new(self.queue.tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) + (posix::Reader(fd.clone()), posix::Writer(fd)) } /// Return whether the device has packet information From 57fc820a0acb823ae79a200e1a6663e7d2fd01b9 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Wed, 17 Jan 2024 13:55:09 +0800 Subject: [PATCH 13/44] Construct TunPacket from certain types that satisfy some trait bounds --- src/async/codec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/async/codec.rs b/src/async/codec.rs index 52ab762a..23dfc11f 100644 --- a/src/async/codec.rs +++ b/src/async/codec.rs @@ -74,9 +74,9 @@ fn infer_proto(buf: &[u8]) -> PacketProtocol { impl TunPacket { /// Create a new `TunPacket` based on a byte slice. - pub fn new(bytes: Vec) -> TunPacket { - let proto = infer_proto(&bytes); - TunPacket(proto, Bytes::from(bytes)) + pub fn new + Into>(bytes: S) -> TunPacket { + let proto = infer_proto(bytes.as_ref()); + TunPacket(proto, bytes.into()) } /// Return this packet's bytes. From 641bd42dfbf77d5d2aaca476522ae583a545e65b Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Wed, 17 Jan 2024 14:27:33 +0800 Subject: [PATCH 14/44] Construct TunPacket from certain types that satisfy some trait bounds (#5) --- src/async/codec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/async/codec.rs b/src/async/codec.rs index 52ab762a..23dfc11f 100644 --- a/src/async/codec.rs +++ b/src/async/codec.rs @@ -74,9 +74,9 @@ fn infer_proto(buf: &[u8]) -> PacketProtocol { impl TunPacket { /// Create a new `TunPacket` based on a byte slice. - pub fn new(bytes: Vec) -> TunPacket { - let proto = infer_proto(&bytes); - TunPacket(proto, Bytes::from(bytes)) + pub fn new + Into>(bytes: S) -> TunPacket { + let proto = infer_proto(bytes.as_ref()); + TunPacket(proto, bytes.into()) } /// Return this packet's bytes. From c024261dbced3988fcf2725f13789a543953f708 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Wed, 17 Jan 2024 17:22:58 +0800 Subject: [PATCH 15/44] fix the mtu of wintun may larger than the provided default capacity of buf --- .gitignore | 1 + Cargo.toml | 2 +- src/async/win/device.rs | 6 ++++-- src/platform/windows/device.rs | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 9cc7b3d3..53da5e72 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target/ **/*.rs.bk Cargo.lock +wintun.dll diff --git a/Cargo.toml b/Cargo.toml index 57dd7edb..90048361 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2" -version = "0.6.3" +version = "0.6.4" edition = "2021" authors = ["meh. ", "@ssrlive"] diff --git a/src/async/win/device.rs b/src/async/win/device.rs index 2cb8afc3..faca1e09 100644 --- a/src/async/win/device.rs +++ b/src/async/win/device.rs @@ -50,8 +50,10 @@ impl AsyncDevice { /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) pub fn into_framed(self) -> Framed { - let codec = TunPacketCodec::new(false, self.get_ref().mtu().unwrap_or(1500)); - Framed::new(self, codec) + let mtu = self.get_ref().mtu().unwrap_or(u16::MAX as i32); + let codec = TunPacketCodec::new(false, mtu); + // guarantee to avoid the mtu of wintun may far away larger than the default provided capacity of buff of Framed + Framed::with_capacity(self, codec, mtu as usize) } } diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index d39292d4..f6efdbb7 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -43,7 +43,7 @@ impl Device { let mask = config.netmask.unwrap_or(Ipv4Addr::new(255, 255, 255, 0)); let gateway = config.destination.map(IpAddr::from); adapter.set_network_addresses_tuple(IpAddr::V4(address), IpAddr::V4(mask), gateway)?; - let mtu = config.mtu.unwrap_or(1500) as usize; + let mtu = config.mtu.unwrap_or(u16::MAX as i32) as usize; let session = adapter.start_session(wintun::MAX_RING_CAPACITY)?; From 86fd2fdf77057a2408c2017f820e030c0763787b Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Wed, 17 Jan 2024 19:53:36 +0800 Subject: [PATCH 16/44] associate mtu with the capacity of ReadBuf for all platforms --- src/async/device.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/async/device.rs b/src/async/device.rs index 54967ccf..43b05ab1 100644 --- a/src/async/device.rs +++ b/src/async/device.rs @@ -50,11 +50,12 @@ impl AsyncDevice { } /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) - pub fn into_framed(mut self) -> Framed { - let packet_information = self.get_mut().has_packet_information(); + pub fn into_framed(self) -> Framed { + let packet_information = self.get_ref().has_packet_information(); let mtu = self.inner.get_ref().mtu().unwrap_or(1504); let codec = TunPacketCodec::new(packet_information, mtu); - Framed::new(self, codec) + // associate mtu with the capacity of ReadBuf + Framed::with_capacity(self, codec, mtu as usize) } } From 199f6758db072e2f30125ea0642a7b9fb39c630a Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Wed, 17 Jan 2024 19:59:03 +0800 Subject: [PATCH 17/44] change to shared reference --- src/platform/linux/device.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index 126dee90..aa5123c2 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -161,7 +161,7 @@ impl Device { } /// Return whether the device has packet information - pub fn has_packet_information(&mut self) -> bool { + pub fn has_packet_information(&self) -> bool { self.queues[0].has_packet_information() } @@ -405,7 +405,7 @@ pub struct Queue { } impl Queue { - pub fn has_packet_information(&mut self) -> bool { + pub fn has_packet_information(&self) -> bool { self.packet_information } From 821dc339a43efc785d2438553d9c075da3696d0f Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:55:04 +0800 Subject: [PATCH 18/44] remove AsyncQueue --- src/async/device.rs | 78 ----------------------------------------- src/async/mod.rs | 4 +-- src/async/win/device.rs | 59 ------------------------------- 3 files changed, 2 insertions(+), 139 deletions(-) diff --git a/src/async/device.rs b/src/async/device.rs index 43b05ab1..5303d90f 100644 --- a/src/async/device.rs +++ b/src/async/device.rs @@ -123,81 +123,3 @@ impl AsyncWrite for AsyncDevice { true } } - -/// An async TUN device queue wrapper around a TUN device queue. -pub struct AsyncQueue { - inner: AsyncFd, -} - -impl AsyncQueue { - /// Create a new `AsyncQueue` wrapping around a `Queue`. - pub fn new(queue: Queue) -> io::Result { - queue.set_nonblock()?; - Ok(AsyncQueue { - inner: AsyncFd::new(queue)?, - }) - } - /// Returns a shared reference to the underlying Queue object - pub fn get_ref(&self) -> &Queue { - self.inner.get_ref() - } - - /// Returns a mutable reference to the underlying Queue object - pub fn get_mut(&mut self) -> &mut Queue { - self.inner.get_mut() - } - - /// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface) - pub fn into_framed(mut self) -> Framed { - let packet_information = self.get_mut().has_packet_information(); - let codec = TunPacketCodec::new(packet_information, 1504); - Framed::new(self, codec) - } -} - -impl AsyncRead for AsyncQueue { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf, - ) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?; - let rbuf = buf.initialize_unfilled(); - match guard.try_io(|inner| inner.get_mut().read(rbuf)) { - Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))), - Err(_wb) => continue, - } - } - } -} - -impl AsyncWrite for AsyncQueue { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; - match guard.try_io(|inner| inner.get_mut().write(buf)) { - Ok(res) => return Poll::Ready(res), - Err(_wb) => continue, - } - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; - match guard.try_io(|inner| inner.get_mut().flush()) { - Ok(res) => return Poll::Ready(res), - Err(_wb) => continue, - } - } - } - - fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} diff --git a/src/async/mod.rs b/src/async/mod.rs index ec5493a9..06f4b8e0 100644 --- a/src/async/mod.rs +++ b/src/async/mod.rs @@ -22,12 +22,12 @@ use crate::platform::create; #[cfg(unix)] mod device; #[cfg(unix)] -pub use self::device::{AsyncDevice, AsyncQueue}; +pub use self::device::AsyncDevice; #[cfg(target_os = "windows")] mod win; #[cfg(target_os = "windows")] -pub use win::device::{AsyncDevice, AsyncQueue}; +pub use win::device::AsyncDevice; mod codec; pub use self::codec::{TunPacket, TunPacketCodec}; diff --git a/src/async/win/device.rs b/src/async/win/device.rs index faca1e09..265de20b 100644 --- a/src/async/win/device.rs +++ b/src/async/win/device.rs @@ -85,65 +85,6 @@ impl AsyncWrite for AsyncDevice { } } -pub struct AsyncQueue { - inner: Queue, - session: WinSession, -} - -impl AsyncQueue { - /// Create a new `AsyncQueue` wrapping around a `Queue`. - pub fn new(queue: Queue) -> io::Result { - let session = WinSession::new(queue.get_session())?; - Ok(AsyncQueue { - inner: queue, - session, - }) - } - /// Returns a shared reference to the underlying Queue object - pub fn get_ref(&self) -> &Queue { - &self.inner - } - - /// Returns a mutable reference to the underlying Queue object - pub fn get_mut(&mut self) -> &mut Queue { - &mut self.inner - } - - /// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface) - pub fn into_framed(self) -> Framed { - let codec = TunPacketCodec::new(false, 1512); - Framed::new(self, codec) - } -} - -impl AsyncRead for AsyncQueue { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf<'_>, - ) -> Poll> { - Pin::new(&mut self.session).poll_read(cx, buf) - } -} - -impl AsyncWrite for AsyncQueue { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Pin::new(&mut self.session).poll_write(cx, buf) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.session).poll_flush(cx) - } - - fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.session).poll_shutdown(cx) - } -} - struct WinSession { session: std::sync::Arc, receiver: tokio::sync::mpsc::UnboundedReceiver>, From f153bbfeddb246fd7e4faf26e1f927992d5f09ac Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:56:49 +0800 Subject: [PATCH 19/44] clippy issues --- src/async/win/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/async/win/device.rs b/src/async/win/device.rs index 265de20b..731a6810 100644 --- a/src/async/win/device.rs +++ b/src/async/win/device.rs @@ -21,7 +21,7 @@ use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; use crate::device::Device as D; -use crate::platform::{Device, Queue}; +use crate::platform::Device; use crate::r#async::codec::*; pub struct AsyncDevice { From fa6d28125abd64aeecd14d5abac8d55fcb6ff0dc Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:59:37 +0800 Subject: [PATCH 20/44] clippy issues --- src/async/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/async/device.rs b/src/async/device.rs index 5303d90f..adbf5eb4 100644 --- a/src/async/device.rs +++ b/src/async/device.rs @@ -23,7 +23,7 @@ use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; use crate::device::Device as D; -use crate::platform::{Device, Queue}; +use crate::platform::Device; use crate::r#async::codec::*; /// An async TUN device wrapper around a TUN device. From 9a5da494b18b93c8840c94b4f422a45f121833d1 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:07:33 +0800 Subject: [PATCH 21/44] refactor interfaces --- Cargo.toml | 2 +- README.md | 2 +- examples/ping-tun.rs | 6 +-- examples/read-async.rs | 2 +- examples/read.rs | 2 +- src/address.rs | 3 +- src/async/device.rs | 4 +- src/async/mod.rs | 4 +- src/async/win/mod.rs | 1 - src/async/{win/device.rs => win_device.rs} | 4 +- src/configuration.rs | 11 +++-- src/device.rs | 9 ++-- src/lib.rs | 4 +- src/platform/android/device.rs | 34 +++++++-------- src/platform/android/mod.rs | 8 ++-- src/platform/ios/device.rs | 49 ++++++++++++---------- src/platform/ios/mod.rs | 10 ++--- src/platform/linux/device.rs | 10 ++--- src/platform/linux/mod.rs | 14 +++---- src/platform/macos/device.rs | 6 +-- src/platform/macos/mod.rs | 8 ++-- src/platform/mod.rs | 12 +++--- src/platform/posix/fd.rs | 5 +-- src/platform/posix/sockaddr.rs | 3 +- src/platform/windows/device.rs | 8 ++-- src/platform/windows/mod.rs | 14 +++---- 26 files changed, 116 insertions(+), 119 deletions(-) delete mode 100644 src/async/win/mod.rs rename src/async/{win/device.rs => win_device.rs} (98%) diff --git a/Cargo.toml b/Cargo.toml index 90048361..7b5ffcd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2" -version = "0.6.4" +version = "0.7.0" edition = "2021" authors = ["meh. ", "@ssrlive"] diff --git a/README.md b/README.md index e4e10a7b..fa8b4edd 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ fn main() { .up(); #[cfg(target_os = "linux")] - config.platform(|config| { + config.platform_config(|config| { config.packet_information(true); config.apply_settings(true); }); diff --git a/examples/ping-tun.rs b/examples/ping-tun.rs index 3e216429..c7a5828b 100644 --- a/examples/ping-tun.rs +++ b/examples/ping-tun.rs @@ -27,14 +27,14 @@ async fn main() -> Result<(), Box> { .up(); #[cfg(target_os = "linux")] - config.platform(|config| { + config.platform_config(|config| { config.packet_information(true); config.apply_settings(true); }); #[cfg(target_os = "windows")] - config.platform(|config| { - config.initialize(Some(9099482345783245345345_u128)); + config.platform_config(|config| { + config.device_guid(Some(9099482345783245345345_u128)); }); let dev = tun2::create_as_async(&config)?; diff --git a/examples/read-async.rs b/examples/read-async.rs index 34ca6433..f600194c 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -25,7 +25,7 @@ async fn main() { .up(); #[cfg(target_os = "linux")] - config.platform(|config| { + config.platform_config(|config| { config.packet_information(true); config.apply_settings(true); }); diff --git a/examples/read.rs b/examples/read.rs index 173f3b91..f1ff5892 100644 --- a/examples/read.rs +++ b/examples/read.rs @@ -24,7 +24,7 @@ fn main() -> Result<(), Box> { .up(); #[cfg(target_os = "linux")] - config.platform(|config| { + config.platform_config(|config| { config.packet_information(true); config.apply_settings(true); }); diff --git a/src/address.rs b/src/address.rs index 704bc0ab..b353428e 100644 --- a/src/address.rs +++ b/src/address.rs @@ -12,11 +12,10 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use crate::error::{Error, Result}; use std::net::{IpAddr, Ipv4Addr}; use std::net::{SocketAddr, SocketAddrV4}; -use crate::error::*; - /// Helper trait to convert things into IPv4 addresses. #[allow(clippy::wrong_self_convention)] pub trait IntoAddress { diff --git a/src/async/device.rs b/src/async/device.rs index adbf5eb4..24260820 100644 --- a/src/async/device.rs +++ b/src/async/device.rs @@ -22,9 +22,9 @@ use tokio::io::unix::AsyncFd; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; -use crate::device::Device as D; +use crate::device::AbstractDevice; use crate::platform::Device; -use crate::r#async::codec::*; +use crate::r#async::codec::TunPacketCodec; /// An async TUN device wrapper around a TUN device. pub struct AsyncDevice { diff --git a/src/async/mod.rs b/src/async/mod.rs index 06f4b8e0..2a8336cb 100644 --- a/src/async/mod.rs +++ b/src/async/mod.rs @@ -25,9 +25,9 @@ mod device; pub use self::device::AsyncDevice; #[cfg(target_os = "windows")] -mod win; +mod win_device; #[cfg(target_os = "windows")] -pub use win::device::AsyncDevice; +pub use win_device::AsyncDevice; mod codec; pub use self::codec::{TunPacket, TunPacketCodec}; diff --git a/src/async/win/mod.rs b/src/async/win/mod.rs deleted file mode 100644 index e8916cf4..00000000 --- a/src/async/win/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod device; diff --git a/src/async/win/device.rs b/src/async/win_device.rs similarity index 98% rename from src/async/win/device.rs rename to src/async/win_device.rs index 731a6810..76be8aaa 100644 --- a/src/async/win/device.rs +++ b/src/async/win_device.rs @@ -20,9 +20,9 @@ use std::io::Error; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; -use crate::device::Device as D; +use crate::device::AbstractDevice; use crate::platform::Device; -use crate::r#async::codec::*; +use crate::r#async::codec::TunPacketCodec; pub struct AsyncDevice { inner: Device, diff --git a/src/configuration.rs b/src/configuration.rs index d26924ff..34a30684 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -19,7 +19,7 @@ use std::os::unix::io::RawFd; use std::os::windows::raw::HANDLE; use crate::address::IntoAddress; -use crate::platform; +use crate::platform::PlatformConfig; /// TUN interface OSI layer of operation. #[derive(Clone, Copy, Default, Debug, Eq, PartialEq)] @@ -33,8 +33,7 @@ pub enum Layer { #[derive(Clone, Default, Debug)] pub struct Configuration { pub(crate) name: Option, - pub(crate) platform: platform::Configuration, - + pub(crate) platform_config: PlatformConfig, pub(crate) address: Option, pub(crate) destination: Option, pub(crate) broadcast: Option, @@ -53,11 +52,11 @@ pub struct Configuration { impl Configuration { /// Access the platform dependant configuration. - pub fn platform(&mut self, f: F) -> &mut Self + pub fn platform_config(&mut self, f: F) -> &mut Self where - F: FnOnce(&mut platform::Configuration), + F: FnOnce(&mut PlatformConfig), { - f(&mut self.platform); + f(&mut self.platform_config); self } diff --git a/src/device.rs b/src/device.rs index b205c7c7..76147d73 100644 --- a/src/device.rs +++ b/src/device.rs @@ -12,14 +12,13 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use crate::configuration::Configuration; +use crate::error::Result; use std::io::{Read, Write}; use std::net::Ipv4Addr; -use crate::configuration::Configuration; -use crate::error::*; - -/// A TUN device. -pub trait Device: Read + Write { +/// A TUN abstract device interface. +pub trait AbstractDevice: Read + Write { type Queue: Read + Write; /// Reconfigure the device. diff --git a/src/lib.rs b/src/lib.rs index 4e73fbf9..cc50d7ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,13 +13,13 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. mod error; -pub use crate::error::*; +pub use crate::error::{Error, Result}; mod address; pub use crate::address::IntoAddress; mod device; -pub use crate::device::Device; +pub use crate::device::AbstractDevice; mod configuration; pub use crate::configuration::{Configuration, Layer}; diff --git a/src/platform/android/device.rs b/src/platform/android/device.rs index fdf7e9b2..2f7375c7 100644 --- a/src/platform/android/device.rs +++ b/src/platform/android/device.rs @@ -13,14 +13,14 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. #![allow(unused_variables)] -use std::io::{self, Read, Write}; +use std::io::{Read, Write}; use std::net::Ipv4Addr; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; use std::sync::Arc; use crate::configuration::Configuration; -use crate::device::Device as D; -use crate::error::*; +use crate::device::AbstractDevice; +use crate::error::{Error, Result}; use crate::platform::posix::{self, Fd}; /// A TUN device for Android. @@ -36,7 +36,7 @@ impl Device { _ => return Err(Error::InvalidConfig), }; let device = { - let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?; + let tun = Fd::new(fd).map_err(|_| std::io::Error::last_os_error())?; Device { queue: Queue { tun }, @@ -57,36 +57,36 @@ impl Device { } /// Set non-blocking mode - pub fn set_nonblock(&self) -> io::Result<()> { + pub fn set_nonblock(&self) -> std::io::Result<()> { self.queue.set_nonblock() } } impl Read for Device { - fn read(&mut self, buf: &mut [u8]) -> io::Result { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.queue.tun.read(buf) } - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { self.queue.tun.read_vectored(bufs) } } impl Write for Device { - fn write(&mut self, buf: &[u8]) -> io::Result { + fn write(&mut self, buf: &[u8]) -> std::io::Result { self.queue.tun.write(buf) } - fn flush(&mut self) -> io::Result<()> { + fn flush(&mut self) -> std::io::Result<()> { self.queue.tun.flush() } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { self.queue.tun.write_vectored(bufs) } } -impl D for Device { +impl AbstractDevice for Device { type Queue = Queue; fn name(&self) -> Result { @@ -172,7 +172,7 @@ impl Queue { false } - pub fn set_nonblock(&self) -> io::Result<()> { + pub fn set_nonblock(&self) -> std::io::Result<()> { self.tun.set_nonblock() } } @@ -190,25 +190,25 @@ impl IntoRawFd for Queue { } impl Read for Queue { - fn read(&mut self, buf: &mut [u8]) -> io::Result { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.tun.read(buf) } - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { self.tun.read_vectored(bufs) } } impl Write for Queue { - fn write(&mut self, buf: &[u8]) -> io::Result { + fn write(&mut self, buf: &[u8]) -> std::io::Result { self.tun.write(buf) } - fn flush(&mut self) -> io::Result<()> { + fn flush(&mut self) -> std::io::Result<()> { self.tun.flush() } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { self.tun.write_vectored(bufs) } } diff --git a/src/platform/android/mod.rs b/src/platform/android/mod.rs index 923e14ff..e27d29c0 100644 --- a/src/platform/android/mod.rs +++ b/src/platform/android/mod.rs @@ -17,14 +17,14 @@ mod device; pub use self::device::{Device, Queue}; -use crate::configuration::Configuration as C; -use crate::error::*; +use crate::configuration::Configuration; +use crate::error::Result; /// Android-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct Configuration {} +pub struct PlatformConfig {} /// Create a TUN device with the given name. -pub fn create(configuration: &C) -> Result { +pub fn create(configuration: &Configuration) -> Result { Device::new(&configuration) } diff --git a/src/platform/ios/device.rs b/src/platform/ios/device.rs index 770656aa..d2c0bb21 100644 --- a/src/platform/ios/device.rs +++ b/src/platform/ios/device.rs @@ -13,15 +13,18 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. #![allow(unused_variables)] -use std::io::{self, Read, Write}; -use std::net::Ipv4Addr; -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; -use std::sync::Arc; - -use crate::configuration::Configuration; -use crate::device::Device as D; -use crate::error::*; -use crate::platform::posix::{self, Fd}; +use crate::{ + configuration::Configuration, + device::AbstractDevice, + error::{Error, Result}, + platform::posix::{self, Fd}, +}; +use std::{ + io::{Read, Write}, + net::Ipv4Addr, + os::unix::io::{AsRawFd, IntoRawFd, RawFd}, + sync::Arc, +}; /// A TUN device for iOS. pub struct Device { @@ -36,7 +39,7 @@ impl Device { _ => return Err(Error::InvalidConfig), }; let mut device = unsafe { - let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?; + let tun = Fd::new(fd).map_err(|_| std::io::Error::last_os_error())?; Device { queue: Queue { tun }, @@ -57,36 +60,36 @@ impl Device { } /// Set non-blocking mode - pub fn set_nonblock(&self) -> io::Result<()> { + pub fn set_nonblock(&self) -> std::io::Result<()> { self.queue.set_nonblock() } } impl Read for Device { - fn read(&mut self, buf: &mut [u8]) -> io::Result { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.queue.tun.read(buf) } - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { self.queue.tun.read_vectored(bufs) } } impl Write for Device { - fn write(&mut self, buf: &[u8]) -> io::Result { + fn write(&mut self, buf: &[u8]) -> std::io::Result { self.queue.tun.write(buf) } - fn flush(&mut self) -> io::Result<()> { + fn flush(&mut self) -> std::io::Result<()> { self.queue.tun.flush() } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { self.queue.tun.write_vectored(bufs) } } -impl D for Device { +impl AbstractDevice for Device { type Queue = Queue; fn name(&self) -> Result { @@ -172,7 +175,7 @@ impl Queue { true } - pub fn set_nonblock(&self) -> io::Result<()> { + pub fn set_nonblock(&self) -> std::io::Result<()> { self.tun.set_nonblock() } } @@ -190,25 +193,25 @@ impl IntoRawFd for Queue { } impl Read for Queue { - fn read(&mut self, buf: &mut [u8]) -> io::Result { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.tun.read(buf) } - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { self.tun.read_vectored(bufs) } } impl Write for Queue { - fn write(&mut self, buf: &[u8]) -> io::Result { + fn write(&mut self, buf: &[u8]) -> std::io::Result { self.tun.write(buf) } - fn flush(&mut self) -> io::Result<()> { + fn flush(&mut self) -> std::io::Result<()> { self.tun.flush() } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { self.tun.write_vectored(bufs) } } diff --git a/src/platform/ios/mod.rs b/src/platform/ios/mod.rs index ea468555..8990c33e 100644 --- a/src/platform/ios/mod.rs +++ b/src/platform/ios/mod.rs @@ -15,16 +15,16 @@ //! iOS specific functionality. mod device; -pub use self::device::{Device, Queue}; +pub use crate::device::{Device, Queue}; -use crate::configuration::Configuration as C; -use crate::error::*; +use crate::configuration::Configuration; +use crate::error::Result; /// iOS-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct Configuration {} +pub struct PlatformConfig {} /// Create a TUN device with the given name. -pub fn create(configuration: &C) -> Result { +pub fn create(configuration: &Configuration) -> Result { Device::new(&configuration) } diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index aa5123c2..f009463c 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -29,8 +29,8 @@ use std::{ use crate::{ configuration::{Configuration, Layer}, - device::Device as D, - error::*, + device::AbstractDevice, + error::{Error, Result}, platform::linux::sys::*, platform::posix::{self, Fd, SockAddr}, }; @@ -81,7 +81,7 @@ impl Device { let iff_no_pi = IFF_NO_PI as c_short; let iff_multi_queue = IFF_MULTI_QUEUE as c_short; - let packet_information = config.platform.packet_information; + let packet_information = config.platform_config.packet_information; req.ifr_ifru.ifru_flags = device_type | if packet_information { 0 } else { iff_no_pi } | if queues_num > 1 { iff_multi_queue } else { 0 }; @@ -108,7 +108,7 @@ impl Device { Device { name, queues, ctl } }; - if config.platform.apply_settings { + if config.platform_config.apply_settings { device.configure(config)?; } @@ -201,7 +201,7 @@ impl Write for Device { } } -impl D for Device { +impl AbstractDevice for Device { type Queue = Queue; fn name(&self) -> Result { diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 20003113..babf44f5 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -19,26 +19,26 @@ pub mod sys; mod device; pub use self::device::{Device, Queue}; -use crate::configuration::Configuration as C; -use crate::error::*; +use crate::configuration::Configuration; +use crate::error::Result; /// Linux-only interface configuration. #[derive(Copy, Clone, Debug)] -pub struct Configuration { +pub struct PlatformConfig { pub(crate) packet_information: bool, pub(crate) apply_settings: bool, } -impl Default for Configuration { +impl Default for PlatformConfig { fn default() -> Self { - Configuration { + PlatformConfig { packet_information: false, apply_settings: true, } } } -impl Configuration { +impl PlatformConfig { /// Enable or disable packet information, when enabled the first 4 bytes of /// each packet is a header with flags and protocol type. pub fn packet_information(&mut self, value: bool) -> &mut Self { @@ -54,6 +54,6 @@ impl Configuration { } /// Create a TUN device with the given name. -pub fn create(configuration: &C) -> Result { +pub fn create(configuration: &Configuration) -> Result { Device::new(configuration) } diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index bbfd1ad7..28cd77f2 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -15,8 +15,8 @@ use crate::{ configuration::{Configuration, Layer}, - device::Device as D, - error::*, + device::AbstractDevice, + error::{Error, Result}, platform::{ macos::sys::*, posix::{self, Fd, SockAddr}, @@ -222,7 +222,7 @@ impl Write for Device { } } -impl D for Device { +impl AbstractDevice for Device { type Queue = Queue; fn name(&self) -> Result { diff --git a/src/platform/macos/mod.rs b/src/platform/macos/mod.rs index 05b390fe..df8f1e38 100644 --- a/src/platform/macos/mod.rs +++ b/src/platform/macos/mod.rs @@ -19,14 +19,14 @@ pub mod sys; mod device; pub use self::device::{Device, Queue}; -use crate::configuration::Configuration as C; -use crate::error::*; +use crate::configuration::Configuration; +use crate::error::Result; /// macOS-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct Configuration {} +pub struct PlatformConfig {} /// Create a TUN device with the given name. -pub fn create(configuration: &C) -> Result { +pub fn create(configuration: &Configuration) -> Result { Device::new(configuration) } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index cbf5ec6b..5d8d3b25 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -20,32 +20,32 @@ pub mod posix; #[cfg(target_os = "linux")] pub mod linux; #[cfg(target_os = "linux")] -pub use self::linux::{create, Configuration, Device, Queue}; +pub use self::linux::{create, Device, PlatformConfig, Queue}; #[cfg(target_os = "macos")] pub mod macos; #[cfg(target_os = "macos")] -pub use self::macos::{create, Configuration, Device, Queue}; +pub use self::macos::{create, Device, PlatformConfig, Queue}; #[cfg(target_os = "ios")] pub mod ios; #[cfg(target_os = "ios")] -pub use self::ios::{create, Configuration, Device, Queue}; +pub use self::ios::{create, Device, PlatformConfig, Queue}; #[cfg(target_os = "android")] pub mod android; #[cfg(target_os = "android")] -pub use self::android::{create, Configuration, Device, Queue}; +pub use self::android::{create, Device, PlatformConfig, Queue}; #[cfg(target_os = "windows")] pub mod windows; #[cfg(target_os = "windows")] -pub use self::windows::{create, Configuration, Device, Queue}; +pub use self::windows::{create, Device, PlatformConfig, Queue}; #[cfg(test)] mod test { use crate::configuration::Configuration; - use crate::device::Device; + use crate::device::AbstractDevice; use std::net::Ipv4Addr; #[test] diff --git a/src/platform/posix/fd.rs b/src/platform/posix/fd.rs index 89ea1614..461b5e20 100644 --- a/src/platform/posix/fd.rs +++ b/src/platform/posix/fd.rs @@ -12,12 +12,11 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use crate::error::{Error, Result}; +use libc::{self, fcntl, F_GETFL, F_SETFL, O_NONBLOCK}; use std::io::{self, Read, Write}; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; -use crate::error::*; -use libc::{self, fcntl, F_GETFL, F_SETFL, O_NONBLOCK}; - /// POSIX file descriptor support for `io` traits. pub struct Fd(pub RawFd); diff --git a/src/platform/posix/sockaddr.rs b/src/platform/posix/sockaddr.rs index ccc2a945..de563722 100644 --- a/src/platform/posix/sockaddr.rs +++ b/src/platform/posix/sockaddr.rs @@ -12,11 +12,10 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use crate::error::{Error, Result}; use libc::{in_addr, sockaddr, sockaddr_in}; use std::{mem, net::Ipv4Addr, ptr}; -use crate::error::*; - /// A wrapper for `sockaddr_in`. #[derive(Copy, Clone)] pub struct SockAddr(sockaddr_in); diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index f6efdbb7..8a856342 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -19,8 +19,8 @@ use std::sync::Arc; use wintun::Session; use crate::configuration::Configuration; -use crate::device::Device as D; -use crate::error::*; +use crate::device::AbstractDevice; +use crate::error::{Error, Result}; /// A TUN device using the wintun driver. pub struct Device { @@ -33,7 +33,7 @@ impl Device { pub fn new(config: &Configuration) -> Result { let wintun = unsafe { wintun::load()? }; let tun_name = config.name.as_deref().unwrap_or("wintun"); - let guid = config.platform.device_guid; + let guid = config.platform_config.device_guid; let adapter = match wintun::Adapter::open(&wintun, tun_name) { Ok(a) => a, Err(_) => wintun::Adapter::create(&wintun, tun_name, tun_name, guid)?, @@ -85,7 +85,7 @@ impl Write for Device { } } -impl D for Device { +impl AbstractDevice for Device { type Queue = Queue; fn name(&self) -> Result { diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs index 5eca4431..e900e654 100644 --- a/src/platform/windows/mod.rs +++ b/src/platform/windows/mod.rs @@ -18,23 +18,23 @@ mod device; pub use device::{Device, Queue}; -use crate::configuration::Configuration as C; -use crate::error::*; +use crate::configuration::Configuration; +use crate::error::Result; /// Windows-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct Configuration { +pub struct PlatformConfig { pub(crate) device_guid: Option, } -impl Configuration { - pub fn initialize(&mut self, device_guid: Option) { - log::trace!("Windows configuration initialize"); +impl PlatformConfig { + pub fn device_guid(&mut self, device_guid: Option) { + log::trace!("Windows configuration device GUID"); self.device_guid = device_guid; } } /// Create a TUN device with the given name. -pub fn create(configuration: &C) -> Result { +pub fn create(configuration: &Configuration) -> Result { Device::new(configuration) } From c2bb8e1835b5932d67f60883e12815a7c5e104fb Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 18 Jan 2024 22:25:16 +0800 Subject: [PATCH 22/44] Bump v0.7.1 --- Cargo.toml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7b5ffcd0..0c5e75a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2" -version = "0.7.0" +version = "0.7.1" edition = "2021" authors = ["meh. ", "@ssrlive"] diff --git a/README.md b/README.md index fa8b4edd..89961683 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ First, add the following to your `Cargo.toml`: ```toml [dependencies] -tun2 = "0.6" +tun2 = "0.7" ``` If you want to use the TUN interface with mio/tokio, you need to enable the `async` feature: ```toml [dependencies] -tun2 = { version = "0.6", features = ["async"] } +tun2 = { version = "0.7", features = ["async"] } ``` Example From 6b0bb56bbbb78b62d5edb1b9d6e85fe8673a3ca5 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:39:10 +0800 Subject: [PATCH 23/44] Create dependabot.yml --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..219c13ac --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "daily" From 5a182ddaaaa3084169ebf03f28293a2d6341bf86 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:55:37 +0800 Subject: [PATCH 24/44] codec module to public --- Cargo.toml | 8 ++++---- src/async/device.rs | 2 +- src/async/mod.rs | 3 --- src/async/win_device.rs | 2 +- src/{async => }/codec.rs | 20 +++++++++----------- src/lib.rs | 3 +++ 6 files changed, 18 insertions(+), 20 deletions(-) rename src/{async => }/codec.rs (90%) diff --git a/Cargo.toml b/Cargo.toml index 0c5e75a0..30bf79a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,14 +11,14 @@ repository = "https://github.com/ssrlive/rust-tun" keywords = ["tun", "network", "tunnel", "bindings"] [dependencies] -byteorder = { version = "1", optional = true } -bytes = { version = "1", optional = true } +byteorder = { version = "1" } +bytes = { version = "1" } futures-core = { version = "0.3", optional = true } libc = "0.2" log = "0.4" thiserror = "1" tokio = { version = "1", features = ["net", "macros"], optional = true } -tokio-util = { version = "0.7", features = ["codec"], optional = true } +tokio-util = { version = "0.7", features = ["codec"] } [target.'cfg(unix)'.dependencies] ioctl = { version = "0.8", package = "ioctl-sys" } @@ -33,7 +33,7 @@ tokio = { version = "1", features = ["rt-multi-thread"] } [features] default = [] -async = ["tokio", "tokio-util", "bytes", "byteorder", "futures-core"] +async = ["tokio", "futures-core"] [[example]] name = "read-async" diff --git a/src/async/device.rs b/src/async/device.rs index 24260820..a7bf9f71 100644 --- a/src/async/device.rs +++ b/src/async/device.rs @@ -22,9 +22,9 @@ use tokio::io::unix::AsyncFd; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; +use crate::codec::TunPacketCodec; use crate::device::AbstractDevice; use crate::platform::Device; -use crate::r#async::codec::TunPacketCodec; /// An async TUN device wrapper around a TUN device. pub struct AsyncDevice { diff --git a/src/async/mod.rs b/src/async/mod.rs index 2a8336cb..4e7eb402 100644 --- a/src/async/mod.rs +++ b/src/async/mod.rs @@ -29,9 +29,6 @@ mod win_device; #[cfg(target_os = "windows")] pub use win_device::AsyncDevice; -mod codec; -pub use self::codec::{TunPacket, TunPacketCodec}; - /// Create a TUN device with the given name. pub fn create_as_async(configuration: &Configuration) -> Result { let device = create(configuration)?; diff --git a/src/async/win_device.rs b/src/async/win_device.rs index 76be8aaa..b6ad8825 100644 --- a/src/async/win_device.rs +++ b/src/async/win_device.rs @@ -20,9 +20,9 @@ use std::io::Error; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; +use crate::codec::TunPacketCodec; use crate::device::AbstractDevice; use crate::platform::Device; -use crate::r#async::codec::TunPacketCodec; pub struct AsyncDevice { inner: Device, diff --git a/src/async/codec.rs b/src/codec.rs similarity index 90% rename from src/async/codec.rs rename to src/codec.rs index 23dfc11f..9e59ab67 100644 --- a/src/async/codec.rs +++ b/src/codec.rs @@ -12,8 +12,6 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::io; - use bytes::{BufMut, Bytes, BytesMut}; use tokio_util::codec::{Decoder, Encoder}; @@ -29,24 +27,24 @@ enum PacketProtocol { // Note: the protocol in the packet information header is platform dependent. impl PacketProtocol { #[cfg(any(target_os = "linux", target_os = "android"))] - fn into_pi_field(self) -> Result { + fn into_pi_field(self) -> std::io::Result { match self { PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16), PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16), - PacketProtocol::Other(_) => Err(io::Error::new( - io::ErrorKind::Other, + PacketProtocol::Other(_) => Err(std::io::Error::new( + std::io::ErrorKind::Other, "neither an IPv4 nor IPv6 packet", )), } } #[cfg(any(target_os = "macos", target_os = "ios"))] - fn into_pi_field(self) -> Result { + fn into_pi_field(self) -> std::io::Result { match self { PacketProtocol::IPv4 => Ok(libc::PF_INET as u16), PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16), - PacketProtocol::Other(_) => Err(io::Error::new( - io::ErrorKind::Other, + PacketProtocol::Other(_) => Err(std::io::Error::new( + std::io::ErrorKind::Other, "neither an IPv4 nor IPv6 packet", )), } @@ -54,7 +52,7 @@ impl PacketProtocol { #[cfg(target_os = "windows")] #[allow(dead_code)] - fn into_pi_field(self) -> Result { + fn into_pi_field(self) -> std::io::Result { unimplemented!() } } @@ -102,7 +100,7 @@ impl TunPacketCodec { impl Decoder for TunPacketCodec { type Item = TunPacket; - type Error = io::Error; + type Error = std::io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { if buf.is_empty() { @@ -129,7 +127,7 @@ impl Decoder for TunPacketCodec { } impl Encoder for TunPacketCodec { - type Error = io::Error; + type Error = std::io::Error; fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { dst.reserve(item.get_bytes().len() + if self.0 { 4 } else { 0 }); diff --git a/src/lib.rs b/src/lib.rs index cc50d7ae..d885f04f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,9 @@ mod error; pub use crate::error::{Error, Result}; +mod codec; +pub use self::codec::{TunPacket, TunPacketCodec}; + mod address; pub use crate::address::IntoAddress; From 4b48324dc9773af36ea96219059989131c8f0666 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 19 Jan 2024 20:39:34 +0800 Subject: [PATCH 25/44] rename to unix_device --- src/async/mod.rs | 4 ++-- src/async/{device.rs => unix_device.rs} | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) rename src/async/{device.rs => unix_device.rs} (93%) diff --git a/src/async/mod.rs b/src/async/mod.rs index 4e7eb402..e816ad7a 100644 --- a/src/async/mod.rs +++ b/src/async/mod.rs @@ -20,9 +20,9 @@ use crate::configuration::Configuration; use crate::platform::create; #[cfg(unix)] -mod device; +mod unix_device; #[cfg(unix)] -pub use self::device::AsyncDevice; +pub use unix_device::AsyncDevice; #[cfg(target_os = "windows")] mod win_device; diff --git a/src/async/device.rs b/src/async/unix_device.rs similarity index 93% rename from src/async/device.rs rename to src/async/unix_device.rs index a7bf9f71..e334ea83 100644 --- a/src/async/device.rs +++ b/src/async/unix_device.rs @@ -12,12 +12,10 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::io; -use std::io::{IoSlice, Read, Write}; - use core::pin::Pin; use core::task::{Context, Poll}; use futures_core::ready; +use std::io::{IoSlice, Read, Write}; use tokio::io::unix::AsyncFd; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_util::codec::Framed; @@ -33,7 +31,7 @@ pub struct AsyncDevice { impl AsyncDevice { /// Create a new `AsyncDevice` wrapping around a `Device`. - pub fn new(device: Device) -> io::Result { + pub fn new(device: Device) -> std::io::Result { device.set_nonblock()?; Ok(AsyncDevice { inner: AsyncFd::new(device)?, @@ -64,7 +62,7 @@ impl AsyncRead for AsyncDevice { mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf, - ) -> Poll> { + ) -> Poll> { loop { let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?; let rbuf = buf.initialize_unfilled(); @@ -81,7 +79,7 @@ impl AsyncWrite for AsyncDevice { mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], - ) -> Poll> { + ) -> Poll> { loop { let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; match guard.try_io(|inner| inner.get_mut().write(buf)) { @@ -91,7 +89,7 @@ impl AsyncWrite for AsyncDevice { } } - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { loop { let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; match guard.try_io(|inner| inner.get_mut().flush()) { @@ -101,7 +99,7 @@ impl AsyncWrite for AsyncDevice { } } - fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } @@ -109,7 +107,7 @@ impl AsyncWrite for AsyncDevice { mut self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], - ) -> Poll> { + ) -> Poll> { loop { let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; match guard.try_io(|inner| inner.get_mut().write_vectored(bufs)) { From e0e079225f671d6d8bf4dc1177446b7d9757db88 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 10:39:14 +0800 Subject: [PATCH 26/44] avoid unnecessary copy and fix lfreq not found on macOS --- Cargo.toml | 2 +- src/platform/android/device.rs | 2 +- src/platform/ios/device.rs | 2 +- src/platform/linux/device.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 30bf79a5..c556fcbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["tun", "network", "tunnel", "bindings"] byteorder = { version = "1" } bytes = { version = "1" } futures-core = { version = "0.3", optional = true } -libc = "0.2" +libc = "0.2.152" log = "0.4" thiserror = "1" tokio = { version = "1", features = ["net", "macros"], optional = true } diff --git a/src/platform/android/device.rs b/src/platform/android/device.rs index 2f7375c7..bc4d099f 100644 --- a/src/platform/android/device.rs +++ b/src/platform/android/device.rs @@ -48,7 +48,7 @@ impl Device { /// Split the interface into a `Reader` and `Writer`. pub fn split(self) -> (posix::Reader, posix::Writer) { let fd = Arc::new(self.queue.tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) + (posix::Reader(fd.clone()), posix::Writer(fd)) } /// Return whether the device has packet information diff --git a/src/platform/ios/device.rs b/src/platform/ios/device.rs index d2c0bb21..262d1962 100644 --- a/src/platform/ios/device.rs +++ b/src/platform/ios/device.rs @@ -51,7 +51,7 @@ impl Device { /// Split the interface into a `Reader` and `Writer`. pub fn split(self) -> (posix::Reader, posix::Writer) { let fd = Arc::new(self.queue.tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) + (posix::Reader(fd.clone()), posix::Writer(fd)) } /// Return whether the device has packet information diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index f009463c..8ab6f235 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -168,7 +168,7 @@ impl Device { /// Split the interface into a `Reader` and `Writer`. pub fn split(mut self) -> (posix::Reader, posix::Writer) { let fd = Arc::new(self.queues.swap_remove(0).tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) + (posix::Reader(fd.clone()), posix::Writer(fd)) } /// Set non-blocking mode From 04fb141447b9d61014feee08c62bfee47966c2a2 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 10:43:09 +0800 Subject: [PATCH 27/44] bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c556fcbe..3838c683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2" -version = "0.7.1" +version = "0.7.2" edition = "2021" authors = ["meh. ", "@ssrlive"] From e9ce3a0a91ab29576fa9c65a96c3b67f27301f9e Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 11:41:13 +0800 Subject: [PATCH 28/44] add split for windows platform --- src/platform/windows/device.rs | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index 8a856342..fb814d48 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -59,6 +59,11 @@ impl Device { Ok(device) } + + pub fn split(self) -> (Reader, Writer) { + let queue = Arc::new(self.queue); + (Reader(queue.clone()), Writer(queue)) + } } impl Read for Device { @@ -228,3 +233,41 @@ impl Drop for Queue { } } } + +#[repr(transparent)] +pub struct Reader(Arc); + +impl Read for Reader { + fn read(&mut self, mut buf: &mut [u8]) -> io::Result { + match self.0.session.receive_blocking() { + Ok(pkt) => match io::copy(&mut pkt.bytes(), &mut buf) { + Ok(n) => Ok(n as usize), + Err(e) => Err(e), + }, + Err(e) => Err(io::Error::new(io::ErrorKind::ConnectionAborted, e)), + } + } +} + +#[repr(transparent)] +pub struct Writer(Arc); + +impl Write for Writer { + fn write(&mut self, mut buf: &[u8]) -> io::Result { + let size = buf.len(); + match self.0.session.allocate_send_packet(size as u16) { + Err(e) => Err(io::Error::new(io::ErrorKind::OutOfMemory, e)), + Ok(mut packet) => match io::copy(&mut buf, &mut packet.bytes_mut()) { + Ok(s) => { + self.0.session.send_packet(packet); + Ok(s as usize) + } + Err(e) => Err(e), + }, + } + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} From a39357f7cff99de9af7f20a7804bcb5dacbf955f Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 11:47:56 +0800 Subject: [PATCH 29/44] recover libc version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3838c683..fd2e5de5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["tun", "network", "tunnel", "bindings"] byteorder = { version = "1" } bytes = { version = "1" } futures-core = { version = "0.3", optional = true } -libc = "0.2.152" +libc = "0.2" log = "0.4" thiserror = "1" tokio = { version = "1", features = ["net", "macros"], optional = true } From fd74d717c7cf054327dff38ed474fc82fcc2de9d Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 13:11:15 +0800 Subject: [PATCH 30/44] refine platform/windows/device.rs --- src/platform/windows/device.rs | 49 +++++++++++++--------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index fb814d48..9b1b48cf 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -191,12 +191,8 @@ impl Queue { pub fn get_session(&self) -> Arc { self.session.clone() } -} - -impl Read for Queue { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result { - let reader_session = self.session.clone(); - match reader_session.receive_blocking() { + fn read_by_ref(&self, mut buf: &mut [u8]) -> io::Result { + match self.session.receive_blocking() { Ok(pkt) => match io::copy(&mut pkt.bytes(), &mut buf) { Ok(n) => Ok(n as usize), Err(e) => Err(e), @@ -204,10 +200,7 @@ impl Read for Queue { Err(e) => Err(io::Error::new(io::ErrorKind::ConnectionAborted, e)), } } -} - -impl Write for Queue { - fn write(&mut self, mut buf: &[u8]) -> io::Result { + fn write_by_ref(&self, mut buf: &[u8]) -> io::Result { let size = buf.len(); match self.session.allocate_send_packet(size as u16) { Err(e) => Err(io::Error::new(io::ErrorKind::OutOfMemory, e)), @@ -220,6 +213,18 @@ impl Write for Queue { }, } } +} + +impl Read for Queue { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.read_by_ref(buf) + } +} + +impl Write for Queue { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.write_by_ref(buf) + } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -238,14 +243,8 @@ impl Drop for Queue { pub struct Reader(Arc); impl Read for Reader { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result { - match self.0.session.receive_blocking() { - Ok(pkt) => match io::copy(&mut pkt.bytes(), &mut buf) { - Ok(n) => Ok(n as usize), - Err(e) => Err(e), - }, - Err(e) => Err(io::Error::new(io::ErrorKind::ConnectionAborted, e)), - } + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read_by_ref(buf) } } @@ -253,18 +252,8 @@ impl Read for Reader { pub struct Writer(Arc); impl Write for Writer { - fn write(&mut self, mut buf: &[u8]) -> io::Result { - let size = buf.len(); - match self.0.session.allocate_send_packet(size as u16) { - Err(e) => Err(io::Error::new(io::ErrorKind::OutOfMemory, e)), - Ok(mut packet) => match io::copy(&mut buf, &mut packet.bytes_mut()) { - Ok(s) => { - self.0.session.send_packet(packet); - Ok(s as usize) - } - Err(e) => Err(e), - }, - } + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write_by_ref(buf) } fn flush(&mut self) -> io::Result<()> { From 13cb7d827209cbf710cdfbe1828968da8a46f532 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 13:20:11 +0800 Subject: [PATCH 31/44] Bump package version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fd2e5de5..4f3788e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2" -version = "0.7.2" +version = "0.7.21" edition = "2021" authors = ["meh. ", "@ssrlive"] From b2d3b10dd836a583e24ce9b42dce2b0c255a737f Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 13:35:18 +0800 Subject: [PATCH 32/44] fix mtu for windows --- src/configuration.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/configuration.rs b/src/configuration.rs index 34a30684..d6f99306 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -92,7 +92,10 @@ impl Configuration { /// Set the MTU. pub fn mtu(&mut self, value: i32) -> &mut Self { - self.mtu = Some(value); + // mtu on windows platform is always 65535 due to wintun + if cfg!(target_family = "unix") { + self.mtu = Some(value); + } self } From bcdbcbc593e87b26ae4f21222cb685ea0d538888 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Mon, 22 Jan 2024 13:36:33 +0800 Subject: [PATCH 33/44] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4f3788e9..418c23e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2" -version = "0.7.21" +version = "0.7.22" edition = "2021" authors = ["meh. ", "@ssrlive"] From 19b77c489e253857aaafb30df55103ce2887a125 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 11:16:49 +0800 Subject: [PATCH 34/44] set PlatformConfig to zero-size type if it is no-op --- src/platform/android/mod.rs | 2 +- src/platform/ios/mod.rs | 2 +- src/platform/macos/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform/android/mod.rs b/src/platform/android/mod.rs index e27d29c0..be5e6c2f 100644 --- a/src/platform/android/mod.rs +++ b/src/platform/android/mod.rs @@ -22,7 +22,7 @@ use crate::error::Result; /// Android-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct PlatformConfig {} +pub struct PlatformConfig; // zero-size type for more optimization /// Create a TUN device with the given name. pub fn create(configuration: &Configuration) -> Result { diff --git a/src/platform/ios/mod.rs b/src/platform/ios/mod.rs index 8990c33e..5ca022d3 100644 --- a/src/platform/ios/mod.rs +++ b/src/platform/ios/mod.rs @@ -22,7 +22,7 @@ use crate::error::Result; /// iOS-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct PlatformConfig {} +pub struct PlatformConfig; // zero-size type for more optimization /// Create a TUN device with the given name. pub fn create(configuration: &Configuration) -> Result { diff --git a/src/platform/macos/mod.rs b/src/platform/macos/mod.rs index df8f1e38..2489ca40 100644 --- a/src/platform/macos/mod.rs +++ b/src/platform/macos/mod.rs @@ -24,7 +24,7 @@ use crate::error::Result; /// macOS-only interface configuration. #[derive(Copy, Clone, Default, Debug)] -pub struct PlatformConfig {} +pub struct PlatformConfig; // zero-size type for more optimization /// Create a TUN device with the given name. pub fn create(configuration: &Configuration) -> Result { From 8fd2629819f37a27842e78b249a81beb91226900 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 13:27:44 +0800 Subject: [PATCH 35/44] revamp encapsulatation --- src/platform/macos/device.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index 28cd77f2..6452884d 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -145,7 +145,7 @@ impl Device { /// Prepare a new request. /// # Safety - pub unsafe fn request(&self) -> Result { + pub(crate) unsafe fn request(&self) -> Result { let name = self.name.as_ref().ok_or(Error::InvalidConfig)?; let mut req: libc::ifreq = mem::zeroed(); ptr::copy_nonoverlapping( @@ -158,7 +158,12 @@ impl Device { } /// Set the IPv4 alias of the device. - pub fn set_alias(&mut self, addr: Ipv4Addr, broadaddr: Ipv4Addr, mask: Ipv4Addr) -> Result<()> { + pub(crate) fn set_alias( + &mut self, + addr: Ipv4Addr, + broadaddr: Ipv4Addr, + mask: Ipv4Addr, + ) -> Result<()> { let name = self.name.as_ref().ok_or(Error::InvalidConfig)?; let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { From 046e9b2e619fdd046ff30284e62b0f1d174b2f82 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 13:41:45 +0800 Subject: [PATCH 36/44] correct read-async example --- Cargo.toml | 2 +- examples/read-async.rs | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 418c23e0..5f6d36ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ wintun = { version = "0.4", features = ["panic_on_unsent_packets"] } [dev-dependencies] futures = "0.3" packet = "0.1" -tokio = { version = "1", features = ["rt-multi-thread"] } +tokio = { version = "1", features = ["rt-multi-thread","io-util"] } [features] default = [] diff --git a/examples/read-async.rs b/examples/read-async.rs index f600194c..22a9b11e 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -12,16 +12,17 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use futures::StreamExt; -use packet::ip::Packet; +use tokio::io::AsyncReadExt; #[tokio::main] async fn main() { + const MTU: i32 = 1500; let mut config = tun2::Configuration::default(); config .address((10, 0, 0, 1)) .netmask((255, 255, 255, 0)) + .mtu(MTU) .up(); #[cfg(target_os = "linux")] @@ -30,14 +31,9 @@ async fn main() { config.apply_settings(true); }); - let dev = tun2::create_as_async(&config).unwrap(); - - let mut stream = dev.into_framed(); - - while let Some(packet) = stream.next().await { - match packet { - Ok(pkt) => println!("pkt: {:#?}", Packet::unchecked(pkt.get_bytes())), - Err(err) => panic!("Error: {:?}", err), - } + let mut dev = tun2::create_as_async(&config).unwrap(); + let mut buf = [0u8; MTU as usize + 4]; + while let Ok(len) = dev.read(&mut buf).await { + println!("pkt: {:?}", &buf[..len]); } } From 8b5d4c0b8576d34b5b278f520e4996496472280b Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 14:09:17 +0800 Subject: [PATCH 37/44] recover pub --- src/platform/macos/device.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index 6452884d..28cd77f2 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -145,7 +145,7 @@ impl Device { /// Prepare a new request. /// # Safety - pub(crate) unsafe fn request(&self) -> Result { + pub unsafe fn request(&self) -> Result { let name = self.name.as_ref().ok_or(Error::InvalidConfig)?; let mut req: libc::ifreq = mem::zeroed(); ptr::copy_nonoverlapping( @@ -158,12 +158,7 @@ impl Device { } /// Set the IPv4 alias of the device. - pub(crate) fn set_alias( - &mut self, - addr: Ipv4Addr, - broadaddr: Ipv4Addr, - mask: Ipv4Addr, - ) -> Result<()> { + pub fn set_alias(&mut self, addr: Ipv4Addr, broadaddr: Ipv4Addr, mask: Ipv4Addr) -> Result<()> { let name = self.name.as_ref().ok_or(Error::InvalidConfig)?; let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { From e87262e2d368082f324d4f09c37f95063ac0f868 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 14:21:00 +0800 Subject: [PATCH 38/44] update dependabot.yml --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 219c13ac..13b4ef51 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,9 @@ version: 2 updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" - package-ecosystem: "cargo" directory: "/" schedule: From 4c6e10713decdd1defd6c60beb7470b2fa6ae202 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 06:21:24 +0000 Subject: [PATCH 39/44] chore(deps): bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7fd4430e..d74cc4cc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -15,7 +15,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: rustfmt run: cargo fmt --all -- --check - name: check From 3f47a6dee962875ce4dd5b2e4a3df0e1a7fd31c5 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 14:30:02 +0800 Subject: [PATCH 40/44] update example --- examples/read-async.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/read-async.rs b/examples/read-async.rs index 22a9b11e..80d9f8a2 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -32,8 +32,11 @@ async fn main() { }); let mut dev = tun2::create_as_async(&config).unwrap(); - let mut buf = [0u8; MTU as usize + 4]; - while let Ok(len) = dev.read(&mut buf).await { - println!("pkt: {:?}", &buf[..len]); + let mut buf: [u8; 1504] = [0u8; MTU as usize + 4]; + loop { + match dev.read(&mut buf).await { + Ok(len) => println!("pkt: {:?}", &buf[..len]), + Err(_) => {} + } } } From 8127bc122661492a9932d111816a57f7676afaf2 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 14:32:16 +0800 Subject: [PATCH 41/44] update --- examples/read-async.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/read-async.rs b/examples/read-async.rs index 80d9f8a2..fb4d6d76 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -34,9 +34,8 @@ async fn main() { let mut dev = tun2::create_as_async(&config).unwrap(); let mut buf: [u8; 1504] = [0u8; MTU as usize + 4]; loop { - match dev.read(&mut buf).await { - Ok(len) => println!("pkt: {:?}", &buf[..len]), - Err(_) => {} + if let Ok(len) = dev.read(&mut buf).await { + println!("pkt: {:?}", &buf[..len]) } } } From 701b7e322e43aa26c6e173bf44fe478397fc0358 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 23 Jan 2024 14:33:14 +0800 Subject: [PATCH 42/44] update --- examples/read-async.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/read-async.rs b/examples/read-async.rs index fb4d6d76..16a1dcfc 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -35,7 +35,7 @@ async fn main() { let mut buf: [u8; 1504] = [0u8; MTU as usize + 4]; loop { if let Ok(len) = dev.read(&mut buf).await { - println!("pkt: {:?}", &buf[..len]) + println!("pkt: {:?}", &buf[..len]); } } } From 0bf68e2c6577e992e4968bb7996168039da32850 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 23 Jan 2024 23:25:13 +0800 Subject: [PATCH 43/44] refine TunPacketCodec (#19) --- Cargo.toml | 5 +- README.md | 4 +- examples/ping-tun.rs | 6 +- src/async/unix_device.rs | 29 ++++--- src/async/win_device.rs | 30 ++++--- src/codec.rs | 144 +++++++++++++++------------------ src/device.rs | 3 + src/platform/android/device.rs | 28 ++++--- src/platform/ios/device.rs | 28 ++++--- src/platform/linux/device.rs | 39 +++++---- src/platform/macos/device.rs | 27 ++++--- src/platform/windows/device.rs | 16 ++++ 12 files changed, 208 insertions(+), 151 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5f6d36ab..79bcd36e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,9 @@ description = "TUN device creation and handling." repository = "https://github.com/ssrlive/rust-tun" keywords = ["tun", "network", "tunnel", "bindings"] +[lib] +crate-type = ["staticlib", "cdylib", "lib"] + [dependencies] byteorder = { version = "1" } bytes = { version = "1" } @@ -29,7 +32,7 @@ wintun = { version = "0.4", features = ["panic_on_unsent_packets"] } [dev-dependencies] futures = "0.3" packet = "0.1" -tokio = { version = "1", features = ["rt-multi-thread","io-util"] } +tokio = { version = "1", features = ["rt-multi-thread", "io-util"] } [features] default = [] diff --git a/README.md b/README.md index 89961683..f0aa0ea5 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ TUN interfaces This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform. > Since the original maintainer @meh is no longer interested in continuing to maintain -> [tun](https://crates.io/crates/tun), -> I (@ssrlive) created the [tun2](https://github.com/ssrlive/rust-tun) branch and +> [tun](https://crates.io/crates/tun) at [repo](https://github.com/meh/rust-tun), +> I (@ssrlive) created the [tun2](https://github.com/ssrlive/rust-tun) branch repo and > continued to actively update. Welcome to any interested contributor. > If you want to be a co-contributor and publisher of [tun2](https://crates.io/crates/tun2), > please contact me in [issues](https://github.com/ssrlive/rust-tun/issues). diff --git a/examples/ping-tun.rs b/examples/ping-tun.rs index c7a5828b..beba90bb 100644 --- a/examples/ping-tun.rs +++ b/examples/ping-tun.rs @@ -14,7 +14,7 @@ use futures::{SinkExt, StreamExt}; use packet::{builder::Builder, icmp, ip, Packet}; -use tun2::{self, Configuration, TunPacket}; +use tun2::{self, AbstractDevice, Configuration, TunPacket}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -38,6 +38,7 @@ async fn main() -> Result<(), Box> { }); let dev = tun2::create_as_async(&config)?; + let packet_information = dev.as_ref().packet_information(); let mut framed = dev.into_framed(); @@ -60,7 +61,8 @@ async fn main() -> Result<(), Box> { .sequence(icmp.sequence())? .payload(icmp.payload())? .build()?; - framed.send(TunPacket::new(reply)).await?; + let pkt = TunPacket::new(packet_information, reply); + framed.send(pkt).await?; } } } diff --git a/src/async/unix_device.rs b/src/async/unix_device.rs index e334ea83..696e8ac5 100644 --- a/src/async/unix_device.rs +++ b/src/async/unix_device.rs @@ -29,6 +29,20 @@ pub struct AsyncDevice { inner: AsyncFd, } +/// Returns a shared reference to the underlying Device object +impl AsRef for AsyncDevice { + fn as_ref(&self) -> &Device { + self.inner.get_ref() + } +} + +/// Returns a mutable reference to the underlying Device object +impl AsMut for AsyncDevice { + fn as_mut(&mut self) -> &mut Device { + self.inner.get_mut() + } +} + impl AsyncDevice { /// Create a new `AsyncDevice` wrapping around a `Device`. pub fn new(device: Device) -> std::io::Result { @@ -37,23 +51,14 @@ impl AsyncDevice { inner: AsyncFd::new(device)?, }) } - /// Returns a shared reference to the underlying Device object - pub fn get_ref(&self) -> &Device { - self.inner.get_ref() - } - - /// Returns a mutable reference to the underlying Device object - pub fn get_mut(&mut self) -> &mut Device { - self.inner.get_mut() - } /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) pub fn into_framed(self) -> Framed { - let packet_information = self.get_ref().has_packet_information(); - let mtu = self.inner.get_ref().mtu().unwrap_or(1504); + let packet_information = self.as_ref().packet_information(); + let mtu = self.as_ref().mtu().unwrap_or(1504) as usize; let codec = TunPacketCodec::new(packet_information, mtu); // associate mtu with the capacity of ReadBuf - Framed::with_capacity(self, codec, mtu as usize) + Framed::with_capacity(self, codec, mtu) } } diff --git a/src/async/win_device.rs b/src/async/win_device.rs index b6ad8825..c6a2a20a 100644 --- a/src/async/win_device.rs +++ b/src/async/win_device.rs @@ -29,6 +29,20 @@ pub struct AsyncDevice { session: WinSession, } +/// Returns a shared reference to the underlying Device object +impl AsRef for AsyncDevice { + fn as_ref(&self) -> &Device { + &self.inner + } +} + +/// Returns a mutable reference to the underlying Device object +impl AsMut for AsyncDevice { + fn as_mut(&mut self) -> &mut Device { + &mut self.inner + } +} + impl AsyncDevice { /// Create a new `AsyncDevice` wrapping around a `Device`. pub fn new(device: Device) -> io::Result { @@ -38,22 +52,14 @@ impl AsyncDevice { session, }) } - /// Returns a shared reference to the underlying Device object - pub fn get_ref(&self) -> &Device { - &self.inner - } - - /// Returns a mutable reference to the underlying Device object - pub fn get_mut(&mut self) -> &mut Device { - &mut self.inner - } /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) pub fn into_framed(self) -> Framed { - let mtu = self.get_ref().mtu().unwrap_or(u16::MAX as i32); - let codec = TunPacketCodec::new(false, mtu); + let packet_information = self.as_ref().packet_information(); + let mtu = self.as_ref().mtu().unwrap_or(u16::MAX as i32) as usize; + let codec = TunPacketCodec::new(packet_information, mtu); // guarantee to avoid the mtu of wintun may far away larger than the default provided capacity of buff of Framed - Framed::with_capacity(self, codec, mtu as usize) + Framed::with_capacity(self, codec, mtu) } } diff --git a/src/codec.rs b/src/codec.rs index 9e59ab67..8ca98ead 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -15,86 +15,89 @@ use bytes::{BufMut, Bytes, BytesMut}; use tokio_util::codec::{Decoder, Encoder}; -/// A packet protocol IP version -#[derive(Debug, Clone, Copy, Default)] -enum PacketProtocol { - #[default] - IPv4, - IPv6, - Other(u8), +const PACKET_INFORMATION_LENGTH: usize = 4; + +/// Infer the protocol based on the first nibble in the packet buffer. +fn is_ipv6(buf: &[u8]) -> std::io::Result { + use std::io::{Error, ErrorKind::InvalidData}; + match buf[0] >> 4 { + 4 => Ok(false), + 6 => Ok(true), + p => Err(Error::new(InvalidData, format!("IP version {}", p))), + } } -// Note: the protocol in the packet information header is platform dependent. -impl PacketProtocol { +fn generate_packet_information(_packet_information: bool, _ipv6: bool) -> Option { #[cfg(any(target_os = "linux", target_os = "android"))] - fn into_pi_field(self) -> std::io::Result { - match self { - PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16), - PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16), - PacketProtocol::Other(_) => Err(std::io::Error::new( - std::io::ErrorKind::Other, - "neither an IPv4 nor IPv6 packet", - )), - } - } + const TUN_PROTO_IP6: [u8; PACKET_INFORMATION_LENGTH] = (libc::ETH_P_IPV6 as u32).to_be_bytes(); + #[cfg(any(target_os = "linux", target_os = "android"))] + const TUN_PROTO_IP4: [u8; PACKET_INFORMATION_LENGTH] = (libc::ETH_P_IP as u32).to_be_bytes(); #[cfg(any(target_os = "macos", target_os = "ios"))] - fn into_pi_field(self) -> std::io::Result { - match self { - PacketProtocol::IPv4 => Ok(libc::PF_INET as u16), - PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16), - PacketProtocol::Other(_) => Err(std::io::Error::new( - std::io::ErrorKind::Other, - "neither an IPv4 nor IPv6 packet", - )), - } - } + const TUN_PROTO_IP6: [u8; PACKET_INFORMATION_LENGTH] = (libc::AF_INET6 as u32).to_be_bytes(); + #[cfg(any(target_os = "macos", target_os = "ios"))] + const TUN_PROTO_IP4: [u8; PACKET_INFORMATION_LENGTH] = (libc::AF_INET as u32).to_be_bytes(); - #[cfg(target_os = "windows")] - #[allow(dead_code)] - fn into_pi_field(self) -> std::io::Result { - unimplemented!() + #[cfg(unix)] + if _packet_information { + let mut buf = BytesMut::with_capacity(PACKET_INFORMATION_LENGTH); + if _ipv6 { + buf.put_slice(&TUN_PROTO_IP6); + } else { + buf.put_slice(&TUN_PROTO_IP4); + } + return Some(buf.freeze()); } + None } /// A Tun Packet to be sent or received on the TUN interface. #[derive(Debug)] -pub struct TunPacket(PacketProtocol, Bytes); - -/// Infer the protocol based on the first nibble in the packet buffer. -fn infer_proto(buf: &[u8]) -> PacketProtocol { - match buf[0] >> 4 { - 4 => PacketProtocol::IPv4, - 6 => PacketProtocol::IPv6, - p => PacketProtocol::Other(p), - } +pub struct TunPacket { + /// The packet information header. + pub(crate) header: Option, + /// The packet bytes. + pub(crate) bytes: Bytes, } impl TunPacket { /// Create a new `TunPacket` based on a byte slice. - pub fn new + Into>(bytes: S) -> TunPacket { - let proto = infer_proto(bytes.as_ref()); - TunPacket(proto, bytes.into()) + pub fn new + Into>(packet_information: bool, bytes: S) -> TunPacket { + let bytes = bytes.into(); + let ipv6 = is_ipv6(bytes.as_ref()).unwrap(); + let header = generate_packet_information(packet_information, ipv6); + TunPacket { header, bytes } } /// Return this packet's bytes. pub fn get_bytes(&self) -> &[u8] { - &self.1 + &self.bytes } pub fn into_bytes(self) -> Bytes { - self.1 + self.bytes } } /// A TunPacket Encoder/Decoder. -pub struct TunPacketCodec(bool, i32); +#[derive(Debug, Default)] +pub struct TunPacketCodec { + /// Whether the underlying tunnel Device has enabled the packet information header. + pub(crate) packet_information: bool, + + /// The MTU of the underlying tunnel Device. + pub(crate) mtu: usize, +} impl TunPacketCodec { /// Create a new `TunPacketCodec` specifying whether the underlying /// tunnel Device has enabled the packet information header. - pub fn new(packet_information: bool, mtu: i32) -> TunPacketCodec { - TunPacketCodec(packet_information, mtu) + pub fn new(packet_information: bool, mtu: usize) -> TunPacketCodec { + let mtu = u16::try_from(mtu).unwrap_or(u16::MAX) as usize; + TunPacketCodec { + packet_information, + mtu, + } } } @@ -110,19 +113,20 @@ impl Decoder for TunPacketCodec { let mut pkt = buf.split_to(buf.len()); // reserve enough space for the next packet - if self.0 { - buf.reserve(self.1 as usize + 4); + if self.packet_information { + buf.reserve(self.mtu + PACKET_INFORMATION_LENGTH); } else { - buf.reserve(self.1 as usize); + buf.reserve(self.mtu); } + let mut header = None; // if the packet information is enabled we have to ignore the first 4 bytes - if self.0 { - let _ = pkt.split_to(4); + if self.packet_information { + header = Some(pkt.split_to(PACKET_INFORMATION_LENGTH).into()); } - let proto = infer_proto(pkt.as_ref()); - Ok(Some(TunPacket(proto, pkt.freeze()))) + let bytes = pkt.freeze(); + Ok(Some(TunPacket { header, bytes })) } } @@ -130,28 +134,14 @@ impl Encoder for TunPacketCodec { type Error = std::io::Error; fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { - dst.reserve(item.get_bytes().len() + if self.0 { 4 } else { 0 }); - match item { - TunPacket(_proto, bytes) if self.0 => { - #[cfg(unix)] - { - use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt}; - - // build the packet information header comprising of 2 u16 - // fields: flags and protocol. - let mut buf = Vec::::with_capacity(4); - - // flags is always 0 - buf.write_u16::(0)?; - // write the protocol as network byte order - buf.write_u16::(_proto.into_pi_field()?)?; - - dst.put_slice(&buf); - } - dst.put(bytes); + let extra = PACKET_INFORMATION_LENGTH; + dst.reserve(item.get_bytes().len() + if self.packet_information { extra } else { 0 }); + if self.packet_information { + if let Some(header) = &item.header { + dst.put_slice(header.as_ref()); } - TunPacket(_, bytes) => dst.put(bytes), } + dst.put(item.get_bytes()); Ok(()) } } diff --git a/src/device.rs b/src/device.rs index 76147d73..185ceb3c 100644 --- a/src/device.rs +++ b/src/device.rs @@ -91,4 +91,7 @@ pub trait AbstractDevice: Read + Write { /// Get a device queue. fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>; + + /// Return whether the device has packet information + fn packet_information(&self) -> bool; } diff --git a/src/platform/android/device.rs b/src/platform/android/device.rs index bc4d099f..29f9f155 100644 --- a/src/platform/android/device.rs +++ b/src/platform/android/device.rs @@ -28,6 +28,18 @@ pub struct Device { queue: Queue, } +impl AsRef + 'static> for Device { + fn as_ref(&self) -> &(dyn AbstractDevice + 'static) { + self + } +} + +impl AsMut + 'static> for Device { + fn as_mut(&mut self) -> &mut (dyn AbstractDevice + 'static) { + self + } +} + impl Device { /// Create a new `Device` for the given `Configuration`. pub fn new(config: &Configuration) -> Result { @@ -42,6 +54,7 @@ impl Device { queue: Queue { tun }, } }; + Ok(device) } @@ -51,11 +64,6 @@ impl Device { (posix::Reader(fd.clone()), posix::Writer(fd)) } - /// Return whether the device has packet information - pub fn has_packet_information(&self) -> bool { - self.queue.has_packet_information() - } - /// Set non-blocking mode pub fn set_nonblock(&self) -> std::io::Result<()> { self.queue.set_nonblock() @@ -148,6 +156,11 @@ impl AbstractDevice for Device { Some(&mut self.queue) } + + fn packet_information(&self) -> bool { + // on Android this is always the case + false + } } impl AsRawFd for Device { @@ -167,11 +180,6 @@ pub struct Queue { } impl Queue { - pub fn has_packet_information(&self) -> bool { - // on Android this is always the case - false - } - pub fn set_nonblock(&self) -> std::io::Result<()> { self.tun.set_nonblock() } diff --git a/src/platform/ios/device.rs b/src/platform/ios/device.rs index 262d1962..f26d590f 100644 --- a/src/platform/ios/device.rs +++ b/src/platform/ios/device.rs @@ -31,6 +31,18 @@ pub struct Device { queue: Queue, } +impl AsRef + 'static> for Device { + fn as_ref(&self) -> &(dyn AbstractDevice + 'static) { + self + } +} + +impl AsMut + 'static> for Device { + fn as_mut(&mut self) -> &mut (dyn AbstractDevice + 'static) { + self + } +} + impl Device { /// Create a new `Device` for the given `Configuration`. pub fn new(config: &Configuration) -> Result { @@ -45,6 +57,7 @@ impl Device { queue: Queue { tun }, } }; + Ok(device) } @@ -54,11 +67,6 @@ impl Device { (posix::Reader(fd.clone()), posix::Writer(fd)) } - /// Return whether the device has packet information - pub fn has_packet_information(&self) -> bool { - self.queue.has_packet_information() - } - /// Set non-blocking mode pub fn set_nonblock(&self) -> std::io::Result<()> { self.queue.set_nonblock() @@ -151,6 +159,11 @@ impl AbstractDevice for Device { Some(&mut self.queue) } + + fn packet_information(&self) -> bool { + // on ios this is always the case + true + } } impl AsRawFd for Device { @@ -170,11 +183,6 @@ pub struct Queue { } impl Queue { - pub fn has_packet_information(&self) -> bool { - // on ios this is always the case - true - } - pub fn set_nonblock(&self) -> std::io::Result<()> { self.tun.set_nonblock() } diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index 8ab6f235..5771d300 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -40,6 +40,19 @@ pub struct Device { name: String, queues: Vec, ctl: Fd, + packet_information: bool, +} + +impl AsRef + 'static> for Device { + fn as_ref(&self) -> &(dyn AbstractDevice + 'static) { + self + } +} + +impl AsMut + 'static> for Device { + fn as_mut(&mut self) -> &mut (dyn AbstractDevice + 'static) { + self + } } impl Device { @@ -94,10 +107,7 @@ impl Device { return Err(io::Error::last_os_error().into()); } - queues.push(Queue { - tun, - packet_information, - }); + queues.push(Queue { tun }); } let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?; @@ -105,7 +115,12 @@ impl Device { let name = CStr::from_ptr(req.ifr_name.as_ptr()) .to_string_lossy() .to_string(); - Device { name, queues, ctl } + Device { + name, + queues, + ctl, + packet_information, + } }; if config.platform_config.apply_settings { @@ -160,11 +175,6 @@ impl Device { } } - /// Return whether the device has packet information - pub fn has_packet_information(&self) -> bool { - self.queues[0].has_packet_information() - } - /// Split the interface into a `Reader` and `Writer`. pub fn split(mut self) -> (posix::Reader, posix::Writer) { let fd = Arc::new(self.queues.swap_remove(0).tun); @@ -383,6 +393,10 @@ impl AbstractDevice for Device { fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> { self.queues.get_mut(index) } + + fn packet_information(&self) -> bool { + self.packet_information + } } impl AsRawFd for Device { @@ -401,14 +415,9 @@ impl IntoRawFd for Device { pub struct Queue { tun: Fd, - packet_information: bool, } impl Queue { - pub fn has_packet_information(&self) -> bool { - self.packet_information - } - pub fn set_nonblock(&self) -> io::Result<()> { self.tun.set_nonblock() } diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index 28cd77f2..69e7fd62 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -43,6 +43,18 @@ pub struct Device { ctl: Option, } +impl AsRef + 'static> for Device { + fn as_ref(&self) -> &(dyn AbstractDevice + 'static) { + self + } +} + +impl AsMut + 'static> for Device { + fn as_mut(&mut self) -> &mut (dyn AbstractDevice + 'static) { + self + } +} + impl Device { /// Create a new `Device` for the given `Configuration`. pub fn new(config: &Configuration) -> Result { @@ -187,11 +199,6 @@ impl Device { (posix::Reader(fd.clone()), posix::Writer(fd)) } - /// Return whether the device has packet information - pub fn has_packet_information(&self) -> bool { - self.queue.has_packet_information() - } - /// Set non-blocking mode pub fn set_nonblock(&self) -> io::Result<()> { self.queue.set_nonblock() @@ -399,6 +406,11 @@ impl AbstractDevice for Device { Some(&mut self.queue) } + + fn packet_information(&self) -> bool { + // on macos this is always the case + true + } } impl AsRawFd for Device { @@ -418,11 +430,6 @@ pub struct Queue { } impl Queue { - pub fn has_packet_information(&self) -> bool { - // on macos this is always the case - true - } - pub fn set_nonblock(&self) -> io::Result<()> { self.tun.set_nonblock() } diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index 9b1b48cf..abfc1b4f 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -90,6 +90,18 @@ impl Write for Device { } } +impl AsRef + 'static> for Device { + fn as_ref(&self) -> &(dyn AbstractDevice + 'static) { + self + } +} + +impl AsMut + 'static> for Device { + fn as_mut(&mut self) -> &mut (dyn AbstractDevice + 'static) { + self + } +} + impl AbstractDevice for Device { type Queue = Queue; @@ -181,6 +193,10 @@ impl AbstractDevice for Device { fn queue(&mut self, _index: usize) -> Option<&mut Self::Queue> { Some(&mut self.queue) } + + fn packet_information(&self) -> bool { + false + } } pub struct Queue { From 32721c8c2d1ee40ccdb3a53a8519106e7e91199b Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 24 Jan 2024 01:11:05 +0800 Subject: [PATCH 44/44] MTU issues --- examples/read-async.rs | 13 ++++++++----- src/async/unix_device.rs | 4 ++-- src/async/win_device.rs | 4 ++-- src/codec.rs | 5 ++--- src/configuration.rs | 4 ++-- src/device.rs | 4 ++-- src/lib.rs | 7 +++++++ src/platform/android/device.rs | 4 ++-- src/platform/ios/device.rs | 4 ++-- src/platform/linux/device.rs | 8 ++++---- src/platform/macos/device.rs | 8 ++++---- src/platform/mod.rs | 4 ++-- src/platform/windows/device.rs | 10 +++++----- 13 files changed, 44 insertions(+), 35 deletions(-) diff --git a/examples/read-async.rs b/examples/read-async.rs index 16a1dcfc..ac482470 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -13,16 +13,16 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. use tokio::io::AsyncReadExt; +use tun2::AbstractDevice; #[tokio::main] -async fn main() { - const MTU: i32 = 1500; +async fn main() -> Result<(), Box> { let mut config = tun2::Configuration::default(); config .address((10, 0, 0, 1)) .netmask((255, 255, 255, 0)) - .mtu(MTU) + .mtu(tun2::DEFAULT_MTU) .up(); #[cfg(target_os = "linux")] @@ -31,11 +31,14 @@ async fn main() { config.apply_settings(true); }); - let mut dev = tun2::create_as_async(&config).unwrap(); - let mut buf: [u8; 1504] = [0u8; MTU as usize + 4]; + let mut dev = tun2::create_as_async(&config)?; + let size = dev.as_ref().mtu()? + tun2::PACKET_INFORMATION_LENGTH; + let mut buf = vec![0; size]; loop { if let Ok(len) = dev.read(&mut buf).await { println!("pkt: {:?}", &buf[..len]); } } + #[allow(unreachable_code)] + Ok(()) } diff --git a/src/async/unix_device.rs b/src/async/unix_device.rs index 696e8ac5..7a2d8bd8 100644 --- a/src/async/unix_device.rs +++ b/src/async/unix_device.rs @@ -55,10 +55,10 @@ impl AsyncDevice { /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) pub fn into_framed(self) -> Framed { let packet_information = self.as_ref().packet_information(); - let mtu = self.as_ref().mtu().unwrap_or(1504) as usize; + let mtu = self.as_ref().mtu().unwrap_or(crate::DEFAULT_MTU); let codec = TunPacketCodec::new(packet_information, mtu); // associate mtu with the capacity of ReadBuf - Framed::with_capacity(self, codec, mtu) + Framed::with_capacity(self, codec, mtu + crate::PACKET_INFORMATION_LENGTH) } } diff --git a/src/async/win_device.rs b/src/async/win_device.rs index c6a2a20a..b136e8a0 100644 --- a/src/async/win_device.rs +++ b/src/async/win_device.rs @@ -56,10 +56,10 @@ impl AsyncDevice { /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) pub fn into_framed(self) -> Framed { let packet_information = self.as_ref().packet_information(); - let mtu = self.as_ref().mtu().unwrap_or(u16::MAX as i32) as usize; + let mtu = self.as_ref().mtu().unwrap_or(crate::DEFAULT_MTU); let codec = TunPacketCodec::new(packet_information, mtu); // guarantee to avoid the mtu of wintun may far away larger than the default provided capacity of buff of Framed - Framed::with_capacity(self, codec, mtu) + Framed::with_capacity(self, codec, mtu + crate::PACKET_INFORMATION_LENGTH) } } diff --git a/src/codec.rs b/src/codec.rs index 8ca98ead..8d75f890 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -12,11 +12,10 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use crate::PACKET_INFORMATION_LENGTH; use bytes::{BufMut, Bytes, BytesMut}; use tokio_util::codec::{Decoder, Encoder}; -const PACKET_INFORMATION_LENGTH: usize = 4; - /// Infer the protocol based on the first nibble in the packet buffer. fn is_ipv6(buf: &[u8]) -> std::io::Result { use std::io::{Error, ErrorKind::InvalidData}; @@ -93,7 +92,7 @@ impl TunPacketCodec { /// Create a new `TunPacketCodec` specifying whether the underlying /// tunnel Device has enabled the packet information header. pub fn new(packet_information: bool, mtu: usize) -> TunPacketCodec { - let mtu = u16::try_from(mtu).unwrap_or(u16::MAX) as usize; + let mtu = u16::try_from(mtu).unwrap_or(crate::DEFAULT_MTU as u16) as usize; TunPacketCodec { packet_information, mtu, diff --git a/src/configuration.rs b/src/configuration.rs index d6f99306..af70c775 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -38,7 +38,7 @@ pub struct Configuration { pub(crate) destination: Option, pub(crate) broadcast: Option, pub(crate) netmask: Option, - pub(crate) mtu: Option, + pub(crate) mtu: Option, pub(crate) enabled: Option, pub(crate) layer: Option, pub(crate) queues: Option, @@ -91,7 +91,7 @@ impl Configuration { } /// Set the MTU. - pub fn mtu(&mut self, value: i32) -> &mut Self { + pub fn mtu(&mut self, value: usize) -> &mut Self { // mtu on windows platform is always 65535 due to wintun if cfg!(target_family = "unix") { self.mtu = Some(value); diff --git a/src/device.rs b/src/device.rs index 185ceb3c..d89c98d1 100644 --- a/src/device.rs +++ b/src/device.rs @@ -84,10 +84,10 @@ pub trait AbstractDevice: Read + Write { fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()>; /// Get the MTU. - fn mtu(&self) -> Result; + fn mtu(&self) -> Result; /// Set the MTU. - fn set_mtu(&mut self, value: i32) -> Result<()>; + fn set_mtu(&mut self, value: usize) -> Result<()>; /// Get a device queue. fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>; diff --git a/src/lib.rs b/src/lib.rs index d885f04f..bc3afda9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,3 +38,10 @@ pub use r#async::*; pub fn configure() -> Configuration { Configuration::default() } + +#[cfg(unix)] +pub const DEFAULT_MTU: usize = 1500; +#[cfg(windows)] +pub const DEFAULT_MTU: usize = 0xFFFF; // 65535 + +pub const PACKET_INFORMATION_LENGTH: usize = 4; diff --git a/src/platform/android/device.rs b/src/platform/android/device.rs index 29f9f155..14d55ef1 100644 --- a/src/platform/android/device.rs +++ b/src/platform/android/device.rs @@ -141,11 +141,11 @@ impl AbstractDevice for Device { Ok(()) } - fn mtu(&self) -> Result { + fn mtu(&self) -> Result { Err(Error::NotImplemented) } - fn set_mtu(&mut self, value: i32) -> Result<()> { + fn set_mtu(&mut self, value: usize) -> Result<()> { Ok(()) } diff --git a/src/platform/ios/device.rs b/src/platform/ios/device.rs index f26d590f..bfaad3e1 100644 --- a/src/platform/ios/device.rs +++ b/src/platform/ios/device.rs @@ -144,11 +144,11 @@ impl AbstractDevice for Device { Ok(()) } - fn mtu(&self) -> Result { + fn mtu(&self) -> Result { Err(Error::NotImplemented) } - fn set_mtu(&mut self, value: i32) -> Result<()> { + fn set_mtu(&mut self, value: usize) -> Result<()> { Ok(()) } diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index 5771d300..d720b6fa 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -365,7 +365,7 @@ impl AbstractDevice for Device { } } - fn mtu(&self) -> Result { + fn mtu(&self) -> Result { unsafe { let mut req = self.request(); @@ -373,14 +373,14 @@ impl AbstractDevice for Device { return Err(io::Error::last_os_error().into()); } - Ok(req.ifr_ifru.ifru_mtu) + Ok(req.ifr_ifru.ifru_mtu as usize) } } - fn set_mtu(&mut self, value: i32) -> Result<()> { + fn set_mtu(&mut self, value: usize) -> Result<()> { unsafe { let mut req = self.request(); - req.ifr_ifru.ifru_mtu = value; + req.ifr_ifru.ifru_mtu = value as i32; if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index 69e7fd62..d1c84b63 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -372,7 +372,7 @@ impl AbstractDevice for Device { } } - fn mtu(&self) -> Result { + fn mtu(&self) -> Result { let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { let mut req = self.request()?; @@ -381,15 +381,15 @@ impl AbstractDevice for Device { return Err(io::Error::last_os_error().into()); } - Ok(req.ifr_ifru.ifru_mtu) + Ok(req.ifr_ifru.ifru_mtu as usize) } } - fn set_mtu(&mut self, value: i32) -> Result<()> { + fn set_mtu(&mut self, value: usize) -> Result<()> { let ctl = self.ctl.as_ref().ok_or(Error::InvalidConfig)?; unsafe { let mut req = self.request()?; - req.ifr_ifru.ifru_mtu = value; + req.ifr_ifru.ifru_mtu = value as i32; if siocsifmtu(ctl.as_raw_fd(), &req) < 0 { return Err(io::Error::last_os_error().into()); diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 5d8d3b25..72ad4cc4 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -55,7 +55,7 @@ mod test { .name("utun6") .address("192.168.50.1") .netmask("255.255.0.0") - .mtu(1400) + .mtu(crate::DEFAULT_MTU) .up(), ) .unwrap(); @@ -70,6 +70,6 @@ mod test { dev.netmask().unwrap() ); - assert_eq!(1400, dev.mtu().unwrap()); + assert_eq!(crate::DEFAULT_MTU, dev.mtu().unwrap()); } } diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index abfc1b4f..f720cb7f 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -43,7 +43,7 @@ impl Device { let mask = config.netmask.unwrap_or(Ipv4Addr::new(255, 255, 255, 0)); let gateway = config.destination.map(IpAddr::from); adapter.set_network_addresses_tuple(IpAddr::V4(address), IpAddr::V4(mask), gateway)?; - let mtu = config.mtu.unwrap_or(u16::MAX as i32) as usize; + let mtu = config.mtu.unwrap_or(crate::DEFAULT_MTU); let session = adapter.start_session(wintun::MAX_RING_CAPACITY)?; @@ -181,12 +181,12 @@ impl AbstractDevice for Device { Ok(()) } - fn mtu(&self) -> Result { - Ok(self.mtu as i32) + fn mtu(&self) -> Result { + Ok(self.mtu) } - fn set_mtu(&mut self, value: i32) -> Result<()> { - self.mtu = value as usize; + fn set_mtu(&mut self, value: usize) -> Result<()> { + self.mtu = value; Ok(()) }