From ab9056fb8f95edac85a2f3648db9883f1aadf5cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 31 Mar 2024 19:06:52 +1100 Subject: [PATCH 01/16] Bump tokio from 1.36.0 to 1.37.0 (#348) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a18ea3cfb..382113263 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5501,9 +5501,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", From 97c9cdf3abb8b39ff77263359ab04b4768b719c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:03:42 +1100 Subject: [PATCH 02/16] Bump security-framework from 2.9.2 to 2.10.0 (#351) --- Cargo.lock | 8 ++++---- clash_lib/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 382113263..6c14492bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4764,9 +4764,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -4777,9 +4777,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index 80e2a445d..f41f9a76b 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -129,4 +129,4 @@ serial_test = "3.0.0" tracing-test = "0.2.4" [target.'cfg(macos)'.dependencies] -security-framework = "2.8.0" +security-framework = "2.10.0" From bdb102f0adeb4f88524fc38a051676de2ecb4fe5 Mon Sep 17 00:00:00 2001 From: Yuwei Ba Date: Thu, 4 Apr 2024 02:33:44 +1100 Subject: [PATCH 03/16] fix docker tests trigger on CI (#347) * f * ci trigger * f * Update ci.yml Signed-off-by: Yuwei Ba * Update ci.yml Signed-off-by: Yuwei Ba * Update ci.yml Signed-off-by: Yuwei Ba * f --------- Signed-off-by: Yuwei Ba --- .github/workflows/ci.yml | 12 ++++++------ clash_lib/build.rs | 2 +- clash_lib/src/lib.rs | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7ee4077e..a5756a387 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,6 @@ name: Build/Test/Release on: push: - branches: [ "*" ] tags: [ "v*" ] pull_request: branches: [ "master" ] @@ -29,6 +28,7 @@ jobs: with: submodules: recursive - uses: ilammy/setup-nasm@v1 + if : ${{ matrix.platforms.os == 'windows-2022' }} - uses: dtolnay/rust-toolchain@stable with: toolchain: stable @@ -39,13 +39,13 @@ jobs: run: cargo check --all --all-features - name: Run cargo clippy run: cargo clippy --all --all-features -- -D warnings - - name: Run cargo test on non-macos - if: ${{ matrix.os }} != 'macos-13' + - name: Run cargo test on Linux + if: ${{ matrix.platforms.os == 'ubuntu-22.04' }} run: cargo test --all --all-features - env: + - name: Run cargo test on non LInux + env: # this is a bit counter intuitive - some tests relies on Docker to run and are marked not(ci), but macos runner doesn't have Docker installed, so we make it "ci" to bypass those tests CLASH_RS_CI: 'true' - - name: Run cargo test on macos - if: ${{ matrix.os }} == 'macos-13' + if: ${{ matrix.platforms.os != 'ubuntu-22.04' }} run: cargo test --all --all-features - name: Build artifacts run: sh ./scripts/build.sh "${{ matrix.platforms.target }}" "${{ matrix.static }}" diff --git a/clash_lib/build.rs b/clash_lib/build.rs index aa8dfbf64..4c2fde659 100644 --- a/clash_lib/build.rs +++ b/clash_lib/build.rs @@ -1,5 +1,5 @@ fn main() { if std::env::var("CLASH_RS_CI").is_ok() { - println!("cargo:rustc-cfg=ci"); + println!("cargo::rustc-cfg=ci"); } } diff --git a/clash_lib/src/lib.rs b/clash_lib/src/lib.rs index 3910e8785..793cbcaf3 100644 --- a/clash_lib/src/lib.rs +++ b/clash_lib/src/lib.rs @@ -149,7 +149,8 @@ async fn start_async(opts: Options) -> Result<(), Error> { let _g = app::logging::setup_logging(config.general.log_level, log_collector, &cwd, opts.log_file) - .map_err(|x| Error::InvalidConfig(format!("failed to setup logging: {}", x)))?; + .map_err(|x| eprintln!("failed to setup logging: {}", x)) + .unwrap_or_default(); let default_panic = std::panic::take_hook(); std::panic::set_hook(Box::new(move |info| { From 93501d5010773d6dde116f43a2069c59762d2516 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 03:20:24 +0000 Subject: [PATCH 04/16] Bump network-interface from 1.1.2 to 1.1.3 (#355) Bumps [network-interface](https://github.com/EstebanBorai/network-interface) from 1.1.2 to 1.1.3. - [Release notes](https://github.com/EstebanBorai/network-interface/releases) - [Changelog](https://github.com/EstebanBorai/network-interface/blob/main/CHANGELOG.md) - [Commits](https://github.com/EstebanBorai/network-interface/compare/v1.1.2...v1.1.3) --- updated-dependencies: - dependency-name: network-interface dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- clash_lib/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c14492bc..ce7d0a4eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3406,9 +3406,9 @@ dependencies = [ [[package]] name = "network-interface" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee524f98ddbe7772762a7477cfb22356df075cac4069bf81ac5082a46db742c" +checksum = "ae72fd9dbd7f55dda80c00d66acc3b2130436fcba9ea89118fc508eaae48dfb0" dependencies = [ "cc", "libc", diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index f41f9a76b..1c3f26656 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -32,7 +32,7 @@ prost = "0.12" tower = { version = "0.4", features = ["util"] } libc = "0.2" foreign-types-shared = "0.3.1" -network-interface = "1.1.2" +network-interface = "1.1.3" base64 = "0.22" uuid = { version = "1.8.0", features = ["v4", "fast-rng", "macro-diagnostics", "serde"] } boring = "4.5.0" From 62973da700338398fbd42d736f5ed751614b1f69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 04:04:42 +0000 Subject: [PATCH 05/16] Bump h2 from 0.4.3 to 0.4.4 (#357) Bumps [h2](https://github.com/hyperium/h2) from 0.4.3 to 0.4.4. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.4.3...v0.4.4) --- updated-dependencies: - dependency-name: h2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- clash_lib/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce7d0a4eb..729389116 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1100,7 +1100,7 @@ dependencies = [ "filetime", "foreign-types-shared", "futures", - "h2 0.4.3", + "h2 0.4.4", "hickory-client", "hickory-proto", "hickory-resolver", @@ -2333,9 +2333,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" +checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" dependencies = [ "bytes", "fnv", diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index 1c3f26656..f70ee304c 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -27,7 +27,7 @@ lru_time_cache = "0.11" hyper = { version = "0.14.28", features = ["http1","http2","client", "server", "tcp"] } http = { version = "1.1" } httparse = "1.8.0" -h2 = "0.4.3" +h2 = "0.4.4" prost = "0.12" tower = { version = "0.4", features = ["util"] } libc = "0.2" From 606caf2887c950e8f7087a5389ad749504fa2753 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 17:53:21 +1100 Subject: [PATCH 06/16] Bump brotli from 3.5.0 to 4.0.0 (#356) --- Cargo.lock | 8 ++++---- clash_lib/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 729389116..079bf332c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -795,9 +795,9 @@ checksum = "2225b558afc76c596898f5f1b3fc35cfce0eb1b13635cbd7d1b2a7177dc10ccd" [[package]] name = "brotli" -version = "3.5.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" +checksum = "125740193d7fee5cc63ab9e16c2fdc4e07c74ba755cc53b327d6ea029e9fc569" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -806,9 +806,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +checksum = "65622a320492e09b5e0ac436b14c54ff68199bac392d0e89a6832c4518eea525" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index f70ee304c..844cabca2 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -50,7 +50,7 @@ opentelemetry-jaeger = { version = "0.21", features = ["collector_client", "hype opentelemetry-otlp = { version = "0.15.0", features = ["http-proto"] } crc32fast = "1.4.0" -brotli = "3.5.0" +brotli = "4.0.0" hmac = "0.12.1" sha2 = "0.10.8" md-5 = "0.10.5" From 29287804f2d92a89f75331e650e43ef2c674dce6 Mon Sep 17 00:00:00 2001 From: V Date: Sun, 7 Apr 2024 18:54:30 +0800 Subject: [PATCH 07/16] enhance/multi docker test (#358) --- clash_lib/src/proxy/shadowsocks/mod.rs | 13 ++- clash_lib/src/proxy/trojan/mod.rs | 6 +- .../src/proxy/utils/test_utils/consts.rs | 1 + .../proxy/utils/test_utils/docker_runner.rs | 109 +++++++++++++++--- clash_lib/src/proxy/utils/test_utils/mod.rs | 18 +-- clash_lib/src/proxy/vmess/mod.rs | 8 +- 6 files changed, 112 insertions(+), 43 deletions(-) diff --git a/clash_lib/src/proxy/shadowsocks/mod.rs b/clash_lib/src/proxy/shadowsocks/mod.rs index ade423be0..eacff40bd 100644 --- a/clash_lib/src/proxy/shadowsocks/mod.rs +++ b/clash_lib/src/proxy/shadowsocks/mod.rs @@ -291,20 +291,22 @@ impl OutboundHandler for Handler { #[cfg(all(test, not(ci)))] mod tests { + use super::super::utils::test_utils::{ + consts::*, docker_runner::DockerTestRunner, run_default_test_suites_and_cleanup, + }; use crate::proxy::utils::test_utils::docker_runner::DockerTestRunnerBuilder; - use super::super::utils::test_utils::{consts::*, docker_runner::DockerTestRunner, run}; - use super::*; const PASSWORD: &str = "FzcLbKs2dY9mhL"; const CIPHER: &str = "aes-256-gcm"; - async fn get_runner() -> anyhow::Result { + async fn get_ss_runner(port: u16) -> anyhow::Result { + let host = format!("0.0.0.0:{}", port); DockerTestRunnerBuilder::new() .image(IMAGE_SS_RUST) .entrypoint(&["ssserver"]) - .cmd(&["-s", "0.0.0.0:10002", "-m", CIPHER, "-k", PASSWORD, "-U"]) + .cmd(&["-s", &host, "-m", CIPHER, "-k", PASSWORD, "-U"]) .build() .await } @@ -322,7 +324,8 @@ mod tests { plugin_opts: Default::default(), udp: false, }; + let port = opts.port; let handler = Handler::new(opts); - run(handler, get_runner()).await + run_default_test_suites_and_cleanup(handler, get_ss_runner(port).await?).await } } diff --git a/clash_lib/src/proxy/trojan/mod.rs b/clash_lib/src/proxy/trojan/mod.rs index 233b8b92e..7b4bfcc80 100644 --- a/clash_lib/src/proxy/trojan/mod.rs +++ b/clash_lib/src/proxy/trojan/mod.rs @@ -231,7 +231,7 @@ mod tests { config_helper::test_config_base_dir, consts::*, docker_runner::{DockerTestRunner, DockerTestRunnerBuilder}, - run, + run_default_test_suites_and_cleanup, }; use super::*; @@ -278,7 +278,7 @@ mod tests { })), }; let handler = Handler::new(opts); - run(handler, get_ws_runner()).await + run_default_test_suites_and_cleanup(handler, get_ws_runner().await?).await } async fn get_grpc_runner() -> anyhow::Result { @@ -317,6 +317,6 @@ mod tests { })), }; let handler = Handler::new(opts); - run(handler, get_grpc_runner()).await + run_default_test_suites_and_cleanup(handler, get_grpc_runner().await?).await } } diff --git a/clash_lib/src/proxy/utils/test_utils/consts.rs b/clash_lib/src/proxy/utils/test_utils/consts.rs index 600c9221d..58ef48123 100644 --- a/clash_lib/src/proxy/utils/test_utils/consts.rs +++ b/clash_lib/src/proxy/utils/test_utils/consts.rs @@ -3,6 +3,7 @@ pub const EXAMPLE_REQ: &[u8] = b"GET / HTTP/1.1\r\nHost: example.com\r\nAccept: pub const EXAMLE_RESP_200: &[u8] = b"HTTP/1.1 200"; pub const IMAGE_SS_RUST: &str = "ghcr.io/shadowsocks/ssserver-rust:latest"; +pub const IMAGE_SHADOW_TLS: &str = "ghcr.io/ihciah/shadow-tls:latest"; pub const IMAGE_TROJAN_GO: &str = "p4gefau1t/trojan-go:latest"; pub const IMAGE_VMESS: &str = "v2fly/v2fly-core:v4.45.2"; pub const IMAGE_XRAY: &str = "teddysun/xray:latest"; diff --git a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs index ac12ffc62..a95e413c8 100644 --- a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs +++ b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs @@ -17,7 +17,7 @@ pub struct DockerTestRunner { } impl DockerTestRunner { - pub async fn new<'a>( + pub async fn try_new<'a>( image_conf: Option>, container_conf: Config, ) -> Result { @@ -39,10 +39,62 @@ impl DockerTestRunner { }) } - // will make sure the container is cleaned up after the future is finished - pub async fn run_and_cleanup( + // you can run the cleanup manually + pub async fn cleanup(self) -> anyhow::Result<()> { + let s = self + .instance + .remove_container( + &self.id, + Some(RemoveContainerOptions { + force: true, + ..Default::default() + }), + ) + .await?; + Ok(s) + } +} + +#[derive(Default)] +pub struct MultiDockerTestRunner { + runners: Vec, +} + +// TODO: use this test runner to support test of ss's plugins +#[allow(unused)] +impl MultiDockerTestRunner { + pub fn new(runners: Vec) -> Self { + Self { runners } + } + + pub async fn add(&mut self, creator: impl Future>) { + match creator.await { + Ok(runner) => { + self.runners.push(runner); + } + Err(e) => { + tracing::warn!( + "cannot start container, please check the docker environment, error: {:?}", + e + ); + } + } + } +} + +#[async_trait::async_trait] +pub trait RunAndCleanup { + async fn run_and_cleanup( + self, + f: impl Future> + Send + 'static, + ) -> anyhow::Result<()>; +} + +#[async_trait::async_trait] +impl RunAndCleanup for DockerTestRunner { + async fn run_and_cleanup( self, - f: impl Future>, + f: impl Future> + Send + 'static, ) -> anyhow::Result<()> { let fut = Box::pin(f); // let res = fut.await; @@ -61,20 +113,33 @@ impl DockerTestRunner { res } +} - // you can run the cleanup manually - pub async fn cleanup(self) -> anyhow::Result<()> { - let s = self - .instance - .remove_container( - &self.id, - Some(RemoveContainerOptions { - force: true, - ..Default::default() - }), - ) - .await?; - Ok(s) +#[async_trait::async_trait] +impl RunAndCleanup for MultiDockerTestRunner { + async fn run_and_cleanup( + self, + f: impl Future> + Send + 'static, + ) -> anyhow::Result<()> { + let fut = Box::pin(f); + // let res = fut.await; + // make sure the container is cleaned up + let res = tokio::select! { + res = fut => { + res + }, + _ = tokio::time::sleep(std::time::Duration::from_secs(TIMEOUT_DURATION))=> { + tracing::warn!("timeout"); + Err(anyhow::anyhow!("timeout")) + } + }; + + // cleanup all the docker containers + for runner in self.runners { + runner.cleanup().await?; + } + + res } } @@ -89,6 +154,7 @@ pub struct DockerTestRunnerBuilder { host_config: HostConfig, exposed_ports: Vec, cmd: Option>, + env: Option>, entrypoint: Option>, _server_port: u16, } @@ -103,6 +169,7 @@ impl Default for DockerTestRunnerBuilder { .map(|x| x.to_string()) .collect::>(), cmd: None, + env: None, entrypoint: None, _server_port: PORT, } @@ -135,6 +202,11 @@ impl DockerTestRunnerBuilder { self } + pub fn env(mut self, env: &[&str]) -> Self { + self.env = Some(env.iter().map(|x| x.to_string()).collect()); + self + } + pub fn entrypoint(mut self, entrypoint: &[&str]) -> Self { self.entrypoint = Some(entrypoint.iter().map(|x| x.to_string()).collect()); self @@ -165,7 +237,7 @@ impl DockerTestRunnerBuilder { .map(|x| (x, Default::default())) .collect::>(); - DockerTestRunner::new( + DockerTestRunner::try_new( Some(CreateImageOptions { from_image: self.image.clone(), ..Default::default() @@ -175,6 +247,7 @@ impl DockerTestRunnerBuilder { tty: Some(true), entrypoint: self.entrypoint, cmd: self.cmd, + env: self.env, exposed_ports: Some(exposed), host_config: Some(self.host_config), ..Default::default() diff --git a/clash_lib/src/proxy/utils/test_utils/mod.rs b/clash_lib/src/proxy/utils/test_utils/mod.rs index d61905bb7..230f60a25 100644 --- a/clash_lib/src/proxy/utils/test_utils/mod.rs +++ b/clash_lib/src/proxy/utils/test_utils/mod.rs @@ -8,14 +8,14 @@ use crate::{ proxy::OutboundHandler, session::{Session, SocksAddr}, }; -use futures::{future::select_all, Future}; +use futures::future::select_all; use tokio::{ io::{split, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, net::TcpListener, }; use tracing::info; -use self::docker_runner::DockerTestRunner; +use self::docker_runner::RunAndCleanup; pub mod config_helper; pub mod consts; @@ -176,19 +176,11 @@ pub async fn latency_test( Ok(end_time.duration_since(start_time)) } -pub async fn run( +pub async fn run_default_test_suites_and_cleanup( handler: Arc, - runner_creater: impl Future>, + docker_test_runner: impl RunAndCleanup, ) -> anyhow::Result<()> { - let watch = match runner_creater.await { - Ok(runner) => runner, - Err(e) => { - tracing::warn!("cannot start container, please check the docker environment"); - return Err(e); - } - }; - - watch + docker_test_runner .run_and_cleanup(async move { let rv = ping_pong_test(handler.clone(), 10001).await; if rv.is_err() { diff --git a/clash_lib/src/proxy/vmess/mod.rs b/clash_lib/src/proxy/vmess/mod.rs index c600a0efc..f8977b5ae 100644 --- a/clash_lib/src/proxy/vmess/mod.rs +++ b/clash_lib/src/proxy/vmess/mod.rs @@ -262,7 +262,7 @@ mod tests { config_helper::test_config_base_dir, consts::*, docker_runner::{DockerTestRunner, DockerTestRunnerBuilder}, - run, + run_default_test_suites_and_cleanup, }; use super::*; @@ -303,7 +303,7 @@ mod tests { })), }; let handler = Handler::new(opts); - run(handler, get_ws_runner()).await + run_default_test_suites_and_cleanup(handler, get_ws_runner().await?).await } async fn get_grpc_runner() -> anyhow::Result { @@ -346,7 +346,7 @@ mod tests { })), }; let handler = Handler::new(opts); - run(handler, get_grpc_runner()).await + run_default_test_suites_and_cleanup(handler, get_grpc_runner().await?).await } async fn get_h2_runner() -> anyhow::Result { @@ -389,6 +389,6 @@ mod tests { })), }; let handler = Handler::new(opts); - run(handler, get_h2_runner()).await + run_default_test_suites_and_cleanup(handler, get_h2_runner().await?).await } } From a0b26042421e37bfb3af1e5de70eb714a59b7970 Mon Sep 17 00:00:00 2001 From: V Date: Tue, 9 Apr 2024 09:11:03 +0800 Subject: [PATCH 08/16] feat: support shadow-tls(v3 only) (#346) * update rustls & tokio-rustls deps, add utls feature; add shadows-tls impl * fix: remove unnecessary logs; check fake_request's result before return error * cargo fmt * add MultiDockerTestRunner to support shadowtls plugin test; modify some names * simplify docker test workflow * fix clippy warnings * cargo fmt * f --------- Co-authored-by: Yuwei Ba Co-authored-by: Yuwei B --- Cargo.lock | 82 ++- Cargo.toml | 6 +- clash_lib/Cargo.toml | 2 +- clash_lib/src/app/inbound/network_listener.rs | 5 +- clash_lib/src/proxy/converters/shadowsocks.rs | 9 + clash_lib/src/proxy/shadowsocks/mod.rs | 102 +++- .../proxy/shadowsocks/shadow_tls/connector.rs | 161 ++++++ .../src/proxy/shadowsocks/shadow_tls/mod.rs | 6 + .../proxy/shadowsocks/shadow_tls/stream.rs | 502 ++++++++++++++++++ .../src/proxy/shadowsocks/shadow_tls/utils.rs | 167 ++++++ clash_lib/src/proxy/trojan/mod.rs | 10 +- clash_lib/src/proxy/utils/socket_helpers.rs | 1 + .../proxy/utils/test_utils/config_helper.rs | 6 +- .../proxy/utils/test_utils/docker_runner.rs | 14 +- clash_lib/src/proxy/utils/test_utils/mod.rs | 6 +- clash_lib/src/proxy/vmess/mod.rs | 11 +- 16 files changed, 1018 insertions(+), 72 deletions(-) create mode 100644 clash_lib/src/proxy/shadowsocks/shadow_tls/connector.rs create mode 100644 clash_lib/src/proxy/shadowsocks/shadow_tls/mod.rs create mode 100644 clash_lib/src/proxy/shadowsocks/shadow_tls/stream.rs create mode 100644 clash_lib/src/proxy/shadowsocks/shadow_tls/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 079bf332c..bdd552990 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -822,9 +822,9 @@ checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "by_address" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8dba2868114ed769a1f2590fc9ae5eb331175b44313b6c9b922f8f7ca813d0" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "byte_string" @@ -1132,13 +1132,14 @@ dependencies = [ "rand", "regex", "register-count", - "rustls 0.21.10", + "rustls 0.21.8", "rustls-pemfile", "security-framework", "serde", "serde_json", "serde_yaml", "serial_test", + "sha1", "sha2", "shadowsocks", "smoltcp", @@ -1158,7 +1159,6 @@ dependencies = [ "tracing-opentelemetry", "tracing-oslog", "tracing-subscriber", - "tracing-test", "tracing-timing", "tuic", "tuic-quinn", @@ -1629,11 +1629,11 @@ dependencies = [ [[package]] name = "derive-adhoc" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc3f185a1a0d933e54447b3492fe9880db2c3ad37c04b3a3bf9b24a73b7bd02" +checksum = "0c768757217a40364c3af0b732d10bf9ed8af1e4f80b32fd5eeed94f375304b8" dependencies = [ - "derive-adhoc-macros 0.8.3", + "derive-adhoc-macros 0.8.4", "heck 0.4.1", ] @@ -1656,9 +1656,9 @@ dependencies = [ [[package]] name = "derive-adhoc-macros" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f1a082460419acefc6a66ff74c6e15c460d9b95530697f5d10892ee624aa60" +checksum = "3b41d3d974cda1ce7e9b40f7ec5160a099f20345bc3137447e526e3ba9d63245" dependencies = [ "heck 0.4.1", "itertools 0.12.1", @@ -2515,7 +2515,7 @@ dependencies = [ "once_cell", "rand", "ring 0.16.20", - "rustls 0.21.10", + "rustls 0.21.8", "rustls-pemfile", "serde", "thiserror", @@ -2541,7 +2541,7 @@ dependencies = [ "parking_lot 0.12.1", "rand", "resolv-conf", - "rustls 0.21.10", + "rustls 0.21.8", "serde", "smallvec", "thiserror", @@ -2565,7 +2565,7 @@ dependencies = [ "hickory-proto", "hickory-resolver", "http 0.2.12", - "rustls 0.21.10", + "rustls 0.21.8", "serde", "thiserror", "time", @@ -2778,7 +2778,7 @@ dependencies = [ "http 0.2.12", "hyper 0.14.28", "log", - "rustls 0.21.10", + "rustls 0.21.8", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3288,9 +3288,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" @@ -3980,9 +3980,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platforms" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "plotters" @@ -4262,7 +4262,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.21.10", + "rustls 0.21.8", "thiserror", "tokio", "tracing", @@ -4278,7 +4278,7 @@ dependencies = [ "rand", "ring 0.16.20", "rustc-hash", - "rustls 0.21.10", + "rustls 0.21.8", "slab", "thiserror", "tinyvec", @@ -4420,7 +4420,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -4440,7 +4440,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -4451,9 +4451,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "register-count" @@ -4608,9 +4608,8 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +version = "0.21.8" +source = "git+https://github.com/Watfaq/rustls.git?rev=43ecd5c610741668488e6d57857f9900a2087a5b#43ecd5c610741668488e6d57857f9900a2087a5b" dependencies = [ "log", "ring 0.17.8", @@ -4654,9 +4653,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868e20fada228fefaf6b652e00cc73623d54f8171e7352c18bb281571f2d92da" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" [[package]] name = "rustls-webpki" @@ -5543,10 +5542,9 @@ dependencies = [ [[package]] name = "tokio-rustls" version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +source = "git+https://github.com/Watfaq/tokio-rustls.git?rev=fcda89f6348c1e696b239bc7e0b168015cfb8c08#fcda89f6348c1e696b239bc7e0b168015cfb8c08" dependencies = [ - "rustls 0.21.10", + "rustls 0.21.8", "tokio", ] @@ -5918,7 +5916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c579e92f3b9e419e68cd317d33f567491365b81f943b063d30f32e4a2f072c5" dependencies = [ "config", - "derive-adhoc 0.8.3", + "derive-adhoc 0.8.4", "derive_builder_fork_arti", "directories", "educe", @@ -6096,7 +6094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4613dfe9d946db3b5769b860a16598a9c4a0f85df21653d0765b1238106d297" dependencies = [ "async-trait", - "derive-adhoc 0.8.3", + "derive-adhoc 0.8.4", "derive_more", "educe", "either", @@ -6164,7 +6162,7 @@ checksum = "365c02c66f2f0159078714dd44947fb06c76956a3621fc102783119e5093be96" dependencies = [ "amplify", "arrayvec", - "derive-adhoc 0.8.3", + "derive-adhoc 0.8.4", "derive_builder_fork_arti", "derive_more", "downcast-rs", @@ -6346,7 +6344,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4bbf6c0a786daab669a75ec7380ae57f9aba91f2c4ea05a12e596d9bc6b49a0" dependencies = [ - "derive-adhoc 0.8.3", + "derive-adhoc 0.8.4", "derive_more", "filetime", "fs-mistrust", @@ -6448,7 +6446,7 @@ dependencies = [ "amplify", "async-trait", "backtrace", - "derive-adhoc 0.8.3", + "derive-adhoc 0.8.4", "derive_more", "educe", "futures", @@ -7415,27 +7413,27 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.0.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index a348c3312..d8a2a56dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,8 @@ edition = "2021" opt-level = "s" codegen-units = 1 lto = true -strip = true \ No newline at end of file +strip = true + +[patch.crates-io] +tokio-rustls = { git = "https://github.com/Watfaq/tokio-rustls.git", rev = "fcda89f6348c1e696b239bc7e0b168015cfb8c08"} +rustls = { git = "https://github.com/Watfaq/rustls.git", rev = "43ecd5c610741668488e6d57857f9900a2087a5b"} diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index 844cabca2..faf9e6d71 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -52,6 +52,7 @@ opentelemetry-otlp = { version = "0.15.0", features = ["http-proto"] } crc32fast = "1.4.0" brotli = "4.0.0" hmac = "0.12.1" +sha1 = "0.10" sha2 = "0.10.8" md-5 = "0.10.5" chacha20poly1305 = "0.10" @@ -126,7 +127,6 @@ tokio-test = "0.4.4" axum-macros = "0.4.0" bollard = "0.16" serial_test = "3.0.0" -tracing-test = "0.2.4" [target.'cfg(macos)'.dependencies] security-framework = "2.10.0" diff --git a/clash_lib/src/app/inbound/network_listener.rs b/clash_lib/src/app/inbound/network_listener.rs index 9d3db7ea5..34642f769 100644 --- a/clash_lib/src/app/inbound/network_listener.rs +++ b/clash_lib/src/app/inbound/network_listener.rs @@ -12,7 +12,7 @@ use tracing::{info, warn}; use std::net::{IpAddr, Ipv4Addr}; use std::sync::Arc; -#[derive(Eq, PartialEq, Hash)] +#[derive(Eq, PartialEq, Hash, Clone, Debug)] pub enum ListenerType { Http, Socks5, @@ -114,13 +114,14 @@ impl NetworkInboundListener { }; if listener.handle_tcp() { + let listener_type = self.listener_type.clone(); info!("{} TCP listening at: {}:{}", self.name, ip, self.port); let tcp_listener = listener.clone(); runners.push( async move { tcp_listener.listen_tcp().await.map_err(|e| { - warn!("handler tcp listen failed: {}", e); + warn!("handler of {:?} tcp listen failed: {}", listener_type, e); e.into() }) } diff --git a/clash_lib/src/proxy/converters/shadowsocks.rs b/clash_lib/src/proxy/converters/shadowsocks.rs index b916650c9..02adb2f9a 100644 --- a/clash_lib/src/proxy/converters/shadowsocks.rs +++ b/clash_lib/src/proxy/converters/shadowsocks.rs @@ -46,6 +46,15 @@ impl TryFrom<&OutboundShadowsocks> for AnyOutboundHandler { .try_into() .map(OBFSOption::V2Ray) .ok(), + "shadow-tls" => s + .plugin_opts + .clone() + .ok_or(Error::InvalidConfig( + "plugin_opts is required for plugin obfs".to_owned(), + ))? + .try_into() + .map(OBFSOption::ShadowTls) + .ok(), _ => { return Err(Error::InvalidConfig(format!( "unsupported plugin: {}", diff --git a/clash_lib/src/proxy/shadowsocks/mod.rs b/clash_lib/src/proxy/shadowsocks/mod.rs index eacff40bd..86f14d083 100644 --- a/clash_lib/src/proxy/shadowsocks/mod.rs +++ b/clash_lib/src/proxy/shadowsocks/mod.rs @@ -1,4 +1,5 @@ mod datagram; +mod shadow_tls; mod simple_obfs; mod stream; mod v2ray; @@ -129,9 +130,42 @@ impl TryFrom> for V2RayOBFSOption { } } +#[derive(Debug)] +pub struct ShadowTlsOption { + pub host: String, + pub password: String, + pub strict: bool, +} + +impl TryFrom> for ShadowTlsOption { + type Error = crate::Error; + + fn try_from(value: HashMap) -> Result { + let host = value + .get("host") + .and_then(|x| x.as_str()) + .unwrap_or("bing.com"); + let password = value + .get("password") + .and_then(|x| x.as_str().to_owned()) + .ok_or(Error::InvalidConfig("obfs mode is required".to_owned()))?; + let strict = value + .get("strict") + .and_then(|x| x.as_bool()) + .unwrap_or(true); + + Ok(Self { + host: host.to_string(), + password: password.to_string(), + strict, + }) + } +} + pub enum OBFSOption { Simple(SimpleOBFSOption), V2Ray(V2RayOBFSOption), + ShadowTls(ShadowTlsOption), } pub struct HandlerOptions { @@ -227,6 +261,11 @@ impl OutboundHandler for Handler { OBFSOption::V2Ray(_opt) => { todo!("v2ray-plugin is not implemented yet") } + OBFSOption::ShadowTls(opts) => { + tracing::debug!("using shadow-tls with option: {:?}", opts); + + (shadow_tls::Connector::wrap(opts, s).await?) as _ + } }, None => s, }; @@ -291,15 +330,17 @@ impl OutboundHandler for Handler { #[cfg(all(test, not(ci)))] mod tests { - use super::super::utils::test_utils::{ - consts::*, docker_runner::DockerTestRunner, run_default_test_suites_and_cleanup, + use super::super::utils::test_utils::{consts::*, docker_runner::DockerTestRunner}; + use crate::proxy::utils::test_utils::{ + docker_runner::{DockerTestRunnerBuilder, MultiDockerTestRunner}, + run_default_test_suites_and_cleanup, }; - use crate::proxy::utils::test_utils::docker_runner::DockerTestRunnerBuilder; use super::*; const PASSWORD: &str = "FzcLbKs2dY9mhL"; const CIPHER: &str = "aes-256-gcm"; + const SHADOW_TLS_PASSWORD: &str = "password"; async fn get_ss_runner(port: u16) -> anyhow::Result { let host = format!("0.0.0.0:{}", port); @@ -328,4 +369,59 @@ mod tests { let handler = Handler::new(opts); run_default_test_suites_and_cleanup(handler, get_ss_runner(port).await?).await } + + async fn get_shadowtls_runner( + ss_port: u16, + stls_port: u16, + ) -> anyhow::Result { + let ss_server_env = format!("SERVER=127.0.0.1:{}", ss_port); + let listen_env = format!("LISTEN=0.0.0.0:{}", stls_port); + let password = format!("PASSWORD={}", SHADOW_TLS_PASSWORD); + DockerTestRunnerBuilder::new() + .image(IMAGE_SHADOW_TLS) + .env(&[ + "MODE=server", + // the port that we need to fill in the config + &listen_env, + // shadowsocks server addr + &ss_server_env, + "TLS=www.feishu.cn:443", + &password, + "V3=1", + ]) + // .cmd(&["-s", "0.0.0.0:10002", "-m", CIPHER, "-k", PASSWORD, "-U"]) + .build() + .await + } + + #[tokio::test] + #[serial_test::serial] + async fn test_shadowtls() -> anyhow::Result<()> { + // the real port that used for communication + let shadow_tls_port = 10002; + // not important, you can assign any port that is not conflict with others + let ss_port = 10004; + let opts = HandlerOptions { + name: "test-ss".to_owned(), + common_opts: Default::default(), + server: LOCAL_ADDR.to_owned(), + port: shadow_tls_port, + password: PASSWORD.to_owned(), + cipher: CIPHER.to_owned(), + plugin_opts: Some(OBFSOption::ShadowTls(ShadowTlsOption { + host: "www.feishu.cn".to_owned(), + password: "password".to_owned(), + strict: true, + })), + udp: false, + }; + let handler = Handler::new(opts); + // we need to store all the runners in a container, to make sure all of them can be destroyed after the test + let mut chained = MultiDockerTestRunner::default(); + chained.add(get_ss_runner(ss_port)).await; + chained + .add(get_shadowtls_runner(ss_port, shadow_tls_port)) + .await; + run_default_test_suites_and_cleanup(handler, chained).await + } } diff --git a/clash_lib/src/proxy/shadowsocks/shadow_tls/connector.rs b/clash_lib/src/proxy/shadowsocks/shadow_tls/connector.rs new file mode 100644 index 000000000..af0413d17 --- /dev/null +++ b/clash_lib/src/proxy/shadowsocks/shadow_tls/connector.rs @@ -0,0 +1,161 @@ +use std::io; +use std::ptr::copy_nonoverlapping; +use std::sync::Arc; + +use rand::Rng; + +use rand::distributions::Distribution; +use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; +use tokio_rustls::client::TlsStream; +use tokio_rustls::rustls::ClientConfig; +use tokio_rustls::TlsConnector; + +use crate::proxy::shadowsocks::ShadowTlsOption; +use crate::proxy::AnyStream; + +use super::prelude::*; + +use super::stream::{ProxyTlsStream, VerifiedStream}; +use super::utils::Hmac; + +#[derive(Clone, Debug)] +#[allow(unused)] +pub struct Opts { + pub fastopen: bool, + pub sni: String, + pub strict: bool, +} + +pub struct Connector { + pub password: String, + pub server_addr: String, + pub tls_config: ClientConfig, + pub connector: TlsConnector, +} + +impl Connector { + fn connector() -> TlsConnector { + use crate::common::tls::GLOBAL_ROOT_STORE; + + let tls_config = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(GLOBAL_ROOT_STORE.clone()) + .with_no_client_auth(); + + TlsConnector::from(Arc::new(tls_config.clone())) + } + + pub async fn wrap(opts: &ShadowTlsOption, stream: AnyStream) -> std::io::Result { + let proxy_stream = ProxyTlsStream::new(stream, &opts.password); + + let hamc_handshake = Hmac::new(&opts.password, (&[], &[])); + let sni_name = rustls::ServerName::try_from(opts.host.as_str()) + .unwrap_or_else(|_| panic!("invalid server name: {}", opts.host)); + let session_id_generator = move |data: &_| generate_session_id(&hamc_handshake, data); + let connector = Self::connector(); + let mut tls = connector + .connect_with(sni_name, proxy_stream, Some(session_id_generator), |_| {}) + .await?; + let authorized = tls.get_mut().0.authorized(); + let maybe_server_random_and_hamc = tls + .get_mut() + .0 + .state() + .as_ref() + .map(|s| (s.server_random, s.hmac.to_owned())); + + // whatever the fake_request is successful or not, we should return an error when strict mode is enabled + if (!authorized || maybe_server_random_and_hamc.is_none()) && opts.strict { + tracing::warn!("shadow-tls V3 strict enabled: traffic hijacked or TLS1.3 is not supported, perform fake request"); + + tls.get_mut().0.fake_request = true; + fake_request(tls).await?; + + return Err(io::Error::new( + io::ErrorKind::Other, + "V3 strict enabled: traffic hijacked or TLS1.3 is not supported, fake request" + .to_string(), + )); + } + + let (server_random, hmac_nop) = match maybe_server_random_and_hamc { + Some(inner) => inner, + None => { + return Err(io::Error::new( + io::ErrorKind::Other, + "server random and hmac not extracted from handshake, fail to connect" + .to_string(), + )); + } + }; + + let hmac_client = Hmac::new(&opts.password, (&server_random, "C".as_bytes())); + let hmac_server = Hmac::new(&opts.password, (&server_random, "S".as_bytes())); + + let verified_stream = VerifiedStream::new( + tls.into_inner().0.raw, + hmac_client, + hmac_server, + Some(hmac_nop), + ); + + Ok(Box::new(verified_stream)) + } +} + +/// Take a slice of tls message[5..] and returns signed session id. +/// +/// Only used by V3 protocol. +fn generate_session_id(hmac: &Hmac, buf: &[u8]) -> [u8; TLS_SESSION_ID_SIZE] { + /// Note: SESSION_ID_START does not include 5 TLS_HEADER_SIZE. + const SESSION_ID_START: usize = 1 + 3 + 2 + TLS_RANDOM_SIZE + 1; + + if buf.len() < SESSION_ID_START + TLS_SESSION_ID_SIZE { + tracing::warn!("unexpected client hello length"); + return [0; TLS_SESSION_ID_SIZE]; + } + + let mut session_id = [0; TLS_SESSION_ID_SIZE]; + rand::thread_rng().fill(&mut session_id[..TLS_SESSION_ID_SIZE - HMAC_SIZE]); + let mut hmac = hmac.to_owned(); + hmac.update(&buf[0..SESSION_ID_START]); + hmac.update(&session_id); + hmac.update(&buf[SESSION_ID_START + TLS_SESSION_ID_SIZE..]); + let hmac_val = hmac.finalize(); + unsafe { + copy_nonoverlapping( + hmac_val.as_ptr(), + session_id.as_mut_ptr().add(TLS_SESSION_ID_SIZE - HMAC_SIZE), + HMAC_SIZE, + ) + } + session_id +} + +/// Doing fake request. +/// +/// Only used by V3 protocol. +async fn fake_request( + mut stream: TlsStream, +) -> std::io::Result<()> { + const HEADER: &[u8; 207] = b"GET / HTTP/1.1\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36\nAccept: gzip, deflate, br\nConnection: Close\nCookie: sessionid="; + const FAKE_REQUEST_LENGTH_RANGE: (usize, usize) = (16, 64); + let cnt = + rand::thread_rng().gen_range(FAKE_REQUEST_LENGTH_RANGE.0..FAKE_REQUEST_LENGTH_RANGE.1); + let mut buffer = Vec::with_capacity(cnt + HEADER.len() + 1); + + buffer.extend_from_slice(HEADER); + rand::distributions::Alphanumeric + .sample_iter(rand::thread_rng()) + .take(cnt) + .for_each(|c| buffer.push(c)); + buffer.push(b'\n'); + + stream.write_all(&buffer).await?; + let _ = stream.shutdown().await; + + // read until eof + let mut buf = Vec::with_capacity(1024); + let r = stream.read_to_end(&mut buf).await; + r.map(|_| ()) +} diff --git a/clash_lib/src/proxy/shadowsocks/shadow_tls/mod.rs b/clash_lib/src/proxy/shadowsocks/shadow_tls/mod.rs new file mode 100644 index 000000000..d5285a144 --- /dev/null +++ b/clash_lib/src/proxy/shadowsocks/shadow_tls/mod.rs @@ -0,0 +1,6 @@ +mod connector; +mod stream; +mod utils; + +pub use connector::Connector; +use utils::prelude; diff --git a/clash_lib/src/proxy/shadowsocks/shadow_tls/stream.rs b/clash_lib/src/proxy/shadowsocks/shadow_tls/stream.rs new file mode 100644 index 000000000..f01cab935 --- /dev/null +++ b/clash_lib/src/proxy/shadowsocks/shadow_tls/stream.rs @@ -0,0 +1,502 @@ +use std::{ + mem::MaybeUninit, + pin::Pin, + ptr::{copy, copy_nonoverlapping}, + task::{ready, Poll}, +}; + +use byteorder::{BigEndian, WriteBytesExt}; +use bytes::{BufMut, BytesMut}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; + +use super::utils::{prelude::*, *}; + +#[derive(Default, Debug)] +pub enum ReadState { + #[default] + WaitingHeader, + WaitingData(usize, [u8; TLS_HEADER_SIZE]), + FlushingData, +} + +#[derive(Default, Debug)] +pub enum WriteState { + #[default] + BuildingData, + FlushingData(usize, usize, usize), +} + +pub trait AsyncReadUnpin: AsyncRead + Unpin {} + +impl AsyncReadUnpin for T {} + +pub trait ReadExtBase { + fn prepare(&mut self) -> (&mut dyn AsyncReadUnpin, &mut BytesMut, &mut usize); +} + +pub trait ReadExt { + fn poll_read_exact( + &mut self, + cx: &mut std::task::Context, + size: usize, + ) -> Poll>; +} + +impl ReadExt for T { + fn poll_read_exact( + &mut self, + cx: &mut std::task::Context, + size: usize, + ) -> Poll> { + let (raw, read_buf, read_pos) = self.prepare(); + read_buf.reserve(size); + // # safety: read_buf has reserved `size` + unsafe { read_buf.set_len(size) } + loop { + if *read_pos < size { + // # safety: read_pos]) + }; + let mut buf = ReadBuf::uninit(dst); + let ptr = buf.filled().as_ptr(); + ready!(Pin::new(&mut *raw).poll_read(cx, &mut buf))?; + assert_eq!(ptr, buf.filled().as_ptr()); + if buf.filled().is_empty() { + return Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "unexpected eof", + ))); + } + *read_pos += buf.filled().len(); + } else { + assert!(*read_pos == size); + *read_pos = 0; + return Poll::Ready(Ok(())); + } + } + } +} + +#[derive(Clone, Debug)] +pub struct Certs { + pub(crate) server_random: [u8; TLS_RANDOM_SIZE], + pub(crate) hmac: Hmac, + pub(crate) key: Vec, +} + +pub struct ProxyTlsStream { + pub raw: S, + password: String, + + pub read_state: ReadState, + pub read_pos: usize, + pub read_buf: BytesMut, + + // need to get from the handshake packets + pub certs: Option, + read_authorized: bool, + tls13: bool, + + // if true, the stream will only act as a wrapper, and won't modify the inner byte stream + pub fake_request: bool, +} + +impl ProxyTlsStream { + pub fn new(raw: S, password: &str) -> Self { + Self { + raw, + password: password.to_string(), + + read_state: Default::default(), + read_pos: Default::default(), + read_buf: Default::default(), + + certs: None, + read_authorized: false, + tls13: false, + + fake_request: false, + } + } + + #[inline(always)] + pub fn authorized(&self) -> bool { + self.read_authorized + } + + #[inline(always)] + pub fn state(&self) -> &Option { + &self.certs + } + + #[allow(unused)] + pub fn tls13(&self) -> bool { + self.tls13 + } +} + +impl ReadExtBase for ProxyTlsStream { + fn prepare(&mut self) -> (&mut dyn AsyncReadUnpin, &mut BytesMut, &mut usize) { + (&mut self.raw, &mut self.read_buf, &mut self.read_pos) + } +} + +impl AsyncRead for ProxyTlsStream { + fn poll_read( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + let this = self.get_mut(); + + if this.fake_request { + return Pin::new(&mut this.raw).poll_read(cx, buf); + } + + // let r = Pin::new(&mut this.raw).poll_read(cx, buf); + + loop { + match this.read_state { + ReadState::WaitingHeader => { + ready!(this.poll_read_exact(cx, TLS_HEADER_SIZE))?; + let buf = this.read_buf.split().freeze().to_vec(); + + let mut size: [u8; 2] = Default::default(); + size.copy_from_slice(&buf[3..5]); + let data_size = u16::from_be_bytes(size) as usize; + + let mut header = [0u8; TLS_HEADER_SIZE]; + header.copy_from_slice(&buf[..TLS_HEADER_SIZE]); + + this.read_state = ReadState::WaitingData(data_size, header); + } + ReadState::WaitingData(size, mut header) => { + ready!(this.poll_read_exact(cx, size))?; + // now the data is ready with the required size + let mut body = this.read_buf.split().freeze().to_vec(); + + match header[0] { + HANDSHAKE => { + if body.len() > SERVER_RANDOM_OFFSET + TLS_RANDOM_SIZE + && body[0] == SERVER_HELLO + { + let mut server_random = [0; TLS_RANDOM_SIZE]; + unsafe { + copy_nonoverlapping( + body.as_ptr().add(SERVER_RANDOM_OFFSET), + server_random.as_mut_ptr(), + TLS_RANDOM_SIZE, + ) + } + let hmac = Hmac::new(&this.password, (&server_random, &[])); + let key = kdf(&this.password, &server_random); + this.certs = Some(Certs { + server_random, + hmac, + key, + }); + this.tls13 = support_tls13(&body); + } + } + APPLICATION_DATA => { + this.read_authorized = false; + if body.len() > HMAC_SIZE { + if let Some(Certs { hmac, key, .. }) = this.certs.as_mut() { + hmac.update(&body[HMAC_SIZE..]); + if hmac.finalize() == body[0..HMAC_SIZE] { + // 1. xor to the the original data + xor_slice(&mut body[HMAC_SIZE..], key); + // 2. remove the hmac + unsafe { + copy( + body.as_ptr().add(HMAC_SIZE), + body.as_mut_ptr(), + body.len() - HMAC_SIZE, + ) + }; + // 3. rewrite the data size in the header + (&mut header[3..5]) + .write_u16::(size as u16 - HMAC_SIZE as u16) + .unwrap(); + this.read_authorized = true; + // 4. rewrite the body length to be put into the read buf + unsafe { + body.set_len(body.len() - HMAC_SIZE); + } + // 4. put the header and body into our own read buf + } else { + tracing::debug!("shadowtls verification failed"); + } + } + } + } + _ => {} + } + + this.read_buf.put(&header[..]); + this.read_buf.put(&body[..]); + this.read_state = ReadState::FlushingData; + } + ReadState::FlushingData => { + // now the data is ready in the read_buf + let size = this.read_buf.len(); + let to_read = std::cmp::min(buf.remaining(), size); + let payload = this.read_buf.split_to(to_read); + buf.put_slice(&payload); + if to_read < size { + // there're unread data, continues in next poll + this.read_state = ReadState::FlushingData; + } else { + // all data consumed, ready to read next chunk + this.read_state = ReadState::WaitingHeader; + } + + return Poll::Ready(Ok(())); + } + } + } + } +} + +impl AsyncWrite for ProxyTlsStream { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + let this = self.get_mut(); + Pin::new(&mut this.raw).poll_write(cx, buf) + } + + fn poll_flush( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let this = self.get_mut(); + Pin::new(&mut this.raw).poll_flush(cx) + } + + fn poll_shutdown( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let this = self.get_mut(); + Pin::new(&mut this.raw).poll_shutdown(cx) + } +} + +#[derive(Debug)] +pub struct VerifiedStream { + pub raw: S, + client_cert: Hmac, + server_cert: Hmac, + nop_cert: Option, + + pub read_buf: BytesMut, + pub read_pos: usize, + pub read_state: ReadState, + + pub write_buf: BytesMut, + pub write_state: WriteState, +} + +impl VerifiedStream { + pub(crate) fn new( + raw: S, + client_cert: Hmac, + server_cert: Hmac, + nop_cert: Option, + ) -> Self { + Self { + raw, + client_cert, + server_cert, + nop_cert, + read_buf: Default::default(), + read_pos: Default::default(), + read_state: Default::default(), + write_buf: Default::default(), + write_state: Default::default(), + } + } +} + +impl ReadExtBase for VerifiedStream { + fn prepare(&mut self) -> (&mut dyn AsyncReadUnpin, &mut BytesMut, &mut usize) { + (&mut self.raw, &mut self.read_buf, &mut self.read_pos) + } +} + +impl AsyncRead for VerifiedStream { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + let this = self.get_mut(); + + loop { + match this.read_state { + ReadState::WaitingHeader => { + ready!(this.poll_read_exact(cx, TLS_HEADER_SIZE))?; + let buf = this.read_buf.split().freeze().to_vec(); + + let mut size: [u8; 2] = Default::default(); + size.copy_from_slice(&buf[3..5]); + let data_size = u16::from_be_bytes(size) as usize; + + let mut header = [0u8; TLS_HEADER_SIZE]; + header.copy_from_slice(&buf[..TLS_HEADER_SIZE]); + + this.read_state = ReadState::WaitingData(data_size, header); + } + ReadState::WaitingData(size, header) => { + ready!(this.poll_read_exact(cx, size))?; + // now the data is ready with the required size + let mut data = this.read_buf.split().freeze().to_vec(); + + if header[0] == APPLICATION_DATA { + // ignore the rest useless data + if let Some(ref mut nop_cert) = this.nop_cert { + if verify_appdata(&header, &mut data, nop_cert, false) { + this.read_state = ReadState::WaitingHeader; + continue; + } else { + this.nop_cert.take(); + } + } + + // the application data from the data server + // we need to verfiy and removec the hmac(4 bytes) + if verify_appdata(&header, &mut data, &mut this.server_cert, true) { + // modify data, reuse the read buf + this.read_buf.clear(); + this.read_buf.put(&data[HMAC_SIZE..]); + this.read_state = ReadState::FlushingData; + } else { + tracing::error!("shadowtls appdata verify failed"); + return Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "appdata verify failed", + ))); + } + } + } + ReadState::FlushingData => { + // now the data is ready in the read_buf + let size = this.read_buf.len(); + let to_read = std::cmp::min(buf.remaining(), size); + let payload = this.read_buf.split_to(to_read); + buf.put_slice(&payload); + if to_read < size { + // there're unread data, continues in next poll + this.read_state = ReadState::FlushingData; + } else { + // all data consumed, ready to read next chunk + this.read_state = ReadState::WaitingHeader; + } + + return Poll::Ready(Ok(())); + } + } + } + } +} + +impl AsyncWrite for VerifiedStream { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + let this = self.get_mut(); + loop { + match this.write_state { + WriteState::BuildingData => { + // header(5 bytes) + zero hmac(4 bytes) + const DEFAULT_HEADER_HMAC: [u8; TLS_HMAC_HEADER_SIZE] = + [APPLICATION_DATA, TLS_MAJOR, TLS_MINOR.0, 0, 0, 0, 0, 0, 0]; + + let mut header_body = Vec::with_capacity(COPY_BUF_SIZE); + header_body.extend_from_slice(&DEFAULT_HEADER_HMAC); + + (&mut header_body[3..5]) + .write_u16::((buf.len() + HMAC_SIZE) as u16) + .unwrap(); + header_body.extend_from_slice(buf); + + this.client_cert.update(buf); + let hmac_val = this.client_cert.finalize(); + this.client_cert.update(&hmac_val); + unsafe { + copy_nonoverlapping( + hmac_val.as_ptr(), + header_body.as_mut_ptr().add(TLS_HEADER_SIZE), + HMAC_SIZE, + ) + }; + + this.write_buf.put_slice(&header_body); + this.write_state = WriteState::FlushingData(buf.len(), header_body.len(), 0); + } + WriteState::FlushingData(consume, total, written) => { + let nw = ready!(tokio_util::io::poll_write_buf( + Pin::new(&mut this.raw), + cx, + &mut this.write_buf + ))?; + if nw == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::WriteZero, + "failed to write whole data", + )) + .into(); + } + + if written + nw >= total { + debug_assert_eq!(written + nw, total); + // data chunk written, go to next chunk + this.write_state = WriteState::BuildingData; + return Poll::Ready(Ok(consume)); + } + + this.write_state = WriteState::FlushingData(consume, total, written + nw); + } + } + } + } + + fn poll_flush( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let this = self.get_mut(); + Pin::new(&mut this.raw).poll_flush(cx) + } + + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let this = self.get_mut(); + Pin::new(&mut this.raw).poll_shutdown(cx) + } +} + +fn verify_appdata( + header: &[u8; TLS_HEADER_SIZE], + data: &mut [u8], + hmac: &mut Hmac, + sep: bool, +) -> bool { + if header[1] != TLS_MAJOR || header[2] != TLS_MINOR.0 { + return false; + } + hmac.update(&data[HMAC_SIZE..]); + let hmac_real = hmac.finalize(); + if sep { + hmac.update(&hmac_real); + } + data[0..HMAC_SIZE] == hmac_real +} diff --git a/clash_lib/src/proxy/shadowsocks/shadow_tls/utils.rs b/clash_lib/src/proxy/shadowsocks/shadow_tls/utils.rs new file mode 100644 index 000000000..70e930d55 --- /dev/null +++ b/clash_lib/src/proxy/shadowsocks/shadow_tls/utils.rs @@ -0,0 +1,167 @@ +use std::{io::Read, ptr::copy_nonoverlapping}; + +use byteorder::{BigEndian, ReadBytesExt}; +use hmac::Mac; + +use prelude::*; +use sha2::{Digest, Sha256}; + +pub(crate) mod prelude { + pub(crate) const TLS_MAJOR: u8 = 0x03; + pub(crate) const TLS_MINOR: (u8, u8) = (0x03, 0x01); + pub(crate) const SUPPORTED_VERSIONS_TYPE: u16 = 43; + pub(crate) const TLS_RANDOM_SIZE: usize = 32; + pub(crate) const TLS_HEADER_SIZE: usize = 5; + pub(crate) const TLS_SESSION_ID_SIZE: usize = 32; + pub(crate) const TLS_13: u16 = 0x0304; + + pub(crate) const SERVER_HELLO: u8 = 0x02; + pub(crate) const HANDSHAKE: u8 = 0x16; + pub(crate) const APPLICATION_DATA: u8 = 0x17; + + pub(crate) const SERVER_RANDOM_OFFSET: usize = 1 + 3 + 2; + pub(crate) const SESSION_ID_LEN_IDX: usize = TLS_HEADER_SIZE + 1 + 3 + 2 + TLS_RANDOM_SIZE; + pub(crate) const TLS_HMAC_HEADER_SIZE: usize = TLS_HEADER_SIZE + HMAC_SIZE; + + pub(crate) const COPY_BUF_SIZE: usize = 4096; + pub(crate) const HMAC_SIZE: usize = 4; +} + +#[derive(Clone)] +pub(crate) struct Hmac(hmac::Hmac); + +impl std::fmt::Debug for Hmac { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Hmac").finish() + } +} + +impl Hmac { + #[inline] + pub(crate) fn new(password: &str, init_data: (&[u8], &[u8])) -> Self { + // Note: infact new_from_slice never returns Err. + let mut hmac: hmac::Hmac = + hmac::Hmac::new_from_slice(password.as_bytes()).expect("unable to build hmac instance"); + hmac.update(init_data.0); + hmac.update(init_data.1); + Self(hmac) + } + + #[inline] + // #[tracing::instrument(skip(data), level = "debug")] + pub(crate) fn update(&mut self, data: &[u8]) { + self.0.update(data); + } + + #[inline] + pub(crate) fn finalize(&self) -> [u8; HMAC_SIZE] { + let hmac = self.0.clone(); + let hash = hmac.finalize().into_bytes(); + let mut res = [0; HMAC_SIZE]; + unsafe { copy_nonoverlapping(hash.as_slice().as_ptr(), res.as_mut_ptr(), HMAC_SIZE) }; + res + } + + #[inline] + pub(crate) fn to_owned(&self) -> Self { + Self(self.0.clone()) + } +} + +#[inline] +pub(crate) fn kdf(password: &str, server_random: &[u8]) -> Vec { + let mut hasher = Sha256::new(); + hasher.update(password.as_bytes()); + hasher.update(server_random); + let hash = hasher.finalize(); + hash.to_vec() +} + +#[inline] +pub(crate) fn xor_slice(data: &mut [u8], key: &[u8]) { + data.iter_mut() + .zip(key.iter().cycle()) + .for_each(|(d, k)| *d ^= k); +} + +#[allow(unused)] +pub(crate) trait CursorExt { + fn read_by_u16(&mut self) -> std::io::Result>; + fn skip(&mut self, n: usize) -> std::io::Result<()>; + fn skip_by_u8(&mut self) -> std::io::Result; + fn skip_by_u16(&mut self) -> std::io::Result; +} + +impl CursorExt for std::io::Cursor +where + std::io::Cursor: std::io::Read, +{ + #[inline] + fn read_by_u16(&mut self) -> std::io::Result> { + let len = self.read_u16::()?; + let mut buf = vec![0; len as usize]; + self.read_exact(&mut buf)?; + Ok(buf) + } + + #[inline] + fn skip(&mut self, n: usize) -> std::io::Result<()> { + for _ in 0..n { + self.read_u8()?; + } + Ok(()) + } + + #[inline] + fn skip_by_u8(&mut self) -> std::io::Result { + let len = self.read_u8()?; + self.skip(len as usize)?; + Ok(len) + } + + #[inline] + fn skip_by_u16(&mut self) -> std::io::Result { + let len = self.read_u16::()?; + self.skip(len as usize)?; + Ok(len) + } +} + +/// Parse ServerHello and return if tls1.3 is supported. +pub(crate) fn support_tls13(frame: &[u8]) -> bool { + if frame.len() < SESSION_ID_LEN_IDX { + return false; + } + let mut cursor = std::io::Cursor::new(&frame[SESSION_ID_LEN_IDX..]); + macro_rules! read_ok { + ($res: expr) => { + match $res { + Ok(r) => r, + Err(_) => { + return false; + } + } + }; + } + + // skip session id + read_ok!(cursor.skip_by_u8()); + // skip cipher suites + read_ok!(cursor.skip(3)); + // skip ext length + let cnt = read_ok!(cursor.read_u16::()); + + for _ in 0..cnt { + let ext_type = read_ok!(cursor.read_u16::()); + if ext_type != SUPPORTED_VERSIONS_TYPE { + read_ok!(cursor.skip_by_u16()); + continue; + } + let ext_len = read_ok!(cursor.read_u16::()); + let ext_val = read_ok!(cursor.read_u16::()); + let use_tls13 = ext_len == 2 && ext_val == TLS_13; + tracing::debug!("found supported_versions extension, tls1.3: {use_tls13}"); + return use_tls13; + } + false +} diff --git a/clash_lib/src/proxy/trojan/mod.rs b/clash_lib/src/proxy/trojan/mod.rs index 7b4bfcc80..6a00e1727 100644 --- a/clash_lib/src/proxy/trojan/mod.rs +++ b/clash_lib/src/proxy/trojan/mod.rs @@ -225,8 +225,6 @@ mod tests { use std::collections::HashMap; - use tracing_test::traced_test; - use crate::proxy::utils::test_utils::{ config_helper::test_config_base_dir, consts::*, @@ -254,9 +252,15 @@ mod tests { } #[tokio::test] - #[traced_test] #[serial_test::serial] async fn test_trojan_ws() -> anyhow::Result<()> { + let _ = tracing_subscriber::fmt() + // any additional configuration of the subscriber you might want here.. + .try_init(); + + let span = tracing::info_span!("test_trojan_ws"); + let _enter = span.enter(); + let opts = Opts { name: "test-trojan-ws".to_owned(), common_opts: Default::default(), diff --git a/clash_lib/src/proxy/utils/socket_helpers.rs b/clash_lib/src/proxy/utils/socket_helpers.rs index fe9ef4b82..1f163db5c 100644 --- a/clash_lib/src/proxy/utils/socket_helpers.rs +++ b/clash_lib/src/proxy/utils/socket_helpers.rs @@ -82,6 +82,7 @@ pub async fn new_tcp_stream<'a>( io::ErrorKind::Other, format!("can't resolve dns: {}", address), ))?; + tracing::debug!("resolved addr of {:?}:{:?}", address, dial_addr); let socket = match (dial_addr, resolver.ipv6()) { (IpAddr::V4(_), _) => { diff --git a/clash_lib/src/proxy/utils/test_utils/config_helper.rs b/clash_lib/src/proxy/utils/test_utils/config_helper.rs index e6c342713..05b713114 100644 --- a/clash_lib/src/proxy/utils/test_utils/config_helper.rs +++ b/clash_lib/src/proxy/utils/test_utils/config_helper.rs @@ -44,11 +44,7 @@ pub async fn load_config() -> anyhow::Result<( debug!("initializing cache store"); let cache_store = profile::ThreadSafeCacheFile::new( - PathBuf::from(root) - .join("cache.db") - .as_path() - .to_str() - .unwrap(), + root.join("cache.db").as_path().to_str().unwrap(), config.profile.store_selected, ); diff --git a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs index a95e413c8..6a0a4bb3a 100644 --- a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs +++ b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs @@ -17,8 +17,8 @@ pub struct DockerTestRunner { } impl DockerTestRunner { - pub async fn try_new<'a>( - image_conf: Option>, + pub async fn try_new( + image_conf: Option>, container_conf: Config, ) -> Result { let docker: Docker = Docker::connect_with_socket_defaults()?; @@ -41,8 +41,7 @@ impl DockerTestRunner { // you can run the cleanup manually pub async fn cleanup(self) -> anyhow::Result<()> { - let s = self - .instance + self.instance .remove_container( &self.id, Some(RemoveContainerOptions { @@ -51,7 +50,7 @@ impl DockerTestRunner { }), ) .await?; - Ok(s) + Ok(()) } } @@ -60,9 +59,8 @@ pub struct MultiDockerTestRunner { runners: Vec, } -// TODO: use this test runner to support test of ss's plugins -#[allow(unused)] impl MultiDockerTestRunner { + #[allow(unused)] pub fn new(runners: Vec) -> Self { Self { runners } } @@ -215,7 +213,7 @@ impl DockerTestRunnerBuilder { pub fn mounts(mut self, pairs: &[(&str, &str)]) -> Self { self.host_config.mounts = Some( pairs - .into_iter() + .iter() .map(|(src, dst)| Mount { target: Some(dst.to_string()), source: Some(src.to_string()), diff --git a/clash_lib/src/proxy/utils/test_utils/mod.rs b/clash_lib/src/proxy/utils/test_utils/mod.rs index 230f60a25..5dc103ddb 100644 --- a/clash_lib/src/proxy/utils/test_utils/mod.rs +++ b/clash_lib/src/proxy/utils/test_utils/mod.rs @@ -200,13 +200,13 @@ pub async fn run_default_test_suites_and_cleanup( }, ) .await; - if rv.is_err() { - return Err(rv.unwrap_err()); + if let Err(e) = rv { + return Err(e); } else { tracing::info!("latency test success: {}", rv.unwrap().as_millis()); } - return Ok(()); + Ok(()) }) .await } diff --git a/clash_lib/src/proxy/vmess/mod.rs b/clash_lib/src/proxy/vmess/mod.rs index f8977b5ae..178ddc1c7 100644 --- a/clash_lib/src/proxy/vmess/mod.rs +++ b/clash_lib/src/proxy/vmess/mod.rs @@ -255,9 +255,6 @@ impl OutboundHandler for Handler { #[cfg(all(test, not(ci)))] mod tests { - - use tracing_test::traced_test; - use crate::proxy::utils::test_utils::{ config_helper::test_config_base_dir, consts::*, @@ -279,9 +276,15 @@ mod tests { } #[tokio::test] - #[traced_test] #[serial_test::serial] async fn test_vmess_ws() -> anyhow::Result<()> { + let _ = tracing_subscriber::fmt() + // any additional configuration of the subscriber you might want here.. + .try_init(); + + let span = tracing::info_span!("test_vmess_ws"); + let _enter = span.enter(); + let opts = HandlerOptions { name: "test-vmess-ws".into(), common_opts: Default::default(), From cdf9d85ff0475f23fa084076c303cc716d9ecb11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 01:36:08 +0000 Subject: [PATCH 09/16] Bump prost from 0.12.3 to 0.12.4 (#359) Bumps [prost](https://github.com/tokio-rs/prost) from 0.12.3 to 0.12.4. - [Release notes](https://github.com/tokio-rs/prost/releases) - [Commits](https://github.com/tokio-rs/prost/compare/v0.12.3...v0.12.4) --- updated-dependencies: - dependency-name: prost dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bdd552990..6017f5365 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4180,9 +4180,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", "prost-derive", @@ -4190,12 +4190,12 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.55", From a53f14aa675bff4d64a40756c0962f77f4080e5c Mon Sep 17 00:00:00 2001 From: V Date: Tue, 9 Apr 2024 19:31:54 +0800 Subject: [PATCH 10/16] Feat/add docker test for wg (#361) * feat: add docker test for wg --- .../data/config/wg_config/.donoteditthisfile | 7 ++ .../data/config/wg_config/coredns/Corefile | 5 ++ .../data/config/wg_config/peer1/peer1.conf | 11 +++ .../data/config/wg_config/peer1/peer1.png | Bin 0 -> 1135 bytes .../config/wg_config/peer1/presharedkey-peer1 | 1 + .../config/wg_config/peer1/privatekey-peer1 | 1 + .../config/wg_config/peer1/publickey-peer1 | 1 + .../config/wg_config/server/privatekey-server | 1 + .../config/wg_config/server/publickey-server | 1 + .../data/config/wg_config/templates/peer.conf | 11 +++ .../config/wg_config/templates/server.conf | 6 ++ .../data/config/wg_config/wg_confs/wg0.conf | 13 ++++ .../src/proxy/utils/test_utils/consts.rs | 1 + .../proxy/utils/test_utils/docker_runner.rs | 27 ++++++- clash_lib/src/proxy/utils/test_utils/mod.rs | 70 ++++++++++++------ clash_lib/src/proxy/wg/mod.rs | 67 +++++++++++++++++ 16 files changed, 197 insertions(+), 26 deletions(-) create mode 100644 clash/tests/data/config/wg_config/.donoteditthisfile create mode 100644 clash/tests/data/config/wg_config/coredns/Corefile create mode 100644 clash/tests/data/config/wg_config/peer1/peer1.conf create mode 100644 clash/tests/data/config/wg_config/peer1/peer1.png create mode 100644 clash/tests/data/config/wg_config/peer1/presharedkey-peer1 create mode 100644 clash/tests/data/config/wg_config/peer1/privatekey-peer1 create mode 100644 clash/tests/data/config/wg_config/peer1/publickey-peer1 create mode 100644 clash/tests/data/config/wg_config/server/privatekey-server create mode 100644 clash/tests/data/config/wg_config/server/publickey-server create mode 100644 clash/tests/data/config/wg_config/templates/peer.conf create mode 100644 clash/tests/data/config/wg_config/templates/server.conf create mode 100644 clash/tests/data/config/wg_config/wg_confs/wg0.conf diff --git a/clash/tests/data/config/wg_config/.donoteditthisfile b/clash/tests/data/config/wg_config/.donoteditthisfile new file mode 100644 index 000000000..3cfff22c3 --- /dev/null +++ b/clash/tests/data/config/wg_config/.donoteditthisfile @@ -0,0 +1,7 @@ +ORIG_SERVERURL="36.161.169.198" +ORIG_SERVERPORT="51820" +ORIG_PEERDNS="10.13.13.1" +ORIG_PEERS="1" +ORIG_INTERFACE="10.13.13" +ORIG_ALLOWEDIPS="0.0.0.0/0" +ORIG_PERSISTENTKEEPALIVE_PEERS="" diff --git a/clash/tests/data/config/wg_config/coredns/Corefile b/clash/tests/data/config/wg_config/coredns/Corefile new file mode 100644 index 000000000..12da81870 --- /dev/null +++ b/clash/tests/data/config/wg_config/coredns/Corefile @@ -0,0 +1,5 @@ +. { + loop + health + forward . /etc/resolv.conf +} diff --git a/clash/tests/data/config/wg_config/peer1/peer1.conf b/clash/tests/data/config/wg_config/peer1/peer1.conf new file mode 100644 index 000000000..db0e5832a --- /dev/null +++ b/clash/tests/data/config/wg_config/peer1/peer1.conf @@ -0,0 +1,11 @@ +[Interface] +Address = 10.13.13.2 +PrivateKey = KIlDUePHyYwzjgn18przw/ZwPioJhh2aEyhxb/dtCXI= +ListenPort = 51820 +DNS = 10.13.13.1 + +[Peer] +PublicKey = INBZyvB715sA5zatkiX8Jn3Dh5tZZboZ09x4pkr66ig= +PresharedKey = +JmZErvtDT4ZfQequxWhZSydBV+ItqUcPMHUWY1j2yc= +Endpoint = 127.0.0.1:10002 +AllowedIPs = 0.0.0.0/0 diff --git a/clash/tests/data/config/wg_config/peer1/peer1.png b/clash/tests/data/config/wg_config/peer1/peer1.png new file mode 100644 index 0000000000000000000000000000000000000000..da119881f8d4cb0b8bcf91dab7eb319fcebb1560 GIT binary patch literal 1135 zcmV-#1d#iQP))r)@$b2b{7P+SOt|w4wyF6dB zNLqAiZ`yX!cHtZf%S)OuOJ}ch7fz$BqsYC8$lm8>l>HPU8YK=jjyV$Qdu_(Be+TO4 z$nrI{|NHw+<{WVc_#zjbFYkwUp;zKz)zzOCPv0R;&S6D{TNAe@Qf{t@D--u?pN|56yesowFEt?iY zHOYNi=rzyJaO*+jOU*0r4Q5f?()x}BKhjBVM=L}IV?bcb#t{B)zAm(ygjyTPD!tYE zPMmgX>@|jXx$U5xA zyp1d|b4sbTVc^$eIMB=L2oERwEHC7a&oER(H)79aKYgLnWGU+t=`(e?5pfubEktSq z9&v8_-`?v(#o{20c}((bslp7&Jm5!I&}az~YcZu65o)D(pFlz-Qrc$bmblEiA(H%v z<5&u8f+7g)(U%(6;77;$Y)$rc?D%V#Z{;&B`_QqQH~e#47mK^Atw^6~*@p@$qGjVh z)?tq&PTqT^8(F5XqiMdf02ca1^Il=xsKY1|IlBe{{ZIL>kMkRG}-_F002ovPDHLkV1mhw BE))O& literal 0 HcmV?d00001 diff --git a/clash/tests/data/config/wg_config/peer1/presharedkey-peer1 b/clash/tests/data/config/wg_config/peer1/presharedkey-peer1 new file mode 100644 index 000000000..9ad12fd4f --- /dev/null +++ b/clash/tests/data/config/wg_config/peer1/presharedkey-peer1 @@ -0,0 +1 @@ ++JmZErvtDT4ZfQequxWhZSydBV+ItqUcPMHUWY1j2yc= diff --git a/clash/tests/data/config/wg_config/peer1/privatekey-peer1 b/clash/tests/data/config/wg_config/peer1/privatekey-peer1 new file mode 100644 index 000000000..0809131e2 --- /dev/null +++ b/clash/tests/data/config/wg_config/peer1/privatekey-peer1 @@ -0,0 +1 @@ +KIlDUePHyYwzjgn18przw/ZwPioJhh2aEyhxb/dtCXI= diff --git a/clash/tests/data/config/wg_config/peer1/publickey-peer1 b/clash/tests/data/config/wg_config/peer1/publickey-peer1 new file mode 100644 index 000000000..5dc898594 --- /dev/null +++ b/clash/tests/data/config/wg_config/peer1/publickey-peer1 @@ -0,0 +1 @@ +H7NHC22d44AhrJf7BSzbNJrW1wiTDCRYNfP0rQicM3g= diff --git a/clash/tests/data/config/wg_config/server/privatekey-server b/clash/tests/data/config/wg_config/server/privatekey-server new file mode 100644 index 000000000..cf2a8a0f2 --- /dev/null +++ b/clash/tests/data/config/wg_config/server/privatekey-server @@ -0,0 +1 @@ +CA7cMGAh7BF/kD000ZRN+ZXDe1SGd1Z3kqNjQxnCAmQ= diff --git a/clash/tests/data/config/wg_config/server/publickey-server b/clash/tests/data/config/wg_config/server/publickey-server new file mode 100644 index 000000000..a2936ff96 --- /dev/null +++ b/clash/tests/data/config/wg_config/server/publickey-server @@ -0,0 +1 @@ +INBZyvB715sA5zatkiX8Jn3Dh5tZZboZ09x4pkr66ig= diff --git a/clash/tests/data/config/wg_config/templates/peer.conf b/clash/tests/data/config/wg_config/templates/peer.conf new file mode 100644 index 000000000..196540e87 --- /dev/null +++ b/clash/tests/data/config/wg_config/templates/peer.conf @@ -0,0 +1,11 @@ +[Interface] +Address = ${CLIENT_IP} +PrivateKey = $(cat /config/${PEER_ID}/privatekey-${PEER_ID}) +ListenPort = 10002 +DNS = ${PEERDNS} + +[Peer] +PublicKey = $(cat /config/server/publickey-server) +PresharedKey = $(cat /config/${PEER_ID}/presharedkey-${PEER_ID}) +Endpoint = ${SERVERURL}:${SERVERPORT} +AllowedIPs = ${ALLOWEDIPS} diff --git a/clash/tests/data/config/wg_config/templates/server.conf b/clash/tests/data/config/wg_config/templates/server.conf new file mode 100644 index 000000000..8d1a3fda2 --- /dev/null +++ b/clash/tests/data/config/wg_config/templates/server.conf @@ -0,0 +1,6 @@ +[Interface] +Address = ${INTERFACE}.1 +ListenPort = 10002 +PrivateKey = $(cat /config/server/privatekey-server) +PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE +PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE diff --git a/clash/tests/data/config/wg_config/wg_confs/wg0.conf b/clash/tests/data/config/wg_config/wg_confs/wg0.conf new file mode 100644 index 000000000..4ab6eb1e3 --- /dev/null +++ b/clash/tests/data/config/wg_config/wg_confs/wg0.conf @@ -0,0 +1,13 @@ +[Interface] +Address = 10.13.13.1 +ListenPort = 10002 +PrivateKey = CA7cMGAh7BF/kD000ZRN+ZXDe1SGd1Z3kqNjQxnCAmQ= +PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE +PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE + +[Peer] +# peer1 +PublicKey = H7NHC22d44AhrJf7BSzbNJrW1wiTDCRYNfP0rQicM3g= +PresharedKey = +JmZErvtDT4ZfQequxWhZSydBV+ItqUcPMHUWY1j2yc= +AllowedIPs = 10.13.13.2/32 + diff --git a/clash_lib/src/proxy/utils/test_utils/consts.rs b/clash_lib/src/proxy/utils/test_utils/consts.rs index 58ef48123..8d81f660a 100644 --- a/clash_lib/src/proxy/utils/test_utils/consts.rs +++ b/clash_lib/src/proxy/utils/test_utils/consts.rs @@ -2,6 +2,7 @@ pub const LOCAL_ADDR: &str = "127.0.0.1"; pub const EXAMPLE_REQ: &[u8] = b"GET / HTTP/1.1\r\nHost: example.com\r\nAccept: */*\r\n\r\n"; pub const EXAMLE_RESP_200: &[u8] = b"HTTP/1.1 200"; +pub const IMAGE_WG: &str = "lscr.io/linuxserver/wireguard:latest"; pub const IMAGE_SS_RUST: &str = "ghcr.io/shadowsocks/ssserver-rust:latest"; pub const IMAGE_SHADOW_TLS: &str = "ghcr.io/ihciah/shadow-tls:latest"; pub const IMAGE_TROJAN_GO: &str = "p4gefau1t/trojan-go:latest"; diff --git a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs index 6a0a4bb3a..fc2a782e6 100644 --- a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs +++ b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs @@ -188,9 +188,9 @@ impl DockerTestRunnerBuilder { pub fn port(mut self, port: u16) -> Self { self._server_port = port; self.exposed_ports = vec![format!("{}/tcp", port), format!("{}/udp", port)]; - let mounts = self.host_config.mounts.take(); - self.host_config = get_host_config(port); - self.host_config.mounts = mounts; + let new_host_config = get_host_config(port); + self.host_config.network_mode = new_host_config.network_mode; + self.host_config.port_bindings = new_host_config.port_bindings; self } @@ -227,6 +227,27 @@ impl DockerTestRunnerBuilder { self } + pub fn sysctls(mut self, sysctls: &[(&str, &str)]) -> Self { + self.host_config.sysctls = Some( + sysctls + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect::>(), + ); + + self + } + + pub fn cap_add(mut self, caps: &[&str]) -> Self { + self.host_config.cap_add = Some(caps.iter().map(|x| x.to_string()).collect()); + self + } + + pub fn net_mode(mut self, mode: &str) -> Self { + self.host_config.network_mode = Some(mode.to_string()); + self + } + pub async fn build(self) -> anyhow::Result { tracing::trace!("building docker test runner: {:?}", &self); let exposed = self diff --git a/clash_lib/src/proxy/utils/test_utils/mod.rs b/clash_lib/src/proxy/utils/test_utils/mod.rs index 5dc103ddb..da04bcdac 100644 --- a/clash_lib/src/proxy/utils/test_utils/mod.rs +++ b/clash_lib/src/proxy/utils/test_utils/mod.rs @@ -176,37 +176,61 @@ pub async fn latency_test( Ok(end_time.duration_since(start_time)) } -pub async fn run_default_test_suites_and_cleanup( +#[derive(Clone, Copy)] +pub enum Suite { + PingPong, + Latency, +} + +pub const DEFAULT_TEST_SUITES: &[Suite] = &[Suite::PingPong, Suite::Latency]; + +pub async fn run_test_suites_and_cleanup( handler: Arc, docker_test_runner: impl RunAndCleanup, + suites: &[Suite], ) -> anyhow::Result<()> { + let suites = suites.to_owned(); docker_test_runner .run_and_cleanup(async move { - let rv = ping_pong_test(handler.clone(), 10001).await; - if rv.is_err() { - tracing::error!("ping_pong_test failed: {:?}", rv); - return rv; - } else { - tracing::info!("ping_pong_test success"); - } - - let rv = latency_test( - handler, - LatencyTestOption { - dst: SocksAddr::Domain("example.com".to_owned(), 80), - req: consts::EXAMPLE_REQ, - expected_resp: consts::EXAMLE_RESP_200, - read_exact: true, - }, - ) - .await; - if let Err(e) = rv { - return Err(e); - } else { - tracing::info!("latency test success: {}", rv.unwrap().as_millis()); + for suite in suites { + match suite { + Suite::PingPong => { + let rv = ping_pong_test(handler.clone(), 10001).await; + if rv.is_err() { + tracing::error!("ping_pong_test failed: {:?}", rv); + return rv; + } else { + tracing::info!("ping_pong_test success"); + } + } + Suite::Latency => { + let rv = latency_test( + handler.clone(), + LatencyTestOption { + dst: SocksAddr::Domain("example.com".to_owned(), 80), + req: consts::EXAMPLE_REQ, + expected_resp: consts::EXAMLE_RESP_200, + read_exact: true, + }, + ) + .await; + if rv.is_err() { + return Err(rv.unwrap_err()); + } else { + tracing::info!("latency test success: {}", rv.unwrap().as_millis()); + } + } + } } Ok(()) }) .await } + +pub async fn run_default_test_suites_and_cleanup( + handler: Arc, + docker_test_runner: impl RunAndCleanup, +) -> anyhow::Result<()> { + run_test_suites_and_cleanup(handler, docker_test_runner, DEFAULT_TEST_SUITES).await +} diff --git a/clash_lib/src/proxy/wg/mod.rs b/clash_lib/src/proxy/wg/mod.rs index d070dc64e..9cc63a0aa 100644 --- a/clash_lib/src/proxy/wg/mod.rs +++ b/clash_lib/src/proxy/wg/mod.rs @@ -290,3 +290,70 @@ impl OutboundHandler for Handler { Ok(Box::new(chained)) } } + +#[cfg(all(test, not(ci)))] +mod tests { + + use crate::proxy::utils::test_utils::docker_runner::DockerTestRunnerBuilder; + use crate::proxy::utils::test_utils::{config_helper::test_config_base_dir, Suite}; + + use super::super::utils::test_utils::{consts::*, docker_runner::DockerTestRunner}; + use crate::proxy::utils::test_utils::run_test_suites_and_cleanup; + + use super::*; + + // see: https://github.com/linuxserver/docker-wireguard?tab=readme-ov-file#usage + // we shouldn't run the wireguard server with host mode, or + // the sysctl of `net.ipv4.conf.all.src_valid_mark` will fail + async fn get_runner() -> anyhow::Result { + let test_config_dir = test_config_base_dir(); + let wg_config = test_config_dir.join("wg_config"); + // the following configs is in accordance with the config in `wg_config` dir + DockerTestRunnerBuilder::new() + .image(IMAGE_WG) + .env(&[ + "PUID=1000", + "PGID=1000", + "TZ=Etc/UTC", + "SERVERPORT=10002", + "PEERS=1", + "PEERDNS=auto", + "INTERNAL_SUBNET=10.13.13.0", + "ALLOWEDIPS=0.0.0.0/0", + ]) + .mounts(&[(wg_config.to_str().unwrap(), "/config")]) + .sysctls(&[("net.ipv4.conf.all.src_valid_mark", "1")]) + .cap_add(&["NET_ADMIN"]) + .net_mode("bridge") // the default network mode for testing is `host` + .build() + .await + } + + #[tokio::test] + #[serial_test::serial] + async fn test_wg() -> anyhow::Result<()> { + let opts = HandlerOpts { + name: "wg".to_owned(), + common_opts: CommonOption::default(), + server: "127.0.0.1".to_owned(), + port: 10002, + ip: Ipv4Addr::new(10, 13, 13, 2), + ipv6: None, + private_key: "KIlDUePHyYwzjgn18przw/ZwPioJhh2aEyhxb/dtCXI=".to_owned(), + public_key: "INBZyvB715sA5zatkiX8Jn3Dh5tZZboZ09x4pkr66ig=".to_owned(), + preshared_key: Some("+JmZErvtDT4ZfQequxWhZSydBV+ItqUcPMHUWY1j2yc=".to_owned()), + remote_dns_resolve: false, + dns: None, + mtu: Some(1000), + udp: true, + allowed_ips: Some(vec!["0.0.0.0/0".to_owned()]), + reserved_bits: None, + }; + let handler = Handler::new(opts); + + // cannot run the ping pong test, since the wireguard server is running on bridge network mode + // and the `net.ipv4.conf.all.src_valid_mark` is not supported in the host network mode + // the latency test should be enough + run_test_suites_and_cleanup(handler, get_runner().await?, &[Suite::Latency]).await + } +} From 31e721b6715ce0a163e4e81ce0252950b3f40a58 Mon Sep 17 00:00:00 2001 From: iHsin Date: Thu, 11 Apr 2024 08:21:49 +0800 Subject: [PATCH 11/16] remove boringssl (#364) --- Cargo.lock | 92 +-------- clash_lib/Cargo.toml | 8 +- clash_lib/build.rs | 1 + clash_lib/src/common/crypto.rs | 184 ++++++------------ .../src/proxy/vmess/vmess_impl/header.rs | 49 +++-- .../src/proxy/vmess/vmess_impl/stream.rs | 56 ++---- clash_lib/src/proxy/vmess/vmess_impl/user.rs | 66 ++----- 7 files changed, 135 insertions(+), 321 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6017f5365..40c27aa6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -586,26 +586,6 @@ dependencies = [ "which", ] -[[package]] -name = "bindgen" -version = "0.68.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" -dependencies = [ - "bitflags 2.5.0", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.55", -] - [[package]] name = "bindgen" version = "0.69.4" @@ -739,31 +719,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "boring" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8259fc1ea91894a550190683fbcda307d1ef85f2875d93a2b1ab3cab58b62fea" -dependencies = [ - "bitflags 2.5.0", - "boring-sys", - "foreign-types", - "libc", - "once_cell", -] - -[[package]] -name = "boring-sys" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace69f2e0d89d2c5e0874efe47f46259ff794fe8cbddfca72132c817611ad471" -dependencies = [ - "bindgen 0.68.1", - "cmake", - "fs_extra", - "fslock", -] - [[package]] name = "boringtun" version = "0.6.0" @@ -1072,6 +1027,7 @@ dependencies = [ name = "clash_lib" version = "0.1.15" dependencies = [ + "aead", "aes", "aes-gcm", "anyhow", @@ -1082,8 +1038,6 @@ dependencies = [ "axum-macros", "base64 0.22.0", "bollard", - "boring", - "boring-sys", "boringtun", "brotli", "byteorder", @@ -1092,6 +1046,7 @@ dependencies = [ "chacha20poly1305", "chrono", "console-subscriber", + "const-fnv1a-hash", "crc32fast", "criterion", "ctor", @@ -1132,6 +1087,7 @@ dependencies = [ "rand", "regex", "register-count", + "ring-compat", "rustls 0.21.8", "rustls-pemfile", "security-framework", @@ -1168,15 +1124,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - [[package]] name = "coarsetime" version = "0.1.34" @@ -1253,6 +1200,12 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "const-fnv1a-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" + [[package]] name = "const-oid" version = "0.9.6" @@ -2050,27 +2003,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.55", -] - [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -2109,12 +2041,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "fsevent-sys" version = "4.1.0" diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index faf9e6d71..dfe7a277a 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -35,8 +35,6 @@ foreign-types-shared = "0.3.1" network-interface = "1.1.3" base64 = "0.22" uuid = { version = "1.8.0", features = ["v4", "fast-rng", "macro-diagnostics", "serde"] } -boring = "4.5.0" -boring-sys = "4.5.0" ip_network_table-deps-treebitmap = "0.5.0" once_cell = "1.18.0" @@ -54,11 +52,14 @@ brotli = "4.0.0" hmac = "0.12.1" sha1 = "0.10" sha2 = "0.10.8" -md-5 = "0.10.5" +md-5 = "0.10" chacha20poly1305 = "0.10" +aead = { version = "0.5.2", features = ["std"] } aes = "0.8.4" aes-gcm = "0.10" cfb-mode = "0.8.2" +const-fnv1a-hash = "1" + filetime = "0.2" axum = { version = "0.7", features = ["ws"] } tower-http = { version = "0.5.2", features = ["fs", "trace", "cors"] } @@ -89,6 +90,7 @@ rustls = { version = "0.21", features=["dangerous_configuration", "quic"] } rustls-pemfile = "1.0.4" webpki-roots = "0.25" dhcproto = "0.11" +ring-compat = { version = "0.8", features = ["aead"] } rand = "0.8" diff --git a/clash_lib/build.rs b/clash_lib/build.rs index 4c2fde659..7bc7594bf 100644 --- a/clash_lib/build.rs +++ b/clash_lib/build.rs @@ -1,4 +1,5 @@ fn main() { + println!("cargo:rerun-if-env-changed=CLASH_RS_CI"); if std::env::var("CLASH_RS_CI").is_ok() { println!("cargo::rustc-cfg=ci"); } diff --git a/clash_lib/src/common/crypto.rs b/clash_lib/src/common/crypto.rs index 10b32c640..e1c5e107e 100644 --- a/clash_lib/src/common/crypto.rs +++ b/clash_lib/src/common/crypto.rs @@ -1,10 +1,7 @@ -use std::ffi::CStr; - -use crate::Error; - use aes::cipher::{AsyncStreamCipher, KeyIvInit}; use aes_gcm::aes::cipher::Unsigned; use aes_gcm::{AeadInPlace, KeyInit}; +use anyhow::Ok; pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &mut [u8]) -> anyhow::Result<()> { match key.len() { @@ -42,126 +39,65 @@ pub fn aes_cfb_decrypt(key: &[u8], iv: &[u8], data: &mut [u8]) -> anyhow::Result } } -pub fn aes_gcm_seal( +pub fn aes_gcm_encrypt( key: &[u8], nonce: &[u8], - data: &[u8], - ad: Option<&[u8]>, + plaintext: &[u8], + associated_data: Option<&[u8]>, ) -> anyhow::Result> { - unsafe { - let ctx = boring_sys::EVP_AEAD_CTX_new( - match key.len() { - 16 => boring_sys::EVP_aead_aes_128_gcm(), - 24 => boring_sys::EVP_aead_aes_192_gcm(), - 32 => boring_sys::EVP_aead_aes_256_gcm(), - _ => anyhow::bail!("invalid key length"), - }, - key.as_ptr(), - key.len(), - boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as _, - ); - - let mut out = vec![0u8; data.len() + boring_sys::EVP_AEAD_MAX_OVERHEAD as usize]; - - let mut out_len = 0; - - let rv = boring_sys::EVP_AEAD_CTX_seal( - ctx, - out.as_mut_ptr(), - &mut out_len, - out.len(), - nonce.as_ptr(), - nonce.len(), - data.as_ptr(), - data.len(), - match ad { - Some(ad) => ad.as_ptr(), - None => std::ptr::null(), - }, - match ad { - Some(ad) => ad.len(), - None => 0, - }, - ); - - boring_sys::EVP_AEAD_CTX_free(ctx); - - return if rv != 1 { - Err(Error::Crypto( - CStr::from_ptr( - boring_sys::ERR_reason_error_string(boring_sys::ERR_get_error()) as _, - ) - .to_str() - .expect("openssl error string is not utf8") - .to_owned(), - ) - .into()) - } else { - out.truncate(out_len); - Ok(out) - }; + let mut buffer = Vec::with_capacity(plaintext.len() + 16); + buffer.append(&mut plaintext.to_vec()); + match key.len() { + 16 => { + let cipher = ring_compat::aead::Aes128Gcm::new_from_slice(key)?; + cipher.encrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + 32 => { + let cipher = ring_compat::aead::Aes256Gcm::new_from_slice(key)?; + cipher.encrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + _ => return Err(anyhow!("Illegal key size {}", key.len())), } + Ok(buffer) } -pub fn aes_gcm_open( +/// TODO +pub fn aes_gcm_decrypt( key: &[u8], nonce: &[u8], - data: &[u8], - ad: Option<&[u8]>, + ciphertext: &[u8], + associated_data: Option<&[u8]>, ) -> anyhow::Result> { - unsafe { - let ctx = boring_sys::EVP_AEAD_CTX_new( - match key.len() { - 16 => boring_sys::EVP_aead_aes_128_gcm(), - 24 => boring_sys::EVP_aead_aes_192_gcm(), - 32 => boring_sys::EVP_aead_aes_256_gcm(), - _ => anyhow::bail!("invalid key length"), - }, - key.as_ptr(), - key.len(), - boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as _, - ); - - let mut out = vec![0u8; data.len()]; - - let mut out_len = 0; - - let rv = boring_sys::EVP_AEAD_CTX_open( - ctx, - out.as_mut_ptr(), - &mut out_len, - out.len(), - nonce.as_ptr(), - nonce.len(), - data.as_ptr(), - data.len(), - match ad { - Some(ad) => ad.as_ptr(), - None => std::ptr::null(), - }, - match ad { - Some(ad) => ad.len(), - None => 0, - }, - ); - - boring_sys::EVP_AEAD_CTX_free(ctx); - - return if rv != 1 { - Err(Error::Crypto( - CStr::from_ptr( - boring_sys::ERR_reason_error_string(boring_sys::ERR_get_error()) as _, - ) - .to_str() - .expect("openssl error string is not utf8") - .to_owned(), - ) - .into()) - } else { - out.truncate(out_len); - Ok(out) - }; + let mut buffer = ciphertext.to_vec(); + match key.len() { + 16 => { + let cipher = ring_compat::aead::Aes128Gcm::new_from_slice(key)?; + cipher.decrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + 32 => { + let cipher = ring_compat::aead::Aes256Gcm::new_from_slice(key)?; + cipher.decrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + _ => return Err(anyhow!("Illegal key size {}", key.len())), } + buffer.shrink_to_fit(); + Ok(buffer) } pub trait AeadCipherHelper: AeadInPlace { @@ -214,9 +150,9 @@ impl AeadCipherHelper for chacha20poly1305::ChaCha20Poly1305 { #[cfg(test)] mod tests { - use crate::common::{crypto::aes_gcm_open, utils}; + use crate::common::{crypto::aes_gcm_decrypt, utils}; - use super::{aes_cfb_encrypt, aes_gcm_seal}; + use super::{aes_cfb_encrypt, aes_gcm_encrypt}; #[test] fn test_aes_cfb_256() { @@ -242,30 +178,26 @@ mod tests { #[test] fn test_aes_gcm_seal_ok() { let key = "1234567890123456".as_bytes(); - let nonce = "456".as_bytes(); + let nonce = "456456456456".as_bytes(); // it has to be 12 bytes let data = "789".as_bytes(); let ad = "abc".as_bytes(); - let encrypted = aes_gcm_seal(key, nonce, data, Some(ad)).expect("sealed"); + let encrypted = aes_gcm_encrypt(key, nonce, data, Some(ad)).expect("sealed"); - let decrypted = aes_gcm_open(key, nonce, &encrypted, Some(ad)).expect("opened"); + let decrypted = aes_gcm_decrypt(key, nonce, &encrypted, Some(ad)).expect("opened"); assert_eq!(decrypted, data); } #[test] fn test_aes_gcm_seal_fail() { let key = "1234567890123456".as_bytes(); - let nonce = "456".as_bytes(); + let nonce = "456456456456".as_bytes(); // it has to be 12 bytes let data = "789".as_bytes(); let ad = "abc".as_bytes(); - let encrypted = aes_gcm_seal(key, nonce, data, Some(ad)).expect("sealed"); + let encrypted = aes_gcm_encrypt(key, nonce, data, Some(ad)).expect("sealed"); let key2 = "1234567890123457".as_bytes(); - let decrypted = aes_gcm_open(key2, nonce, &encrypted, Some(ad)); + let decrypted = aes_gcm_decrypt(key2, nonce, &encrypted, Some(ad)); assert!(decrypted.is_err()); - assert_eq!( - decrypted.unwrap_err().to_string(), - "crypto error: BAD_DECRYPT" - ); } } diff --git a/clash_lib/src/proxy/vmess/vmess_impl/header.rs b/clash_lib/src/proxy/vmess/vmess_impl/header.rs index 97d944b83..76c553d62 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/header.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/header.rs @@ -1,4 +1,6 @@ -use bytes::{BufMut, BytesMut}; +use aead::{generic_array::GenericArray, KeyInit}; +use aes::cipher::BlockEncrypt; +use bytes::{Buf, BufMut, BytesMut}; use crate::common::{crypto, errors::map_io_error, utils}; @@ -20,14 +22,15 @@ fn create_auth_id(cmd_key: [u8; 16], timestamp: u64) -> [u8; 16] { let zero = crc32fast::hash(buf.as_ref()); buf.put_u32(zero); - let mut aes_key = boring_sys::AES_KEY::default(); let pk = kdf::vmess_kdf_1_one_shot(&cmd_key[..], KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); - unsafe { - boring_sys::AES_set_encrypt_key(pk.as_ptr() as _, 128, &mut aes_key); - boring_sys::AES_encrypt(buf.as_mut_ptr() as _, buf.as_mut_ptr() as _, &aes_key); - } - - buf.freeze()[..16].try_into().unwrap() + let pk: [u8; 16] = pk[..16].try_into().unwrap(); // That's wired + let key = GenericArray::from(pk); + let cipher = aes::Aes128::new(&key); + let mut block = [0u8; 16]; + buf.copy_to_slice(&mut block); + let mut block = GenericArray::from(block); + cipher.encrypt_block(&mut block); + block.as_slice()[..16].try_into().unwrap() } pub(crate) fn seal_vmess_aead_header( @@ -52,7 +55,7 @@ pub(crate) fn seal_vmess_aead_header( &connection_nonce[..], )[..12]; - let header_len_encrypted = crypto::aes_gcm_seal( + let header_len_encrypted = crypto::aes_gcm_encrypt( payload_header_length_aead_key, payload_header_length_aead_nonce, (data.len() as u16).to_be_bytes().as_ref(), @@ -73,7 +76,7 @@ pub(crate) fn seal_vmess_aead_header( &connection_nonce[..], )[..12]; - let payload_encrypted = crypto::aes_gcm_seal( + let payload_encrypted = crypto::aes_gcm_encrypt( payload_header_aead_key, payload_header_aead_nonce, &data, @@ -92,8 +95,6 @@ pub(crate) fn seal_vmess_aead_header( #[cfg(test)] mod tests { - use bytes::{BufMut, BytesMut}; - use crate::{ common::crypto, proxy::vmess::vmess_impl::kdf::{ @@ -104,6 +105,9 @@ mod tests { KDF_SALT_CONST_VMESS_HEADER_PAYLOAD_LENGTH_AEAD_KEY, }, }; + use aead::{generic_array::GenericArray, KeyInit}; + use aes::cipher::BlockEncrypt; + use bytes::{Buf, BufMut, BytesMut}; #[test] fn test_create_auth_id() { @@ -119,15 +123,18 @@ mod tests { buf.put_u32(zero); let cmd_key = "1234567890123456".as_bytes(); - let mut aes_key = boring_sys::AES_KEY::default(); - let pk = kdf::vmess_kdf_1_one_shot(cmd_key, KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); - unsafe { - boring_sys::AES_set_encrypt_key(pk.as_ptr() as _, 128, &mut aes_key); - boring_sys::AES_encrypt(buf.as_mut_ptr() as _, buf.as_mut_ptr() as _, &aes_key); - } + let pk = kdf::vmess_kdf_1_one_shot(&cmd_key[..], KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); + let pk: [u8; 16] = pk[..16].try_into().unwrap(); // That's wired + let key = GenericArray::from(pk); + let cipher = aes::Aes128::new(&key); + let mut block = [0u8; 16]; + buf.copy_to_slice(&mut block); + let mut block = GenericArray::from(block); + cipher.encrypt_block(&mut block); + let block: [u8; 16] = block.as_slice()[..16].try_into().unwrap(); assert_eq!( - buf.freeze()[..16], + block.to_vec(), vec![55, 189, 144, 149, 192, 213, 241, 57, 37, 21, 179, 197, 135, 54, 86, 79] ); } @@ -152,7 +159,7 @@ mod tests { &connection_nonce[..], )[..12]; - let header_len_encrypted = crypto::aes_gcm_seal( + let header_len_encrypted = crypto::aes_gcm_encrypt( payload_header_length_aead_key, payload_header_length_aead_nonce, (data.len() as u16).to_be_bytes().as_ref(), @@ -173,7 +180,7 @@ mod tests { &connection_nonce[..], )[..12]; - let payload_encrypted = crypto::aes_gcm_seal( + let payload_encrypted = crypto::aes_gcm_encrypt( payload_header_aead_key, payload_header_aead_nonce, &data, diff --git a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs index 2fb919098..982b040ce 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs @@ -4,6 +4,8 @@ use aes_gcm::Aes128Gcm; use bytes::{BufMut, BytesMut}; use chacha20poly1305::ChaCha20Poly1305; use futures::ready; + +use md5::Md5; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadBuf}; use crate::{ @@ -23,7 +25,7 @@ use super::{ self, KDF_SALT_CONST_AEAD_RESP_HEADER_LEN_IV, KDF_SALT_CONST_AEAD_RESP_HEADER_LEN_KEY, KDF_SALT_CONST_AEAD_RESP_HEADER_PAYLOAD_IV, KDF_SALT_CONST_AEAD_RESP_HEADER_PAYLOAD_KEY, }, - user::{ID, ID_BYTES_LEN}, + user::ID, Security, CHUNK_SIZE, COMMAND_TCP, COMMAND_UDP, OPTION_CHUNK_STREAM, SECURITY_AES_128_GCM, SECURITY_CHACHA20_POLY1305, SECURITY_NONE, VERSION, }; @@ -225,6 +227,8 @@ where S: AsyncWrite + Unpin, { async fn send_handshake_request(&mut self) -> std::io::Result<()> { + use hmac::{Hmac, Mac}; + type HmacMd5 = Hmac; let Self { ref mut stream, ref req_body_key, @@ -246,21 +250,10 @@ where let mut mbuf = BytesMut::new(); if !is_aead { - let mut hash = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize]; - let mut out_len: u32 = 0; - - unsafe { - boring_sys::HMAC( - boring_sys::EVP_md5(), - id.uuid.as_bytes().as_ptr() as _, - ID_BYTES_LEN, - now.to_be_bytes().as_mut_ptr() as _, - 8, - &mut hash as _, - &mut out_len as _, - ); - } - mbuf.put_slice(&hash[..out_len as _]) + let mut mac = + HmacMd5::new_from_slice(id.uuid.as_bytes()).expect("key len expected to be 16"); + mac.update(now.to_be_bytes().as_slice()); + mbuf.put_slice(&mac.finalize().into_bytes()); } let mut buf = BytesMut::new(); @@ -289,10 +282,8 @@ where buf.put_slice(&padding); } - unsafe { - let sum = boring_sys::OPENSSL_hash32(buf.as_mut_ptr() as _, buf.len()); - buf.put_slice(sum.to_be_bytes().as_ref()); - } + let sum = const_fnv1a_hash::fnv1a_hash_32(&buf, None); + buf.put_slice(&sum.to_be_bytes()); if !is_aead { let mut data = buf.to_vec(); @@ -363,7 +354,7 @@ where KDF_SALT_CONST_AEAD_RESP_HEADER_LEN_IV, )[..12]; - let decrypted_response_header_len = crypto::aes_gcm_open( + let decrypted_response_header_len = crypto::aes_gcm_decrypt( aead_response_header_length_encryption_key, aead_response_header_length_encryption_iv, this.read_buf.split().as_ref(), @@ -402,7 +393,7 @@ where KDF_SALT_CONST_AEAD_RESP_HEADER_PAYLOAD_IV, )[..12]; - let buf = crypto::aes_gcm_open( + let buf = crypto::aes_gcm_decrypt( aead_response_header_payload_encryption_key, aead_response_header_payload_encryption_iv, this.read_buf.split().as_ref(), @@ -576,17 +567,12 @@ where } fn hash_timestamp(timestamp: u64) -> [u8; 16] { - unsafe { - let mut ctx = boring_sys::MD5_CTX::default(); - boring_sys::MD5_Init(&mut ctx); - - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - - let mut hash = [0u8; 16]; - boring_sys::MD5_Final(hash.as_mut_ptr() as _, &mut ctx); - hash - } + use md5::Digest; + let mut hasher = md5::Md5::new(); + // TODO Why four times? + hasher.update(timestamp.to_be_bytes()); + hasher.update(timestamp.to_be_bytes()); + hasher.update(timestamp.to_be_bytes()); + hasher.update(timestamp.to_be_bytes()); + hasher.finalize().into() } diff --git a/clash_lib/src/proxy/vmess/vmess_impl/user.rs b/clash_lib/src/proxy/vmess/vmess_impl/user.rs index b9fa267a0..ae9a0d912 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/user.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/user.rs @@ -1,11 +1,9 @@ -use boring_sys::MD5_DIGEST_LENGTH; - -pub const ID_BYTES_LEN: usize = 16; +use md5::Digest; #[derive(Clone)] pub struct ID { pub uuid: uuid::Uuid, - pub cmd_key: [u8; MD5_DIGEST_LENGTH as _], + pub cmd_key: [u8; 16], } pub fn new_alter_id_list(primary: &ID, alter_id_count: u16) -> Vec { @@ -25,61 +23,23 @@ pub fn new_alter_id_list(primary: &ID, alter_id_count: u16) -> Vec { alter_id_list } +/// TODO docs pub fn new_id(uuid: &uuid::Uuid) -> ID { let uuid = uuid.to_owned(); - let mut cmd_key = [0u8; MD5_DIGEST_LENGTH as _]; - - let mut ctx = boring_sys::MD5_CTX::default(); - unsafe { - boring_sys::MD5_Init(&mut ctx as _); - boring_sys::MD5_Update( - &mut ctx as _, - uuid.as_bytes().as_ptr() as _, - uuid.as_bytes().len(), - ); - boring_sys::MD5_Update( - &mut ctx as _, - b"c48619fe-8f02-49e0-b9e9-edf763e17e21".as_ptr() as _, - 36, - ); - boring_sys::MD5_Final(cmd_key.as_mut_ptr() as _, &mut ctx as _); - } - + let mut hasher = md5::Md5::new(); + hasher.update(uuid.as_bytes()); + hasher.update(b"c48619fe-8f02-49e0-b9e9-edf763e17e21"); // What? + let cmd_key: [u8; 16] = hasher.finalize().into(); ID { uuid, cmd_key } } +/// TODO docs fn next_id(i: &uuid::Uuid) -> uuid::Uuid { - let mut ctx = boring_sys::MD5_CTX::default(); - unsafe { - boring_sys::MD5_Init(&mut ctx as _); - boring_sys::MD5_Update( - &mut ctx as _, - i.as_bytes().as_ptr() as _, - i.as_bytes().len(), - ); - boring_sys::MD5_Update( - &mut ctx as _, - b"16167dc8-16b6-4e6d-b8bb-65dd68113a81".as_ptr() as _, - 36, - ); - let mut buf = [0u8; MD5_DIGEST_LENGTH as _]; - /* - loop { - boring_sys::MD5_Final(buf.as_mut_ptr() as _, &mut ctx as _); - if i.as_bytes() != buf.as_slice() { - return uuid::Uuid::from_bytes(buf); - } - - boring_sys::MD5_Update( - &mut ctx as _, - b"533eff8a-4113-4b10-b5ce-0f5d76b98cd2".as_ptr() as _, - 36, - ); - } - */ - boring_sys::MD5_Final(buf.as_mut_ptr() as _, &mut ctx as _); - uuid::Uuid::from_bytes(buf) - } + let mut hasher = md5::Md5::new(); + hasher.update(i.as_bytes()); + hasher.update(b"16167dc8-16b6-4e6d-b8bb-65dd68113a81"); // Why? + let buf: [u8; 16] = hasher.finalize().into(); + uuid::Uuid::from_bytes(buf) } #[cfg(test)] From 48a26d0eed83733659c06c73382f4ef1fe3f7166 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Apr 2024 03:23:49 +0000 Subject: [PATCH 12/16] Bump anyhow from 1.0.81 to 1.0.82 (#367) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.81 to 1.0.82. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.81...1.0.82) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40c27aa6f..4d0c5e6cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "arc-swap" From ccbe9afe04383eb54ea0f8dbb289815bcc3315eb Mon Sep 17 00:00:00 2001 From: Yuwei Ba Date: Fri, 12 Apr 2024 00:37:09 +0800 Subject: [PATCH 13/16] Update README.md Signed-off-by: Yuwei Ba --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index aa12a517e..d935e226f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,10 @@ A custom protocol, rule based network proxy software. ## 📦 Install +### Use With GUI + +https://github.com/LibNyanpasu/clash-nyanpasu + ### Download Prebuilt Binary Can be found at https://github.com/Watfaq/clash-rs/releases From 50f6852c694a8b76d40fc7c2237ab11972674648 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 03:21:00 +0000 Subject: [PATCH 14/16] Bump async-trait from 0.1.79 to 0.1.80 (#369) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.79 to 0.1.80. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.79...0.1.80) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d0c5e6cd..c1f84875a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", From f04a96d69f83d974414be31c011f055d6591b7bb Mon Sep 17 00:00:00 2001 From: iHsin Date: Fri, 12 Apr 2024 21:34:46 +0800 Subject: [PATCH 15/16] refactor(ci): use cross (#368) * refactor: use cross * ci: change job name * ci: add static-crt builds * ci: add missing tokio_unstable * build: remove eyre * ci: fix cv mistake * ci: replace armv7 static-crt with musl * cI: change cache key * ci: remove old files --- .cargo/config | 15 - .github/release.yaml | 11 - .github/workflows/ci.yml | 310 ++++++++++++++---- Cargo.lock | 180 ++-------- Cross.toml | 9 + clash_lib/Cargo.toml | 4 +- clash_lib/src/common/errors.rs | 7 +- clash_lib/src/proxy/utils/test_utils/mod.rs | 4 +- .../src/proxy/vmess/vmess_impl/stream.rs | 9 +- scripts/build.sh | 172 ---------- scripts/cmake/aarch64-musl.cmake | 3 - scripts/cmake/arm-musl.cmake | 3 - scripts/cmake/armhf-musl.cmake | 3 - scripts/cmake/armv7-musl.cmake | 3 - scripts/cmake/armv7hf-musl.cmake | 3 - scripts/cmake/x86_64-musl.cmake | 3 - 16 files changed, 294 insertions(+), 445 deletions(-) delete mode 100644 .github/release.yaml create mode 100644 Cross.toml delete mode 100644 scripts/build.sh delete mode 100644 scripts/cmake/aarch64-musl.cmake delete mode 100644 scripts/cmake/arm-musl.cmake delete mode 100644 scripts/cmake/armhf-musl.cmake delete mode 100644 scripts/cmake/armv7-musl.cmake delete mode 100644 scripts/cmake/armv7hf-musl.cmake delete mode 100644 scripts/cmake/x86_64-musl.cmake diff --git a/.cargo/config b/.cargo/config index 3420c1fc8..13c84ae1c 100644 --- a/.cargo/config +++ b/.cargo/config @@ -4,18 +4,3 @@ rustflags = ["--cfg", "tokio_unstable"] [env] RUST_LOG = { value = "clash=trace" } - -[target.aarch64-unknown-linux-gnu] -linker = "/usr/bin/aarch64-linux-gnu-gcc" - -[target.armv7-unknown-linux-gnueabihf] -linker = "/usr/bin/arm-linux-gnueabihf-gcc" - -[target.armv7-unknown-linux-gnueabi] -linker = "/usr/bin/arm-linux-gnueabi-gcc" - -[target.arm-unknown-linux-gnueabihf] -linker = "/usr/bin/arm-linux-gnueabihf-gcc" - -[target.arm-unknown-linux-gnueabi] -linker = "/usr/bin/arm-linux-gnueabi-gcc" \ No newline at end of file diff --git a/.github/release.yaml b/.github/release.yaml deleted file mode 100644 index 7aa8ef72b..000000000 --- a/.github/release.yaml +++ /dev/null @@ -1,11 +0,0 @@ -changelog: - categories: - - title: 🏕 Features - labels: - - '*' - exclude: - labels: - - dependencies - - title: 👒 Dependencies - labels: - - dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5756a387..bc03d0f83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,71 +3,261 @@ name: Build/Test/Release on: push: tags: [ "v*" ] + branches: [ "master" ] pull_request: branches: [ "master" ] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + PACKAGE: "clash" + jobs: - test: - name: test ${{ matrix.platforms.target }} on ${{ matrix.platforms.os }} static - ${{ matrix.static }} + compile: + name: ${{ matrix.release-name || matrix.target || 'Unknown' }} + permissions: + contents: write + runs-on: ${{ matrix.os || 'ubuntu-latest' }} strategy: + fail-fast: false matrix: - static: [true, false] - platforms: [ - {os: ubuntu-22.04, target: x86_64-unknown-linux-gnu}, - {os: ubuntu-22.04, target: aarch64-unknown-linux-gnu}, - {os: ubuntu-22.04, target: armv7-unknown-linux-gnueabihf}, - {os: ubuntu-22.04, target: armv7-unknown-linux-gnueabi}, - {os: macos-13, target: aarch64-apple-darwin}, - {os: macos-13, target: x86_64-apple-darwin}, - {os: windows-2022, target: x86_64-pc-windows-msvc}, - ] - runs-on: ${{ matrix.platforms.os }} + include: + # Example + # when not set, default will be used (except target, cross) + # - os: ubuntu-latest + # target: x86_64-unknown-linux-gnu + # release-name: x86_64-linux + # toolchain: stable + # cross: true + # postfix: "" + # extra-args: "" + # components: "" + # rustflags: "" + + # Linux x86 + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + cross: true + extra-args: "--all-features" + - os: ubuntu-latest + target: i686-unknown-linux-gnu + cross: true + extra-args: "--all-features" + # Linux x86 static-crt + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + release-name: x86_64-unknown-linux-gnu-static-crt + cross: true + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + - os: ubuntu-latest + target: i686-unknown-linux-gnu + release-name: i686-unknown-linux-gnu-static-crt + cross: true + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + # Linux arm + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + cross: true + extra-args: "--all-features" + - os: ubuntu-latest + target: armv7-unknown-linux-gnueabi + cross: true + extra-args: "--all-features" + - os: ubuntu-latest + target: armv7-unknown-linux-gnueabihf + cross: true + extra-args: "--all-features" + # Linux arm static-crt + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + release-name: aarch64-unknown-linux-gnu-static-crt + cross: true + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + - os: ubuntu-latest + target: armv7-unknown-linux-gnueabi + release-name: armv7-unknown-linux-gnueabi-static-crt + cross: true + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + - os: ubuntu-latest + target: armv7-unknown-linux-musleabihf + cross: true + extra-args: "--all-features" + rustflags: "--cfg tokio_unstable" + # Windows + - os: windows-latest + target: x86_64-pc-windows-msvc + cross: false + postfix: ".exe" + extra-args: "--all-features" + - os: windows-latest + target: i686-pc-windows-msvc + cross: false + postfix: ".exe" + extra-args: "--all-features" + # Windows static-crt + - os: windows-latest + target: x86_64-pc-windows-msvc + release-name: x86_64-pc-windows-msvc-static-crt + cross: false + postfix: ".exe" + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + - os: windows-latest + target: i686-pc-windows-msvc + release-name: i686-pc-windows-msvc-static-crt + cross: false + postfix: ".exe" + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + # MacOSX + - os: macos-12 + target: x86_64-apple-darwin + cross: false + extra-args: "--all-features" + - os: macos-14 + target: aarch64-apple-darwin + cross: false + extra-args: "--all-features" + # MacOSX static-crt + - os: macos-12 + target: x86_64-apple-darwin + release-name: x86_64-apple-darwin-static-crt + cross: false + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + - os: macos-14 + target: aarch64-apple-darwin + release-name: aarch64-apple-darwin-static-crt + cross: false + extra-args: "--all-features" + rustflags: "-Ctarget-feature=+crt-static --cfg tokio_unstable" + # Linux mips: tier-3, pity + # Linux risc-v: needs update rustls + # Windows gnu: tokio dont work + # Windows aarch: todo + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ matrix.release-name || matrix.target }}-${{ hashFiles('**/Cargo.toml') }} + restore-keys: | + ${{ matrix.release-name || matrix.target }} + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.toolchain || 'stable' }} + target: ${{ matrix.target }} + components: ${{ matrix.components || 'rustfmt, clippy' }} + + - name: Cargo fmt + uses: clechasseur/rs-cargo@v2 + with: + use-cross: ${{ matrix.cross }} + command: fmt + args: --all -- --check + + - name: Cargo clippy + uses: clechasseur/rs-cargo@v2 + with: + use-cross: ${{ matrix.cross }} + command: clippy + args: --all --target ${{ matrix.target }} ${{ matrix.extra-args }} -- -D warnings + env: + RUSTFLAGS: ${{ matrix.rustflags || '--cfg tokio_unstable' }} + - name: Cargo test + uses: clechasseur/rs-cargo@v2 + if: startsWith(matrix.os, 'ubuntu') + with: + use-cross: ${{ matrix.cross }} + command: test + args: --all --target ${{ matrix.target }} ${{ matrix.extra-args }} + env: + CROSS_CONTAINER_OPTS: "--network host" + RUSTFLAGS: ${{ matrix.rustflags || '--cfg tokio_unstable' }} + + - name: Cargo test (no docker test) + uses: clechasseur/rs-cargo@v2 + if: ${{ !startsWith(matrix.os, 'ubuntu') }} + with: + use-cross: ${{ matrix.cross }} + command: test + args: --all --target ${{ matrix.target }} ${{ matrix.extra-args }} + env: + CLASH_RS_CI: "true" + RUSTFLAGS: ${{ matrix.rustflags || '--cfg tokio_unstable' }} + + - name: Cargo build + uses: clechasseur/rs-cargo@v2 + with: + use-cross: ${{ matrix.cross }} + command: build + args: --release --target ${{ matrix.target }} ${{ matrix.extra-args }} + env: + RUSTFLAGS: ${{ matrix.rustflags || '--cfg tokio_unstable' }} + + - name: Rename binary + run: mv target/${{ matrix.target }}/release/${{ env.PACKAGE }}${{ matrix.postfix }} ${{ env.PACKAGE }}-${{ matrix.release-name || matrix.target }}${{ matrix.postfix }} + + - name: Upload binaries + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.release-name || matrix.target }} + path: ${{ env.PACKAGE }}-${{ matrix.release-name || matrix.target }}${{ matrix.postfix }} + + release: + name: Release + + needs: [compile] + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - uses: ilammy/setup-nasm@v1 - if : ${{ matrix.platforms.os == 'windows-2022' }} - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - components: rustfmt, clippy - - name: Run cargo fmt - run: cargo fmt --all -- --check - - name: Run cargo check - run: cargo check --all --all-features - - name: Run cargo clippy - run: cargo clippy --all --all-features -- -D warnings - - name: Run cargo test on Linux - if: ${{ matrix.platforms.os == 'ubuntu-22.04' }} - run: cargo test --all --all-features - - name: Run cargo test on non LInux - env: # this is a bit counter intuitive - some tests relies on Docker to run and are marked not(ci), but macos runner doesn't have Docker installed, so we make it "ci" to bypass those tests - CLASH_RS_CI: 'true' - if: ${{ matrix.platforms.os != 'ubuntu-22.04' }} - run: cargo test --all --all-features - - name: Build artifacts - run: sh ./scripts/build.sh "${{ matrix.platforms.target }}" "${{ matrix.static }}" - - name: Stash artifacts - uses: actions/upload-artifact@v4 - with: - name: clash-${{ matrix.platforms.os }}-${{ matrix.platforms.target }}-${{ matrix.static }} - path: target/artifacts/ - - - - name: Create Release - if: contains(github.ref, 'tags/v') - id: create_release - uses: softprops/action-gh-release@v2 - with: - generate_release_notes: true - - name: Upload Release Asset - if: contains(github.ref, 'tags/v') - id: upload-release-asset - uses: dwenegar/upload-release-assets@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - release_id: ${{ steps.create_release.outputs.id }} - assets_path: target/artifacts + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Merge binaries + uses: actions/upload-artifact/merge@v4 + with: + name: binaries + pattern: '*' + retention-days: 1 + + - name: Download binaries + uses: actions/download-artifact@v4 + with: + name: binaries + path: ./packages + + - name: Github stable release + uses: "mathieucarbou/marvinpinto-action-automatic-releases@master" + if: startsWith(github.ref, 'refs/tags/v') + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + prerelease: false + files: | + packages/* + LICENSE + + - name: Github nightly release + uses: "mathieucarbou/marvinpinto-action-automatic-releases@master" + if: startsWith(github.ref, 'refs/heads/master') + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + prerelease: true + automatic_release_tag: "latest" + files: | + packages/* + LICENSE diff --git a/Cargo.lock b/Cargo.lock index c1f84875a..a6bb4f26d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,15 +160,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anstream" version = "0.6.13" @@ -386,17 +377,6 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.2.0" @@ -565,15 +545,13 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bindgen" -version = "0.59.2" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ "bitflags 1.3.2", "cexpr", "clang-sys", - "clap 2.34.0", - "env_logger", "lazy_static", "lazycell", "log", @@ -583,6 +561,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", + "syn 1.0.109", "which", ] @@ -734,7 +713,7 @@ dependencies = [ "ip_network_table", "libc", "nix", - "parking_lot 0.12.1", + "parking_lot", "rand_core", "ring 0.17.8", "tracing", @@ -953,21 +932,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap", - "unicode-width", - "vec_map", -] - [[package]] name = "clap" version = "4.5.4" @@ -1012,7 +976,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" name = "clash" version = "0.1.15" dependencies = [ - "clap 4.5.4", + "clap", "clash_lib", ] @@ -1267,7 +1231,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.4", + "clap", "criterion-plot", "futures", "is-terminal", @@ -1508,7 +1472,7 @@ dependencies = [ "hashbrown 0.14.3", "lock_api", "once_cell", - "parking_lot_core 0.9.9", + "parking_lot_core", ] [[package]] @@ -1886,19 +1850,6 @@ dependencies = [ "syn 2.0.55", ] -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -1977,7 +1928,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "windows-sys 0.52.0", ] @@ -2380,15 +2331,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.9" @@ -2464,7 +2406,7 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.1", + "parking_lot", "rand", "resolv-conf", "rustls 0.21.8", @@ -2868,15 +2810,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "integer-encoding" version = "3.0.4" @@ -2950,7 +2883,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", "windows-sys 0.52.0", ] @@ -3080,7 +3013,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ "bitflags 2.5.0", "libc", - "redox_syscall 0.4.1", + "redox_syscall", ] [[package]] @@ -3472,7 +3405,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -3722,17 +3655,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -3740,21 +3662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -3765,7 +3673,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "windows-targets 0.48.5", ] @@ -3970,7 +3878,7 @@ dependencies = [ "atomic", "crossbeam-queue", "futures", - "parking_lot 0.12.1", + "parking_lot", "pin-project", "static_assertions", "thiserror", @@ -4308,15 +4216,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -4871,7 +4770,7 @@ dependencies = [ "futures", "lazy_static", "log", - "parking_lot 0.12.1", + "parking_lot", "serial_test_derive", ] @@ -5163,12 +5062,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "strsim" version = "0.10.0" @@ -5283,30 +5176,12 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "termtree" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.58" @@ -5435,7 +5310,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -6548,15 +6423,14 @@ dependencies = [ [[package]] name = "tracing-oslog" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bc58223383423483e4bc056c7e7b3f77bdee924a9d33834112c69ead06dc847" +source = "git+https://github.com/Absolucy/tracing-oslog.git?branch=main#2207764b7edd3a5c059f4c3e8837fe72127067f9" dependencies = [ - "bindgen 0.59.2", + "bindgen 0.64.0", "cc", "cfg-if", "fnv", "once_cell", - "parking_lot 0.11.2", + "parking_lot", "tracing-core", "tracing-subscriber", ] @@ -6656,7 +6530,7 @@ source = "git+https://github.com/Itsusinn/tuic.git?rev=82fab62#82fab626d6344f69f dependencies = [ "bytes", "futures-util", - "parking_lot 0.12.1", + "parking_lot", "register-count", "thiserror", "uuid", @@ -6753,12 +6627,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - [[package]] name = "universal-hash" version = "0.5.1" @@ -6852,12 +6720,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 000000000..47efca849 --- /dev/null +++ b/Cross.toml @@ -0,0 +1,9 @@ + +[build] +# zig = "2.17" +# pre-build = "./.github/prebuild.sh" + +[build.env] +# Docker in docker +volumes = ["/var/run/docker.sock=/var/run/docker.sock"] +# passthrough = ["VAR1_ARG", "VAR2_ARG=VALUE"] \ No newline at end of file diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index dfe7a277a..d44d14d77 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -15,7 +15,7 @@ tokio = { version = "1", features = ["full"] } tokio-util = { version = "0.7", features = ["net", "codec", "io", "compat"] } thiserror = "1.0" async-trait = "0.1" -anyhow = "1.0" +anyhow = "1" futures = "0.3" bytes = "1.6" async-recursion = "1" @@ -99,7 +99,7 @@ tokio-tungstenite = "0.21.0" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } -tracing-oslog = "0.1" +tracing-oslog = { branch = "main", git = "https://github.com/Absolucy/tracing-oslog.git" } tracing-appender = "0.2.3" diff --git a/clash_lib/src/common/errors.rs b/clash_lib/src/common/errors.rs index 8b1994f36..fbc23e75a 100644 --- a/clash_lib/src/common/errors.rs +++ b/clash_lib/src/common/errors.rs @@ -4,6 +4,9 @@ pub fn new_io_error(msg: &str) -> io::Error { io::Error::new(io::ErrorKind::Other, msg) } -pub fn map_io_error(err: T) -> io::Error { - io::Error::new(io::ErrorKind::Other, err.to_string()) +pub fn map_io_error(err: T) -> io::Error +where + T: Into + Send, +{ + io::Error::new(io::ErrorKind::Other, format!("{:?}", anyhow::anyhow!(err))) } diff --git a/clash_lib/src/proxy/utils/test_utils/mod.rs b/clash_lib/src/proxy/utils/test_utils/mod.rs index da04bcdac..cee304d15 100644 --- a/clash_lib/src/proxy/utils/test_utils/mod.rs +++ b/clash_lib/src/proxy/utils/test_utils/mod.rs @@ -87,7 +87,7 @@ pub async fn ping_pong_test(handler: Arc, port: u16) -> any .write_all(chunk.as_bytes()) .await .inspect_err(|x| { - tracing::error!("proxy_fn write error: {}", x); + tracing::error!("proxy_fn write error: {x:?}"); })?; } write_half.flush().await?; @@ -96,7 +96,7 @@ pub async fn ping_pong_test(handler: Arc, port: u16) -> any for _ in 0..100 { read_half.read_exact(&mut buf).await.inspect_err(|x| { - tracing::error!("proxy_fn read error: {}", x); + tracing::error!("proxy_fn read error: {x:?}"); })?; assert_eq!(buf, "world".as_bytes().to_owned()); } diff --git a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs index 982b040ce..1e97f6dc3 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs @@ -167,18 +167,19 @@ where } SECURITY_CHACHA20_POLY1305 => { let mut key = [0u8; 32]; - let tmp = utils::md5(&req_body_key); - key.copy_from_slice(&tmp); + key[..16].copy_from_slice(&utils::md5(&req_body_key)); let tmp = utils::md5(&key[..16]); key[16..].copy_from_slice(&tmp); + let write_cipher = VmessSecurity::ChaCha20Poly1305(ChaCha20Poly1305::new_with_slice(&key)); let write_cipher = AeadCipher::new(&req_body_iv, write_cipher); - let tmp = utils::md5(&req_body_key); - key.copy_from_slice(&tmp); + let mut key = [0u8; 32]; + key[..16].copy_from_slice(&utils::md5(&resp_body_key)); let tmp = utils::md5(&key[..16]); key[16..].copy_from_slice(&tmp); + let reader_cipher = VmessSecurity::ChaCha20Poly1305(ChaCha20Poly1305::new_with_slice(&key)); let read_cipher = AeadCipher::new(&resp_body_iv, reader_cipher); diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100644 index d543ef3d9..000000000 --- a/scripts/build.sh +++ /dev/null @@ -1,172 +0,0 @@ -#!/bin/sh - -set -xe - -[ ! -d "target/artifacts" ] && mkdir -p target/artifacts - -os=`uname` -case $os in - Linux) - sudo apt update - sudo apt install -y gcc-multilib gcc make musl-dev musl-tools - ;; -esac - -llvm_version=16 - -install_llvm() { - status=$(command -v -- "clang-$llvm_version" > /dev/null 2>&1; echo $?) - if [ $status -ne 0 ]; then - wget https://apt.llvm.org/llvm.sh -O /tmp/llvm.sh - chmod +x /tmp/llvm.sh - sudo /tmp/llvm.sh $llvm_version - fi -} - -ROOT_DIR=`git rev-parse --show-toplevel` - - -for TARGET in $1; do - TARGET=`echo "$TARGET" | tr -d '[:space:]' | tr -d '\n' | tr -d '\r'` - echo "building for $TARGET(static: $2)" - rustup target add $TARGET - - case $TARGET in - x86_64-unknown-linux-musl) - install_llvm - export CC=clang-$llvm_version - export CXX=clang++-$llvm_version - export LDFLAGS="-fuse-ld=lld" - export CMAKE_TOOLCHAIN_FILE=$ROOT_DIR/scripts/cmake/x86_64-musl.cmake - ;; - aarch64-unknown-linux-gnu) - sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu libc6-dev-arm64-cross - export CC=aarch64-linux-gnu-gcc - export CXX=aarch64-linux-gnu-g++ - export BINDGEN_EXTRA_CLANG_ARGS="--sysroot=/usr/aarch64-linux-gnu" - ;; - aarch64-unknown-linux-musl) - sudo apt install -y libc6-dev-arm64-cross - install_llvm - export CC=clang-$llvm_version - export CXX=clang++-$llvm_version - export LDFLAGS="-fuse-ld=lld --sysroot=/usr/aarch64-linux-gnu" - export BINDGEN_EXTRA_CLANG_ARGS="--sysroot=/usr/aarch64-linux-gnu" - export CMAKE_TOOLCHAIN_FILE=$ROOT_DIR/scripts/cmake/aarch64-musl.cmake - ;; - arm-unknown-linux-gnueabi | armv7-unknown-linux-gnueabi) - sudo apt install -y gcc-arm-linux-gnueabi g++-arm-linux-gnueabi binutils-arm-linux-gnueabi libc6-dev-armel-cross - export CC=arm-linux-gnueabi-gcc - export CXX=arm-linux-gnueabi-g++ - ;; - arm-unknown-linux-gnueabihf | armv7-unknown-linux-gnueabihf) - sudo apt install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf libc6-dev-armhf-cross - export CC=arm-linux-gnueabihf-gcc - export CXX=arm-linux-gnueabihf-g++ - ;; - arm-unknown-linux-musleabi) - sudo apt install -y libc6-dev-armel-cross - install_llvm - export CC=clang-$llvm_version - export CXX=clang++-$llvm_version - export LDFLAGS="-fuse-ld=lld --sysroot=/usr/arm-linux-gnueabi" - export CMAKE_TOOLCHAIN_FILE=$ROOT_DIR/scripts/cmake/arm-musl.cmake - ;; - arm-unknown-linux-musleabihf) - sudo apt install -y libc6-dev-armhf-cross - install_llvm - export CC=clang-$llvm_version - export CXX=clang++-$llvm_version - export LDFLAGS="-fuse-ld=lld --sysroot=/usr/arm-linux-gnueabihf" - export CMAKE_TOOLCHAIN_FILE=$ROOT_DIR/scripts/cmake/armhf-musl.cmake - ;; - armv7-unknown-linux-musleabi) - sudo apt install -y libc6-dev-armel-cross - install_llvm - export CC=clang-$llvm_version - export CXX=clang++-$llvm_version - export LDFLAGS="-fuse-ld=lld --sysroot=/usr/arm-linux-gnueabi" - export CMAKE_TOOLCHAIN_FILE=$ROOT_DIR/scripts/cmake/armv7-musl.cmake - ;; - armv7-unknown-linux-musleabihf) - sudo apt install -y libc6-dev-armhf-cross - install_llvm - export CC=clang-$llvm_version - export CXX=clang++-$llvm_version - export LDFLAGS="-fuse-ld=lld --sysroot=/usr/arm-linux-gnueabihf" - export CMAKE_TOOLCHAIN_FILE=$ROOT_DIR/scripts/cmake/armv7hf-musl.cmake - ;; - i686-unknown-linux-gnu) - sudo apt install -y libc6-dev-i386 - ;; - mips-unknown-linux-gnu) - sudo apt install -y gcc-mips-linux-gnu g++-mips-linux-gnu binutils-mips-linux-gnu libc6-dev-mips-cross - export CC=mips-linux-gnu-gcc - export CXX=mips-linux-gnu-g++ - ;; - mipsel-unknown-linux-gnu) - sudo apt install -y gcc-mipsel-linux-gnu g++-mipsel-linux-gnu binutils-mipsel-linux-gnu libc6-dev-mipsel-cross - export CC=mipsel-linux-gnu-gcc - export CXX=mipsel-linux-gnu-g++ - ;; - mips64-unknown-linux-gnuabi64) - sudo apt install -y gcc-mips64-linux-gnuabi64 g++-mips64-linux-gnuabi64 binutils-mips64-linux-gnuabi64 libc6-dev-mips64-cross - export CC=mips64-linux-gnuabi64-gcc - export CXX=mips64-linux-gnuabi64-g++ - ;; - mips64el-unknown-linux-gnuabi64) - sudo apt install -y gcc-mips64el-linux-gnuabi64 g++-mips64el-linux-gnuabi64 binutils-mips64el-linux-gnuabi64 libc6-dev-mips64el-cross - export CC=mips64el-linux-gnuabi64-gcc - export CXX=mips64el-linux-gnuabi64-g++ - ;; - powerpc-unknown-linux-gnu) - sudo apt install -y gcc-powerpc-linux-gnu g++-powerpc-linux-gnu binutils-powerpc-linux-gnu libc6-dev-powerpc-cross - export CC=powerpc-linux-gnu-gcc - export CXX=powerpc-linux-gnu-g++ - ;; - powerpc64-unknown-linux-gnu) - sudo apt install -y gcc-powerpc64-linux-gnu g++-powerpc64-linux-gnu binutils-powerpc64-linux-gnu libc6-dev-powerpc64-cross - export CC=powerpc64-linux-gnu-gcc - export CXX=powerpc64-linux-gnu-g++ - ;; - powerpc64le-unknown-linux-gnu) - sudo apt install -y gcc-powerpc64le-linux-gnu g++-powerpc64le-linux-gnu binutils-powerpc64le-linux-gnu libc6-dev-powerpc64le-cross - export CC=powerpc64le-linux-gnu-gcc - export CXX=powerpc64le-linux-gnu-g++ - ;; - s390x-unknown-linux-gnu) - sudo apt install -y gcc-s390x-linux-gnu g++-s390x-linux-gnu binutils-s390x-linux-gnu libc6-dev-s390x-cross - export CC=s390x-linux-gnu-gcc - export CXX=s390x-linux-gnu-g++ - ;; - riscv64gc-unknown-linux-gnu) - sudo apt install -y gcc-riscv64-linux-gnu g++-riscv64-linux-gnu binutils-riscv64-linux-gnu libc6-dev-riscv64-cross - export CC=riscv64-linux-gnu-gcc - export CXX=riscv64-linux-gnu-g++ - ;; - esac - - case $TARGET in - *musl*) - if [ "$2" = "true" ]; then - export RUSTFLAGS="-Clinker=rust-lld -Clink-self-contained=yes -Ctarget-feature=+crt-static" - else - export RUSTFLAGS="-Clinker=rust-lld" - fi - ;; - *) - if [ "$2" = "true" ]; then - export RUSTFLAGS="-Ctarget-feature=+crt-static" - fi - ;; - esac - - OUTPUT_BIN=./target/artifacts/clash-$TARGET - if [ "$2" = "true" ]; then - OUTPUT_BIN=$OUTPUT_BIN-static-crt - fi - - cargo build -p clash --target $TARGET --release - ls -l ./target/$TARGET/release/ - mv ./target/$TARGET/release/clash $OUTPUT_BIN -done diff --git a/scripts/cmake/aarch64-musl.cmake b/scripts/cmake/aarch64-musl.cmake deleted file mode 100644 index 7f363ed53..000000000 --- a/scripts/cmake/aarch64-musl.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR aarch64) -set(CMAKE_LINKER ld.ldd) \ No newline at end of file diff --git a/scripts/cmake/arm-musl.cmake b/scripts/cmake/arm-musl.cmake deleted file mode 100644 index 5d825ca5f..000000000 --- a/scripts/cmake/arm-musl.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR arm) -set(CMAKE_LINKER ld.ldd) \ No newline at end of file diff --git a/scripts/cmake/armhf-musl.cmake b/scripts/cmake/armhf-musl.cmake deleted file mode 100644 index c11e52db3..000000000 --- a/scripts/cmake/armhf-musl.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR armhf) -set(CMAKE_LINKER ld.ldd) \ No newline at end of file diff --git a/scripts/cmake/armv7-musl.cmake b/scripts/cmake/armv7-musl.cmake deleted file mode 100644 index 08da48447..000000000 --- a/scripts/cmake/armv7-musl.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR armv7) -set(CMAKE_LINKER ld.ldd) \ No newline at end of file diff --git a/scripts/cmake/armv7hf-musl.cmake b/scripts/cmake/armv7hf-musl.cmake deleted file mode 100644 index 664af8d59..000000000 --- a/scripts/cmake/armv7hf-musl.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR armv7hf) -set(CMAKE_LINKER ld.ldd) \ No newline at end of file diff --git a/scripts/cmake/x86_64-musl.cmake b/scripts/cmake/x86_64-musl.cmake deleted file mode 100644 index 9eee6d80f..000000000 --- a/scripts/cmake/x86_64-musl.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR x86_64) -set(CMAKE_LINKER ld.ldd) \ No newline at end of file From 7b37493fc554d408dff550b1e54c887a97e72ae3 Mon Sep 17 00:00:00 2001 From: dev0 Date: Sat, 13 Apr 2024 00:23:41 +1000 Subject: [PATCH 16/16] bump 0.1.16 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6bb4f26d..d926e4ab6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -974,7 +974,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clash" -version = "0.1.15" +version = "0.1.16" dependencies = [ "clap", "clash_lib", @@ -982,14 +982,14 @@ dependencies = [ [[package]] name = "clash_doc" -version = "0.1.15" +version = "0.1.16" dependencies = [ "clash_lib", ] [[package]] name = "clash_lib" -version = "0.1.15" +version = "0.1.16" dependencies = [ "aead", "aes", diff --git a/Cargo.toml b/Cargo.toml index d8a2a56dd..001cd80b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ [workspace.package] -version = "0.1.15" +version = "0.1.16" repository = "https://github.com/Watfaq/clash-rs.git" edition = "2021"