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 1/7] 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; From 0044756f78a1d8e3bc4c100a3e21e8bd1f1b01ca Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:59:07 +0800 Subject: [PATCH 2/7] --dns-addr option --- README.md | 4 +--- src/lib.rs | 6 ++++++ src/main.rs | 31 ++++++++++++++++++++----------- src/tun2proxy.rs | 2 +- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 4b89238..09981ec 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A tunnel interface for HTTP and SOCKS proxies on Linux based on [smoltcp](https: - IPv4 and IPv6 support - GFW evasion mechanism for certain use cases (see [issue #35](https://github.com/blechschmidt/tun2proxy/issues/35)) - SOCKS5 UDP support +- Native support for proxying DNS over TCP ## Build Clone the repository and `cd` into the project folder. Then run the following: @@ -122,6 +123,3 @@ asked to open connections to IPv6 destinations. In such a case, you can disable either through `sysctl -w net.ipv6.conf.all.disable_ipv6=1` and `sysctl -w net.ipv6.conf.default.disable_ipv6=1` or through `ip -6 route del default`, which causes the `libc` resolver (and other software) to not issue DNS AAAA requests for IPv6 addresses. - -## TODO -- Native support for proxying DNS over TCP or TLS diff --git a/src/lib.rs b/src/lib.rs index eac2bbf..4cbffa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,6 +100,7 @@ pub struct Options { virtual_dns: Option, mtu: Option, dns_over_tcp: bool, + dns_addr: Option, ipv6_enabled: bool, } @@ -120,6 +121,11 @@ impl Options { self } + pub fn with_dns_addr(mut self, addr: Option) -> Self { + self.dns_addr = addr; + self + } + pub fn with_ipv6_enabled(mut self) -> Self { self.ipv6_enabled = true; self diff --git a/src/main.rs b/src/main.rs index e579f06..c513d1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,13 +25,13 @@ struct Args { #[arg(short, long, value_parser = Proxy::from_url, value_name = "URL")] proxy: Proxy, - /// DNS handling - #[arg(short, long, value_name = "method", value_enum, default_value = "virtual")] + /// DNS handling strategy + #[arg(short, long, value_name = "strategy", value_enum, default_value = "virtual")] dns: ArgDns, - /// Enable DNS over TCP - #[arg(long)] - dns_over_tcp: bool, + /// DNS resolver address + #[arg(long, value_name = "IP", default_value = "8.8.8.8")] + dns_addr: IpAddr, /// IPv6 enabled #[arg(short = '6', long)] @@ -50,10 +50,15 @@ struct Args { verbosity: ArgVerbosity, } +/// DNS query handling strategy +/// - Virtual: Intercept DNS queries and resolve them locally with a fake IP address +/// - OverTcp: Use TCP to send DNS queries to the DNS server +/// - Direct: Looks as general UDP traffic but change the destination to the DNS server #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] enum ArgDns { Virtual, - None, + OverTcp, + Direct, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] @@ -83,13 +88,17 @@ fn main() -> ExitCode { log::info!("Proxy {proxy_type} server: {addr}"); let mut options = Options::new(); - if args.dns == ArgDns::Virtual { - options = options.with_virtual_dns(); + match args.dns { + ArgDns::Virtual => { + options = options.with_virtual_dns(); + } + ArgDns::OverTcp => { + options = options.with_dns_over_tcp(); + } + _ => {} } - if args.dns_over_tcp { - options = options.with_dns_over_tcp(); - } + options = options.with_dns_addr(Some(args.dns_addr)); if args.ipv6_enabled { options = options.with_ipv6_enabled(); diff --git a/src/tun2proxy.rs b/src/tun2proxy.rs index 88c6fbc..b540053 100644 --- a/src/tun2proxy.rs +++ b/src/tun2proxy.rs @@ -505,7 +505,7 @@ impl<'a> TunToProxy<'a> { let mut info = info; let port = origin_dst.port(); if port == DNS_PORT && info.protocol == IpProtocol::Udp && dns::addr_is_private(&origin_dst) { - let dns_addr: SocketAddr = "8.8.8.8:53".parse()?; // TODO: Configurable + let dns_addr: SocketAddr = (self.options.dns_addr.ok_or("dns_addr")?, DNS_PORT).into(); info.dst = Address::from(dns_addr); } info From abcff395d83747b1b607d602e9c37d1f7da65647 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:11:35 +0800 Subject: [PATCH 3/7] Bump version 0.1.6 --- Cargo.toml | 6 +++--- README.md | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4ca6380..d86b722 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] authors = ["B. Blechschmidt"] -edition = "2018" +edition = "2021" name = "tun2proxy" -version = "0.1.5" +version = "0.1.6" [lib] crate-type = ["cdylib", "lib"] @@ -19,7 +19,7 @@ httparse = "1.8" libc = "0.2" log = "0.4" mio = { version = "0.8", features = ["os-poll", "net", "os-ext"] } -nix = { version = "0.26", features = ["process", "signal"] } +nix = { version = "0.27", features = ["process", "signal"] } prctl = "1.0" smoltcp = { version = "0.10", features = ["std", "phy-tuntap_interface"] } socks5-impl = { version = "0.5", default-features = false } diff --git a/README.md b/README.md index 09981ec..4b245e0 100644 --- a/README.md +++ b/README.md @@ -91,13 +91,18 @@ Tunnel interface to proxy. Usage: tun2proxy [OPTIONS] --proxy Options: - -t, --tun Name of the tun interface [default: tun0] - -p, --proxy Proxy URL in the form proto://[username[:password]@]host:port - -d, --dns DNS handling [default: virtual] [possible values: virtual, none] - -s, --setup Routing and system setup [possible values: auto] - --bypass-ip Public proxy IP used in routing setup which should bypassing the tunnel - -h, --help Print help - -V, --version Print version + -t, --tun Name of the tun interface [default: tun0] + --tun-fd File descriptor of the tun interface + --tun-mtu MTU of the tun interface (only with tunnel file descriptor) [default: 1500] + -p, --proxy Proxy URL in the form proto://[username[:password]@]host:port + -d, --dns DNS handling strategy [default: virtual] [possible values: virtual, over-tcp, direct] + --dns-addr DNS resolver address [default: 8.8.8.8] + -6, --ipv6-enabled IPv6 enabled + -s, --setup Routing and system setup [possible values: auto] + --bypass-ip Public proxy IP used in routing setup which should bypassing the tunnel + -v, --verbosity Verbosity level [default: info] [possible values: off, error, warn, info, debug, trace] + -h, --help Print help + -V, --version Print version ``` Currently, tun2proxy supports HTTP, SOCKS4/SOCKS4a and SOCKS5. A proxy is supplied to the `--proxy` argument in the URL format. For example, an HTTP proxy at `1.2.3.4:3128` with a username of `john.doe` and a password of `secret` is From a17d9587d67127a305a81faba0f083d05501ef71 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:35:37 +0800 Subject: [PATCH 4/7] dependencies issues --- Cargo.toml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d86b722..4422225 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib", "lib"] [dependencies] base64 = { version = "0.21" } -clap = { version = "4.3", features = ["derive"] } +clap = { version = "4.4", features = ["derive"] } ctrlc = "3.4" digest_auth = "0.3" dotenvy = "0.15" @@ -19,7 +19,13 @@ httparse = "1.8" libc = "0.2" log = "0.4" mio = { version = "0.8", features = ["os-poll", "net", "os-ext"] } -nix = { version = "0.27", features = ["process", "signal"] } +nix = { version = "0.27", features = [ + "process", + "signal", + "fs", + "mount", + "user", +] } prctl = "1.0" smoltcp = { version = "0.10", features = ["std", "phy-tuntap_interface"] } socks5-impl = { version = "0.5", default-features = false } From 0e3b45be4a3ae64042f55a7947233956b8c18918 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:54:28 -0400 Subject: [PATCH 5/7] Publish script --- .github/workflows/format-build.yml | 2 + .github/workflows/install-cross.sh | 11 ++++ .github/workflows/publish-exe.yml | 81 ++++++++++++++++++++++++------ 3 files changed, 78 insertions(+), 16 deletions(-) create mode 100755 .github/workflows/install-cross.sh diff --git a/.github/workflows/format-build.yml b/.github/workflows/format-build.yml index 9b76859..6fefc0f 100644 --- a/.github/workflows/format-build.yml +++ b/.github/workflows/format-build.yml @@ -51,3 +51,5 @@ jobs: with: command: clippy args: -- -D warnings + - name: Build + run: cargo build --verbose diff --git a/.github/workflows/install-cross.sh b/.github/workflows/install-cross.sh new file mode 100755 index 0000000..95b5c04 --- /dev/null +++ b/.github/workflows/install-cross.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +curl -s https://api.github.com/repos/cross-rs/cross/releases/latest \ + | grep cross-x86_64-unknown-linux-gnu.tar.gz \ + | cut -d : -f 2,3 \ + | tr -d \" \ + | wget -qi - + +tar -zxvf cross-x86_64-unknown-linux-gnu.tar.gz -C /usr/bin +rm -f cross-x86_64-unknown-linux-gnu.tar.gz + diff --git a/.github/workflows/publish-exe.yml b/.github/workflows/publish-exe.yml index 8b19a38..c376706 100644 --- a/.github/workflows/publish-exe.yml +++ b/.github/workflows/publish-exe.yml @@ -3,28 +3,77 @@ on: tags: - "*" -name: Build and publish executable +name: Publish Releases jobs: build_publish: - name: Build and publish executable - runs-on: ubuntu-latest + name: Publishing Tasks + strategy: + matrix: + target: + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + - i686-unknown-linux-musl + - aarch64-unknown-linux-gnu + - armv7-unknown-linux-gnueabihf + - x86_64-apple-darwin + - aarch64-apple-darwin + - x86_64-pc-windows-msvc + - i686-pc-windows-msvc + + include: + - target: x86_64-unknown-linux-gnu + host_os: ubuntu-latest + - target: x86_64-unknown-linux-musl + host_os: ubuntu-latest + - target: i686-unknown-linux-musl + host_os: ubuntu-latest + - target: aarch64-unknown-linux-gnu + host_os: ubuntu-latest + - target: armv7-unknown-linux-gnueabihf + host_os: ubuntu-latest + - target: x86_64-apple-darwin + host_os: macos-latest + - target: aarch64-apple-darwin + host_os: macos-latest + - target: x86_64-pc-windows-msvc + host_os: windows-latest + - target: i686-pc-windows-msvc + host_os: windows-latest + + runs-on: ${{ matrix.host_os }} steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: build - args: --release --target x86_64-unknown-linux-gnu - - name: Rename - run: mkdir build && mv target/x86_64-unknown-linux-gnu/release/tun2proxy build/tun2proxy-x86_64 + - uses: actions/checkout@v3 + + - name: Prepare + shell: bash + run: | + mkdir publishdir + rustup target add ${{ matrix.target }} + if [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then + sudo .github/workflows/install-cross.sh + fi + + - name: Build + shell: bash + run: | + if [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then + cross build --all-features --release --target ${{ matrix.target }} + else + cargo build --all-features --release --target ${{ matrix.target }} + fi + if [[ "${{ matrix.host_os }}" == "windows-latest" ]]; then + powershell Compress-Archive -Path target/${{ matrix.target }}/release/tun2proxy.exe -DestinationPath publishdir/tun2proxy-${{ matrix.target }}.zip + elif [[ "${{ matrix.host_os }}" == "macos-latest" ]]; then + zip -j publishdir/tun2proxy-${{ matrix.target }}.zip target/${{ matrix.target }}/release/tun2proxy + elif [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then + zip -j publishdir/tun2proxy-${{ matrix.target }}.zip target/${{ matrix.target }}/release/tun2proxy + fi + - name: Publish uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - files: build/* + files: publishdir/* + From 11995d525b3ca553b757229e0aea6b303c7aec2e Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:17:12 +0800 Subject: [PATCH 6/7] dns_over_tcp_expiry --- src/tun2proxy.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/tun2proxy.rs b/src/tun2proxy.rs index b540053..4753180 100644 --- a/src/tun2proxy.rs +++ b/src/tun2proxy.rs @@ -195,7 +195,7 @@ struct ConnectionState { udp_token: Option, origin_dst: SocketAddr, udp_data_cache: LinkedList>, - udp_over_tcp_expiry: Option<::std::time::Instant>, + dns_over_tcp_expiry: Option<::std::time::Instant>, } pub(crate) trait TcpProxy { @@ -555,7 +555,7 @@ impl<'a> TunToProxy<'a> { let err = "udp over tcp state not find"; let state = self.connection_map.get_mut(info).ok_or(err)?; - state.udp_over_tcp_expiry = Some(Self::common_udp_life_timeout()); + state.dns_over_tcp_expiry = Some(Self::common_udp_life_timeout()); let data_event = IncomingDataEvent { direction: IncomingDirection::FromClient, @@ -568,8 +568,8 @@ impl<'a> TunToProxy<'a> { fn receive_dns_over_tcp_packet_and_write_to_client(&mut self, info: &ConnectionInfo) -> Result<()> { let err = "udp connection state not found"; let state = self.connection_map.get_mut(info).ok_or(err)?; - assert!(state.udp_over_tcp_expiry.is_some()); - state.udp_over_tcp_expiry = Some(Self::common_udp_life_timeout()); + assert!(state.dns_over_tcp_expiry.is_some()); + state.dns_over_tcp_expiry = Some(Self::common_udp_life_timeout()); // Code similar to the code in parent function. TODO: Cleanup. let mut vecbuf = Vec::::new(); @@ -638,9 +638,9 @@ impl<'a> TunToProxy<'a> { Ok(()) } - fn udp_over_tcp_timeout_expired(&self, info: &ConnectionInfo) -> bool { + fn dns_over_tcp_timeout_expired(&self, info: &ConnectionInfo) -> bool { if let Some(state) = self.connection_map.get(info) { - if let Some(expiry) = state.udp_over_tcp_expiry { + if let Some(expiry) = state.dns_over_tcp_expiry { return expiry < ::std::time::Instant::now(); } } @@ -650,8 +650,8 @@ impl<'a> TunToProxy<'a> { fn clearup_expired_dns_over_tcp(&mut self) -> Result<()> { let keys = self.connection_map.keys().cloned().collect::>(); for key in keys { - if self.udp_over_tcp_timeout_expired(&key) { - log::trace!("UDP over TCP timeout: {}", key); + if self.dns_over_tcp_timeout_expired(&key) { + log::trace!("DNS over TCP timeout: {}", key); self.remove_connection(&key)?; } } @@ -817,7 +817,7 @@ impl<'a> TunToProxy<'a> { udp_token, origin_dst: dst, udp_data_cache: LinkedList::new(), - udp_over_tcp_expiry: None, + dns_over_tcp_expiry: None, }; Ok(state) } From e5a645638a8d12b3b22779559caf4a3970e165d0 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:28:06 +0800 Subject: [PATCH 7/7] rename TcpProxy to ProxyHandler --- src/http.rs | 6 ++--- src/socks.rs | 6 ++--- src/tun2proxy.rs | 64 ++++++++++++++++++++++-------------------------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/http.rs b/src/http.rs index cdbeca2..693650a 100644 --- a/src/http.rs +++ b/src/http.rs @@ -2,7 +2,7 @@ use crate::{ error::Error, tun2proxy::{ ConnectionInfo, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection, OutgoingDataEvent, - OutgoingDirection, TcpProxy, + OutgoingDirection, ProxyHandler, }, }; use base64::Engine; @@ -317,7 +317,7 @@ impl HttpConnection { } } -impl TcpProxy for HttpConnection { +impl ProxyHandler for HttpConnection { fn get_connection_info(&self) -> &ConnectionInfo { &self.info } @@ -395,7 +395,7 @@ pub(crate) struct HttpManager { } impl ConnectionManager for HttpManager { - fn new_tcp_proxy(&self, info: &ConnectionInfo, _: bool) -> Result, Error> { + fn new_proxy_handler(&self, info: &ConnectionInfo, _: bool) -> Result, Error> { if info.protocol != IpProtocol::Tcp { return Err("Invalid protocol".into()); } diff --git a/src/socks.rs b/src/socks.rs index ee65501..5cb171b 100644 --- a/src/socks.rs +++ b/src/socks.rs @@ -2,7 +2,7 @@ use crate::{ error::{Error, Result}, tun2proxy::{ ConnectionInfo, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection, OutgoingDataEvent, - OutgoingDirection, TcpProxy, + OutgoingDirection, ProxyHandler, }, }; use socks5_impl::protocol::{self, handshake, password_method, Address, AuthMethod, StreamOperation, UserKey, Version}; @@ -268,7 +268,7 @@ impl SocksProxyImpl { } } -impl TcpProxy for SocksProxyImpl { +impl ProxyHandler for SocksProxyImpl { fn get_connection_info(&self) -> &ConnectionInfo { &self.info } @@ -346,7 +346,7 @@ pub(crate) struct SocksProxyManager { } impl ConnectionManager for SocksProxyManager { - fn new_tcp_proxy(&self, info: &ConnectionInfo, udp_associate: bool) -> Result> { + fn new_proxy_handler(&self, info: &ConnectionInfo, udp_associate: bool) -> Result> { use socks5_impl::protocol::Command::{Connect, UdpAssociate}; let command = if udp_associate { UdpAssociate } else { Connect }; let credentials = self.credentials.clone(); diff --git a/src/tun2proxy.rs b/src/tun2proxy.rs index 4753180..5a3ce45 100644 --- a/src/tun2proxy.rs +++ b/src/tun2proxy.rs @@ -186,7 +186,7 @@ struct ConnectionState { smoltcp_handle: Option, mio_stream: TcpStream, token: Token, - tcp_proxy_handler: Box, + proxy_handler: Box, close_state: u8, wait_read: bool, wait_write: bool, @@ -198,7 +198,7 @@ struct ConnectionState { dns_over_tcp_expiry: Option<::std::time::Instant>, } -pub(crate) trait TcpProxy { +pub(crate) trait ProxyHandler { fn get_connection_info(&self) -> &ConnectionInfo; fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), Error>; fn consume_data(&mut self, dir: OutgoingDirection, size: usize); @@ -210,7 +210,7 @@ pub(crate) trait TcpProxy { } pub(crate) trait ConnectionManager { - fn new_tcp_proxy(&self, info: &ConnectionInfo, udp_associate: bool) -> Result>; + fn new_proxy_handler(&self, info: &ConnectionInfo, udp_associate: bool) -> Result>; fn close_connection(&self, info: &ConnectionInfo); fn get_server_addr(&self) -> SocketAddr; fn get_credentials(&self) -> &Option; @@ -399,10 +399,10 @@ impl<'a> TunToProxy<'a> { let mut closed_ends = 0; if (state.close_state & SERVER_WRITE_CLOSED) == SERVER_WRITE_CLOSED && !state - .tcp_proxy_handler + .proxy_handler .have_data(Direction::Incoming(IncomingDirection::FromServer)) && !state - .tcp_proxy_handler + .proxy_handler .have_data(Direction::Outgoing(OutgoingDirection::ToClient)) { if let Some(handle) = state.smoltcp_handle { @@ -415,10 +415,10 @@ impl<'a> TunToProxy<'a> { if (state.close_state & CLIENT_WRITE_CLOSED) == CLIENT_WRITE_CLOSED && !state - .tcp_proxy_handler + .proxy_handler .have_data(Direction::Incoming(IncomingDirection::FromClient)) && !state - .tcp_proxy_handler + .proxy_handler .have_data(Direction::Outgoing(OutgoingDirection::ToServer)) { // Close remote server @@ -452,7 +452,7 @@ impl<'a> TunToProxy<'a> { direction: IncomingDirection::FromClient, buffer: data, }; - error = state.tcp_proxy_handler.push_data(event); + error = state.proxy_handler.push_data(event); (data.len(), ()) })?; } @@ -534,9 +534,9 @@ impl<'a> TunToProxy<'a> { if !self.connection_map.contains_key(info) { log::info!("DNS over TCP {} ({})", info, origin_dst); - let tcp_proxy_handler = manager.new_tcp_proxy(info, false)?; + let proxy_handler = manager.new_proxy_handler(info, false)?; let server_addr = manager.get_server_addr(); - let state = self.create_new_tcp_connection_state(server_addr, origin_dst, tcp_proxy_handler, false)?; + let state = self.create_new_tcp_connection_state(server_addr, origin_dst, proxy_handler, false)?; self.connection_map.insert(info.clone(), state); // TODO: Move this 3 lines to the function end? @@ -561,7 +561,7 @@ impl<'a> TunToProxy<'a> { direction: IncomingDirection::FromClient, buffer: &buf, }; - state.tcp_proxy_handler.push_data(data_event)?; + state.proxy_handler.push_data(data_event)?; Ok(()) } @@ -589,13 +589,13 @@ impl<'a> TunToProxy<'a> { direction: IncomingDirection::FromServer, buffer: &data[0..read], }; - if let Err(error) = state.tcp_proxy_handler.push_data(data_event) { + if let Err(error) = state.proxy_handler.push_data(data_event) { log::error!("{}", error); self.remove_connection(&info.clone())?; return Ok(()); } - let dns_event = state.tcp_proxy_handler.peek_data(OutgoingDirection::ToClient); + let dns_event = state.proxy_handler.peek_data(OutgoingDirection::ToClient); let mut buf = dns_event.buffer.to_vec(); let mut to_send: LinkedList> = LinkedList::new(); @@ -615,9 +615,7 @@ impl<'a> TunToProxy<'a> { let ip = dns::extract_ipaddr_from_dns_message(&message); log::trace!("DNS over TCP query result: {} -> {:?}", name, ip); - state - .tcp_proxy_handler - .consume_data(OutgoingDirection::ToClient, len + 2); + state.proxy_handler.consume_data(OutgoingDirection::ToClient, len + 2); if !self.options.ipv6_enabled { dns::remove_ipv6_entries(&mut message); @@ -667,9 +665,9 @@ impl<'a> TunToProxy<'a> { ) -> Result<()> { if !self.connection_map.contains_key(info) { log::info!("UDP associate session {} ({})", info, origin_dst); - let tcp_proxy_handler = manager.new_tcp_proxy(info, true)?; + let proxy_handler = manager.new_proxy_handler(info, true)?; let server_addr = manager.get_server_addr(); - let state = self.create_new_tcp_connection_state(server_addr, origin_dst, tcp_proxy_handler, true)?; + let state = self.create_new_tcp_connection_state(server_addr, origin_dst, proxy_handler, true)?; self.connection_map.insert(info.clone(), state); self.expect_smoltcp_send()?; @@ -689,7 +687,7 @@ impl<'a> TunToProxy<'a> { UdpHeader::new(0, info.dst.clone()).write_to_stream(&mut s5_udp_data)?; s5_udp_data.extend_from_slice(payload); - if let Some(udp_associate) = state.tcp_proxy_handler.get_udp_associate() { + if let Some(udp_associate) = state.proxy_handler.get_udp_associate() { // UDP associate session has been established, we can send packets directly... if let Some(socket) = state.udp_socket.as_ref() { socket.send_to(&s5_udp_data, udp_associate)?; @@ -718,9 +716,9 @@ impl<'a> TunToProxy<'a> { if info.protocol == IpProtocol::Tcp { if _first_packet { - let tcp_proxy_handler = manager.new_tcp_proxy(&info, false)?; + let proxy_handler = manager.new_proxy_handler(&info, false)?; let server = manager.get_server_addr(); - let state = self.create_new_tcp_connection_state(server, origin_dst, tcp_proxy_handler, false)?; + let state = self.create_new_tcp_connection_state(server, origin_dst, proxy_handler, false)?; self.connection_map.insert(info.clone(), state); log::info!("Connect done {} ({})", info, origin_dst); @@ -773,7 +771,7 @@ impl<'a> TunToProxy<'a> { &mut self, server_addr: SocketAddr, dst: SocketAddr, - tcp_proxy_handler: Box, + proxy_handler: Box, udp_associate: bool, ) -> Result { let mut socket = tcp::Socket::new( @@ -808,7 +806,7 @@ impl<'a> TunToProxy<'a> { smoltcp_handle: Some(handle), mio_stream: client, token, - tcp_proxy_handler, + proxy_handler, close_state: 0, wait_read: true, wait_write: false, @@ -860,7 +858,7 @@ impl<'a> TunToProxy<'a> { fn write_to_server(&mut self, info: &ConnectionInfo) -> Result<(), Error> { if let Some(state) = self.connection_map.get_mut(info) { - let event = state.tcp_proxy_handler.peek_data(OutgoingDirection::ToServer); + let event = state.proxy_handler.peek_data(OutgoingDirection::ToServer); let buffer_size = event.buffer.len(); if buffer_size == 0 { state.wait_write = false; @@ -871,9 +869,7 @@ impl<'a> TunToProxy<'a> { let result = state.mio_stream.write(event.buffer); match result { Ok(written) => { - state - .tcp_proxy_handler - .consume_data(OutgoingDirection::ToServer, written); + state.proxy_handler.consume_data(OutgoingDirection::ToServer, written); state.wait_write = written < buffer_size; Self::update_mio_socket_interest(&mut self.poll, state)?; } @@ -897,7 +893,7 @@ impl<'a> TunToProxy<'a> { Some(handle) => handle, None => break, }; - let event = state.tcp_proxy_handler.peek_data(OutgoingDirection::ToClient); + let event = state.proxy_handler.peek_data(OutgoingDirection::ToClient); let buflen = event.buffer.len(); let consumed; { @@ -908,9 +904,7 @@ impl<'a> TunToProxy<'a> { virtual_dns.touch_ip(&IpAddr::from(socket.local_endpoint().unwrap().addr)); } consumed = socket.send_slice(event.buffer)?; - state - .tcp_proxy_handler - .consume_data(OutgoingDirection::ToClient, consumed); + state.proxy_handler.consume_data(OutgoingDirection::ToClient, consumed); self.expect_smoltcp_send()?; if consumed < buflen { self.write_sockets.insert(token); @@ -994,7 +988,7 @@ impl<'a> TunToProxy<'a> { // Try to send the first UDP packets to remote SOCKS5 server for UDP associate session if let Some(state) = self.connection_map.get_mut(info) { if let Some(udp_socket) = state.udp_socket.as_ref() { - if let Some(addr) = state.tcp_proxy_handler.get_udp_associate() { + if let Some(addr) = state.proxy_handler.get_udp_associate() { // Consume udp_data_cache data while let Some(buf) = state.udp_data_cache.pop_front() { udp_socket.send_to(&buf, addr)?; @@ -1030,7 +1024,7 @@ impl<'a> TunToProxy<'a> { .connection_map .get(&conn_info) .ok_or("")? - .tcp_proxy_handler + .proxy_handler .connection_established(); if self.options.dns_over_tcp && conn_info.dst.port() == DNS_PORT && established { self.receive_dns_over_tcp_packet_and_write_to_client(&conn_info)?; @@ -1057,14 +1051,14 @@ impl<'a> TunToProxy<'a> { direction: IncomingDirection::FromServer, buffer: &data[0..read], }; - if let Err(error) = state.tcp_proxy_handler.push_data(data_event) { + if let Err(error) = state.proxy_handler.push_data(data_event) { log::error!("{}", error); self.remove_connection(&conn_info.clone())?; return Ok(()); } // The handler request for reset the server connection - if state.tcp_proxy_handler.reset_connection() { + if state.proxy_handler.reset_connection() { _ = self.poll.registry().deregister(&mut state.mio_stream); // Closes the connection with the proxy state.mio_stream.shutdown(Shutdown::Both)?;