From beae8c0f791cee5cdb7f9a114b3c0510eb5a6b26 Mon Sep 17 00:00:00 2001 From: JettChenT Date: Mon, 19 Jun 2023 22:45:25 +0800 Subject: [PATCH] Add Read and Write for Async TunInterface Those features are implemented using AsyncFD. While write doesn't require a mutable reference to self, read does. Make Async Tun a feature remove async tun from workspace rename write/read to send/recv --- .vscode/settings.json | 2 +- Cargo.lock | 62 +++++++++++++++++++++++++++++++++------ Cargo.toml | 2 +- tun-async/Cargo.toml | 9 ------ tun-async/src/lib.rs | 14 --------- tun/Cargo.toml | 8 +++++ tun/src/lib.rs | 4 +++ tun/src/tokio/mod.rs | 58 ++++++++++++++++++++++++++++++++++++ tun/src/unix/apple/mod.rs | 15 ++-------- tun/src/unix/linux/mod.rs | 8 +---- tun/src/unix/mod.rs | 14 +++------ tun/tests/configure.rs | 3 +- 12 files changed, 135 insertions(+), 64 deletions(-) delete mode 100644 tun-async/Cargo.toml delete mode 100644 tun-async/src/lib.rs create mode 100644 tun/src/tokio/mod.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 649e121..887fb70 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,5 +19,5 @@ ], "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer", - }, + } } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 59691cf..146bbc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -482,6 +482,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -489,6 +504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -497,6 +513,34 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -515,10 +559,16 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -1383,9 +1433,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -1472,6 +1522,7 @@ dependencies = [ "bindgen", "byteorder", "fehler", + "futures", "lazy_static", "libc", "libloading", @@ -1487,13 +1538,6 @@ dependencies = [ "zip", ] -[[package]] -name = "tun-async" -version = "0.1.0" -dependencies = [ - "tun", -] - [[package]] name = "typenum" version = "1.16.0" diff --git a/Cargo.toml b/Cargo.toml index bb03a92..fcb83f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["burrow", "tun-async", "tun"] +members = ["burrow", "tun"] diff --git a/tun-async/Cargo.toml b/tun-async/Cargo.toml deleted file mode 100644 index e011ca4..0000000 --- a/tun-async/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tun-async" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -tun = { version = "0.1", path = "../tun" } diff --git a/tun-async/src/lib.rs b/tun-async/src/lib.rs deleted file mode 100644 index 7d12d9a..0000000 --- a/tun-async/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/tun/Cargo.toml b/tun/Cargo.toml index 71579a3..79b2735 100644 --- a/tun/Cargo.toml +++ b/tun/Cargo.toml @@ -12,6 +12,14 @@ tokio = { version = "1.28", features = [] } byteorder = "1.4" log = "0.4" +futures = { version = "0.3.28", optional = true } + +[features] +tokio = ["tokio/net", "dep:futures"] + +[target.'cfg(feature = "tokio")'.dev-dependencies] +tokio = { features = ["rt", "macros"] } + [target.'cfg(windows)'.dependencies] lazy_static = "1.4" libloading = "0.7" diff --git a/tun/src/lib.rs b/tun/src/lib.rs index c05fca9..f0c0a6e 100644 --- a/tun/src/lib.rs +++ b/tun/src/lib.rs @@ -8,5 +8,9 @@ pub(crate) mod imp; mod options; +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +#[cfg(feature = "tokio")] +pub mod tokio; + pub use imp::{TunInterface, TunQueue}; pub use options::TunOptions; diff --git a/tun/src/tokio/mod.rs b/tun/src/tokio/mod.rs new file mode 100644 index 0000000..674dfe6 --- /dev/null +++ b/tun/src/tokio/mod.rs @@ -0,0 +1,58 @@ +use std::io; +use tokio::io::unix::AsyncFd; + +pub struct TunInterface { + inner: AsyncFd, +} + +impl TunInterface { + pub fn new(tun: crate::TunInterface) -> io::Result { + Ok(Self { + inner: AsyncFd::new(tun)?, + }) + } + + pub async fn write(&self, buf: &[u8]) -> io::Result { + loop { + let mut guard = self.inner.writable().await?; + match guard.try_io(|inner| inner.get_ref().send(buf)) { + Ok(result) => return result, + Err(_would_block) => continue, + } + } + } + + pub async fn read(&mut self, buf: &mut [u8]) -> io::Result { + loop { + let mut guard = self.inner.readable_mut().await?; + match guard.try_io(|inner| (*inner).get_mut().recv(buf)) { + Ok(result) => return result, + Err(_would_block) => continue, + } + } + } +} + +#[cfg(test)] +mod tests { + use std::net::Ipv4Addr; + + use super::*; + #[tokio::test] + async fn test_create() { + let tun = crate::TunInterface::new().unwrap(); + let _async_tun = TunInterface::new(tun).unwrap(); + } + + #[tokio::test] + async fn test_write() { + let tun = crate::TunInterface::new().unwrap(); + tun.set_ipv4_addr(Ipv4Addr::from([192, 168, 1, 10])) + .unwrap(); + let async_tun = TunInterface::new(tun).unwrap(); + let mut buf = [0u8; 1500]; + buf[0] = 6 << 4; + let bytes_written = async_tun.write(&buf).await.unwrap(); + assert!(bytes_written > 0); + } +} diff --git a/tun/src/unix/apple/mod.rs b/tun/src/unix/apple/mod.rs index a82ceb9..2da4644 100644 --- a/tun/src/unix/apple/mod.rs +++ b/tun/src/unix/apple/mod.rs @@ -2,13 +2,10 @@ use byteorder::{ByteOrder, NetworkEndian}; use fehler::throws; use libc::{c_char, iovec, writev, AF_INET, AF_INET6}; use socket2::{Domain, SockAddr, Socket, Type}; -use std::io::{IoSlice, Write}; +use std::io::IoSlice; use std::net::{Ipv4Addr, SocketAddrV4}; use std::os::fd::{AsRawFd, RawFd}; -use std::{ - io::{Error}, - mem, -}; +use std::{io::Error, mem}; mod kern_control; mod sys; @@ -130,11 +127,9 @@ impl TunInterface { self.perform(|fd| unsafe { sys::if_set_netmask(fd, &iff) })?; } -} -impl Write for TunInterface { #[throws] - fn write(&mut self, buf: &[u8]) -> usize { + pub fn send(&self, buf: &[u8]) -> usize { use std::io::ErrorKind; let proto = match buf[0] >> 4 { 6 => Ok(AF_INET6), @@ -156,10 +151,6 @@ impl Write for TunInterface { .try_into() .map_err(|_| Error::new(ErrorKind::Other, "Conversion error"))? } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } } #[cfg(test)] diff --git a/tun/src/unix/linux/mod.rs b/tun/src/unix/linux/mod.rs index cd3e4c0..abc1ccd 100644 --- a/tun/src/unix/linux/mod.rs +++ b/tun/src/unix/linux/mod.rs @@ -166,17 +166,11 @@ impl TunInterface { let socket = Socket::new(Domain::IPV6, Type::DGRAM, None)?; perform(socket.as_raw_fd())? } -} -impl Write for TunInterface { #[throws] - fn write(&mut self, buf: &[u8]) -> usize { + pub fn send(&self, buf: &[u8]) -> usize { self.socket.send(buf)? } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } } #[cfg(test)] diff --git a/tun/src/unix/mod.rs b/tun/src/unix/mod.rs index 550df4d..af67d39 100644 --- a/tun/src/unix/mod.rs +++ b/tun/src/unix/mod.rs @@ -40,13 +40,8 @@ impl IntoRawFd for TunInterface { } impl TunInterface { - // #[throws] - // pub fn write(&self, buf: &[u8]) -> usize { - // self.socket.send(buf)? - // } - #[throws] - pub fn read(&mut self, buf: &mut [u8]) -> usize { + pub fn recv(&mut self, buf: &mut [u8]) -> usize { self.socket.read(buf)? } } @@ -72,7 +67,6 @@ pub fn string_to_ifname(name: &str) -> [libc::c_char; libc::IFNAMSIZ] { mod test { use super::*; - use std::io::Write; use std::net::Ipv4Addr; @@ -88,7 +82,7 @@ mod test { println!("tun ip: {:?}", tun.ipv4_addr()?); println!("Waiting for a packet..."); let buf = &mut [0u8; 1500]; - let res = tun.read(buf); + let res = tun.recv(buf); println!("Received!"); assert!(res.is_ok()); } @@ -96,10 +90,10 @@ mod test { #[test] #[throws] fn write_packets() { - let mut tun = TunInterface::new()?; + let tun = TunInterface::new()?; let mut buf = [0u8; 1500]; buf[0] = 6 << 4; - let bytes_written = tun.write(&buf)?; + let bytes_written = tun.send(&buf)?; assert_eq!(bytes_written, 1504); } } diff --git a/tun/tests/configure.rs b/tun/tests/configure.rs index 05e5ef6..48ddd96 100644 --- a/tun/tests/configure.rs +++ b/tun/tests/configure.rs @@ -1,6 +1,6 @@ use fehler::throws; use std::io::Error; -use std::net::{Ipv4Addr, Ipv6Addr}; +use std::net::{Ipv4Addr}; use tun::TunInterface; #[test] @@ -23,6 +23,7 @@ fn test_set_get_ipv4() { #[test] #[throws] +#[cfg(target_os = "linux")] fn test_set_get_ipv6() { let tun = TunInterface::new()?;