From bbb8d3b24443fce148b15705de95a994716ff215 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:31:02 +0800 Subject: [PATCH] port to windows or macos (#61) --- .github/workflows/format-build.yml | 5 ++- Cargo.toml | 4 +- src/error.rs | 1 + src/lib.rs | 1 + src/main.rs | 8 +++- src/tun2proxy.rs | 59 ++++++++++++++++++++++++++---- src/virtdns.rs | 2 + tests/proxy.rs | 1 + 8 files changed, 69 insertions(+), 12 deletions(-) diff --git a/.github/workflows/format-build.yml b/.github/workflows/format-build.yml index 3079be2..9b76859 100644 --- a/.github/workflows/format-build.yml +++ b/.github/workflows/format-build.yml @@ -35,7 +35,10 @@ jobs: clippy: name: Clippy - runs-on: ubuntu-latest + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 diff --git a/Cargo.toml b/Cargo.toml index 43b2b85..4ca6380 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ ctrlc = "3.4" digest_auth = "0.3" dotenvy = "0.15" env_logger = "0.10" -fork = "0.1" hashlink = "0.8" httparse = "1.8" libc = "0.2" @@ -29,6 +28,9 @@ trust-dns-proto = "0.23" unicase = "2.7" url = "2.4" +[target.'cfg(target_family="unix")'.dependencies] +fork = "0.1" + [target.'cfg(target_os="android")'.dependencies] android_logger = "0.13" jni = { version = "0.21", default-features = false } diff --git a/src/error.rs b/src/error.rs index d45f0ee..18c625d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -52,6 +52,7 @@ pub enum Error { #[error("{0}")] String(String), + #[cfg(target_family = "unix")] #[error("nix::errno::Errno {0:?}")] OSError(#[from] nix::errno::Errno), diff --git a/src/lib.rs b/src/lib.rs index 0b77eb0..eac2bbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ pub struct Proxy { pub enum NetworkInterface { Named(String), + #[cfg(target_family = "unix")] Fd(std::os::fd::RawFd), } diff --git a/src/main.rs b/src/main.rs index 84ec63b..e579f06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,11 +95,15 @@ fn main() -> ExitCode { options = options.with_ipv6_enabled(); } + #[allow(unused_assignments)] let interface = match args.tun_fd { None => NetworkInterface::Named(args.tun.clone()), - Some(fd) => { + Some(_fd) => { options = options.with_mtu(args.tun_mtu); - NetworkInterface::Fd(fd) + #[cfg(not(target_family = "unix"))] + panic!("Not supported"); + #[cfg(target_family = "unix")] + NetworkInterface::Fd(_fd) } }; diff --git a/src/tun2proxy.rs b/src/tun2proxy.rs index ecdc62b..88c6fbc 100644 --- a/src/tun2proxy.rs +++ b/src/tun2proxy.rs @@ -1,20 +1,32 @@ +#![allow(dead_code)] + use crate::{dns, error::Error, error::Result, virtdevice::VirtualTunDevice, NetworkInterface, Options}; -use mio::{event::Event, net::TcpStream, net::UdpSocket, unix::SourceFd, Events, Interest, Poll, Token}; +#[cfg(target_family = "unix")] +use mio::unix::SourceFd; +use mio::{event::Event, net::TcpStream, net::UdpSocket, Events, Interest, Poll, Token}; +#[cfg(not(target_family = "unix"))] +use smoltcp::phy::DeviceCapabilities; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use smoltcp::phy::RawSocket; +#[cfg(any(target_os = "linux", target_os = "android"))] +use smoltcp::phy::TunTapInterface; +#[cfg(target_family = "unix")] +use smoltcp::phy::{Device, Medium, RxToken, TxToken}; use smoltcp::{ iface::{Config, Interface, SocketHandle, SocketSet}, - phy::{Device, Medium, RxToken, TunTapInterface, TxToken}, socket::{tcp, tcp::State, udp, udp::UdpMetadata}, time::Instant, wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket, UDP_HEADER_LEN}, }; use socks5_impl::protocol::{Address, StreamOperation, UdpHeader, UserKey}; use std::collections::LinkedList; +#[cfg(target_family = "unix")] +use std::os::unix::io::AsRawFd; use std::{ collections::{HashMap, HashSet}, convert::{From, TryFrom}, io::{Read, Write}, net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}, - os::unix::io::AsRawFd, rc::Rc, str::FromStr, }; @@ -208,7 +220,10 @@ const TUN_TOKEN: Token = Token(0); const EXIT_TOKEN: Token = Token(2); pub struct TunToProxy<'a> { + #[cfg(any(target_os = "linux", target_os = "android"))] tun: TunTapInterface, + #[cfg(any(target_os = "macos", target_os = "ios"))] + tun: RawSocket, poll: Poll, iface: Interface, connection_map: HashMap, @@ -218,31 +233,53 @@ pub struct TunToProxy<'a> { device: VirtualTunDevice, options: Options, write_sockets: HashSet, + #[cfg(target_family = "unix")] _exit_receiver: mio::unix::pipe::Receiver, + #[cfg(target_family = "unix")] exit_sender: mio::unix::pipe::Sender, } impl<'a> TunToProxy<'a> { - pub fn new(interface: &NetworkInterface, options: Options) -> Result { - let tun = match interface { + pub fn new(_interface: &NetworkInterface, options: Options) -> Result { + #[cfg(any(target_os = "linux", target_os = "android"))] + let tun = match _interface { NetworkInterface::Named(name) => TunTapInterface::new(name.as_str(), Medium::Ip)?, NetworkInterface::Fd(fd) => TunTapInterface::from_fd(*fd, Medium::Ip, options.mtu.unwrap_or(1500))?, }; + + #[cfg(any(target_os = "macos", target_os = "ios"))] + let tun = match _interface { + NetworkInterface::Named(name) => RawSocket::new(name.as_str(), Medium::Ip)?, + NetworkInterface::Fd(_fd) => panic!("Not supported"), + }; + let poll = Poll::new()?; + + #[cfg(target_family = "unix")] poll.registry() .register(&mut SourceFd(&tun.as_raw_fd()), TUN_TOKEN, Interest::READABLE)?; + #[cfg(target_family = "unix")] let (exit_sender, mut exit_receiver) = mio::unix::pipe::new()?; + #[cfg(target_family = "unix")] poll.registry() .register(&mut exit_receiver, EXIT_TOKEN, Interest::READABLE)?; + #[cfg(target_family = "unix")] #[rustfmt::skip] let config = match tun.capabilities().medium { Medium::Ethernet => Config::new(smoltcp::wire::EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into()), Medium::Ip => Config::new(smoltcp::wire::HardwareAddress::Ip), Medium::Ieee802154 => todo!(), }; + #[cfg(not(target_family = "unix"))] + let config = Config::new(smoltcp::wire::HardwareAddress::Ip); + + #[cfg(target_family = "unix")] let mut device = VirtualTunDevice::new(tun.capabilities()); + #[cfg(not(target_family = "unix"))] + let mut device = VirtualTunDevice::new(DeviceCapabilities::default()); + let gateway4: Ipv4Addr = Ipv4Addr::from_str("0.0.0.1")?; let gateway6: Ipv6Addr = Ipv6Addr::from_str("::1")?; let mut iface = Interface::new(config, &mut device, Instant::now()); @@ -255,6 +292,7 @@ impl<'a> TunToProxy<'a> { iface.set_any_ip(true); let tun = Self { + #[cfg(target_family = "unix")] tun, poll, iface, @@ -265,7 +303,9 @@ impl<'a> TunToProxy<'a> { device, options, write_sockets: HashSet::default(), + #[cfg(target_family = "unix")] _exit_receiver: exit_receiver, + #[cfg(target_family = "unix")] exit_sender, }; Ok(tun) @@ -286,14 +326,15 @@ impl<'a> TunToProxy<'a> { self.iface.poll(Instant::now(), &mut self.device, &mut self.sockets); while let Some(vec) = self.device.exfiltrate_packet() { - let slice = vec.as_slice(); + let _slice = vec.as_slice(); // TODO: Actual write. Replace. + #[cfg(target_family = "unix")] self.tun .transmit(Instant::now()) .ok_or("tx token not available")? - .consume(slice.len(), |buf| { - buf[..].clone_from_slice(slice); + .consume(_slice.len(), |buf| { + buf[..].clone_from_slice(_slice); }); } Ok(()) @@ -892,6 +933,7 @@ impl<'a> TunToProxy<'a> { fn tun_event(&mut self, event: &Event) -> Result<(), Error> { if event.is_readable() { + #[cfg(target_family = "unix")] while let Some((rx_token, _)) = self.tun.receive(Instant::now()) { rx_token.consume(|frame| self.receive_tun(frame))?; } @@ -1098,6 +1140,7 @@ impl<'a> TunToProxy<'a> { } pub fn shutdown(&mut self) -> Result<(), Error> { + #[cfg(target_family = "unix")] self.exit_sender.write_all(&[1])?; Ok(()) } diff --git a/src/virtdns.rs b/src/virtdns.rs index 148b45c..eaed24b 100644 --- a/src/virtdns.rs +++ b/src/virtdns.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use crate::error::Result; use hashlink::{linked_hash_map::RawEntryMut, LruCache}; use smoltcp::wire::Ipv4Cidr; diff --git a/tests/proxy.rs b/tests/proxy.rs index a7274a2..3ced894 100644 --- a/tests/proxy.rs +++ b/tests/proxy.rs @@ -1,3 +1,4 @@ +#[cfg(target_os = "linux")] #[cfg(test)] mod tests { extern crate reqwest;