From 23d4e5936761e90383edadea00e62ba172fdba4a Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Mon, 11 Nov 2024 11:51:28 +0800 Subject: [PATCH 01/63] minor changes --- src/bin/udpgw_server.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/udpgw_server.rs b/src/bin/udpgw_server.rs index 8f475e5..d02d6c4 100644 --- a/src/bin/udpgw_server.rs +++ b/src/bin/udpgw_server.rs @@ -29,6 +29,7 @@ impl Client { } #[derive(Debug, Clone, clap::Parser)] +#[command(author, version, about = "UDP Gateway Server for tun2proxy", long_about = None)] pub struct UdpGwArgs { /// UDP gateway listen address #[arg(short, long, value_name = "IP:PORT", default_value = "127.0.0.1:7300")] From 731490684175cb6f1a34de1c6a228e5331b6d33f Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:48:02 +0800 Subject: [PATCH 02/63] mask_socket_addr function --- src/bin/udpgw_server.rs | 53 +++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/bin/udpgw_server.rs b/src/bin/udpgw_server.rs index d02d6c4..e78fbb9 100644 --- a/src/bin/udpgw_server.rs +++ b/src/bin/udpgw_server.rs @@ -77,7 +77,7 @@ async fn send_keepalive_response(tx: Sender, conn_id: u16) { /// Send data field of packet from client to destination server and receive response, /// then wrap response data to the packet's data field and send packet back to client. -async fn process_udp(_client: SocketAddr, udp_mtu: u16, udp_timeout: u64, tx: Sender, mut packet: Packet) -> Result<()> { +async fn process_udp(udp_mtu: u16, udp_timeout: u64, tx: Sender, mut packet: Packet) -> Result<()> { let Some(dst_addr) = &packet.address else { return Err(std::io::Error::new(std::io::ErrorKind::AddrNotAvailable, "udp request address is None").into()); }; @@ -107,22 +107,53 @@ async fn process_udp(_client: SocketAddr, udp_mtu: u16, udp_timeout: u64, tx: Se Ok(()) } +fn mask_ip(ip: &str) -> String { + if ip.len() <= 2 { + return ip.to_string(); + } + let mut masked_ip = String::new(); + for (i, c) in ip.chars().enumerate() { + if i == 0 || i == ip.len() - 1 || c == '.' || c == ':' { + masked_ip.push(c); + } else { + masked_ip.push('*'); + } + } + masked_ip +} + +fn mask_socket_addr(socket_addr: std::net::SocketAddr) -> String { + match socket_addr { + std::net::SocketAddr::V4(addr) => { + let masked_ip = mask_ip(&addr.ip().to_string()); + format!("{}:{}", masked_ip, addr.port()) + } + std::net::SocketAddr::V6(addr) => { + let masked_ip = mask_ip(&addr.ip().to_string()); + format!("[{}]:{}", masked_ip, addr.port()) + } + } +} + async fn process_client_udp_req(args: &UdpGwArgs, tx: Sender, mut client: Client, mut reader: ReadHalf<'_>) -> std::io::Result<()> { let udp_timeout = args.udp_timeout; let udp_mtu = args.udp_mtu; + let masked_addr = mask_socket_addr(client.addr); + loop { + let masked_addr = masked_addr.clone(); // 1. read udpgw packet from client let res = tokio::time::timeout(tokio::time::Duration::from_secs(2), Packet::retrieve_from_async_stream(&mut reader)).await; let packet = match res { Ok(Ok(packet)) => packet, Ok(Err(e)) => { - log::debug!("client {} retrieve_from_async_stream \"{}\"", client.addr, e); + log::debug!("client {} retrieve_from_async_stream \"{}\"", masked_addr, e); break; } Err(e) => { if client.last_activity.elapsed() >= CLIENT_DISCONNECT_TIMEOUT { - log::debug!("client {} last_activity elapsed \"{e}\"", client.addr); + log::debug!("client {} last_activity elapsed \"{e}\"", masked_addr); break; } continue; @@ -133,19 +164,19 @@ async fn process_client_udp_req(args: &UdpGwArgs, tx: Sender, mut client let flags = packet.header.flags; let conn_id = packet.header.conn_id; if flags & UdpFlag::KEEPALIVE == UdpFlag::KEEPALIVE { - log::trace!("client {} send keepalive", client.addr); + log::trace!("client {} send keepalive", masked_addr); // 2. if keepalive packet, do nothing, send keepalive response to client send_keepalive_response(tx.clone(), conn_id).await; continue; } - log::trace!("client {} received udp data {}", client.addr, packet); + log::trace!("client {} received udp data {}", masked_addr, packet); // 3. process client udpgw packet in a new task let tx = tx.clone(); tokio::spawn(async move { - if let Err(e) = process_udp(client.addr, udp_mtu, udp_timeout, tx.clone(), packet).await { + if let Err(e) = process_udp(udp_mtu, udp_timeout, tx.clone(), packet).await { send_error_response(tx, conn_id).await; - log::debug!("client {} process udp function \"{e}\"", client.addr); + log::debug!("client {} process udp function \"{e}\"", masked_addr); } }); } @@ -153,10 +184,11 @@ async fn process_client_udp_req(args: &UdpGwArgs, tx: Sender, mut client } async fn write_to_client(addr: SocketAddr, mut writer: WriteHalf<'_>, mut rx: Receiver) -> std::io::Result<()> { + let masked_addr = mask_socket_addr(addr); loop { use std::io::{Error, ErrorKind::BrokenPipe}; let packet = rx.recv().await.ok_or(Error::new(BrokenPipe, "recv error"))?; - log::trace!("send response to client {} with {}", addr, packet); + log::trace!("send response to client {} with {}", masked_addr, packet); let data: Vec = packet.into(); let _r = writer.write(&data).await?; } @@ -196,7 +228,8 @@ pub async fn run(args: UdpGwArgs, shutdown_token: tokio_util::sync::Cancellation _ = shutdown_token.cancelled() => break, }; let client = Client::new(addr); - log::info!("client {} connected", addr); + let masked_addr = mask_socket_addr(addr); + log::info!("client {} connected", masked_addr); let params = args.clone(); tokio::spawn(async move { let (tx, rx) = tokio::sync::mpsc::channel::(100); @@ -205,7 +238,7 @@ pub async fn run(args: UdpGwArgs, shutdown_token: tokio_util::sync::Cancellation v = process_client_udp_req(¶ms, tx, client, tcp_read_stream) => v, v = write_to_client(addr, tcp_write_stream, rx) => v, }; - log::info!("client {} disconnected with {:?}", addr, res); + log::info!("client {} disconnected with {:?}", masked_addr, res); }); } Ok::<(), Error>(()) From ee4df8f97bc4dc0aea76ca33c778d9a4fcabe0a8 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sat, 16 Nov 2024 23:52:17 +0800 Subject: [PATCH 03/63] cbindgen issues --- .github/workflows/publish-exe.yml | 8 ++++---- build-aarch64-apple-ios-debug.sh | 2 +- build-aarch64-apple-ios.sh | 2 +- build-android.sh | 2 +- build-apple.sh | 2 +- cbindgen.toml | 4 ++++ 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish-exe.yml b/.github/workflows/publish-exe.yml index f9c20a0..628baf3 100644 --- a/.github/workflows/publish-exe.yml +++ b/.github/workflows/publish-exe.yml @@ -90,13 +90,13 @@ jobs: cargo build --all-features --release --target ${{ matrix.target }} fi fi - cbindgen --config cbindgen.toml -l C --cpp-compat -o target/tun2proxy-ffi.h + cbindgen --config cbindgen.toml -o target/tun2proxy.h if [[ "${{ matrix.host_os }}" == "windows-latest" ]]; then powershell -Command "(Get-Item README.md).LastWriteTime = Get-Date" powershell -Command "(Get-Item target/${{ matrix.target }}/release/wintun.dll).LastWriteTime = Get-Date" - powershell Compress-Archive -Path target/${{ matrix.target }}/release/tun2proxy-bin.exe, target/${{ matrix.target }}/release/udpgw-server.exe, README.md, target/tun2proxy-ffi.h, target/${{ matrix.target }}/release/tun2proxy.dll, target/${{ matrix.target }}/release/wintun.dll -DestinationPath mypubdir4/tun2proxy-${{ matrix.target }}.zip + powershell Compress-Archive -Path target/${{ matrix.target }}/release/tun2proxy-bin.exe, target/${{ matrix.target }}/release/udpgw-server.exe, README.md, target/tun2proxy.h, target/${{ matrix.target }}/release/tun2proxy.dll, target/${{ matrix.target }}/release/wintun.dll -DestinationPath mypubdir4/tun2proxy-${{ matrix.target }}.zip elif [[ "${{ matrix.host_os }}" == "macos-latest" ]]; then - zip -j mypubdir4/tun2proxy-${{ matrix.target }}.zip target/${{ matrix.target }}/release/tun2proxy-bin target/${{ matrix.target }}/release/udpgw-server README.md target/tun2proxy-ffi.h target/${{ matrix.target }}/release/libtun2proxy.dylib + zip -j mypubdir4/tun2proxy-${{ matrix.target }}.zip target/${{ matrix.target }}/release/tun2proxy-bin target/${{ matrix.target }}/release/udpgw-server README.md target/tun2proxy.h target/${{ matrix.target }}/release/libtun2proxy.dylib if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then ./build-aarch64-apple-ios.sh zip -r mypubdir4/tun2proxy-aarch64-apple-ios-xcframework.zip ./tun2proxy.xcframework/ @@ -104,7 +104,7 @@ jobs: zip -r mypubdir4/tun2proxy-apple-xcframework.zip ./tun2proxy.xcframework/ fi elif [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then - zip -j mypubdir4/tun2proxy-${{ matrix.target }}.zip target/${{ matrix.target }}/release/tun2proxy-bin target/${{ matrix.target }}/release/udpgw-server README.md target/tun2proxy-ffi.h target/${{ matrix.target }}/release/libtun2proxy.so + zip -j mypubdir4/tun2proxy-${{ matrix.target }}.zip target/${{ matrix.target }}/release/tun2proxy-bin target/${{ matrix.target }}/release/udpgw-server README.md target/tun2proxy.h target/${{ matrix.target }}/release/libtun2proxy.so if [[ "${{ matrix.target }}" == "x86_64-unknown-linux-gnu" ]]; then ./build-android.sh cp ./tun2proxy-android-libs.zip ./mypubdir4/ diff --git a/build-aarch64-apple-ios-debug.sh b/build-aarch64-apple-ios-debug.sh index 7642758..6c97921 100755 --- a/build-aarch64-apple-ios-debug.sh +++ b/build-aarch64-apple-ios-debug.sh @@ -10,7 +10,7 @@ cargo build --target aarch64-apple-ios --features mimalloc echo "Generating includes..." mkdir -p target/include/ rm -rf target/include/* -cbindgen --config cbindgen.toml -l C --cpp-compat -o target/include/tun2proxy.h +cbindgen --config cbindgen.toml -o target/include/tun2proxy.h cat > target/include/tun2proxy.modulemap < target/include/tun2proxy.modulemap < target/include/tun2proxy.modulemap < Date: Thu, 21 Nov 2024 14:15:37 +0800 Subject: [PATCH 04/63] Bump version 0.6.5 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e9351ca..c426865 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.6.4" +version = "0.6.5" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 987635d3dc201d9b2a279cde710e5dc6558a1b87 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sat, 23 Nov 2024 22:10:53 +0800 Subject: [PATCH 05/63] Contributors in README --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 06f0601..f737745 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ +[![tun2proxy](https://socialify.git.ci/tun2proxy/tun2proxy/image?description=1&language=1&name=1&stargazers=1&theme=Light)](https://github.com/tun2proxy/tun2proxy) + # tun2proxy A tunnel interface for HTTP and SOCKS proxies on Linux, Android, macOS, iOS and Windows. [![Crates.io](https://img.shields.io/crates/v/tun2proxy.svg)](https://crates.io/crates/tun2proxy) -![tun2proxy](https://docs.rs/tun2proxy/badge.svg) +[![tun2proxy](https://docs.rs/tun2proxy/badge.svg)](https://docs.rs/tun2proxy) [![Documentation](https://img.shields.io/badge/docs-release-brightgreen.svg?style=flat)](https://docs.rs/tun2proxy) [![Download](https://img.shields.io/crates/d/tun2proxy.svg)](https://crates.io/crates/tun2proxy) [![License](https://img.shields.io/crates/l/tun2proxy.svg?style=flat)](https://github.com/tun2proxy/tun2proxy/blob/master/LICENSE) @@ -216,3 +218,10 @@ 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. + +## Contributors ✨ +Thanks goes to these wonderful people: + + + + From d37cb44b6221c0b1b5e3841ead6eb98c4a8d920f Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:17:16 +0800 Subject: [PATCH 06/63] Fix #165 --- src/args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/args.rs b/src/args.rs index 85904db..33f160c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -397,7 +397,7 @@ impl TryFrom<&str> for ArgProxy { let mut url_host = String::from(host); let e = format!("`{s}` does not contain a port"); - let port = url.port().ok_or(Error::from(&e))?; + let port = url.port_or_known_default().ok_or(Error::from(&e))?; url_host.push(':'); url_host.push_str(port.to_string().as_str()); From 46bf4434ef4dc6eb29950aacbdeff0c16bc733c2 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:28:03 +0800 Subject: [PATCH 07/63] Bump version 0.6.6 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c426865..a2285cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.6.5" +version = "0.6.6" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 7a7293effd893dcf9e94eeb1e10bdede4a499000 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:50:07 +0800 Subject: [PATCH 08/63] Refine code --- src/args.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/args.rs b/src/args.rs index 33f160c..38c2a09 100644 --- a/src/args.rs +++ b/src/args.rs @@ -395,17 +395,11 @@ impl TryFrom<&str> for ArgProxy { let e = format!("`{s}` does not contain a host"); let host = url.host_str().ok_or(Error::from(e))?; - let mut url_host = String::from(host); let e = format!("`{s}` does not contain a port"); let port = url.port_or_known_default().ok_or(Error::from(&e))?; - url_host.push(':'); - url_host.push_str(port.to_string().as_str()); - let e = format!("`{host}` could not be resolved"); - let mut addr_iter = url_host.to_socket_addrs().map_err(|_| Error::from(&e))?; - - let e = format!("`{host}` does not resolve to a usable IP address"); - let addr = addr_iter.next().ok_or(Error::from(&e))?; + let e2 = format!("`{host}` does not resolve to a usable IP address"); + let addr = (host, port).to_socket_addrs()?.next().ok_or(Error::from(&e2))?; let credentials = if url.username() == "" && url.password().is_none() { None From 724557b30e5199febf3ff96f667836856da6d726 Mon Sep 17 00:00:00 2001 From: Paper-Dragon <2678885646@qq.com> Date: Tue, 26 Nov 2024 13:12:04 +0800 Subject: [PATCH 09/63] docker-compose.yaml support (#166) --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f737745..3f320e2 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,8 @@ Currently, tun2proxy supports HTTP, SOCKS4/SOCKS4a and SOCKS5. A proxy is suppli 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 supplied as `--proxy http://john.doe:secret@1.2.3.4:3128`. This works analogously to curl's `--proxy` argument. -## Docker Support +## Container Support +### Docker Tun2proxy can serve as a proxy for other Docker containers. To make use of that feature, first build the image: ```bash @@ -197,6 +198,36 @@ docker run -it \ --network "container:tun2proxy" \ ubuntu:latest ``` +### Docker Compose + +The above docker command is written into a `docker-compose.yaml` file. + +```yaml +services: + tun2proxy: + volumes: + - /dev/net/tun:/dev/net/tun + sysctls: + - net.ipv6.conf.default.disable_ipv6=0 + cap_add: + - NET_ADMIN + container_name: tun2proxy + image: ghcr.io/tun2proxy/tun2proxy:latest + command: --proxy proto://[username[:password]@]host:port + alpine: + stdin_open: true + tty: true + network_mode: container:tun2proxy + image: alpine:latest + command: apk add curl && curl ifconfig.icu && sleep 10 +``` + +run compose file + +```bash +docker compose up -d tun2proxy +docker compose up alpine +``` ## Configuration Tips ### DNS From a01de17b365bc6343dbff4051490f0b3b974e463 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:32:39 +0800 Subject: [PATCH 10/63] minor changes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f320e2..5c9b591 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ docker run -it \ ``` ### Docker Compose -The above docker command is written into a `docker-compose.yaml` file. +Write a `docker-compose.yaml` file with the following content: ```yaml services: @@ -222,7 +222,7 @@ services: command: apk add curl && curl ifconfig.icu && sleep 10 ``` -run compose file +Then run the compose file ```bash docker compose up -d tun2proxy From 258637a52ea663e832a8cb380a78d5774140c8ab Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:17:51 +0800 Subject: [PATCH 11/63] upgrade dependencies --- Cargo.toml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2285cb..1f46a49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,14 +26,16 @@ ctrlc2 = { version = "3", features = ["tokio", "termination"] } digest_auth = "0.3" dotenvy = "0.15" env_logger = "0.11" -hashlink = "0.9" +hashlink = "0.10" hickory-proto = "0.24" httparse = "1" ipstack = { version = "0.1" } log = { version = "0.4", features = ["std"] } mimalloc = { version = "0.1", default-features = false, optional = true } percent-encoding = "2" -socks5-impl = { version = "0.5" } +socks5-impl = { version = "0.6", default-features = false, features = [ + "tokio", +] } thiserror = "2" tokio = { version = "1", features = ["full"] } tokio-util = "0.7" @@ -43,6 +45,9 @@ udp-stream = { version = "0.0.12", default-features = false } unicase = "2" url = "2" +[build-dependencies] +serde_json = "1" + [target.'cfg(target_os="linux")'.dependencies] serde = { version = "1", features = ["derive"] } bincode = "1" @@ -62,9 +67,6 @@ nix = { version = "0.29", default-features = false, features = [ [target.'cfg(target_os = "windows")'.dependencies] windows-service = "0.7" -[build-dependencies] -serde_json = "1" - [[bin]] name = "tun2proxy-bin" path = "src/bin/main.rs" From 4d4a0ce85cc3222d34f9dd7cf38ec05548cb189b Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:38:13 +0800 Subject: [PATCH 12/63] minor changes --- Cargo.toml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1f46a49..f203a2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,15 @@ rust-version = "1.80" [lib] crate-type = ["staticlib", "cdylib", "lib"] +[[bin]] +name = "tun2proxy-bin" +path = "src/bin/main.rs" + +[[bin]] +name = "udpgw-server" +path = "src/bin/udpgw_server.rs" +required-features = ["udpgw"] + [features] default = ["udpgw"] udpgw = [] @@ -67,14 +76,5 @@ nix = { version = "0.29", default-features = false, features = [ [target.'cfg(target_os = "windows")'.dependencies] windows-service = "0.7" -[[bin]] -name = "tun2proxy-bin" -path = "src/bin/main.rs" - -[[bin]] -name = "udpgw-server" -path = "src/bin/udpgw_server.rs" -required-features = ["udpgw"] - [profile.release] strip = "symbols" From ea5ee834dbbfa6cf373b14fd77caee9946e22403 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 27 Dec 2024 16:59:11 +0800 Subject: [PATCH 13/63] Bump version 0.6.7 --- .github/workflows/publish-exe.yml | 8 ++++++++ Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-exe.yml b/.github/workflows/publish-exe.yml index 628baf3..c9730b9 100644 --- a/.github/workflows/publish-exe.yml +++ b/.github/workflows/publish-exe.yml @@ -15,6 +15,7 @@ jobs: attestations: write strategy: + fail-fast: false matrix: target: - x86_64-unknown-linux-gnu @@ -77,6 +78,7 @@ jobs: fi - name: Build + if: ${{ !cancelled() }} shell: bash run: | if [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then @@ -112,20 +114,26 @@ jobs: fi - name: Upload artifacts + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: bin-${{ matrix.target }} path: mypubdir4/* - name: Generate artifact attestation + if: ${{ !cancelled() }} uses: actions/attest-build-provenance@v1 with: subject-path: mypubdir4/* - name: Publish + if: ${{ !cancelled() }} uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: files: mypubdir4/* + - name: Abort on error + if: ${{ failure() }} + run: echo "Some of jobs failed" && false diff --git a/Cargo.toml b/Cargo.toml index f203a2e..171b742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.6.6" +version = "0.6.7" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 2a8e31225c8369b4a0ccd346c45288c04fb0019d Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:05:32 +0800 Subject: [PATCH 14/63] refine clap::Parser --- src/args.rs | 3 +-- src/bin/udpgw_server.rs | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/args.rs b/src/args.rs index 38c2a09..71a85f2 100644 --- a/src/args.rs +++ b/src/args.rs @@ -181,8 +181,7 @@ impl Default for Args { impl Args { #[allow(clippy::let_and_return)] pub fn parse_args() -> Self { - use clap::Parser; - let args = Self::parse(); + let args = ::parse(); #[cfg(target_os = "linux")] if !args.setup && args.tun.is_none() { eprintln!("Missing required argument, '--tun' must present when '--setup' is not used."); diff --git a/src/bin/udpgw_server.rs b/src/bin/udpgw_server.rs index e78fbb9..9cf144a 100644 --- a/src/bin/udpgw_server.rs +++ b/src/bin/udpgw_server.rs @@ -54,10 +54,8 @@ pub struct UdpGwArgs { } impl UdpGwArgs { - #[allow(clippy::let_and_return)] pub fn parse_args() -> Self { - use clap::Parser; - Self::parse() + ::parse() } } From 7136e2a20c63526f217c1ce9ca05f4ced26b0bba Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:18:40 +0800 Subject: [PATCH 15/63] refactor desktop_run_async --- Cargo.toml | 2 +- cbindgen.toml | 1 + src/bin/main.rs | 3 +- src/desktop_api.rs | 116 ++++++++++++++++++++++++++++----------------- src/mobile_api.rs | 101 +++++++++++++++++++-------------------- src/win_svc.rs | 2 +- 6 files changed, 127 insertions(+), 98 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 171b742..e93e99b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.6.7" +version = "0.7.0" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" diff --git a/cbindgen.toml b/cbindgen.toml index 8354c6c..10e4235 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -3,6 +3,7 @@ cpp_compat = true [export] include = [ + "tun2proxy_run_with_cli", "tun2proxy_with_fd_run", "tun2proxy_with_name_run", "tun2proxy_with_name_stop", diff --git a/src/bin/main.rs b/src/bin/main.rs index e39b7b4..d5b1ebe 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,3 +1,4 @@ +use tun::DEFAULT_MTU as MTU; use tun2proxy::{Args, BoxError}; fn main() -> Result<(), BoxError> { @@ -49,7 +50,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { } unsafe { tun2proxy::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = tun2proxy::desktop_run_async(args, shutdown_token).await { + if let Err(err) = tun2proxy::desktop_run_async(args, MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); } } diff --git a/src/desktop_api.rs b/src/desktop_api.rs index 17428fb..ed8dbb5 100644 --- a/src/desktop_api.rs +++ b/src/desktop_api.rs @@ -5,7 +5,6 @@ use crate::{ ArgVerbosity, Args, }; use std::os::raw::{c_char, c_int}; -use tproxy_config::{TproxyArgs, TUN_GATEWAY, TUN_IPV4, TUN_NETMASK}; use tun::{AbstractDevice, DEFAULT_MTU as MTU}; static TUN_QUIT: std::sync::Mutex> = std::sync::Mutex::new(None); @@ -29,6 +28,42 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( _root_privilege: bool, verbosity: ArgVerbosity, ) -> c_int { + let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); + let proxy = ArgProxy::try_from(proxy_url).unwrap(); + let tun = std::ffi::CStr::from_ptr(tun).to_str().unwrap().to_string(); + + let mut args = Args::default(); + if let Ok(bypass) = std::ffi::CStr::from_ptr(bypass).to_str() { + args.bypass(bypass.parse().unwrap()); + } + args.proxy(proxy).tun(tun).dns(dns_strategy).verbosity(verbosity); + + #[cfg(target_os = "linux")] + args.setup(_root_privilege); + + desktop_run(args) +} + +/// # Safety +/// Run the tun2proxy component with command line arguments +/// Parameters: +/// - cli_args: The command line arguments, +/// e.g. `tun2proxy-bin --setup --proxy socks5://127.0.0.1:1080 --bypass 98.76.54.0/24 --dns over-tcp --verbosity trace` +#[no_mangle] +pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char) -> c_int { + let Ok(cli_args) = std::ffi::CStr::from_ptr(cli_args).to_str() else { + return -5; + }; + let args = ::parse_from(cli_args.split_whitespace()); + desktop_run(args) +} + +pub fn desktop_run(args: Args) -> c_int { + log::set_max_level(args.verbosity.into()); + if let Err(err) = log::set_boxed_logger(Box::::default()) { + log::warn!("set logger error: {}", err); + } + let shutdown_token = tokio_util::sync::CancellationToken::new(); { if let Ok(mut lock) = TUN_QUIT.lock() { @@ -41,51 +76,38 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( } } - log::set_max_level(verbosity.into()); - if let Err(err) = log::set_boxed_logger(Box::::default()) { - log::warn!("set logger error: {}", err); - } - - let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); - let proxy = ArgProxy::try_from(proxy_url).unwrap(); - let tun = std::ffi::CStr::from_ptr(tun).to_str().unwrap().to_string(); - - let mut args = Args::default(); - args.proxy(proxy).tun(tun).dns(dns_strategy).verbosity(verbosity); - - #[cfg(target_os = "linux")] - args.setup(_root_privilege); - - if let Ok(bypass) = std::ffi::CStr::from_ptr(bypass).to_str() { - args.bypass(bypass.parse().unwrap()); - } - - let main_loop = async move { - if let Err(err) = desktop_run_async(args, shutdown_token).await { + let Ok(rt) = tokio::runtime::Builder::new_multi_thread().enable_all().build() else { + return -3; + }; + let res = rt.block_on(async move { + if let Err(err) = desktop_run_async(args, MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); return Err(err); } Ok(()) - }; - - let exit_code = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { - Err(_e) => -3, - Ok(rt) => match rt.block_on(main_loop) { - Ok(_) => 0, - Err(_e) => -4, - }, - }; - - exit_code + }); + match res { + Ok(_) => 0, + Err(_) => -4, + } } /// Run the tun2proxy component with some arguments. -pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::CancellationToken) -> std::io::Result<()> { - let bypass_ips = args.bypass.clone(); - +pub async fn desktop_run_async( + args: Args, + tun_mtu: u16, + _packet_information: bool, + shutdown_token: tokio_util::sync::CancellationToken, +) -> std::io::Result<()> { let mut tun_config = tun::Configuration::default(); - tun_config.address(TUN_IPV4).netmask(TUN_NETMASK).mtu(MTU).up(); - tun_config.destination(TUN_GATEWAY); + + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] + { + use tproxy_config::{TUN_GATEWAY, TUN_IPV4, TUN_NETMASK}; + tun_config.address(TUN_IPV4).netmask(TUN_NETMASK).mtu(tun_mtu).up(); + tun_config.destination(TUN_GATEWAY); + } + #[cfg(unix)] if let Some(fd) = args.tun_fd { tun_config.raw_fd(fd); @@ -112,11 +134,17 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can cfg.device_guid(12324323423423434234_u128); }); + #[cfg(any(target_os = "ios", target_os = "macos"))] + tun_config.platform_config(|cfg| { + cfg.packet_information(_packet_information); + }); + + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] #[allow(unused_variables)] - let mut tproxy_args = TproxyArgs::new() + let mut tproxy_args = tproxy_config::TproxyArgs::new() .tun_dns(args.dns_addr) .proxy_addr(args.proxy.addr) - .bypass_ips(&bypass_ips) + .bypass_ips(&args.bypass) .ipv6_default_route(args.ipv6_enabled); #[allow(unused_mut, unused_assignments, unused_variables)] @@ -124,12 +152,14 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can let device = tun::create_as_async(&tun_config)?; + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] if let Ok(tun_name) = device.tun_name() { tproxy_args = tproxy_args.tun_name(&tun_name); } // TproxyState implements the Drop trait to restore network configuration, // so we need to assign it to a variable, even if it is not used. + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] let mut _restore: Option = None; #[cfg(target_os = "linux")] @@ -166,10 +196,8 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can } } - let join_handle = tokio::spawn(crate::run(device, MTU, args, shutdown_token)); - join_handle.await.map_err(std::io::Error::from)??; - - Ok::<(), std::io::Error>(()) + let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); + Ok(join_handle.await.map_err(std::io::Error::from)??) } /// # Safety diff --git a/src/mobile_api.rs b/src/mobile_api.rs index a32f68d..3f885d5 100644 --- a/src/mobile_api.rs +++ b/src/mobile_api.rs @@ -8,68 +8,67 @@ static TUN_QUIT: std::sync::Mutex> = /// Dummy function to make the build pass. #[doc(hidden)] #[cfg(not(target_os = "macos"))] -pub async fn desktop_run_async(_: Args, _: tokio_util::sync::CancellationToken) -> std::io::Result<()> { +pub async fn desktop_run_async(_: Args, _: u16, _: bool, _: tokio_util::sync::CancellationToken) -> std::io::Result<()> { Ok(()) } +pub async fn mobile_run_async( + args: Args, + tun_mtu: u16, + _packet_information: bool, + shutdown_token: tokio_util::sync::CancellationToken, +) -> std::io::Result<()> { + let mut config = tun::Configuration::default(); + + #[cfg(unix)] + if let Some(fd) = args.tun_fd { + config.raw_fd(fd); + if let Some(v) = args.close_fd_on_drop { + config.close_fd_on_drop(v); + }; + } else if let Some(ref tun) = args.tun { + config.tun_name(tun); + } + #[cfg(windows)] + if let Some(ref tun) = args.tun { + config.tun_name(tun); + } + + #[cfg(any(target_os = "ios", target_os = "macos"))] + config.platform_config(|config| { + config.packet_information(_packet_information); + }); + + let device = tun::create_as_async(&config).map_err(std::io::Error::from)?; + let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); + + Ok(join_handle.await.map_err(std::io::Error::from)??) +} + pub fn mobile_run(args: Args, tun_mtu: u16, _packet_information: bool) -> c_int { let shutdown_token = tokio_util::sync::CancellationToken::new(); - { - if let Ok(mut lock) = TUN_QUIT.lock() { - if lock.is_some() { - log::error!("tun2proxy already started"); - return -1; - } - *lock = Some(shutdown_token.clone()); - } else { - log::error!("failed to lock tun2proxy quit token"); - return -2; + if let Ok(mut lock) = TUN_QUIT.lock() { + if lock.is_some() { + log::error!("tun2proxy already started"); + return -1; } + *lock = Some(shutdown_token.clone()); + } else { + log::error!("failed to lock tun2proxy quit token"); + return -2; } - let block = async move { - let mut config = tun::Configuration::default(); - - #[cfg(unix)] - if let Some(fd) = args.tun_fd { - config.raw_fd(fd); - if let Some(v) = args.close_fd_on_drop { - config.close_fd_on_drop(v); - }; - } else if let Some(ref tun) = args.tun { - config.tun_name(tun); - } - #[cfg(windows)] - if let Some(ref tun) = args.tun { - config.tun_name(tun); - } - - #[cfg(any(target_os = "ios", target_os = "macos"))] - config.platform_config(|config| { - config.packet_information(_packet_information); - }); - - let device = tun::create_as_async(&config).map_err(std::io::Error::from)?; - let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); - - join_handle.await.map_err(std::io::Error::from)? + let Ok(rt) = tokio::runtime::Builder::new_multi_thread().enable_all().build() else { + log::error!("failed to create tokio runtime with"); + return -1; }; - - let exit_code = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { + match rt.block_on(mobile_run_async(args, tun_mtu, _packet_information, shutdown_token)) { + Ok(_) => 0, Err(e) => { - log::error!("failed to create tokio runtime with error: {:?}", e); - -1 + log::error!("failed to run tun2proxy with error: {:?}", e); + -2 } - Ok(rt) => match rt.block_on(block) { - Ok(_) => 0, - Err(e) => { - log::error!("failed to run tun2proxy with error: {:?}", e); - -2 - } - }, - }; - - exit_code + } } pub fn mobile_stop() -> c_int { diff --git a/src/win_svc.rs b/src/win_svc.rs index afca2f1..e775049 100644 --- a/src/win_svc.rs +++ b/src/win_svc.rs @@ -78,7 +78,7 @@ fn run_service(_arguments: Vec) -> Result<(), crate::BoxErro } unsafe { crate::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = crate::desktop_run_async(args, shutdown_token).await { + if let Err(err) = crate::desktop_run_async(args, tun::DEFAULT_MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); } Ok::<(), crate::Error>(()) From e933e5d4c032b1319f111b263e3091c7d7d7d485 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 3 Jan 2025 00:41:29 +0800 Subject: [PATCH 16/63] iOS & Android testing suits --- .github/workflows/rust.yml | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 13992eb..693d55c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -47,6 +47,52 @@ jobs: if: ${{ failure() }} run: echo "Some of jobs failed" && false + build_n_test_android: + strategy: + fail-fast: false + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Install cargo ndk and rust compiler for android target + if: ${{ !cancelled() }} + run: | + cargo install --locked cargo-ndk + rustup target add x86_64-linux-android + - name: clippy + if: ${{ !cancelled() }} + run: cargo ndk -t x86_64 clippy --all-features -- -D warnings + - name: Build + if: ${{ !cancelled() }} + run: | + cargo ndk -t x86_64 rustc --verbose --all-features --lib --crate-type=cdylib + - name: Abort on error + if: ${{ failure() }} + run: echo "Android build job failed" && false + + build_n_test_ios: + strategy: + fail-fast: false + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + - name: Install cargo lipo and rust compiler for ios target + if: ${{ !cancelled() }} + run: | + cargo install --locked cargo-lipo + rustup target add x86_64-apple-ios aarch64-apple-ios + - name: clippy + if: ${{ !cancelled() }} + run: cargo clippy --target x86_64-apple-ios --all-features -- -D warnings + - name: Build + if: ${{ !cancelled() }} + run: | + cargo lipo --verbose --all-features + - name: Abort on error + if: ${{ failure() }} + run: echo "iOS build job failed" && false + semver: name: Check semver strategy: From 60348702649f0ec4a896e33f9f02fe02cbca9956 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 3 Jan 2025 01:37:40 +0800 Subject: [PATCH 17/63] rename desktop_run_async to general_run_async --- src/android.rs | 4 +- src/bin/main.rs | 2 +- src/{desktop_api.rs => general_api.rs} | 50 +++++++++------- src/lib.rs | 14 +---- src/{apple.rs => mobile.rs} | 9 +-- src/mobile_api.rs | 82 -------------------------- src/win_svc.rs | 2 +- 7 files changed, 37 insertions(+), 126 deletions(-) rename src/{desktop_api.rs => general_api.rs} (84%) rename src/{apple.rs => mobile.rs} (82%) delete mode 100644 src/mobile_api.rs diff --git a/src/android.rs b/src/android.rs index cca174c..21dd5eb 100644 --- a/src/android.rs +++ b/src/android.rs @@ -52,7 +52,7 @@ pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run( .close_fd_on_drop(close_fd_on_drop) .dns(dns) .verbosity(verbosity); - crate::mobile_api::mobile_run(args, tun_mtu, false) + crate::general_api::general_run_for_api(args, tun_mtu, false) } /// # Safety @@ -60,7 +60,7 @@ pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run( /// Shutdown tun2proxy #[no_mangle] pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_stop(_env: JNIEnv, _: JClass) -> jint { - crate::mobile_api::mobile_stop() + crate::general_api::tun2proxy_stop_internal() } fn get_java_string(env: &mut JNIEnv, string: &JString) -> Result { diff --git a/src/bin/main.rs b/src/bin/main.rs index d5b1ebe..e690f6c 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -50,7 +50,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { } unsafe { tun2proxy::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = tun2proxy::desktop_run_async(args, MTU, false, shutdown_token).await { + if let Err(err) = tun2proxy::general_run_async(args, MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); } } diff --git a/src/desktop_api.rs b/src/general_api.rs similarity index 84% rename from src/desktop_api.rs rename to src/general_api.rs index ed8dbb5..9385f48 100644 --- a/src/desktop_api.rs +++ b/src/general_api.rs @@ -1,11 +1,9 @@ -#![cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] - use crate::{ args::{ArgDns, ArgProxy}, ArgVerbosity, Args, }; use std::os::raw::{c_char, c_int}; -use tun::{AbstractDevice, DEFAULT_MTU as MTU}; +use tun::DEFAULT_MTU as MTU; static TUN_QUIT: std::sync::Mutex> = std::sync::Mutex::new(None); @@ -41,7 +39,7 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( #[cfg(target_os = "linux")] args.setup(_root_privilege); - desktop_run(args) + general_run_for_api(args, MTU, false) } /// # Safety @@ -55,45 +53,48 @@ pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char) -> return -5; }; let args = ::parse_from(cli_args.split_whitespace()); - desktop_run(args) + general_run_for_api(args, MTU, false) } -pub fn desktop_run(args: Args) -> c_int { +pub fn general_run_for_api(args: Args, tun_mtu: u16, packet_information: bool) -> c_int { log::set_max_level(args.verbosity.into()); if let Err(err) = log::set_boxed_logger(Box::::default()) { - log::warn!("set logger error: {}", err); + log::debug!("set logger error: {}", err); } let shutdown_token = tokio_util::sync::CancellationToken::new(); - { - if let Ok(mut lock) = TUN_QUIT.lock() { - if lock.is_some() { - return -1; - } - *lock = Some(shutdown_token.clone()); - } else { - return -2; + if let Ok(mut lock) = TUN_QUIT.lock() { + if lock.is_some() { + log::error!("tun2proxy already started"); + return -1; } + *lock = Some(shutdown_token.clone()); + } else { + log::error!("failed to lock tun2proxy quit token"); + return -2; } let Ok(rt) = tokio::runtime::Builder::new_multi_thread().enable_all().build() else { + log::error!("failed to create tokio runtime with"); return -3; }; - let res = rt.block_on(async move { - if let Err(err) = desktop_run_async(args, MTU, false, shutdown_token).await { + match rt.block_on(async move { + if let Err(err) = general_run_async(args, tun_mtu, packet_information, shutdown_token).await { log::error!("main loop error: {}", err); return Err(err); } Ok(()) - }); - match res { + }) { Ok(_) => 0, - Err(_) => -4, + Err(e) => { + log::error!("failed to run tun2proxy with error: {:?}", e); + -4 + } } } /// Run the tun2proxy component with some arguments. -pub async fn desktop_run_async( +pub async fn general_run_async( args: Args, tun_mtu: u16, _packet_information: bool, @@ -153,7 +154,8 @@ pub async fn desktop_run_async( let device = tun::create_as_async(&tun_config)?; #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] - if let Ok(tun_name) = device.tun_name() { + if let Ok(tun_name) = tun::AbstractDevice::tun_name(&*device) { + // Above line is equivalent to: `use tun::AbstractDevice; if let Ok(tun_name) = device.tun_name() {` tproxy_args = tproxy_args.tun_name(&tun_name); } @@ -205,6 +207,10 @@ pub async fn desktop_run_async( /// Shutdown the tun2proxy component. #[no_mangle] pub unsafe extern "C" fn tun2proxy_with_name_stop() -> c_int { + tun2proxy_stop_internal() +} + +pub(crate) fn tun2proxy_stop_internal() -> c_int { if let Ok(mut lock) = TUN_QUIT.lock() { if let Some(shutdown_token) = lock.take() { shutdown_token.cancel(); diff --git a/src/lib.rs b/src/lib.rs index 1972b9c..f211110 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,25 +40,17 @@ pub use { #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; -#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] -pub use desktop_api::desktop_run_async; - -#[cfg(any(target_os = "ios", target_os = "android"))] -pub use mobile_api::{desktop_run_async, mobile_run, mobile_stop}; - -#[cfg(target_os = "macos")] -pub use mobile_api::{mobile_run, mobile_stop}; +pub use general_api::general_run_async; mod android; -mod apple; mod args; -mod desktop_api; mod directions; mod dns; mod dump_logger; mod error; +mod general_api; mod http; -mod mobile_api; +mod mobile; mod no_proxy; mod proxy_handler; mod session_info; diff --git a/src/apple.rs b/src/mobile.rs similarity index 82% rename from src/apple.rs rename to src/mobile.rs index 155b101..3747d67 100644 --- a/src/apple.rs +++ b/src/mobile.rs @@ -27,11 +27,6 @@ pub unsafe extern "C" fn tun2proxy_with_fd_run( dns_strategy: ArgDns, verbosity: ArgVerbosity, ) -> c_int { - log::set_max_level(verbosity.into()); - if let Err(err) = log::set_boxed_logger(Box::::default()) { - log::warn!("failed to set logger: {:?}", err); - } - let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); let proxy = ArgProxy::try_from(proxy_url).unwrap(); @@ -42,7 +37,7 @@ pub unsafe extern "C" fn tun2proxy_with_fd_run( .dns(dns_strategy) .verbosity(verbosity); - crate::mobile_api::mobile_run(args, tun_mtu, packet_information) + crate::general_api::general_run_for_api(args, tun_mtu, packet_information) } /// # Safety @@ -50,5 +45,5 @@ pub unsafe extern "C" fn tun2proxy_with_fd_run( /// Shutdown the tun2proxy component. #[no_mangle] pub unsafe extern "C" fn tun2proxy_with_fd_stop() -> c_int { - crate::mobile_api::mobile_stop() + crate::general_api::tun2proxy_stop_internal() } diff --git a/src/mobile_api.rs b/src/mobile_api.rs deleted file mode 100644 index 3f885d5..0000000 --- a/src/mobile_api.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![cfg(any(target_os = "ios", target_os = "android", target_os = "macos"))] - -use crate::Args; -use std::os::raw::c_int; - -static TUN_QUIT: std::sync::Mutex> = std::sync::Mutex::new(None); - -/// Dummy function to make the build pass. -#[doc(hidden)] -#[cfg(not(target_os = "macos"))] -pub async fn desktop_run_async(_: Args, _: u16, _: bool, _: tokio_util::sync::CancellationToken) -> std::io::Result<()> { - Ok(()) -} - -pub async fn mobile_run_async( - args: Args, - tun_mtu: u16, - _packet_information: bool, - shutdown_token: tokio_util::sync::CancellationToken, -) -> std::io::Result<()> { - let mut config = tun::Configuration::default(); - - #[cfg(unix)] - if let Some(fd) = args.tun_fd { - config.raw_fd(fd); - if let Some(v) = args.close_fd_on_drop { - config.close_fd_on_drop(v); - }; - } else if let Some(ref tun) = args.tun { - config.tun_name(tun); - } - #[cfg(windows)] - if let Some(ref tun) = args.tun { - config.tun_name(tun); - } - - #[cfg(any(target_os = "ios", target_os = "macos"))] - config.platform_config(|config| { - config.packet_information(_packet_information); - }); - - let device = tun::create_as_async(&config).map_err(std::io::Error::from)?; - let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); - - Ok(join_handle.await.map_err(std::io::Error::from)??) -} - -pub fn mobile_run(args: Args, tun_mtu: u16, _packet_information: bool) -> c_int { - let shutdown_token = tokio_util::sync::CancellationToken::new(); - if let Ok(mut lock) = TUN_QUIT.lock() { - if lock.is_some() { - log::error!("tun2proxy already started"); - return -1; - } - *lock = Some(shutdown_token.clone()); - } else { - log::error!("failed to lock tun2proxy quit token"); - return -2; - } - - let Ok(rt) = tokio::runtime::Builder::new_multi_thread().enable_all().build() else { - log::error!("failed to create tokio runtime with"); - return -1; - }; - match rt.block_on(mobile_run_async(args, tun_mtu, _packet_information, shutdown_token)) { - Ok(_) => 0, - Err(e) => { - log::error!("failed to run tun2proxy with error: {:?}", e); - -2 - } - } -} - -pub fn mobile_stop() -> c_int { - if let Ok(mut lock) = TUN_QUIT.lock() { - if let Some(shutdown_token) = lock.take() { - shutdown_token.cancel(); - return 0; - } - } - -1 -} diff --git a/src/win_svc.rs b/src/win_svc.rs index e775049..ac87417 100644 --- a/src/win_svc.rs +++ b/src/win_svc.rs @@ -78,7 +78,7 @@ fn run_service(_arguments: Vec) -> Result<(), crate::BoxErro } unsafe { crate::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = crate::desktop_run_async(args, tun::DEFAULT_MTU, false, shutdown_token).await { + if let Err(err) = crate::general_run_async(args, tun::DEFAULT_MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); } Ok::<(), crate::Error>(()) From bac54ec56c844267768dd257252c5e622a3f10bd Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 3 Jan 2025 02:26:51 +0800 Subject: [PATCH 18/63] Bump version 0.7.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e93e99b..c2a9df3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.0" +version = "0.7.1" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 51de01854bf9429ba420d91479753fa7ad3a64a3 Mon Sep 17 00:00:00 2001 From: Mostafa Kazemi <32548292+mkay1375@users.noreply.github.com> Date: Fri, 3 Jan 2025 06:30:19 +0330 Subject: [PATCH 19/63] Fix typo in comment (#178) --- src/http.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http.rs b/src/http.rs index 2b5f491..6c5f0d6 100644 --- a/src/http.rs +++ b/src/http.rs @@ -252,7 +252,7 @@ impl HttpConnection { } // The HTTP/1.1 expected to be keep alive waiting for the next frame so, we must - // compute the lenght of the response in order to detect the next frame (response) + // compute the length of the response in order to detect the next frame (response) // [RFC-9112](https://datatracker.ietf.org/doc/html/rfc9112#body.content-length) // Transfer-Encoding isn't supported yet From ecd1ab80bfa0f94c743e423f5e7cbf062c2a5478 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:10:14 +0800 Subject: [PATCH 20/63] base64 removed --- Cargo.toml | 2 +- src/http.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c2a9df3..e7edc93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ udpgw = [] [dependencies] async-trait = "0.1" -base64 = { version = "0.22" } +base64easy = "0.1" chrono = "0.4" clap = { version = "4", features = ["derive", "wrap_help", "color"] } ctrlc2 = { version = "3", features = ["tokio", "termination"] } diff --git a/src/http.rs b/src/http.rs index 6c5f0d6..0b6adf5 100644 --- a/src/http.rs +++ b/src/http.rs @@ -4,7 +4,6 @@ use crate::{ proxy_handler::{ProxyHandler, ProxyHandlerManager}, session_info::{IpProtocol, SessionInfo}, }; -use base64::Engine; use httparse::Response; use socks5_impl::protocol::UserKey; use std::{ @@ -141,8 +140,7 @@ impl HttpConnection { .extend(format!("{}: {}\r\n", PROXY_AUTHORIZATION, response.to_header_string()).as_bytes()); } AuthenticationScheme::Basic => { - let cred = format!("{}:{}", credentials.username, credentials.password); - let auth_b64 = base64::engine::general_purpose::STANDARD.encode(cred); + let auth_b64 = base64easy::encode(credentials.to_string(), base64easy::EngineKind::Standard); self.server_outbuf .extend(format!("{}: Basic {}\r\n", PROXY_AUTHORIZATION, auth_b64).as_bytes()); } From e939f5f3dcfe4c2671fbb1ba8bf39c9d23c5fb45 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:15:05 +0800 Subject: [PATCH 21/63] remove mod mobile --- cbindgen.toml | 3 +-- src/general_api.rs | 48 +++++++++++++++++++++++++++++++++++++++------ src/lib.rs | 1 - src/mobile.rs | 49 ---------------------------------------------- 4 files changed, 43 insertions(+), 58 deletions(-) delete mode 100644 src/mobile.rs diff --git a/cbindgen.toml b/cbindgen.toml index 10e4235..50ea65f 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -6,8 +6,7 @@ include = [ "tun2proxy_run_with_cli", "tun2proxy_with_fd_run", "tun2proxy_with_name_run", - "tun2proxy_with_name_stop", - "tun2proxy_with_fd_stop", + "tun2proxy_stop", "tun2proxy_set_log_callback", "tun2proxy_set_traffic_status_callback", ] diff --git a/src/general_api.rs b/src/general_api.rs index 9385f48..d4bc0ce 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -2,8 +2,7 @@ use crate::{ args::{ArgDns, ArgProxy}, ArgVerbosity, Args, }; -use std::os::raw::{c_char, c_int}; -use tun::DEFAULT_MTU as MTU; +use std::os::raw::{c_char, c_int, c_ushort}; static TUN_QUIT: std::sync::Mutex> = std::sync::Mutex::new(None); @@ -39,7 +38,42 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( #[cfg(target_os = "linux")] args.setup(_root_privilege); - general_run_for_api(args, MTU, false) + general_run_for_api(args, tun::DEFAULT_MTU, false) +} + +/// # Safety +/// +/// Run the tun2proxy component with some arguments. +/// Parameters: +/// - proxy_url: the proxy url, e.g. "socks5://127.0.0.1:1080" +/// - tun_fd: the tun file descriptor, it will be owned by tun2proxy +/// - close_fd_on_drop: whether close the tun_fd on drop +/// - packet_information: indicates whether exists packet information in packet from TUN device +/// - tun_mtu: the tun mtu +/// - dns_strategy: the dns strategy, see ArgDns enum +/// - verbosity: the verbosity level, see ArgVerbosity enum +#[cfg(unix)] +#[no_mangle] +pub unsafe extern "C" fn tun2proxy_with_fd_run( + proxy_url: *const c_char, + tun_fd: c_int, + close_fd_on_drop: bool, + packet_information: bool, + tun_mtu: c_ushort, + dns_strategy: ArgDns, + verbosity: ArgVerbosity, +) -> c_int { + let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); + let proxy = ArgProxy::try_from(proxy_url).unwrap(); + + let mut args = Args::default(); + args.proxy(proxy) + .tun_fd(Some(tun_fd)) + .close_fd_on_drop(close_fd_on_drop) + .dns(dns_strategy) + .verbosity(verbosity); + + general_run_for_api(args, tun_mtu, packet_information) } /// # Safety @@ -47,13 +81,15 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( /// Parameters: /// - cli_args: The command line arguments, /// e.g. `tun2proxy-bin --setup --proxy socks5://127.0.0.1:1080 --bypass 98.76.54.0/24 --dns over-tcp --verbosity trace` +/// - tun_mtu: The MTU of the TUN device, e.g. 1500 +/// - packet_information: Whether exists packet information in packet from TUN device #[no_mangle] -pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char) -> c_int { +pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char, tun_mtu: c_ushort, packet_information: bool) -> c_int { let Ok(cli_args) = std::ffi::CStr::from_ptr(cli_args).to_str() else { return -5; }; let args = ::parse_from(cli_args.split_whitespace()); - general_run_for_api(args, MTU, false) + general_run_for_api(args, tun_mtu, packet_information) } pub fn general_run_for_api(args: Args, tun_mtu: u16, packet_information: bool) -> c_int { @@ -206,7 +242,7 @@ pub async fn general_run_async( /// /// Shutdown the tun2proxy component. #[no_mangle] -pub unsafe extern "C" fn tun2proxy_with_name_stop() -> c_int { +pub unsafe extern "C" fn tun2proxy_stop() -> c_int { tun2proxy_stop_internal() } diff --git a/src/lib.rs b/src/lib.rs index f211110..40c6774 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,6 @@ mod dump_logger; mod error; mod general_api; mod http; -mod mobile; mod no_proxy; mod proxy_handler; mod session_info; diff --git a/src/mobile.rs b/src/mobile.rs deleted file mode 100644 index 3747d67..0000000 --- a/src/mobile.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![cfg(any(target_os = "android", target_os = "ios", target_os = "macos"))] - -use crate::{ - args::{ArgDns, ArgProxy}, - ArgVerbosity, Args, -}; -use std::os::raw::{c_char, c_int, c_ushort}; - -/// # Safety -/// -/// Run the tun2proxy component with some arguments. -/// Parameters: -/// - proxy_url: the proxy url, e.g. "socks5://127.0.0.1:1080" -/// - tun_fd: the tun file descriptor, it will be owned by tun2proxy -/// - close_fd_on_drop: whether close the tun_fd on drop -/// - packet_information: whether exists packet information in tun_fd -/// - tun_mtu: the tun mtu -/// - dns_strategy: the dns strategy, see ArgDns enum -/// - verbosity: the verbosity level, see ArgVerbosity enum -#[no_mangle] -pub unsafe extern "C" fn tun2proxy_with_fd_run( - proxy_url: *const c_char, - tun_fd: c_int, - close_fd_on_drop: bool, - packet_information: bool, - tun_mtu: c_ushort, - dns_strategy: ArgDns, - verbosity: ArgVerbosity, -) -> c_int { - let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); - let proxy = ArgProxy::try_from(proxy_url).unwrap(); - - let mut args = Args::default(); - args.proxy(proxy) - .tun_fd(Some(tun_fd)) - .close_fd_on_drop(close_fd_on_drop) - .dns(dns_strategy) - .verbosity(verbosity); - - crate::general_api::general_run_for_api(args, tun_mtu, packet_information) -} - -/// # Safety -/// -/// Shutdown the tun2proxy component. -#[no_mangle] -pub unsafe extern "C" fn tun2proxy_with_fd_stop() -> c_int { - crate::general_api::tun2proxy_stop_internal() -} From 8ba2c1a2b73e934c5033b3e638895f3f51f5cc5e Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:30:41 +0800 Subject: [PATCH 22/63] Bump version 0.7.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e7edc93..0bc479f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.1" +version = "0.7.2" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From f8c902b61c8667bbd5b8c962014c1133f615f7a7 Mon Sep 17 00:00:00 2001 From: Ahmed Elsayed Date: Tue, 7 Jan 2025 15:03:25 +0200 Subject: [PATCH 23/63] use shlex instead of split whitespaces. (#179) --- Cargo.toml | 1 + src/general_api.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0bc479f..58ca7ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ ipstack = { version = "0.1" } log = { version = "0.4", features = ["std"] } mimalloc = { version = "0.1", default-features = false, optional = true } percent-encoding = "2" +shlex = "1.3.0" socks5-impl = { version = "0.6", default-features = false, features = [ "tokio", ] } diff --git a/src/general_api.rs b/src/general_api.rs index d4bc0ce..665026e 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -88,7 +88,11 @@ pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char, tu let Ok(cli_args) = std::ffi::CStr::from_ptr(cli_args).to_str() else { return -5; }; - let args = ::parse_from(cli_args.split_whitespace()); + let Some(args) = shlex::split(cli_args) else { + log::error!("Failed to split CLI arguments"); + return -6; + }; + let args = ::parse_from(args); general_run_for_api(args, tun_mtu, packet_information) } From 04db15f5532ad53d88091f82994a2da8fb9450a1 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 7 Jan 2025 21:15:44 +0800 Subject: [PATCH 24/63] Bump version 0.7.3 --- Cargo.toml | 2 +- src/general_api.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 58ca7ac..8b71fb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.2" +version = "0.7.3" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" diff --git a/src/general_api.rs b/src/general_api.rs index 665026e..c877fd4 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -86,6 +86,7 @@ pub unsafe extern "C" fn tun2proxy_with_fd_run( #[no_mangle] pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char, tun_mtu: c_ushort, packet_information: bool) -> c_int { let Ok(cli_args) = std::ffi::CStr::from_ptr(cli_args).to_str() else { + log::error!("Failed to convert CLI arguments to string"); return -5; }; let Some(args) = shlex::split(cli_args) else { From 5287bef3c0b1c7d14af6c242a5a5392e3697cd8d Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 10 Jan 2025 18:43:55 +0800 Subject: [PATCH 25/63] PI issues for macOS --- src/bin/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index e690f6c..0ed98c7 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,4 +1,3 @@ -use tun::DEFAULT_MTU as MTU; use tun2proxy::{Args, BoxError}; fn main() -> Result<(), BoxError> { @@ -50,7 +49,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { } unsafe { tun2proxy::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = tun2proxy::general_run_async(args, MTU, false, shutdown_token).await { + if let Err(err) = tun2proxy::general_run_async(args, tun::DEFAULT_MTU, cfg!(target_os = "macos"), shutdown_token).await { log::error!("main loop error: {}", err); } } From 6b038c2a80a06b493a4d0ebab74899e5fc0407ed Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:09:37 +0800 Subject: [PATCH 26/63] Bump version 0.7.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8b71fb7..993b959 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.3" +version = "0.7.4" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From c5d907551ba1765ae32ec8176e42e1935ef15eba Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 12 Feb 2025 20:37:49 +0800 Subject: [PATCH 27/63] ubuntu-20.04 used in publish script --- .github/workflows/publish-exe.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-exe.yml b/.github/workflows/publish-exe.yml index c9730b9..31312e6 100644 --- a/.github/workflows/publish-exe.yml +++ b/.github/workflows/publish-exe.yml @@ -34,7 +34,7 @@ jobs: include: - target: x86_64-unknown-linux-gnu - host_os: ubuntu-latest + host_os: ubuntu-20.04 - target: x86_64-unknown-linux-musl host_os: ubuntu-latest - target: i686-unknown-linux-musl @@ -73,7 +73,7 @@ jobs: rustup target add ${{ matrix.target }} fi cargo install cbindgen - if [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then + if [[ "${{ contains(matrix.host_os, 'ubuntu') }}" == "true" && "${{ matrix.host_os }}" != "ubuntu-20.04" ]]; then sudo .github/workflows/install-cross.sh fi @@ -81,7 +81,7 @@ jobs: if: ${{ !cancelled() }} shell: bash run: | - if [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then + if [[ "${{ contains(matrix.host_os, 'ubuntu') }}" == "true" && "${{ matrix.host_os }}" != "ubuntu-20.04" ]]; then cross build --all-features --release --target ${{ matrix.target }} else if [[ "${{ matrix.target }}" == "x86_64-win7-windows-msvc" || "${{ matrix.target }}" == "i686-win7-windows-msvc" ]]; then @@ -105,7 +105,7 @@ jobs: ./build-apple.sh zip -r mypubdir4/tun2proxy-apple-xcframework.zip ./tun2proxy.xcframework/ fi - elif [[ "${{ matrix.host_os }}" == "ubuntu-latest" ]]; then + elif [[ "${{ contains(matrix.host_os, 'ubuntu') }}" == "true" ]]; then zip -j mypubdir4/tun2proxy-${{ matrix.target }}.zip target/${{ matrix.target }}/release/tun2proxy-bin target/${{ matrix.target }}/release/udpgw-server README.md target/tun2proxy.h target/${{ matrix.target }}/release/libtun2proxy.so if [[ "${{ matrix.target }}" == "x86_64-unknown-linux-gnu" ]]; then ./build-android.sh From 9a018f2393b727ffd52720cc7ae61b06a72f65d7 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 18 Feb 2025 13:23:04 +0800 Subject: [PATCH 28/63] update ipstack --- Cargo.toml | 4 ++-- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 993b959..691c15d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ env_logger = "0.11" hashlink = "0.10" hickory-proto = "0.24" httparse = "1" -ipstack = { version = "0.1" } +ipstack = { version = "0.2" } log = { version = "0.4", features = ["std"] } mimalloc = { version = "0.1", default-features = false, optional = true } percent-encoding = "2" @@ -75,7 +75,7 @@ nix = { version = "0.29", default-features = false, features = [ ] } [target.'cfg(target_os = "windows")'.dependencies] -windows-service = "0.7" +windows-service = "0.8" [profile.release] strip = "symbols" diff --git a/src/lib.rs b/src/lib.rs index 40c6774..fac9095 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -375,7 +375,7 @@ where } IpStackStream::UnknownTransport(u) => { let len = u.payload().len(); - log::info!("#0 unhandled transport - Ip Protocol 0x{:02X}, length {}", u.ip_protocol(), len); + log::info!("#0 unhandled transport - Ip Protocol {:?}, length {}", u.ip_protocol(), len); continue; } IpStackStream::UnknownNetwork(pkt) => { From fd7dca998897dddc3130b6d539674e70585784aa Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 27 Feb 2025 13:53:39 +0800 Subject: [PATCH 29/63] unsafe_in_unsafe issues --- .github/workflows/rust.yml | 1 + Cargo.toml | 4 ++-- src/android.rs | 8 ++++---- src/bin/main.rs | 4 ++-- src/bin/udpgw_server.rs | 4 ++-- src/dns.rs | 2 +- src/dump_logger.rs | 4 ++-- src/general_api.rs | 20 ++++++++++---------- src/http.rs | 2 +- src/lib.rs | 6 +++--- src/socket_transfer.rs | 4 ++-- src/socks.rs | 2 +- src/traffic_status.rs | 4 ++-- src/udpgw.rs | 4 ++-- src/virtual_dns.rs | 2 +- src/win_svc.rs | 2 +- 16 files changed, 37 insertions(+), 36 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 693d55c..75d5c93 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -77,6 +77,7 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable - name: Install cargo lipo and rust compiler for ios target if: ${{ !cancelled() }} run: | diff --git a/Cargo.toml b/Cargo.toml index 691c15d..36a5784 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "tun2proxy" version = "0.7.4" -edition = "2021" +edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" homepage = "https://github.com/tun2proxy/tun2proxy" authors = ["B. Blechschmidt", "ssrlive"] description = "Tunnel interface to proxy" readme = "README.md" -rust-version = "1.80" +rust-version = "1.85" [lib] crate-type = ["staticlib", "cdylib", "lib"] diff --git a/src/android.rs b/src/android.rs index 21dd5eb..030e921 100644 --- a/src/android.rs +++ b/src/android.rs @@ -1,14 +1,14 @@ #![cfg(target_os = "android")] use crate::{ + Args, args::ArgProxy, error::{Error, Result}, - Args, }; use jni::{ + JNIEnv, objects::{JClass, JString}, sys::{jboolean, jchar, jint}, - JNIEnv, }; /// # Safety @@ -21,7 +21,7 @@ use jni::{ /// - tun_mtu: the tun mtu /// - dns_strategy: the dns strategy, see ArgDns enum /// - verbosity: the verbosity level, see ArgVerbosity enum -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run( mut env: JNIEnv, _clazz: JClass, @@ -58,7 +58,7 @@ pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run( /// # Safety /// /// Shutdown tun2proxy -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_stop(_env: JNIEnv, _: JClass) -> jint { crate::general_api::tun2proxy_stop_internal() } diff --git a/src/bin/main.rs b/src/bin/main.rs index 0ed98c7..b8ad59e 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -44,7 +44,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { } unsafe extern "C" fn traffic_cb(status: *const tun2proxy::TrafficStatus, _: *mut std::ffi::c_void) { - let status = &*status; + let status = unsafe { &*status }; log::debug!("Traffic: ▲ {} : ▼ {}", status.tx, status.rx); } unsafe { tun2proxy::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; @@ -79,7 +79,7 @@ async fn namespace_proxy_main( _args: Args, _shutdown_token: tokio_util::sync::CancellationToken, ) -> Result { - use nix::fcntl::{open, OFlag}; + use nix::fcntl::{OFlag, open}; use nix::sys::stat::Mode; use std::os::fd::AsRawFd; diff --git a/src/bin/udpgw_server.rs b/src/bin/udpgw_server.rs index 9cf144a..370897a 100644 --- a/src/bin/udpgw_server.rs +++ b/src/bin/udpgw_server.rs @@ -3,14 +3,14 @@ use std::net::SocketAddr; use tokio::{ io::AsyncWriteExt, net::{ - tcp::{ReadHalf, WriteHalf}, UdpSocket, + tcp::{ReadHalf, WriteHalf}, }, sync::mpsc::{Receiver, Sender}, }; use tun2proxy::{ - udpgw::{Packet, UdpFlag}, ArgVerbosity, BoxError, Error, Result, + udpgw::{Packet, UdpFlag}, }; pub(crate) const CLIENT_DISCONNECT_TIMEOUT: tokio::time::Duration = std::time::Duration::from_secs(60); diff --git a/src/dns.rs b/src/dns.rs index e18d218..6f9470d 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -1,6 +1,6 @@ use hickory_proto::{ op::{Message, MessageType, ResponseCode}, - rr::{record_type::RecordType, Name, RData, Record}, + rr::{Name, RData, Record, record_type::RecordType}, }; use std::{net::IpAddr, str::FromStr}; diff --git a/src/dump_logger.rs b/src/dump_logger.rs index b04ff09..aba05dd 100644 --- a/src/dump_logger.rs +++ b/src/dump_logger.rs @@ -9,7 +9,7 @@ pub(crate) static DUMP_CALLBACK: Mutex> = Mutex::new(None); /// # Safety /// /// set dump log info callback. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn tun2proxy_set_log_callback( callback: Option, ctx: *mut c_void, @@ -23,7 +23,7 @@ pub struct DumpCallback(Option> = /// - dns_strategy: the dns strategy, see ArgDns enum /// - root_privilege: whether to run with root privilege /// - verbosity: the verbosity level, see ArgVerbosity enum -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn tun2proxy_with_name_run( proxy_url: *const c_char, tun: *const c_char, @@ -25,12 +25,12 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( _root_privilege: bool, verbosity: ArgVerbosity, ) -> c_int { - let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); + let proxy_url = unsafe { std::ffi::CStr::from_ptr(proxy_url) }.to_str().unwrap(); let proxy = ArgProxy::try_from(proxy_url).unwrap(); - let tun = std::ffi::CStr::from_ptr(tun).to_str().unwrap().to_string(); + let tun = unsafe { std::ffi::CStr::from_ptr(tun) }.to_str().unwrap().to_string(); let mut args = Args::default(); - if let Ok(bypass) = std::ffi::CStr::from_ptr(bypass).to_str() { + if let Ok(bypass) = unsafe { std::ffi::CStr::from_ptr(bypass) }.to_str() { args.bypass(bypass.parse().unwrap()); } args.proxy(proxy).tun(tun).dns(dns_strategy).verbosity(verbosity); @@ -53,7 +53,7 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( /// - dns_strategy: the dns strategy, see ArgDns enum /// - verbosity: the verbosity level, see ArgVerbosity enum #[cfg(unix)] -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn tun2proxy_with_fd_run( proxy_url: *const c_char, tun_fd: c_int, @@ -63,7 +63,7 @@ pub unsafe extern "C" fn tun2proxy_with_fd_run( dns_strategy: ArgDns, verbosity: ArgVerbosity, ) -> c_int { - let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); + let proxy_url = unsafe { std::ffi::CStr::from_ptr(proxy_url) }.to_str().unwrap(); let proxy = ArgProxy::try_from(proxy_url).unwrap(); let mut args = Args::default(); @@ -83,9 +83,9 @@ pub unsafe extern "C" fn tun2proxy_with_fd_run( /// e.g. `tun2proxy-bin --setup --proxy socks5://127.0.0.1:1080 --bypass 98.76.54.0/24 --dns over-tcp --verbosity trace` /// - tun_mtu: The MTU of the TUN device, e.g. 1500 /// - packet_information: Whether exists packet information in packet from TUN device -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char, tun_mtu: c_ushort, packet_information: bool) -> c_int { - let Ok(cli_args) = std::ffi::CStr::from_ptr(cli_args).to_str() else { + let Ok(cli_args) = unsafe { std::ffi::CStr::from_ptr(cli_args) }.to_str() else { log::error!("Failed to convert CLI arguments to string"); return -5; }; @@ -246,7 +246,7 @@ pub async fn general_run_async( /// # Safety /// /// Shutdown the tun2proxy component. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn tun2proxy_stop() -> c_int { tun2proxy_stop_internal() } diff --git a/src/http.rs b/src/http.rs index 0b6adf5..caf79e9 100644 --- a/src/http.rs +++ b/src/http.rs @@ -7,7 +7,7 @@ use crate::{ use httparse::Response; use socks5_impl::protocol::UserKey; use std::{ - collections::{hash_map::RandomState, HashMap, VecDeque}, + collections::{HashMap, VecDeque, hash_map::RandomState}, iter::FromIterator, net::SocketAddr, str, diff --git a/src/lib.rs b/src/lib.rs index fac9095..e9b2bfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,18 +22,18 @@ use std::{ use tokio::{ io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, net::{TcpSocket, TcpStream, UdpSocket}, - sync::{mpsc::Receiver, Mutex}, + sync::{Mutex, mpsc::Receiver}, }; pub use tokio_util::sync::CancellationToken; use tproxy_config::is_private_ip; use udp_stream::UdpStream; #[cfg(feature = "udpgw")] -use udpgw::{UdpGwClientStream, UdpGwResponse, UDPGW_KEEPALIVE_TIME, UDPGW_MAX_CONNECTIONS}; +use udpgw::{UDPGW_KEEPALIVE_TIME, UDPGW_MAX_CONNECTIONS, UdpGwClientStream, UdpGwResponse}; pub use { args::{ArgDns, ArgProxy, ArgVerbosity, Args, ProxyType}, error::{BoxError, Error, Result}, - traffic_status::{tun2proxy_set_traffic_status_callback, TrafficStatus}, + traffic_status::{TrafficStatus, tun2proxy_set_traffic_status_callback}, }; #[cfg(feature = "mimalloc")] diff --git a/src/socket_transfer.rs b/src/socket_transfer.rs index f10b3f2..fcc2932 100644 --- a/src/socket_transfer.rs +++ b/src/socket_transfer.rs @@ -1,10 +1,10 @@ #![cfg(target_os = "linux")] -use crate::{error, SocketDomain, SocketProtocol}; +use crate::{SocketDomain, SocketProtocol, error}; use nix::{ errno::Errno, fcntl::{self, FdFlag}, - sys::socket::{cmsg_space, getsockopt, recvmsg, sendmsg, sockopt, ControlMessage, ControlMessageOwned, MsgFlags, SockType}, + sys::socket::{ControlMessage, ControlMessageOwned, MsgFlags, SockType, cmsg_space, getsockopt, recvmsg, sendmsg, sockopt}, }; use serde::{Deserialize, Serialize}; use std::{ diff --git a/src/socks.rs b/src/socks.rs index 3800c6a..9c8ad2d 100644 --- a/src/socks.rs +++ b/src/socks.rs @@ -4,7 +4,7 @@ use crate::{ proxy_handler::{ProxyHandler, ProxyHandlerManager}, session_info::SessionInfo, }; -use socks5_impl::protocol::{self, handshake, password_method, Address, AuthMethod, StreamOperation, UserKey, Version}; +use socks5_impl::protocol::{self, Address, AuthMethod, StreamOperation, UserKey, Version, handshake, password_method}; use std::{collections::VecDeque, net::SocketAddr, sync::Arc}; use tokio::sync::Mutex; diff --git a/src/traffic_status.rs b/src/traffic_status.rs index 3117a22..1922401 100644 --- a/src/traffic_status.rs +++ b/src/traffic_status.rs @@ -5,7 +5,7 @@ use std::sync::{LazyLock, Mutex}; /// # Safety /// /// set traffic status callback. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn tun2proxy_set_traffic_status_callback( send_interval_secs: u32, callback: Option, @@ -34,7 +34,7 @@ struct TrafficStatusCallback(Option(); diff --git a/src/virtual_dns.rs b/src/virtual_dns.rs index 8dae2a7..7794d37 100644 --- a/src/virtual_dns.rs +++ b/src/virtual_dns.rs @@ -1,5 +1,5 @@ use crate::error::Result; -use hashlink::{linked_hash_map::RawEntryMut, LruCache}; +use hashlink::{LruCache, linked_hash_map::RawEntryMut}; use std::{ collections::HashMap, convert::TryInto, diff --git a/src/win_svc.rs b/src/win_svc.rs index ac87417..a4090e3 100644 --- a/src/win_svc.rs +++ b/src/win_svc.rs @@ -73,7 +73,7 @@ fn run_service(_arguments: Vec) -> Result<(), crate::BoxErro let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?; rt.block_on(async { unsafe extern "C" fn traffic_cb(status: *const crate::TrafficStatus, _: *mut std::ffi::c_void) { - let status = &*status; + let status = unsafe { &*status }; log::debug!("Traffic: ▲ {} : ▼ {}", status.tx, status.rx); } unsafe { crate::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; From e556f7657b92b8e20a67220eca41ee51a84de184 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 27 Feb 2025 14:56:14 +0800 Subject: [PATCH 30/63] Bump version 0.7.5 --- .github/workflows/publish-exe.yml | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-exe.yml b/.github/workflows/publish-exe.yml index 31312e6..dc2f007 100644 --- a/.github/workflows/publish-exe.yml +++ b/.github/workflows/publish-exe.yml @@ -34,7 +34,7 @@ jobs: include: - target: x86_64-unknown-linux-gnu - host_os: ubuntu-20.04 + host_os: ubuntu-22.04 - target: x86_64-unknown-linux-musl host_os: ubuntu-latest - target: i686-unknown-linux-musl @@ -73,7 +73,7 @@ jobs: rustup target add ${{ matrix.target }} fi cargo install cbindgen - if [[ "${{ contains(matrix.host_os, 'ubuntu') }}" == "true" && "${{ matrix.host_os }}" != "ubuntu-20.04" ]]; then + if [[ "${{ contains(matrix.host_os, 'ubuntu') }}" == "true" && "${{ matrix.host_os }}" != "ubuntu-22.04" ]]; then sudo .github/workflows/install-cross.sh fi @@ -81,7 +81,7 @@ jobs: if: ${{ !cancelled() }} shell: bash run: | - if [[ "${{ contains(matrix.host_os, 'ubuntu') }}" == "true" && "${{ matrix.host_os }}" != "ubuntu-20.04" ]]; then + if [[ "${{ contains(matrix.host_os, 'ubuntu') }}" == "true" && "${{ matrix.host_os }}" != "ubuntu-22.04" ]]; then cross build --all-features --release --target ${{ matrix.target }} else if [[ "${{ matrix.target }}" == "x86_64-win7-windows-msvc" || "${{ matrix.target }}" == "i686-win7-windows-msvc" ]]; then diff --git a/Cargo.toml b/Cargo.toml index 36a5784..b1d96ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.4" +version = "0.7.5" edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 68716bdc9fa23fd52e0abd11a9ef0c311f979a82 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 7 Mar 2025 12:48:39 +0800 Subject: [PATCH 31/63] update deps --- .github/workflows/auto-merge.yaml | 2 +- Cargo.toml | 4 ++-- src/error.rs | 4 ---- src/lib.rs | 10 ++++++-- src/socket_transfer.rs | 39 ++++++++++++++++++++----------- 5 files changed, 37 insertions(+), 22 deletions(-) diff --git a/.github/workflows/auto-merge.yaml b/.github/workflows/auto-merge.yaml index c39e8a6..1280f57 100644 --- a/.github/workflows/auto-merge.yaml +++ b/.github/workflows/auto-merge.yaml @@ -15,6 +15,6 @@ jobs: - name: Auto approve pull request, then squash and merge uses: ahmadnassri/action-dependabot-auto-merge@v2 with: - target: minor + # target: minor # here `PAT_REPO_ADMIN` is a user's passkey provided by github. github-token: ${{ secrets.PAT_REPO_ADMIN }} diff --git a/Cargo.toml b/Cargo.toml index b1d96ad..750989c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,10 +60,10 @@ serde_json = "1" [target.'cfg(target_os="linux")'.dependencies] serde = { version = "1", features = ["derive"] } -bincode = "1" +bincode = "2" [target.'cfg(target_os="android")'.dependencies] -android_logger = "0.14" +android_logger = "0.15" jni = { version = "0.21", default-features = false } [target.'cfg(unix)'.dependencies] diff --git a/src/error.rs b/src/error.rs index 755ee0c..c93ecb5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,10 +43,6 @@ pub enum Error { #[error("std::num::ParseIntError {0:?}")] IntParseError(#[from] std::num::ParseIntError), - - #[cfg(target_os = "linux")] - #[error("bincode::Error {0:?}")] - BincodeError(#[from] bincode::Error), } impl From<&str> for Error { diff --git a/src/lib.rs b/src/lib.rs index e9b2bfb..c62e08b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,10 @@ use std::sync::atomic::Ordering::Relaxed; #[allow(unused)] #[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)] -#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + target_os = "linux", + derive(bincode::Encode, bincode::Decode, serde::Serialize, serde::Deserialize) +)] pub enum SocketProtocol { Tcp, Udp, @@ -77,7 +80,10 @@ pub enum SocketProtocol { #[allow(unused)] #[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)] -#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + target_os = "linux", + derive(bincode::Encode, bincode::Decode, serde::Serialize, serde::Deserialize) +)] pub enum SocketDomain { IpV4, IpV6, diff --git a/src/socket_transfer.rs b/src/socket_transfer.rs index fcc2932..e069b1d 100644 --- a/src/socket_transfer.rs +++ b/src/socket_transfer.rs @@ -16,14 +16,14 @@ use tokio::net::{TcpSocket, UdpSocket, UnixDatagram}; const REQUEST_BUFFER_SIZE: usize = 64; -#[derive(Hash, Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] +#[derive(bincode::Encode, bincode::Decode, Hash, Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] struct Request { protocol: SocketProtocol, domain: SocketDomain, number: u32, } -#[derive(Hash, Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] +#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug, Hash, Copy, Clone, Eq, Serialize, Deserialize)] enum Response { Ok, } @@ -135,14 +135,21 @@ where // Borrow socket as mut to prevent multiple simultaneous requests let socket = socket.deref_mut(); - // Send request - let request = bincode::serialize(&Request { - protocol: T::domain(), - domain, - number, - })?; + let mut request = [0u8; 1000]; - socket.send(&request[..]).await?; + // Send request + let size = bincode::encode_into_slice( + Request { + protocol: T::domain(), + domain, + number, + }, + &mut request, + bincode::config::standard(), + ) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?; + + socket.send(&request[..size]).await?; // Receive response loop { @@ -161,7 +168,9 @@ where // Parse response let response = &msg.iovs().next().unwrap()[..msg.bytes]; - let response: Response = bincode::deserialize(response)?; + let response: Response = bincode::decode_from_slice(response, bincode::config::standard()) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))? + .0; if !matches!(response, Response::Ok) { return Err("Request for new sockets failed".into()); } @@ -194,10 +203,14 @@ pub async fn process_socket_requests(socket: &UnixDatagram) -> error::Result<()> let len = socket.recv(&mut buf[..]).await?; - let request: Request = bincode::deserialize(&buf[..len])?; + let request: Request = bincode::decode_from_slice(&buf[..len], bincode::config::standard()) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))? + .0; let response = Response::Ok; - let buf = bincode::serialize(&response)?; + let mut buf = [0u8; 1000]; + let size = bincode::encode_into_slice(response, &mut buf, bincode::config::standard()) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?; let mut owned_fd_buf: Vec = Vec::with_capacity(request.number as usize); for _ in 0..request.number { @@ -223,7 +236,7 @@ pub async fn process_socket_requests(socket: &UnixDatagram) -> error::Result<()> let raw_fd_buf: Vec = owned_fd_buf.iter().map(|fd| fd.as_raw_fd()).collect(); let cmsg = ControlMessage::ScmRights(&raw_fd_buf[..]); - let iov = [IoSlice::new(&buf[..])]; + let iov = [IoSlice::new(&buf[..size])]; sendmsg::<()>(socket.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None)?; } From ca7cd25c4e6ea041cb1113fc6836e63b2d2edb81 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 7 Mar 2025 14:15:14 +0800 Subject: [PATCH 32/63] Bump version 0.7.6 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 750989c..2d48a4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.5" +version = "0.7.6" edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 61bbafcf82761e0bc540f9a3672c6d4a1cafe6c9 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 11 Mar 2025 12:37:22 +0800 Subject: [PATCH 33/63] version_info method --- Cargo.toml | 5 +++-- build.rs | 16 ++++++++++++++++ src/args.rs | 6 +++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2d48a4d..f23360b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ unicase = "2" url = "2" [build-dependencies] +chrono = "0.4" serde_json = "1" [target.'cfg(target_os="linux")'.dependencies] @@ -77,5 +78,5 @@ nix = { version = "0.29", default-features = false, features = [ [target.'cfg(target_os = "windows")'.dependencies] windows-service = "0.8" -[profile.release] -strip = "symbols" +# [profile.release] +# strip = "symbols" diff --git a/build.rs b/build.rs index a7dc782..ccf40ea 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,13 @@ fn main() -> Result<(), Box> { + if let Ok(git_hash) = get_git_hash() { + // Set the environment variables + println!("cargo:rustc-env=GIT_HASH={}", git_hash.trim()); + } + + // Get the build time + let build_time = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); + println!("cargo:rustc-env=BUILD_TIME={}", build_time); + #[cfg(target_os = "windows")] if let Ok(cargo_target_dir) = get_cargo_target_dir() { let mut f = std::fs::File::create(cargo_target_dir.join("build.log"))?; @@ -85,3 +94,10 @@ fn get_crate_dir(crate_name: &str) -> Result std::io::Result { + use std::process::Command; + let git_hash = Command::new("git").args(["rev-parse", "--short", "HEAD"]).output()?.stdout; + let git_hash = String::from_utf8(git_hash).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; + Ok(git_hash) +} diff --git a/src/args.rs b/src/args.rs index 71a85f2..ee1ab58 100644 --- a/src/args.rs +++ b/src/args.rs @@ -9,7 +9,7 @@ use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; use std::str::FromStr; #[derive(Debug, Clone, clap::Parser)] -#[command(author, version, about = "Tunnel interface to proxy.", long_about = None)] +#[command(author, version = version_info(), about = "Tunnel interface to proxy.", long_about = None)] pub struct Args { /// Proxy URL in the form proto://[username[:password]@]host:port, /// where proto is one of socks4, socks5, http. @@ -127,6 +127,10 @@ pub struct Args { pub udpgw_keepalive: Option, } +fn version_info() -> &'static str { + concat!(env!("CARGO_PKG_VERSION"), " (", env!("GIT_HASH"), " ", env!("BUILD_TIME"), ")") +} + fn validate_tun(p: &str) -> Result { #[cfg(target_os = "macos")] if p.len() <= 4 || &p[..4] != "utun" { From a2399c8b28a7a9759d3a22b24ff175ff280d70e7 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 12 Mar 2025 11:18:47 +0800 Subject: [PATCH 34/63] log ipstack info adjusted --- src/bin/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index b8ad59e..0c82309 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,4 +1,4 @@ -use tun2proxy::{Args, BoxError}; +use tun2proxy::{ArgVerbosity, Args, BoxError}; fn main() -> Result<(), BoxError> { dotenvy::dotenv().ok(); @@ -28,7 +28,11 @@ fn main() -> Result<(), BoxError> { } async fn main_async(args: Args) -> Result<(), BoxError> { - let default = format!("{:?},hickory_proto=warn", args.verbosity); + let ipstack = match args.verbosity { + ArgVerbosity::Trace => ArgVerbosity::Debug, + _ => args.verbosity, + }; + let default = format!("{:?},hickory_proto=warn,ipstack={:?}", args.verbosity, ipstack); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(default)).init(); let shutdown_token = tokio_util::sync::CancellationToken::new(); From a380817951e8c3be166b73eebae52b4d86d09d85 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 19 Mar 2025 08:36:29 +0800 Subject: [PATCH 35/63] update hickory-proto (DNS parser) --- Cargo.toml | 2 +- src/dns.rs | 23 ++++++++--------------- src/error.rs | 2 +- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f23360b..3614e90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ digest_auth = "0.3" dotenvy = "0.15" env_logger = "0.11" hashlink = "0.10" -hickory-proto = "0.24" +hickory-proto = "0.25" httparse = "1" ipstack = { version = "0.2" } log = { version = "0.4", features = ["std"] } diff --git a/src/dns.rs b/src/dns.rs index 6f9470d..ed36f5f 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -1,21 +1,16 @@ use hickory_proto::{ op::{Message, MessageType, ResponseCode}, - rr::{Name, RData, Record, record_type::RecordType}, + rr::{ + Name, RData, Record, + rdata::{A, AAAA}, + }, }; use std::{net::IpAddr, str::FromStr}; pub fn build_dns_response(mut request: Message, domain: &str, ip: IpAddr, ttl: u32) -> Result { let record = match ip { - IpAddr::V4(ip) => { - let mut record = Record::with(Name::from_str(domain)?, RecordType::A, ttl); - record.set_data(Some(RData::A(ip.into()))); - record - } - IpAddr::V6(ip) => { - let mut record = Record::with(Name::from_str(domain)?, RecordType::AAAA, ttl); - record.set_data(Some(RData::AAAA(ip.into()))); - record - } + IpAddr::V4(ip) => Record::from_rdata(Name::from_str(domain)?, ttl, RData::A(A(ip))), + IpAddr::V6(ip) => Record::from_rdata(Name::from_str(domain)?, ttl, RData::AAAA(AAAA(ip))), }; // We must indicate that this message is a response. Otherwise, implementations may not @@ -27,9 +22,7 @@ pub fn build_dns_response(mut request: Message, domain: &str, ip: IpAddr, ttl: u } pub fn remove_ipv6_entries(message: &mut Message) { - message - .answers_mut() - .retain(|answer| !matches!(answer.data(), Some(RData::AAAA(_)))); + message.answers_mut().retain(|answer| !matches!(answer.data(), RData::AAAA(_))); } pub fn extract_ipaddr_from_dns_message(message: &Message) -> Result { @@ -38,7 +31,7 @@ pub fn extract_ipaddr_from_dns_message(message: &Message) -> Result { return Ok(IpAddr::V4((*addr).into())); } diff --git a/src/error.rs b/src/error.rs index c93ecb5..99107c2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -26,7 +26,7 @@ pub enum Error { IpStack(#[from] ipstack::IpStackError), #[error("DnsProtoError {0:?}")] - DnsProto(#[from] hickory_proto::error::ProtoError), + DnsProto(#[from] hickory_proto::ProtoError), #[error("httparse::Error {0:?}")] Httparse(#[from] httparse::Error), From 7657f1603f001b9a0bbafbb2b86a1a3c85f81be3 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 28 Mar 2025 20:23:47 +0800 Subject: [PATCH 36/63] Bump version 0.7.7 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3614e90..b730860 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.6" +version = "0.7.7" edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 9e75475a2370bdceef0bf3778be557912d50890b Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 18 Apr 2025 11:03:05 +0800 Subject: [PATCH 37/63] force exit process while fatal error --- src/bin/main.rs | 17 +++++++++++++---- src/general_api.rs | 17 ++++++++++++----- src/lib.rs | 28 +++++++++++++++------------- src/win_svc.rs | 12 ++++++++++-- 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 0c82309..d7174d9 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -37,6 +37,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { let shutdown_token = tokio_util::sync::CancellationToken::new(); let main_loop_handle = tokio::spawn({ + let args = args.clone(); let shutdown_token = shutdown_token.clone(); async move { #[cfg(target_os = "linux")] @@ -44,7 +45,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { if let Err(err) = namespace_proxy_main(args, shutdown_token).await { log::error!("namespace proxy error: {}", err); } - return; + return Ok(0); } unsafe extern "C" fn traffic_cb(status: *const tun2proxy::TrafficStatus, _: *mut std::ffi::c_void) { @@ -53,9 +54,11 @@ async fn main_async(args: Args) -> Result<(), BoxError> { } unsafe { tun2proxy::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = tun2proxy::general_run_async(args, tun::DEFAULT_MTU, cfg!(target_os = "macos"), shutdown_token).await { - log::error!("main loop error: {}", err); + let ret = tun2proxy::general_run_async(args, tun::DEFAULT_MTU, cfg!(target_os = "macos"), shutdown_token).await; + if let Err(err) = &ret { + log::error!("main loop error: {err}"); } + ret } }); @@ -68,13 +71,19 @@ async fn main_async(args: Args) -> Result<(), BoxError> { }) .await; - main_loop_handle.await?; + let tasks = main_loop_handle.await??; if ctrlc_fired.load(std::sync::atomic::Ordering::SeqCst) { log::info!("Ctrl-C fired, waiting the handler to finish..."); ctrlc_handel.await.map_err(|err| err.to_string())?; } + if args.exit_on_fatal_error && tasks >= args.max_sessions { + // Because `main_async` function perhaps stuck in `await` state, so we need to exit the process forcefully + log::info!("Internal fatal error, max sessions reached ({tasks}/{})", args.max_sessions); + std::process::exit(-1); + } + Ok(()) } diff --git a/src/general_api.rs b/src/general_api.rs index 2838271..9e7dd3c 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -120,11 +120,18 @@ pub fn general_run_for_api(args: Args, tun_mtu: u16, packet_information: bool) - return -3; }; match rt.block_on(async move { - if let Err(err) = general_run_async(args, tun_mtu, packet_information, shutdown_token).await { - log::error!("main loop error: {}", err); - return Err(err); + let ret = general_run_async(args.clone(), tun_mtu, packet_information, shutdown_token).await; + match &ret { + Ok(sessions) => { + if args.exit_on_fatal_error && *sessions >= args.max_sessions { + log::error!("Forced exit due to max sessions reached ({sessions}/{})", args.max_sessions); + std::process::exit(-1); + } + log::debug!("tun2proxy exited normally, current sessions: {sessions}"); + } + Err(err) => log::error!("main loop error: {err}"), } - Ok(()) + ret }) { Ok(_) => 0, Err(e) => { @@ -140,7 +147,7 @@ pub async fn general_run_async( tun_mtu: u16, _packet_information: bool, shutdown_token: tokio_util::sync::CancellationToken, -) -> std::io::Result<()> { +) -> std::io::Result { let mut tun_config = tun::Configuration::default(); #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] diff --git a/src/lib.rs b/src/lib.rs index c62e08b..06e3697 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ pub mod win_svc; const DNS_PORT: u16 = 53; -static TASK_COUNT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); +static TASK_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); use std::sync::atomic::Ordering::Relaxed; #[allow(unused)] @@ -154,7 +154,9 @@ async fn create_udp_stream(socket_queue: &Option>, peer: Socket /// * `mtu` - The MTU of the network device /// * `args` - The arguments to use /// * `shutdown_token` - The token to exit the server -pub async fn run(device: D, mtu: u16, args: Args, shutdown_token: CancellationToken) -> crate::Result<()> +/// # Returns +/// * The number of sessions while exiting +pub async fn run(device: D, mtu: u16, args: Args, shutdown_token: CancellationToken) -> crate::Result where D: AsyncRead + AsyncWrite + Unpin + Send + 'static, { @@ -265,10 +267,10 @@ where ip_stack_stream? } }; - let max_sessions = args.max_sessions as u64; + let max_sessions = args.max_sessions; match ip_stack_stream { IpStackStream::Tcp(tcp) => { - if TASK_COUNT.load(Relaxed) > max_sessions { + if TASK_COUNT.load(Relaxed) >= max_sessions { if args.exit_on_fatal_error { log::info!("Too many sessions that over {max_sessions}, exiting..."); break; @@ -276,7 +278,7 @@ where log::warn!("Too many sessions that over {max_sessions}, dropping new session"); continue; } - log::trace!("Session count {}", TASK_COUNT.fetch_add(1, Relaxed) + 1); + log::trace!("Session count {}", TASK_COUNT.fetch_add(1, Relaxed).saturating_add(1)); let info = SessionInfo::new(tcp.local_addr(), tcp.peer_addr(), IpProtocol::Tcp); let domain_name = if let Some(virtual_dns) = &virtual_dns { let mut virtual_dns = virtual_dns.lock().await; @@ -291,11 +293,11 @@ where if let Err(err) = handle_tcp_session(tcp, proxy_handler, socket_queue).await { log::error!("{} error \"{}\"", info, err); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed) - 1); + log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); }); } IpStackStream::Udp(udp) => { - if TASK_COUNT.load(Relaxed) > max_sessions { + if TASK_COUNT.load(Relaxed) >= max_sessions { if args.exit_on_fatal_error { log::info!("Too many sessions that over {max_sessions}, exiting..."); break; @@ -303,7 +305,7 @@ where log::warn!("Too many sessions that over {max_sessions}, dropping new session"); continue; } - log::trace!("Session count {}", TASK_COUNT.fetch_add(1, Relaxed) + 1); + log::trace!("Session count {}", TASK_COUNT.fetch_add(1, Relaxed).saturating_add(1)); let mut info = SessionInfo::new(udp.local_addr(), udp.peer_addr(), IpProtocol::Udp); if info.dst.port() == DNS_PORT { if is_private_ip(info.dst.ip()) { @@ -317,7 +319,7 @@ where if let Err(err) = handle_dns_over_tcp_session(udp, proxy_handler, socket_queue, ipv6_enabled).await { log::error!("{} error \"{}\"", info, err); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed) - 1); + log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); }); continue; } @@ -328,7 +330,7 @@ where log::error!("{} error \"{}\"", info, err); } } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed) - 1); + log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); }); continue; } @@ -359,7 +361,7 @@ where if let Err(e) = handle_udp_gateway_session(udp, udpgw, &dst_addr, proxy_handler, queue, ipv6_enabled).await { log::info!("Ending {} with \"{}\"", info, e); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed) - 1); + log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); }); continue; } @@ -371,7 +373,7 @@ where if let Err(err) = handle_udp_associate_session(udp, ty, proxy_handler, socket_queue, ipv6_enabled).await { log::info!("Ending {} with \"{}\"", info, err); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed) - 1); + log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); }); } Err(e) => { @@ -390,7 +392,7 @@ where } } } - Ok(()) + Ok(TASK_COUNT.load(Relaxed)) } async fn handle_virtual_dns_session(mut udp: IpStackUdpStream, dns: Arc>) -> crate::Result<()> { diff --git a/src/win_svc.rs b/src/win_svc.rs index a4090e3..5ee416e 100644 --- a/src/win_svc.rs +++ b/src/win_svc.rs @@ -78,8 +78,16 @@ fn run_service(_arguments: Vec) -> Result<(), crate::BoxErro } unsafe { crate::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = crate::general_run_async(args, tun::DEFAULT_MTU, false, shutdown_token).await { - log::error!("main loop error: {}", err); + let ret = crate::general_run_async(args.clone(), tun::DEFAULT_MTU, false, shutdown_token).await; + match &ret { + Ok(sessions) => { + if args.exit_on_fatal_error && *sessions >= args.max_sessions { + log::error!("Forced exit due to max sessions reached ({sessions}/{})", args.max_sessions); + std::process::exit(-1); + } + log::debug!("tun2proxy exited normally, current sessions: {sessions}"); + } + Err(err) => log::error!("main loop error: {err}"), } Ok::<(), crate::Error>(()) })?; From 7121a80300359644e2b0719181845157c40e02b3 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sat, 19 Apr 2025 17:50:56 +0800 Subject: [PATCH 38/63] Bump version 0.7.8 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b730860..dc4fec7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.7" +version = "0.7.8" edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" @@ -38,7 +38,7 @@ env_logger = "0.11" hashlink = "0.10" hickory-proto = "0.25" httparse = "1" -ipstack = { version = "0.2" } +ipstack = { version = "0.3", git = "https://github.com/ssrlive/ipstack.git", rev = "53c648e" } log = { version = "0.4", features = ["std"] } mimalloc = { version = "0.1", default-features = false, optional = true } percent-encoding = "2" From 88423039c643d010ef36723aa251e53932624397 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sun, 20 Apr 2025 19:56:36 +0800 Subject: [PATCH 39/63] make TASK_COUNT as local task_count variable --- src/lib.rs | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 06e3697..5f77672 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,9 +64,6 @@ pub mod win_svc; const DNS_PORT: u16 = 53; -static TASK_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); -use std::sync::atomic::Ordering::Relaxed; - #[allow(unused)] #[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)] #[cfg_attr( @@ -224,11 +221,11 @@ where let socket_queue = None; use socks5_impl::protocol::Version::{V4, V5}; - let mgr = match args.proxy.proxy_type { - ProxyType::Socks5 => Arc::new(SocksProxyManager::new(server_addr, V5, key)) as Arc, - ProxyType::Socks4 => Arc::new(SocksProxyManager::new(server_addr, V4, key)) as Arc, - ProxyType::Http => Arc::new(HttpManager::new(server_addr, key)) as Arc, - ProxyType::None => Arc::new(NoProxyManager::new()) as Arc, + let mgr: Arc = match args.proxy.proxy_type { + ProxyType::Socks5 => Arc::new(SocksProxyManager::new(server_addr, V5, key)), + ProxyType::Socks4 => Arc::new(SocksProxyManager::new(server_addr, V4, key)), + ProxyType::Http => Arc::new(HttpManager::new(server_addr, key)), + ProxyType::None => Arc::new(NoProxyManager::new()), }; let mut ipstack_config = ipstack::IpStackConfig::default(); @@ -256,7 +253,11 @@ where client }); + let task_count = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0)); + use std::sync::atomic::Ordering::Relaxed; + loop { + let task_count = task_count.clone(); let virtual_dns = virtual_dns.clone(); let ip_stack_stream = tokio::select! { _ = shutdown_token.cancelled() => { @@ -270,7 +271,7 @@ where let max_sessions = args.max_sessions; match ip_stack_stream { IpStackStream::Tcp(tcp) => { - if TASK_COUNT.load(Relaxed) >= max_sessions { + if task_count.load(Relaxed) >= max_sessions { if args.exit_on_fatal_error { log::info!("Too many sessions that over {max_sessions}, exiting..."); break; @@ -278,7 +279,7 @@ where log::warn!("Too many sessions that over {max_sessions}, dropping new session"); continue; } - log::trace!("Session count {}", TASK_COUNT.fetch_add(1, Relaxed).saturating_add(1)); + log::trace!("Session count {}", task_count.fetch_add(1, Relaxed).saturating_add(1)); let info = SessionInfo::new(tcp.local_addr(), tcp.peer_addr(), IpProtocol::Tcp); let domain_name = if let Some(virtual_dns) = &virtual_dns { let mut virtual_dns = virtual_dns.lock().await; @@ -293,11 +294,11 @@ where if let Err(err) = handle_tcp_session(tcp, proxy_handler, socket_queue).await { log::error!("{} error \"{}\"", info, err); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); + log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); } IpStackStream::Udp(udp) => { - if TASK_COUNT.load(Relaxed) >= max_sessions { + if task_count.load(Relaxed) >= max_sessions { if args.exit_on_fatal_error { log::info!("Too many sessions that over {max_sessions}, exiting..."); break; @@ -305,11 +306,11 @@ where log::warn!("Too many sessions that over {max_sessions}, dropping new session"); continue; } - log::trace!("Session count {}", TASK_COUNT.fetch_add(1, Relaxed).saturating_add(1)); + log::trace!("Session count {}", task_count.fetch_add(1, Relaxed).saturating_add(1)); let mut info = SessionInfo::new(udp.local_addr(), udp.peer_addr(), IpProtocol::Udp); if info.dst.port() == DNS_PORT { if is_private_ip(info.dst.ip()) { - info.dst.set_ip(dns_addr); + info.dst.set_ip(dns_addr); // !!! Here we change the destination address to remote DNS server!!! } if args.dns == ArgDns::OverTcp { info.protocol = IpProtocol::Tcp; @@ -319,7 +320,7 @@ where if let Err(err) = handle_dns_over_tcp_session(udp, proxy_handler, socket_queue, ipv6_enabled).await { log::error!("{} error \"{}\"", info, err); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); + log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); continue; } @@ -330,7 +331,7 @@ where log::error!("{} error \"{}\"", info, err); } } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); + log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); continue; } @@ -361,7 +362,7 @@ where if let Err(e) = handle_udp_gateway_session(udp, udpgw, &dst_addr, proxy_handler, queue, ipv6_enabled).await { log::info!("Ending {} with \"{}\"", info, e); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); + log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); continue; } @@ -373,7 +374,7 @@ where if let Err(err) = handle_udp_associate_session(udp, ty, proxy_handler, socket_queue, ipv6_enabled).await { log::info!("Ending {} with \"{}\"", info, err); } - log::trace!("Session count {}", TASK_COUNT.fetch_sub(1, Relaxed).saturating_sub(1)); + log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); } Err(e) => { @@ -392,7 +393,7 @@ where } } } - Ok(TASK_COUNT.load(Relaxed)) + Ok(task_count.load(Relaxed)) } async fn handle_virtual_dns_session(mut udp: IpStackUdpStream, dns: Arc>) -> crate::Result<()> { From 2ead13a3f4081d0fd72312666883fd4a4e7b073c Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:58:52 +0800 Subject: [PATCH 40/63] version_info & about_info --- src/args.rs | 17 ++++++++++++----- src/bin/udpgw_server.rs | 8 ++++++-- src/lib.rs | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/args.rs b/src/args.rs index ee1ab58..02f5ec4 100644 --- a/src/args.rs +++ b/src/args.rs @@ -8,8 +8,19 @@ use std::ffi::OsString; use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; use std::str::FromStr; +#[macro_export] +macro_rules! version_info { + () => { + concat!(env!("CARGO_PKG_VERSION"), " (", env!("GIT_HASH"), " ", env!("BUILD_TIME"), ")") + }; +} + +fn about_info() -> &'static str { + concat!("Tunnel interface to proxy.\nVersion: ", version_info!()) +} + #[derive(Debug, Clone, clap::Parser)] -#[command(author, version = version_info(), about = "Tunnel interface to proxy.", long_about = None)] +#[command(author, version = version_info!(), about = about_info(), long_about = None)] pub struct Args { /// Proxy URL in the form proto://[username[:password]@]host:port, /// where proto is one of socks4, socks5, http. @@ -127,10 +138,6 @@ pub struct Args { pub udpgw_keepalive: Option, } -fn version_info() -> &'static str { - concat!(env!("CARGO_PKG_VERSION"), " (", env!("GIT_HASH"), " ", env!("BUILD_TIME"), ")") -} - fn validate_tun(p: &str) -> Result { #[cfg(target_os = "macos")] if p.len() <= 4 || &p[..4] != "utun" { diff --git a/src/bin/udpgw_server.rs b/src/bin/udpgw_server.rs index 370897a..05f39a6 100644 --- a/src/bin/udpgw_server.rs +++ b/src/bin/udpgw_server.rs @@ -28,8 +28,12 @@ impl Client { } } +fn about_info() -> &'static str { + concat!("UDP Gateway Server for tun2proxy\nVersion: ", tun2proxy::version_info!()) +} + #[derive(Debug, Clone, clap::Parser)] -#[command(author, version, about = "UDP Gateway Server for tun2proxy", long_about = None)] +#[command(author, version = tun2proxy::version_info!(), about = about_info(), long_about = None)] pub struct UdpGwArgs { /// UDP gateway listen address #[arg(short, long, value_name = "IP:PORT", default_value = "127.0.0.1:7300")] @@ -193,7 +197,7 @@ async fn write_to_client(addr: SocketAddr, mut writer: WriteHalf<'_>, mut rx: Re } async fn main_async(args: UdpGwArgs) -> Result<(), BoxError> { - log::info!("{} {} starting...", module_path!(), env!("CARGO_PKG_VERSION")); + log::info!("{} {} starting...", module_path!(), tun2proxy::version_info!()); log::info!("UDP Gateway Server running at {}", args.listen_addr); let shutdown_token = tokio_util::sync::CancellationToken::new(); diff --git a/src/lib.rs b/src/lib.rs index 5f77672..942c509 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,7 +157,7 @@ pub async fn run(device: D, mtu: u16, args: Args, shutdown_token: Cancellatio where D: AsyncRead + AsyncWrite + Unpin + Send + 'static, { - log::info!("{} {} starting...", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + log::info!("{} {} starting...", env!("CARGO_PKG_NAME"), version_info!()); log::info!("Proxy {} server: {}", args.proxy.proxy_type, args.proxy.addr); let server_addr = args.proxy.addr; From b71f479bf3dce0aba316abbd94a3951e1fdea73d Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 23 Apr 2025 09:36:38 +0800 Subject: [PATCH 41/63] close-stale-issues.yml --- .github/workflows/close-stale-issues.yml | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/close-stale-issues.yml diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml new file mode 100644 index 0000000..d06ff8a --- /dev/null +++ b/.github/workflows/close-stale-issues.yml @@ -0,0 +1,26 @@ +name: Close stale issues and PRs + +on: + schedule: + - cron: "0 0 * * *" # run a cron job every day at midnight + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - name: Close stale issues and PRs + uses: actions/stale@v9 + with: + stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' + stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.' + close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' + days-before-issue-stale: 30 + days-before-pr-stale: 45 + days-before-issue-close: 5 + days-before-pr-close: 10 + stale-issue-label: 'no-issue-activity' + exempt-issue-labels: 'keep-open,awaiting-approval,work-in-progress' + stale-pr-label: 'no-pr-activity' + exempt-pr-labels: 'awaiting-approval,work-in-progress' + # only-labels: 'awaiting-feedback,awaiting-answers' From 54f7dbc81b3ec65be0d2f0190fccd9a2dbe53695 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 30 Apr 2025 10:55:43 +0800 Subject: [PATCH 42/63] update nix deps --- Cargo.toml | 2 +- src/bin/main.rs | 2 +- src/socket_transfer.rs | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dc4fec7..a4d94dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ jni = { version = "0.21", default-features = false } [target.'cfg(unix)'.dependencies] daemonize = "0.5" -nix = { version = "0.29", default-features = false, features = [ +nix = { version = "0.30", default-features = false, features = [ "fs", "socket", "uio", diff --git a/src/bin/main.rs b/src/bin/main.rs index d7174d9..102b6a3 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -102,7 +102,7 @@ async fn namespace_proxy_main( let child = tokio::process::Command::new("unshare") .args("--user --map-current-user --net --mount --keep-caps --kill-child --fork".split(' ')) - .arg(format!("/proc/self/fd/{}", fd)) + .arg(format!("/proc/self/fd/{}", fd.as_raw_fd())) .arg("--socket-transfer-fd") .arg(remote_fd.as_raw_fd().to_string()) .args(std::env::args().skip(1)) diff --git a/src/socket_transfer.rs b/src/socket_transfer.rs index e069b1d..e68bef2 100644 --- a/src/socket_transfer.rs +++ b/src/socket_transfer.rs @@ -30,17 +30,17 @@ enum Response { /// Reconstruct socket from raw `fd` pub fn reconstruct_socket(fd: RawFd) -> Result { - // Check if `fd` is valid - let fd_flags = fcntl::fcntl(fd, fcntl::F_GETFD)?; - // `fd` is confirmed to be valid so it should be closed let socket = unsafe { OwnedFd::from_raw_fd(fd) }; + // Check if `fd` is valid + let fd_flags = fcntl::fcntl(socket.as_fd(), fcntl::F_GETFD)?; + // Insert CLOEXEC flag to the `fd` to prevent further propagation across `execve(2)` calls let mut fd_flags = FdFlag::from_bits(fd_flags).ok_or(ErrorKind::Unsupported)?; if !fd_flags.contains(FdFlag::FD_CLOEXEC) { fd_flags.insert(FdFlag::FD_CLOEXEC); - fcntl::fcntl(fd, fcntl::F_SETFD(fd_flags))?; + fcntl::fcntl(socket.as_fd(), fcntl::F_SETFD(fd_flags))?; } Ok(socket) @@ -70,12 +70,12 @@ pub async fn create_transfer_socket_pair() -> std::io::Result<(UnixDatagram, Own let remote_fd: OwnedFd = remote.into_std().unwrap().into(); // Get `remote_fd` flags - let fd_flags = fcntl::fcntl(remote_fd.as_raw_fd(), fcntl::F_GETFD)?; + let fd_flags = fcntl::fcntl(remote_fd.as_fd(), fcntl::F_GETFD)?; // Remove CLOEXEC flag from the `remote_fd` to allow propagating across `execve(2)` let mut fd_flags = FdFlag::from_bits(fd_flags).ok_or(ErrorKind::Unsupported)?; fd_flags.remove(FdFlag::FD_CLOEXEC); - fcntl::fcntl(remote_fd.as_raw_fd(), fcntl::F_SETFD(fd_flags))?; + fcntl::fcntl(remote_fd.as_fd(), fcntl::F_SETFD(fd_flags))?; Ok((local, remote_fd)) } From cf4a565f93f5438587f926c0595ce18a7203d544 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 08:30:43 +0800 Subject: [PATCH 43/63] Update socks5-impl requirement from 0.6 to 0.7 (#201) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a4d94dc..041288f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ log = { version = "0.4", features = ["std"] } mimalloc = { version = "0.1", default-features = false, optional = true } percent-encoding = "2" shlex = "1.3.0" -socks5-impl = { version = "0.6", default-features = false, features = [ +socks5-impl = { version = "0.7", default-features = false, features = [ "tokio", ] } thiserror = "2" From 7c32b6272744ff1c4d16d06600b508682ae4b392 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 2 May 2025 16:10:17 +0800 Subject: [PATCH 44/63] Exclude dependabot[bot] in Integration Tests --- .github/workflows/publish-exe.yml | 1 + .github/workflows/rust.yml | 1 + .github/workflows/tests.yml | 10 +++------- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish-exe.yml b/.github/workflows/publish-exe.yml index dc2f007..697f352 100644 --- a/.github/workflows/publish-exe.yml +++ b/.github/workflows/publish-exe.yml @@ -1,4 +1,5 @@ on: + workflow_dispatch: push: tags: - "v*.*.*" diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 75d5c93..82fa836 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,6 +1,7 @@ name: Push or PR on: + workflow_dispatch: push: branches: - '**' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c274674..51f65cf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,14 +12,10 @@ jobs: proxy_tests: name: Proxy Tests runs-on: ubuntu-latest - if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'safe to test') + if: (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'safe to test')) && github.actor != 'dependabot[bot]' && github.actor != 'github-actions[bot]' steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable - name: Populate .env env: DOTENV: ${{ secrets.DOTENV }} From 3dc8f222cb32b77d0a2c45d896364537287888f3 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 8 May 2025 10:26:00 +0800 Subject: [PATCH 45/63] Bump version 0.7.9 --- Cargo.toml | 4 ++-- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 041288f..083a8d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.8" +version = "0.7.9" edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" @@ -38,7 +38,7 @@ env_logger = "0.11" hashlink = "0.10" hickory-proto = "0.25" httparse = "1" -ipstack = { version = "0.3", git = "https://github.com/ssrlive/ipstack.git", rev = "53c648e" } +ipstack = { version = "0.4" } log = { version = "0.4", features = ["std"] } mimalloc = { version = "0.1", default-features = false, optional = true } percent-encoding = "2" diff --git a/src/lib.rs b/src/lib.rs index 942c509..ceddcf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ use crate::{ session_info::{IpProtocol, SessionInfo}, virtual_dns::VirtualDns, }; -use ipstack::stream::{IpStackStream, IpStackTcpStream, IpStackUdpStream}; +use ipstack::{IpStackStream, IpStackTcpStream, IpStackUdpStream}; use proxy_handler::{ProxyHandler, ProxyHandlerManager}; use socks::SocksProxyManager; pub use socks5_impl::protocol::UserKey; From 6a5692cea0285afbb2841c79ef0fdf3b873ccef8 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Wed, 21 May 2025 15:19:18 +0800 Subject: [PATCH 46/63] refine code --- Cargo.toml | 20 ++++++++++---------- src/error.rs | 10 ++++++++-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 083a8d8..3fcc22d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,18 +55,17 @@ udp-stream = { version = "0.0.12", default-features = false } unicase = "2" url = "2" -[build-dependencies] -chrono = "0.4" -serde_json = "1" - -[target.'cfg(target_os="linux")'.dependencies] -serde = { version = "1", features = ["derive"] } -bincode = "2" - [target.'cfg(target_os="android")'.dependencies] android_logger = "0.15" jni = { version = "0.21", default-features = false } +[target.'cfg(target_os="linux")'.dependencies] +bincode = "2" +serde = { version = "1", features = ["derive"] } + +[target.'cfg(target_os="windows")'.dependencies] +windows-service = "0.8" + [target.'cfg(unix)'.dependencies] daemonize = "0.5" nix = { version = "0.30", default-features = false, features = [ @@ -75,8 +74,9 @@ nix = { version = "0.30", default-features = false, features = [ "uio", ] } -[target.'cfg(target_os = "windows")'.dependencies] -windows-service = "0.8" +[build-dependencies] +chrono = "0.4" +serde_json = "1" # [profile.release] # strip = "symbols" diff --git a/src/error.rs b/src/error.rs index 99107c2..b6a6b92 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,7 +23,7 @@ pub enum Error { TryFromSlice(#[from] std::array::TryFromSliceError), #[error("IpStackError {0:?}")] - IpStack(#[from] ipstack::IpStackError), + IpStack(#[from] Box), #[error("DnsProtoError {0:?}")] DnsProto(#[from] hickory_proto::ProtoError), @@ -45,6 +45,12 @@ pub enum Error { IntParseError(#[from] std::num::ParseIntError), } +impl From for Error { + fn from(err: ipstack::IpStackError) -> Self { + Self::IpStack(Box::new(err)) + } +} + impl From<&str> for Error { fn from(err: &str) -> Self { Self::String(err.to_string()) @@ -67,7 +73,7 @@ impl From for std::io::Error { fn from(err: Error) -> Self { match err { Error::Io(err) => err, - _ => std::io::Error::new(std::io::ErrorKind::Other, err), + _ => std::io::Error::other(err), } } } From 8cdb4f535d30c1f3a5e553ae2834daaebb3e914f Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Mon, 2 Jun 2025 10:31:44 +0800 Subject: [PATCH 47/63] Significant change in --setup parameter (#207) --- README.md | 4 ++-- src/args.rs | 5 +++-- src/general_api.rs | 10 +--------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 5c9b591..00537af 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,8 @@ Options: --unshare-pidfile Create a pidfile of `unshare` process when using `--unshare` -6, --ipv6-enabled IPv6 enabled -s, --setup Routing and system setup, which decides whether to setup the routing and system - configuration. This option is only available on Linux and requires root-like privileges. - See `capabilities(7)` + configuration. This option requires root-like privileges on every platform. + It is very important on Linux, see `capabilities(7)` -d, --dns DNS handling strategy [default: direct] [possible values: virtual, over-tcp, direct] --dns-addr DNS resolver address [default: 8.8.8.8] --virtual-dns-pool IP address pool to be used by virtual DNS in CIDR notation [default: 198.18.0.0/15] diff --git a/src/args.rs b/src/args.rs index 02f5ec4..2b74748 100644 --- a/src/args.rs +++ b/src/args.rs @@ -76,8 +76,9 @@ pub struct Args { pub ipv6_enabled: bool, /// Routing and system setup, which decides whether to setup the routing and system configuration. - /// This option is only available on Linux and requires root-like privileges. See `capabilities(7)`. - #[arg(short, long, default_value = if cfg!(target_os = "linux") { "false" } else { "true" })] + /// This option requires root-like privileges on every platform. + /// It is very important on Linux, see `capabilities(7)`. + #[arg(short, long)] pub setup: bool, /// DNS handling strategy diff --git a/src/general_api.rs b/src/general_api.rs index 9e7dd3c..f359b73 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -196,9 +196,6 @@ pub async fn general_run_async( .bypass_ips(&args.bypass) .ipv6_default_route(args.ipv6_enabled); - #[allow(unused_mut, unused_assignments, unused_variables)] - let mut setup = true; - let device = tun::create_as_async(&tun_config)?; #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] @@ -212,13 +209,8 @@ pub async fn general_run_async( #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] let mut _restore: Option = None; - #[cfg(target_os = "linux")] - { - setup = args.setup; - } - #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] - if setup { + if args.setup { _restore = Some(tproxy_config::tproxy_setup(&tproxy_args)?); } From ddebf5ee50a5df1b96101d62cd8bd6ca13feedb8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:02:31 +0800 Subject: [PATCH 48/63] Update tun requirement from 0.7 to 0.8 (#209) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3fcc22d..abad68b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ thiserror = "2" tokio = { version = "1", features = ["full"] } tokio-util = "0.7" tproxy-config = { version = "6", default-features = false } -tun = { version = "0.7", features = ["async"] } +tun = { version = "0.8", features = ["async"] } udp-stream = { version = "0.0.12", default-features = false } unicase = "2" url = "2" From 88d31ce16868cc0dff228aa6171a9aa481c4d5a8 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:05:28 +0800 Subject: [PATCH 49/63] Bump version 0.7.10 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index abad68b..10f3488 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.9" +version = "0.7.10" edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From fbc47a3001148d0f9f069cfdd4a8a2b274e99505 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Tue, 10 Jun 2025 23:00:36 +0200 Subject: [PATCH 50/63] fix(ci): account for change in load_dotenv --- .github/workflows/tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 51f65cf..32d02f5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,7 +19,9 @@ jobs: - name: Populate .env env: DOTENV: ${{ secrets.DOTENV }} - run: echo "$DOTENV" > .env + run: | + echo "$DOTENV" > tests/.env + ln -s tests/.env - name: Set up Python uses: actions/setup-python@v2 @@ -36,7 +38,7 @@ jobs: - name: Build project run: cargo build --release - + - name: Run tests run: | source venv/bin/activate From 8b4ecabd8f831a83a09d973bcefb2f784831642e Mon Sep 17 00:00:00 2001 From: Paper-Dragon <2678885646@qq.com> Date: Wed, 11 Jun 2025 14:12:02 +0800 Subject: [PATCH 51/63] build image based on alpine/musl (#212) --- .github/workflows/publish-docker.yml | 15 +++++++++++++-- Dockerfile.alpine | 18 ++++++++++++++++++ Dockerfile => Dockerfile.ubuntu | 0 README.md | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 Dockerfile.alpine rename Dockerfile => Dockerfile.ubuntu (100%) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 10db660..a848c80 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -50,11 +50,22 @@ jobs: # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - - name: Build and push Docker image + - name: Build gnu and push Docker image uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 with: platforms: linux/amd64,linux/arm64 context: . + file: Dockerfile.ubuntu push: true - tags: ${{ steps.meta.outputs.tags }} + tags: ${{ steps.meta.outputs.tags }}-ubuntu labels: ${{ steps.meta.outputs.labels }} + + - name: Build musl and push Docker image + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + platforms: linux/amd64 + context: . + file: Dockerfile.alpine + push: true + tags: ${{ steps.meta.outputs.tags }}-alpine + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000..570b819 --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,18 @@ +#################################################################################################### +## Builder +#################################################################################################### +FROM rust:latest AS builder +WORKDIR /worker +COPY ./ . +RUN rustup target add x86_64-unknown-linux-musl +RUN cargo build --release --target x86_64-unknown-linux-musl + +#################################################################################################### +## Final image +#################################################################################################### +FROM alpine:latest +RUN apk add --no-cache iproute2 + +COPY --from=builder /worker/target/x86_64-unknown-linux-musl/release/tun2proxy-bin /usr/bin/tun2proxy-bin + +ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] diff --git a/Dockerfile b/Dockerfile.ubuntu similarity index 100% rename from Dockerfile rename to Dockerfile.ubuntu diff --git a/README.md b/README.md index 00537af..18be7ba 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ services: cap_add: - NET_ADMIN container_name: tun2proxy - image: ghcr.io/tun2proxy/tun2proxy:latest + image: ghcr.io/tun2proxy/tun2proxy:latest-ubuntu command: --proxy proto://[username[:password]@]host:port alpine: stdin_open: true From 1880396822866fcf753d85f1b56881f6e8bf70e9 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sat, 14 Jun 2025 08:30:45 +0800 Subject: [PATCH 52/63] use ctrlc2 async feature --- Cargo.toml | 2 +- src/bin/main.rs | 8 ++++---- src/bin/udpgw_server.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 10f3488..f3b06b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ async-trait = "0.1" base64easy = "0.1" chrono = "0.4" clap = { version = "4", features = ["derive", "wrap_help", "color"] } -ctrlc2 = { version = "3", features = ["tokio", "termination"] } +ctrlc2 = { version = "3.6.5", features = ["async", "termination"] } digest_auth = "0.3" dotenvy = "0.15" env_logger = "0.11" diff --git a/src/bin/main.rs b/src/bin/main.rs index 102b6a3..7bf00ef 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -64,18 +64,18 @@ async fn main_async(args: Args) -> Result<(), BoxError> { let ctrlc_fired = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); let ctrlc_fired_clone = ctrlc_fired.clone(); - let ctrlc_handel = ctrlc2::set_async_handler(async move { + let ctrlc_handel = ctrlc2::AsyncCtrlC::new(move || { log::info!("Ctrl-C received, exiting..."); ctrlc_fired_clone.store(true, std::sync::atomic::Ordering::SeqCst); shutdown_token.cancel(); - }) - .await; + true + })?; let tasks = main_loop_handle.await??; if ctrlc_fired.load(std::sync::atomic::Ordering::SeqCst) { log::info!("Ctrl-C fired, waiting the handler to finish..."); - ctrlc_handel.await.map_err(|err| err.to_string())?; + ctrlc_handel.await?; } if args.exit_on_fatal_error && tasks >= args.max_sessions { diff --git a/src/bin/udpgw_server.rs b/src/bin/udpgw_server.rs index 05f39a6..2a8f91d 100644 --- a/src/bin/udpgw_server.rs +++ b/src/bin/udpgw_server.rs @@ -205,18 +205,18 @@ async fn main_async(args: UdpGwArgs) -> Result<(), BoxError> { let ctrlc_fired = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); let ctrlc_fired_clone = ctrlc_fired.clone(); - let ctrlc_handel = ctrlc2::set_async_handler(async move { + let ctrlc_handel = ctrlc2::AsyncCtrlC::new(move || { log::info!("Ctrl-C received, exiting..."); ctrlc_fired_clone.store(true, std::sync::atomic::Ordering::SeqCst); shutdown_token.cancel(); - }) - .await; + true + })?; let _ = main_loop_handle.await?; if ctrlc_fired.load(std::sync::atomic::Ordering::SeqCst) { log::info!("Ctrl-C fired, waiting the handler to finish..."); - ctrlc_handel.await.map_err(|err| err.to_string())?; + ctrlc_handel.await?; } Ok(()) From 584bdc17ed6de5a1c2368792b525de3950726863 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Mon, 16 Jun 2025 00:21:52 +0200 Subject: [PATCH 53/63] feat(Linux): phase out reliance on iproute2 --- Cargo.toml | 2 +- src/general_api.rs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f3b06b8..7e5efbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ socks5-impl = { version = "0.7", default-features = false, features = [ thiserror = "2" tokio = { version = "1", features = ["full"] } tokio-util = "0.7" -tproxy-config = { version = "6", default-features = false } +tproxy-config = { version = "7", default-features = false } tun = { version = "0.8", features = ["async"] } udp-stream = { version = "0.0.12", default-features = false } unicase = "2" diff --git a/src/general_api.rs b/src/general_api.rs index f359b73..843a2b3 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -207,11 +207,11 @@ pub async fn general_run_async( // TproxyState implements the Drop trait to restore network configuration, // so we need to assign it to a variable, even if it is not used. #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] - let mut _restore: Option = None; + let mut restore: Option = None; #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] if args.setup { - _restore = Some(tproxy_config::tproxy_setup(&tproxy_args)?); + restore = Some(tproxy_config::tproxy_setup(&tproxy_args).await?); } #[cfg(target_os = "linux")] @@ -238,8 +238,16 @@ pub async fn general_run_async( } } - let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); - Ok(join_handle.await.map_err(std::io::Error::from)??) + let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token.clone())); + + match join_handle.await? { + Ok(sessions) => { + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] + tproxy_config::tproxy_remove(restore).await?; + Ok(sessions) + } + Err(err) => Err(std::io::Error::from(err)), + } } /// # Safety From b36473ced9fbfe35a552eaff6606c83aa63fabe3 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Thu, 19 Jun 2025 13:32:01 +0200 Subject: [PATCH 54/63] feat(Docker): multi-stage Dockerfile with OS-less container --- .dockerignore | 1 + .github/workflows/publish-docker.yml | 40 +++++++++---------- Dockerfile | 60 ++++++++++++++++++++++++++++ Dockerfile.alpine | 18 --------- Dockerfile.ubuntu | 20 ---------- README.md | 15 +++++-- 6 files changed, 93 insertions(+), 61 deletions(-) create mode 120000 .dockerignore create mode 100644 Dockerfile delete mode 100644 Dockerfile.alpine delete mode 100644 Dockerfile.ubuntu diff --git a/.dockerignore b/.dockerignore new file mode 120000 index 0000000..3e4e48b --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.gitignore \ No newline at end of file diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index a848c80..9e46180 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,20 +1,25 @@ -# name: Create and publish a Docker image -# Configures this workflow to run every time a change is pushed to the branch called `release`. on: push: tags: [ 'v*.*.*' ] + release: + types: [ released ] + workflow_dispatch: # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} + DEFAULT_OS: scratch # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. jobs: build-and-push-image: runs-on: ubuntu-latest + strategy: + matrix: + os: [ 'scratch', 'ubuntu', 'alpine' ] # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. permissions: contents: read @@ -34,38 +39,33 @@ jobs: # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - - name: Extract metadata (tags, labels) for Docker + - name: Extract metadata (tags, labels) for Docker Image id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # We publish the images with an OS-suffix. + # The image based on a default OS is also published without a suffix. + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.os }} + ${{ env.DEFAULT_OS == matrix.os && format('{0}/{1}', env.REGISTRY, env.IMAGE_NAME) || '' }} # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - - name: Build gnu and push Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + - name: Build and push Docker image (U) + uses: docker/build-push-action@v6 with: platforms: linux/amd64,linux/arm64 context: . - file: Dockerfile.ubuntu + file: Dockerfile + target: {{ env.IMAGE_NAME }}-${{ matrix.os }} push: true - tags: ${{ steps.meta.outputs.tags }}-ubuntu + tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - - - name: Build musl and push Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 - with: - platforms: linux/amd64 - context: . - file: Dockerfile.alpine - push: true - tags: ${{ steps.meta.outputs.tags }}-alpine - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e8e317f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,60 @@ +#################################################################################################### +# This is a multi-stage Dockerfile. +# Build with `docker buildx build -t --target .` +# For example, to build the Alpine-based image while naming it tun2proxy, run: +# `docker buildx build -t tun2proxy --target tun2proxy-alpine .` +#################################################################################################### + +#################################################################################################### +## glibc builder +#################################################################################################### +FROM rust:latest AS glibc-builder + + WORKDIR /worker + COPY ./ . + RUN cargo build --release + +#################################################################################################### +## musl builder +#################################################################################################### +FROM rust:latest AS musl-builder + + WORKDIR /worker + COPY ./ . + RUN rustup target add x86_64-unknown-linux-musl + RUN cargo build --release --target x86_64-unknown-linux-musl + + RUN mkdir /.etc \ + && touch /.etc/resolv.conf \ + && mkdir /.tmp \ + && chmod 777 /.tmp \ + && chmod +t /.tmp + +#################################################################################################### +## Alpine image +#################################################################################################### +FROM alpine:latest AS tun2proxy-alpine + + COPY --from=musl-builder /worker/target/x86_64-unknown-linux-musl/release/tun2proxy-bin /usr/bin/tun2proxy-bin + + ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] + +#################################################################################################### +## Ubuntu image +#################################################################################################### +FROM ubuntu:latest AS tun2proxy-ubuntu + + COPY --from=glibc-builder /worker/target/release/tun2proxy-bin /usr/bin/tun2proxy-bin + + ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] + +#################################################################################################### +## OS-less image (default) +#################################################################################################### +FROM scratch AS tun2proxy-scratch + + COPY --from=musl-builder ./tmp /tmp + COPY --from=musl-builder ./etc /etc + COPY --from=musl-builder /worker/target/x86_64-unknown-linux-musl/release/tun2proxy-bin /usr/bin/tun2proxy-bin + + ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine deleted file mode 100644 index 570b819..0000000 --- a/Dockerfile.alpine +++ /dev/null @@ -1,18 +0,0 @@ -#################################################################################################### -## Builder -#################################################################################################### -FROM rust:latest AS builder -WORKDIR /worker -COPY ./ . -RUN rustup target add x86_64-unknown-linux-musl -RUN cargo build --release --target x86_64-unknown-linux-musl - -#################################################################################################### -## Final image -#################################################################################################### -FROM alpine:latest -RUN apk add --no-cache iproute2 - -COPY --from=builder /worker/target/x86_64-unknown-linux-musl/release/tun2proxy-bin /usr/bin/tun2proxy-bin - -ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu deleted file mode 100644 index e6ad592..0000000 --- a/Dockerfile.ubuntu +++ /dev/null @@ -1,20 +0,0 @@ -#################################################################################################### -## Builder -#################################################################################################### -FROM rust:latest AS builder - -WORKDIR /worker -COPY ./ . -RUN cargo build --release - - -#################################################################################################### -## Final image -#################################################################################################### -FROM ubuntu:latest - -RUN apt update && apt install -y iproute2 && apt clean all - -COPY --from=builder /worker/target/release/tun2proxy-bin /usr/bin/tun2proxy-bin - -ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] diff --git a/README.md b/README.md index 18be7ba..107971d 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,16 @@ supplied as `--proxy http://john.doe:secret@1.2.3.4:3128`. This works analogousl Tun2proxy can serve as a proxy for other Docker containers. To make use of that feature, first build the image: ```bash -docker build -t tun2proxy . +docker buildx build -t tun2proxy . +``` + +This will build an image containing a statically linked `tun2proxy` binary (based on `musl`) without OS. + +Alternatively, you can build images based on Ubuntu or Alpine as follows: + +```bash +docker buildx build -t tun2proxy --target tun2proxy-ubuntu . +docker buildx build -t tun2proxy --target tun2proxy-alpine . ``` Next, start a container from the tun2proxy image: @@ -188,7 +197,7 @@ docker run -d \ --sysctl net.ipv6.conf.default.disable_ipv6=0 \ --cap-add NET_ADMIN \ --name tun2proxy \ - tun2proxy-bin --proxy proto://[username[:password]@]host:port + tun2proxy --proxy proto://[username[:password]@]host:port ``` You can then provide the running container's network to another worker container by sharing the network namespace (like kubernetes sidecar): @@ -200,7 +209,7 @@ docker run -it \ ``` ### Docker Compose -Write a `docker-compose.yaml` file with the following content: +Create a `docker-compose.yaml` file with the following content: ```yaml services: From fa09daabac59d7e611a98328edaedb3b9e9b9006 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Thu, 19 Jun 2025 13:42:57 +0200 Subject: [PATCH 55/63] fix: variable ref in publish-docker action --- .github/workflows/publish-docker.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 9e46180..8d6a181 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -36,7 +36,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - + # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@v3 @@ -55,7 +55,7 @@ jobs: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.os }} ${{ env.DEFAULT_OS == matrix.os && format('{0}/{1}', env.REGISTRY, env.IMAGE_NAME) || '' }} - + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. @@ -65,7 +65,7 @@ jobs: platforms: linux/amd64,linux/arm64 context: . file: Dockerfile - target: {{ env.IMAGE_NAME }}-${{ matrix.os }} + target: ${{ env.IMAGE_NAME }}-${{ matrix.os }} push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From d87562b8d3b98b0bb2f46cbfce60d354492d6c58 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Thu, 19 Jun 2025 13:43:14 +0200 Subject: [PATCH 56/63] style: add pre-commit-config --- .pre-commit-config.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4a7b842 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/rhysd/actionlint + rev: v1.7.7 + hooks: + - id: actionlint From bc00dcc5ae38bc375460a9ad4633369481642533 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Thu, 19 Jun 2025 13:47:48 +0200 Subject: [PATCH 57/63] fix: docker publish workflow --- .github/workflows/publish-docker.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 8d6a181..d136c67 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -10,7 +10,9 @@ on: # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} + # This also contains the owner, i.e. tun2proxy/tun2proxy. + IMAGE_PATH: ${{ github.repository }} + IMAGE_NAME: ${{ github.event.repository.name }} DEFAULT_OS: scratch # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. @@ -53,13 +55,13 @@ jobs: # We publish the images with an OS-suffix. # The image based on a default OS is also published without a suffix. images: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.os }} - ${{ env.DEFAULT_OS == matrix.os && format('{0}/{1}', env.REGISTRY, env.IMAGE_NAME) || '' }} + ${{ env.REGISTRY }}/${{ env.IMAGE_PATH }}-${{ matrix.os }} + ${{ env.DEFAULT_OS == matrix.os && format('{0}/{1}', env.REGISTRY, env.IMAGE_PATH) || '' }} # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - - name: Build and push Docker image (U) + - name: Build and push Docker image uses: docker/build-push-action@v6 with: platforms: linux/amd64,linux/arm64 From 0cf4427ef6ca559e00c80b957207d1126fc5e208 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 19 Jun 2025 20:15:47 +0800 Subject: [PATCH 58/63] setup_logging function --- src/bin/main.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 7bf00ef..36789a3 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -27,13 +27,20 @@ fn main() -> Result<(), BoxError> { rt.block_on(main_async(args)) } -async fn main_async(args: Args) -> Result<(), BoxError> { - let ipstack = match args.verbosity { +fn setup_logging(args: &Args) { + let avoid_trace = match args.verbosity { ArgVerbosity::Trace => ArgVerbosity::Debug, _ => args.verbosity, }; - let default = format!("{:?},hickory_proto=warn,ipstack={:?}", args.verbosity, ipstack); + let default = format!( + "{:?},hickory_proto=warn,ipstack={:?},netlink_proto={:?},netlink_sys={:?}", + args.verbosity, avoid_trace, avoid_trace, avoid_trace + ); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(default)).init(); +} + +async fn main_async(args: Args) -> Result<(), BoxError> { + setup_logging(&args); let shutdown_token = tokio_util::sync::CancellationToken::new(); let main_loop_handle = tokio::spawn({ From 3baa41a1fbd4c7b6bfcae52e71f6aa076502c310 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Thu, 19 Jun 2025 15:09:06 +0200 Subject: [PATCH 59/63] fix: support multi-arch musl builds in Dockerfile --- .github/workflows/publish-docker.yml | 4 +++- Dockerfile | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index d136c67..1288c74 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,4 +1,4 @@ -name: Create and publish a Docker image +name: Publish Docker Images on: push: @@ -18,8 +18,10 @@ env: # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. jobs: build-and-push-image: + name: Build and push Docker image runs-on: ubuntu-latest strategy: + fail-fast: false matrix: os: [ 'scratch', 'ubuntu', 'alpine' ] # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. diff --git a/Dockerfile b/Dockerfile index e8e317f..f7aafdc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,8 +21,9 @@ FROM rust:latest AS musl-builder WORKDIR /worker COPY ./ . - RUN rustup target add x86_64-unknown-linux-musl - RUN cargo build --release --target x86_64-unknown-linux-musl + RUN ARCH=$(rustc -vV | sed -nE 's/host:\s*([^-]+).*/\1/p') \ + && rustup target add "$ARCH-unknown-linux-musl" \ + && cargo build --release --target "$ARCH-unknown-linux-musl" RUN mkdir /.etc \ && touch /.etc/resolv.conf \ @@ -35,7 +36,7 @@ FROM rust:latest AS musl-builder #################################################################################################### FROM alpine:latest AS tun2proxy-alpine - COPY --from=musl-builder /worker/target/x86_64-unknown-linux-musl/release/tun2proxy-bin /usr/bin/tun2proxy-bin + COPY --from=musl-builder /worker/target/*/release/tun2proxy-bin /usr/bin/tun2proxy-bin ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] @@ -55,6 +56,6 @@ FROM scratch AS tun2proxy-scratch COPY --from=musl-builder ./tmp /tmp COPY --from=musl-builder ./etc /etc - COPY --from=musl-builder /worker/target/x86_64-unknown-linux-musl/release/tun2proxy-bin /usr/bin/tun2proxy-bin + COPY --from=musl-builder /worker/target/*/release/tun2proxy-bin /usr/bin/tun2proxy-bin ENTRYPOINT ["/usr/bin/tun2proxy-bin", "--setup"] From b5fbaa2d19bb1be363a69615525731bf9ee08f08 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Thu, 19 Jun 2025 16:08:01 +0200 Subject: [PATCH 60/63] doc: fix Docker URL in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 107971d..e813cb0 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ cargo build --release ``` ### Building Framework for Apple Devices -To build an XCFramework for macOS and iOS, run the following: +To build an XCFramework for macOS and iOS, run the following: ``` ./build-apple.sh ``` @@ -221,7 +221,7 @@ services: cap_add: - NET_ADMIN container_name: tun2proxy - image: ghcr.io/tun2proxy/tun2proxy:latest-ubuntu + image: ghcr.io/tun2proxy/tun2proxy-ubuntu:latest command: --proxy proto://[username[:password]@]host:port alpine: stdin_open: true From 9a6c96cf8b006b13d7167f1f4d1cf08d30ae3d13 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Thu, 19 Jun 2025 19:16:24 +0200 Subject: [PATCH 61/63] chore: publish v0.7.11 --- .github/workflows/publish-docker.yml | 3 --- Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 1288c74..541e53e 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -3,9 +3,6 @@ name: Publish Docker Images on: push: tags: [ 'v*.*.*' ] - release: - types: [ released ] - workflow_dispatch: # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: diff --git a/Cargo.toml b/Cargo.toml index 7e5efbe..04c93b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.7.10" +version = "0.7.11" edition = "2024" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" From 31b0972801c74162ac6a7f4c7fad214cde7598d5 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Sun, 29 Jun 2025 16:06:03 +0800 Subject: [PATCH 62/63] make rustc happy --- .github/workflows/rust.yml | 2 ++ build.rs | 4 ++-- src/args.rs | 2 +- src/bin/main.rs | 9 +++------ src/bin/udpgw_server.rs | 24 +++++++++++------------ src/general_api.rs | 4 ++-- src/http.rs | 2 +- src/lib.rs | 40 +++++++++++++++++++------------------- src/session_info.rs | 2 +- src/socks.rs | 8 ++++---- src/traffic_status.rs | 2 +- src/udpgw.rs | 14 ++++++------- src/win_svc.rs | 2 +- 13 files changed, 56 insertions(+), 59 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 82fa836..2e57100 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -8,6 +8,8 @@ on: pull_request: branches: - '**' + schedule: + - cron: '0 0 * * 0' # Every Sunday at midnight UTC env: CARGO_TERM_COLOR: always diff --git a/build.rs b/build.rs index ccf40ea..a628cef 100644 --- a/build.rs +++ b/build.rs @@ -6,7 +6,7 @@ fn main() -> Result<(), Box> { // Get the build time let build_time = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); - println!("cargo:rustc-env=BUILD_TIME={}", build_time); + println!("cargo:rustc-env=BUILD_TIME={build_time}"); #[cfg(target_os = "windows")] if let Ok(cargo_target_dir) = get_cargo_target_dir() { @@ -28,7 +28,7 @@ fn main() -> Result<(), Box> { // Copy to the target directory if let Err(e) = std::fs::copy(src_path, &dst_path) { - f.write_all(format!("Failed to copy 'wintun.dll': {}\r\n", e).as_bytes())?; + f.write_all(format!("Failed to copy 'wintun.dll': {e}\r\n").as_bytes())?; } else { f.write_all(format!("Copied 'wintun.dll' to '{}'\r\n", dst_path.display()).as_bytes())?; diff --git a/src/args.rs b/src/args.rs index 2b74748..333e758 100644 --- a/src/args.rs +++ b/src/args.rs @@ -379,7 +379,7 @@ impl Default for ArgProxy { impl std::fmt::Display for ArgProxy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let auth = match &self.credentials { - Some(creds) => format!("{}", creds), + Some(creds) => format!("{creds}"), None => "".to_owned(), }; if auth.is_empty() { diff --git a/src/bin/main.rs b/src/bin/main.rs index 36789a3..1f5142f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -50,7 +50,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { #[cfg(target_os = "linux")] if args.unshare && args.socket_transfer_fd.is_none() { if let Err(err) = namespace_proxy_main(args, shutdown_token).await { - log::error!("namespace proxy error: {}", err); + log::error!("namespace proxy error: {err}"); } return Ok(0); } @@ -133,13 +133,10 @@ async fn namespace_proxy_main( log::info!("Use `tun2proxy-bin --unshare --setup [...] -- openvpn --config [...]`"); log::info!(""); log::info!("To run a new process in the created namespace (e.g. a flatpak app)"); - log::info!( - "Use `nsenter --preserve-credentials --user --net --mount --target {} /bin/sh`", - unshare_pid - ); + log::info!("Use `nsenter --preserve-credentials --user --net --mount --target {unshare_pid} /bin/sh`"); log::info!(""); if let Some(pidfile) = _args.unshare_pidfile.as_ref() { - log::info!("Writing unshare pid to {}", pidfile); + log::info!("Writing unshare pid to {pidfile}"); std::fs::write(pidfile, unshare_pid.to_string()).ok(); } tokio::spawn(async move { tun2proxy::socket_transfer::process_socket_requests(&socket).await }); diff --git a/src/bin/udpgw_server.rs b/src/bin/udpgw_server.rs index 2a8f91d..b6c2dc6 100644 --- a/src/bin/udpgw_server.rs +++ b/src/bin/udpgw_server.rs @@ -66,14 +66,14 @@ impl UdpGwArgs { async fn send_error_response(tx: Sender, conn_id: u16) { let error_packet = Packet::build_error_packet(conn_id); if let Err(e) = tx.send(error_packet).await { - log::error!("send error response error {:?}", e); + log::error!("send error response error {e:?}"); } } async fn send_keepalive_response(tx: Sender, conn_id: u16) { let keepalive_packet = Packet::build_keepalive_packet(conn_id); if let Err(e) = tx.send(keepalive_packet).await { - log::error!("send keepalive response error {:?}", e); + log::error!("send keepalive response error {e:?}"); } } @@ -150,12 +150,12 @@ async fn process_client_udp_req(args: &UdpGwArgs, tx: Sender, mut client let packet = match res { Ok(Ok(packet)) => packet, Ok(Err(e)) => { - log::debug!("client {} retrieve_from_async_stream \"{}\"", masked_addr, e); + log::debug!("client {masked_addr} retrieve_from_async_stream \"{e}\""); break; } Err(e) => { if client.last_activity.elapsed() >= CLIENT_DISCONNECT_TIMEOUT { - log::debug!("client {} last_activity elapsed \"{e}\"", masked_addr); + log::debug!("client {masked_addr} last_activity elapsed \"{e}\""); break; } continue; @@ -166,19 +166,19 @@ async fn process_client_udp_req(args: &UdpGwArgs, tx: Sender, mut client let flags = packet.header.flags; let conn_id = packet.header.conn_id; if flags & UdpFlag::KEEPALIVE == UdpFlag::KEEPALIVE { - log::trace!("client {} send keepalive", masked_addr); + log::trace!("client {masked_addr} send keepalive"); // 2. if keepalive packet, do nothing, send keepalive response to client send_keepalive_response(tx.clone(), conn_id).await; continue; } - log::trace!("client {} received udp data {}", masked_addr, packet); + log::trace!("client {masked_addr} received udp data {packet}"); // 3. process client udpgw packet in a new task let tx = tx.clone(); tokio::spawn(async move { if let Err(e) = process_udp(udp_mtu, udp_timeout, tx.clone(), packet).await { send_error_response(tx, conn_id).await; - log::debug!("client {} process udp function \"{e}\"", masked_addr); + log::debug!("client {masked_addr} process udp function \"{e}\""); } }); } @@ -190,7 +190,7 @@ async fn write_to_client(addr: SocketAddr, mut writer: WriteHalf<'_>, mut rx: Re loop { use std::io::{Error, ErrorKind::BrokenPipe}; let packet = rx.recv().await.ok_or(Error::new(BrokenPipe, "recv error"))?; - log::trace!("send response to client {} with {}", masked_addr, packet); + log::trace!("send response to client {masked_addr} with {packet}"); let data: Vec = packet.into(); let _r = writer.write(&data).await?; } @@ -231,7 +231,7 @@ pub async fn run(args: UdpGwArgs, shutdown_token: tokio_util::sync::Cancellation }; let client = Client::new(addr); let masked_addr = mask_socket_addr(addr); - log::info!("client {} connected", masked_addr); + log::info!("client {masked_addr} connected"); let params = args.clone(); tokio::spawn(async move { let (tx, rx) = tokio::sync::mpsc::channel::(100); @@ -240,7 +240,7 @@ pub async fn run(args: UdpGwArgs, shutdown_token: tokio_util::sync::Cancellation v = process_client_udp_req(¶ms, tx, client, tcp_read_stream) => v, v = write_to_client(addr, tcp_write_stream, rx) => v, }; - log::info!("client {} disconnected with {:?}", masked_addr, res); + log::info!("client {masked_addr} disconnected with {res:?}"); }); } Ok::<(), Error>(()) @@ -263,9 +263,7 @@ fn main() -> Result<(), BoxError> { .stdout(stdout) .stderr(stderr) .privileged_action(|| "Executed before drop privileges"); - let _ = daemonize - .start() - .map_err(|e| format!("Failed to daemonize process, error:{:?}", e))?; + let _ = daemonize.start().map_err(|e| format!("Failed to daemonize process, error:{e:?}"))?; } let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?; diff --git a/src/general_api.rs b/src/general_api.rs index 843a2b3..e713409 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -100,7 +100,7 @@ pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char, tu pub fn general_run_for_api(args: Args, tun_mtu: u16, packet_information: bool) -> c_int { log::set_max_level(args.verbosity.into()); if let Err(err) = log::set_boxed_logger(Box::::default()) { - log::debug!("set logger error: {}", err); + log::debug!("set logger error: {err}"); } let shutdown_token = tokio_util::sync::CancellationToken::new(); @@ -135,7 +135,7 @@ pub fn general_run_for_api(args: Args, tun_mtu: u16, packet_information: bool) - }) { Ok(_) => 0, Err(e) => { - log::error!("failed to run tun2proxy with error: {:?}", e); + log::error!("failed to run tun2proxy with error: {e:?}"); -4 } } diff --git a/src/http.rs b/src/http.rs index caf79e9..2b08ed1 100644 --- a/src/http.rs +++ b/src/http.rs @@ -142,7 +142,7 @@ impl HttpConnection { AuthenticationScheme::Basic => { let auth_b64 = base64easy::encode(credentials.to_string(), base64easy::EngineKind::Standard); self.server_outbuf - .extend(format!("{}: Basic {}\r\n", PROXY_AUTHORIZATION, auth_b64).as_bytes()); + .extend(format!("{PROXY_AUTHORIZATION}: Basic {auth_b64}\r\n").as_bytes()); } AuthenticationScheme::None => {} } diff --git a/src/lib.rs b/src/lib.rs index ceddcf8..737a82d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -237,7 +237,7 @@ where #[cfg(feature = "udpgw")] let udpgw_client = args.udpgw_server.map(|addr| { - log::info!("UDP Gateway enabled, server: {}", addr); + log::info!("UDP Gateway enabled, server: {addr}"); use std::time::Duration; let client = Arc::new(UdpGwClient::new( mtu, @@ -292,7 +292,7 @@ where let socket_queue = socket_queue.clone(); tokio::spawn(async move { if let Err(err) = handle_tcp_session(tcp, proxy_handler, socket_queue).await { - log::error!("{} error \"{}\"", info, err); + log::error!("{info} error \"{err}\""); } log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); @@ -318,7 +318,7 @@ where let socket_queue = socket_queue.clone(); tokio::spawn(async move { if let Err(err) = handle_dns_over_tcp_session(udp, proxy_handler, socket_queue, ipv6_enabled).await { - log::error!("{} error \"{}\"", info, err); + log::error!("{info} error \"{err}\""); } log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); @@ -328,7 +328,7 @@ where tokio::spawn(async move { if let Some(virtual_dns) = virtual_dns { if let Err(err) = handle_virtual_dns_session(udp, virtual_dns).await { - log::error!("{} error \"{}\"", info, err); + log::error!("{info} error \"{err}\""); } } log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); @@ -360,7 +360,7 @@ where None => dst.into(), }; if let Err(e) = handle_udp_gateway_session(udp, udpgw, &dst_addr, proxy_handler, queue, ipv6_enabled).await { - log::info!("Ending {} with \"{}\"", info, e); + log::info!("Ending {info} with \"{e}\""); } log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); @@ -372,13 +372,13 @@ where tokio::spawn(async move { let ty = args.proxy.proxy_type; if let Err(err) = handle_udp_associate_session(udp, ty, proxy_handler, socket_queue, ipv6_enabled).await { - log::info!("Ending {} with \"{}\"", info, err); + log::info!("Ending {info} with \"{err}\""); } log::trace!("Session count {}", task_count.fetch_sub(1, Relaxed).saturating_sub(1)); }); } Err(e) => { - log::error!("Failed to create UDP connection: {}", e); + log::error!("Failed to create UDP connection: {e}"); } } } @@ -402,7 +402,7 @@ async fn handle_virtual_dns_session(mut udp: IpStackUdpStream, dns: Arc { // indicate UDP read fails not an error. - log::debug!("Virtual DNS session error: {}", e); + log::debug!("Virtual DNS session error: {e}"); break; } Ok(len) => len, @@ -412,7 +412,7 @@ async fn handle_virtual_dns_session(mut udp: IpStackUdpStream, dns: Arc {}", qname, ip); + log::debug!("Virtual DNS query: {qname} -> {ip}"); } Ok(()) } @@ -431,7 +431,7 @@ where total += n as u64; let (tx, rx) = if is_tx { (n, 0) } else { (0, n) }; if let Err(e) = crate::traffic_status::traffic_status_update(tx, rx) { - log::debug!("Record traffic status error: {}", e); + log::debug!("Record traffic status error: {e}"); } writer.write_all(&buf[..n]).await?; } @@ -453,7 +453,7 @@ async fn handle_tcp_session( let mut server = create_tcp_stream(&socket_queue, server_addr).await?; - log::info!("Beginning {}", session_info); + log::info!("Beginning {session_info}"); if let Err(e) = handle_proxy_session(&mut server, proxy_handler).await { tcp_stack.shutdown().await?; @@ -467,19 +467,19 @@ async fn handle_tcp_session( async move { let r = copy_and_record_traffic(&mut t_rx, &mut s_tx, true).await; if let Err(err) = s_tx.shutdown().await { - log::trace!("{} s_tx shutdown error {}", session_info, err); + log::trace!("{session_info} s_tx shutdown error {err}"); } r }, async move { let r = copy_and_record_traffic(&mut s_rx, &mut t_tx, false).await; if let Err(err) = t_tx.shutdown().await { - log::trace!("{} t_tx shutdown error {}", session_info, err); + log::trace!("{session_info} t_tx shutdown error {err}"); } r }, ); - log::info!("Ending {} with {:?}", session_info, res); + log::info!("Ending {session_info} with {res:?}"); Ok(()) } @@ -509,7 +509,7 @@ async fn handle_udp_gateway_session( None => { let mut tcp_server_stream = create_tcp_stream(&socket_queue, proxy_server_addr).await?; if let Err(e) = handle_proxy_session(&mut tcp_server_stream, proxy_handler).await { - return Err(format!("udpgw connection error: {}", e).into()); + return Err(format!("udpgw connection error: {e}").into()); } break UdpGwClientStream::new(tcp_server_stream); } @@ -625,7 +625,7 @@ async fn handle_udp_associate_session( ) }; - log::info!("Beginning {}", session_info); + log::info!("Beginning {session_info}"); // `_server` is meaningful here, it must be alive all the time // to ensure that UDP transmission will not be interrupted accidentally. @@ -702,7 +702,7 @@ async fn handle_udp_associate_session( } } - log::info!("Ending {}", session_info); + log::info!("Ending {session_info}"); Ok(()) } @@ -721,7 +721,7 @@ async fn handle_dns_over_tcp_session( let mut server = create_tcp_stream(&socket_queue, server_addr).await?; - log::info!("Beginning {}", session_info); + log::info!("Beginning {session_info}"); let _ = handle_proxy_session(&mut server, proxy_handler).await?; @@ -774,7 +774,7 @@ async fn handle_dns_over_tcp_session( let name = dns::extract_domain_from_dns_message(&message)?; let ip = dns::extract_ipaddr_from_dns_message(&message); - log::trace!("DNS over TCP query result: {} -> {:?}", name, ip); + log::trace!("DNS over TCP query result: {name} -> {ip:?}"); if !ipv6_enabled { dns::remove_ipv6_entries(&mut message); @@ -794,7 +794,7 @@ async fn handle_dns_over_tcp_session( } } - log::info!("Ending {}", session_info); + log::info!("Ending {session_info}"); Ok(()) } diff --git a/src/session_info.rs b/src/session_info.rs index fc4e938..a0784a9 100644 --- a/src/session_info.rs +++ b/src/session_info.rs @@ -16,7 +16,7 @@ impl std::fmt::Display for IpProtocol { IpProtocol::Tcp => write!(f, "TCP"), IpProtocol::Udp => write!(f, "UDP"), IpProtocol::Icmp => write!(f, "ICMP"), - IpProtocol::Other(v) => write!(f, "Other(0x{:02X})", v), + IpProtocol::Other(v) => write!(f, "Other(0x{v:02X})"), } } } diff --git a/src/socks.rs b/src/socks.rs index 9c8ad2d..e2265ba 100644 --- a/src/socks.rs +++ b/src/socks.rs @@ -78,7 +78,7 @@ impl SocksProxyImpl { } } SocketAddr::V6(addr) => { - return Err(format!("SOCKS4 does not support IPv6: {}", addr).into()); + return Err(format!("SOCKS4 does not support IPv6: {addr}").into()); } } self.server_outbuf.extend(ip_vec); @@ -136,7 +136,7 @@ impl SocksProxyImpl { let response = handshake::Response::retrieve_from_stream(&mut self.server_inbuf.clone()); if let Err(e) = response { if e.kind() == std::io::ErrorKind::UnexpectedEof { - log::trace!("receive_server_hello_socks5 needs more data \"{}\"...", e); + log::trace!("receive_server_hello_socks5 needs more data \"{e}\"..."); return Ok(()); } else { return Err(e); @@ -181,7 +181,7 @@ impl SocksProxyImpl { let response = Response::retrieve_from_stream(&mut self.server_inbuf.clone()); if let Err(e) = response { if e.kind() == std::io::ErrorKind::UnexpectedEof { - log::trace!("receive_auth_data needs more data \"{}\"...", e); + log::trace!("receive_auth_data needs more data \"{e}\"..."); return Ok(()); } else { return Err(e); @@ -213,7 +213,7 @@ impl SocksProxyImpl { let response = protocol::Response::retrieve_from_stream(&mut self.server_inbuf.clone()); if let Err(e) = response { if e.kind() == std::io::ErrorKind::UnexpectedEof { - log::trace!("receive_connection_status needs more data \"{}\"...", e); + log::trace!("receive_connection_status needs more data \"{e}\"..."); return Ok(()); } else { return Err(e); diff --git a/src/traffic_status.rs b/src/traffic_status.rs index 1922401..9f32b7c 100644 --- a/src/traffic_status.rs +++ b/src/traffic_status.rs @@ -51,7 +51,7 @@ static TIME_STAMP: LazyLock> = LazyLock::new(|| Mutex: pub(crate) fn traffic_status_update(delta_tx: usize, delta_rx: usize) -> Result<()> { { let is_none_or_error = TRAFFIC_STATUS_CALLBACK.lock().map(|guard| guard.is_none()).unwrap_or_else(|e| { - log::error!("Failed to acquire lock: {}", e); + log::error!("Failed to acquire lock: {e}"); true }); if is_none_or_error { diff --git a/src/udpgw.rs b/src/udpgw.rs index 3670d64..24edaad 100644 --- a/src/udpgw.rs +++ b/src/udpgw.rs @@ -32,9 +32,9 @@ impl std::fmt::Display for UdpFlag { 0x01 => "KEEPALIVE", 0x20 => "ERR", 0x02 => "DATA", - n => return write!(f, "Unknown UdpFlag(0x{:02X})", n), + n => return write!(f, "Unknown UdpFlag(0x{n:02X})"), }; - write!(f, "{}", flag) + write!(f, "{flag}") } } @@ -332,7 +332,7 @@ impl std::fmt::Display for UdpGwResponse { UdpGwResponse::KeepAlive => write!(f, "KeepAlive"), UdpGwResponse::Error => write!(f, "Error"), UdpGwResponse::TcpClose => write!(f, "TcpClose"), - UdpGwResponse::Data(packet) => write!(f, "Data({})", packet), + UdpGwResponse::Data(packet) => write!(f, "Data({packet})"), } } } @@ -487,21 +487,21 @@ impl UdpGwClient { let keepalive_packet: Vec = Packet::build_keepalive_packet(sn).into(); tx += keepalive_packet.len(); if let Err(e) = stream_writer.write_all(&keepalive_packet).await { - log::warn!("stream {} {:?} send keepalive failed: {}", sn, local_addr, e); + log::warn!("stream {sn} {local_addr:?} send keepalive failed: {e}"); continue; } match UdpGwClient::recv_udpgw_packet(self.udp_mtu, self.udp_timeout, &mut stream_reader).await { Ok((len, UdpGwResponse::KeepAlive)) => { stream.update_activity(); self.store_server_connection_full(stream, stream_reader, stream_writer).await; - log::trace!("stream {sn} {:?} send keepalive and recieve it successfully", local_addr); + log::trace!("stream {sn} {local_addr:?} send keepalive and recieve it successfully"); rx += len; } Ok((len, v)) => { - log::debug!("stream {sn} {:?} keepalive unexpected response: {v}", local_addr); + log::debug!("stream {sn} {local_addr:?} keepalive unexpected response: {v}"); rx += len; } - Err(e) => log::debug!("stream {sn} {:?} keepalive no response, error \"{e}\"", local_addr), + Err(e) => log::debug!("stream {sn} {local_addr:?} keepalive no response, error \"{e}\""), } } crate::traffic_status::traffic_status_update(tx, rx)?; diff --git a/src/win_svc.rs b/src/win_svc.rs index 5ee416e..2fed698 100644 --- a/src/win_svc.rs +++ b/src/win_svc.rs @@ -16,7 +16,7 @@ fn my_service_main(arguments: Vec) { // `service_dispatcher::start` from `main`. if let Err(_e) = run_service(arguments) { - log::error!("Error: {:?}", _e); + log::error!("Error: {_e:?}"); } } From a8ebe0b9beb78c15ea12447a146bb18a3e375d9d Mon Sep 17 00:00:00 2001 From: Koi to Coco Date: Sun, 29 Jun 2025 16:18:25 +0800 Subject: [PATCH 63/63] fix: use `vec!` to allocate buffer #213 (#214) --- src/socket_transfer.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/socket_transfer.rs b/src/socket_transfer.rs index e68bef2..4c81da7 100644 --- a/src/socket_transfer.rs +++ b/src/socket_transfer.rs @@ -157,8 +157,7 @@ where let mut buf = [0_u8; REQUEST_BUFFER_SIZE]; let mut iov = [IoSliceMut::new(&mut buf[..])]; - let mut cmsg = Vec::with_capacity(cmsg_space::() * number as usize); - + let mut cmsg = vec![0; cmsg_space::() * number as usize]; let msg = recvmsg::<()>(socket.as_fd().as_raw_fd(), &mut iov, Some(&mut cmsg), MsgFlags::empty()); let msg = match msg {