From b2cc38ee63929ac279ce3309b7f11917b40e0f61 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Tue, 7 Apr 2026 10:27:33 +0200 Subject: [PATCH 01/24] chore(clippy): disallow some methods from itertools (#2075) --- easytier/.clippy.toml | 11 +++++++++++ easytier/src/connector/dns_connector.rs | 3 +-- easytier/src/peers/peer_ospf_route.rs | 3 +-- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 easytier/.clippy.toml diff --git a/easytier/.clippy.toml b/easytier/.clippy.toml new file mode 100644 index 00000000..9ee46783 --- /dev/null +++ b/easytier/.clippy.toml @@ -0,0 +1,11 @@ +disallowed-methods = [ + { path = "itertools::Itertools::map_into", reason = "Blocks underlying iterator optimizations. Use the native `.map(Into::into)` instead." }, + { path = "itertools::Itertools::map_ok", reason = "Blocks underlying iterator optimizations. Use the native `.map(|r| r.map(f))` instead." }, + { path = "itertools::Itertools::filter_ok", reason = "Blocks underlying iterator optimizations. Use a native approach, e.g., `.filter(|r| r.as_ref().map_or(true, condition))`." }, + { path = "itertools::Itertools::filter_map_ok", reason = "Blocks underlying iterator optimizations. Use native `.map()` and `.flatten()`, or extract logic into a standard `.filter_map()`." }, + + { path = "itertools::Itertools::collect_vec", reason = "Non-standard idiom. Directly use the standard library's `.collect::>()`." }, + { path = "itertools::Itertools::try_collect", reason = "Non-standard idiom. Standard `collect()` already supports Result/Option inversion; use `.collect::>()`." }, + { path = "itertools::Itertools::set_from", reason = "Non-standard idiom. Directly use the `.extend()` method provided by the standard library's `Extend` trait." }, + { path = "itertools::Itertools::concat", reason = "Non-standard idiom. Use native `.flatten().collect()` or a slice's `.concat()` instead." } +] \ No newline at end of file diff --git a/easytier/src/connector/dns_connector.rs b/easytier/src/connector/dns_connector.rs index 813d5f36..f264a7d7 100644 --- a/easytier/src/connector/dns_connector.rs +++ b/easytier/src/connector/dns_connector.rs @@ -14,7 +14,6 @@ use crate::{ use anyhow::Context; use dashmap::DashSet; use hickory_resolver::proto::rr::rdata::SRV; -use itertools::Itertools; use rand::{seq::SliceRandom, Rng as _}; use strum::VariantArray; @@ -117,7 +116,7 @@ impl DnsTunnelConnector { let srv_domains = IpScheme::VARIANTS .iter() .map(|s| (s, format!("_easytier._{}.{}", s, domain_name))) - .collect_vec(); + .collect::>(); tracing::info!("build srv_domains: {:?}", srv_domains); let responses = Arc::new(DashSet::new()); let srv_lookup_tasks = srv_domains diff --git a/easytier/src/peers/peer_ospf_route.rs b/easytier/src/peers/peer_ospf_route.rs index f346d475..0a99ca29 100644 --- a/easytier/src/peers/peer_ospf_route.rs +++ b/easytier/src/peers/peer_ospf_route.rs @@ -71,7 +71,6 @@ use super::{ }; use atomic_shim::AtomicU64; -use itertools::Itertools; static SERVICE_ID: u32 = 7; static UPDATE_PEER_INFO_PERIOD: Duration = Duration::from_secs(3600); @@ -1327,7 +1326,7 @@ impl RouteTable { .into_iter() .flat_map(|info| &info.proxy_cidrs) .filter_map(|cidr| cidr.parse::().ok()) - .collect_vec(); + .collect::>(); // build next hop map let (graph, start_node) = From 371b4b70a3bc3113791347704942ee2cb7a2ab03 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Tue, 7 Apr 2026 18:06:48 +0200 Subject: [PATCH 02/24] proto(utils): add TransientDigest trait (#2071) --- easytier/src/proto/mod.rs | 1 + easytier/src/proto/utils.rs | 20 ++++++++++++++++++++ easytier/src/utils.rs | 3 ++- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 easytier/src/proto/utils.rs diff --git a/easytier/src/proto/mod.rs b/easytier/src/proto/mod.rs index bffca9b0..cb455a89 100644 --- a/easytier/src/proto/mod.rs +++ b/easytier/src/proto/mod.rs @@ -12,6 +12,7 @@ pub mod web; #[cfg(test)] pub mod tests; +pub mod utils; const DESCRIPTOR_POOL_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/file_descriptor_set.bin")); diff --git a/easytier/src/proto/utils.rs b/easytier/src/proto/utils.rs new file mode 100644 index 00000000..c75e57c2 --- /dev/null +++ b/easytier/src/proto/utils.rs @@ -0,0 +1,20 @@ +use prost::Message; +use sha2::{Digest, Sha256}; + +/// Generates a stable digest strictly within the lifecycle of the current process. +/// +/// ⚠️ WARNING: +/// - This digest is ONLY guaranteed to be deterministic within a **single process and the exact same binary build**. +pub trait TransientDigest: Message { + fn digest(&self) -> [u8; 32] + where + Self: Sized, + { + let buf = self.encode_to_vec(); + let mut hasher = Sha256::new(); + hasher.update(buf); + hasher.finalize().into() + } +} + +impl TransientDigest for S {} diff --git a/easytier/src/utils.rs b/easytier/src/utils.rs index 9612be46..5d3fdd7d 100644 --- a/easytier/src/utils.rs +++ b/easytier/src/utils.rs @@ -1,5 +1,6 @@ use crate::common::log; use indoc::formatdoc; +use std::sync::Arc; use std::{fs::OpenOptions, str::FromStr}; pub type PeerRoutePair = crate::proto::api::instance::PeerRoutePair; @@ -136,7 +137,7 @@ pub fn find_free_tcp_port(mut range: std::ops::Range) -> Option { range.find(|&port| check_tcp_available(port)) } -pub fn weak_upgrade(weak: &std::sync::Weak) -> anyhow::Result> { +pub fn weak_upgrade(weak: &std::sync::Weak) -> anyhow::Result> { weak.upgrade() .ok_or_else(|| anyhow::anyhow!("{} not available", std::any::type_name::())) } From 26b179472340cc78300a65a096d85ca7134565dd Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Wed, 8 Apr 2026 02:43:03 +0200 Subject: [PATCH 03/24] ci: accecelerate pipeline (#2078) * enable concurrency pr * do not run build on draft PRs pr * enable fail-fast for build workflows --- .github/workflows/core.yml | 9 +++++++-- .github/workflows/gui.yml | 11 ++++++++--- .github/workflows/mobile.yml | 11 ++++++++--- .github/workflows/nix.yml | 6 ++++++ .github/workflows/ohos.yml | 8 +++++++- .github/workflows/test.yml | 4 ++++ tauri-plugin-vpnservice/.github/workflows/audit.yml | 2 +- tauri-plugin-vpnservice/.github/workflows/clippy.yml | 2 +- tauri-plugin-vpnservice/.github/workflows/test.yml | 2 +- 9 files changed, 43 insertions(+), 12 deletions(-) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 377ff767..8402d490 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -5,6 +5,11 @@ on: branches: ["develop", "main", "releases/**"] pull_request: branches: ["develop", "main"] + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true env: CARGO_TERM_COLOR: always @@ -21,7 +26,7 @@ jobs: # Map a step output to a job output outputs: # do not skip push on branch starts with releases/ - should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} + should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 @@ -51,7 +56,7 @@ jobs: easytier-web/frontend/dist/* build: strategy: - fail-fast: false + fail-fast: true matrix: include: - TARGET: aarch64-unknown-linux-musl diff --git a/.github/workflows/gui.yml b/.github/workflows/gui.yml index afa7a1e3..994c8981 100644 --- a/.github/workflows/gui.yml +++ b/.github/workflows/gui.yml @@ -5,7 +5,12 @@ on: branches: ["develop", "main", "releases/**"] pull_request: branches: ["develop", "main"] - + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always @@ -20,7 +25,7 @@ jobs: runs-on: ubuntu-latest # Map a step output to a job output outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} + should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 @@ -32,7 +37,7 @@ jobs: paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", ".github/workflows/gui.yml", ".github/workflows/install_rust.sh", ".github/workflows/install_gui_dep.sh", "easytier-web/frontend-lib/**"]' build-gui: strategy: - fail-fast: false + fail-fast: true matrix: include: - TARGET: aarch64-unknown-linux-musl diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml index f44ad550..74df2452 100644 --- a/.github/workflows/mobile.yml +++ b/.github/workflows/mobile.yml @@ -5,7 +5,12 @@ on: branches: ["develop", "main", "releases/**"] pull_request: branches: ["develop", "main"] - + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always @@ -20,7 +25,7 @@ jobs: runs-on: ubuntu-latest # Map a step output to a job output outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} + should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 @@ -32,7 +37,7 @@ jobs: paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", "tauri-plugin-vpnservice/**", ".github/workflows/mobile.yml", ".github/workflows/install_rust.sh"]' build-mobile: strategy: - fail-fast: false + fail-fast: true matrix: include: - TARGET: android diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 3182ce07..4590f6d7 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -8,12 +8,18 @@ on: - "flake.lock" pull_request: branches: ["main", "develop"] + types: [opened, synchronize, reopened, ready_for_review] paths: - "**/*.nix" - "flake.lock" +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: check-full-shell: + if: github.event_name != 'pull_request' || !github.event.pull_request.draft runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/ohos.yml b/.github/workflows/ohos.yml index 2febe3fb..292a9f79 100644 --- a/.github/workflows/ohos.yml +++ b/.github/workflows/ohos.yml @@ -8,8 +8,13 @@ on: - '!*-pre' pull_request: branches: ["develop", "main"] + types: [opened, synchronize, reopened, ready_for_review] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always @@ -20,6 +25,7 @@ defaults: jobs: cargo_fmt_check: + if: github.event_name != 'pull_request' || !github.event.pull_request.draft runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -35,7 +41,7 @@ jobs: # Map a step output to a job output outputs: # do not skip push on branch starts with releases/ - should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} + should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 72dad752..01d9d37d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ "develop", "main" ] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always # RUSTC_WRAPPER: "sccache" diff --git a/tauri-plugin-vpnservice/.github/workflows/audit.yml b/tauri-plugin-vpnservice/.github/workflows/audit.yml index f353a1ef..6b92c916 100644 --- a/tauri-plugin-vpnservice/.github/workflows/audit.yml +++ b/tauri-plugin-vpnservice/.github/workflows/audit.yml @@ -19,7 +19,7 @@ on: - "**/Cargo.toml" concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: diff --git a/tauri-plugin-vpnservice/.github/workflows/clippy.yml b/tauri-plugin-vpnservice/.github/workflows/clippy.yml index 6f67af43..264bb67d 100644 --- a/tauri-plugin-vpnservice/.github/workflows/clippy.yml +++ b/tauri-plugin-vpnservice/.github/workflows/clippy.yml @@ -17,7 +17,7 @@ on: - "**/Cargo.toml" concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: diff --git a/tauri-plugin-vpnservice/.github/workflows/test.yml b/tauri-plugin-vpnservice/.github/workflows/test.yml index cafd6575..821b3e28 100644 --- a/tauri-plugin-vpnservice/.github/workflows/test.yml +++ b/tauri-plugin-vpnservice/.github/workflows/test.yml @@ -9,7 +9,7 @@ on: - main concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: From c5fbd29c0e018f874c27530c887152ab43ef9a7d Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Thu, 9 Apr 2026 03:45:04 +0200 Subject: [PATCH 04/24] ci: fix skip condition for draft pull requests in CI workflows (#2088) * ci: run xxx-result only when pre_job is run successfully * fix get-result steps --- .github/workflows/core.yml | 19 +++++++------------ .github/workflows/gui.yml | 11 +++++------ .github/workflows/mobile.yml | 11 +++++------ .github/workflows/ohos.yml | 3 ++- .github/workflows/test.yml | 6 +++--- 5 files changed, 22 insertions(+), 28 deletions(-) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 8402d490..f2df8fb5 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -23,10 +23,11 @@ jobs: pre_job: # continue-on-error: true # Uncomment once integration is finished runs-on: ubuntu-latest + if: github.event_name != 'pull_request' || !github.event.pull_request.draft # Map a step output to a job output outputs: # do not skip push on branch starts with releases/ - should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} + should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 @@ -279,24 +280,18 @@ jobs: ./artifacts/* core-result: - if: needs.pre_job.outputs.should_skip != 'true' && always() runs-on: ubuntu-latest - needs: - - pre_job - - build_web - - build + needs: [ pre_job, build_web, build ] + if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() steps: - name: Mark result as failed - if: needs.build.result != 'success' + if: contains(needs.*.result, 'failure') run: exit 1 magisk_build: - needs: - - pre_job - - build_web - - build - if: needs.pre_job.outputs.should_skip != 'true' && always() runs-on: ubuntu-latest + needs: [ pre_job, build_web, build ] + if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() steps: - name: Checkout Code uses: actions/checkout@v5 # 必须先检出代码才能获取模块配置 diff --git a/.github/workflows/gui.yml b/.github/workflows/gui.yml index 994c8981..77c75496 100644 --- a/.github/workflows/gui.yml +++ b/.github/workflows/gui.yml @@ -23,9 +23,10 @@ jobs: pre_job: # continue-on-error: true # Uncomment once integration is finished runs-on: ubuntu-latest + if: github.event_name != 'pull_request' || !github.event.pull_request.draft # Map a step output to a job output outputs: - should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} + should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 @@ -206,12 +207,10 @@ jobs: ./artifacts/* gui-result: - if: needs.pre_job.outputs.should_skip != 'true' && always() runs-on: ubuntu-latest - needs: - - pre_job - - build-gui + needs: [ pre_job, build-gui ] + if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() steps: - name: Mark result as failed - if: needs.build-gui.result != 'success' + if: contains(needs.*.result, 'failure') run: exit 1 diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml index 74df2452..4276f404 100644 --- a/.github/workflows/mobile.yml +++ b/.github/workflows/mobile.yml @@ -23,9 +23,10 @@ jobs: pre_job: # continue-on-error: true # Uncomment once integration is finished runs-on: ubuntu-latest + if: github.event_name != 'pull_request' || !github.event.pull_request.draft # Map a step output to a job output outputs: - should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} + should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 @@ -125,12 +126,10 @@ jobs: ./artifacts/* mobile-result: - if: needs.pre_job.outputs.should_skip != 'true' && always() runs-on: ubuntu-latest - needs: - - pre_job - - build-mobile + needs: [ pre_job, build-mobile ] + if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() steps: - name: Mark result as failed - if: needs.build-mobile.result != 'success' + if: contains(needs.*.result, 'failure') run: exit 1 diff --git a/.github/workflows/ohos.yml b/.github/workflows/ohos.yml index 292a9f79..39371112 100644 --- a/.github/workflows/ohos.yml +++ b/.github/workflows/ohos.yml @@ -38,10 +38,11 @@ jobs: pre_job: # continue-on-error: true # Uncomment once integration is finished runs-on: ubuntu-latest + if: github.event_name != 'pull_request' || !github.event.pull_request.draft # Map a step output to a job output outputs: # do not skip push on branch starts with releases/ - should_skip: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) || (steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/')) }} + should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 01d9d37d..5f624d4f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -150,9 +150,9 @@ jobs: test: runs-on: ubuntu-latest - needs: [ pre_job, test_matrix ] - if: needs.pre_job.outputs.should_skip != 'true' && always() + needs: [ pre_job, check, test_matrix ] + if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() steps: - name: Mark result as failed - if: needs.test_matrix.result != 'success' + if: contains(needs.*.result, 'failure') run: exit 1 From a8feb9ac2b7da301fa3a467a67dedabf8cb469ed Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Thu, 9 Apr 2026 03:45:55 +0200 Subject: [PATCH 05/24] chore: use Debug to print errors (#2086) --- easytier/src/core.rs | 10 +++++----- easytier/src/gateway/tcp_proxy.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/easytier/src/core.rs b/easytier/src/core.rs index f3453e7e..4f01f805 100644 --- a/easytier/src/core.rs +++ b/easytier/src/core.rs @@ -1185,9 +1185,9 @@ fn win_service_event_loop( status_handle.set_service_status(normal_status).unwrap(); std::process::exit(0); } - Err(e) => { + Err(error) => { status_handle.set_service_status(error_status).unwrap(); - log::error!("{}", e); + log::error!(?error); } } }, @@ -1501,8 +1501,8 @@ pub async fn main() -> ExitCode { // Verify configurations if cli.check_config { - if let Err(e) = validate_config(&cli).await { - log::error!("Config validation failed: {:?}", e); + if let Err(error) = validate_config(&cli).await { + log::error!(?error, "Config validation failed"); return ExitCode::FAILURE; } else { return ExitCode::SUCCESS; @@ -1512,7 +1512,7 @@ pub async fn main() -> ExitCode { let mut ret_code = 0; if let Err(error) = run_main(cli).await { - log::error!(%error); + log::error!(?error); ret_code = 1; } diff --git a/easytier/src/gateway/tcp_proxy.rs b/easytier/src/gateway/tcp_proxy.rs index 74c9ed2a..b4095c19 100644 --- a/easytier/src/gateway/tcp_proxy.rs +++ b/easytier/src/gateway/tcp_proxy.rs @@ -67,7 +67,7 @@ impl NatDstConnector for NatDstTcpConnector { let socket = match TcpSocket::new_v4() { Ok(s) => s, Err(error) => { - log::error!(%error, "create v4 socket failed"); + log::error!(?error, "create v4 socket failed"); return Err(error.into()); } }; From a879dd1b14e4e8b34a23a7875630635cb4911a3f Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Thu, 9 Apr 2026 18:22:12 +0200 Subject: [PATCH 06/24] chore: update Rust to 2024 edition (#2066) --- Cargo.toml | 4 + .../easytier-android-jni/Cargo.toml | 2 +- .../easytier-android-jni/src/lib.rs | 64 +++---- easytier-contrib/easytier-ffi/Cargo.toml | 2 +- easytier-contrib/easytier-ffi/src/lib.rs | 14 +- easytier-contrib/easytier-uptime/Cargo.toml | 2 +- .../easytier-uptime/src/api/handlers.rs | 32 ++-- .../easytier-uptime/src/api/routes.rs | 2 +- .../easytier-uptime/src/db/cleanup.rs | 4 +- .../easytier-uptime/src/db/mod.rs | 6 +- .../easytier-uptime/src/db/operations.rs | 2 +- .../easytier-uptime/src/health_checker.rs | 2 +- .../src/health_checker_manager.rs | 4 +- easytier-contrib/easytier-uptime/src/main.rs | 6 +- easytier-gui/src-tauri/Cargo.toml | 2 +- easytier-gui/src-tauri/src/elevate/linux.rs | 2 +- easytier-gui/src-tauri/src/elevate/macos.rs | 4 +- easytier-gui/src-tauri/src/elevate/windows.rs | 4 +- easytier-gui/src-tauri/src/lib.rs | 68 +++---- easytier-rpc-build/Cargo.toml | 3 +- easytier-web/Cargo.toml | 2 +- easytier-web/src/client_manager/mod.rs | 8 +- easytier-web/src/client_manager/session.rs | 50 ++--- easytier-web/src/db/mod.rs | 8 +- easytier-web/src/main.rs | 2 +- easytier-web/src/restful/auth.rs | 23 +-- .../src/restful/captcha/base/captcha.rs | 2 +- .../src/restful/captcha/builder/spec.rs | 6 +- easytier-web/src/restful/mod.rs | 12 +- easytier-web/src/restful/network.rs | 4 +- easytier-web/src/restful/oidc.rs | 25 +-- easytier-web/src/restful/rpc.rs | 6 +- easytier-web/src/restful/users.rs | 6 +- easytier-web/src/web/mod.rs | 3 +- easytier/Cargo.toml | 4 +- easytier/build.rs | 4 +- easytier/src/arch/windows.rs | 8 +- easytier/src/common/acl_processor.rs | 38 ++-- easytier/src/common/compressor.rs | 2 +- easytier/src/common/config.rs | 129 ++++++------- easytier/src/common/dns.rs | 2 +- easytier/src/common/env_parser.rs | 41 ++-- easytier/src/common/global_ctx.rs | 4 +- easytier/src/common/ifcfg/darwin.rs | 2 +- easytier/src/common/ifcfg/netlink.rs | 12 +- easytier/src/common/ifcfg/win/luid.rs | 6 +- easytier/src/common/ifcfg/windows.rs | 10 +- easytier/src/common/log.rs | 4 +- easytier/src/common/mod.rs | 12 +- easytier/src/common/netns.rs | 2 +- easytier/src/common/stats_manager.rs | 24 ++- easytier/src/common/stun.rs | 14 +- easytier/src/common/stun_codec_ext.rs | 4 +- easytier/src/common/token_bucket.rs | 2 +- .../common/tracing_rolling_appender/base.rs | 19 +- .../common/tracing_rolling_appender/mod.rs | 22 +-- easytier/src/connector/direct.rs | 32 ++-- easytier/src/connector/dns_connector.rs | 4 +- easytier/src/connector/http_connector.rs | 4 +- easytier/src/connector/manual.rs | 2 +- easytier/src/connector/mod.rs | 4 +- easytier/src/connector/tcp_hole_punch.rs | 46 +++-- .../connector/udp_hole_punch/both_easy_sym.rs | 10 +- .../src/connector/udp_hole_punch/common.rs | 10 +- easytier/src/connector/udp_hole_punch/cone.rs | 8 +- easytier/src/connector/udp_hole_punch/mod.rs | 22 ++- .../connector/udp_hole_punch/sym_to_cone.rs | 27 ++- easytier/src/core.rs | 53 +++--- easytier/src/easytier-cli.rs | 28 +-- easytier/src/easytier-core.rs | 4 +- easytier/src/gateway/fast_socks5/mod.rs | 2 +- easytier/src/gateway/fast_socks5/server.rs | 6 +- .../gateway/fast_socks5/util/target_addr.rs | 4 +- easytier/src/gateway/icmp_proxy.rs | 12 +- easytier/src/gateway/ip_reassembler.rs | 18 +- easytier/src/gateway/kcp_proxy.rs | 4 +- easytier/src/gateway/quic_proxy.rs | 24 ++- easytier/src/gateway/socks5.rs | 49 +++-- easytier/src/gateway/tcp_proxy.rs | 20 +- .../gateway/tokio_smoltcp/channel_device.rs | 2 +- easytier/src/gateway/tokio_smoltcp/mod.rs | 2 +- easytier/src/gateway/tokio_smoltcp/reactor.rs | 10 +- easytier/src/gateway/tokio_smoltcp/socket.rs | 2 +- .../gateway/tokio_smoltcp/socket_allocator.rs | 3 +- easytier/src/gateway/udp_proxy.rs | 14 +- easytier/src/gateway/wrapped_proxy.rs | 6 +- easytier/src/instance/dns_server/server.rs | 2 +- .../instance/dns_server/server_instance.rs | 49 +++-- easytier/src/instance/instance.rs | 71 +++---- easytier/src/instance/listeners.rs | 6 +- easytier/src/instance/virtual_nic.rs | 14 +- easytier/src/instance_manager.rs | 100 +++++----- easytier/src/launcher.rs | 64 ++++--- easytier/src/peer_center/instance.rs | 16 +- easytier/src/peers/acl_filter.rs | 38 ++-- easytier/src/peers/credential_manager.rs | 29 +-- easytier/src/peers/encrypt/aes_gcm.rs | 2 +- easytier/src/peers/encrypt/ring.rs | 2 +- easytier/src/peers/encrypt/xor.rs | 2 +- easytier/src/peers/foreign_network_client.rs | 4 +- easytier/src/peers/foreign_network_manager.rs | 61 +++--- easytier/src/peers/peer.rs | 8 +- easytier/src/peers/peer_conn.rs | 53 +++--- easytier/src/peers/peer_conn_ping.rs | 10 +- easytier/src/peers/peer_manager.rs | 115 ++++++------ easytier/src/peers/peer_map.rs | 7 +- easytier/src/peers/peer_ospf_route.rs | 177 +++++++++++------- easytier/src/peers/peer_rpc.rs | 10 +- easytier/src/peers/peer_session.rs | 14 +- easytier/src/peers/peer_task.rs | 2 +- easytier/src/peers/relay_peer_map.rs | 20 +- easytier/src/peers/route_trait.rs | 2 +- easytier/src/peers/tests.rs | 40 ++-- easytier/src/peers/traffic_metrics.rs | 41 ++-- easytier/src/proto/api.rs | 25 +-- easytier/src/proto/common.rs | 25 ++- easytier/src/proto/rpc_impl/bidirect.rs | 4 +- easytier/src/proto/rpc_impl/client.rs | 4 +- easytier/src/proto/rpc_impl/mod.rs | 2 +- easytier/src/proto/rpc_impl/packet.rs | 2 +- easytier/src/proto/rpc_impl/server.rs | 9 +- easytier/src/proto/rpc_impl/standalone.rs | 4 +- easytier/src/proto/tests.rs | 2 +- easytier/src/rpc_service/api.rs | 2 +- easytier/src/rpc_service/instance_manage.rs | 21 +-- easytier/src/rpc_service/logger.rs | 10 +- easytier/src/rpc_service/mod.rs | 10 +- easytier/src/rpc_service/remote_client.rs | 31 ++- easytier/src/service_manager/mod.rs | 2 +- easytier/src/tests/credential_tests.rs | 6 +- easytier/src/tests/mod.rs | 8 + easytier/src/tests/three_node.rs | 20 +- easytier/src/tunnel/common.rs | 12 +- easytier/src/tunnel/fake_tcp/mod.rs | 6 +- .../tunnel/fake_tcp/netfilter/linux_bpf.rs | 18 +- .../tunnel/fake_tcp/netfilter/macos_bpf.rs | 2 +- .../src/tunnel/fake_tcp/netfilter/pnet.rs | 4 +- .../tunnel/fake_tcp/netfilter/windivert.rs | 2 +- easytier/src/tunnel/fake_tcp/stack.rs | 4 +- easytier/src/tunnel/filter.rs | 28 ++- easytier/src/tunnel/mpsc.rs | 8 +- easytier/src/tunnel/packet_def.rs | 2 +- easytier/src/tunnel/quic.rs | 8 +- easytier/src/tunnel/ring.rs | 8 +- easytier/src/tunnel/tcp.rs | 4 +- easytier/src/tunnel/udp.rs | 16 +- easytier/src/tunnel/unix.rs | 4 +- easytier/src/tunnel/websocket.rs | 27 ++- easytier/src/tunnel/wireguard.rs | 24 +-- easytier/src/utils.rs | 2 +- easytier/src/vpn_portal/wireguard.rs | 28 +-- easytier/src/web_client/mod.rs | 7 +- easytier/src/web_client/security.rs | 4 +- easytier/src/web_client/session.rs | 2 +- tauri-plugin-vpnservice/Cargo.toml | 3 +- tauri-plugin-vpnservice/src/error.rs | 2 +- tauri-plugin-vpnservice/src/lib.rs | 2 +- tauri-plugin-vpnservice/src/mobile.rs | 2 +- 158 files changed, 1327 insertions(+), 1231 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0768f4f7..59e3db80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,10 @@ exclude = [ "easytier-contrib/easytier-ohrs", # it needs ohrs sdk ] +[workspace.package] +edition = "2024" +rust-version = "1.93.0" + [profile.dev] panic = "unwind" debug = 2 diff --git a/easytier-contrib/easytier-android-jni/Cargo.toml b/easytier-contrib/easytier-android-jni/Cargo.toml index e2b9465a..5f069daa 100644 --- a/easytier-contrib/easytier-android-jni/Cargo.toml +++ b/easytier-contrib/easytier-android-jni/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "easytier-android-jni" version = "0.1.0" -edition = "2021" +edition.workspace = true [lib] crate-type = ["cdylib"] diff --git a/easytier-contrib/easytier-android-jni/src/lib.rs b/easytier-contrib/easytier-android-jni/src/lib.rs index f6ada298..a9f3731e 100644 --- a/easytier-contrib/easytier-android-jni/src/lib.rs +++ b/easytier-contrib/easytier-android-jni/src/lib.rs @@ -1,7 +1,7 @@ use easytier::proto::api::manage::{NetworkInstanceRunningInfo, NetworkInstanceRunningInfoMap}; +use jni::JNIEnv; use jni::objects::{JClass, JObjectArray, JString}; use jni::sys::{jint, jstring}; -use jni::JNIEnv; use once_cell::sync::Lazy; use std::ffi::{CStr, CString}; use std::ptr; @@ -15,7 +15,7 @@ pub struct KeyValuePair { } // 声明外部 C 函数 -extern "C" { +unsafe extern "C" { fn set_tun_fd(inst_name: *const std::ffi::c_char, fd: std::ffi::c_int) -> std::ffi::c_int; fn get_error_msg(out: *mut *const std::ffi::c_char); fn free_string(s: *const std::ffi::c_char); @@ -68,7 +68,7 @@ fn throw_exception(env: &mut JNIEnv, message: &str) { } /// 设置 TUN 文件描述符 -#[no_mangle] +#[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_setTunFd( mut env: JNIEnv, _class: JClass, @@ -87,17 +87,17 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_setTunFd( unsafe { let result = set_tun_fd(inst_name_cstr.as_ptr(), fd); - if result != 0 { - if let Some(error) = get_last_error() { - throw_exception(&mut env, &error); - } + if result != 0 + && let Some(error) = get_last_error() + { + throw_exception(&mut env, &error); } result } } /// 解析配置 -#[no_mangle] +#[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_parseConfig( mut env: JNIEnv, _class: JClass, @@ -115,17 +115,17 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_parseConfig( unsafe { let result = parse_config(config_cstr.as_ptr()); - if result != 0 { - if let Some(error) = get_last_error() { - throw_exception(&mut env, &error); - } + if result != 0 + && let Some(error) = get_last_error() + { + throw_exception(&mut env, &error); } result } } /// 运行网络实例 -#[no_mangle] +#[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_runNetworkInstance( mut env: JNIEnv, _class: JClass, @@ -143,17 +143,17 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_runNetworkInstance( unsafe { let result = run_network_instance(config_cstr.as_ptr()); - if result != 0 { - if let Some(error) = get_last_error() { - throw_exception(&mut env, &error); - } + if result != 0 + && let Some(error) = get_last_error() + { + throw_exception(&mut env, &error); } result } } /// 保持网络实例 -#[no_mangle] +#[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_retainNetworkInstance( mut env: JNIEnv, _class: JClass, @@ -165,10 +165,10 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_retainNetworkInstance( if instance_names.is_null() { unsafe { let result = retain_network_instance(ptr::null(), 0); - if result != 0 { - if let Some(error) = get_last_error() { - throw_exception(&mut env, &error); - } + if result != 0 + && let Some(error) = get_last_error() + { + throw_exception(&mut env, &error); } return result; } @@ -187,10 +187,10 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_retainNetworkInstance( if array_length == 0 { unsafe { let result = retain_network_instance(ptr::null(), 0); - if result != 0 { - if let Some(error) = get_last_error() { - throw_exception(&mut env, &error); - } + if result != 0 + && let Some(error) = get_last_error() + { + throw_exception(&mut env, &error); } return result; } @@ -234,17 +234,17 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_retainNetworkInstance( unsafe { let result = retain_network_instance(c_string_ptrs.as_ptr(), c_string_ptrs.len()); - if result != 0 { - if let Some(error) = get_last_error() { - throw_exception(&mut env, &error); - } + if result != 0 + && let Some(error) = get_last_error() + { + throw_exception(&mut env, &error); } result } } /// 收集网络信息 -#[no_mangle] +#[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_collectNetworkInfos( mut env: JNIEnv, _class: JClass, @@ -304,7 +304,7 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_collectNetworkInfos( } /// 获取最后的错误信息 -#[no_mangle] +#[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_getLastError( env: JNIEnv, _class: JClass, diff --git a/easytier-contrib/easytier-ffi/Cargo.toml b/easytier-contrib/easytier-ffi/Cargo.toml index fff8262a..52e66241 100644 --- a/easytier-contrib/easytier-ffi/Cargo.toml +++ b/easytier-contrib/easytier-ffi/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "easytier-ffi" version = "0.1.0" -edition = "2021" +edition.workspace = true [lib] crate-type = ["cdylib"] diff --git a/easytier-contrib/easytier-ffi/src/lib.rs b/easytier-contrib/easytier-ffi/src/lib.rs index 8686e534..e9b65be4 100644 --- a/easytier-contrib/easytier-ffi/src/lib.rs +++ b/easytier-contrib/easytier-ffi/src/lib.rs @@ -30,7 +30,7 @@ fn set_error_msg(msg: &str) { /// # Safety /// Set the tun fd -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn set_tun_fd( inst_name: *const std::ffi::c_char, fd: std::ffi::c_int, @@ -59,7 +59,7 @@ pub unsafe extern "C" fn set_tun_fd( /// # Safety /// Get the last error message -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn get_error_msg(out: *mut *const std::ffi::c_char) { let msg_buf = ERROR_MSG.lock().unwrap(); if msg_buf.is_empty() { @@ -74,7 +74,7 @@ pub unsafe extern "C" fn get_error_msg(out: *mut *const std::ffi::c_char) { } } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn free_string(s: *const std::ffi::c_char) { if s.is_null() { return; @@ -86,7 +86,7 @@ pub extern "C" fn free_string(s: *const std::ffi::c_char) { /// # Safety /// Parse the config -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn parse_config(cfg_str: *const std::ffi::c_char) -> std::ffi::c_int { let cfg_str = unsafe { assert!(!cfg_str.is_null()); @@ -105,7 +105,7 @@ pub unsafe extern "C" fn parse_config(cfg_str: *const std::ffi::c_char) -> std:: /// # Safety /// Run the network instance -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn run_network_instance(cfg_str: *const std::ffi::c_char) -> std::ffi::c_int { let cfg_str = unsafe { assert!(!cfg_str.is_null()); @@ -144,7 +144,7 @@ pub unsafe extern "C" fn run_network_instance(cfg_str: *const std::ffi::c_char) /// # Safety /// Retain the network instance -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn retain_network_instance( inst_names: *const *const std::ffi::c_char, length: usize, @@ -188,7 +188,7 @@ pub unsafe extern "C" fn retain_network_instance( /// # Safety /// Collect the network infos -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn collect_network_infos( infos: *mut KeyValuePair, max_length: usize, diff --git a/easytier-contrib/easytier-uptime/Cargo.toml b/easytier-contrib/easytier-uptime/Cargo.toml index e36e0018..9643e92f 100644 --- a/easytier-contrib/easytier-uptime/Cargo.toml +++ b/easytier-contrib/easytier-uptime/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "easytier-uptime" version = "0.1.0" -edition = "2021" +edition.workspace = true [dependencies] tokio = { version = "1.0", features = ["full"] } diff --git a/easytier-contrib/easytier-uptime/src/api/handlers.rs b/easytier-contrib/easytier-uptime/src/api/handlers.rs index 6c266611..850e09d6 100644 --- a/easytier-contrib/easytier-uptime/src/api/handlers.rs +++ b/easytier-contrib/easytier-uptime/src/api/handlers.rs @@ -1,7 +1,7 @@ use std::ops::{Div, Mul}; -use axum::extract::{Path, State}; use axum::Json; +use axum::extract::{Path, State}; use sea_orm::{ ColumnTrait, Condition, EntityTrait, IntoActiveModel, ModelTrait, Order, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, Set, TryIntoModel, @@ -14,7 +14,7 @@ use crate::api::{ models::*, }; use crate::db::entity::{self, health_records, shared_nodes}; -use crate::db::{operations::*, Db}; +use crate::db::{Db, operations::*}; use crate::health_checker_manager::HealthCheckerManager; use axum_extra::extract::Query; use std::sync::Arc; @@ -273,7 +273,7 @@ pub struct InstanceFilterParams { use crate::config::AppConfig; use axum::http::{HeaderMap, StatusCode}; use chrono::{Duration, Utc}; -use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; +use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, decode, encode}; use serde::Serialize; #[derive(Debug, Serialize, Deserialize)] @@ -370,19 +370,19 @@ pub async fn admin_get_nodes( let ids = NodeOperations::filter_node_ids_by_tag(&app_state.db, &tag).await?; filtered_ids = Some(ids); } - if let Some(tags) = filters.tags { - if !tags.is_empty() { - let ids_any = NodeOperations::filter_node_ids_by_tags_any(&app_state.db, &tags).await?; - filtered_ids = match filtered_ids { - Some(mut existing) => { - existing.extend(ids_any); - existing.sort(); - existing.dedup(); - Some(existing) - } - None => Some(ids_any), - }; - } + if let Some(tags) = filters.tags + && !tags.is_empty() + { + let ids_any = NodeOperations::filter_node_ids_by_tags_any(&app_state.db, &tags).await?; + filtered_ids = match filtered_ids { + Some(mut existing) => { + existing.extend(ids_any); + existing.sort(); + existing.dedup(); + Some(existing) + } + None => Some(ids_any), + }; } if let Some(ids) = filtered_ids { if ids.is_empty() { diff --git a/easytier-contrib/easytier-uptime/src/api/routes.rs b/easytier-contrib/easytier-uptime/src/api/routes.rs index d7c49a93..a1a6f510 100644 --- a/easytier-contrib/easytier-uptime/src/api/routes.rs +++ b/easytier-contrib/easytier-uptime/src/api/routes.rs @@ -1,5 +1,5 @@ -use axum::routing::{delete, get, post, put}; use axum::Router; +use axum::routing::{delete, get, post, put}; use tower_http::compression::CompressionLayer; use tower_http::cors::CorsLayer; diff --git a/easytier-contrib/easytier-uptime/src/db/cleanup.rs b/easytier-contrib/easytier-uptime/src/db/cleanup.rs index 0645b1fe..14638c67 100644 --- a/easytier-contrib/easytier-uptime/src/db/cleanup.rs +++ b/easytier-contrib/easytier-uptime/src/db/cleanup.rs @@ -1,7 +1,7 @@ -use crate::db::entity::*; use crate::db::Db; +use crate::db::entity::*; use sea_orm::*; -use tokio::time::{sleep, Duration}; +use tokio::time::{Duration, sleep}; use tracing::{error, info, warn}; /// 数据清理策略配置 diff --git a/easytier-contrib/easytier-uptime/src/db/mod.rs b/easytier-contrib/easytier-uptime/src/db/mod.rs index e25a9407..bb4099bb 100644 --- a/easytier-contrib/easytier-uptime/src/db/mod.rs +++ b/easytier-contrib/easytier-uptime/src/db/mod.rs @@ -5,12 +5,12 @@ pub mod operations; use std::fmt; use sea_orm::{ - prelude::*, sea_query::OnConflict, ColumnTrait as _, DatabaseConnection, DbErr, EntityTrait, - QueryFilter as _, Set, SqlxSqliteConnector, Statement, TransactionTrait as _, + ColumnTrait as _, DatabaseConnection, DbErr, EntityTrait, QueryFilter as _, Set, + SqlxSqliteConnector, Statement, TransactionTrait as _, prelude::*, sea_query::OnConflict, }; use sea_orm_migration::MigratorTrait as _; use serde::{Deserialize, Serialize}; -use sqlx::{migrate::MigrateDatabase as _, Sqlite, SqlitePool}; +use sqlx::{Sqlite, SqlitePool, migrate::MigrateDatabase as _}; use crate::migrator; diff --git a/easytier-contrib/easytier-uptime/src/db/operations.rs b/easytier-contrib/easytier-uptime/src/db/operations.rs index 9ff5d669..7c518219 100644 --- a/easytier-contrib/easytier-uptime/src/db/operations.rs +++ b/easytier-contrib/easytier-uptime/src/db/operations.rs @@ -1,8 +1,8 @@ use crate::api::CreateNodeRequest; -use crate::db::entity::*; use crate::db::Db; use crate::db::HealthStats; use crate::db::HealthStatus; +use crate::db::entity::*; use sea_orm::*; use std::collections::{HashMap, HashSet}; diff --git a/easytier-contrib/easytier-uptime/src/health_checker.rs b/easytier-contrib/easytier-uptime/src/health_checker.rs index 25b2fdcf..49198a30 100644 --- a/easytier-contrib/easytier-uptime/src/health_checker.rs +++ b/easytier-contrib/easytier-uptime/src/health_checker.rs @@ -19,9 +19,9 @@ use sqlx::any; use tracing::{debug, error, info, instrument, warn}; use crate::db::{ + Db, HealthStatus, entity::shared_nodes, operations::{HealthOperations, NodeOperations}, - Db, HealthStatus, }; pub struct HealthCheckOneNode { diff --git a/easytier-contrib/easytier-uptime/src/health_checker_manager.rs b/easytier-contrib/easytier-uptime/src/health_checker_manager.rs index fe26f055..98681ef1 100644 --- a/easytier-contrib/easytier-uptime/src/health_checker_manager.rs +++ b/easytier-contrib/easytier-uptime/src/health_checker_manager.rs @@ -1,11 +1,11 @@ use std::{collections::HashSet, sync::Arc, time::Duration}; use anyhow::Context as _; -use tokio::time::{interval, Interval}; +use tokio::time::{Interval, interval}; use tracing::{error, info}; use crate::{ - db::{entity::shared_nodes, operations::NodeOperations, Db}, + db::{Db, entity::shared_nodes, operations::NodeOperations}, health_checker::HealthChecker, }; diff --git a/easytier-contrib/easytier-uptime/src/main.rs b/easytier-contrib/easytier-uptime/src/main.rs index 34749641..b4f7668e 100644 --- a/easytier-contrib/easytier-uptime/src/main.rs +++ b/easytier-contrib/easytier-uptime/src/main.rs @@ -10,7 +10,7 @@ mod migrator; use api::routes::create_routes; use clap::Parser; use config::AppConfig; -use db::{operations::NodeOperations, Db}; +use db::{Db, operations::NodeOperations}; use easytier::common::log; use health_checker::HealthChecker; use health_checker_manager::HealthCheckerManager; @@ -49,7 +49,9 @@ async fn main() -> anyhow::Result<()> { // 如果提供了管理员密码,设置环境变量 if let Some(password) = args.admin_password { - env::set_var("ADMIN_PASSWORD", password); + unsafe { + env::set_var("ADMIN_PASSWORD", password); + } } tracing::info!( diff --git a/easytier-gui/src-tauri/Cargo.toml b/easytier-gui/src-tauri/Cargo.toml index 6f42a322..f49aa3a2 100644 --- a/easytier-gui/src-tauri/Cargo.toml +++ b/easytier-gui/src-tauri/Cargo.toml @@ -3,7 +3,7 @@ name = "easytier-gui" version = "2.6.0" description = "EasyTier GUI" authors = ["you"] -edition = "2021" +edition.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/easytier-gui/src-tauri/src/elevate/linux.rs b/easytier-gui/src-tauri/src/elevate/linux.rs index ec97a3a2..da178c05 100644 --- a/easytier-gui/src-tauri/src/elevate/linux.rs +++ b/easytier-gui/src-tauri/src/elevate/linux.rs @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ use super::Command; -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use std::env; use std::ffi::OsStr; use std::process::{Command as StdCommand, Output}; diff --git a/easytier-gui/src-tauri/src/elevate/macos.rs b/easytier-gui/src-tauri/src/elevate/macos.rs index fc6c2136..41b6cc48 100644 --- a/easytier-gui/src-tauri/src/elevate/macos.rs +++ b/easytier-gui/src-tauri/src/elevate/macos.rs @@ -30,10 +30,10 @@ use std::os::unix::process::ExitStatusExt; use std::path::Path; use std::ptr; -use libc::{fileno, wait, EINTR, SHUT_WR}; +use libc::{EINTR, SHUT_WR, fileno, wait}; use security_framework_sys::authorization::{ - errAuthorizationSuccess, kAuthorizationFlagDefaults, kAuthorizationFlagDestroyRights, AuthorizationCreate, AuthorizationExecuteWithPrivileges, AuthorizationFree, AuthorizationRef, + errAuthorizationSuccess, kAuthorizationFlagDefaults, kAuthorizationFlagDestroyRights, }; const ENV_PATH: &str = "PATH"; diff --git a/easytier-gui/src-tauri/src/elevate/windows.rs b/easytier-gui/src-tauri/src/elevate/windows.rs index 7678cc3a..ab421c58 100644 --- a/easytier-gui/src-tauri/src/elevate/windows.rs +++ b/easytier-gui/src-tauri/src/elevate/windows.rs @@ -11,11 +11,11 @@ use std::process::{ExitStatus, Output}; use winapi::shared::minwindef::{DWORD, LPVOID}; use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; use winapi::um::securitybaseapi::GetTokenInformation; -use winapi::um::winnt::{TokenElevation, HANDLE, TOKEN_ELEVATION, TOKEN_QUERY}; -use windows::core::{w, HSTRING, PCWSTR}; +use winapi::um::winnt::{HANDLE, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation}; use windows::Win32::Foundation::HWND; use windows::Win32::UI::Shell::ShellExecuteW; use windows::Win32::UI::WindowsAndMessaging::SW_HIDE; +use windows::core::{HSTRING, PCWSTR, w}; /// The implementation of state check and elevated executing varies on each platform impl Command { diff --git a/easytier-gui/src-tauri/src/lib.rs b/easytier-gui/src-tauri/src/lib.rs index 35dbe6e8..2b6c613b 100644 --- a/easytier-gui/src-tauri/src/lib.rs +++ b/easytier-gui/src-tauri/src/lib.rs @@ -21,9 +21,9 @@ use easytier::{ instance_manager::NetworkInstanceManager, launcher::NetworkConfig, rpc_service::ApiRpcServer, + tunnel::TunnelListener, tunnel::ring::RingTunnelListener, tunnel::tcp::TcpTunnelListener, - tunnel::TunnelListener, utils::{self}, }; use std::ops::Deref; @@ -559,10 +559,10 @@ fn toggle_window_visibility(app: &tauri::AppHandle) { } fn get_exe_path() -> String { - if let Ok(appimage_path) = std::env::var("APPIMAGE") { - if !appimage_path.is_empty() { - return appimage_path; - } + if let Ok(appimage_path) = std::env::var("APPIMAGE") + && !appimage_path.is_empty() + { + return appimage_path; } std::env::current_exe() .map(|p| p.to_string_lossy().to_string()) @@ -596,8 +596,8 @@ mod manager { use easytier::proto::rpc_types::controller::BaseController; use easytier::rpc_service::logger::LoggerRpcService; use easytier::rpc_service::remote_client::PersistentConfig; - use easytier::tunnel::ring::RingTunnelConnector; use easytier::tunnel::TunnelConnector; + use easytier::tunnel::ring::RingTunnelConnector; use easytier::web_client::WebClientHooks; pub(super) struct GuiHooks { @@ -979,34 +979,34 @@ mod manager { .get_rpc_client(app.clone()) .ok_or_else(|| anyhow::anyhow!("RPC client not found"))?; for id in enabled_networks { - if let Ok(uuid) = id.parse() { - if !self.storage.enabled_networks.contains(&uuid) { - let config = self - .storage - .network_configs - .get(&uuid) - .map(|i| i.value().1.clone()); - let Some(config) = config else { - continue; - }; - let toml_config = config.gen_config()?; - self.pre_run_network_instance_hook(&app, &toml_config) - .await - .map_err(|e| anyhow::anyhow!(e))?; - client - .run_network_instance( - BaseController::default(), - RunNetworkInstanceRequest { - inst_id: None, - config: Some(config), - overwrite: false, - }, - ) - .await?; - self.post_run_network_instance_hook(&app, &uuid) - .await - .map_err(|e| anyhow::anyhow!(e))?; - } + if let Ok(uuid) = id.parse() + && !self.storage.enabled_networks.contains(&uuid) + { + let config = self + .storage + .network_configs + .get(&uuid) + .map(|i| i.value().1.clone()); + let Some(config) = config else { + continue; + }; + let toml_config = config.gen_config()?; + self.pre_run_network_instance_hook(&app, &toml_config) + .await + .map_err(|e| anyhow::anyhow!(e))?; + client + .run_network_instance( + BaseController::default(), + RunNetworkInstanceRequest { + inst_id: None, + config: Some(config), + overwrite: false, + }, + ) + .await?; + self.post_run_network_instance_hook(&app, &uuid) + .await + .map_err(|e| anyhow::anyhow!(e))?; } } Ok(()) diff --git a/easytier-rpc-build/Cargo.toml b/easytier-rpc-build/Cargo.toml index 9c65ec44..510d8381 100644 --- a/easytier-rpc-build/Cargo.toml +++ b/easytier-rpc-build/Cargo.toml @@ -2,13 +2,12 @@ name = "easytier-rpc-build" description = "Protobuf RPC Service Generator for EasyTier" version = "0.1.0" -edition = "2021" +edition.workspace = true homepage = "https://github.com/EasyTier/EasyTier" repository = "https://github.com/EasyTier/EasyTier" authors = ["kkrainbow"] keywords = ["vpn", "p2p", "network", "easytier"] categories = ["network-programming", "command-line-utilities"] -rust-version = "1.93.0" license-file = "LICENSE" readme = "README.md" diff --git a/easytier-web/Cargo.toml b/easytier-web/Cargo.toml index e08ed2f2..96883b54 100644 --- a/easytier-web/Cargo.toml +++ b/easytier-web/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "easytier-web" version = "2.6.0" -edition = "2021" +edition.workspace = true description = "Config server for easytier. easytier-core gets config from this and web frontend use it as restful api server." [dependencies] diff --git a/easytier-web/src/client_manager/mod.rs b/easytier-web/src/client_manager/mod.rs index 074a5631..d18c2ab0 100644 --- a/easytier-web/src/client_manager/mod.rs +++ b/easytier-web/src/client_manager/mod.rs @@ -2,8 +2,8 @@ pub mod session; pub mod storage; use std::sync::{ - atomic::{AtomicU32, Ordering}, Arc, + atomic::{AtomicU32, Ordering}, }; use dashmap::DashMap; @@ -19,11 +19,11 @@ use maxminddb::geoip2; use session::{Location, Session}; use storage::{Storage, StorageToken}; -use crate::webhook::SharedWebhookConfig; use crate::FeatureFlags; +use crate::webhook::SharedWebhookConfig; use tokio::task::JoinSet; -use crate::db::{entity::user_running_network_configs, Db, UserIdInDb}; +use crate::db::{Db, UserIdInDb, entity::user_running_network_configs}; #[derive(rust_embed::Embed)] #[folder = "resources/"] @@ -340,7 +340,7 @@ mod tests { }; use sqlx::Executor; - use crate::{client_manager::ClientManager, db::Db, FeatureFlags}; + use crate::{FeatureFlags, client_manager::ClientManager, db::Db}; #[tokio::test] async fn test_client() { diff --git a/easytier-web/src/client_manager/session.rs b/easytier-web/src/client_manager/session.rs index 2159a093..3a2e527f 100644 --- a/easytier-web/src/client_manager/session.rs +++ b/easytier-web/src/client_manager/session.rs @@ -20,11 +20,11 @@ use easytier::{ rpc_service::remote_client::{ListNetworkProps, Storage as _}, tunnel::Tunnel, }; -use tokio::sync::{broadcast, RwLock}; +use tokio::sync::{RwLock, broadcast}; use super::storage::{Storage, StorageToken, WeakRefStorage}; -use crate::webhook::SharedWebhookConfig; use crate::FeatureFlags; +use crate::webhook::SharedWebhookConfig; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Location { @@ -87,30 +87,30 @@ impl SessionData { impl Drop for SessionData { fn drop(&mut self) { - if let Ok(storage) = Storage::try_from(self.storage.clone()) { - if let Some(token) = self.storage_token.as_ref() { - storage.remove_client(token); + if let Ok(storage) = Storage::try_from(self.storage.clone()) + && let Some(token) = self.storage_token.as_ref() + { + storage.remove_client(token); - // Notify the webhook receiver when a node disconnects. - if self.webhook_config.is_enabled() { - let webhook = self.webhook_config.clone(); - let machine_id = token.machine_id.to_string(); - let user_id = Some(token.user_id); - let token_value = token.token.clone(); - let web_instance_id = webhook.web_instance_id.clone(); - let binding_version = self.binding_version; - tokio::spawn(async move { - webhook - .notify_node_disconnected(&crate::webhook::NodeDisconnectedRequest { - machine_id, - token: token_value, - user_id, - web_instance_id, - binding_version, - }) - .await; - }); - } + // Notify the webhook receiver when a node disconnects. + if self.webhook_config.is_enabled() { + let webhook = self.webhook_config.clone(); + let machine_id = token.machine_id.to_string(); + let user_id = Some(token.user_id); + let token_value = token.token.clone(); + let web_instance_id = webhook.web_instance_id.clone(); + let binding_version = self.binding_version; + tokio::spawn(async move { + webhook + .notify_node_disconnected(&crate::webhook::NodeDisconnectedRequest { + machine_id, + token: token_value, + user_id, + web_instance_id, + binding_version, + }) + .await; + }); } } } diff --git a/easytier-web/src/db/mod.rs b/easytier-web/src/db/mod.rs index b525a0cc..8627b505 100644 --- a/easytier-web/src/db/mod.rs +++ b/easytier-web/src/db/mod.rs @@ -8,11 +8,11 @@ use easytier::{ }; use entity::user_running_network_configs; use sea_orm::{ - prelude::Expr, sea_query::OnConflict, ColumnTrait as _, DatabaseConnection, DbErr, EntityTrait, - QueryFilter as _, Set, SqlxSqliteConnector, TransactionTrait as _, + ColumnTrait as _, DatabaseConnection, DbErr, EntityTrait, QueryFilter as _, Set, + SqlxSqliteConnector, TransactionTrait as _, prelude::Expr, sea_query::OnConflict, }; use sea_orm_migration::MigratorTrait as _; -use sqlx::{migrate::MigrateDatabase as _, types::chrono, Sqlite, SqlitePool}; +use sqlx::{Sqlite, SqlitePool, migrate::MigrateDatabase as _, types::chrono}; use uuid::Uuid; use crate::migrator; @@ -280,7 +280,7 @@ mod tests { use easytier::{proto::api::manage::NetworkConfig, rpc_service::remote_client::Storage}; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter as _}; - use crate::db::{entity::user_running_network_configs, Db, ListNetworkProps}; + use crate::db::{Db, ListNetworkProps, entity::user_running_network_configs}; #[tokio::test] async fn test_user_network_config_management() { diff --git a/easytier-web/src/main.rs b/easytier-web/src/main.rs index 143ce5bc..6c741727 100644 --- a/easytier-web/src/main.rs +++ b/easytier-web/src/main.rs @@ -16,7 +16,7 @@ use easytier::{ log, network::{local_ipv4, local_ipv6}, }, - tunnel::{tcp::TcpTunnelListener, udp::UdpTunnelListener, TunnelListener}, + tunnel::{TunnelListener, tcp::TcpTunnelListener, udp::UdpTunnelListener}, utils::setup_panic_handler, }; diff --git a/easytier-web/src/restful/auth.rs b/easytier-web/src/restful/auth.rs index fb65d21c..775870b2 100644 --- a/easytier-web/src/restful/auth.rs +++ b/easytier-web/src/restful/auth.rs @@ -1,7 +1,7 @@ use axum::{ + Router, http::StatusCode, routing::{get, post, put}, - Router, }; use axum_login::login_required; use axum_messages::Message; @@ -14,8 +14,8 @@ use std::sync::Arc; use crate::FeatureFlags; use super::{ - users::{AuthSession, Credentials}, AppStateInner, + users::{AuthSession, Credentials}, }; #[derive(Debug, Deserialize, Serialize)] @@ -44,7 +44,7 @@ mod put { use axum_login::AuthUser; use easytier::proto::common::Void; - use crate::restful::{other_error, users::ChangePassword, HttpHandleError}; + use crate::restful::{HttpHandleError, other_error, users::ChangePassword}; use super::*; @@ -71,14 +71,14 @@ mod put { } mod post { - use axum::{extract::Extension, Json}; + use axum::{Json, extract::Extension}; use easytier::proto::common::Void; use crate::restful::{ - captcha::extension::{axum_tower_sessions::CaptchaAxumTowerSessionStaticExt, CaptchaUtil}, + HttpHandleError, + captcha::extension::{CaptchaUtil, axum_tower_sessions::CaptchaAxumTowerSessionStaticExt}, other_error, users::RegisterNewUser, - HttpHandleError, }; use super::*; @@ -99,7 +99,7 @@ mod post { return Err(( StatusCode::INTERNAL_SERVER_ERROR, Json::from(other_error(format!("{:?}", e))), - )) + )); } }; @@ -150,14 +150,15 @@ mod post { mod get { use crate::restful::{ + HttpHandleError, captcha::{ - builder::spec::SpecCaptcha, - extension::{axum_tower_sessions::CaptchaAxumTowerSessionExt as _, CaptchaUtil}, NewCaptcha as _, + builder::spec::SpecCaptcha, + extension::{CaptchaUtil, axum_tower_sessions::CaptchaAxumTowerSessionExt as _}, }, - other_error, HttpHandleError, + other_error, }; - use axum::{response::Response, Json}; + use axum::{Json, response::Response}; use easytier::proto::common::Void; use tower_sessions::Session; diff --git a/easytier-web/src/restful/captcha/base/captcha.rs b/easytier-web/src/restful/captcha/base/captcha.rs index 3bed68e7..6885d845 100644 --- a/easytier-web/src/restful/captcha/base/captcha.rs +++ b/easytier-web/src/restful/captcha/base/captcha.rs @@ -2,8 +2,8 @@ use super::super::base::randoms::Randoms; use super::super::utils::color::Color; use super::super::utils::font; -use base64::prelude::BASE64_STANDARD; use base64::Engine; +use base64::prelude::BASE64_STANDARD; use rusttype::Font; use std::fmt::Debug; diff --git a/easytier-web/src/restful/captcha/builder/spec.rs b/easytier-web/src/restful/captcha/builder/spec.rs index c58d01f8..c911b574 100644 --- a/easytier-web/src/restful/captcha/builder/spec.rs +++ b/easytier-web/src/restful/captcha/builder/spec.rs @@ -9,14 +9,14 @@ use super::super::{CaptchaFont, NewCaptcha}; use image::{ImageBuffer, Rgba}; use imageproc::drawing; -use rand::{rngs::ThreadRng, Rng}; +use rand::{Rng, rngs::ThreadRng}; use rusttype::{Font, Scale}; use std::io::{Cursor, Write}; use std::sync::Arc; mod color { use image::Rgba; - use rand::{rngs::ThreadRng, Rng}; + use rand::{Rng, rngs::ThreadRng}; pub fn gen_background_color(rng: &mut ThreadRng) -> Rgba { let red = rng.gen_range(200..=255); let green = rng.gen_range(200..=255); @@ -133,7 +133,7 @@ impl<'a, 'b> CaptchaBuilder<'a, 'b> { fn draw_line(&self, image: &mut ImageBuffer, Vec>, rng: &mut ThreadRng) { let line_color = color::gen_line_color(rng); - let is_h = rng.gen(); + let is_h = rng.r#gen(); let (start, end) = if is_h { let xa = rng.gen_range(0.0..(self.width as f32) / 2.0); let ya = rng.gen_range(0.0..(self.height as f32)); diff --git a/easytier-web/src/restful/mod.rs b/easytier-web/src/restful/mod.rs index 9fd2bc43..b78e9e00 100644 --- a/easytier-web/src/restful/mod.rs +++ b/easytier-web/src/restful/mod.rs @@ -8,13 +8,13 @@ mod users; use std::{net::SocketAddr, sync::Arc}; use axum::extract::Path; -use axum::http::{header, Request, StatusCode}; +use axum::http::{Request, StatusCode, header}; use axum::middleware::{self as axum_mw, Next}; use axum::response::Response; use axum::routing::{delete, post}; -use axum::{extract::State, routing::get, Extension, Json, Router}; +use axum::{Extension, Json, Router, extract::State, routing::get}; use axum_login::tower_sessions::{ExpiredDeletion, SessionManagerLayer}; -use axum_login::{login_required, AuthManagerLayerBuilder, AuthUser, AuthzBackend}; +use axum_login::{AuthManagerLayerBuilder, AuthUser, AuthzBackend, login_required}; use axum_messages::MessagesManagerLayer; use easytier::common::config::{ConfigLoader, TomlConfigLoader}; use easytier::common::scoped_task::ScopedTask; @@ -23,17 +23,17 @@ use easytier::proto::rpc_types; use network::NetworkApi; use sea_orm::DbErr; use tokio::net::TcpListener; +use tower_sessions::Expiry; use tower_sessions::cookie::time::Duration; use tower_sessions::cookie::{Key, SameSite}; -use tower_sessions::Expiry; use tower_sessions_sqlx_store::SqliteStore; use users::{AuthSession, Backend}; -use crate::client_manager::storage::StorageToken; +use crate::FeatureFlags; use crate::client_manager::ClientManager; +use crate::client_manager::storage::StorageToken; use crate::db::{Db, UserIdInDb}; use crate::webhook::SharedWebhookConfig; -use crate::FeatureFlags; /// Embed assets for web dashboard, build frontend first #[cfg(feature = "embed")] diff --git a/easytier-web/src/restful/network.rs b/easytier-web/src/restful/network.rs index e97e010b..b47f5167 100644 --- a/easytier-web/src/restful/network.rs +++ b/easytier-web/src/restful/network.rs @@ -1,7 +1,7 @@ use axum::extract::Path; use axum::http::StatusCode; use axum::routing::{delete, post}; -use axum::{extract::State, routing::get, Json, Router}; +use axum::{Json, Router, extract::State, routing::get}; use axum_login::AuthUser; use easytier::launcher::NetworkConfig; use easytier::proto::common::Void; @@ -16,7 +16,7 @@ use crate::db::UserIdInDb; use super::users::AuthSession; use super::{ - convert_db_error, other_error, AppState, AppStateInner, Error, HttpHandleError, RpcError, + AppState, AppStateInner, Error, HttpHandleError, RpcError, convert_db_error, other_error, }; fn convert_rpc_error(e: RpcError) -> (StatusCode, Json) { diff --git a/easytier-web/src/restful/oidc.rs b/easytier-web/src/restful/oidc.rs index 7796509c..efca09d4 100644 --- a/easytier-web/src/restful/oidc.rs +++ b/easytier-web/src/restful/oidc.rs @@ -4,8 +4,8 @@ use std::time::Duration; use subtle::ConstantTimeEq; -use axum::routing::get; use axum::Router; +use axum::routing::get; use openidconnect::core::{ CoreAuthDisplay, CoreAuthPrompt, CoreErrorResponseType, CoreGenderClaim, CoreJsonWebKey, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreProviderMetadata, @@ -216,7 +216,9 @@ impl OidcConfig { } = opts; if oidc_issuer_url.is_none() || oidc_client_id.is_none() || oidc_redirect_url.is_none() { - return Err(anyhow::anyhow!("--oidc-issuer-url, --oidc-client-id and --oidc-redirect-url are required when using OIDC authentication")); + return Err(anyhow::anyhow!( + "--oidc-issuer-url, --oidc-client-id and --oidc-redirect-url are required when using OIDC authentication" + )); } if oidc_username_claim.trim().is_empty() { return Err(anyhow::anyhow!("--oidc-username-claim cannot be empty")); @@ -373,18 +375,17 @@ mod route { ) .into_response(); } - if let Some(verifier) = pkce_verifier { - if let Err(e) = session + if let Some(verifier) = pkce_verifier + && let Err(e) = session .insert("oidc_pkce_verifier", verifier.secret().clone()) .await - { - tracing::error!("Failed to store pkce_verifier in session: {:?}", e); - return ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(other_error("Session error")), - ) - .into_response(); - } + { + tracing::error!("Failed to store pkce_verifier in session: {:?}", e); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(other_error("Session error")), + ) + .into_response(); } if let Err(e) = session.insert("oidc_pkce_used", pkce_enabled).await { tracing::error!("Failed to store pkce_used in session: {:?}", e); diff --git a/easytier-web/src/restful/rpc.rs b/easytier-web/src/restful/rpc.rs index 7d2ec032..e938a87f 100644 --- a/easytier-web/src/restful/rpc.rs +++ b/easytier-web/src/restful/rpc.rs @@ -1,15 +1,15 @@ use axum::{ + Json, Router, extract::{Path, State}, http::StatusCode, routing::post, - Json, Router, }; use axum_login::AuthUser as _; use easytier::proto::rpc_types::controller::BaseController; use crate::db::UserIdInDb; -use super::{other_error, AppState, HttpHandleError}; +use super::{AppState, HttpHandleError, other_error}; #[derive(Debug, serde::Deserialize)] pub struct ProxyRpcRequest { @@ -120,7 +120,7 @@ async fn handle_proxy_rpc_by_session( return Err(( StatusCode::BAD_REQUEST, other_error(format!("Unknown service: {}", service_name)).into(), - )) + )); } }; diff --git a/easytier-web/src/restful/users.rs b/easytier-web/src/restful/users.rs index 325bf994..5ec86918 100644 --- a/easytier-web/src/restful/users.rs +++ b/easytier-web/src/restful/users.rs @@ -39,9 +39,9 @@ impl AuthUser for User { fn session_auth_hash(&self) -> &[u8] { self.db_user.password.as_bytes() // We use the password hash as the auth - // hash--what this means - // is when the user changes their password the - // auth session becomes invalid. + // hash--what this means + // is when the user changes their password the + // auth session becomes invalid. } } diff --git a/easytier-web/src/web/mod.rs b/easytier-web/src/web/mod.rs index eabe307e..934108ed 100644 --- a/easytier-web/src/web/mod.rs +++ b/easytier-web/src/web/mod.rs @@ -1,8 +1,9 @@ use axum::{ + Router, extract::State, http::header, response::{IntoResponse, Response}, - routing, Router, + routing, }; use axum_embed::ServeEmbed; use easytier::common::scoped_task::ScopedTask; diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 410726c8..b7e53f6f 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -4,11 +4,11 @@ description = "A full meshed p2p VPN, connecting all your devices in one network homepage = "https://github.com/EasyTier/EasyTier" repository = "https://github.com/EasyTier/EasyTier" version = "2.6.0" -edition = "2021" +edition.workspace = true +rust-version.workspace = true authors = ["kkrainbow"] keywords = ["vpn", "p2p", "network", "easytier"] categories = ["network-programming", "command-line-utilities"] -rust-version = "1.93.0" license-file = "LICENSE" readme = "README.md" diff --git a/easytier/build.rs b/easytier/build.rs index 520a3f7f..5f6a74d8 100644 --- a/easytier/build.rs +++ b/easytier/build.rs @@ -86,7 +86,9 @@ impl WindowsBuild { } else { Self::download_protoc() }; - std::env::set_var("PROTOC", protoc_path); + unsafe { + std::env::set_var("PROTOC", protoc_path); + } } } diff --git a/easytier/src/arch/windows.rs b/easytier/src/arch/windows.rs index 9d97ecfc..d709d499 100644 --- a/easytier/src/arch/windows.rs +++ b/easytier/src/arch/windows.rs @@ -3,7 +3,6 @@ use std::{io, mem::ManuallyDrop, net::SocketAddr, os::windows::io::AsRawSocket}; use anyhow::Context; use network_interface::NetworkInterfaceConfig; use windows::{ - core::BSTR, Win32::{ Foundation::{BOOL, FALSE}, NetworkManagement::WindowsFirewall::{ @@ -12,15 +11,16 @@ use windows::{ NET_FW_RULE_DIR_OUT, }, Networking::WinSock::{ - htonl, setsockopt, WSAGetLastError, WSAIoctl, IPPROTO_IP, IPPROTO_IPV6, - IPV6_UNICAST_IF, IP_UNICAST_IF, SIO_UDP_CONNRESET, SOCKET, SOCKET_ERROR, + IP_UNICAST_IF, IPPROTO_IP, IPPROTO_IPV6, IPV6_UNICAST_IF, SIO_UDP_CONNRESET, SOCKET, + SOCKET_ERROR, WSAGetLastError, WSAIoctl, htonl, setsockopt, }, System::Com::{ - CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_MULTITHREADED, + CLSCTX_ALL, COINIT_MULTITHREADED, CoCreateInstance, CoInitializeEx, CoUninitialize, }, System::Ole::{SafeArrayCreateVector, SafeArrayPutElement}, System::Variant::{VARENUM, VARIANT, VT_ARRAY, VT_BSTR, VT_VARIANT}, }, + core::BSTR, }; pub fn disable_connection_reset(socket: &S) -> io::Result<()> { diff --git a/easytier/src/common/acl_processor.rs b/easytier/src/common/acl_processor.rs index 3a86d98d..73376f1c 100644 --- a/easytier/src/common/acl_processor.rs +++ b/easytier/src/common/acl_processor.rs @@ -507,7 +507,7 @@ impl AclProcessor { matched_rule: Some(RuleId::Default), should_log: false, log_context: Some(AclLogContext::UnsupportedChainType), - } + }; } }; @@ -679,28 +679,28 @@ impl AclProcessor { } // Source port check - if let Some(src_port) = packet_info.src_port { - if !rule.src_port_ranges.is_empty() { - let matches = rule - .src_port_ranges - .iter() - .any(|(start, end)| src_port >= *start && src_port <= *end); - if !matches { - return false; - } + if let Some(src_port) = packet_info.src_port + && !rule.src_port_ranges.is_empty() + { + let matches = rule + .src_port_ranges + .iter() + .any(|(start, end)| src_port >= *start && src_port <= *end); + if !matches { + return false; } } // Destination port check - if let Some(dst_port) = packet_info.dst_port { - if !rule.dst_port_ranges.is_empty() { - let matches = rule - .dst_port_ranges - .iter() - .any(|(start, end)| dst_port >= *start && dst_port <= *end); - if !matches { - return false; - } + if let Some(dst_port) = packet_info.dst_port + && !rule.dst_port_ranges.is_empty() + { + let matches = rule + .dst_port_ranges + .iter() + .any(|(start, end)| dst_port >= *start && dst_port <= *end); + if !matches { + return false; } } diff --git a/easytier/src/common/compressor.rs b/easytier/src/common/compressor.rs index a5201852..d78972ee 100644 --- a/easytier/src/common/compressor.rs +++ b/easytier/src/common/compressor.rs @@ -9,7 +9,7 @@ use zstd::bulk; use zerocopy::{AsBytes as _, FromBytes as _}; -use crate::tunnel::packet_def::{CompressorAlgo, CompressorTail, ZCPacket, COMPRESSOR_TAIL_SIZE}; +use crate::tunnel::packet_def::{COMPRESSOR_TAIL_SIZE, CompressorAlgo, CompressorTail, ZCPacket}; type Error = anyhow::Error; diff --git a/easytier/src/common/config.rs b/easytier/src/common/config.rs index e4c9c5e6..a58e840f 100644 --- a/easytier/src/common/config.rs +++ b/easytier/src/common/config.rs @@ -6,10 +6,10 @@ use std::{ }; use anyhow::Context; -use base64::{prelude::BASE64_STANDARD, Engine as _}; +use base64::{Engine as _, prelude::BASE64_STANDARD}; use cfg_if::cfg_if; -use clap::builder::PossibleValue; use clap::ValueEnum; +use clap::builder::PossibleValue; use serde::{Deserialize, Serialize}; use strum::{Display, EnumString, VariantArray}; use tokio::io::AsyncReadExt as _; @@ -621,14 +621,14 @@ impl ConfigLoader for TomlConfigLoader { if locked_config.proxy_network.is_none() { locked_config.proxy_network = Some(vec![]); } - if let Some(mapped_cidr) = mapped_cidr.as_ref() { - if cidr.network_length() != mapped_cidr.network_length() { - return Err(anyhow::anyhow!( - "Mapped CIDR must have the same network length as the original CIDR: {} != {}", - cidr.network_length(), - mapped_cidr.network_length() - )); - } + if let Some(mapped_cidr) = mapped_cidr.as_ref() + && cidr.network_length() != mapped_cidr.network_length() + { + return Err(anyhow::anyhow!( + "Mapped CIDR must have the same network length as the original CIDR: {} != {}", + cidr.network_length(), + mapped_cidr.network_length() + )); } // insert if no duplicate if !locked_config @@ -881,10 +881,10 @@ impl ConfigLoader for TomlConfigLoader { let mut flag_map: serde_json::Map = Default::default(); for (key, value) in default_flags_hashmap { - if let Some(v) = cur_flags_hashmap.get(&key) { - if *v != value { - flag_map.insert(key, v.clone()); - } + if let Some(v) = cur_flags_hashmap.get(&key) + && *v != value + { + flag_map.insert(key, v.clone()); } } @@ -1089,6 +1089,7 @@ pub async fn load_config_from_file( #[cfg(test)] pub mod tests { use super::*; + use crate::tests::{remove_env_var, set_env_var}; use std::io::Write; use std::path::PathBuf; use tempfile::NamedTempFile; @@ -1212,8 +1213,8 @@ proto = "tcp" #[tokio::test] async fn test_env_var_expansion_and_readonly_flag() { // 设置测试环境变量 - std::env::set_var("TEST_SECRET", "my-test-secret-123"); - std::env::set_var("TEST_NETWORK", "test-network"); + set_env_var("TEST_SECRET", "my-test-secret-123"); + set_env_var("TEST_NETWORK", "test-network"); // 创建临时配置文件,包含环境变量占位符 let mut temp_file = NamedTempFile::new().unwrap(); @@ -1253,8 +1254,8 @@ network_secret = "${TEST_SECRET}" ); // 清理环境变量 - std::env::remove_var("TEST_SECRET"); - std::env::remove_var("TEST_NETWORK"); + remove_env_var("TEST_SECRET"); + remove_env_var("TEST_NETWORK"); } /// RPC API 安全测试(只读配置保护) @@ -1267,7 +1268,7 @@ network_secret = "${TEST_SECRET}" /// `easytier/src/rpc_service/instance_manage.rs` 中实现 #[tokio::test] async fn test_readonly_config_api_protection() { - std::env::set_var("API_TEST_SECRET", "secret-value"); + set_env_var("API_TEST_SECRET", "secret-value"); // 创建包含环境变量的配置 let mut temp_file = NamedTempFile::new().unwrap(); @@ -1298,7 +1299,7 @@ network_secret = "${API_TEST_SECRET}" "Permission flag should be set correctly" ); - std::env::remove_var("API_TEST_SECRET"); + remove_env_var("API_TEST_SECRET"); } /// CLI 参数测试(--disable-env-parsing 开关) @@ -1308,7 +1309,7 @@ network_secret = "${API_TEST_SECRET}" /// - 配置不会被标记为只读 #[tokio::test] async fn test_disable_env_parsing_flag() { - std::env::set_var("DISABLED_TEST_VAR", "should-not-expand"); + set_env_var("DISABLED_TEST_VAR", "should-not-expand"); // 创建包含环境变量占位符的配置 let mut temp_file = NamedTempFile::new().unwrap(); @@ -1346,7 +1347,7 @@ network_secret = "${DISABLED_TEST_VAR}" "Config should be NO_DELETE due to no config_dir, not env vars" ); - std::env::remove_var("DISABLED_TEST_VAR"); + remove_env_var("DISABLED_TEST_VAR"); } /// 多实例隔离测试 @@ -1357,8 +1358,8 @@ network_secret = "${DISABLED_TEST_VAR}" #[tokio::test] async fn test_multiple_instances_with_different_env_vars() { // 实例1:使用第一组环境变量 - std::env::set_var("INSTANCE_SECRET", "instance1-secret"); - std::env::set_var("INSTANCE_NAME", "instance-one"); + set_env_var("INSTANCE_SECRET", "instance1-secret"); + set_env_var("INSTANCE_NAME", "instance-one"); let mut temp_file1 = NamedTempFile::new().unwrap(); let config_content = r#" @@ -1388,8 +1389,8 @@ network_secret = "${INSTANCE_SECRET}" ); // 实例2:修改环境变量后加载同一模板 - std::env::set_var("INSTANCE_SECRET", "instance2-secret"); - std::env::set_var("INSTANCE_NAME", "instance-two"); + set_env_var("INSTANCE_SECRET", "instance2-secret"); + set_env_var("INSTANCE_NAME", "instance-two"); let mut temp_file2 = NamedTempFile::new().unwrap(); temp_file2.write_all(config_content.as_bytes()).unwrap(); @@ -1419,8 +1420,8 @@ network_secret = "${INSTANCE_SECRET}" ); // 清理 - std::env::remove_var("INSTANCE_SECRET"); - std::env::remove_var("INSTANCE_NAME"); + remove_env_var("INSTANCE_SECRET"); + remove_env_var("INSTANCE_NAME"); } /// 实际配置字段测试(network_secret、peer.uri 等) @@ -1433,11 +1434,11 @@ network_secret = "${INSTANCE_SECRET}" #[tokio::test] async fn test_real_config_fields_expansion() { // 设置各种实际场景的环境变量 - std::env::set_var("ET_SECRET", "production-secret-key"); - std::env::set_var("PEER_HOST", "peer.example.com"); - std::env::set_var("PEER_PORT", "11011"); - std::env::set_var("LISTEN_PORT", "11010"); - std::env::set_var("NETWORK_NAME", "prod-network"); + set_env_var("ET_SECRET", "production-secret-key"); + set_env_var("PEER_HOST", "peer.example.com"); + set_env_var("PEER_PORT", "11011"); + set_env_var("LISTEN_PORT", "11010"); + set_env_var("NETWORK_NAME", "prod-network"); // 创建包含多个实际字段的完整配置 let mut temp_file = NamedTempFile::new().unwrap(); @@ -1485,11 +1486,11 @@ uri = "tcp://${PEER_HOST}:${PEER_PORT}" assert!(control.is_no_delete()); // 清理环境变量 - std::env::remove_var("ET_SECRET"); - std::env::remove_var("PEER_HOST"); - std::env::remove_var("PEER_PORT"); - std::env::remove_var("LISTEN_PORT"); - std::env::remove_var("NETWORK_NAME"); + remove_env_var("ET_SECRET"); + remove_env_var("PEER_HOST"); + remove_env_var("PEER_PORT"); + remove_env_var("LISTEN_PORT"); + remove_env_var("NETWORK_NAME"); } /// 带默认值的环境变量 @@ -1499,8 +1500,8 @@ uri = "tcp://${PEER_HOST}:${PEER_PORT}" #[tokio::test] async fn test_env_var_with_default_value() { // 确保变量未定义 - std::env::remove_var("UNDEFINED_PORT"); - std::env::remove_var("UNDEFINED_SECRET"); + remove_env_var("UNDEFINED_PORT"); + remove_env_var("UNDEFINED_SECRET"); let mut temp_file = NamedTempFile::new().unwrap(); let config_content = r#" @@ -1541,7 +1542,7 @@ network_secret = "${UNDEFINED_SECRET:-default-secret}" /// - 未定义的环境变量保持原样(shellexpand 的默认行为) #[tokio::test] async fn test_undefined_env_var_without_default() { - std::env::remove_var("COMPLETELY_UNDEFINED"); + remove_env_var("COMPLETELY_UNDEFINED"); let mut temp_file = NamedTempFile::new().unwrap(); let config_content = r#" @@ -1571,6 +1572,8 @@ network_secret = "${COMPLETELY_UNDEFINED}" // 注意:由于没有实际替换发生,控制标记不应因环境变量而设置 // 但会因为其他原因(如没有 config_dir)被标记为 NO_DELETE + // 这里我们主要验证 NO_DELETE 标记的逻辑 + // 由于没有 config_dir,文件会被标记为 NO_DELETE,但不是因为环境变量 assert!(control.is_no_delete()); } @@ -1582,9 +1585,9 @@ network_secret = "${COMPLETELY_UNDEFINED}" #[tokio::test] async fn test_boolean_type_env_vars() { // 设置布尔类型的环境变量 - std::env::set_var("ENABLE_DHCP", "true"); - std::env::set_var("ENABLE_ENCRYPTION", "false"); - std::env::set_var("ENABLE_IPV6", "true"); + set_env_var("ENABLE_DHCP", "true"); + set_env_var("ENABLE_ENCRYPTION", "false"); + set_env_var("ENABLE_IPV6", "true"); let mut temp_file = NamedTempFile::new().unwrap(); let config_content = r#" @@ -1622,9 +1625,9 @@ enable_ipv6 = ${ENABLE_IPV6} assert!(control.is_no_delete()); // 清理 - std::env::remove_var("ENABLE_DHCP"); - std::env::remove_var("ENABLE_ENCRYPTION"); - std::env::remove_var("ENABLE_IPV6"); + remove_env_var("ENABLE_DHCP"); + remove_env_var("ENABLE_ENCRYPTION"); + remove_env_var("ENABLE_IPV6"); } /// 数字类型环境变量 @@ -1635,8 +1638,8 @@ enable_ipv6 = ${ENABLE_IPV6} #[tokio::test] async fn test_numeric_type_env_vars() { // 设置数字类型的环境变量 - std::env::set_var("MTU_VALUE", "1400"); - std::env::set_var("THREAD_COUNT", "4"); + set_env_var("MTU_VALUE", "1400"); + set_env_var("THREAD_COUNT", "4"); let mut temp_file = NamedTempFile::new().unwrap(); let config_content = r#" @@ -1671,8 +1674,8 @@ multi_thread_count = ${THREAD_COUNT} assert!(control.is_no_delete()); // 清理 - std::env::remove_var("MTU_VALUE"); - std::env::remove_var("THREAD_COUNT"); + remove_env_var("MTU_VALUE"); + remove_env_var("THREAD_COUNT"); } /// 混合类型环境变量 @@ -1684,12 +1687,12 @@ multi_thread_count = ${THREAD_COUNT} #[tokio::test] async fn test_mixed_type_env_vars() { // 设置不同类型的环境变量 - std::env::set_var("MIXED_SECRET", "mixed-secret-key"); - std::env::set_var("MIXED_NETWORK", "production"); - std::env::set_var("MIXED_DHCP", "true"); - std::env::set_var("MIXED_MTU", "1500"); - std::env::set_var("MIXED_ENCRYPTION", "false"); - std::env::set_var("MIXED_LISTEN_PORT", "12345"); + set_env_var("MIXED_SECRET", "mixed-secret-key"); + set_env_var("MIXED_NETWORK", "production"); + set_env_var("MIXED_DHCP", "true"); + set_env_var("MIXED_MTU", "1500"); + set_env_var("MIXED_ENCRYPTION", "false"); + set_env_var("MIXED_LISTEN_PORT", "12345"); let mut temp_file = NamedTempFile::new().unwrap(); let config_content = r#" @@ -1741,11 +1744,11 @@ enable_encryption = ${MIXED_ENCRYPTION} assert!(control.is_no_delete()); // 清理 - std::env::remove_var("MIXED_SECRET"); - std::env::remove_var("MIXED_NETWORK"); - std::env::remove_var("MIXED_DHCP"); - std::env::remove_var("MIXED_MTU"); - std::env::remove_var("MIXED_ENCRYPTION"); - std::env::remove_var("MIXED_LISTEN_PORT"); + remove_env_var("MIXED_SECRET"); + remove_env_var("MIXED_NETWORK"); + remove_env_var("MIXED_DHCP"); + remove_env_var("MIXED_MTU"); + remove_env_var("MIXED_ENCRYPTION"); + remove_env_var("MIXED_LISTEN_PORT"); } } diff --git a/easytier/src/common/dns.rs b/easytier/src/common/dns.rs index e368e640..dd7eaef1 100644 --- a/easytier/src/common/dns.rs +++ b/easytier/src/common/dns.rs @@ -1,6 +1,6 @@ use std::net::SocketAddr; -use std::sync::atomic::AtomicBool; use std::sync::Arc; +use std::sync::atomic::AtomicBool; use anyhow::Context; use hickory_proto::runtime::TokioRuntimeProvider; diff --git a/easytier/src/common/env_parser.rs b/easytier/src/common/env_parser.rs index bb65b805..15fcf5d4 100644 --- a/easytier/src/common/env_parser.rs +++ b/easytier/src/common/env_parser.rs @@ -42,10 +42,11 @@ pub fn expand_env_vars(text: &str) -> (String, bool) { #[cfg(test)] mod tests { use super::*; + use crate::tests::{remove_env_var, set_env_var}; #[test] fn test_expand_standard_syntax() { - std::env::set_var("TEST_VAR_STANDARD", "test_value"); + set_env_var("TEST_VAR_STANDARD", "test_value"); let (result, changed) = expand_env_vars("secret=${TEST_VAR_STANDARD}"); assert_eq!(result, "secret=test_value"); assert!(changed); @@ -53,7 +54,7 @@ mod tests { #[test] fn test_expand_short_syntax() { - std::env::set_var("TEST_VAR_SHORT", "short_value"); + set_env_var("TEST_VAR_SHORT", "short_value"); let (result, changed) = expand_env_vars("key=$TEST_VAR_SHORT"); assert_eq!(result, "key=short_value"); assert!(changed); @@ -62,7 +63,7 @@ mod tests { #[test] fn test_expand_with_default() { // 确保变量未定义 - std::env::remove_var("UNDEFINED_VAR_WITH_DEFAULT"); + remove_env_var("UNDEFINED_VAR_WITH_DEFAULT"); let (result, changed) = expand_env_vars("port=${UNDEFINED_VAR_WITH_DEFAULT:-8080}"); assert_eq!(result, "port=8080"); assert!(changed); @@ -84,8 +85,8 @@ mod tests { #[test] fn test_multiple_vars() { - std::env::set_var("VAR1", "value1"); - std::env::set_var("VAR2", "value2"); + set_env_var("VAR1", "value1"); + set_env_var("VAR2", "value2"); let (result, changed) = expand_env_vars("${VAR1} and ${VAR2}"); assert_eq!(result, "value1 and value2"); assert!(changed); @@ -94,7 +95,7 @@ mod tests { #[test] fn test_undefined_var_without_default() { // 确保变量未定义 - std::env::remove_var("COMPLETELY_UNDEFINED_VAR"); + remove_env_var("COMPLETELY_UNDEFINED_VAR"); let (result, changed) = expand_env_vars("value=${COMPLETELY_UNDEFINED_VAR}"); // shellexpand::env 对未定义的变量会保持原样 assert_eq!(result, "value=${COMPLETELY_UNDEFINED_VAR}"); @@ -103,8 +104,8 @@ mod tests { #[test] fn test_complex_toml_config() { - std::env::set_var("ET_SECRET", "my-secret-key"); - std::env::set_var("ET_PORT", "11010"); + set_env_var("ET_SECRET", "my-secret-key"); + set_env_var("ET_PORT", "11010"); let config = r#" [network_identity] @@ -123,7 +124,7 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_escape_syntax_double_dollar() { - std::env::set_var("ESCAPED_VAR", "should_not_expand"); + set_env_var("ESCAPED_VAR", "should_not_expand"); // shellexpand 使用 $$ 作为转义序列,表示字面量的单个 $ // $$ 会被转义为单个 $,不会触发变量扩展 let (result, changed) = expand_env_vars("value=$${ESCAPED_VAR}"); @@ -133,7 +134,7 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_escape_syntax_backslash() { - std::env::set_var("ESCAPED_VAR", "should_not_expand"); + set_env_var("ESCAPED_VAR", "should_not_expand"); // shellexpand 中反斜杠转义的行为:\$ 会展开为 \<变量值> // 这不是推荐的转义方式,此测试仅为记录实际行为 let (result, changed) = expand_env_vars(r"value=\${ESCAPED_VAR}"); @@ -143,7 +144,7 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_multiple_dollar_signs() { - std::env::set_var("TEST_VAR", "value"); + set_env_var("TEST_VAR", "value"); // 测试多个连续的 $ 符号 let (result1, changed1) = expand_env_vars("$$"); assert_eq!(result1, "$"); @@ -161,7 +162,7 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_empty_var_value() { - std::env::set_var("EMPTY_VAR", ""); + set_env_var("EMPTY_VAR", ""); let (result, changed) = expand_env_vars("value=${EMPTY_VAR}"); // 变量存在但值为空 assert_eq!(result, "value="); @@ -170,7 +171,7 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_default_with_special_chars() { - std::env::remove_var("UNDEFINED_SPECIAL"); + remove_env_var("UNDEFINED_SPECIAL"); // 测试默认值包含冒号、等号、空格等特殊字符 let (result, changed) = expand_env_vars("url=${UNDEFINED_SPECIAL:-http://localhost:8080}"); assert_eq!(result, "url=http://localhost:8080"); @@ -187,9 +188,9 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_var_name_with_numbers_underscores() { - std::env::set_var("VAR_123", "num_value"); - std::env::set_var("_VAR", "underscore_prefix"); - std::env::set_var("VAR_", "underscore_suffix"); + set_env_var("VAR_123", "num_value"); + set_env_var("_VAR", "underscore_prefix"); + set_env_var("VAR_", "underscore_suffix"); let (result1, changed1) = expand_env_vars("${VAR_123}"); assert_eq!(result1, "num_value"); @@ -214,7 +215,7 @@ uri = "tcp://127.0.0.1:${ET_PORT}" // 注意:未闭合的 ${VAR 实际上 shellexpand 会当作普通文本处理 // 它会尝试查找名为 "VAR" 的环境变量(到字符串末尾) - std::env::remove_var("VAR"); + remove_env_var("VAR"); let (result2, _changed2) = expand_env_vars("incomplete ${VAR"); // 如果 VAR 未定义,shellexpand 会返回错误或保持原样 assert_eq!(result2, "incomplete ${VAR"); @@ -224,8 +225,8 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_mixed_defined_undefined_vars() { - std::env::set_var("DEFINED_VAR", "defined"); - std::env::remove_var("UNDEFINED_VAR"); + set_env_var("DEFINED_VAR", "defined"); + remove_env_var("UNDEFINED_VAR"); // 混合已定义和未定义的变量 // shellexpand::env 在遇到未定义变量时会返回错误(默认行为) @@ -237,7 +238,7 @@ uri = "tcp://127.0.0.1:${ET_PORT}" #[test] fn test_nested_braces() { - std::env::set_var("OUTER", "outer_value"); + set_env_var("OUTER", "outer_value"); // 嵌套的大括号是无效语法,shellexpand::env 会返回错误 let (result, changed) = expand_env_vars("${OUTER} and ${{INNER}}"); // 由于语法错误,整个字符串保持不变 diff --git a/easytier/src/common/global_ctx.rs b/easytier/src/common/global_ctx.rs index 6a61b774..ed3a2286 100644 --- a/easytier/src/common/global_ctx.rs +++ b/easytier/src/common/global_ctx.rs @@ -1,5 +1,5 @@ use std::{ - collections::{hash_map::DefaultHasher, HashMap}, + collections::{HashMap, hash_map::DefaultHasher}, hash::Hasher, net::{IpAddr, SocketAddr}, sync::{Arc, Mutex}, @@ -10,11 +10,11 @@ use arc_swap::ArcSwap; use dashmap::DashMap; use super::{ + PeerId, config::{ConfigLoader, Flags}, netns::NetNS, network::IPCollector, stun::{StunInfoCollector, StunInfoCollectorTrait}, - PeerId, }; use crate::{ common::{ diff --git a/easytier/src/common/ifcfg/darwin.rs b/easytier/src/common/ifcfg/darwin.rs index 1da21e5e..b556b186 100644 --- a/easytier/src/common/ifcfg/darwin.rs +++ b/easytier/src/common/ifcfg/darwin.rs @@ -1,6 +1,6 @@ use std::net::Ipv4Addr; -use super::{cidr_to_subnet_mask, run_shell_cmd, Error, IfConfiguerTrait}; +use super::{Error, IfConfiguerTrait, cidr_to_subnet_mask, run_shell_cmd}; use async_trait::async_trait; use cidr::{Ipv4Inet, Ipv6Inet}; diff --git a/easytier/src/common/ifcfg/netlink.rs b/easytier/src/common/ifcfg/netlink.rs index 1c3550a2..13bad869 100644 --- a/easytier/src/common/ifcfg/netlink.rs +++ b/easytier/src/common/ifcfg/netlink.rs @@ -10,27 +10,27 @@ use anyhow::Context; use async_trait::async_trait; use cidr::{IpInet, Ipv4Inet, Ipv6Inet}; use netlink_packet_core::{ - NetlinkDeserializable, NetlinkHeader, NetlinkMessage, NetlinkPayload, NetlinkSerializable, - NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_EXCL, NLM_F_REQUEST, + NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_EXCL, NLM_F_REQUEST, NetlinkDeserializable, + NetlinkHeader, NetlinkMessage, NetlinkPayload, NetlinkSerializable, }; use netlink_packet_route::{ + AddressFamily, RouteNetlinkMessage, address::{AddressAttribute, AddressMessage}, route::{ RouteAddress, RouteAttribute, RouteHeader, RouteMessage, RouteProtocol, RouteScope, RouteType, }, - AddressFamily, RouteNetlinkMessage, }; -use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr}; +use netlink_sys::{Socket, SocketAddr, protocols::NETLINK_ROUTE}; use nix::{ ifaddrs::getifaddrs, - libc::{self, ifreq, ioctl, Ioctl, SIOCGIFFLAGS, SIOCGIFMTU, SIOCSIFFLAGS, SIOCSIFMTU}, + libc::{self, Ioctl, SIOCGIFFLAGS, SIOCGIFMTU, SIOCSIFFLAGS, SIOCSIFMTU, ifreq, ioctl}, net::if_::InterfaceFlags, sys::socket::SockaddrLike as _, }; use pnet::ipnetwork::ip_mask_to_prefix; -use super::{route::Route, Error, IfConfiguerTrait}; +use super::{Error, IfConfiguerTrait, route::Route}; pub(crate) fn dummy_socket() -> Result { Ok(std::net::UdpSocket::bind("0:0")?) diff --git a/easytier/src/common/ifcfg/win/luid.rs b/easytier/src/common/ifcfg/win/luid.rs index bae2316a..67405440 100644 --- a/easytier/src/common/ifcfg/win/luid.rs +++ b/easytier/src/common/ifcfg/win/luid.rs @@ -740,10 +740,6 @@ impl InterfaceLuid { // SAFETY: TODO let ret = unsafe { SetIpInterfaceEntry(&mut row) }; - if NO_ERROR == ret { - Ok(()) - } else { - Err(ret) - } + if NO_ERROR == ret { Ok(()) } else { Err(ret) } } } diff --git a/easytier/src/common/ifcfg/windows.rs b/easytier/src/common/ifcfg/windows.rs index 078219e9..35ef12f7 100644 --- a/easytier/src/common/ifcfg/windows.rs +++ b/easytier/src/common/ifcfg/windows.rs @@ -10,14 +10,14 @@ use std::{ }; use windows_sys::Win32::{ Foundation::NO_ERROR, - NetworkManagement::IpHelper::{GetIfEntry, SetIfEntry, MIB_IFROW}, + NetworkManagement::IpHelper::{GetIfEntry, MIB_IFROW, SetIfEntry}, System::Diagnostics::Debug::{ - FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, + FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessageW, }, }; use winreg::{ - enums::{HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE}, RegKey, + enums::{HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE}, }; use super::{Error, IfConfiguerTrait}; @@ -331,7 +331,7 @@ impl RegistryManager { r"SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\Tcpip_"; pub fn reg_delete_obsoleted_items(dev_name: &str) -> io::Result<()> { - use winreg::{enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS, RegKey}; + use winreg::{RegKey, enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS}; let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); let profiles_key = hklm.open_subkey_with_flags( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles", @@ -405,7 +405,7 @@ impl RegistryManager { } pub fn reg_change_catrgory_in_profile(dev_name: &str) -> io::Result<()> { - use winreg::{enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS, RegKey}; + use winreg::{RegKey, enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS}; let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); let profiles_key = hklm.open_subkey_with_flags( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles", diff --git a/easytier/src/common/log.rs b/easytier/src/common/log.rs index d6058f19..9dad049a 100644 --- a/easytier/src/common/log.rs +++ b/easytier/src/common/log.rs @@ -9,11 +9,11 @@ use paste::paste; use regex::Regex; use tracing::level_filters::LevelFilter; use tracing::{Level, Metadata}; -use tracing_subscriber::filter::{filter_fn, FilterExt}; +use tracing_subscriber::Registry; +use tracing_subscriber::filter::{FilterExt, filter_fn}; use tracing_subscriber::fmt::layer; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; -use tracing_subscriber::Registry; use tracing_subscriber::{EnvFilter, Layer}; macro_rules! __log__ { diff --git a/easytier/src/common/mod.rs b/easytier/src/common/mod.rs index 86607a54..1b8e303c 100644 --- a/easytier/src/common/mod.rs +++ b/easytier/src/common/mod.rs @@ -41,8 +41,8 @@ pub fn get_logger_timer( tracing_subscriber::fmt::time::OffsetTime::new(local_offset, format) } -pub fn get_logger_timer_rfc3339( -) -> tracing_subscriber::fmt::time::OffsetTime { +pub fn get_logger_timer_rfc3339() +-> tracing_subscriber::fmt::time::OffsetTime { get_logger_timer(time::format_description::well_known::Rfc3339) } @@ -117,10 +117,10 @@ pub fn get_machine_id() -> uuid::Uuid { .unwrap_or_else(|_| std::path::PathBuf::from("et_machine_id")); // try load from local file - if let Ok(mid) = std::fs::read_to_string(&machine_id_file) { - if let Ok(mid) = uuid::Uuid::parse_str(mid.trim()) { - return mid; - } + if let Ok(mid) = std::fs::read_to_string(&machine_id_file) + && let Ok(mid) = uuid::Uuid::parse_str(mid.trim()) + { + return mid; } #[cfg(any( diff --git a/easytier/src/common/netns.rs b/easytier/src/common/netns.rs index 95d6b3f7..25e38faf 100644 --- a/easytier/src/common/netns.rs +++ b/easytier/src/common/netns.rs @@ -1,7 +1,7 @@ use futures::Future; #[cfg(target_os = "linux")] -use nix::sched::{setns, CloneFlags}; +use nix::sched::{CloneFlags, setns}; #[cfg(target_os = "linux")] use std::os::fd::AsFd; diff --git a/easytier/src/common/stats_manager.rs b/easytier/src/common/stats_manager.rs index 2218263a..d5355759 100644 --- a/easytier/src/common/stats_manager.rs +++ b/easytier/src/common/stats_manager.rs @@ -374,7 +374,9 @@ impl UnsafeCounter { /// that no other thread is accessing this counter simultaneously. pub unsafe fn add(&self, delta: u64) { let ptr = self.value.get(); - *ptr = (*ptr).saturating_add(delta); + unsafe { + *ptr = (*ptr).saturating_add(delta); + } } /// Increment the counter by 1 @@ -382,7 +384,9 @@ impl UnsafeCounter { /// This method is unsafe because it uses UnsafeCell. The caller must ensure /// that no other thread is accessing this counter simultaneously. pub unsafe fn inc(&self) { - self.add(1); + unsafe { + self.add(1); + } } /// Get the current value of the counter @@ -391,7 +395,7 @@ impl UnsafeCounter { /// that no other thread is modifying this counter simultaneously. pub unsafe fn get(&self) -> u64 { let ptr = self.value.get(); - *ptr + unsafe { *ptr } } /// Reset the counter to zero @@ -400,7 +404,9 @@ impl UnsafeCounter { /// that no other thread is accessing this counter simultaneously. pub unsafe fn reset(&self) { let ptr = self.value.get(); - *ptr = 0; + unsafe { + *ptr = 0; + } } /// Set the counter to a specific value @@ -409,7 +415,9 @@ impl UnsafeCounter { /// that no other thread is accessing this counter simultaneously. pub unsafe fn set(&self, value: u64) { let ptr = self.value.get(); - *ptr = value; + unsafe { + *ptr = value; + } } } @@ -446,7 +454,9 @@ impl MetricData { /// that no other thread is accessing this timestamp simultaneously. unsafe fn touch(&self) { let ptr = self.last_updated.get(); - *ptr = Instant::now(); + unsafe { + *ptr = Instant::now(); + } } /// Get the last updated timestamp @@ -455,7 +465,7 @@ impl MetricData { /// that no other thread is modifying this timestamp simultaneously. unsafe fn get_last_updated(&self) -> Instant { let ptr = self.last_updated.get(); - *ptr + unsafe { *ptr } } } diff --git a/easytier/src/common/stun.rs b/easytier/src/common/stun.rs index f77e8fd7..1eebfff1 100644 --- a/easytier/src/common/stun.rs +++ b/easytier/src/common/stun.rs @@ -11,8 +11,8 @@ use crossbeam::atomic::AtomicCell; use rand::seq::IteratorRandom; use socket2::{SockAddr, SockRef}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::{lookup_host, UdpSocket}; -use tokio::sync::{broadcast, Mutex}; +use tokio::net::{UdpSocket, lookup_host}; +use tokio::sync::{Mutex, broadcast}; use tokio::task::JoinSet; use tracing::{Instrument, Level}; @@ -1340,7 +1340,7 @@ impl StunInfoCollectorTrait for MockStunInfoCollector { mod tests { use crate::{ common::scoped_task::ScopedTask, - tunnel::{udp::UdpTunnelListener, TunnelListener}, + tunnel::{TunnelListener, udp::UdpTunnelListener}, }; use tokio::time::{sleep, timeout}; @@ -1404,10 +1404,10 @@ mod tests { loop { let ret = detector.detect_nat_type(0).await; println!("{:#?}, {:?}", ret, ret.as_ref().map(|x| x.nat_type())); - if let Ok(resp) = ret { - if !resp.stun_resps.is_empty() { - return; - } + if let Ok(resp) = ret + && !resp.stun_resps.is_empty() + { + return; } sleep(Duration::from_secs(1)).await; } diff --git a/easytier/src/common/stun_codec_ext.rs b/easytier/src/common/stun_codec_ext.rs index c0139951..884645af 100644 --- a/easytier/src/common/stun_codec_ext.rs +++ b/easytier/src/common/stun_codec_ext.rs @@ -1,13 +1,13 @@ use std::net::SocketAddr; use bytecodec::fixnum::{U32beDecoder, U32beEncoder}; -use stun_codec::net::{socket_addr_xor, SocketAddrDecoder, SocketAddrEncoder}; +use stun_codec::net::{SocketAddrDecoder, SocketAddrEncoder, socket_addr_xor}; use stun_codec::rfc5389::attributes::{ MappedAddress, Software, XorMappedAddress, XorMappedAddress2, }; use stun_codec::rfc5780::attributes::{OtherAddress, ResponseOrigin}; -use stun_codec::{define_attribute_enums, AttributeType, Message, TransactionId}; +use stun_codec::{AttributeType, Message, TransactionId, define_attribute_enums}; use bytecodec::{ByteCount, Decode, Encode, Eos, Result, SizedEncode, TryTaggedDecode}; diff --git a/easytier/src/common/token_bucket.rs b/easytier/src/common/token_bucket.rs index 9c706b2f..efffe030 100644 --- a/easytier/src/common/token_bucket.rs +++ b/easytier/src/common/token_bucket.rs @@ -231,7 +231,7 @@ mod tests { }; use super::*; - use tokio::time::{sleep, Duration}; + use tokio::time::{Duration, sleep}; /// Test initial state after creation #[tokio::test] diff --git a/easytier/src/common/tracing_rolling_appender/base.rs b/easytier/src/common/tracing_rolling_appender/base.rs index 99af38dc..ababc18f 100644 --- a/easytier/src/common/tracing_rolling_appender/base.rs +++ b/easytier/src/common/tracing_rolling_appender/base.rs @@ -57,17 +57,16 @@ impl Default for RollingConditionBase { impl RollingCondition for RollingConditionBase { fn should_rollover(&mut self, now: &DateTime, current_filesize: u64) -> bool { let mut rollover = false; - if let Some(frequency) = self.frequency_opt.as_ref() { - if let Some(last_write) = self.last_write_opt.as_ref() { - if frequency.equivalent_datetime(now) != frequency.equivalent_datetime(last_write) { - rollover = true; - } - } + if let Some(frequency) = self.frequency_opt.as_ref() + && let Some(last_write) = self.last_write_opt.as_ref() + && frequency.equivalent_datetime(now) != frequency.equivalent_datetime(last_write) + { + rollover = true; } - if let Some(max_size) = self.max_size_opt.as_ref() { - if current_filesize >= *max_size { - rollover = true; - } + if let Some(max_size) = self.max_size_opt.as_ref() + && current_filesize >= *max_size + { + rollover = true; } self.last_write_opt = Some(*now); rollover diff --git a/easytier/src/common/tracing_rolling_appender/mod.rs b/easytier/src/common/tracing_rolling_appender/mod.rs index bf674d3b..2074586b 100644 --- a/easytier/src/common/tracing_rolling_appender/mod.rs +++ b/easytier/src/common/tracing_rolling_appender/mod.rs @@ -81,11 +81,7 @@ where /// Determines the final filename, where n==0 indicates the current file fn filename_for(&self, n: usize) -> String { let f = self.filename.clone(); - if n > 0 { - format!("{}.{}", f, n) - } else { - f - } + if n > 0 { format!("{}.{}", f, n) } else { f } } /// Rotates old files to make room for a new one. @@ -145,14 +141,14 @@ where /// Writes data using the given datetime to calculate the rolling condition pub fn write_with_datetime(&mut self, buf: &[u8], now: &DateTime) -> io::Result { - if self.condition.should_rollover(now, self.current_filesize) { - if let Err(e) = self.rollover() { - // If we can't rollover, just try to continue writing anyway - // (better than missing data). - // This will likely used to implement logging, so - // avoid using log::warn and log to stderr directly - eprintln!("WARNING: Failed to rotate logfile {}: {}", self.filename, e); - } + if self.condition.should_rollover(now, self.current_filesize) + && let Err(e) = self.rollover() + { + // If we can't rollover, just try to continue writing anyway + // (better than missing data). + // This will likely used to implement logging, so + // avoid using log::warn and log to stderr directly + eprintln!("WARNING: Failed to rotate logfile {}: {}", self.filename, e); } self.open_writer_if_needed()?; if let Some(writer) = self.writer_opt.as_mut() { diff --git a/easytier/src/connector/direct.rs b/easytier/src/connector/direct.rs index 00a88265..6a5b63e1 100644 --- a/easytier/src/connector/direct.rs +++ b/easytier/src/connector/direct.rs @@ -5,16 +5,16 @@ use std::{ net::{IpAddr, Ipv6Addr, SocketAddr}, str::FromStr, sync::{ - atomic::{AtomicBool, Ordering}, Arc, + atomic::{AtomicBool, Ordering}, }, time::{Duration, Instant}, }; use crate::{ common::{ - dns::socket_addrs, error::Error, global_ctx::ArcGlobalCtx, stun::StunInfoCollectorTrait, - PeerId, + PeerId, dns::socket_addrs, error::Error, global_ctx::ArcGlobalCtx, + stun::StunInfoCollectorTrait, }, connector::udp_hole_punch::handle_rpc_result, peers::{ @@ -31,7 +31,7 @@ use crate::{ }, rpc_types::controller::BaseController, }, - tunnel::{matches_protocol, udp::UdpTunnelConnector, IpVersion}, + tunnel::{IpVersion, matches_protocol, udp::UdpTunnelConnector}, use_global_var, }; @@ -39,7 +39,7 @@ use super::{ create_connector_by_url, should_background_p2p_with_peer, should_try_p2p_with_peer, udp_hole_punch, }; -use crate::tunnel::{matches_scheme, FromUrl, IpScheme, TunnelScheme}; +use crate::tunnel::{FromUrl, IpScheme, TunnelScheme, matches_scheme}; use anyhow::Context; use rand::Rng; use socket2::Protocol; @@ -769,12 +769,9 @@ mod tests { let port = if proto == "wg" { 11040 } else { 11041 }; if !ipv6 { - p_c.get_global_ctx().config.set_listeners(vec![format!( - "{}://0.0.0.0:{}", - proto, port - ) - .parse() - .unwrap()]); + p_c.get_global_ctx().config.set_listeners(vec![ + format!("{}://0.0.0.0:{}", proto, port).parse().unwrap(), + ]); } else { p_c.get_global_ctx() .config @@ -814,11 +811,12 @@ mod tests { .await .unwrap(); - assert!(data - .dst_listener_blacklist - .contains(&DstListenerUrlBlackListItem( - 1, - "tcp://127.0.0.1:10222".parse().unwrap() - ))); + assert!( + data.dst_listener_blacklist + .contains(&DstListenerUrlBlackListItem( + 1, + "tcp://127.0.0.1:10222".parse().unwrap() + )) + ); } } diff --git a/easytier/src/connector/dns_connector.rs b/easytier/src/connector/dns_connector.rs index f264a7d7..c41a5a53 100644 --- a/easytier/src/connector/dns_connector.rs +++ b/easytier/src/connector/dns_connector.rs @@ -3,7 +3,7 @@ use std::{net::SocketAddr, sync::Arc}; use super::{create_connector_by_url, http_connector::TunnelWithInfo}; use crate::{ common::{ - dns::{resolve_txt_record, RESOLVER}, + dns::{RESOLVER, resolve_txt_record}, error::Error, global_ctx::ArcGlobalCtx, log, @@ -14,7 +14,7 @@ use crate::{ use anyhow::Context; use dashmap::DashSet; use hickory_resolver::proto::rr::rdata::SRV; -use rand::{seq::SliceRandom, Rng as _}; +use rand::{Rng as _, seq::SliceRandom}; use strum::VariantArray; fn weighted_choice(options: &[(T, u64)]) -> Option<&T> { diff --git a/easytier/src/connector/http_connector.rs b/easytier/src/connector/http_connector.rs index dc133ae1..154b02a1 100644 --- a/easytier/src/connector/http_connector.rs +++ b/easytier/src/connector/http_connector.rs @@ -10,9 +10,9 @@ use rand::seq::SliceRandom as _; use url::Url; use crate::{ + VERSION, common::{error::Error, global_ctx::ArcGlobalCtx}, tunnel::{IpVersion, Tunnel, TunnelConnector, TunnelError, ZCPacketSink, ZCPacketStream}, - VERSION, }; use crate::proto::common::TunnelInfo; @@ -257,7 +257,7 @@ mod tests { use crate::{ common::global_ctx::tests::get_mock_global_ctx_with_network, - tunnel::{tcp::TcpTunnelListener, TunnelConnector, TunnelListener}, + tunnel::{TunnelConnector, TunnelListener, tcp::TcpTunnelListener}, }; use super::*; diff --git a/easytier/src/connector/manual.rs b/easytier/src/connector/manual.rs index 98bbc1a4..8e9fd902 100644 --- a/easytier/src/connector/manual.rs +++ b/easytier/src/connector/manual.rs @@ -7,7 +7,7 @@ use dashmap::DashSet; use tokio::{sync::mpsc, task::JoinSet, time::timeout}; use crate::{ - common::{dns::socket_addrs, join_joinset_background, PeerId}, + common::{PeerId, dns::socket_addrs, join_joinset_background}, peers::peer_conn::PeerConnId, proto::{ api::instance::{ diff --git a/easytier/src/connector/mod.rs b/easytier/src/connector/mod.rs index c6ab6a28..bfe8740c 100644 --- a/easytier/src/connector/mod.rs +++ b/easytier/src/connector/mod.rs @@ -8,8 +8,8 @@ use crate::{ connector::dns_connector::DnsTunnelConnector, proto::common::PeerFeatureFlag, tunnel::{ - self, ring::RingTunnelConnector, tcp::TcpTunnelConnector, udp::UdpTunnelConnector, FromUrl, - IpScheme, IpVersion, TunnelConnector, TunnelError, TunnelScheme, + self, FromUrl, IpScheme, IpVersion, TunnelConnector, TunnelError, TunnelScheme, + ring::RingTunnelConnector, tcp::TcpTunnelConnector, udp::UdpTunnelConnector, }, utils::BoxExt, }; diff --git a/easytier/src/connector/tcp_hole_punch.rs b/easytier/src/connector/tcp_hole_punch.rs index 7ce4f2b4..024ac163 100644 --- a/easytier/src/connector/tcp_hole_punch.rs +++ b/easytier/src/connector/tcp_hole_punch.rs @@ -9,7 +9,7 @@ use rand::Rng as _; use tokio::task::JoinSet; use crate::{ - common::{join_joinset_background, stun::StunInfoCollectorTrait, PeerId}, + common::{PeerId, join_joinset_background, stun::StunInfoCollectorTrait}, connector::udp_hole_punch::BackOff, peers::{ peer_manager::PeerManager, @@ -24,8 +24,8 @@ use crate::{ rpc_types::{self, controller::BaseController}, }, tunnel::{ - tcp::{TcpTunnelConnector, TcpTunnelListener}, TunnelConnector as _, TunnelListener as _, + tcp::{TcpTunnelConnector, TcpTunnelListener}, }, }; @@ -719,18 +719,20 @@ mod tests { tokio::time::sleep(Duration::from_secs(2)).await; - assert!(p_a - .get_peer_map() - .list_peer_conns(p_c.my_peer_id()) - .await - .map(|c| c.is_empty()) - .unwrap_or(true)); - assert!(p_c - .get_peer_map() - .list_peer_conns(p_a.my_peer_id()) - .await - .map(|c| c.is_empty()) - .unwrap_or(true)); + assert!( + p_a.get_peer_map() + .list_peer_conns(p_c.my_peer_id()) + .await + .map(|c| c.is_empty()) + .unwrap_or(true) + ); + assert!( + p_c.get_peer_map() + .list_peer_conns(p_a.my_peer_id()) + .await + .map(|c| c.is_empty()) + .unwrap_or(true) + ); } #[tokio::test] @@ -751,14 +753,18 @@ mod tests { connect_peer_manager(p_b.clone(), p_c.clone()).await; wait_route_appear(p_a.clone(), p_c.clone()).await.unwrap(); - assert!(!collect_lazy_punch_peers(p_a.clone()) - .await - .contains(&p_c.my_peer_id())); + assert!( + !collect_lazy_punch_peers(p_a.clone()) + .await + .contains(&p_c.my_peer_id()) + ); p_a.mark_recent_traffic(p_c.my_peer_id()); - assert!(collect_lazy_punch_peers(p_a.clone()) - .await - .contains(&p_c.my_peer_id())); + assert!( + collect_lazy_punch_peers(p_a.clone()) + .await + .contains(&p_c.my_peer_id()) + ); } } diff --git a/easytier/src/connector/udp_hole_punch/both_easy_sym.rs b/easytier/src/connector/udp_hole_punch/both_easy_sym.rs index 6db6c0d3..87f49538 100644 --- a/easytier/src/connector/udp_hole_punch/both_easy_sym.rs +++ b/easytier/src/connector/udp_hole_punch/both_easy_sym.rs @@ -8,9 +8,9 @@ use anyhow::Context; use tokio::sync::Mutex; use crate::{ - common::{scoped_task::ScopedTask, stun::StunInfoCollectorTrait, PeerId}, + common::{PeerId, scoped_task::ScopedTask, stun::StunInfoCollectorTrait}, connector::udp_hole_punch::common::{ - try_connect_with_socket, UdpHolePunchListener, HOLE_PUNCH_PACKET_BODY_LEN, + HOLE_PUNCH_PACKET_BODY_LEN, UdpHolePunchListener, try_connect_with_socket, }, connector::udp_hole_punch::handle_rpc_result, peers::peer_manager::PeerManager, @@ -21,7 +21,7 @@ use crate::{ }, rpc_types::{self, controller::BaseController}, }, - tunnel::{udp::new_hole_punch_packet, Tunnel}, + tunnel::{Tunnel, udp::new_hole_punch_packet}, }; use super::common::{PunchHoleServerCommon, UdpNatType, UdpSocketArray}; @@ -340,7 +340,7 @@ impl PunchBothEasySymHoleClient { #[cfg(test)] pub mod tests { use std::{ - sync::{atomic::AtomicU32, Arc}, + sync::{Arc, atomic::AtomicU32}, time::Duration, }; @@ -349,7 +349,7 @@ pub mod tests { use crate::connector::udp_hole_punch::RUN_TESTING; use crate::{ connector::udp_hole_punch::{ - tests::create_mock_peer_manager_with_mock_stun, UdpHolePunchConnector, + UdpHolePunchConnector, tests::create_mock_peer_manager_with_mock_stun, }, peers::tests::{connect_peer_manager, wait_route_appear}, proto::common::NatType, diff --git a/easytier/src/connector/udp_hole_punch/common.rs b/easytier/src/connector/udp_hole_punch/common.rs index 30b2620b..c99b8094 100644 --- a/easytier/src/connector/udp_hole_punch/common.rs +++ b/easytier/src/connector/udp_hole_punch/common.rs @@ -8,21 +8,21 @@ use crossbeam::atomic::AtomicCell; use dashmap::{DashMap, DashSet}; use rand::seq::SliceRandom as _; use tokio::{net::UdpSocket, sync::Mutex, task::JoinSet}; -use tracing::{instrument, Instrument, Level}; +use tracing::{Instrument, Level, instrument}; use zerocopy::FromBytes as _; use crate::{ common::{ - error::Error, global_ctx::ArcGlobalCtx, join_joinset_background, netns::NetNS, - stun::StunInfoCollectorTrait as _, PeerId, + PeerId, error::Error, global_ctx::ArcGlobalCtx, join_joinset_background, netns::NetNS, + stun::StunInfoCollectorTrait as _, }, defer, peers::peer_manager::PeerManager, proto::common::NatType, tunnel::{ - packet_def::{UDPTunnelHeader, UdpPacketType, UDP_TUNNEL_HEADER_SIZE}, - udp::{new_hole_punch_packet, UdpTunnelConnector, UdpTunnelListener}, Tunnel, TunnelConnCounter, TunnelListener as _, + packet_def::{UDP_TUNNEL_HEADER_SIZE, UDPTunnelHeader, UdpPacketType}, + udp::{UdpTunnelConnector, UdpTunnelListener, new_hole_punch_packet}, }, }; diff --git a/easytier/src/connector/udp_hole_punch/cone.rs b/easytier/src/connector/udp_hole_punch/cone.rs index 69b2d761..a88eb5c7 100644 --- a/easytier/src/connector/udp_hole_punch/cone.rs +++ b/easytier/src/connector/udp_hole_punch/cone.rs @@ -7,9 +7,9 @@ use anyhow::Context; use tokio::net::UdpSocket; use crate::{ - common::{scoped_task::ScopedTask, stun::StunInfoCollectorTrait, PeerId}, + common::{PeerId, scoped_task::ScopedTask, stun::StunInfoCollectorTrait}, connector::udp_hole_punch::common::{ - try_connect_with_socket, UdpSocketArray, HOLE_PUNCH_PACKET_BODY_LEN, + HOLE_PUNCH_PACKET_BODY_LEN, UdpSocketArray, try_connect_with_socket, }, connector::udp_hole_punch::handle_rpc_result, peers::peer_manager::PeerManager, @@ -20,7 +20,7 @@ use crate::{ }, rpc_types::{self, controller::BaseController}, }, - tunnel::{udp::new_hole_punch_packet, Tunnel}, + tunnel::{Tunnel, udp::new_hole_punch_packet}, }; use super::common::PunchHoleServerCommon; @@ -249,7 +249,7 @@ pub mod tests { use crate::{ connector::udp_hole_punch::{ - tests::create_mock_peer_manager_with_mock_stun, UdpHolePunchConnector, + UdpHolePunchConnector, tests::create_mock_peer_manager_with_mock_stun, }, peers::tests::{connect_peer_manager, wait_route_appear, wait_route_appear_with_cost}, proto::common::NatType, diff --git a/easytier/src/connector/udp_hole_punch/mod.rs b/easytier/src/connector/udp_hole_punch/mod.rs index 66197d01..779d428b 100644 --- a/easytier/src/connector/udp_hole_punch/mod.rs +++ b/easytier/src/connector/udp_hole_punch/mod.rs @@ -1,5 +1,5 @@ use std::{ - sync::{atomic::AtomicBool, Arc}, + sync::{Arc, atomic::AtomicBool}, time::{Duration, Instant}, }; @@ -13,7 +13,7 @@ use sym_to_cone::{PunchSymToConeHoleClient, PunchSymToConeHoleServer}; use tokio::{sync::Mutex, task::JoinHandle}; use crate::{ - common::{stun::StunInfoCollectorTrait, PeerId}, + common::{PeerId, stun::StunInfoCollectorTrait}, peers::{ peer_manager::PeerManager, peer_task::{PeerTaskLauncher, PeerTaskManager}, @@ -601,7 +601,7 @@ pub mod tests { use crate::proto::common::NatType; use crate::tunnel::common::tests::wait_for_condition; - use super::{UdpHolePunchConnector, UdpHolePunchPeerTaskLauncher, RUN_TESTING}; + use super::{RUN_TESTING, UdpHolePunchConnector, UdpHolePunchPeerTaskLauncher}; pub fn replace_stun_info_collector(peer_mgr: Arc, udp_nat_type: NatType) { let collector = Box::new(MockStunInfoCollector { udp_nat_type }); @@ -676,14 +676,18 @@ pub mod tests { connect_peer_manager(p_b.clone(), p_c.clone()).await; wait_route_appear(p_a.clone(), p_c.clone()).await.unwrap(); - assert!(!collect_lazy_punch_peers(p_a.clone()) - .await - .contains(&p_c.my_peer_id())); + assert!( + !collect_lazy_punch_peers(p_a.clone()) + .await + .contains(&p_c.my_peer_id()) + ); p_a.mark_recent_traffic(p_c.my_peer_id()); - assert!(collect_lazy_punch_peers(p_a.clone()) - .await - .contains(&p_c.my_peer_id())); + assert!( + collect_lazy_punch_peers(p_a.clone()) + .await + .contains(&p_c.my_peer_id()) + ); } } diff --git a/easytier/src/connector/udp_hole_punch/sym_to_cone.rs b/easytier/src/connector/udp_hole_punch/sym_to_cone.rs index c66bc531..fc8973b4 100644 --- a/easytier/src/connector/udp_hole_punch/sym_to_cone.rs +++ b/easytier/src/connector/udp_hole_punch/sym_to_cone.rs @@ -2,24 +2,24 @@ use std::{ net::Ipv4Addr, ops::{Div, Mul}, sync::{ - atomic::{AtomicBool, Ordering}, Arc, + atomic::{AtomicBool, Ordering}, }, time::{Duration, Instant}, }; use anyhow::Context; -use rand::{seq::SliceRandom, Rng}; +use rand::{Rng, seq::SliceRandom}; use tokio::{net::UdpSocket, sync::RwLock}; use tracing::Level; use crate::{ common::{ - global_ctx::ArcGlobalCtx, scoped_task::ScopedTask, stun::StunInfoCollectorTrait, PeerId, + PeerId, global_ctx::ArcGlobalCtx, scoped_task::ScopedTask, stun::StunInfoCollectorTrait, }, connector::udp_hole_punch::{ common::{ - send_symmetric_hole_punch_packet, try_connect_with_socket, HOLE_PUNCH_PACKET_BODY_LEN, + HOLE_PUNCH_PACKET_BODY_LEN, send_symmetric_hole_punch_packet, try_connect_with_socket, }, handle_rpc_result, }, @@ -33,7 +33,7 @@ use crate::{ }, rpc_types::{self, controller::BaseController}, }, - tunnel::{udp::new_hole_punch_packet, Tunnel}, + tunnel::{Tunnel, udp::new_hole_punch_packet}, }; use super::common::{PunchHoleServerCommon, UdpNatType, UdpSocketArray}; @@ -445,16 +445,15 @@ impl PunchSymToConeHoleClient { ))?; // try direct connect first - if self.try_direct_connect.load(Ordering::Relaxed) { - if let Ok(tunnel) = try_connect_with_socket( + if self.try_direct_connect.load(Ordering::Relaxed) + && let Ok(tunnel) = try_connect_with_socket( global_ctx.clone(), Arc::new(UdpSocket::bind("0.0.0.0:0").await?), remote_mapped_addr.into(), ) .await - { - return Ok(Some(tunnel)); - } + { + return Ok(Some(tunnel)); } let stun_info = global_ctx.get_stun_info_collector().get_stun_info(); @@ -467,7 +466,7 @@ impl PunchSymToConeHoleClient { return Err(anyhow::anyhow!("failed to get public ips")); } - let tid = rand::thread_rng().gen(); + let tid = rand::thread_rng().r#gen(); let packet = new_hole_punch_packet(tid, HOLE_PUNCH_PACKET_BODY_LEN).into_bytes(); udp_array.add_intreast_tid(tid); defer! { udp_array.remove_intreast_tid(tid);} @@ -544,7 +543,7 @@ impl PunchSymToConeHoleClient { #[cfg(test)] pub mod tests { use std::{ - sync::{atomic::AtomicU32, Arc}, + sync::{Arc, atomic::AtomicU32}, time::Duration, }; @@ -552,7 +551,7 @@ pub mod tests { use crate::{ connector::udp_hole_punch::{ - tests::create_mock_peer_manager_with_mock_stun, UdpHolePunchConnector, RUN_TESTING, + RUN_TESTING, UdpHolePunchConnector, tests::create_mock_peer_manager_with_mock_stun, }, peers::tests::{connect_peer_manager, wait_route_appear, wait_route_appear_with_cost}, proto::common::NatType, @@ -617,7 +616,7 @@ pub mod tests { .await .is_ok() }, - Duration::from_secs(30), + Duration::from_secs(60), ) .await; println!("{:?}", p_a.list_routes().await); diff --git a/easytier/src/core.rs b/easytier/src/core.rs index 4f01f805..44f667d1 100644 --- a/easytier/src/core.rs +++ b/easytier/src/core.rs @@ -4,15 +4,16 @@ use std::{ net::{IpAddr, SocketAddr}, path::PathBuf, process::ExitCode, - sync::{atomic::AtomicBool, Arc}, + sync::{Arc, atomic::AtomicBool}, }; use crate::{ + ShellType, common::{ config::{ - load_config_from_file, process_secure_mode_cfg, ConfigFileControl, ConfigLoader, - ConsoleLoggerConfig, EncryptionAlgorithm, FileLoggerConfig, LoggingConfigLoader, - NetworkIdentity, PeerConfig, PortForwardConfig, TomlConfigLoader, VpnPortalConfig, + ConfigFileControl, ConfigLoader, ConsoleLoggerConfig, EncryptionAlgorithm, + FileLoggerConfig, LoggingConfigLoader, NetworkIdentity, PeerConfig, PortForwardConfig, + TomlConfigLoader, VpnPortalConfig, load_config_from_file, process_secure_mode_cfg, }, constants::EASYTIER_VERSION, log, @@ -23,7 +24,7 @@ use crate::{ proto::common::{CompressionAlgoPb, SecureModeConfig}, rpc_service::ApiRpcServer, utils::setup_panic_handler, - web_client, ShellType, + web_client, }; use anyhow::Context; use cidr::IpCidr; @@ -34,7 +35,7 @@ use tokio::io::AsyncReadExt; use crate::tunnel::IpScheme; #[cfg(feature = "jemalloc-prof")] -use jemalloc_ctl::{epoch, stats, Access as _, AsName as _}; +use jemalloc_ctl::{Access as _, AsName as _, epoch, stats}; #[cfg(target_os = "windows")] windows_service::define_windows_service!(ffi_service_main, win_service_main); @@ -741,17 +742,17 @@ impl Cli { let origin_listeners = listeners; let mut listeners: Vec = Vec::new(); - if origin_listeners.len() == 1 { - if let Ok(port) = origin_listeners[0].parse::() { - for proto in IpScheme::VARIANTS { - listeners.push(format!( - "{}://0.0.0.0:{}", - proto, - port + proto.port_offset() - )); - } - return Ok(listeners); + if origin_listeners.len() == 1 + && let Ok(port) = origin_listeners[0].parse::() + { + for proto in IpScheme::VARIANTS { + listeners.push(format!( + "{}://0.0.0.0:{}", + proto, + port + proto.port_offset() + )); } + return Ok(listeners); } for l in &origin_listeners { @@ -994,15 +995,15 @@ impl NetworkOptions { local_public_key: None, }; cfg.set_secure_mode(Some(process_secure_mode_cfg(c)?)); - } else if let Some(secure_mode) = self.secure_mode { - if secure_mode { - let c = SecureModeConfig { - enabled: secure_mode, - local_private_key: self.local_private_key.clone(), - local_public_key: self.local_public_key.clone(), - }; - cfg.set_secure_mode(Some(process_secure_mode_cfg(c)?)); - } + } else if let Some(secure_mode) = self.secure_mode + && secure_mode + { + let c = SecureModeConfig { + enabled: secure_mode, + local_private_key: self.local_private_key.clone(), + local_public_key: self.local_public_key.clone(), + }; + cfg.set_secure_mode(Some(process_secure_mode_cfg(c)?)); } let mut f = cfg.get_flags(); @@ -1134,7 +1135,7 @@ impl LoggingConfigLoader for &LoggingOptions { #[cfg(target_os = "windows")] fn win_service_set_work_dir(service_name: &std::ffi::OsString) -> anyhow::Result<()> { use crate::common::constants::WIN_SERVICE_WORK_DIR_REG_KEY; - use winreg::{enums::*, RegKey}; + use winreg::{RegKey, enums::*}; let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); let key = hklm.open_subkey_with_flags(WIN_SERVICE_WORK_DIR_REG_KEY, KEY_READ)?; diff --git a/easytier/src/easytier-cli.rs b/easytier/src/easytier-cli.rs index f4555f1f..af55343d 100644 --- a/easytier/src/easytier-cli.rs +++ b/easytier/src/easytier-cli.rs @@ -12,8 +12,8 @@ use std::{ }; use anyhow::Context; -use base64::prelude::BASE64_STANDARD; use base64::Engine as _; +use base64::prelude::BASE64_STANDARD; use cidr::Ipv4Inet; use clap::{Args, CommandFactory, Parser, Subcommand}; use dashmap::DashMap; @@ -21,8 +21,8 @@ use easytier::ShellType; use humansize::format_size; use rust_i18n::t; use service_manager::*; -use tabled::settings::{location::ByColumnName, object::Columns, Disable, Modify, Style, Width}; -use terminal_size::{terminal_size, Width as TerminalWidth}; +use tabled::settings::{Disable, Modify, Style, Width, location::ByColumnName, object::Columns}; +use terminal_size::{Width as TerminalWidth, terminal_size}; use unicode_width::UnicodeWidthStr; use easytier::service_manager::{Service, ServiceInstallOptions}; @@ -42,9 +42,7 @@ use easytier::{ InstanceConfigPatch, PatchConfigRequest, PortForwardPatch, StringPatch, UrlPatch, }, instance::{ - instance_identifier::{InstanceSelector, Selector}, - list_global_foreign_network_response, list_peer_route_pair, AclManageRpc, - AclManageRpcClientFactory, Connector, ConnectorManageRpc, + AclManageRpc, AclManageRpcClientFactory, Connector, ConnectorManageRpc, ConnectorManageRpcClientFactory, CredentialManageRpc, CredentialManageRpcClientFactory, DumpRouteRequest, ForeignNetworkEntryPb, GenerateCredentialRequest, GetAclStatsRequest, GetPrometheusStatsRequest, @@ -60,6 +58,8 @@ use easytier::{ StatsRpc, StatsRpcClientFactory, TcpProxyEntryState, TcpProxyEntryTransportType, TcpProxyRpc, TcpProxyRpcClientFactory, TrustedKeySourcePb, VpnPortalInfo, VpnPortalRpc, VpnPortalRpcClientFactory, + instance_identifier::{InstanceSelector, Selector}, + list_global_foreign_network_response, list_peer_route_pair, }, logger::{ GetLoggerConfigRequest, LogLevel, LoggerRpc, LoggerRpcClientFactory, @@ -75,8 +75,8 @@ use easytier::{ rpc_impl::standalone::StandAloneClient, rpc_types::controller::BaseController, }, - tunnel::{tcp::TcpTunnelConnector, TunnelScheme}, - utils::{cost_to_str, PeerRoutePair}, + tunnel::{TunnelScheme, tcp::TcpTunnelConnector}, + utils::{PeerRoutePair, cost_to_str}, }; rust_i18n::i18n!("locales", fallback = "en"); @@ -1972,7 +1972,12 @@ impl<'a> CommandHandler<'a> { "info" => LogLevel::Info, "debug" => LogLevel::Debug, "trace" => LogLevel::Trace, - _ => return Err(anyhow::anyhow!("Invalid log level: {}. Valid levels are: disabled, error, warning, info, debug, trace", level)), + _ => { + return Err(anyhow::anyhow!( + "Invalid log level: {}. Valid levels are: disabled, error, warning, info, debug, trace", + level + )); + } }; let client = self.get_logger_client().await?; @@ -2497,10 +2502,9 @@ fn header_indices(headers: &[String], names: &[&str]) -> Vec { if let Some(index) = headers .iter() .position(|header| header.eq_ignore_ascii_case(name)) + && !indices.contains(&index) { - if !indices.contains(&index) { - indices.push(index); - } + indices.push(index); } } indices diff --git a/easytier/src/easytier-core.rs b/easytier/src/easytier-core.rs index 656b138a..03cf30b4 100644 --- a/easytier/src/easytier-core.rs +++ b/easytier/src/easytier-core.rs @@ -13,12 +13,12 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; #[cfg(feature = "jemalloc-prof")] #[allow(non_upper_case_globals)] -#[export_name = "malloc_conf"] +#[unsafe(export_name = "malloc_conf")] pub static malloc_conf: &[u8] = b"prof:true,prof_active:true,lg_prof_sample:19,retain:false\0"; #[cfg(not(feature = "jemalloc-prof"))] #[allow(non_upper_case_globals)] -#[export_name = "malloc_conf"] +#[unsafe(export_name = "malloc_conf")] pub static malloc_conf: &[u8] = b"retain:false\0"; rust_i18n::i18n!("locales", fallback = "en"); diff --git a/easytier/src/gateway/fast_socks5/mod.rs b/easytier/src/gateway/fast_socks5/mod.rs index 73e32e87..424f0816 100644 --- a/easytier/src/gateway/fast_socks5/mod.rs +++ b/easytier/src/gateway/fast_socks5/mod.rs @@ -46,9 +46,9 @@ use anyhow::Context; use std::fmt; use std::io; use thiserror::Error; -use util::target_addr::read_address; use util::target_addr::TargetAddr; use util::target_addr::ToTargetAddr; +use util::target_addr::read_address; use tokio::io::AsyncReadExt; diff --git a/easytier/src/gateway/fast_socks5/server.rs b/easytier/src/gateway/fast_socks5/server.rs index 82e7d52d..5eea5aaf 100644 --- a/easytier/src/gateway/fast_socks5/server.rs +++ b/easytier/src/gateway/fast_socks5/server.rs @@ -1,10 +1,10 @@ +use super::Socks5Command; use super::new_udp_header; use super::parse_udp_request; use super::read_exact; use super::util::stream::tcp_connect_with_timeout; -use super::util::target_addr::{read_address, TargetAddr}; -use super::Socks5Command; -use super::{consts, AuthenticationMethod, ReplyError, Result, SocksError}; +use super::util::target_addr::{TargetAddr, read_address}; +use super::{AuthenticationMethod, ReplyError, Result, SocksError, consts}; use anyhow::Context; use std::io; use std::net::IpAddr; diff --git a/easytier/src/gateway/fast_socks5/util/target_addr.rs b/easytier/src/gateway/fast_socks5/util/target_addr.rs index c0ac8e0c..76833a2c 100644 --- a/easytier/src/gateway/fast_socks5/util/target_addr.rs +++ b/easytier/src/gateway/fast_socks5/util/target_addr.rs @@ -1,6 +1,6 @@ +use crate::gateway::fast_socks5::SocksError; use crate::gateway::fast_socks5::consts; use crate::gateway::fast_socks5::consts::SOCKS5_ADDR_TYPE_IPV4; -use crate::gateway::fast_socks5::SocksError; use crate::read_exact; use anyhow::Context; @@ -99,7 +99,7 @@ impl TargetAddr { buf.extend_from_slice(&(addr.ip()).octets()); // ip buf.extend_from_slice(&addr.port().to_be_bytes()); // port } - TargetAddr::Domain(ref domain, port) => { + TargetAddr::Domain(domain, port) => { debug!("TargetAddr::Domain"); if domain.len() > u8::MAX as usize { return Err(SocksError::ExceededMaxDomainLen(domain.len()).into()); diff --git a/easytier/src/gateway/icmp_proxy.rs b/easytier/src/gateway/icmp_proxy.rs index 40ad3485..0e0182d2 100644 --- a/easytier/src/gateway/icmp_proxy.rs +++ b/easytier/src/gateway/icmp_proxy.rs @@ -8,29 +8,29 @@ use std::{ use anyhow::Context; use pnet::packet::{ - icmp::{self, echo_reply::MutableEchoReplyPacket, IcmpCode, IcmpTypes, MutableIcmpPacket}, + Packet, + icmp::{self, IcmpCode, IcmpTypes, MutableIcmpPacket, echo_reply::MutableEchoReplyPacket}, ip::IpNextHeaderProtocols, ipv4::Ipv4Packet, - Packet, }; use socket2::Socket; use tokio::{ - sync::{mpsc::UnboundedSender, Mutex}, + sync::{Mutex, mpsc::UnboundedSender}, task::JoinSet, }; use tracing::Instrument; use crate::{ - common::{error::Error, global_ctx::ArcGlobalCtx, PeerId}, + common::{PeerId, error::Error, global_ctx::ArcGlobalCtx}, gateway::ip_reassembler::ComposeIpv4PacketArgs, - peers::{peer_manager::PeerManager, PeerPacketFilter}, + peers::{PeerPacketFilter, peer_manager::PeerManager}, tunnel::packet_def::{PacketType, ZCPacket}, }; use super::{ - ip_reassembler::{compose_ipv4_packet, IpReassembler}, CidrSet, + ip_reassembler::{IpReassembler, compose_ipv4_packet}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/easytier/src/gateway/ip_reassembler.rs b/easytier/src/gateway/ip_reassembler.rs index be579d7c..543429aa 100644 --- a/easytier/src/gateway/ip_reassembler.rs +++ b/easytier/src/gateway/ip_reassembler.rs @@ -1,7 +1,7 @@ use dashmap::DashMap; +use pnet::packet::Packet; use pnet::packet::ip::IpNextHeaderProtocol; use pnet::packet::ipv4::{self, Ipv4Flags, Ipv4Packet, MutableIpv4Packet}; -use pnet::packet::Packet; use std::net::Ipv4Addr; use std::time::{Duration, Instant}; @@ -45,13 +45,25 @@ impl IpPacket { // make sure the fragment doesn't overlap with existing fragments for f in &self.fragments { if f.offset <= fragment.offset && fragment.offset < f.offset + f.data.len() as u16 { - tracing::trace!("fragment overlap 1, f.offset = {}, fragment.offset = {}, f.data.len() = {}, fragment.data.len() = {}", f.offset, fragment.offset, f.data.len(), fragment.data.len()); + tracing::trace!( + "fragment overlap 1, f.offset = {}, fragment.offset = {}, f.data.len() = {}, fragment.data.len() = {}", + f.offset, + fragment.offset, + f.data.len(), + fragment.data.len() + ); return; } if fragment.offset <= f.offset && f.offset < fragment.offset + fragment.data.len() as u16 { - tracing::trace!("fragment overlap 2, f.offset = {}, fragment.offset = {}, f.data.len() = {}, fragment.data.len() = {}", f.offset, fragment.offset, f.data.len(), fragment.data.len()); + tracing::trace!( + "fragment overlap 2, f.offset = {}, fragment.offset = {}, f.data.len() = {}, fragment.data.len() = {}", + f.offset, + fragment.offset, + f.data.len(), + fragment.data.len() + ); return; } } diff --git a/easytier/src/gateway/kcp_proxy.rs b/easytier/src/gateway/kcp_proxy.rs index 37ddbab7..53dbbbfa 100644 --- a/easytier/src/gateway/kcp_proxy.rs +++ b/easytier/src/gateway/kcp_proxy.rs @@ -17,8 +17,8 @@ use prost::Message; use tokio::{select, task::JoinSet}; use super::{ - tcp_proxy::{NatDstConnector, NatDstTcpConnector, TcpProxy}, CidrSet, + tcp_proxy::{NatDstConnector, NatDstTcpConnector, TcpProxy}, }; use crate::{ common::{ @@ -27,7 +27,7 @@ use crate::{ global_ctx::{ArcGlobalCtx, GlobalCtx}, }, gateway::wrapped_proxy::{ProxyAclHandler, TcpProxyForWrappedSrcTrait}, - peers::{peer_manager::PeerManager, PeerPacketFilter}, + peers::{PeerPacketFilter, peer_manager::PeerManager}, proto::{ acl::{ChainType, Protocol}, api::instance::{ diff --git a/easytier/src/gateway/quic_proxy.rs b/easytier/src/gateway/quic_proxy.rs index 4178cc03..743a9b88 100644 --- a/easytier/src/gateway/quic_proxy.rs +++ b/easytier/src/gateway/quic_proxy.rs @@ -1,11 +1,11 @@ +use crate::common::PeerId; use crate::common::acl_processor::PacketInfo; use crate::common::global_ctx::{ArcGlobalCtx, GlobalCtx}; -use crate::common::PeerId; +use crate::gateway::CidrSet; use crate::gateway::tcp_proxy::{NatDstConnector, TcpProxy}; use crate::gateway::wrapped_proxy::{ProxyAclHandler, TcpProxyForWrappedSrcTrait}; -use crate::gateway::CidrSet; -use crate::peers::peer_manager::PeerManager; use crate::peers::PeerPacketFilter; +use crate::peers::peer_manager::PeerManager; use crate::proto::acl::{ChainType, Protocol}; use crate::proto::api::instance::{ ListTcpProxyEntryRequest, ListTcpProxyEntryResponse, TcpProxyEntry, TcpProxyEntryState, @@ -15,10 +15,10 @@ use crate::proto::peer_rpc::KcpConnData as QuicConnData; use crate::proto::rpc_types; use crate::proto::rpc_types::controller::BaseController; use crate::tunnel::packet_def::{ - PacketType, PeerManagerHeader, ZCPacket, ZCPacketType, TAIL_RESERVED_SIZE, + PacketType, PeerManagerHeader, TAIL_RESERVED_SIZE, ZCPacket, ZCPacketType, }; use crate::tunnel::quic::{client_config, endpoint_config, server_config}; -use anyhow::{anyhow, Context, Error}; +use anyhow::{Context, Error, anyhow}; use atomic_refcell::AtomicRefCell; use bytes::{BufMut, Bytes, BytesMut}; use dashmap::DashMap; @@ -36,11 +36,11 @@ use std::ptr::copy_nonoverlapping; use std::sync::{Arc, Weak}; use std::task::Poll; use std::time::Duration; -use tokio::io::{join, AsyncReadExt, Join}; +use tokio::io::{AsyncReadExt, Join, join}; use tokio::sync::mpsc::error::TrySendError; -use tokio::sync::mpsc::{channel, Receiver, Sender}; +use tokio::sync::mpsc::{Receiver, Sender, channel}; use tokio::task::JoinSet; -use tokio::time::{timeout, Instant}; +use tokio::time::{Instant, timeout}; use tokio::{join, pin, select}; use tokio_util::sync::PollSender; use tracing::{debug, error, info, instrument, trace, warn}; @@ -174,9 +174,7 @@ impl AsyncUdpSocket for QuicSocket { } trace!( "{:?} received {:?} bytes from {:?}", - self.addr, - len, - packet.addr + self.addr, len, packet.addr ); buf[0..len].copy_from_slice(&packet.payload); *meta = RecvMeta { @@ -193,7 +191,7 @@ impl AsyncUdpSocket for QuicSocket { return Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::ConnectionAborted, "socket closed", - ))) + ))); } Poll::Pending => break, } @@ -1250,7 +1248,7 @@ mod tests { // We agree that the first byte of data is (stream_index % 255) // This ensures stream data is not mixed let expected_byte = data[0] as usize; // Get the actual received marker - // Simple check of head and tail here, CRC can be used in production + // Simple check of head and tail here, CRC can be used in production if data[data.len() - 1] != data[0] { panic!("Stream data corruption"); } diff --git a/easytier/src/gateway/socks5.rs b/easytier/src/gateway/socks5.rs index ff31c4e9..7b19ffff 100644 --- a/easytier/src/gateway/socks5.rs +++ b/easytier/src/gateway/socks5.rs @@ -2,8 +2,8 @@ use std::{ any::Any, net::{IpAddr, Ipv4Addr, SocketAddr}, sync::{ - atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, Weak, + atomic::{AtomicBool, AtomicUsize, Ordering}, }, time::{Duration, Instant}, }; @@ -28,7 +28,7 @@ use crate::{ util::stream::tcp_connect_with_timeout, }, ip_reassembler::IpReassembler, - tokio_smoltcp::{channel_device, BufferSize, Net, NetConfig}, + tokio_smoltcp::{BufferSize, Net, NetConfig, channel_device}, }, tunnel::{ common::setup_sokcet2, @@ -38,20 +38,20 @@ use crate::{ use anyhow::Context; use dashmap::DashMap; use pnet::packet::{ - ip::IpNextHeaderProtocols, ipv4::Ipv4Packet, tcp::TcpPacket, udp::UdpPacket, Packet, + Packet, ip::IpNextHeaderProtocols, ipv4::Ipv4Packet, tcp::TcpPacket, udp::UdpPacket, }; use tokio::{ io::{AsyncRead, AsyncWrite}, net::{TcpListener, TcpSocket, UdpSocket}, select, - sync::{mpsc, Mutex, Notify}, + sync::{Mutex, Notify, mpsc}, task::JoinSet, time::timeout, }; use crate::{ common::{error::Error, global_ctx::GlobalCtx}, - peers::{peer_manager::PeerManager, PeerPacketFilter}, + peers::{PeerPacketFilter, peer_manager::PeerManager}, }; #[cfg(feature = "kcp")] @@ -92,12 +92,10 @@ impl AsyncRead for SocksTcpStream { buf: &mut tokio::io::ReadBuf<'_>, ) -> std::task::Poll> { match self.get_mut() { - SocksTcpStream::Tcp(ref mut stream) => std::pin::Pin::new(stream).poll_read(cx, buf), - SocksTcpStream::SmolTcp(ref mut stream) => { - std::pin::Pin::new(stream).poll_read(cx, buf) - } + SocksTcpStream::Tcp(stream) => std::pin::Pin::new(stream).poll_read(cx, buf), + SocksTcpStream::SmolTcp(stream) => std::pin::Pin::new(stream).poll_read(cx, buf), #[cfg(feature = "kcp")] - SocksTcpStream::Kcp(ref mut stream) => std::pin::Pin::new(stream).poll_read(cx, buf), + SocksTcpStream::Kcp(stream) => std::pin::Pin::new(stream).poll_read(cx, buf), } } } @@ -109,12 +107,10 @@ impl AsyncWrite for SocksTcpStream { buf: &[u8], ) -> std::task::Poll> { match self.get_mut() { - SocksTcpStream::Tcp(ref mut stream) => std::pin::Pin::new(stream).poll_write(cx, buf), - SocksTcpStream::SmolTcp(ref mut stream) => { - std::pin::Pin::new(stream).poll_write(cx, buf) - } + SocksTcpStream::Tcp(stream) => std::pin::Pin::new(stream).poll_write(cx, buf), + SocksTcpStream::SmolTcp(stream) => std::pin::Pin::new(stream).poll_write(cx, buf), #[cfg(feature = "kcp")] - SocksTcpStream::Kcp(ref mut stream) => std::pin::Pin::new(stream).poll_write(cx, buf), + SocksTcpStream::Kcp(stream) => std::pin::Pin::new(stream).poll_write(cx, buf), } } @@ -123,10 +119,10 @@ impl AsyncWrite for SocksTcpStream { cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { match self.get_mut() { - SocksTcpStream::Tcp(ref mut stream) => std::pin::Pin::new(stream).poll_flush(cx), - SocksTcpStream::SmolTcp(ref mut stream) => std::pin::Pin::new(stream).poll_flush(cx), + SocksTcpStream::Tcp(stream) => std::pin::Pin::new(stream).poll_flush(cx), + SocksTcpStream::SmolTcp(stream) => std::pin::Pin::new(stream).poll_flush(cx), #[cfg(feature = "kcp")] - SocksTcpStream::Kcp(ref mut stream) => std::pin::Pin::new(stream).poll_flush(cx), + SocksTcpStream::Kcp(stream) => std::pin::Pin::new(stream).poll_flush(cx), } } @@ -135,10 +131,10 @@ impl AsyncWrite for SocksTcpStream { cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { match self.get_mut() { - SocksTcpStream::Tcp(ref mut stream) => std::pin::Pin::new(stream).poll_shutdown(cx), - SocksTcpStream::SmolTcp(ref mut stream) => std::pin::Pin::new(stream).poll_shutdown(cx), + SocksTcpStream::Tcp(stream) => std::pin::Pin::new(stream).poll_shutdown(cx), + SocksTcpStream::SmolTcp(stream) => std::pin::Pin::new(stream).poll_shutdown(cx), #[cfg(feature = "kcp")] - SocksTcpStream::Kcp(ref mut stream) => std::pin::Pin::new(stream).poll_shutdown(cx), + SocksTcpStream::Kcp(stream) => std::pin::Pin::new(stream).poll_shutdown(cx), } } } @@ -284,10 +280,10 @@ impl AsyncTcpConnector for Socks5AutoConnector { return Err(anyhow::anyhow!("peer manager is dropped").into()); }; - if let Some(local_addr) = self.smoltcp_net.as_ref().map(|n| n.get_address()) { - if local_addr == addr.ip() { - addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), addr.port()); - } + if let Some(local_addr) = self.smoltcp_net.as_ref().map(|n| n.get_address()) + && local_addr == addr.ip() + { + addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), addr.port()); } if self.smoltcp_net.is_none() @@ -805,7 +801,8 @@ impl Socks5Server { Ok((from_client, from_server)) => { tracing::info!( "port forward connection finished: client->server: {} bytes, server->client: {} bytes", - from_client, from_server + from_client, + from_server ); } Err(e) => { diff --git a/easytier/src/gateway/tcp_proxy.rs b/easytier/src/gateway/tcp_proxy.rs index b4095c19..3b4075c6 100644 --- a/easytier/src/gateway/tcp_proxy.rs +++ b/easytier/src/gateway/tcp_proxy.rs @@ -3,19 +3,19 @@ use cidr::Ipv4Inet; use core::panic; use crossbeam::atomic::AtomicCell; use dashmap::DashMap; -use pnet::packet::ip::IpNextHeaderProtocols; -use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet}; -use pnet::packet::tcp::{ipv4_checksum, MutableTcpPacket, TcpPacket}; use pnet::packet::MutablePacket; use pnet::packet::Packet; +use pnet::packet::ip::IpNextHeaderProtocols; +use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet}; +use pnet::packet::tcp::{MutableTcpPacket, TcpPacket, ipv4_checksum}; use socket2::{SockRef, TcpKeepalive}; use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::atomic::{AtomicBool, AtomicU16}; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; -use tokio::io::{copy_bidirectional, AsyncRead, AsyncWrite, AsyncWriteExt}; +use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, copy_bidirectional}; use tokio::net::{TcpListener, TcpSocket, TcpStream}; -use tokio::sync::{mpsc, Mutex}; +use tokio::sync::{Mutex, mpsc}; use tokio::task::JoinSet; use tokio::time::timeout; use tracing::Instrument; @@ -38,7 +38,7 @@ use crate::tunnel::packet_def::{PacketType, PeerManagerHeader, ZCPacket}; use super::CidrSet; #[cfg(feature = "smoltcp")] -use super::tokio_smoltcp::{self, channel_device, Net, NetConfig}; +use super::tokio_smoltcp::{self, Net, NetConfig, channel_device}; #[async_trait::async_trait] pub(crate) trait NatDstConnector: Send + Sync + Clone + 'static { @@ -347,10 +347,10 @@ impl PeerPacketFilter for TcpProxy { if let Err(e) = smoltcp_stack_sender.try_send(packet) { tracing::error!("send to smoltcp stack failed: {:?}", e); } - } else if let Some(peer_manager) = self.get_peer_manager() { - if let Err(e) = peer_manager.get_nic_channel().send(packet).await { - tracing::error!("send to nic failed: {:?}", e); - } + } else if let Some(peer_manager) = self.get_peer_manager() + && let Err(e) = peer_manager.get_nic_channel().send(packet).await + { + tracing::error!("send to nic failed: {:?}", e); } return None; } else { diff --git a/easytier/src/gateway/tokio_smoltcp/channel_device.rs b/easytier/src/gateway/tokio_smoltcp/channel_device.rs index 1285780c..b643bc49 100644 --- a/easytier/src/gateway/tokio_smoltcp/channel_device.rs +++ b/easytier/src/gateway/tokio_smoltcp/channel_device.rs @@ -5,7 +5,7 @@ use std::{ pin::Pin, task::{Context, Poll}, }; -use tokio::sync::mpsc::{channel, Receiver, Sender}; +use tokio::sync::mpsc::{Receiver, Sender, channel}; use tokio_util::sync::{PollSendError, PollSender}; use super::device::AsyncDevice; diff --git a/easytier/src/gateway/tokio_smoltcp/mod.rs b/easytier/src/gateway/tokio_smoltcp/mod.rs index 011edc14..302496fd 100644 --- a/easytier/src/gateway/tokio_smoltcp/mod.rs +++ b/easytier/src/gateway/tokio_smoltcp/mod.rs @@ -6,8 +6,8 @@ use std::{ io, net::{IpAddr, SocketAddr}, sync::{ - atomic::{AtomicU16, Ordering}, Arc, + atomic::{AtomicU16, Ordering}, }, }; diff --git a/easytier/src/gateway/tokio_smoltcp/reactor.rs b/easytier/src/gateway/tokio_smoltcp/reactor.rs index b28f5064..21a735ef 100644 --- a/easytier/src/gateway/tokio_smoltcp/reactor.rs +++ b/easytier/src/gateway/tokio_smoltcp/reactor.rs @@ -2,7 +2,7 @@ use super::{ device::{BufferDevice, Packet}, socket_allocator::{BufferSize, SocketAlloctor}, }; -use futures::{stream::iter, FutureExt, SinkExt, StreamExt}; +use futures::{FutureExt, SinkExt, StreamExt, stream::iter}; use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; use smoltcp::{ iface::{Context, Interface, SocketHandle}, @@ -92,10 +92,10 @@ async fn run( // wake up all closed sockets (smoltcp seems have a bug that it doesn't wake up closed sockets) for (_, socket) in socket_allocator.sockets().lock().iter_mut() { - if let Socket::Tcp(tcp) = socket { - if tcp.state() == smoltcp::socket::tcp::State::Closed { - tcp.abort(); - } + if let Socket::Tcp(tcp) = socket + && tcp.state() == smoltcp::socket::tcp::State::Closed + { + tcp.abort(); } } } diff --git a/easytier/src/gateway/tokio_smoltcp/socket.rs b/easytier/src/gateway/tokio_smoltcp/socket.rs index 1ff64ee6..f36e4bc3 100644 --- a/easytier/src/gateway/tokio_smoltcp/socket.rs +++ b/easytier/src/gateway/tokio_smoltcp/socket.rs @@ -1,6 +1,6 @@ use super::{reactor::Reactor, socket_allocator::SocketHandle}; use futures::future::{self, poll_fn}; -use futures::{ready, Stream}; +use futures::{Stream, ready}; pub use smoltcp::socket::tcp; use smoltcp::socket::udp; use smoltcp::wire::{IpAddress, IpEndpoint}; diff --git a/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs b/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs index 934d40f8..0f01678e 100644 --- a/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs +++ b/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs @@ -85,9 +85,8 @@ impl SocketAlloctor { vec![udp::PacketMetadata::EMPTY; self.buffer_size.udp_tx_meta_size], vec![0; self.buffer_size.udp_tx_size], ); - let udp = udp::Socket::new(rx_buffer, tx_buffer); - udp + udp::Socket::new(rx_buffer, tx_buffer) } } diff --git a/easytier/src/gateway/udp_proxy.rs b/easytier/src/gateway/udp_proxy.rs index 1f5eaaaf..5a9a98d6 100644 --- a/easytier/src/gateway/udp_proxy.rs +++ b/easytier/src/gateway/udp_proxy.rs @@ -1,6 +1,6 @@ use std::{ net::{Ipv4Addr, SocketAddr, SocketAddrV4}, - sync::{atomic::AtomicBool, Arc, Weak}, + sync::{Arc, Weak, atomic::AtomicBool}, time::Duration, }; @@ -9,12 +9,12 @@ use cidr::Ipv4Inet; use crossbeam::atomic::AtomicCell; use dashmap::DashMap; use pnet::packet::{ + Packet, ip::IpNextHeaderProtocols, ipv4::Ipv4Packet, udp::{self, MutableUdpPacket}, - Packet, }; -use tokio::sync::mpsc::{channel, error::TrySendError, Receiver, Sender}; +use tokio::sync::mpsc::{Receiver, Sender, channel, error::TrySendError}; use tokio::{ net::UdpSocket, sync::Mutex, @@ -25,16 +25,16 @@ use tokio::{ use tracing::Level; use crate::{ - common::{error::Error, global_ctx::ArcGlobalCtx, scoped_task::ScopedTask, PeerId}, - gateway::ip_reassembler::{compose_ipv4_packet, ComposeIpv4PacketArgs}, - peers::{peer_manager::PeerManager, PeerPacketFilter}, + common::{PeerId, error::Error, global_ctx::ArcGlobalCtx, scoped_task::ScopedTask}, + gateway::ip_reassembler::{ComposeIpv4PacketArgs, compose_ipv4_packet}, + peers::{PeerPacketFilter, peer_manager::PeerManager}, tunnel::{ common::{reserve_buf, setup_sokcet2}, packet_def::{PacketType, ZCPacket}, }, }; -use super::{ip_reassembler::IpReassembler, CidrSet}; +use super::{CidrSet, ip_reassembler::IpReassembler}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct UdpNatKey { diff --git a/easytier/src/gateway/wrapped_proxy.rs b/easytier/src/gateway/wrapped_proxy.rs index 64eeddc7..1e5aefd8 100644 --- a/easytier/src/gateway/wrapped_proxy.rs +++ b/easytier/src/gateway/wrapped_proxy.rs @@ -4,19 +4,19 @@ use std::{ }; use pnet::packet::{ + Packet as _, ip::IpNextHeaderProtocols, ipv4::Ipv4Packet, tcp::{TcpFlags, TcpPacket}, - Packet as _, }; -use tokio::io::{copy_bidirectional, AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite, copy_bidirectional}; use tokio_util::io::InspectReader; use crate::tunnel::packet_def::{PacketType, PeerManagerHeader}; use crate::{ common::{acl_processor::PacketInfo, error::Result}, gateway::tcp_proxy::{NatDstConnector, TcpProxy}, - peers::{acl_filter::AclFilter, NicPacketFilter}, + peers::{NicPacketFilter, acl_filter::AclFilter}, proto::acl::{Action, ChainType}, tunnel::packet_def::ZCPacket, }; diff --git a/easytier/src/instance/dns_server/server.rs b/easytier/src/instance/dns_server/server.rs index fc812ff6..f9b434bb 100644 --- a/easytier/src/instance/dns_server/server.rs +++ b/easytier/src/instance/dns_server/server.rs @@ -5,11 +5,11 @@ use hickory_proto::rr::LowerName; use hickory_resolver::config::ResolverOpts; use hickory_resolver::name_server::TokioConnectionProvider; use hickory_resolver::system_conf::read_system_conf; +use hickory_server::ServerFuture; use hickory_server::authority::{AuthorityObject, Catalog, ZoneType}; use hickory_server::server::{Request, RequestHandler, ResponseHandler, ResponseInfo}; use hickory_server::store::forwarder::ForwardConfig; use hickory_server::store::{forwarder::ForwardAuthority, in_memory::InMemoryAuthority}; -use hickory_server::ServerFuture; use std::io; use std::net::SocketAddr; use std::str::FromStr; diff --git a/easytier/src/instance/dns_server/server_instance.rs b/easytier/src/instance/dns_server/server_instance.rs index 2d3129f1..91d21514 100644 --- a/easytier/src/instance/dns_server/server_instance.rs +++ b/easytier/src/instance/dns_server/server_instance.rs @@ -7,28 +7,28 @@ // all the clients will exit and let the easytier instance to launch a new server instance. use super::{ + MAGIC_DNS_INSTANCE_ADDR, config::{GeneralConfigBuilder, RunConfigBuilder}, server::Server, system_config::{OSConfig, SystemConfig}, - MAGIC_DNS_INSTANCE_ADDR, }; use crate::{ common::{ - ifcfg::{IfConfiger, IfConfiguerTrait}, PeerId, + ifcfg::{IfConfiger, IfConfiguerTrait}, }, instance::dns_server::{ config::{Record, RecordBuilder, RecordType}, server::build_authority, }, - peers::{peer_manager::PeerManager, NicPacketFilter}, + peers::{NicPacketFilter, peer_manager::PeerManager}, proto::{ api::instance::Route, common::{TunnelInfo, Void}, magic_dns::{ - dns_record::{self}, DnsRecord, DnsRecordA, DnsRecordList, GetDnsRecordResponse, HandshakeRequest, HandshakeResponse, MagicDnsServerRpc, MagicDnsServerRpcServer, UpdateDnsRecordRequest, + dns_record::{self}, }, rpc_impl::standalone::{RpcServerHook, StandAloneServer}, rpc_types::controller::{BaseController, Controller}, @@ -47,11 +47,10 @@ use pnet::packet::icmp::{IcmpTypes, MutableIcmpPacket}; use pnet::packet::ipv4::Ipv4Packet; use pnet::packet::udp::UdpPacket; use pnet::packet::{ - icmp, + MutablePacket, Packet, icmp, ip::IpNextHeaderProtocols, ipv4::{self, MutableIpv4Packet}, udp::{self, MutableUdpPacket}, - MutablePacket, Packet, }; use std::net::{SocketAddr, SocketAddrV4}; use std::sync::Mutex; @@ -528,18 +527,18 @@ impl MagicDnsServerInstance { let mut dns_server = Server::new(dns_config); dns_server.run().await?; - if !tun_inet.contains(&fake_ip) { - if let Some(tun_dev_name) = &tun_dev { - let cost = if cfg!(target_os = "windows") { - Some(4) - } else { - None - }; - let ifcfg = IfConfiger {}; - ifcfg - .add_ipv4_route(tun_dev_name, fake_ip, 32, cost) - .await?; - } + if !tun_inet.contains(&fake_ip) + && let Some(tun_dev_name) = &tun_dev + { + let cost = if cfg!(target_os = "windows") { + Some(4) + } else { + None + }; + let ifcfg = IfConfiger {}; + ifcfg + .add_ipv4_route(tun_dev_name, fake_ip, 32, cost) + .await?; } let data = Arc::new(MagicDnsServerInstanceData { @@ -587,13 +586,13 @@ impl MagicDnsServerInstance { if let Err(e) = ret { tracing::error!("Failed to close system config: {:?}", e); } - if !self.tun_inet.contains(&self.data.fake_ip) { - if let Some(tun_dev_name) = &self.data.tun_dev { - let ifcfg = IfConfiger {}; - let _ = ifcfg - .remove_ipv4_route(tun_dev_name, self.data.fake_ip, 32) - .await; - } + if !self.tun_inet.contains(&self.data.fake_ip) + && let Some(tun_dev_name) = &self.data.tun_dev + { + let ifcfg = IfConfiger {}; + let _ = ifcfg + .remove_ipv4_route(tun_dev_name, self.data.fake_ip, 32) + .await; } } diff --git a/easytier/src/instance/instance.rs b/easytier/src/instance/instance.rs index e46da50d..7a5966ce 100644 --- a/easytier/src/instance/instance.rs +++ b/easytier/src/instance/instance.rs @@ -17,12 +17,12 @@ use tokio::{sync::oneshot, task::JoinSet}; #[cfg(feature = "magic-dns")] use tokio_util::sync::CancellationToken; +use crate::common::PeerId; use crate::common::acl_processor::AclRuleBuilder; use crate::common::config::ConfigLoader; use crate::common::error::Error; use crate::common::global_ctx::{ArcGlobalCtx, GlobalCtx, GlobalCtxEvent}; use crate::common::scoped_task::ScopedTask; -use crate::common::PeerId; use crate::connector::direct::DirectConnectorManager; use crate::connector::manual::{ConnectorManagerRpcService, ManualConnectorManager}; use crate::connector::tcp_hole_punch::TcpHolePunchConnector; @@ -40,7 +40,7 @@ use crate::peers::peer_manager::{PeerManager, RouteAlgoType}; #[cfg(feature = "tun")] use crate::peers::recv_packet_from_chan; use crate::peers::rpc_service::PeerManagerRpcService; -use crate::peers::{create_packet_recv_chan, PacketRecvChanReceiver}; +use crate::peers::{PacketRecvChanReceiver, create_packet_recv_chan}; use crate::proto::api::config::{ ConfigPatchAction, ConfigRpc, GetConfigRequest, GetConfigResponse, PatchConfigRequest, PatchConfigResponse, PortForwardPatch, @@ -63,7 +63,7 @@ use crate::utils::weak_upgrade; use crate::vpn_portal::{self, VpnPortal}; #[cfg(feature = "magic-dns")] -use super::dns_server::{runner::DnsRunner, MAGIC_DNS_FAKE_IP}; +use super::dns_server::{MAGIC_DNS_FAKE_IP, runner::DnsRunner}; use super::listeners::ListenerManager; #[cfg(feature = "socks5")] @@ -272,11 +272,11 @@ impl InstanceConfigPatcher { global_ctx.set_hostname(hostname.clone()); global_ctx.config.set_hostname(Some(hostname)); } - if let Some(ipv4) = patch.ipv4 { - if !global_ctx.config.get_dhcp() { - global_ctx.set_ipv4(Some(ipv4.into())); - global_ctx.config.set_ipv4(Some(ipv4.into())); - } + if let Some(ipv4) = patch.ipv4 + && !global_ctx.config.get_dhcp() + { + global_ctx.set_ipv4(Some(ipv4.into())); + global_ctx.config.set_ipv4(Some(ipv4.into())); } if let Some(ipv6) = patch.ipv6 { global_ctx.set_ipv6(Some(ipv6.into())); @@ -667,13 +667,13 @@ impl Instance { packet_recv: Arc>, ) { #[cfg(feature = "magic-dns")] - if let Some(old_ctx) = arc_nic_ctx.lock().await.take() { - if let Some(dns_runner) = old_ctx.magic_dns { - dns_runner.dns_runner_cancel_token.cancel(); - tracing::debug!("cancelling dns runner task"); - let ret = dns_runner.dns_runner_task.await; - tracing::debug!("dns runner task cancelled, ret: {:?}", ret); - } + if let Some(old_ctx) = arc_nic_ctx.lock().await.take() + && let Some(dns_runner) = old_ctx.magic_dns + { + dns_runner.dns_runner_cancel_token.cancel(); + tracing::debug!("cancelling dns runner task"); + let ret = dns_runner.dns_runner_task.await; + tracing::debug!("dns runner task cancelled, ret: {:?}", ret); }; let mut tasks = JoinSet::new(); @@ -772,10 +772,11 @@ impl Instance { let dhcp_inet = used_ipv4.iter().next().unwrap_or(&default_ipv4_addr); // if old ip is already in this subnet and not conflicted, use it - if let Some(ip) = current_dhcp_ip { - if ip.network() == dhcp_inet.network() && !used_ipv4.contains(&ip) { - continue; - } + if let Some(ip) = current_dhcp_ip + && ip.network() == dhcp_inet.network() + && !used_ipv4.contains(&ip) + { + continue; } // find an available ip in the subnet @@ -1070,7 +1071,9 @@ impl Instance { self.peer_manager.my_peer_id() } - fn get_vpn_portal_rpc_service(&self) -> impl VpnPortalRpc + Clone { + fn get_vpn_portal_rpc_service( + &self, + ) -> impl VpnPortalRpc + Clone + use<> { #[derive(Clone)] struct VpnPortalRpcService { peer_mgr: Weak, @@ -1115,7 +1118,7 @@ impl Instance { fn get_mapped_listener_manager_rpc_service( &self, - ) -> impl MappedListenerManageRpc + Clone { + ) -> impl MappedListenerManageRpc + Clone + use<> { #[derive(Clone)] pub struct MappedListenerManagerRpcService(Weak); @@ -1146,7 +1149,7 @@ impl Instance { fn get_port_forward_manager_rpc_service( &self, - ) -> impl PortForwardManageRpc + Clone { + ) -> impl PortForwardManageRpc + Clone + use<> { #[derive(Clone)] pub struct PortForwardManagerRpcService { global_ctx: Weak, @@ -1176,7 +1179,7 @@ impl Instance { } } - fn get_stats_rpc_service(&self) -> impl StatsRpc + Clone { + fn get_stats_rpc_service(&self) -> impl StatsRpc + Clone + use<> { #[derive(Clone)] pub struct StatsRpcService { global_ctx: Weak, @@ -1242,7 +1245,7 @@ impl Instance { } } - fn get_config_service(&self) -> impl ConfigRpc + Clone { + fn get_config_service(&self) -> impl ConfigRpc + Clone + use<> { #[derive(Clone)] pub struct ConfigRpcService { patcher: InstanceConfigPatcher, @@ -1285,7 +1288,7 @@ impl Instance { } } - pub fn get_api_rpc_service(&self) -> impl InstanceRpcService { + pub fn get_api_rpc_service(&self) -> impl InstanceRpcService + use<> { use crate::proto::api::instance::*; #[derive(Clone)] @@ -1308,15 +1311,15 @@ impl Instance { #[async_trait::async_trait] impl< - A: PeerManageRpc + Send + Sync, - B: ConnectorManageRpc + Send + Sync, - C: MappedListenerManageRpc + Send + Sync, - D: VpnPortalRpc + Send + Sync, - E: AclManageRpc + Send + Sync, - F: PortForwardManageRpc + Send + Sync, - G: StatsRpc + Send + Sync, - H: ConfigRpc + Send + Sync, - > InstanceRpcService for ApiRpcServiceImpl + A: PeerManageRpc + Send + Sync, + B: ConnectorManageRpc + Send + Sync, + C: MappedListenerManageRpc + Send + Sync, + D: VpnPortalRpc + Send + Sync, + E: AclManageRpc + Send + Sync, + F: PortForwardManageRpc + Send + Sync, + G: StatsRpc + Send + Sync, + H: ConfigRpc + Send + Sync, + > InstanceRpcService for ApiRpcServiceImpl { fn get_peer_manage_service(&self) -> &dyn PeerManageRpc { &self.peer_mgr_rpc_service diff --git a/easytier/src/instance/listeners.rs b/easytier/src/instance/listeners.rs index 37f5c6a7..6f7782dd 100644 --- a/easytier/src/instance/listeners.rs +++ b/easytier/src/instance/listeners.rs @@ -17,8 +17,8 @@ use crate::{ }, peers::peer_manager::PeerManager, tunnel::{ - self, ring::RingTunnelListener, tcp::TcpTunnelListener, udp::UdpTunnelListener, IpScheme, - Tunnel, TunnelListener, TunnelScheme, + self, IpScheme, Tunnel, TunnelListener, TunnelScheme, ring::RingTunnelListener, + tcp::TcpTunnelListener, udp::UdpTunnelListener, }, utils::BoxExt, }; @@ -284,7 +284,7 @@ mod tests { use crate::{ common::global_ctx::tests::get_mock_global_ctx, - tunnel::{packet_def::ZCPacket, ring::RingTunnelConnector, TunnelConnector, TunnelError}, + tunnel::{TunnelConnector, TunnelError, packet_def::ZCPacket, ring::RingTunnelConnector}, }; use super::*; diff --git a/easytier/src/instance/virtual_nic.rs b/easytier/src/instance/virtual_nic.rs index d4e77a03..280147b4 100644 --- a/easytier/src/instance/virtual_nic.rs +++ b/easytier/src/instance/virtual_nic.rs @@ -15,18 +15,18 @@ use crate::{ log, }, instance::proxy_cidrs_monitor::ProxyCidrsMonitor, - peers::{peer_manager::PeerManager, recv_packet_from_chan, PacketRecvChanReceiver}, + peers::{PacketRecvChanReceiver, peer_manager::PeerManager, recv_packet_from_chan}, tunnel::{ - common::{reserve_buf, FramedWriter, TunnelWrapper, ZCPacketToBytes}, - packet_def::{ZCPacket, ZCPacketType, TAIL_RESERVED_SIZE}, StreamItem, Tunnel, TunnelError, ZCPacketSink, ZCPacketStream, + common::{FramedWriter, TunnelWrapper, ZCPacketToBytes, reserve_buf}, + packet_def::{TAIL_RESERVED_SIZE, ZCPacket, ZCPacketType}, }, }; use byteorder::WriteBytesExt as _; use bytes::{BufMut, BytesMut}; use cidr::{Ipv4Inet, Ipv6Inet}; -use futures::{lock::BiLock, ready, SinkExt, Stream, StreamExt}; +use futures::{SinkExt, Stream, StreamExt, lock::BiLock, ready}; use pin_project_lite::pin_project; use pnet::packet::{ipv4::Ipv4Packet, ipv6::Ipv6Packet}; use tokio::{ @@ -530,7 +530,9 @@ impl VirtualNic { Ok(_) => tracing::info!("add_self_to_firewall_allowlist successful!"), Err(error) => { log::warn!(%error, "Failed to add Easytier to firewall allowlist, Subnet proxy and KCP proxy may not work properly."); - log::warn!("You can add firewall rules manually, or use --use-smoltcp to run with user-space TCP/IP stack."); + log::warn!( + "You can add firewall rules manually, or use --use-smoltcp to run with user-space TCP/IP stack." + ); } } @@ -768,7 +770,7 @@ impl VirtualNic { Ok(()) } - pub fn get_ifcfg(&self) -> impl IfConfiguerTrait { + pub fn get_ifcfg(&self) -> impl IfConfiguerTrait + use<> { IfConfiger {} } } diff --git a/easytier/src/instance_manager.rs b/easytier/src/instance_manager.rs index 1fb3f2b5..4ad710e8 100644 --- a/easytier/src/instance_manager.rs +++ b/easytier/src/instance_manager.rs @@ -85,11 +85,11 @@ impl NetworkInstanceManager { let _t = instance_event_receiver .map(|event| ScopedTask::from(handle_event(instance_id, event))); instance_stop_notifier.notified().await; - if let Some(instance) = instance_map.get(&instance_id) { - if let Some(error) = instance.get_latest_error_msg() { - log::error!(%error, "instance {} stopped", instance_id); - instance_error_messages.insert(instance_id, error); - } + if let Some(instance) = instance_map.get(&instance_id) + && let Some(error) = instance.get_latest_error_msg() + { + log::error!(%error, "instance {} stopped", instance_id); + instance_error_messages.insert(instance_id, error); } stop_check_notifier.notify_one(); instance_stop_tasks.remove(&instance_id); @@ -543,45 +543,57 @@ mod tests { let port = crate::utils::find_free_tcp_port(10012..65534).expect("no free tcp port found"); - assert!(manager - .run_network_instance( - TomlConfigLoader::new_from_str(cfg_str).unwrap(), - true, - ConfigFileControl::STATIC_CONFIG - ) - .is_err()); - assert!(manager - .run_network_instance( - TomlConfigLoader::new_from_str(cfg_str).unwrap(), - true, - ConfigFileControl::STATIC_CONFIG - ) - .is_err()); - assert!(manager - .run_network_instance( - TomlConfigLoader::new_from_str(cfg_str) - .inspect(|c| { - c.set_listeners(vec![format!("tcp://0.0.0.0:{}", port).parse().unwrap()]); - }) - .unwrap(), - false, - ConfigFileControl::STATIC_CONFIG - ) - .is_ok()); - assert!(manager - .run_network_instance( - TomlConfigLoader::new_from_str(cfg_str).unwrap(), - true, - ConfigFileControl::STATIC_CONFIG - ) - .is_err()); - assert!(manager - .run_network_instance( - TomlConfigLoader::new_from_str(cfg_str).unwrap(), - false, - ConfigFileControl::STATIC_CONFIG - ) - .is_ok()); + assert!( + manager + .run_network_instance( + TomlConfigLoader::new_from_str(cfg_str).unwrap(), + true, + ConfigFileControl::STATIC_CONFIG + ) + .is_err() + ); + assert!( + manager + .run_network_instance( + TomlConfigLoader::new_from_str(cfg_str).unwrap(), + true, + ConfigFileControl::STATIC_CONFIG + ) + .is_err() + ); + assert!( + manager + .run_network_instance( + TomlConfigLoader::new_from_str(cfg_str) + .inspect(|c| { + c.set_listeners(vec![ + format!("tcp://0.0.0.0:{}", port).parse().unwrap(), + ]); + }) + .unwrap(), + false, + ConfigFileControl::STATIC_CONFIG + ) + .is_ok() + ); + assert!( + manager + .run_network_instance( + TomlConfigLoader::new_from_str(cfg_str).unwrap(), + true, + ConfigFileControl::STATIC_CONFIG + ) + .is_err() + ); + assert!( + manager + .run_network_instance( + TomlConfigLoader::new_from_str(cfg_str).unwrap(), + false, + ConfigFileControl::STATIC_CONFIG + ) + .is_ok() + ); std::thread::sleep(std::time::Duration::from_secs(1)); // wait instance actually started diff --git a/easytier/src/launcher.rs b/easytier/src/launcher.rs index b9061077..a5dc001f 100644 --- a/easytier/src/launcher.rs +++ b/easytier/src/launcher.rs @@ -1,12 +1,12 @@ -use crate::common::config::{process_secure_mode_cfg, ConfigFileControl, PortForwardConfig}; +use crate::common::config::{ConfigFileControl, PortForwardConfig, process_secure_mode_cfg}; use crate::proto::api::{self, manage}; use crate::proto::rpc_types::controller::BaseController; use crate::rpc_service::InstanceRpcService; use crate::{ common::{ config::{ - gen_default_flags, ConfigLoader, NetworkIdentity, PeerConfig, TomlConfigLoader, - VpnPortalConfig, + ConfigLoader, NetworkIdentity, PeerConfig, TomlConfigLoader, VpnPortalConfig, + gen_default_flags, }, constants::EASYTIER_VERSION, global_ctx::{EventBusSubscriber, GlobalCtxEvent}, @@ -19,7 +19,7 @@ use chrono::{DateTime, Local}; use std::{ collections::VecDeque, net::SocketAddr, - sync::{atomic::AtomicBool, Arc, Mutex, RwLock}, + sync::{Arc, Mutex, RwLock, atomic::AtomicBool}, }; use tokio::{ sync::{broadcast, mpsc}, @@ -272,10 +272,10 @@ impl Drop for EasyTierLauncher { fn drop(&mut self) { self.stop_flag .store(true, std::sync::atomic::Ordering::Relaxed); - if let Some(handle) = self.thread_handle.take() { - if let Err(e) = handle.join() { - println!("Error when joining thread: {:?}", e); - } + if let Some(handle) = self.thread_handle.take() + && let Err(e) = handle.join() + { + println!("Error when joining thread: {:?}", e); } } } @@ -656,12 +656,12 @@ impl NetworkConfig { cfg.set_exit_nodes(exit_nodes); } - if self.enable_socks5.unwrap_or_default() { - if let Some(socks5_port) = self.socks5_port { - cfg.set_socks5_portal(Some( - format!("socks5://0.0.0.0:{}", socks5_port).parse().unwrap(), - )); - } + if self.enable_socks5.unwrap_or_default() + && let Some(socks5_port) = self.socks5_port + { + cfg.set_socks5_portal(Some( + format!("socks5://0.0.0.0:{}", socks5_port).parse().unwrap(), + )); } if !self.mapped_listeners.is_empty() { @@ -909,11 +909,11 @@ impl NetworkConfig { result.vpn_portal_listen_port = Some(vpn_config.wireguard_listen.port() as i32); } - if let Some(routes) = config.get_routes() { - if !routes.is_empty() { - result.enable_manual_routes = Some(true); - result.routes = routes.iter().map(|r| r.to_string()).collect(); - } + if let Some(routes) = config.get_routes() + && !routes.is_empty() + { + result.enable_manual_routes = Some(true); + result.routes = routes.iter().map(|r| r.to_string()).collect(); } let exit_nodes = config.get_exit_nodes(); @@ -986,10 +986,10 @@ impl NetworkConfig { #[cfg(test)] mod tests { use crate::{ - common::config::{process_secure_mode_cfg, ConfigLoader}, + common::config::{ConfigLoader, process_secure_mode_cfg}, proto::common::SecureModeConfig, }; - use base64::prelude::{Engine as _, BASE64_STANDARD}; + use base64::prelude::{BASE64_STANDARD, Engine as _}; use rand::Rng; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -1014,9 +1014,12 @@ mod tests { let generated_config_str = generated_config.dump(); assert_eq!( - config_str, generated_config_str, - "Generated config does not match original config:\nOriginal:\n{}\n\nGenerated:\n{}\nNetwork Config: {}\n", - config_str, generated_config_str, serde_json::to_string(&network_config).unwrap() + config_str, + generated_config_str, + "Generated config does not match original config:\nOriginal:\n{}\n\nGenerated:\n{}\nNetwork Config: {}\n", + config_str, + generated_config_str, + serde_json::to_string(&network_config).unwrap() ); Ok(()) } @@ -1033,13 +1036,13 @@ mod tests { config.set_dhcp(rng.gen_bool(0.5)); if rng.gen_bool(0.7) { - let hostname = format!("host-{}", rng.gen::()); + let hostname = format!("host-{}", rng.r#gen::()); config.set_hostname(Some(hostname)); } config.set_network_identity(crate::common::config::NetworkIdentity::new( - format!("network-{}", rng.gen::()), - format!("secret-{}", rng.gen::()), + format!("network-{}", rng.r#gen::()), + format!("secret-{}", rng.r#gen::()), )); config.set_inst_name(config.get_network_identity().network_name.clone()); @@ -1251,9 +1254,12 @@ mod tests { let generated_config_str = generated_config.dump(); assert_eq!( - config_str, generated_config_str, + config_str, + generated_config_str, "Generated config does not match original config:\nOriginal:\n{}\n\nGenerated:\n{}\nNetwork Config: {}\n", - config_str, generated_config_str, serde_json::to_string(&network_config).unwrap() + config_str, + generated_config_str, + serde_json::to_string(&network_config).unwrap() ); } diff --git a/easytier/src/peer_center/instance.rs b/easytier/src/peer_center/instance.rs index 2ce5ed46..461d74b7 100644 --- a/easytier/src/peer_center/instance.rs +++ b/easytier/src/peer_center/instance.rs @@ -12,7 +12,7 @@ use tokio::task::JoinSet; use tracing::Instrument; use crate::{ - common::{global_ctx::GlobalCtx, PeerId}, + common::{PeerId, global_ctx::GlobalCtx}, peers::{ peer_manager::PeerManager, peer_map::PeerMap, @@ -30,7 +30,7 @@ use crate::{ }, }; -use super::{server::PeerCenterServer, Digest, Error}; +use super::{Digest, Error, server::PeerCenterServer}; #[async_trait::async_trait] #[auto_impl::auto_impl(&, Arc, Box)] @@ -97,12 +97,12 @@ impl PeerCenterBase { &self, job_ctx: T, job_fn: impl Fn( - Box + Send>, - Arc>, - ) -> Fut - + Send - + Sync - + 'static, + Box + Send>, + Arc>, + ) -> Fut + + Send + + Sync + + 'static, ) { let my_peer_id = self.my_peer_id; let peer_mgr = self.peer_mgr.clone(); diff --git a/easytier/src/peers/acl_filter.rs b/easytier/src/peers/acl_filter.rs index 6b3d6263..b4271d63 100644 --- a/easytier/src/peers/acl_filter.rs +++ b/easytier/src/peers/acl_filter.rs @@ -3,14 +3,14 @@ use std::sync::atomic::Ordering; use std::time::Instant; use std::{ net::IpAddr, - sync::{atomic::AtomicBool, Arc}, + sync::{Arc, atomic::AtomicBool}, }; use arc_swap::ArcSwap; use dashmap::DashMap; use pnet::packet::ipv6::Ipv6Packet; use pnet::packet::{ - ip::IpNextHeaderProtocols, ipv4::Ipv4Packet, tcp::TcpPacket, udp::UdpPacket, Packet as _, + Packet as _, ip::IpNextHeaderProtocols, ipv4::Ipv4Packet, tcp::TcpPacket, udp::UdpPacket, }; use crate::common::scoped_task::ScopedTask; @@ -238,23 +238,23 @@ impl AclFilter { chain_type: ChainType, processor: &AclProcessor, ) { - if result.should_log { - if let Some(ref log_context) = result.log_context { - let log_message = log_context.to_message(); - tracing::info!( - src_ip = %packet_info.src_ip, - dst_ip = %packet_info.dst_ip, - src_port = packet_info.src_port, - dst_port = packet_info.dst_port, - src_group = packet_info.src_groups.join(","), - dst_group = packet_info.dst_groups.join(","), - protocol = ?packet_info.protocol, - action = ?result.action, - rule = result.matched_rule_str().as_deref().unwrap_or("unknown"), - chain_type = ?chain_type, - "ACL: {}", log_message - ); - } + if result.should_log + && let Some(ref log_context) = result.log_context + { + let log_message = log_context.to_message(); + tracing::info!( + src_ip = %packet_info.src_ip, + dst_ip = %packet_info.dst_ip, + src_port = packet_info.src_port, + dst_port = packet_info.dst_port, + src_group = packet_info.src_groups.join(","), + dst_group = packet_info.dst_groups.join(","), + protocol = ?packet_info.protocol, + action = ?result.action, + rule = result.matched_rule_str().as_deref().unwrap_or("unknown"), + chain_type = ?chain_type, + "ACL: {}", log_message + ); } // Update global statistics in the ACL processor diff --git a/easytier/src/peers/credential_manager.rs b/easytier/src/peers/credential_manager.rs index 5833948d..c003711e 100644 --- a/easytier/src/peers/credential_manager.rs +++ b/easytier/src/peers/credential_manager.rs @@ -5,8 +5,8 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; -use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; use base64::Engine; +use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; use serde::{Deserialize, Serialize}; use x25519_dalek::{PublicKey, StaticSecret}; @@ -62,10 +62,10 @@ impl CredentialManager { .map(|x| x.trim().to_string()) .filter(|x| !x.is_empty()) { - if let Some(existing) = credentials.get(&id) { - if !existing.secret.is_empty() { - return (id, existing.secret.clone()); - } + if let Some(existing) = credentials.get(&id) + && !existing.secret.is_empty() + { + return (id, existing.secret.clone()); } id } else { @@ -191,10 +191,10 @@ impl CredentialManager { return; }; let creds = self.credentials.lock().unwrap(); - if let Ok(json) = serde_json::to_string_pretty(&*creds) { - if let Err(e) = std::fs::write(path, json) { - tracing::warn!(?e, "failed to save credentials to disk"); - } + if let Ok(json) = serde_json::to_string_pretty(&*creds) + && let Err(e) = std::fs::write(path, json) + { + tracing::warn!(?e, "failed to save credentials to disk"); } } @@ -386,11 +386,12 @@ mod tests { ); assert!(tc.credential.as_ref().unwrap().expiry_unix > 0); assert!(tc.verify_credential_hmac("sec")); - assert!(tc - .credential - .as_ref() - .map(|x| !x.pubkey.is_empty()) - .unwrap_or(false)); + assert!( + tc.credential + .as_ref() + .map(|x| !x.pubkey.is_empty()) + .unwrap_or(false) + ); let sk: [u8; 32] = BASE64_STANDARD.decode(&secret).unwrap().try_into().unwrap(); let pk = PublicKey::from(&StaticSecret::from(sk)).as_bytes().to_vec(); diff --git a/easytier/src/peers/encrypt/aes_gcm.rs b/easytier/src/peers/encrypt/aes_gcm.rs index a48bd38e..c1018d9f 100644 --- a/easytier/src/peers/encrypt/aes_gcm.rs +++ b/easytier/src/peers/encrypt/aes_gcm.rs @@ -137,7 +137,7 @@ impl Encryptor for AesGcmCipher { #[cfg(test)] mod tests { use crate::{ - peers::encrypt::{aes_gcm::AesGcmCipher, Encryptor}, + peers::encrypt::{Encryptor, aes_gcm::AesGcmCipher}, tunnel::packet_def::{StandardAeadTail, ZCPacket}, }; use zerocopy::FromBytes; diff --git a/easytier/src/peers/encrypt/ring.rs b/easytier/src/peers/encrypt/ring.rs index a0876468..b5177eb7 100644 --- a/easytier/src/peers/encrypt/ring.rs +++ b/easytier/src/peers/encrypt/ring.rs @@ -155,7 +155,7 @@ impl Encryptor for RingCipher { #[cfg(test)] mod tests { use crate::{ - peers::encrypt::{ring::RingCipher, Encryptor}, + peers::encrypt::{Encryptor, ring::RingCipher}, tunnel::packet_def::{StandardAeadTail, ZCPacket}, }; use zerocopy::FromBytes; diff --git a/easytier/src/peers/encrypt/xor.rs b/easytier/src/peers/encrypt/xor.rs index 3e2ddb00..a6d3165c 100644 --- a/easytier/src/peers/encrypt/xor.rs +++ b/easytier/src/peers/encrypt/xor.rs @@ -61,7 +61,7 @@ impl Encryptor for XorCipher { #[cfg(test)] mod tests { use crate::{ - peers::encrypt::{xor::XorCipher, Encryptor}, + peers::encrypt::{Encryptor, xor::XorCipher}, tunnel::packet_def::ZCPacket, }; diff --git a/easytier/src/peers/foreign_network_client.rs b/easytier/src/peers/foreign_network_client.rs index 99e2794f..9670c15e 100644 --- a/easytier/src/peers/foreign_network_client.rs +++ b/easytier/src/peers/foreign_network_client.rs @@ -1,11 +1,11 @@ use std::sync::{Arc, Mutex}; use crate::{ - common::{error::Error, global_ctx::ArcGlobalCtx, scoped_task::ScopedTask, PeerId}, + common::{PeerId, error::Error, global_ctx::ArcGlobalCtx, scoped_task::ScopedTask}, tunnel::packet_def::ZCPacket, }; -use super::{peer_conn::PeerConn, peer_map::PeerMap, peer_rpc::PeerRpcManager, PacketRecvChan}; +use super::{PacketRecvChan, peer_conn::PeerConn, peer_map::PeerMap, peer_rpc::PeerRpcManager}; pub struct ForeignNetworkClient { global_ctx: ArcGlobalCtx, diff --git a/easytier/src/peers/foreign_network_manager.rs b/easytier/src/peers/foreign_network_manager.rs index cc06d4dd..3edd9603 100644 --- a/easytier/src/peers/foreign_network_manager.rs +++ b/easytier/src/peers/foreign_network_manager.rs @@ -13,21 +13,21 @@ use std::{ use dashmap::{DashMap, DashSet}; use tokio::{ sync::{ - mpsc::{self, UnboundedReceiver, UnboundedSender}, Mutex, + mpsc::{self, UnboundedReceiver, UnboundedSender}, }, task::JoinSet, }; use crate::{ common::{ + PeerId, config::{ConfigLoader, TomlConfigLoader}, error::Error, global_ctx::{ArcGlobalCtx, GlobalCtx, GlobalCtxEvent, NetworkIdentity, TrustedKeySource}, join_joinset_background, shrink_dashmap, stats_manager::{LabelSet, LabelType, MetricName, StatsManager}, token_bucket::TokenBucket, - PeerId, }, peer_center::instance::{PeerCenterInstance, PeerMapWithPeerRpcManager}, peers::route_trait::{Route, RouteInterface}, @@ -44,7 +44,7 @@ use crate::{ }; use super::{ - create_packet_recv_chan, + PUBLIC_SERVER_HOSTNAME_PREFIX, PacketRecvChan, PacketRecvChanReceiver, create_packet_recv_chan, peer_conn::PeerConn, peer_map::PeerMap, peer_ospf_route::PeerRoute, @@ -55,10 +55,9 @@ use super::{ relay_peer_map::RelayPeerMap, route_trait::NextHopPolicy, traffic_metrics::{ - route_peer_info_instance_id, InstanceLabelKind, LogicalTrafficMetrics, - TrafficMetricRecorder, + InstanceLabelKind, LogicalTrafficMetrics, TrafficMetricRecorder, + route_peer_info_instance_id, }, - PacketRecvChan, PacketRecvChanReceiver, PUBLIC_SERVER_HOSTNAME_PREFIX, }; #[async_trait::async_trait] @@ -1454,9 +1453,11 @@ pub mod tests { .get_foreign_network_manager() .list_foreign_networks() .await; - assert!(without_trusted_keys.foreign_networks["net1"] - .trusted_keys - .is_empty()); + assert!( + without_trusted_keys.foreign_networks["net1"] + .trusted_keys + .is_empty() + ); let foreign_mgr = pm_center.get_foreign_network_manager(); wait_for_condition( @@ -1477,9 +1478,11 @@ pub mod tests { .await; let with_trusted_keys = foreign_mgr.list_foreign_networks_with_options(true).await; - assert!(!with_trusted_keys.foreign_networks["net1"] - .trusted_keys - .is_empty()); + assert!( + !with_trusted_keys.foreign_networks["net1"] + .trusted_keys + .is_empty() + ); } #[tokio::test] @@ -1558,12 +1561,14 @@ pub mod tests { assert!(client.await.unwrap().is_ok()); assert!(server.await.unwrap().is_err()); - assert!(pm_center - .get_foreign_network_manager() - .list_foreign_networks() - .await - .foreign_networks - .is_empty()); + assert!( + pm_center + .get_foreign_network_manager() + .list_foreign_networks() + .await + .foreign_networks + .is_empty() + ); } async fn foreign_network_whitelist_helper(name: String) { @@ -1651,20 +1656,24 @@ pub mod tests { .unwrap(); assert_eq!( - vec![pm_center - .get_foreign_network_manager() - .get_network_peer_id("net1") - .unwrap()], + vec![ + pm_center + .get_foreign_network_manager() + .get_network_peer_id("net1") + .unwrap() + ], pma_net1 .get_foreign_network_client() .get_peer_map() .list_peers() ); assert_eq!( - vec![pm_center - .get_foreign_network_manager() - .get_network_peer_id("net1") - .unwrap()], + vec![ + pm_center + .get_foreign_network_manager() + .get_network_peer_id("net1") + .unwrap() + ], pmb_net1 .get_foreign_network_client() .get_peer_map() diff --git a/easytier/src/peers/peer.rs b/easytier/src/peers/peer.rs index fbc15eb6..4c3b55ff 100644 --- a/easytier/src/peers/peer.rs +++ b/easytier/src/peers/peer.rs @@ -9,14 +9,14 @@ use tokio::{select, sync::mpsc}; use tracing::Instrument; use super::{ - peer_conn::{PeerConn, PeerConnId}, PacketRecvChan, + peer_conn::{PeerConn, PeerConnId}, }; use crate::{ common::{ + PeerId, error::Error, global_ctx::{ArcGlobalCtx, GlobalCtxEvent}, - PeerId, }, proto::peer_rpc::PeerIdentityType, tunnel::packet_def::ZCPacket, @@ -294,7 +294,7 @@ impl Drop for Peer { #[cfg(test)] mod tests { - use base64::prelude::{Engine as _, BASE64_STANDARD}; + use base64::prelude::{BASE64_STANDARD, Engine as _}; use rand::rngs::OsRng; use std::sync::Arc; use tokio::time::timeout; @@ -302,7 +302,7 @@ mod tests { use crate::{ common::{ config::{NetworkIdentity, PeerConfig}, - global_ctx::{tests::get_mock_global_ctx, GlobalCtx}, + global_ctx::{GlobalCtx, tests::get_mock_global_ctx}, new_peer_id, }, peers::{create_packet_recv_chan, peer_conn::PeerConn, peer_session::PeerSessionStore}, diff --git a/easytier/src/peers/peer_conn.rs b/easytier/src/peers/peer_conn.rs index 32b710f7..4aafb1b9 100644 --- a/easytier/src/peers/peer_conn.rs +++ b/easytier/src/peers/peer_conn.rs @@ -3,37 +3,37 @@ use std::{ fmt::Debug, pin::Pin, sync::{ - atomic::{AtomicU32, Ordering}, Arc, + atomic::{AtomicU32, Ordering}, }, }; use crossbeam::atomic::AtomicCell; use futures::{StreamExt, TryFutureExt}; -use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; use base64::Engine as _; +use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; use hmac::Mac; use prost::Message; use tokio::{ - sync::{broadcast, Mutex}, + sync::{Mutex, broadcast}, task::JoinSet, - time::{timeout, Duration}, + time::{Duration, timeout}, }; use tracing::Instrument; use zerocopy::AsBytes; -use snow::{params::NoiseParams, HandshakeState}; +use snow::{HandshakeState, params::NoiseParams}; use crate::{ common::{ + PeerId, config::{NetworkIdentity, NetworkSecretDigest}, defer, error::Error, global_ctx::ArcGlobalCtx, - PeerId, }, peers::peer_session::{PeerSessionStore, SessionKey, UpsertResponderSessionReturn}, proto::{ @@ -45,20 +45,20 @@ use crate::{ }, }, tunnel::{ + Tunnel, TunnelError, ZCPacketStream, filter::{StatsRecorderTunnelFilter, TunnelFilter, TunnelFilterChain, TunnelWithFilter}, mpsc::{MpscTunnel, MpscTunnelSender}, packet_def::{PacketType, ZCPacket}, stats::{Throughput, WindowLatency}, - Tunnel, TunnelError, ZCPacketStream, }, use_global_var, }; use super::{ + PacketRecvChan, peer_conn_ping::PeerConnPinger, peer_session::{PeerSession, PeerSessionAction}, traffic_metrics::AggregateTrafficMetrics, - PacketRecvChan, }; pub type PeerConnId = uuid::Uuid; @@ -458,12 +458,12 @@ impl PeerConn { return Err(Error::WaitRespError(format!( "conn recv error during wait handshake response, err: {:?}", e - ))) + ))); } None => { return Err(Error::WaitRespError( "conn closed during wait handshake response".to_owned(), - )) + )); } }; @@ -610,7 +610,7 @@ impl PeerConn { return Err(Error::WaitRespError(format!( "conn recv error during wait handshake response, err: {:?}", e - ))) + ))); } }; @@ -716,12 +716,11 @@ impl PeerConn { remote_network_name: &str, ) -> Result { // 1. Verify proof - if let Some(proof) = proof { - if let Some(mac) = self.global_ctx.get_secret_proof(handshake_hash) { - if mac.verify_slice(proof).is_ok() { - return Ok(SecureAuthLevel::NetworkSecretConfirmed); - } - } + if let Some(proof) = proof + && let Some(mac) = self.global_ctx.get_secret_proof(handshake_hash) + && mac.verify_slice(proof).is_ok() + { + return Ok(SecureAuthLevel::NetworkSecretConfirmed); } // 2. Check pinned pubkey @@ -848,10 +847,10 @@ impl PeerConn { .await??; self.record_control_rx(&network.network_name, msg2.buf_len() as u64); let remote_peer_id = msg2.get_src_peer_id().expect("missing src peer id"); - if let Some(hint) = self.peer_id_hint { - if hint != remote_peer_id { - return Err(Error::WaitRespError("peer_id mismatch".to_owned())); - } + if let Some(hint) = self.peer_id_hint + && hint != remote_peer_id + { + return Err(Error::WaitRespError("peer_id mismatch".to_owned())); } let msg2_pb = Self::decode_handshake_message::( PacketType::NoiseHandshakeMsg2, @@ -1604,16 +1603,16 @@ pub mod tests { use super::*; use crate::common::config::PeerConfig; - use crate::common::global_ctx::tests::get_mock_global_ctx; use crate::common::global_ctx::GlobalCtx; + use crate::common::global_ctx::tests::get_mock_global_ctx; use crate::common::new_peer_id; use crate::common::scoped_task::ScopedTask; use crate::common::stats_manager::{LabelSet, LabelType, MetricName}; use crate::peers::create_packet_recv_chan; use crate::peers::recv_packet_from_chan; use crate::tunnel::common::tests::wait_for_condition; - use crate::tunnel::filter::tests::DropSendTunnelFilter; use crate::tunnel::filter::PacketRecorderTunnelFilter; + use crate::tunnel::filter::tests::DropSendTunnelFilter; use crate::tunnel::ring::create_ring_tunnel_pair; pub fn set_secure_mode_cfg(global_ctx: &GlobalCtx, enabled: bool) { @@ -2489,9 +2488,11 @@ pub mod tests { ); // Revoke the credential - assert!(admin_ctx - .get_credential_manager() - .revoke_credential(&cred_id)); + assert!( + admin_ctx + .get_credential_manager() + .revoke_credential(&cred_id) + ); // Now try to connect with the revoked credential let (c, s) = create_ring_tunnel_pair(); diff --git a/easytier/src/peers/peer_conn_ping.rs b/easytier/src/peers/peer_conn_ping.rs index 538d1f2c..1a3cde30 100644 --- a/easytier/src/peers/peer_conn_ping.rs +++ b/easytier/src/peers/peer_conn_ping.rs @@ -1,27 +1,27 @@ use std::{ sync::{ - atomic::{AtomicU32, Ordering}, Arc, + atomic::{AtomicU32, Ordering}, }, time::Duration, }; -use rand::{thread_rng, Rng}; +use rand::{Rng, thread_rng}; use tokio::{ sync::broadcast, task::JoinSet, - time::{timeout, Interval}, + time::{Interval, timeout}, }; use tracing::Instrument; use crate::{ - common::{error::Error, PeerId}, + common::{PeerId, error::Error}, peers::traffic_metrics::AggregateTrafficMetrics, tunnel::{ + TunnelError, mpsc::MpscTunnelSender, packet_def::{PacketType, ZCPacket}, stats::{Throughput, WindowLatency}, - TunnelError, }, }; diff --git a/easytier/src/peers/peer_manager.rs b/easytier/src/peers/peer_manager.rs index 57b9ede8..8379cad6 100644 --- a/easytier/src/peers/peer_manager.rs +++ b/easytier/src/peers/peer_manager.rs @@ -1,7 +1,7 @@ use std::{ fmt::Debug, net::{IpAddr, Ipv4Addr, Ipv6Addr}, - sync::{atomic::AtomicBool, Arc, Weak}, + sync::{Arc, Weak, atomic::AtomicBool}, time::{Duration, Instant, SystemTime}, }; @@ -12,14 +12,15 @@ use dashmap::DashMap; use tokio::{ sync::{ - mpsc::{self, UnboundedReceiver, UnboundedSender}, Mutex, RwLock, + mpsc::{self, UnboundedReceiver, UnboundedSender}, }, task::JoinSet, }; use crate::{ common::{ + PeerId, compressor::{Compressor as _, DefaultCompressor}, constants::EASYTIER_VERSION, error::Error, @@ -27,24 +28,23 @@ use crate::{ shrink_dashmap, stats_manager::{CounterHandle, LabelSet, LabelType, MetricName}, stun::StunInfoCollectorTrait, - PeerId, }, peers::{ + PeerPacketFilter, peer_conn::PeerConn, peer_rpc::PeerRpcManagerTransport, peer_session::PeerSessionStore, recv_packet_from_chan, route_trait::{ForeignNetworkRouteInfoMap, MockRoute, NextHopPolicy, RouteInterface}, traffic_metrics::{ - route_peer_info_instance_id, InstanceLabelKind, LogicalTrafficMetrics, - TrafficMetricRecorder, + InstanceLabelKind, LogicalTrafficMetrics, TrafficMetricRecorder, + route_peer_info_instance_id, }, - PeerPacketFilter, }, proto::{ api::instance::{ - self, list_global_foreign_network_response::OneForeignNetwork, - ListGlobalForeignNetworkResponse, + self, ListGlobalForeignNetworkResponse, + list_global_foreign_network_response::OneForeignNetwork, }, peer_rpc::{ ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, PeerIdentityType, @@ -52,13 +52,13 @@ use crate::{ }, }, tunnel::{ - self, + self, Tunnel, TunnelConnector, packet_def::{CompressorAlgo, PacketType, ZCPacket}, - Tunnel, TunnelConnector, }, }; use super::{ + BoxNicPacketFilter, BoxPeerPacketFilter, PacketRecvChan, PacketRecvChanReceiver, create_packet_recv_chan, encrypt::{Encryptor, NullCipher}, foreign_network_client::ForeignNetworkClient, @@ -70,7 +70,6 @@ use super::{ peer_task::ExternalTaskSignal, relay_peer_map::RelayPeerMap, route_trait::{ArcRoute, Route}, - BoxNicPacketFilter, BoxPeerPacketFilter, PacketRecvChan, PacketRecvChanReceiver, }; struct RpcTransport { @@ -1408,10 +1407,10 @@ impl PeerManager { Err(Error::RouteError(None)) }; - if send_result.is_ok() { - if let Some(metrics) = direct_tx_metrics { - metrics.record_tx(dst_peer_id, packet_type, msg_len).await; - } + if send_result.is_ok() + && let Some(metrics) = direct_tx_metrics + { + metrics.record_tx(dst_peer_id, packet_type, msg_len).await; } send_result @@ -1996,7 +1995,7 @@ mod tests { use crate::{ common::{ config::Flags, - global_ctx::{tests::get_mock_global_ctx, NetworkIdentity}, + global_ctx::{NetworkIdentity, tests::get_mock_global_ctx}, stats_manager::{LabelSet, LabelType, MetricName}, }, connector::{ @@ -2020,11 +2019,11 @@ mod tests { peer_rpc::SecureAuthLevel, }, tunnel::{ + TunnelConnector, TunnelListener, common::tests::wait_for_condition, - filter::{tests::DropSendTunnelFilter, TunnelWithFilter}, + filter::{TunnelWithFilter, tests::DropSendTunnelFilter}, packet_def::{PacketType, ZCPacket}, ring::create_ring_tunnel_pair, - TunnelConnector, TunnelListener, }, }; @@ -2194,24 +2193,28 @@ mod tests { .value, 0 ); - assert!(peer_mgr - .get_global_ctx() - .stats_manager() - .get_metric( - MetricName::TrafficBytesTxByInstance, - &network_labels - .clone() - .with_label_type(LabelType::ToInstanceId("unknown".to_string())), - ) - .is_none()); - assert!(peer_mgr - .get_global_ctx() - .stats_manager() - .get_metric( - MetricName::TrafficPacketsTxByInstance, - &network_labels.with_label_type(LabelType::ToInstanceId("unknown".to_string())), - ) - .is_none()); + assert!( + peer_mgr + .get_global_ctx() + .stats_manager() + .get_metric( + MetricName::TrafficBytesTxByInstance, + &network_labels + .clone() + .with_label_type(LabelType::ToInstanceId("unknown".to_string())), + ) + .is_none() + ); + assert!( + peer_mgr + .get_global_ctx() + .stats_manager() + .get_metric( + MetricName::TrafficPacketsTxByInstance, + &network_labels.with_label_type(LabelType::ToInstanceId("unknown".to_string())), + ) + .is_none() + ); } #[tokio::test] @@ -2265,24 +2268,28 @@ mod tests { ), 0 ); - assert!(peer_mgr - .get_global_ctx() - .stats_manager() - .get_metric( - MetricName::TrafficBytesTxByInstance, - &network_labels - .clone() - .with_label_type(LabelType::ToInstanceId("unknown".to_string())), - ) - .is_none()); - assert!(peer_mgr - .get_global_ctx() - .stats_manager() - .get_metric( - MetricName::TrafficControlBytesTxByInstance, - &network_labels.with_label_type(LabelType::ToInstanceId("unknown".to_string())), - ) - .is_none()); + assert!( + peer_mgr + .get_global_ctx() + .stats_manager() + .get_metric( + MetricName::TrafficBytesTxByInstance, + &network_labels + .clone() + .with_label_type(LabelType::ToInstanceId("unknown".to_string())), + ) + .is_none() + ); + assert!( + peer_mgr + .get_global_ctx() + .stats_manager() + .get_metric( + MetricName::TrafficControlBytesTxByInstance, + &network_labels.with_label_type(LabelType::ToInstanceId("unknown".to_string())), + ) + .is_none() + ); } #[tokio::test] diff --git a/easytier/src/peers/peer_map.rs b/easytier/src/peers/peer_map.rs index 6de1103e..46e55aaf 100644 --- a/easytier/src/peers/peer_map.rs +++ b/easytier/src/peers/peer_map.rs @@ -10,22 +10,23 @@ use tokio::sync::RwLock; use crate::{ common::{ + PeerId, error::Error, global_ctx::{ArcGlobalCtx, GlobalCtxEvent, NetworkIdentity}, - shrink_dashmap, PeerId, + shrink_dashmap, }, proto::{ api::instance::{self, PeerConnInfo}, peer_rpc::{PeerIdentityType, RoutePeerInfo}, }, - tunnel::{packet_def::ZCPacket, TunnelError}, + tunnel::{TunnelError, packet_def::ZCPacket}, }; use super::{ + PacketRecvChan, peer::Peer, peer_conn::{PeerConn, PeerConnId}, route_trait::{ArcRoute, NextHopPolicy}, - PacketRecvChan, }; pub struct PeerMap { diff --git a/easytier/src/peers/peer_ospf_route.rs b/easytier/src/peers/peer_ospf_route.rs index 0a99ca29..f54841a7 100644 --- a/easytier/src/peers/peer_ospf_route.rs +++ b/easytier/src/peers/peer_ospf_route.rs @@ -3,8 +3,8 @@ use std::{ fmt::Debug, net::{IpAddr, Ipv4Addr, Ipv6Addr}, sync::{ - atomic::{AtomicBool, AtomicU32, Ordering}, Arc, Weak, + atomic::{AtomicBool, AtomicU32, Ordering}, }, time::{Duration, Instant, SystemTime}, }; @@ -14,12 +14,12 @@ use cidr::{IpCidr, Ipv4Cidr, Ipv6Cidr}; use crossbeam::atomic::AtomicCell; use dashmap::DashMap; use ordered_hash_map::OrderedHashMap; -use parking_lot::{lock_api::RwLockUpgradableReadGuard, RwLock}; +use parking_lot::{RwLock, lock_api::RwLockUpgradableReadGuard}; use petgraph::{ + Directed, algo::dijkstra, graph::{Graph, NodeIndex}, visit::{EdgeRef, IntoNodeReferences}, - Directed, }; use prefix_trie::PrefixMap; use prost::Message; @@ -32,25 +32,24 @@ use tokio::{ use crate::{ common::{ + PeerId, config::NetworkIdentity, constants::EASYTIER_VERSION, global_ctx::{ArcGlobalCtx, GlobalCtxEvent}, shrink_dashmap, stun::StunInfoCollectorTrait, - PeerId, }, peers::route_trait::{Route, RouteInterfaceBox}, proto::{ acl::GroupIdentity, common::{Ipv4Inet, NatType, StunInfo}, peer_rpc::{ - route_foreign_network_infos, route_foreign_network_summary, - sync_route_info_request::ConnInfo, ForeignNetworkRouteInfoEntry, - ForeignNetworkRouteInfoKey, OspfRouteRpc, OspfRouteRpcClientFactory, - OspfRouteRpcServer, PeerGroupInfo, PeerIdVersion, PeerIdentityType, - RouteForeignNetworkInfos, RouteForeignNetworkSummary, RoutePeerInfo, RoutePeerInfos, - SyncRouteInfoError, SyncRouteInfoRequest, SyncRouteInfoResponse, - TrustedCredentialPubkey, + ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, OspfRouteRpc, + OspfRouteRpcClientFactory, OspfRouteRpcServer, PeerGroupInfo, PeerIdVersion, + PeerIdentityType, RouteForeignNetworkInfos, RouteForeignNetworkSummary, RoutePeerInfo, + RoutePeerInfos, SyncRouteInfoError, SyncRouteInfoRequest, SyncRouteInfoResponse, + TrustedCredentialPubkey, route_foreign_network_infos, route_foreign_network_summary, + sync_route_info_request::ConnInfo, }, rpc_types::{ self, @@ -61,13 +60,13 @@ use crate::{ }; use super::{ + PeerPacketFilter, graph_algo::dijkstra_with_first_hop, peer_rpc::PeerRpcManager, route_trait::{ DefaultRouteCostCalculator, ForeignNetworkRouteInfoMap, NextHopPolicy, RouteCostCalculator, RouteCostCalculatorInterface, }, - PeerPacketFilter, }; use atomic_shim::AtomicU64; @@ -2521,13 +2520,12 @@ impl PeerRouteServiceImpl { let now = SystemTime::now(); let mut to_remove = Vec::new(); for (peer_id, peer_info) in self.synced_route_info.peer_infos.read().iter() { - if let Ok(d) = now.duration_since(peer_info.last_update.unwrap().try_into().unwrap()) { - if d > REMOVE_DEAD_PEER_INFO_AFTER + if let Ok(d) = now.duration_since(peer_info.last_update.unwrap().try_into().unwrap()) + && (d > REMOVE_DEAD_PEER_INFO_AFTER || (d > REMOVE_UNREACHABLE_PEER_INFO_AFTER - && !self.route_table.peer_reachable(*peer_id)) - { - to_remove.push(*peer_id); - } + && !self.route_table.peer_reachable(*peer_id))) + { + to_remove.push(*peer_id); } } @@ -2621,8 +2619,16 @@ impl PeerRouteServiceImpl { return true; } - tracing::debug!(?foreign_network, "sync_route request need send to peer. my_id {:?}, dst_peer_id: {:?}, peer_infos: {:?}, conn_info: {:?}, synced_route_info: {:?} session: {:?}", - my_peer_id, dst_peer_id, peer_infos, conn_info, self.synced_route_info, session); + tracing::debug!( + ?foreign_network, + "sync_route request need send to peer. my_id {:?}, dst_peer_id: {:?}, peer_infos: {:?}, conn_info: {:?}, synced_route_info: {:?} session: {:?}", + my_peer_id, + dst_peer_id, + peer_infos, + conn_info, + self.synced_route_info, + session + ); session .need_sync_initiator_info @@ -2664,7 +2670,11 @@ impl PeerRouteServiceImpl { tracing::debug!( "sync_route_info resp: {:?}, req: {:?}, session: {:?}, my_info: {:?}, next_last_sync_succ_timestamp: {:?}", - ret, sync_route_info_req, session, self.global_ctx.network, next_last_sync_succ_timestamp + ret, + sync_route_info_req, + session, + self.global_ctx.network, + next_last_sync_succ_timestamp ); match ret.as_ref() { @@ -3020,10 +3030,10 @@ impl RouteSessionManager { service_impl.my_peer_id ); // update initiator flag for previous session - if let Some(cur_peer_id_to_initiate) = cur_dst_peer_id_to_initiate { - if let Some(session) = service_impl.get_session(cur_peer_id_to_initiate) { - session.update_initiator_flag(false); - } + if let Some(cur_peer_id_to_initiate) = cur_dst_peer_id_to_initiate + && let Some(session) = service_impl.get_session(cur_peer_id_to_initiate) + { + session.update_initiator_flag(false); } cur_dst_peer_id_to_initiate = new_initiator_dst; @@ -3247,7 +3257,14 @@ impl RouteSessionManager { tracing::debug!( "handling sync_route_info rpc: from_peer_id: {:?}, is_initiator: {:?}, peer_infos: {:?}, conn_info: {:?}, synced_route_info: {:?} session: {:?}, new_route_table: {:?}", - from_peer_id, is_initiator, peer_infos, conn_info, service_impl.synced_route_info, session, service_impl.route_table); + from_peer_id, + is_initiator, + peer_infos, + conn_info, + service_impl.synced_route_info, + session, + service_impl.route_table + ); session .dst_is_initiator @@ -3622,8 +3639,8 @@ mod tests { use std::{ collections::{BTreeSet, HashMap}, sync::{ - atomic::{AtomicU32, Ordering}, Arc, + atomic::{AtomicU32, Ordering}, }, time::{Duration, SystemTime}, }; @@ -3631,14 +3648,14 @@ mod tests { use super::{PeerRoute, REMOVE_DEAD_PEER_INFO_AFTER}; use crate::{ common::{ - global_ctx::{tests::get_mock_global_ctx, GlobalCtxEvent, TrustedKeySource}, PeerId, + global_ctx::{GlobalCtxEvent, TrustedKeySource, tests::get_mock_global_ctx}, }, connector::udp_hole_punch::tests::replace_stun_info_collector, peers::{ create_packet_recv_chan, peer_manager::{PeerManager, RouteAlgoType}, - peer_ospf_route::{PeerIdVersion, PeerRouteServiceImpl, FORCE_USE_CONN_LIST}, + peer_ospf_route::{FORCE_USE_CONN_LIST, PeerIdVersion, PeerRouteServiceImpl}, route_trait::{NextHopPolicy, Route, RouteCostCalculatorInterface, RouteInterface}, tests::{connect_peer_manager, create_mock_peer_manager, wait_route_appear}, }, @@ -3917,15 +3934,21 @@ mod tests { } assert!(service_impl.synced_route_info.is_admin_peer(&admin_info)); - assert!(!service_impl - .synced_route_info - .is_admin_peer(&credential_info)); - assert!(service_impl - .synced_route_info - .is_credential_peer(credential_info.peer_id)); - assert!(!service_impl - .synced_route_info - .is_credential_peer(admin_info.peer_id)); + assert!( + !service_impl + .synced_route_info + .is_admin_peer(&credential_info) + ); + assert!( + service_impl + .synced_route_info + .is_credential_peer(credential_info.peer_id) + ); + assert!( + !service_impl + .synced_route_info + .is_credential_peer(admin_info.peer_id) + ); } #[tokio::test] @@ -3983,14 +4006,18 @@ mod tests { .synced_route_info .verify_and_update_credential_trusts(Some(network_secret)); - assert!(service_impl - .synced_route_info - .trusted_credential_pubkeys - .contains_key(&admin_key)); - assert!(!service_impl - .synced_route_info - .trusted_credential_pubkeys - .contains_key(&credential_key)); + assert!( + service_impl + .synced_route_info + .trusted_credential_pubkeys + .contains_key(&admin_key) + ); + assert!( + !service_impl + .synced_route_info + .trusted_credential_pubkeys + .contains_key(&credential_key) + ); } #[tokio::test] @@ -4055,11 +4082,13 @@ mod tests { let guard = route.service_impl.synced_route_info.peer_infos.read(); let stored = guard.get(&from_peer_id).unwrap(); - assert!(stored - .feature_flag - .as_ref() - .map(|x| x.is_credential_peer) - .unwrap_or(false)); + assert!( + stored + .feature_flag + .as_ref() + .map(|x| x.is_credential_peer) + .unwrap_or(false) + ); assert!(stored.proxy_cidrs.is_empty()); assert!(guard.get(&forwarded_peer_id).is_none()); } @@ -4118,11 +4147,13 @@ mod tests { .await .unwrap(); - assert!(!route - .service_impl - .synced_route_info - .trusted_credential_pubkeys - .contains_key(&credential_key)); + assert!( + !route + .service_impl + .synced_route_info + .trusted_credential_pubkeys + .contains_key(&credential_key) + ); } #[tokio::test] @@ -4180,10 +4211,12 @@ mod tests { .global_ctx .update_trusted_keys(global_trusted_keys, &network_name); - assert!(service_impl - .synced_route_info - .trusted_credential_pubkeys - .contains_key(&credential_pubkey)); + assert!( + service_impl + .synced_route_info + .trusted_credential_pubkeys + .contains_key(&credential_pubkey) + ); service_impl.clear_expired_peer().await; @@ -4193,16 +4226,20 @@ mod tests { TrustedKeySource::OspfCredential, )); assert!(closed_peers.lock().contains(&credential_peer_id)); - assert!(!service_impl - .synced_route_info - .peer_infos - .read() - .contains_key(&admin_peer_id)); - assert!(!service_impl - .synced_route_info - .peer_infos - .read() - .contains_key(&credential_peer_id)); + assert!( + !service_impl + .synced_route_info + .peer_infos + .read() + .contains_key(&admin_peer_id) + ); + assert!( + !service_impl + .synced_route_info + .peer_infos + .read() + .contains_key(&credential_peer_id) + ); } #[rstest::rstest] diff --git a/easytier/src/peers/peer_rpc.rs b/easytier/src/peers/peer_rpc.rs index 35f30c85..37da48cd 100644 --- a/easytier/src/peers/peer_rpc.rs +++ b/easytier/src/peers/peer_rpc.rs @@ -4,7 +4,7 @@ use futures::{SinkExt as _, StreamExt}; use tokio::task::JoinSet; use crate::{ - common::{error::Error, stats_manager::StatsManager, PeerId}, + common::{PeerId, error::Error, stats_manager::StatsManager}, proto::rpc_impl::{self, bidirect::BidirectRpcManager}, tunnel::packet_def::ZCPacket, }; @@ -109,7 +109,7 @@ pub mod tests { use tokio::sync::Mutex; use crate::{ - common::{error::Error, new_peer_id, PeerId}, + common::{PeerId, error::Error, new_peer_id}, peers::{ peer_rpc::PeerRpcManager, tests::{connect_peer_manager, create_mock_peer_manager, wait_route_appear}, @@ -119,16 +119,16 @@ pub mod tests { tests::{GreetingClientFactory, GreetingServer, GreetingService, SayHelloRequest}, }, tunnel::{ - packet_def::ZCPacket, ring::create_ring_tunnel_pair, Tunnel, ZCPacketSink, - ZCPacketStream, + Tunnel, ZCPacketSink, ZCPacketStream, packet_def::ZCPacket, + ring::create_ring_tunnel_pair, }, }; use super::PeerRpcManagerTransport; fn random_string(len: usize) -> String { - use rand::distributions::Alphanumeric; use rand::Rng; + use rand::distributions::Alphanumeric; let mut rng = rand::thread_rng(); let s: Vec = std::iter::repeat(()) .map(|()| rng.sample(Alphanumeric)) diff --git a/easytier/src/peers/peer_session.rs b/easytier/src/peers/peer_session.rs index b69e7609..1fe813f6 100644 --- a/easytier/src/peers/peer_session.rs +++ b/easytier/src/peers/peer_session.rs @@ -1,7 +1,7 @@ use std::{ sync::{ - atomic::{AtomicBool, AtomicU32, Ordering}, Arc, Mutex, RwLock, + atomic::{AtomicBool, AtomicU32, Ordering}, }, time::{SystemTime, UNIX_EPOCH}, }; @@ -10,7 +10,7 @@ use atomic_shim::AtomicU64; use crate::{ common::PeerId, - peers::encrypt::{create_encryptor, Encryptor}, + peers::encrypt::{Encryptor, create_encryptor}, tunnel::packet_def::{StandardAeadTail, ZCPacket}, }; use anyhow::anyhow; @@ -189,11 +189,11 @@ impl PeerSessionStore { PeerSessionAction::Sync | PeerSessionAction::Create => { let root_key = root_key_32.ok_or_else(|| anyhow!("missing root_key"))?; // If the existing session is invalidated, remove it so we create a fresh one - if let Some(existing) = self.sessions.get(key) { - if !existing.is_valid() { - drop(existing); - self.sessions.remove(key); - } + if let Some(existing) = self.sessions.get(key) + && !existing.is_valid() + { + drop(existing); + self.sessions.remove(key); } let session = self .sessions diff --git a/easytier/src/peers/peer_task.rs b/easytier/src/peers/peer_task.rs index 4af026a2..72371819 100644 --- a/easytier/src/peers/peer_task.rs +++ b/easytier/src/peers/peer_task.rs @@ -1,6 +1,6 @@ use std::{ result::Result, - sync::{atomic::Ordering, Arc, Mutex}, + sync::{Arc, Mutex, atomic::Ordering}, }; use atomic_shim::AtomicU64; diff --git a/easytier/src/peers/relay_peer_map.rs b/easytier/src/peers/relay_peer_map.rs index 55a40e29..441010aa 100644 --- a/easytier/src/peers/relay_peer_map.rs +++ b/easytier/src/peers/relay_peer_map.rs @@ -3,13 +3,13 @@ use std::{sync::Arc, time::Instant}; use dashmap::DashMap; use prost::Message; use snow::params::NoiseParams; -use tokio::sync::{oneshot, Mutex, OwnedMutexGuard}; -use tokio::time::{timeout, Duration}; +use tokio::sync::{Mutex, OwnedMutexGuard, oneshot}; +use tokio::time::{Duration, timeout}; use crate::peers::foreign_network_client::ForeignNetworkClient; use crate::{ common::error::Error, - common::{global_ctx::ArcGlobalCtx, PeerId}, + common::{PeerId, global_ctx::ArcGlobalCtx}, peers::peer_map::PeerMap, peers::peer_session::{PeerSession, PeerSessionAction, PeerSessionStore, SessionKey}, peers::route_trait::NextHopPolicy, @@ -274,13 +274,13 @@ impl RelayPeerMap { return Ok(()); } - if let Some(next_retry_at) = self.states.get(&dst_peer_id).and_then(|v| v.next_retry_at) { - if Instant::now() < next_retry_at { - self.pending_packets.remove(&dst_peer_id); - return Err(Error::RouteError(Some( - "relay handshake backoff".to_string(), - ))); - } + if let Some(next_retry_at) = self.states.get(&dst_peer_id).and_then(|v| v.next_retry_at) + && Instant::now() < next_retry_at + { + self.pending_packets.remove(&dst_peer_id); + return Err(Error::RouteError(Some( + "relay handshake backoff".to_string(), + ))); } let mut last_err = None; diff --git a/easytier/src/peers/route_trait.rs b/easytier/src/peers/route_trait.rs index b5b4d9b7..55691132 100644 --- a/easytier/src/peers/route_trait.rs +++ b/easytier/src/peers/route_trait.rs @@ -6,7 +6,7 @@ use std::{ use dashmap::DashMap; use crate::{ - common::{global_ctx::NetworkIdentity, PeerId}, + common::{PeerId, global_ctx::NetworkIdentity}, proto::peer_rpc::{ ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, PeerIdentityType, RouteForeignNetworkInfos, RouteForeignNetworkSummary, RoutePeerInfo, diff --git a/easytier/src/peers/tests.rs b/easytier/src/peers/tests.rs index 400c795b..647859f3 100644 --- a/easytier/src/peers/tests.rs +++ b/easytier/src/peers/tests.rs @@ -5,13 +5,13 @@ use base64::Engine as _; use crate::{ common::{ + PeerId, error::Error, global_ctx::{ - tests::{get_mock_global_ctx, get_mock_global_ctx_with_network}, NetworkIdentity, + tests::{get_mock_global_ctx, get_mock_global_ctx_with_network}, }, stats_manager::{LabelSet, LabelType, MetricName}, - PeerId, }, proto::api::instance::TrustedKeySourcePb, tunnel::{ @@ -324,12 +324,14 @@ async fn private_mode_rejects_foreign_network_with_different_secret() { ); let _ = client_ret; wait_for_public_peers_empty(client).await; - assert!(server - .get_foreign_network_manager() - .list_foreign_networks() - .await - .foreign_networks - .is_empty()); + assert!( + server + .get_foreign_network_manager() + .list_foreign_networks() + .await + .foreign_networks + .is_empty() + ); } #[tokio::test] @@ -968,8 +970,8 @@ pub async fn create_mock_peer_manager_credential( ) -> Arc { use crate::common::config::NetworkIdentity; use crate::proto::common::SecureModeConfig; - use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; use base64::Engine; + use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; let (s, _r) = create_packet_recv_chan(); let g = get_mock_global_ctx_with_network(Some(NetworkIdentity::new_credential(network_name))); @@ -1127,10 +1129,12 @@ async fn credential_revocation_removes_from_routes() { .await; // Now revoke the credential - assert!(admin_a - .get_global_ctx() - .get_credential_manager() - .revoke_credential(&cred_id)); + assert!( + admin_a + .get_global_ctx() + .get_credential_manager() + .revoke_credential(&cred_id) + ); // Issue event to trigger OSPF sync admin_a .get_global_ctx() @@ -1416,10 +1420,12 @@ async fn multi_admin_multi_credential_route_and_revocation_isolation() { ) .await; - assert!(admin_a - .get_global_ctx() - .get_credential_manager() - .revoke_credential(&cred1_id)); + assert!( + admin_a + .get_global_ctx() + .get_credential_manager() + .revoke_credential(&cred1_id) + ); admin_a .get_global_ctx() .issue_event(crate::common::global_ctx::GlobalCtxEvent::CredentialChanged); diff --git a/easytier/src/peers/traffic_metrics.rs b/easytier/src/peers/traffic_metrics.rs index 4812e4cf..a75006b8 100644 --- a/easytier/src/peers/traffic_metrics.rs +++ b/easytier/src/peers/traffic_metrics.rs @@ -4,9 +4,8 @@ use dashmap::DashMap; use futures::future::BoxFuture; use crate::common::{ - shrink_dashmap, + PeerId, shrink_dashmap, stats_manager::{CounterHandle, LabelSet, LabelType, MetricName, StatsManager}, - PeerId, }; use crate::proto::peer_rpc::RoutePeerInfo; use crate::tunnel::packet_def::PacketType; @@ -147,11 +146,11 @@ impl LogicalTrafficMetrics { { self.total.add_sample(bytes); - if let Some(entry) = self.per_peer.get(&peer_id) { - if entry.value().is_resolved() { - entry.value().counters().add_sample(bytes); - return; - } + if let Some(entry) = self.per_peer.get(&peer_id) + && entry.value().is_resolved() + { + entry.value().counters().add_sample(bytes); + return; } let resolved_instance_id = resolver().await; @@ -388,18 +387,22 @@ mod tests { .value, 300 ); - assert!(stats_mgr - .get_metric( - MetricName::TrafficBytesTx, - &to_instance_labels("default", UNKNOWN_INSTANCE_ID), - ) - .is_none()); - assert!(stats_mgr - .get_metric( - MetricName::TrafficBytesTx, - &to_instance_labels("default", resolved_instance_id), - ) - .is_none()); + assert!( + stats_mgr + .get_metric( + MetricName::TrafficBytesTx, + &to_instance_labels("default", UNKNOWN_INSTANCE_ID), + ) + .is_none() + ); + assert!( + stats_mgr + .get_metric( + MetricName::TrafficBytesTx, + &to_instance_labels("default", resolved_instance_id), + ) + .is_none() + ); assert_eq!( stats_mgr .get_metric( diff --git a/easytier/src/proto/api.rs b/easytier/src/proto/api.rs index 73bedce0..d3b81be6 100644 --- a/easytier/src/proto/api.rs +++ b/easytier/src/proto/api.rs @@ -110,11 +110,7 @@ pub mod instance { ret += stats.rx_bytes; } - if ret == 0 { - None - } else { - Some(ret) - } + if ret == 0 { None } else { Some(ret) } } pub fn get_tx_bytes(&self) -> Option { @@ -127,11 +123,7 @@ pub mod instance { ret += stats.tx_bytes; } - if ret == 0 { - None - } else { - Some(ret) - } + if ret == 0 { None } else { Some(ret) } } pub fn get_loss_rate(&self) -> Option { @@ -167,11 +159,7 @@ pub mod instance { } } - if ret.is_empty() { - None - } else { - Some(ret) - } + if ret.is_empty() { None } else { Some(ret) } } pub fn get_udp_nat_type(&self) -> String { @@ -366,9 +354,10 @@ mod tests { ..Default::default() }; - assert!(pair - .get_loss_rate() - .is_some_and(|loss_rate| (loss_rate - 0.4).abs() < 1e-6)); + assert!( + pair.get_loss_rate() + .is_some_and(|loss_rate| (loss_rate - 0.4).abs() < 1e-6) + ); } #[test] diff --git a/easytier/src/proto/common.rs b/easytier/src/proto/common.rs index 33a3e016..89473192 100644 --- a/easytier/src/proto/common.rs +++ b/easytier/src/proto/common.rs @@ -4,10 +4,10 @@ use std::{ }; use anyhow::Context; -use base64::{prelude::BASE64_STANDARD, Engine as _}; +use base64::{Engine as _, prelude::BASE64_STANDARD}; use strum::VariantArray; -use crate::tunnel::{packet_def::CompressorAlgo, IpScheme}; +use crate::tunnel::{IpScheme, packet_def::CompressorAlgo}; include!(concat!(env!("OUT_DIR"), "/common.rs")); @@ -288,18 +288,17 @@ impl fmt::Display for Url { fn split_tunnel_scheme(raw_scheme: &str) -> Option<(&str, &'static str, bool)> { for scheme in IpScheme::VARIANTS { let scheme: &'static str = scheme.into(); - if let Some(base) = raw_scheme.strip_suffix('6') { - if let Some(prefix) = base.strip_suffix(scheme) { - if prefix.is_empty() || prefix.ends_with('-') { - return Some((prefix, scheme, true)); - } - } + if let Some(base) = raw_scheme.strip_suffix('6') + && let Some(prefix) = base.strip_suffix(scheme) + && (prefix.is_empty() || prefix.ends_with('-')) + { + return Some((prefix, scheme, true)); } - if let Some(prefix) = raw_scheme.strip_suffix(scheme) { - if prefix.is_empty() || prefix.ends_with('-') { - return Some((prefix, scheme, false)); - } + if let Some(prefix) = raw_scheme.strip_suffix(scheme) + && (prefix.is_empty() || prefix.ends_with('-')) + { + return Some((prefix, scheme, false)); } } @@ -532,7 +531,7 @@ impl SecureModeConfig { #[cfg(test)] mod tests { - use super::{normalize_tunnel_url, TunnelInfo, Url}; + use super::{TunnelInfo, Url, normalize_tunnel_url}; fn assert_ipv6_tunnel_normalization(scheme: &str, port: u16) { let expected = format!("{scheme}6://[2001:db8::1]:{port}"); diff --git a/easytier/src/proto/rpc_impl/bidirect.rs b/easytier/src/proto/rpc_impl/bidirect.rs index ab55b8ed..9ceb436c 100644 --- a/easytier/src/proto/rpc_impl/bidirect.rs +++ b/easytier/src/proto/rpc_impl/bidirect.rs @@ -1,4 +1,4 @@ -use std::sync::{atomic::AtomicBool, Arc, Mutex}; +use std::sync::{Arc, Mutex, atomic::AtomicBool}; use futures::{SinkExt as _, StreamExt}; use tokio::{task::JoinSet, time::timeout}; @@ -6,7 +6,7 @@ use tokio::{task::JoinSet, time::timeout}; use crate::{ defer, proto::rpc_types::error::Error, - tunnel::{packet_def::PacketType, ring::create_ring_tunnel_pair, Tunnel}, + tunnel::{Tunnel, packet_def::PacketType, ring::create_ring_tunnel_pair}, }; use super::{client::Client, server::Server, service_registry::ServiceRegistry}; diff --git a/easytier/src/proto/rpc_impl/client.rs b/easytier/src/proto/rpc_impl/client.rs index 5df6a6a5..9ae04c48 100644 --- a/easytier/src/proto/rpc_impl/client.rs +++ b/easytier/src/proto/rpc_impl/client.rs @@ -12,15 +12,15 @@ use tokio_stream::StreamExt; use crate::common::shrink_dashmap; use crate::common::{ - stats_manager::{LabelSet, LabelType, MetricName, StatsManager}, PeerId, + stats_manager::{LabelSet, LabelType, MetricName, StatsManager}, }; use crate::defer; use crate::proto::common::{ CompressionAlgoPb, RpcCompressionInfo, RpcDescriptor, RpcPacket, RpcRequest, RpcResponse, }; use crate::proto::rpc_impl::packet::{ - build_rpc_packet, compress_packet, decompress_packet, BuildRpcPacketArgs, + BuildRpcPacketArgs, build_rpc_packet, compress_packet, decompress_packet, }; use crate::proto::rpc_types::controller::Controller; use crate::proto::rpc_types::descriptor::MethodDescriptor; diff --git a/easytier/src/proto/rpc_impl/mod.rs b/easytier/src/proto/rpc_impl/mod.rs index 8d7da71f..09366a36 100644 --- a/easytier/src/proto/rpc_impl/mod.rs +++ b/easytier/src/proto/rpc_impl/mod.rs @@ -1,4 +1,4 @@ -use crate::tunnel::{mpsc::MpscTunnel, Tunnel}; +use crate::tunnel::{Tunnel, mpsc::MpscTunnel}; pub type RpcController = super::rpc_types::controller::BaseController; diff --git a/easytier/src/proto/rpc_impl/packet.rs b/easytier/src/proto/rpc_impl/packet.rs index 12280538..4f8b62b7 100644 --- a/easytier/src/proto/rpc_impl/packet.rs +++ b/easytier/src/proto/rpc_impl/packet.rs @@ -1,7 +1,7 @@ use prost::Message as _; use crate::{ - common::{compressor::DefaultCompressor, PeerId}, + common::{PeerId, compressor::DefaultCompressor}, proto::{ common::{CompressionAlgoPb, RpcCompressionInfo, RpcDescriptor, RpcPacket}, rpc_types::error::Error, diff --git a/easytier/src/proto/rpc_impl/server.rs b/easytier/src/proto/rpc_impl/server.rs index 94de54c8..4b251202 100644 --- a/easytier/src/proto/rpc_impl/server.rs +++ b/easytier/src/proto/rpc_impl/server.rs @@ -11,9 +11,8 @@ use tokio_stream::StreamExt; use crate::{ common::{ - join_joinset_background, + PeerId, join_joinset_background, stats_manager::{LabelSet, LabelType, MetricName, StatsManager}, - PeerId, }, proto::{ common::{ @@ -24,16 +23,16 @@ use crate::{ rpc_types::{controller::Controller, error::Result}, }, tunnel::{ + Tunnel, ZCPacketStream, mpsc::{MpscTunnel, MpscTunnelSender}, ring::create_ring_tunnel_pair, - Tunnel, ZCPacketStream, }, }; use super::{ - packet::{build_rpc_packet, compress_packet, decompress_packet, PacketMerger}, - service_registry::ServiceRegistry, RpcController, Transport, + packet::{PacketMerger, build_rpc_packet, compress_packet, decompress_packet}, + service_registry::ServiceRegistry, }; #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/easytier/src/proto/rpc_impl/standalone.rs b/easytier/src/proto/rpc_impl/standalone.rs index a392f55c..0988ad04 100644 --- a/easytier/src/proto/rpc_impl/standalone.rs +++ b/easytier/src/proto/rpc_impl/standalone.rs @@ -1,5 +1,5 @@ use std::{ - sync::{atomic::AtomicU32, Arc, Mutex}, + sync::{Arc, Mutex, atomic::AtomicU32}, time::Duration, }; @@ -204,8 +204,8 @@ mod tests { use crate::{ proto::rpc_impl::standalone::StandAloneServer, tunnel::{ - tcp::{TcpTunnelConnector, TcpTunnelListener}, TunnelConnector as _, + tcp::{TcpTunnelConnector, TcpTunnelListener}, }, }; diff --git a/easytier/src/proto/tests.rs b/easytier/src/proto/tests.rs index 8d9379e7..ee32bea3 100644 --- a/easytier/src/proto/tests.rs +++ b/easytier/src/proto/tests.rs @@ -191,8 +191,8 @@ impl TestContext { } fn random_string(len: usize) -> String { - use rand::distributions::Alphanumeric; use rand::Rng; + use rand::distributions::Alphanumeric; let mut rng = rand::thread_rng(); let s: Vec = std::iter::repeat(()) .map(|()| rng.sample(Alphanumeric)) diff --git a/easytier/src/rpc_service/api.rs b/easytier/src/rpc_service/api.rs index e414e9e9..77aafd0d 100644 --- a/easytier/src/rpc_service/api.rs +++ b/easytier/src/rpc_service/api.rs @@ -30,7 +30,7 @@ use crate::{ port_forward_manage::PortForwardManageRpcService, proxy::TcpProxyRpcService, stats::StatsRpcService, vpn_portal::VpnPortalRpcService, }, - tunnel::{tcp::TcpTunnelListener, TunnelListener}, + tunnel::{TunnelListener, tcp::TcpTunnelListener}, web_client::{DefaultHooks, WebClientHooks}, }; diff --git a/easytier/src/rpc_service/instance_manage.rs b/easytier/src/rpc_service/instance_manage.rs index 4562344e..9e69b63a 100644 --- a/easytier/src/rpc_service/instance_manage.rs +++ b/easytier/src/rpc_service/instance_manage.rs @@ -92,17 +92,16 @@ impl WebClientService for InstanceManageRpcService { ConfigFileControl::new(None, ConfigFilePermission::default()) }; - if !control.is_read_only() { - if let Some(config_file) = control.path.as_ref() { - if let Err(e) = std::fs::write(config_file, cfg.dump()) { - tracing::warn!( - "failed to write config file {}: {}", - config_file.display(), - e - ); - control.set_read_only(true); - } - } + if !control.is_read_only() + && let Some(config_file) = control.path.as_ref() + && let Err(e) = std::fs::write(config_file, cfg.dump()) + { + tracing::warn!( + "failed to write config file {}: {}", + config_file.display(), + e + ); + control.set_read_only(true); } if let Err(e) = self.hooks.pre_run_network_instance(&cfg).await { diff --git a/easytier/src/rpc_service/logger.rs b/easytier/src/rpc_service/logger.rs index 23a73cde..f46e8599 100644 --- a/easytier/src/rpc_service/logger.rs +++ b/easytier/src/rpc_service/logger.rs @@ -1,4 +1,4 @@ -use std::sync::{mpsc::Sender, Mutex, OnceLock}; +use std::sync::{Mutex, OnceLock, mpsc::Sender}; use crate::proto::{ api::logger::{ @@ -72,10 +72,10 @@ impl LoggerRpc for LoggerRpcService { } // 更新当前日志级别 - if let Some(current_level) = CURRENT_LOG_LEVEL.get() { - if let Ok(mut level) = current_level.lock() { - *level = Self::log_level_to_string(request.level()); - } + if let Some(current_level) = CURRENT_LOG_LEVEL.get() + && let Ok(mut level) = current_level.lock() + { + *level = Self::log_level_to_string(request.level()); } Ok(SetLoggerConfigResponse {}) diff --git a/easytier/src/rpc_service/mod.rs b/easytier/src/rpc_service/mod.rs index cd6ca67e..a51cd987 100644 --- a/easytier/src/rpc_service/mod.rs +++ b/easytier/src/rpc_service/mod.rs @@ -100,12 +100,10 @@ fn get_instance_service( if let Some(api::instance::instance_identifier::Selector::InstanceSelector( selector, )) = selector + && let Some(name) = selector.name.as_ref() + && v.get_inst_name() != *name { - if let Some(name) = selector.name.as_ref() { - if v.get_inst_name() != *name { - return false; - } - } + return false; } true }) @@ -118,7 +116,7 @@ fn get_instance_service( return Err(anyhow::anyhow!( "{} instances match the selector, please specify the instance ID", ids.len() - )) + )); } } }; diff --git a/easytier/src/rpc_service/remote_client.rs b/easytier/src/rpc_service/remote_client.rs index e40fcbcf..b088dde8 100644 --- a/easytier/src/rpc_service/remote_client.rs +++ b/easytier/src/rpc_service/remote_client.rs @@ -208,8 +208,8 @@ where ) -> Result> { let mut metas = std::collections::HashMap::new(); - if let Some(client) = self.get_rpc_client(identify.clone()) { - if let Ok(resp) = client + if let Some(client) = self.get_rpc_client(identify.clone()) + && let Ok(resp) = client .list_network_instance_meta( BaseController::default(), ListNetworkInstanceMetaRequest { @@ -217,12 +217,11 @@ where }, ) .await - { - for meta in resp.metas { - if let Some(inst_id) = meta.inst_id.as_ref() { - let inst_id: uuid::Uuid = (*inst_id).into(); - metas.insert(inst_id, meta); - } + { + for meta in resp.metas { + if let Some(inst_id) = meta.inst_id.as_ref() { + let inst_id: uuid::Uuid = (*inst_id).into(); + metas.insert(inst_id, meta); } } } @@ -271,8 +270,8 @@ where identify: T, inst_id: uuid::Uuid, ) -> Result> { - if let Some(client) = self.get_rpc_client(identify.clone()) { - if let Ok(resp) = client + if let Some(client) = self.get_rpc_client(identify.clone()) + && let Ok(resp) = client .get_network_instance_config( BaseController::default(), GetNetworkInstanceConfigRequest { @@ -280,11 +279,9 @@ where }, ) .await - { - if let Some(config) = resp.config { - return Ok(config); - } - } + && let Some(config) = resp.config + { + return Ok(config); } let inst_id = inst_id.to_string(); @@ -354,7 +351,7 @@ where ) -> Result<(), E>; async fn delete_network_configs(&self, identify: T, network_inst_ids: &[Uuid]) - -> Result<(), E>; + -> Result<(), E>; async fn update_network_config_state( &self, @@ -364,7 +361,7 @@ where ) -> Result<(), E>; async fn list_network_configs(&self, identify: T, props: ListNetworkProps) - -> Result, E>; + -> Result, E>; async fn get_network_config(&self, identify: T, network_inst_id: &str) -> Result, E>; } diff --git a/easytier/src/service_manager/mod.rs b/easytier/src/service_manager/mod.rs index 83486250..c1944504 100644 --- a/easytier/src/service_manager/mod.rs +++ b/easytier/src/service_manager/mod.rs @@ -351,7 +351,7 @@ mod win_service_manager { ServiceStopCtx, ServiceUninstallCtx, }; - use winreg::{enums::*, RegKey}; + use winreg::{RegKey, enums::*}; use crate::common::constants::WIN_SERVICE_WORK_DIR_REG_KEY; diff --git a/easytier/src/tests/credential_tests.rs b/easytier/src/tests/credential_tests.rs index fbbf59ef..989e2aa6 100644 --- a/easytier/src/tests/credential_tests.rs +++ b/easytier/src/tests/credential_tests.rs @@ -235,11 +235,7 @@ async fn wait_ping_reachability(src_ns: &str, dst_ip: &str, reachable: bool, tim wait_for_condition( || async { let ping_result = ping_test(src_ns, dst_ip, None).await; - if reachable { - ping_result - } else { - !ping_result - } + if reachable { ping_result } else { !ping_result } }, timeout, ) diff --git a/easytier/src/tests/mod.rs b/easytier/src/tests/mod.rs index ec55d629..7f48a63b 100644 --- a/easytier/src/tests/mod.rs +++ b/easytier/src/tests/mod.rs @@ -11,6 +11,14 @@ use std::io::IsTerminal as _; use crate::common::PeerId; use crate::peers::peer_manager::PeerManager; +pub fn set_env_var, V: AsRef>(key: K, value: V) { + unsafe { std::env::set_var(key, value) } +} + +pub fn remove_env_var>(key: K) { + unsafe { std::env::remove_var(key) } +} + pub fn get_guest_veth_name(net_ns: &str) -> &str { Box::leak(format!("veth_{}_g", net_ns).into_boxed_str()) } diff --git a/easytier/src/tests/three_node.rs b/easytier/src/tests/three_node.rs index dafabd8b..8436c0a3 100644 --- a/easytier/src/tests/three_node.rs +++ b/easytier/src/tests/three_node.rs @@ -3,11 +3,11 @@ use core::panic; use std::{ future::Future, - sync::{atomic::AtomicU32, Arc}, + sync::{Arc, atomic::AtomicU32}, time::Duration, }; -use rand::{rngs::OsRng, Rng}; +use rand::{Rng, rngs::OsRng}; use tokio::{net::UdpSocket, task::JoinSet}; use x25519_dalek::StaticSecret; @@ -846,15 +846,13 @@ pub async fn proxy_three_node_disconnect_test(#[values("tcp", "wg")] proto: &str })); wait_for_condition( || async { - let ret = !insts[2] + !insts[2] .get_peer_manager() .get_peer_map() .list_peers_with_conn() .await .iter() - .any(|r| *r == inst4.peer_id()); - - ret + .any(|r| *r == inst4.peer_id()) }, // 0 down, assume last packet is recv in -0.01 // [2, 7) send ping @@ -999,7 +997,7 @@ pub async fn foreign_network_forward_nic_data() { use std::{net::SocketAddr, str::FromStr}; use defguard_wireguard_rs::{ - host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi, + InterfaceConfiguration, WGApi, WireguardInterfaceApi, host::Peer, key::Key, net::IpAddrMask, }; fn run_wireguard_client( @@ -2257,10 +2255,10 @@ pub async fn acl_group_base_test( #[values(true, false)] enable_quic_proxy: bool, ) { use crate::tunnel::{ + TunnelConnector, TunnelListener, common::tests::_tunnel_pingpong_netns_with_timeout, tcp::{TcpTunnelConnector, TcpTunnelListener}, udp::{UdpTunnelConnector, UdpTunnelListener}, - TunnelConnector, TunnelListener, }; use rand::Rng; @@ -2683,10 +2681,10 @@ pub async fn acl_group_self_test( #[values(true, false)] enable_quic_proxy: bool, ) { use crate::tunnel::{ + TunnelConnector, TunnelListener, common::tests::_tunnel_pingpong_netns_with_timeout, tcp::{TcpTunnelConnector, TcpTunnelListener}, udp::{UdpTunnelConnector, UdpTunnelListener}, - TunnelConnector, TunnelListener, }; use rand::Rng; @@ -2877,10 +2875,10 @@ pub async fn whitelist_test( .await; use crate::tunnel::{ + TunnelConnector, TunnelListener, common::tests::_tunnel_pingpong_netns_with_timeout, tcp::{TcpTunnelConnector, TcpTunnelListener}, udp::{UdpTunnelConnector, UdpTunnelListener}, - TunnelConnector, TunnelListener, }; use rand::Rng; @@ -3052,7 +3050,7 @@ pub async fn config_patch_test() { pub fn generate_secure_mode_config_with_key( private_key: &x25519_dalek::StaticSecret, ) -> SecureModeConfig { - use base64::{prelude::BASE64_STANDARD, Engine}; + use base64::{Engine, prelude::BASE64_STANDARD}; use x25519_dalek::PublicKey; let public = PublicKey::from(private_key); diff --git a/easytier/src/tunnel/common.rs b/easytier/src/tunnel/common.rs index b4c05ff5..f6814f6e 100644 --- a/easytier/src/tunnel/common.rs +++ b/easytier/src/tunnel/common.rs @@ -3,10 +3,10 @@ use std::{ net::{IpAddr, SocketAddr}, pin::Pin, sync::{Arc, Mutex}, - task::{ready, Poll}, + task::{Poll, ready}, }; -use futures::{stream::FuturesUnordered, Future, Sink, Stream}; +use futures::{Future, Sink, Stream, stream::FuturesUnordered}; use network_interface::NetworkInterfaceConfig as _; use pin_project_lite::pin_project; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; @@ -18,12 +18,12 @@ use zerocopy::FromBytes as _; use super::TunnelInfo; -use crate::tunnel::packet_def::{ZCPacket, PEER_MANAGER_HEADER_SIZE}; +use crate::tunnel::packet_def::{PEER_MANAGER_HEADER_SIZE, ZCPacket}; use super::{ - buf::BufList, - packet_def::{TCPTunnelHeader, ZCPacketType, TCP_TUNNEL_HEADER_SIZE}, SinkItem, StreamItem, Tunnel, TunnelError, ZCPacketSink, ZCPacketStream, + buf::BufList, + packet_def::{TCP_TUNNEL_HEADER_SIZE, TCPTunnelHeader, ZCPacketType}, }; pub struct TunnelWrapper { @@ -454,7 +454,7 @@ pub mod tests { use crate::{ common::netns::NetNS, - tunnel::{packet_def::ZCPacket, TunnelConnector, TunnelListener}, + tunnel::{TunnelConnector, TunnelListener, packet_def::ZCPacket}, }; pub async fn _tunnel_echo_server(tunnel: Box, once: bool) { diff --git a/easytier/src/tunnel/fake_tcp/mod.rs b/easytier/src/tunnel/fake_tcp/mod.rs index 87b38be1..c255ab54 100644 --- a/easytier/src/tunnel/fake_tcp/mod.rs +++ b/easytier/src/tunnel/fake_tcp/mod.rs @@ -17,11 +17,11 @@ use tokio::{io::AsyncReadExt, net::TcpStream, sync::Mutex}; use crate::{ common::scoped_task::ScopedTask, tunnel::{ - common::TunnelWrapper, - fake_tcp::netfilter::create_tun, - packet_def::{ZCPacket, ZCPacketType, PEER_MANAGER_HEADER_SIZE, TCP_TUNNEL_HEADER_SIZE}, FromUrl, IpVersion, SinkError, SinkItem, StreamItem, Tunnel, TunnelConnector, TunnelError, TunnelInfo, TunnelListener, + common::TunnelWrapper, + fake_tcp::netfilter::create_tun, + packet_def::{PEER_MANAGER_HEADER_SIZE, TCP_TUNNEL_HEADER_SIZE, ZCPacket, ZCPacketType}, }, }; diff --git a/easytier/src/tunnel/fake_tcp/netfilter/linux_bpf.rs b/easytier/src/tunnel/fake_tcp/netfilter/linux_bpf.rs index b710fc15..0b138f91 100644 --- a/easytier/src/tunnel/fake_tcp/netfilter/linux_bpf.rs +++ b/easytier/src/tunnel/fake_tcp/netfilter/linux_bpf.rs @@ -7,8 +7,8 @@ use std::mem; use std::net::IpAddr; use std::net::SocketAddr; use std::os::fd::{AsRawFd, FromRawFd, OwnedFd}; -use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::time::{Duration, Instant}; use tokio::sync::Mutex; @@ -182,13 +182,13 @@ fn build_tcp_filter( src_addr: Option, dst_addr: SocketAddr, ) -> io::Result> { - if let Some(src) = src_addr { - if src.is_ipv4() != dst_addr.is_ipv4() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "src/dst addr family mismatch", - )); - } + if let Some(src) = src_addr + && src.is_ipv4() != dst_addr.is_ipv4() + { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "src/dst addr family mismatch", + )); } let mut b = BpfBuilder::new(); @@ -637,7 +637,7 @@ mod tests { use pnet::util::MacAddr; use rand::Rng; use std::net::{IpAddr, Ipv4Addr}; - use tokio::time::{timeout, Duration}; + use tokio::time::{Duration, timeout}; fn is_root() -> bool { unsafe { libc::geteuid() == 0 } diff --git a/easytier/src/tunnel/fake_tcp/netfilter/macos_bpf.rs b/easytier/src/tunnel/fake_tcp/netfilter/macos_bpf.rs index 17278088..afc11927 100644 --- a/easytier/src/tunnel/fake_tcp/netfilter/macos_bpf.rs +++ b/easytier/src/tunnel/fake_tcp/netfilter/macos_bpf.rs @@ -7,8 +7,8 @@ use std::mem; use std::net::IpAddr; use std::net::SocketAddr; use std::os::fd::{AsRawFd, FromRawFd, OwnedFd}; -use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use tokio::sync::Mutex; use tracing::{debug, info, warn}; diff --git a/easytier/src/tunnel/fake_tcp/netfilter/pnet.rs b/easytier/src/tunnel/fake_tcp/netfilter/pnet.rs index a7f4fd20..4f6e5e66 100644 --- a/easytier/src/tunnel/fake_tcp/netfilter/pnet.rs +++ b/easytier/src/tunnel/fake_tcp/netfilter/pnet.rs @@ -2,8 +2,8 @@ use std::{ io, net::{IpAddr, SocketAddr}, sync::{ - atomic::{AtomicU32, Ordering}, Arc, Weak, + atomic::{AtomicU32, Ordering}, }, }; @@ -25,10 +25,10 @@ fn filter_tcp_packet( src_addr: Option<&SocketAddr>, dst_addr: Option<&SocketAddr>, ) -> bool { + use pnet::packet::Packet; use pnet::packet::ethernet::EthernetPacket; use pnet::packet::ipv4::Ipv4Packet; use pnet::packet::tcp::TcpPacket; - use pnet::packet::Packet; let ethernet = if let Some(ethernet) = EthernetPacket::new(packet) { ethernet diff --git a/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs b/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs index 5aac0dcf..1d58f235 100644 --- a/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs +++ b/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs @@ -9,7 +9,7 @@ use tokio::sync::Mutex; use windivert::error::WinDivertError; use windivert::packet::WinDivertPacket; use windivert::prelude::{WinDivertFlags, WinDivertShutdownMode}; -use windivert::{layer, WinDivert}; +use windivert::{WinDivert, layer}; use crate::tunnel::fake_tcp::stack; diff --git a/easytier/src/tunnel/fake_tcp/stack.rs b/easytier/src/tunnel/fake_tcp/stack.rs index e6b7f27f..3173c383 100644 --- a/easytier/src/tunnel/fake_tcp/stack.rs +++ b/easytier/src/tunnel/fake_tcp/stack.rs @@ -44,14 +44,14 @@ use super::packet::*; use bytes::{Bytes, BytesMut}; use crossbeam::atomic::AtomicCell; use pnet::packet::tcp::TcpOptionNumbers; -use pnet::packet::{tcp, Packet}; +use pnet::packet::{Packet, tcp}; use pnet::util::MacAddr; use std::collections::{HashMap, HashSet}; use std::fmt; use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; use std::sync::{ - atomic::{AtomicU32, Ordering}, Arc, RwLock, + atomic::{AtomicU32, Ordering}, }; use tokio::sync::broadcast; use tokio::time; diff --git a/easytier/src/tunnel/filter.rs b/easytier/src/tunnel/filter.rs index 929f3537..787eeab9 100644 --- a/easytier/src/tunnel/filter.rs +++ b/easytier/src/tunnel/filter.rs @@ -98,7 +98,7 @@ where } } - fn wrap_sink(&self, sink: S) -> impl ZCPacketSink { + fn wrap_sink(filter: Arc, sink: S) -> impl ZCPacketSink { struct SinkWrapper { sink: S, filter: Arc, @@ -143,13 +143,13 @@ where } } - SinkWrapper { - sink, - filter: self.filter.clone(), - } + SinkWrapper { sink, filter } } - fn wrap_stream(&self, stream: S) -> impl ZCPacketStream { + fn wrap_stream( + filter: Arc, + stream: S, + ) -> impl ZCPacketStream { struct StreamWrapper { stream: S, filter: Arc, @@ -186,10 +186,7 @@ where } } - StreamWrapper { - stream, - filter: self.filter.clone(), - } + StreamWrapper { stream, filter } } } @@ -204,9 +201,10 @@ where fn split(&self) -> (Pin>, Pin>) { let (stream, sink) = self.inner.split(); + let filter = self.filter.clone(); ( - Box::pin(self.wrap_stream(stream)), - Box::pin(self.wrap_sink(sink)), + Box::pin(Self::wrap_stream(filter.clone(), stream)), + Box::pin(Self::wrap_sink(filter, sink)), ) } } @@ -363,9 +361,9 @@ pub mod tests { let out = filter.filter_output(); - let a = out.0 .0 .0 .1; - let b = out.0 .0 .1; - let c = out.0 .1; + let a = out.0.0.0.1; + let b = out.0.0.1; + let c = out.0.1; let _d = out.1; assert_eq!(1, a.0.len()); diff --git a/easytier/src/tunnel/mpsc.rs b/easytier/src/tunnel/mpsc.rs index 870222c0..77e77257 100644 --- a/easytier/src/tunnel/mpsc.rs +++ b/easytier/src/tunnel/mpsc.rs @@ -7,9 +7,9 @@ use tokio::time::timeout; use crate::{common::scoped_task::ScopedTask, proto::common::TunnelInfo}; -use super::{packet_def::ZCPacket, Tunnel, TunnelError, ZCPacketSink, ZCPacketStream}; +use super::{Tunnel, TunnelError, ZCPacketSink, ZCPacketStream, packet_def::ZCPacket}; -use tokio::sync::mpsc::{channel, error::TrySendError, Receiver, Sender}; +use tokio::sync::mpsc::{Receiver, Sender, channel, error::TrySendError}; // use tachyonix::{channel, Receiver, Sender, TrySendError}; use futures::SinkExt; @@ -141,9 +141,9 @@ mod tests { use futures::StreamExt; use crate::tunnel::{ - ring::{create_ring_tunnel_pair, RING_TUNNEL_CAP}, - tcp::{TcpTunnelConnector, TcpTunnelListener}, TunnelConnector, TunnelListener, + ring::{RING_TUNNEL_CAP, create_ring_tunnel_pair}, + tcp::{TcpTunnelConnector, TcpTunnelListener}, }; use super::*; diff --git a/easytier/src/tunnel/packet_def.rs b/easytier/src/tunnel/packet_def.rs index 949b3258..0103c4ff 100644 --- a/easytier/src/tunnel/packet_def.rs +++ b/easytier/src/tunnel/packet_def.rs @@ -1,9 +1,9 @@ use bytes::Bytes; use bytes::BytesMut; -use zerocopy::byteorder::*; use zerocopy::AsBytes; use zerocopy::FromBytes; use zerocopy::FromZeroes; +use zerocopy::byteorder::*; type DefaultEndian = LittleEndian; diff --git a/easytier/src/tunnel/quic.rs b/easytier/src/tunnel/quic.rs index b211d733..96ca5a6f 100644 --- a/easytier/src/tunnel/quic.rs +++ b/easytier/src/tunnel/quic.rs @@ -7,15 +7,15 @@ use std::{ }; use crate::tunnel::{ - common::{setup_sokcet2, FramedReader, FramedWriter, TunnelWrapper}, FromUrl, TunnelInfo, + common::{FramedReader, FramedWriter, TunnelWrapper, setup_sokcet2}, }; use anyhow::Context; use super::{IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener}; use quinn::{ - congestion::BbrConfig, udp::RecvMeta, AsyncUdpSocket, ClientConfig, Connection, Endpoint, - EndpointConfig, ServerConfig, TransportConfig, UdpPoller, + AsyncUdpSocket, ClientConfig, Connection, Endpoint, EndpointConfig, ServerConfig, + TransportConfig, UdpPoller, congestion::BbrConfig, udp::RecvMeta, }; pub fn transport_config() -> Arc { @@ -309,8 +309,8 @@ impl TunnelConnector for QuicTunnelConnector { #[cfg(test)] mod tests { use crate::tunnel::{ - common::tests::{_tunnel_bench, _tunnel_pingpong}, IpVersion, TunnelConnector, + common::tests::{_tunnel_bench, _tunnel_pingpong}, }; use super::*; diff --git a/easytier/src/tunnel/ring.rs b/easytier/src/tunnel/ring.rs index 0459c393..2573bdcc 100644 --- a/easytier/src/tunnel/ring.rs +++ b/easytier/src/tunnel/ring.rs @@ -1,10 +1,10 @@ -use async_ringbuf::{traits::*, AsyncHeapCons, AsyncHeapProd, AsyncHeapRb}; +use async_ringbuf::{AsyncHeapCons, AsyncHeapProd, AsyncHeapRb, traits::*}; use crossbeam::atomic::AtomicCell; use std::{ collections::HashMap, fmt::Debug, sync::Arc, - task::{ready, Poll}, + task::{Poll, ready}, }; use async_trait::async_trait; @@ -18,8 +18,8 @@ use uuid::Uuid; use crate::tunnel::{FromUrl, IpVersion, SinkError, SinkItem}; use super::{ - build_url_from_socket_addr, common::TunnelWrapper, StreamItem, Tunnel, TunnelConnector, - TunnelError, TunnelInfo, TunnelListener, + StreamItem, Tunnel, TunnelConnector, TunnelError, TunnelInfo, TunnelListener, + build_url_from_socket_addr, common::TunnelWrapper, }; pub static RING_TUNNEL_CAP: usize = 128; diff --git a/easytier/src/tunnel/tcp.rs b/easytier/src/tunnel/tcp.rs index 70fd13b4..abcb73f6 100644 --- a/easytier/src/tunnel/tcp.rs +++ b/easytier/src/tunnel/tcp.rs @@ -7,8 +7,8 @@ use futures::stream::FuturesUnordered; use tokio::net::{TcpListener, TcpSocket, TcpStream}; use super::{ - common::{wait_for_connect_futures, FramedReader, FramedWriter, TunnelWrapper}, IpVersion, Tunnel, TunnelError, TunnelListener, + common::{FramedReader, FramedWriter, TunnelWrapper, wait_for_connect_futures}, }; const TCP_MTU_BYTES: usize = 2000; @@ -216,8 +216,8 @@ impl super::TunnelConnector for TcpTunnelConnector { #[cfg(test)] mod tests { use crate::tunnel::{ - common::tests::{_tunnel_bench, _tunnel_pingpong}, TunnelConnector, + common::tests::{_tunnel_bench, _tunnel_pingpong}, }; use super::*; diff --git a/easytier/src/tunnel/udp.rs b/easytier/src/tunnel/udp.rs index b191b7b3..6432b64f 100644 --- a/easytier/src/tunnel/udp.rs +++ b/easytier/src/tunnel/udp.rs @@ -8,7 +8,7 @@ use anyhow::Context; use async_trait::async_trait; use bytes::BytesMut; use dashmap::DashMap; -use futures::{stream::FuturesUnordered, SinkExt, StreamExt}; +use futures::{SinkExt, StreamExt, stream::FuturesUnordered}; use rand::{Rng, SeedableRng}; use zerocopy::{AsBytes, FromBytes}; @@ -19,20 +19,20 @@ use tokio::{ task::JoinSet, }; -use tracing::{instrument, Instrument}; +use tracing::{Instrument, instrument}; use super::{ - common::{setup_sokcet2, setup_sokcet2_ext, wait_for_connect_futures}, - packet_def::{UDPTunnelHeader, V6HolePunchPacket, UDP_TUNNEL_HEADER_SIZE}, - ring::{RingSink, RingStream}, FromUrl, IpVersion, Tunnel, TunnelConnCounter, TunnelError, TunnelInfo, TunnelListener, TunnelUrl, + common::{setup_sokcet2, setup_sokcet2_ext, wait_for_connect_futures}, + packet_def::{UDP_TUNNEL_HEADER_SIZE, UDPTunnelHeader, V6HolePunchPacket}, + ring::{RingSink, RingStream}, }; use crate::{ common::{join_joinset_background, scoped_task::ScopedTask, shrink_dashmap}, tunnel::{ build_url_from_socket_addr, - common::{reserve_buf, TunnelWrapper}, + common::{TunnelWrapper, reserve_buf}, packet_def::{UdpPacketType, ZCPacket, ZCPacketType}, ring::RingTunnel, }, @@ -150,8 +150,8 @@ async fn respond_stun_packet( use crate::common::stun_codec_ext::*; use bytecodec::{DecodeExt as _, EncodeExt as _}; use stun_codec::{ - rfc5389::{attributes::XorMappedAddress, methods::BINDING}, Message, MessageClass, MessageDecoder, MessageEncoder, + rfc5389::{attributes::XorMappedAddress, methods::BINDING}, }; let mut decoder = MessageDecoder::::new(); @@ -884,11 +884,11 @@ mod tests { use crate::{ common::global_ctx::tests::get_mock_global_ctx, tunnel::{ + TunnelConnector, common::{ get_interface_name_by_ip, tests::{_tunnel_bench, _tunnel_echo_server, _tunnel_pingpong, wait_for_condition}, }, - TunnelConnector, }, }; diff --git a/easytier/src/tunnel/unix.rs b/easytier/src/tunnel/unix.rs index 6c8415d2..7cba3f2a 100644 --- a/easytier/src/tunnel/unix.rs +++ b/easytier/src/tunnel/unix.rs @@ -1,13 +1,13 @@ use std::path::Path; use async_trait::async_trait; -use tokio::net::{unix::SocketAddr, UnixListener, UnixStream}; +use tokio::net::{UnixListener, UnixStream, unix::SocketAddr}; use super::TunnelInfo; use super::{ - common::{FramedReader, FramedWriter, TunnelWrapper}, IpVersion, Tunnel, TunnelError, TunnelListener, + common::{FramedReader, FramedWriter, TunnelWrapper}, }; const MAX_PACKET_SIZE: usize = 4096; diff --git a/easytier/src/tunnel/websocket.rs b/easytier/src/tunnel/websocket.rs index 1f1394ce..eed5f111 100644 --- a/easytier/src/tunnel/websocket.rs +++ b/easytier/src/tunnel/websocket.rs @@ -1,14 +1,14 @@ use super::{ - common::{setup_sokcet2, wait_for_connect_futures, TunnelWrapper}, + FromUrl, IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener, + common::{TunnelWrapper, setup_sokcet2, wait_for_connect_futures}, insecure_tls::{get_insecure_tls_cert, init_crypto_provider}, packet_def::{ZCPacket, ZCPacketType}, - FromUrl, IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener, }; use crate::{proto::common::TunnelInfo, tunnel::insecure_tls::get_insecure_tls_client_config}; use anyhow::Context; use bytes::BytesMut; use forwarded_header_value::ForwardedHeaderValue; -use futures::{stream::FuturesUnordered, SinkExt, StreamExt}; +use futures::{SinkExt, StreamExt, stream::FuturesUnordered}; use pnet::ipnetwork::IpNetwork; use std::{ net::SocketAddr, @@ -117,8 +117,7 @@ impl WsTunnelListener { if TRUSTED_PROXIES .iter() .any(|net| net.contains(peer_addr.ip())) - { - if let Some(forwarded) = request + && let Some(forwarded) = request .headers() .get("Forwarded") .and_then(|f| f.to_str().ok()) @@ -130,16 +129,14 @@ impl WsTunnelListener { .and_then(|f| f.to_str().ok()) .and_then(|f| ForwardedHeaderValue::from_x_forwarded_for(f).ok()) }) - { - if let Some(ip) = forwarded.remotest_forwarded_for_ip() { - remote_addr.set_host(Some(&ip.to_string())).map_err(|_| { - TunnelError::InvalidAddr(format!("invalid forwarded ip {}", ip)) - })?; - remote_addr - .query_pairs_mut() - .append_pair("proxy", &peer_addr.to_string()); - } - } + && let Some(ip) = forwarded.remotest_forwarded_for_ip() + { + remote_addr + .set_host(Some(&ip.to_string())) + .map_err(|_| TunnelError::InvalidAddr(format!("invalid forwarded ip {}", ip)))?; + remote_addr + .query_pairs_mut() + .append_pair("proxy", &peer_addr.to_string()); } let (write, read) = stream.split(); diff --git a/easytier/src/tunnel/wireguard.rs b/easytier/src/tunnel/wireguard.rs index e8833973..d1968c60 100644 --- a/easytier/src/tunnel/wireguard.rs +++ b/easytier/src/tunnel/wireguard.rs @@ -2,7 +2,7 @@ use std::{ fmt::{Debug, Formatter}, net::SocketAddr, pin::Pin, - sync::{atomic::AtomicBool, Arc}, + sync::{Arc, atomic::AtomicBool}, time::Duration, }; @@ -10,30 +10,30 @@ use anyhow::Context; use async_recursion::async_recursion; use async_trait::async_trait; use boringtun::{ - noise::{errors::WireGuardError, Tunn, TunnResult}, + noise::{Tunn, TunnResult, errors::WireGuardError}, x25519::{PublicKey, StaticSecret}, }; use bytes::BytesMut; use crossbeam::atomic::AtomicCell; use dashmap::DashMap; -use futures::{stream::FuturesUnordered, SinkExt, StreamExt}; +use futures::{SinkExt, StreamExt, stream::FuturesUnordered}; use rand::RngCore; use tokio::{net::UdpSocket, sync::Mutex, task::JoinSet}; use super::{ - common::{setup_sokcet2, setup_sokcet2_ext, wait_for_connect_futures}, - generate_digest_from_str, - packet_def::{ZCPacketType, PEER_MANAGER_HEADER_SIZE}, - ring::create_ring_tunnel_pair, FromUrl, IpVersion, Tunnel, TunnelError, TunnelInfo, TunnelListener, TunnelUrl, ZCPacketSink, ZCPacketStream, + common::{setup_sokcet2, setup_sokcet2_ext, wait_for_connect_futures}, + generate_digest_from_str, + packet_def::{PEER_MANAGER_HEADER_SIZE, ZCPacketType}, + ring::create_ring_tunnel_pair, }; use crate::{ common::shrink_dashmap, tunnel::{ build_url_from_socket_addr, common::TunnelWrapper, - packet_def::{ZCPacket, WG_TUNNEL_HEADER_SIZE}, + packet_def::{WG_TUNNEL_HEADER_SIZE, ZCPacket}, }, }; @@ -331,11 +331,7 @@ impl WgPeerData { } fn remove_ip_header<'a>(&self, packet: &'a [u8], is_v4: bool) -> &'a [u8] { - if is_v4 { - &packet[20..] - } else { - &packet[40..] - } + if is_v4 { &packet[20..] } else { &packet[40..] } } } @@ -772,8 +768,8 @@ impl super::TunnelConnector for WgTunnelConnector { pub mod tests { use super::*; use crate::tunnel::{ - common::tests::{_tunnel_bench, _tunnel_pingpong}, TunnelConnector, + common::tests::{_tunnel_bench, _tunnel_pingpong}, }; use boringtun::*; diff --git a/easytier/src/utils.rs b/easytier/src/utils.rs index 5d3fdd7d..e2b35676 100644 --- a/easytier/src/utils.rs +++ b/easytier/src/utils.rs @@ -19,7 +19,7 @@ pub fn float_to_str(f: f64, precision: usize) -> String { #[cfg(target_os = "windows")] pub fn utf8_or_gbk_to_string(s: &[u8]) -> String { - use encoding::{all::GBK, DecoderTrap, Encoding}; + use encoding::{DecoderTrap, Encoding, all::GBK}; if let Ok(utf8_str) = String::from_utf8(s.to_vec()) { utf8_str } else { diff --git a/easytier/src/vpn_portal/wireguard.rs b/easytier/src/vpn_portal/wireguard.rs index 358c1d3a..ab85ff93 100644 --- a/easytier/src/vpn_portal/wireguard.rs +++ b/easytier/src/vpn_portal/wireguard.rs @@ -4,7 +4,7 @@ use std::{ }; use anyhow::Context; -use base64::{prelude::BASE64_STANDARD, Engine}; +use base64::{Engine, prelude::BASE64_STANDARD}; use cidr::Ipv4Inet; use dashmap::DashMap; use futures::StreamExt; @@ -18,12 +18,12 @@ use crate::{ global_ctx::{ArcGlobalCtx, GlobalCtxEvent}, join_joinset_background, shrink_dashmap, }, - peers::{peer_manager::PeerManager, PeerPacketFilter}, + peers::{PeerPacketFilter, peer_manager::PeerManager}, tunnel::{ + Tunnel, TunnelListener, mpsc::{MpscTunnel, MpscTunnelSender}, packet_def::{PacketType, ZCPacket, ZCPacketType}, wireguard::{WgConfig, WgTunnelListener}, - Tunnel, TunnelListener, }, }; @@ -256,17 +256,17 @@ impl WireGuardImpl { self.start_listener(&self.listener_addr).await?; // if binding to v4 unspecified, also start a listener on v6 unspecified - if let SocketAddr::V4(v4) = &self.listener_addr { - if v4.ip().is_unspecified() { - let _ = self - .start_listener(&SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::UNSPECIFIED, - v4.port(), - 0, - 0, - ))) - .await; - } + if let SocketAddr::V4(v4) = &self.listener_addr + && v4.ip().is_unspecified() + { + let _ = self + .start_listener(&SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::UNSPECIFIED, + v4.port(), + 0, + 0, + ))) + .await; }; join_joinset_background(self.tasks.clone(), "wireguard".to_string()); diff --git a/easytier/src/web_client/mod.rs b/easytier/src/web_client/mod.rs index 47710a0c..c487d13f 100644 --- a/easytier/src/web_client/mod.rs +++ b/easytier/src/web_client/mod.rs @@ -162,7 +162,10 @@ impl WebClient { if secure_mode { connected.store(false, Ordering::Release); let wait = 1; - log::warn!("secure-mode enabled but server does not support encryption, retrying in {} seconds...", wait); + log::warn!( + "secure-mode enabled but server does not support encryption, retrying in {} seconds...", + wait + ); tokio::time::sleep(std::time::Duration::from_secs(wait)).await; continue; } @@ -238,7 +241,7 @@ pub async fn run_web_client( #[cfg(test)] mod tests { - use std::sync::{atomic::AtomicBool, Arc}; + use std::sync::{Arc, atomic::AtomicBool}; use crate::instance_manager::NetworkInstanceManager; diff --git a/easytier/src/web_client/security.rs b/easytier/src/web_client/security.rs index 27ba3869..30020024 100644 --- a/easytier/src/web_client/security.rs +++ b/easytier/src/web_client/security.rs @@ -3,14 +3,14 @@ use std::time::Duration; use bytes::BytesMut; use futures::{SinkExt, StreamExt}; -use snow::{params::NoiseParams, Builder, TransportState}; +use snow::{Builder, TransportState, params::NoiseParams}; use crate::{ proto::common::TunnelInfo, tunnel::{ + SplitTunnel, StreamItem, Tunnel, TunnelError, ZCPacketSink, ZCPacketStream, filter::{TunnelFilter, TunnelWithFilter}, packet_def::{PacketType, ZCPacket, ZCPacketType}, - SplitTunnel, StreamItem, Tunnel, TunnelError, ZCPacketSink, ZCPacketStream, }, }; diff --git a/easytier/src/web_client/session.rs b/easytier/src/web_client/session.rs index bf33bc65..fd28961b 100644 --- a/easytier/src/web_client/session.rs +++ b/easytier/src/web_client/session.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Weak}; use tokio::{ - sync::{broadcast, Mutex}, + sync::{Mutex, broadcast}, task::JoinSet, time::interval, }; diff --git a/tauri-plugin-vpnservice/Cargo.toml b/tauri-plugin-vpnservice/Cargo.toml index 61a72097..c8a92b61 100644 --- a/tauri-plugin-vpnservice/Cargo.toml +++ b/tauri-plugin-vpnservice/Cargo.toml @@ -3,8 +3,7 @@ name = "tauri-plugin-vpnservice" version = "0.0.0" authors = ["You"] description = "" -edition = "2021" -rust-version = "1.70" +edition.workspace = true exclude = ["/examples", "/webview-dist", "/webview-src", "/node_modules"] links = "tauri-plugin-vpnservice" diff --git a/tauri-plugin-vpnservice/src/error.rs b/tauri-plugin-vpnservice/src/error.rs index 177e8c26..fb57ca57 100644 --- a/tauri-plugin-vpnservice/src/error.rs +++ b/tauri-plugin-vpnservice/src/error.rs @@ -1,4 +1,4 @@ -use serde::{ser::Serializer, Serialize}; +use serde::{Serialize, ser::Serializer}; pub type Result = std::result::Result; diff --git a/tauri-plugin-vpnservice/src/lib.rs b/tauri-plugin-vpnservice/src/lib.rs index daabe6fb..d6f6b1d0 100644 --- a/tauri-plugin-vpnservice/src/lib.rs +++ b/tauri-plugin-vpnservice/src/lib.rs @@ -1,6 +1,6 @@ use tauri::{ - plugin::{Builder, TauriPlugin}, Runtime, + plugin::{Builder, TauriPlugin}, }; #[cfg(mobile)] diff --git a/tauri-plugin-vpnservice/src/mobile.rs b/tauri-plugin-vpnservice/src/mobile.rs index 21129b93..20ed1efb 100644 --- a/tauri-plugin-vpnservice/src/mobile.rs +++ b/tauri-plugin-vpnservice/src/mobile.rs @@ -1,7 +1,7 @@ use serde::de::DeserializeOwned; use tauri::{ - plugin::{PluginApi, PluginHandle}, AppHandle, Runtime, + plugin::{PluginApi, PluginHandle}, }; use crate::models::*; From 19c80c7b9c44ce07a94f9703ccade53b4c1b04b3 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:21:15 +0200 Subject: [PATCH 07/24] cli: do not add offset when port = 0 (#2085) --- easytier/src/connector/udp_hole_punch/cone.rs | 2 +- easytier/src/core.rs | 70 +++++++++++-------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/easytier/src/connector/udp_hole_punch/cone.rs b/easytier/src/connector/udp_hole_punch/cone.rs index a88eb5c7..71be9519 100644 --- a/easytier/src/connector/udp_hole_punch/cone.rs +++ b/easytier/src/connector/udp_hole_punch/cone.rs @@ -120,7 +120,7 @@ impl PunchConeHoleClient { let local_addr = local_socket .local_addr() - .with_context(|| anyhow::anyhow!("failed to get local port from udp array"))?; + .with_context(|| "failed to get local port from udp array")?; let local_port = local_addr.port(); drop(local_socket); diff --git a/easytier/src/core.rs b/easytier/src/core.rs index 44f667d1..218d87af 100644 --- a/easytier/src/core.rs +++ b/easytier/src/core.rs @@ -740,43 +740,50 @@ impl Cli { return Ok(vec![]); } - let origin_listeners = listeners; - let mut listeners: Vec = Vec::new(); - if origin_listeners.len() == 1 - && let Ok(port) = origin_listeners[0].parse::() + if listeners.len() == 1 + && let Ok(port) = listeners[0].parse::() { - for proto in IpScheme::VARIANTS { - listeners.push(format!( - "{}://0.0.0.0:{}", - proto, - port + proto.port_offset() - )); - } + let listeners = IpScheme::VARIANTS + .iter() + .map(|proto| { + format!( + "{}://0.0.0.0:{}", + proto, + if port == 0 { + 0 + } else { + port + proto.port_offset() + } + ) + }) + .collect(); return Ok(listeners); } - for l in &origin_listeners { - let proto_port: Vec<&str> = l.split(':').collect(); - if proto_port.len() > 2 { - if let Ok(url) = l.parse::() { - listeners.push(url.to_string()); - } else { - panic!("failed to parse listener: {}", l); + listeners + .into_iter() + .map(|l| { + let l = l + .parse::() + .or_else(|_| url::Url::parse(&format!("{}:", l)))?; + + if l.has_authority() { + return Ok(l.to_string()); } - } else { - let scheme: IpScheme = proto_port[0].parse()?; - let port = if proto_port.len() == 2 { - proto_port[1].parse::().unwrap() - } else { - 11010 + scheme.port_offset() + let scheme: IpScheme = l.scheme().parse()?; + let port = { + let port = l.path(); + if port.is_empty() { + 11010 + scheme.port_offset() + } else { + port.parse::() + .with_context(|| format!("invalid port: {}", port))? + } }; - - listeners.push(format!("{}://0.0.0.0:{}", scheme, port)); - } - } - - Ok(listeners) + Ok(format!("{}://0.0.0.0:{}", scheme, port)) + }) + .collect() } } @@ -848,7 +855,8 @@ impl NetworkOptions { if self.no_listener || !self.listeners.is_empty() { cfg.set_listeners( - Cli::parse_listeners(self.no_listener, self.listeners.clone())? + Cli::parse_listeners(self.no_listener, self.listeners.clone()) + .with_context(|| format!("failed to parse listeners: {:?}", self.listeners))? .into_iter() .map(|s| s.parse().unwrap()) .collect(), From 8311b11713ddc6bdb3bc7bdbeeb6cf052567805b Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:22:08 +0200 Subject: [PATCH 08/24] refactor: remove NoGroAsyncUdpSocket (#1867) --- easytier/src/connector/mod.rs | 4 +- easytier/src/gateway/quic_proxy.rs | 10 +- easytier/src/gateway/socks5.rs | 6 +- easytier/src/gateway/udp_proxy.rs | 4 +- easytier/src/instance/listeners.rs | 8 +- easytier/src/tunnel/common.rs | 11 +- easytier/src/tunnel/mod.rs | 2 +- easytier/src/tunnel/quic.rs | 496 +++++++++++++++++++++-------- easytier/src/tunnel/tcp.rs | 6 +- easytier/src/tunnel/udp.rs | 10 +- easytier/src/tunnel/websocket.rs | 6 +- easytier/src/tunnel/wireguard.rs | 10 +- 12 files changed, 401 insertions(+), 172 deletions(-) diff --git a/easytier/src/connector/mod.rs b/easytier/src/connector/mod.rs index bfe8740c..832f0173 100644 --- a/easytier/src/connector/mod.rs +++ b/easytier/src/connector/mod.rs @@ -105,7 +105,9 @@ pub async fn create_connector_by_url( IpScheme::Tcp => TcpTunnelConnector::new(url).boxed(), IpScheme::Udp => UdpTunnelConnector::new(url).boxed(), #[cfg(feature = "quic")] - IpScheme::Quic => tunnel::quic::QuicTunnelConnector::new(url).boxed(), + IpScheme::Quic => { + tunnel::quic::QuicTunnelConnector::new(url, global_ctx.clone()).boxed() + } #[cfg(feature = "wireguard")] IpScheme::Wg => { use crate::tunnel::wireguard::{WgConfig, WgTunnelConnector}; diff --git a/easytier/src/gateway/quic_proxy.rs b/easytier/src/gateway/quic_proxy.rs index 743a9b88..c959efc8 100644 --- a/easytier/src/gateway/quic_proxy.rs +++ b/easytier/src/gateway/quic_proxy.rs @@ -26,7 +26,9 @@ use derivative::Derivative; use derive_more::{Constructor, Deref, DerefMut, From, Into}; use prost::Message; use quinn::udp::{EcnCodepoint, RecvMeta, Transmit}; -use quinn::{AsyncUdpSocket, Endpoint, RecvStream, SendStream, StreamId, TokioRuntime, UdpPoller}; +use quinn::{ + AsyncUdpSocket, Endpoint, RecvStream, SendStream, StreamId, UdpPoller, default_runtime, +}; use std::cmp::min; use std::future::Future; use std::io::IoSliceMut; @@ -806,7 +808,7 @@ impl QuicProxy { endpoint_config(), Some(server_config()), Arc::new(socket), - Arc::new(TokioRuntime), + default_runtime().unwrap(), ) .unwrap(); endpoint.set_default_client_config(client_config()); @@ -1020,7 +1022,7 @@ mod tests { endpoint_config.clone(), Some(server_config.clone()), socket_client.clone(), - Arc::new(TokioRuntime), + default_runtime().unwrap(), ) .unwrap(); client_endpoint.set_default_client_config(client_config.clone()); @@ -1030,7 +1032,7 @@ mod tests { endpoint_config.clone(), Some(server_config.clone()), socket_server.clone(), - Arc::new(TokioRuntime), + default_runtime().unwrap(), ) .unwrap(); server_endpoint.set_default_client_config(client_config.clone()); diff --git a/easytier/src/gateway/socks5.rs b/easytier/src/gateway/socks5.rs index 7b19ffff..728bd131 100644 --- a/easytier/src/gateway/socks5.rs +++ b/easytier/src/gateway/socks5.rs @@ -31,7 +31,7 @@ use crate::{ tokio_smoltcp::{BufferSize, Net, NetConfig, channel_device}, }, tunnel::{ - common::setup_sokcet2, + common::setup_socket2, packet_def::{PacketType, ZCPacket}, }, }; @@ -336,7 +336,7 @@ fn bind_tcp_socket(addr: SocketAddr, net_ns: NetNS) -> Result Result Some(socket2::Protocol::UDP), )?; - setup_sokcet2(&socket2_socket, &addr)?; + setup_socket2(&socket2_socket, &addr, true)?; Ok(UdpSocket::from_std(socket2_socket.into())?) } diff --git a/easytier/src/gateway/udp_proxy.rs b/easytier/src/gateway/udp_proxy.rs index 5a9a98d6..ab6ecc95 100644 --- a/easytier/src/gateway/udp_proxy.rs +++ b/easytier/src/gateway/udp_proxy.rs @@ -29,7 +29,7 @@ use crate::{ gateway::ip_reassembler::{ComposeIpv4PacketArgs, compose_ipv4_packet}, peers::{PeerPacketFilter, peer_manager::PeerManager}, tunnel::{ - common::{reserve_buf, setup_sokcet2}, + common::{reserve_buf, setup_socket2}, packet_def::{PacketType, ZCPacket}, }, }; @@ -72,7 +72,7 @@ impl UdpNatEntry { Some(socket2::Protocol::UDP), )?; let dst_socket_addr = "0.0.0.0:0".parse().unwrap(); - setup_sokcet2(&socket2_socket, &dst_socket_addr)?; + setup_socket2(&socket2_socket, &dst_socket_addr, true)?; Some(UdpSocket::from_std(socket2_socket.into())?) }; diff --git a/easytier/src/instance/listeners.rs b/easytier/src/instance/listeners.rs index 6f7782dd..72a1b9af 100644 --- a/easytier/src/instance/listeners.rs +++ b/easytier/src/instance/listeners.rs @@ -25,7 +25,7 @@ use crate::{ pub fn create_listener_by_url( l: &url::Url, - #[allow(unused_variables)] ctx: ArcGlobalCtx, + global_ctx: ArcGlobalCtx, ) -> Result, Error> { Ok(match l.try_into()? { TunnelScheme::Ip(scheme) => match scheme { @@ -34,7 +34,7 @@ pub fn create_listener_by_url( #[cfg(feature = "wireguard")] IpScheme::Wg => { use crate::tunnel::wireguard::{WgConfig, WgTunnelListener}; - let nid = ctx.get_network_identity(); + let nid = global_ctx.get_network_identity(); let wg_config = WgConfig::new_from_network_identity( &nid.network_name, &nid.network_secret.unwrap_or_default(), @@ -42,7 +42,9 @@ pub fn create_listener_by_url( WgTunnelListener::new(l.clone(), wg_config).boxed() } #[cfg(feature = "quic")] - IpScheme::Quic => tunnel::quic::QuicTunnelListener::new(l.clone()).boxed(), + IpScheme::Quic => { + tunnel::quic::QuicTunnelListener::new(l.clone(), global_ctx.clone()).boxed() + } #[cfg(feature = "websocket")] IpScheme::Ws | IpScheme::Wss => { tunnel::websocket::WsTunnelListener::new(l.clone()).boxed() diff --git a/easytier/src/tunnel/common.rs b/easytier/src/tunnel/common.rs index f6814f6e..92766a29 100644 --- a/easytier/src/tunnel/common.rs +++ b/easytier/src/tunnel/common.rs @@ -344,10 +344,11 @@ pub(crate) fn get_interface_name_by_ip(local_ip: &IpAddr) -> Option { None } -pub(crate) fn setup_sokcet2_ext( +pub(crate) fn setup_socket2_ext( socket2_socket: &socket2::Socket, bind_addr: &SocketAddr, #[allow(unused_variables)] bind_dev: Option, + only_v6: bool, ) -> Result<(), TunnelError> { #[cfg(target_os = "windows")] { @@ -356,7 +357,7 @@ pub(crate) fn setup_sokcet2_ext( } if bind_addr.is_ipv6() { - socket2_socket.set_only_v6(true)?; + socket2_socket.set_only_v6(only_v6)?; } socket2_socket.set_nonblocking(true)?; @@ -428,14 +429,16 @@ where Err(last_err.unwrap_or(TunnelError::Shutdown)) } -pub(crate) fn setup_sokcet2( +pub(crate) fn setup_socket2( socket2_socket: &socket2::Socket, bind_addr: &SocketAddr, + only_v6: bool, ) -> Result<(), TunnelError> { - setup_sokcet2_ext( + setup_socket2_ext( socket2_socket, bind_addr, super::common::get_interface_name_by_ip(&bind_addr.ip()), + only_v6, ) } diff --git a/easytier/src/tunnel/mod.rs b/easytier/src/tunnel/mod.rs index ca169327..36feb753 100644 --- a/easytier/src/tunnel/mod.rs +++ b/easytier/src/tunnel/mod.rs @@ -46,7 +46,7 @@ pub mod unix; #[derive(thiserror::Error, Debug)] pub enum TunnelError { - #[error("io error")] + #[error("io error: {0}")] IOError(#[from] std::io::Error), #[error("invalid packet. msg: {0}")] InvalidPacket(String), diff --git a/easytier/src/tunnel/quic.rs b/easytier/src/tunnel/quic.rs index 96ca5a6f..5263ce3c 100644 --- a/easytier/src/tunnel/quic.rs +++ b/easytier/src/tunnel/quic.rs @@ -2,22 +2,25 @@ //! //! Checkout the `README.md` for guidance. -use std::{ - error::Error, io::IoSliceMut, net::SocketAddr, pin::Pin, sync::Arc, task::Poll, time::Duration, -}; - +use super::{FromUrl, IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener}; +use crate::common::global_ctx::ArcGlobalCtx; use crate::tunnel::{ - FromUrl, TunnelInfo, - common::{FramedReader, FramedWriter, TunnelWrapper, setup_sokcet2}, + TunnelInfo, + common::{FramedReader, FramedWriter, TunnelWrapper, setup_socket2}, }; use anyhow::Context; - -use super::{IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener}; +use derivative::Derivative; +use derive_more::{Deref, DerefMut}; +use parking_lot::RwLock; use quinn::{ - AsyncUdpSocket, ClientConfig, Connection, Endpoint, EndpointConfig, ServerConfig, - TransportConfig, UdpPoller, congestion::BbrConfig, udp::RecvMeta, + ClientConfig, Connection, Endpoint, EndpointConfig, ServerConfig, TransportConfig, + congestion::BbrConfig, default_runtime, }; +use std::net::{Ipv4Addr, Ipv6Addr}; +use std::sync::OnceLock; +use std::{net::SocketAddr, sync::Arc, time::Duration}; +// region config pub fn transport_config() -> Arc { let mut config = TransportConfig::default(); @@ -50,86 +53,287 @@ pub fn endpoint_config() -> EndpointConfig { config.max_udp_payload_size(65527).unwrap(); config } +//endregion -#[derive(Clone, Debug)] -struct NoGroAsyncUdpSocket { - inner: Arc, +//region rw pool +#[derive(Derivative)] +#[derivative(Default(bound = ""))] +#[derive(Debug, Deref, DerefMut)] +struct RwPoolInner { + #[deref] + #[deref_mut] + pool: Vec, + enabled: bool, } -impl AsyncUdpSocket for NoGroAsyncUdpSocket { - fn create_io_poller(self: Arc) -> Pin> { - self.inner.clone().create_io_poller() +#[derive(Debug)] +struct RwPool { + ephemeral: RwLock>, + persistent: RwLock>, + capacity: usize, +} + +impl RwPool { + fn new(capacity: usize) -> Self { + Self { + ephemeral: RwLock::new(RwPoolInner::default()), + persistent: RwLock::new(RwPoolInner::default()), + capacity, + } } - fn try_send(&self, transmit: &quinn::udp::Transmit) -> std::io::Result<()> { - self.inner.try_send(transmit) - } - - /// Receive UDP datagrams, or register to be woken if receiving may succeed in the future - fn poll_recv( + /// return the capacity of the ephemeral pool; + /// if `ephemeral` or `persistent` is None, read lock `self`'s pool + fn capacity( &self, - cx: &mut std::task::Context, - bufs: &mut [IoSliceMut<'_>], - meta: &mut [RecvMeta], - ) -> Poll> { - self.inner.poll_recv(cx, bufs, meta) + ephemeral: Option<&RwPoolInner>, + persistent: Option<&RwPoolInner>, + ) -> usize { + let guard; + let ephemeral = if let Some(ephemeral) = ephemeral { + ephemeral + } else { + guard = self.ephemeral.read(); + &guard + }; + + let guard; + let persistent = if let Some(persistent) = persistent { + persistent + } else { + guard = self.persistent.read(); + &guard + }; + + (self.capacity * ephemeral.enabled as usize).saturating_sub(persistent.len()) } - /// Look up the local IP address and port used by this socket - fn local_addr(&self) -> std::io::Result { - self.inner.local_addr() + fn is_full(&self) -> bool { + let pool = self.ephemeral.read(); + pool.len() >= self.capacity(Some(&pool), None) } - fn may_fragment(&self) -> bool { - self.inner.may_fragment() + fn is_enabled(&self) -> bool { + self.ephemeral.read().enabled } - fn max_transmit_segments(&self) -> usize { - self.inner.max_transmit_segments() + fn enable(&self) { + self.ephemeral.write().enabled = true; + self.resize(); } - fn max_receive_segments(&self) -> usize { - 1 + fn disable(&self) { + self.ephemeral.write().enabled = false; + self.resize(); + } + + /// push an item to the persistent pool + fn push(&self, item: Item) { + self.persistent.write().push(item); + self.resize(); + } + + /// try to push an item to the ephemeral pool, return the item if full + fn try_push(&self, item: Item) -> Option { + let mut pool = self.ephemeral.write(); + if pool.len() < self.capacity(Some(&pool), None) { + pool.push(item); + return None; + } + Some(item) + } + + fn resize(&self) { + let resize = { + let pool = self.ephemeral.read(); + pool.capacity() != self.capacity(Some(&pool), None) + }; + if resize { + let mut pool = self.ephemeral.write(); + let capacity = self.capacity(Some(&pool), None); + pool.reserve_exact(capacity); + pool.truncate(capacity); + pool.shrink_to(capacity); + } + } + + fn with_iter(&self, f: F) -> R + where + F: FnOnce(&mut dyn Iterator) -> R, + { + let ephemeral = self.ephemeral.read(); + let persistent = self.persistent.read(); + f(&mut persistent.iter().chain(ephemeral.iter())) + } +} +//endregion + +//region endpoint manager +#[derive(Debug)] +pub struct QuicEndpointManager { + ipv4: RwPool, + ipv6: RwPool, + both: RwPool, +} + +static QUIC_ENDPOINT_MANAGER: OnceLock = OnceLock::new(); + +impl QuicEndpointManager { + fn try_create(addr: SocketAddr, dual_stack: bool) -> std::io::Result { + let socket = socket2::Socket::new( + socket2::Domain::for_address(addr), + socket2::Type::DGRAM, + Some(socket2::Protocol::UDP), + )?; + setup_socket2(&socket, &addr, addr.is_ipv6() && !dual_stack) + .map_err(std::io::Error::other)?; + let socket = std::net::UdpSocket::from(socket); + let runtime = default_runtime().ok_or(std::io::Error::other("no async runtime found"))?; + let mut endpoint = Endpoint::new_with_abstract_socket( + endpoint_config(), + None, + runtime.wrap_udp_socket(socket)?, + runtime, + )?; + endpoint.set_default_client_config(client_config()); + Ok(endpoint) + } + + fn create(&self, mut selector: F) -> std::io::Result<(&RwPool, Option)> + where + F: FnMut(&QuicEndpointManager) -> (&RwPool, Option<(SocketAddr, bool)>), + { + loop { + let (pool, r) = selector(self); + let Some((addr, dual_stack)) = r else { + return Ok((pool, None)); + }; + + let endpoint = Self::try_create(addr, dual_stack); + if let Err(e) = endpoint.as_ref() + && dual_stack + { + tracing::warn!("create dual stack quic endpoint failed: {:?}", e); + self.both.disable(); + self.ipv4.enable(); + self.ipv6.enable(); + continue; + } + + return Ok((pool, Some(endpoint?))); + } } } -/// Constructs a QUIC endpoint configured to listen for incoming connections on a certain address -/// and port. -/// -/// ## Returns -/// -/// - an [`Endpoint`] configured to accept incoming QUIC connections -#[allow(unused)] -pub fn make_server_endpoint(bind_addr: SocketAddr) -> Result> { - let server_config = server_config(); - let client_config = client_config(); - let endpoint_config = endpoint_config(); +impl QuicEndpointManager { + fn new(capacity: usize) -> Self { + let ipv4 = RwPool::new(capacity.div_ceil(2)); + let ipv6 = RwPool::new(capacity.div_ceil(2)); + let both = RwPool::new(capacity); + both.enable(); + Self { ipv4, ipv6, both } + } - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(bind_addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - setup_sokcet2(&socket2_socket, &bind_addr)?; - let socket = std::net::UdpSocket::from(socket2_socket); + fn load(global_ctx: &ArcGlobalCtx) -> &Self { + let capacity = global_ctx + .config + .get_flags() + .multi_thread + .then(std::thread::available_parallelism) + .and_then(|r| r.ok()) + .map(|n| n.get()) + .unwrap_or(1); - let runtime = - quinn::default_runtime().ok_or_else(|| std::io::Error::other("no async runtime found"))?; - let socket: NoGroAsyncUdpSocket = NoGroAsyncUdpSocket { - inner: runtime.wrap_udp_socket(socket)?, - }; - let mut endpoint = Endpoint::new_with_abstract_socket( - endpoint_config, - Some(server_config), - Arc::new(socket), - runtime, - )?; - endpoint.set_default_client_config(client_config); - Ok(endpoint) + let mgr = QUIC_ENDPOINT_MANAGER.get(); + match mgr { + Some(mgr) => { + for pool in [&mgr.ipv4, &mgr.ipv6, &mgr.both] { + pool.resize(); + } + } + None => { + let _ = QUIC_ENDPOINT_MANAGER.set(Self::new(capacity)); + } + } + + QUIC_ENDPOINT_MANAGER.get().unwrap() + } + + /// Get a QUIC endpoint to be used as a server + /// + /// # Arguments + /// * `addr`: listen address + fn server(global_ctx: &ArcGlobalCtx, addr: SocketAddr) -> std::io::Result { + let mgr = Self::load(global_ctx); + + let (pool, endpoint) = mgr.create(|mgr| { + let dual_stack = addr.ip() == Ipv6Addr::UNSPECIFIED && mgr.both.is_enabled(); + let pool = if addr.is_ipv4() { + &mgr.ipv4 + } else if dual_stack { + &mgr.both + } else { + &mgr.ipv6 + }; + (pool, Some((addr, dual_stack))) + })?; + + let endpoint = endpoint.expect("server endpoint creation should not return None"); + endpoint.set_server_config(Some(server_config())); + pool.push(endpoint.clone()); + + Ok(endpoint) + } + + /// Get a quic endpoint to be used as a client + /// + /// # Arguments + /// * `ip_version`: the IP version of the remote address + fn client(global_ctx: &ArcGlobalCtx, ip_version: IpVersion) -> std::io::Result { + let mgr = Self::load(global_ctx); + + let (pool, endpoint) = mgr.create(|mgr| { + let dual_stack = mgr.both.is_enabled(); + let (pool, addr) = match ip_version { + IpVersion::V4 if !dual_stack => (&mgr.ipv4, (Ipv4Addr::UNSPECIFIED, 0).into()), + _ => { + let pool = if dual_stack { &mgr.both } else { &mgr.ipv6 }; + (pool, (Ipv6Addr::UNSPECIFIED, 0).into()) + } + }; + if pool.is_full() { + (pool, None) + } else { + (pool, Some((addr, dual_stack))) + } + })?; + + if let Some(endpoint) = endpoint { + pool.try_push(endpoint); + } + + Ok(pool.with_iter(|iter| iter.min_by_key(|e| e.open_connections()).unwrap().clone())) + } + + async fn connect( + global_ctx: &ArcGlobalCtx, + addr: SocketAddr, + ) -> std::io::Result<(Endpoint, Connection)> { + let ip_version = if addr.ip().is_ipv4() { + IpVersion::V4 + } else { + IpVersion::V6 + }; + let endpoint = Self::client(global_ctx, ip_version)?; + let connection = endpoint + .connect(addr, "localhost") + .map_err(std::io::Error::other)? + .await?; + + Ok((endpoint, connection)) + } } - -#[allow(unused)] -pub const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"]; +//endregion struct ConnWrapper { conn: Connection, @@ -143,13 +347,15 @@ impl Drop for ConnWrapper { pub struct QuicTunnelListener { addr: url::Url, + global_ctx: ArcGlobalCtx, endpoint: Option, } impl QuicTunnelListener { - pub fn new(addr: url::Url) -> Self { + pub fn new(addr: url::Url, global_ctx: ArcGlobalCtx) -> Self { QuicTunnelListener { addr, + global_ctx, endpoint: None, } } @@ -192,13 +398,11 @@ impl QuicTunnelListener { impl TunnelListener for QuicTunnelListener { async fn listen(&mut self) -> Result<(), TunnelError> { let addr = SocketAddr::from_url(self.addr.clone(), IpVersion::Both).await?; - let endpoint = make_server_endpoint(addr) - .map_err(|e| anyhow::anyhow!("make server endpoint error: {:?}", e))?; - self.endpoint = Some(endpoint); - + let endpoint = QuicEndpointManager::server(&self.global_ctx, addr)?; self.addr - .set_port(Some(self.endpoint.as_ref().unwrap().local_addr()?.port())) + .set_port(Some(endpoint.local_addr()?.port())) .unwrap(); + self.endpoint = Some(endpoint); Ok(()) } @@ -222,15 +426,15 @@ impl TunnelListener for QuicTunnelListener { pub struct QuicTunnelConnector { addr: url::Url, - endpoint: Option, + global_ctx: ArcGlobalCtx, ip_version: IpVersion, } impl QuicTunnelConnector { - pub fn new(addr: url::Url) -> Self { + pub fn new(addr: url::Url, global_ctx: ArcGlobalCtx) -> Self { QuicTunnelConnector { addr, - endpoint: None, + global_ctx, ip_version: IpVersion::Both, } } @@ -240,38 +444,10 @@ impl QuicTunnelConnector { impl TunnelConnector for QuicTunnelConnector { async fn connect(&mut self) -> Result, TunnelError> { let addr = SocketAddr::from_url(self.addr.clone(), self.ip_version).await?; - if addr.port() == 0 { - return Err(TunnelError::InvalidAddr(format!( - "invalid remote QUIC port 0 in url: {} (port 0 is not a valid QUIC port)", - self.addr - ))); - } - let local_addr = if addr.is_ipv4() { - "0.0.0.0:0" - } else { - "[::]:0" - }; - - let mut endpoint = Endpoint::client(local_addr.parse().unwrap())?; - endpoint.set_default_client_config(client_config()); - - // connect to server - let connection = endpoint - .connect(addr, "localhost") - .map_err(|e| { - TunnelError::InvalidAddr(format!( - "failed to create QUIC connection, url: {}, error: {}", - self.addr, e - )) - })? - .await - .with_context(|| "connect failed")?; - tracing::info!("[client] connected: addr={}", connection.remote_address()); + let (endpoint, connection) = QuicEndpointManager::connect(&self.global_ctx, addr).await?; let local_addr = endpoint.local_addr()?; - self.endpoint = Some(endpoint); - let (w, r) = connection .open_bi() .await @@ -308,68 +484,112 @@ impl TunnelConnector for QuicTunnelConnector { #[cfg(test)] mod tests { + use crate::common::global_ctx::tests::get_mock_global_ctx_with_network; use crate::tunnel::{ - IpVersion, TunnelConnector, + TunnelConnector, common::tests::{_tunnel_bench, _tunnel_pingpong}, }; + use std::sync::LazyLock; + use tokio::runtime::{Builder, Runtime}; use super::*; - #[tokio::test] - async fn quic_pingpong() { - let listener = QuicTunnelListener::new("quic://0.0.0.0:21011".parse().unwrap()); - let connector = QuicTunnelConnector::new("quic://127.0.0.1:21011".parse().unwrap()); + // Shared runtime for all tests to avoid endpoint invalidation across runtimes + static RUNTIME: LazyLock = + LazyLock::new(|| Builder::new_multi_thread().enable_all().build().unwrap()); + + fn global_ctx() -> ArcGlobalCtx { + let identity = crate::common::config::NetworkIdentity::default(); + get_mock_global_ctx_with_network(Some(identity)) + } + + #[test] + fn quic_pingpong() { + RUNTIME.block_on(quic_pingpong_impl()) + } + async fn quic_pingpong_impl() { + let listener = QuicTunnelListener::new("quic://[::]:21011".parse().unwrap(), global_ctx()); + let connector = + QuicTunnelConnector::new("quic://127.0.0.1:21011".parse().unwrap(), global_ctx()); _tunnel_pingpong(listener, connector).await } - #[tokio::test] - async fn quic_bench() { - let listener = QuicTunnelListener::new("quic://0.0.0.0:21012".parse().unwrap()); - let connector = QuicTunnelConnector::new("quic://127.0.0.1:21012".parse().unwrap()); + #[test] + fn quic_bench() { + RUNTIME.block_on(quic_bench_impl()) + } + async fn quic_bench_impl() { + let listener = QuicTunnelListener::new("quic://[::]:21012".parse().unwrap(), global_ctx()); + let connector = + QuicTunnelConnector::new("quic://127.0.0.1:21012".parse().unwrap(), global_ctx()); _tunnel_bench(listener, connector).await } - #[tokio::test] - async fn ipv6_pingpong() { - let listener = QuicTunnelListener::new("quic://[::1]:31015".parse().unwrap()); - let connector = QuicTunnelConnector::new("quic://[::1]:31015".parse().unwrap()); + #[test] + fn ipv6_pingpong() { + RUNTIME.block_on(ipv6_pingpong_impl()) + } + async fn ipv6_pingpong_impl() { + let listener = QuicTunnelListener::new("quic://[::1]:31015".parse().unwrap(), global_ctx()); + let connector = + QuicTunnelConnector::new("quic://[::1]:31015".parse().unwrap(), global_ctx()); _tunnel_pingpong(listener, connector).await } - #[tokio::test] - async fn ipv6_domain_pingpong() { - let listener = QuicTunnelListener::new("quic://[::1]:31016".parse().unwrap()); - let mut connector = - QuicTunnelConnector::new("quic://test.easytier.top:31016".parse().unwrap()); + #[test] + fn ipv6_domain_pingpong() { + RUNTIME.block_on(ipv6_domain_pingpong_impl()) + } + async fn ipv6_domain_pingpong_impl() { + let listener = QuicTunnelListener::new("quic://[::1]:31016".parse().unwrap(), global_ctx()); + let mut connector = QuicTunnelConnector::new( + "quic://test.easytier.top:31016".parse().unwrap(), + global_ctx(), + ); connector.set_ip_version(IpVersion::V6); _tunnel_pingpong(listener, connector).await; - let listener = QuicTunnelListener::new("quic://127.0.0.1:31016".parse().unwrap()); - let mut connector = - QuicTunnelConnector::new("quic://test.easytier.top:31016".parse().unwrap()); + let listener = + QuicTunnelListener::new("quic://127.0.0.1:31016".parse().unwrap(), global_ctx()); + let mut connector = QuicTunnelConnector::new( + "quic://test.easytier.top:31016".parse().unwrap(), + global_ctx(), + ); connector.set_ip_version(IpVersion::V4); _tunnel_pingpong(listener, connector).await; } - #[tokio::test] - async fn test_alloc_port() { + #[test] + fn alloc_port() { + RUNTIME.block_on(alloc_port_impl()) + } + async fn alloc_port_impl() { // v4 - let mut listener = QuicTunnelListener::new("quic://0.0.0.0:0".parse().unwrap()); + let mut listener = + QuicTunnelListener::new("quic://0.0.0.0:0".parse().unwrap(), global_ctx()); listener.listen().await.unwrap(); let port = listener.local_url().port().unwrap(); assert!(port > 0); // v6 - let mut listener = QuicTunnelListener::new("quic://[::]:0".parse().unwrap()); + let mut listener = QuicTunnelListener::new("quic://[::]:0".parse().unwrap(), global_ctx()); listener.listen().await.unwrap(); let port = listener.local_url().port().unwrap(); assert!(port > 0); } - #[tokio::test] - async fn quic_connector_reject_port_zero() { - let mut connector = QuicTunnelConnector::new("quic://127.0.0.1:0".parse().unwrap()); - let err = connector.connect().await.unwrap_err().to_string(); - assert!(err.contains("port 0"), "unexpected error: {}", err); + #[test] + fn invalid_peer_addr() { + RUNTIME.block_on(invalid_peer_addr_impl()) + } + async fn invalid_peer_addr_impl() { + let mut connector = + QuicTunnelConnector::new("quic://127.0.0.1:0".parse().unwrap(), global_ctx()); + let err = connector.connect().await.unwrap_err(); + assert!( + err.to_string().contains("invalid remote address"), + "unexpected error: {:?}", + err + ); } } diff --git a/easytier/src/tunnel/tcp.rs b/easytier/src/tunnel/tcp.rs index abcb73f6..2061c2fe 100644 --- a/easytier/src/tunnel/tcp.rs +++ b/easytier/src/tunnel/tcp.rs @@ -1,7 +1,7 @@ use std::net::SocketAddr; use super::{FromUrl, TunnelInfo}; -use crate::tunnel::common::setup_sokcet2; +use crate::tunnel::common::setup_socket2; use async_trait::async_trait; use futures::stream::FuturesUnordered; use tokio::net::{TcpListener, TcpSocket, TcpStream}; @@ -66,7 +66,7 @@ impl TunnelListener for TcpTunnelListener { socket2::Type::STREAM, Some(socket2::Protocol::TCP), )?; - setup_sokcet2(&socket2_socket, &addr)?; + setup_socket2(&socket2_socket, &addr, true)?; let socket = TcpSocket::from_std_stream(socket2_socket.into()); if let Err(e) = socket.set_nodelay(true) { @@ -175,7 +175,7 @@ impl TcpTunnelConnector { Some(socket2::Protocol::TCP), )?; - if let Err(e) = setup_sokcet2(&socket2_socket, bind_addr) { + if let Err(e) = setup_socket2(&socket2_socket, bind_addr, true) { tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); continue; } diff --git a/easytier/src/tunnel/udp.rs b/easytier/src/tunnel/udp.rs index 6432b64f..7119d143 100644 --- a/easytier/src/tunnel/udp.rs +++ b/easytier/src/tunnel/udp.rs @@ -24,7 +24,7 @@ use tracing::{Instrument, instrument}; use super::{ FromUrl, IpVersion, Tunnel, TunnelConnCounter, TunnelError, TunnelInfo, TunnelListener, TunnelUrl, - common::{setup_sokcet2, setup_sokcet2_ext, wait_for_connect_futures}, + common::{setup_socket2, setup_socket2_ext, wait_for_connect_futures}, packet_def::{UDP_TUNNEL_HEADER_SIZE, UDPTunnelHeader, V6HolePunchPacket}, ring::{RingSink, RingStream}, }; @@ -545,9 +545,9 @@ impl TunnelListener for UdpTunnelListener { let tunnel_url: TunnelUrl = self.addr.clone().into(); if let Some(bind_dev) = tunnel_url.bind_dev() { - setup_sokcet2_ext(&socket2_socket, &addr, Some(bind_dev))?; + setup_socket2_ext(&socket2_socket, &addr, Some(bind_dev), true)?; } else { - setup_sokcet2(&socket2_socket, &addr)?; + setup_socket2(&socket2_socket, &addr, true)?; } self.socket = Some(Arc::new(UdpSocket::from_std(socket2_socket.into())?)); @@ -838,7 +838,7 @@ impl UdpTunnelConnector { socket2::Type::DGRAM, Some(socket2::Protocol::UDP), )?; - if let Err(e) = setup_sokcet2(&socket2_socket, bind_addr) { + if let Err(e) = setup_socket2(&socket2_socket, bind_addr, true) { tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); continue; } @@ -1040,7 +1040,7 @@ mod tests { Some(socket2::Protocol::UDP), ) .unwrap(); - setup_sokcet2_ext(&socket2_socket, &addr, bind_dev.clone()).unwrap(); + setup_socket2_ext(&socket2_socket, &addr, bind_dev.clone(), true).unwrap(); } } diff --git a/easytier/src/tunnel/websocket.rs b/easytier/src/tunnel/websocket.rs index eed5f111..2772dad7 100644 --- a/easytier/src/tunnel/websocket.rs +++ b/easytier/src/tunnel/websocket.rs @@ -1,6 +1,6 @@ use super::{ FromUrl, IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener, - common::{TunnelWrapper, setup_sokcet2, wait_for_connect_futures}, + common::{TunnelWrapper, setup_socket2, wait_for_connect_futures}, insecure_tls::{get_insecure_tls_cert, init_crypto_provider}, packet_def::{ZCPacket, ZCPacketType}, }; @@ -166,7 +166,7 @@ impl TunnelListener for WsTunnelListener { socket2::Type::STREAM, Some(socket2::Protocol::TCP), )?; - setup_sokcet2(&socket2_socket, &addr)?; + setup_socket2(&socket2_socket, &addr, true)?; let socket = TcpSocket::from_std_stream(socket2_socket.into()); self.addr @@ -291,7 +291,7 @@ impl WsTunnelConnector { Some(socket2::Protocol::TCP), )?; - if let Err(e) = setup_sokcet2(&socket2_socket, bind_addr) { + if let Err(e) = setup_socket2(&socket2_socket, bind_addr, true) { tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); continue; } diff --git a/easytier/src/tunnel/wireguard.rs b/easytier/src/tunnel/wireguard.rs index d1968c60..844f384b 100644 --- a/easytier/src/tunnel/wireguard.rs +++ b/easytier/src/tunnel/wireguard.rs @@ -23,7 +23,7 @@ use tokio::{net::UdpSocket, sync::Mutex, task::JoinSet}; use super::{ FromUrl, IpVersion, Tunnel, TunnelError, TunnelInfo, TunnelListener, TunnelUrl, ZCPacketSink, ZCPacketStream, - common::{setup_sokcet2, setup_sokcet2_ext, wait_for_connect_futures}, + common::{setup_socket2, setup_socket2_ext, wait_for_connect_futures}, generate_digest_from_str, packet_def::{PEER_MANAGER_HEADER_SIZE, ZCPacketType}, ring::create_ring_tunnel_pair, @@ -563,9 +563,9 @@ impl TunnelListener for WgTunnelListener { let tunnel_url: TunnelUrl = self.addr.clone().into(); if let Some(bind_dev) = tunnel_url.bind_dev() { - setup_sokcet2_ext(&socket2_socket, &addr, Some(bind_dev))?; + setup_socket2_ext(&socket2_socket, &addr, Some(bind_dev), true)?; } else { - setup_sokcet2(&socket2_socket, &addr)?; + setup_socket2(&socket2_socket, &addr, true)?; } self.udp = Some(Arc::new(UdpSocket::from_std(socket2_socket.into())?)); @@ -700,7 +700,7 @@ impl WgTunnelConnector { socket2::Type::DGRAM, Some(socket2::Protocol::UDP), )?; - setup_sokcet2_ext(&socket2_socket, &"[::]:0".parse().unwrap(), None)?; + setup_socket2_ext(&socket2_socket, &"[::]:0".parse().unwrap(), None, true)?; let socket = UdpSocket::from_std(socket2_socket.into())?; Self::connect_with_socket(self.addr.clone(), self.config.clone(), socket, addr).await } @@ -728,7 +728,7 @@ impl super::TunnelConnector for WgTunnelConnector { socket2::Type::DGRAM, Some(socket2::Protocol::UDP), )?; - if let Err(e) = setup_sokcet2(&socket2_socket, &bind_addr) { + if let Err(e) = setup_socket2(&socket2_socket, &bind_addr, true) { tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); continue; } From 51befdbf876e2ec997183f6fbc3b18a69c5e0da0 Mon Sep 17 00:00:00 2001 From: fanyang Date: Sun, 12 Apr 2026 13:02:23 +0800 Subject: [PATCH 09/24] fix(faketcp): harden packet parsing against malformed frames (#2103) Discard malformed fake TCP frames instead of panicking so OpenWrt nodes can survive unexpected or truncated packets. Also emit the correct IPv6 ethertype and cover the parser with round-trip and truncation regression tests. --- easytier/src/tunnel/fake_tcp/packet.rs | 162 ++++++++++++++++++++++--- easytier/src/tunnel/fake_tcp/stack.rs | 15 ++- 2 files changed, 153 insertions(+), 24 deletions(-) diff --git a/easytier/src/tunnel/fake_tcp/packet.rs b/easytier/src/tunnel/fake_tcp/packet.rs index 0651fd70..41770e3b 100644 --- a/easytier/src/tunnel/fake_tcp/packet.rs +++ b/easytier/src/tunnel/fake_tcp/packet.rs @@ -80,7 +80,10 @@ pub fn build_tcp_packet( let mut ethernet = MutableEthernetPacket::new(&mut eth_buf).unwrap(); ethernet.set_destination(dst_mac); ethernet.set_source(src_mac); - ethernet.set_ethertype(EtherTypes::Ipv4); + ethernet.set_ethertype(match local_addr { + SocketAddr::V4(_) => EtherTypes::Ipv4, + SocketAddr::V6(_) => EtherTypes::Ipv6, + }); match (local_addr, remote_addr) { (SocketAddr::V4(local), SocketAddr::V4(remote)) => { @@ -129,31 +132,150 @@ pub fn build_tcp_packet( pub fn parse_ip_packet( buf: &Bytes, ) -> Option<(MacAddr, MacAddr, IPPacket<'_>, tcp::TcpPacket<'_>)> { - let eth = EthernetPacket::new(buf).unwrap(); + let eth = EthernetPacket::new(buf.as_ref())?; let src_mac = eth.get_source(); let dst_mac = eth.get_destination(); + let ethertype = eth.get_ethertype(); tracing::trace!("Parsing IP packet: {:?}", eth); - let buf = &buf[ETH_HDR_LEN..]; - if buf[0] >> 4 == 4 { - let v4 = ipv4::Ipv4Packet::new(buf).unwrap(); - if v4.get_next_level_protocol() != ip::IpNextHeaderProtocols::Tcp { - return None; - } + let ip_payload = &buf[ETH_HDR_LEN..]; - let tcp = tcp::TcpPacket::new(&buf[IPV4_HEADER_LEN..]).unwrap(); - Some((src_mac, dst_mac, IPPacket::V4(v4), tcp)) - } else if buf[0] >> 4 == 6 { - let v6 = ipv6::Ipv6Packet::new(buf).unwrap(); - if v6.get_next_header() != ip::IpNextHeaderProtocols::Tcp { - return None; - } + match ethertype { + EtherTypes::Ipv4 => { + let v4 = ipv4::Ipv4Packet::new(ip_payload)?; + if v4.get_next_level_protocol() != ip::IpNextHeaderProtocols::Tcp { + return None; + } - let tcp = tcp::TcpPacket::new(&buf[IPV6_HEADER_LEN..]).unwrap(); - Some((src_mac, dst_mac, IPPacket::V6(v6), tcp)) - } else { - tracing::trace!("Invalid IP version: {}", buf[0] >> 4); - None + let tcp_offset = usize::from(v4.get_header_length()) * 4; + if tcp_offset < IPV4_HEADER_LEN || tcp_offset > ip_payload.len() { + return None; + } + + let tcp = tcp::TcpPacket::new(&ip_payload[tcp_offset..])?; + Some((src_mac, dst_mac, IPPacket::V4(v4), tcp)) + } + EtherTypes::Ipv6 => { + let v6 = ipv6::Ipv6Packet::new(ip_payload)?; + if v6.get_next_header() != ip::IpNextHeaderProtocols::Tcp { + return None; + } + + let tcp = tcp::TcpPacket::new(&ip_payload[IPV6_HEADER_LEN..])?; + Some((src_mac, dst_mac, IPPacket::V6(v6), tcp)) + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use pnet::packet::Packet as _; + + #[test] + fn parse_ipv4_packet_round_trip() { + let src_mac = MacAddr::new(0x02, 0, 0, 0, 0, 1); + let dst_mac = MacAddr::new(0x02, 0, 0, 0, 0, 2); + let local_addr: SocketAddr = "192.0.2.1:12345".parse().unwrap(); + let remote_addr: SocketAddr = "198.51.100.2:23456".parse().unwrap(); + let payload = b"hello fake tcp"; + + let packet = build_tcp_packet( + src_mac, + dst_mac, + local_addr, + remote_addr, + 10, + 20, + tcp::TcpFlags::ACK, + Some(payload), + ); + + let (parsed_src_mac, parsed_dst_mac, ip_packet, tcp_packet) = + parse_ip_packet(&packet).unwrap(); + + assert_eq!(parsed_src_mac, src_mac); + assert_eq!(parsed_dst_mac, dst_mac); + assert_eq!(ip_packet.get_source(), local_addr.ip()); + assert_eq!(ip_packet.get_destination(), remote_addr.ip()); + assert_eq!(tcp_packet.get_source(), local_addr.port()); + assert_eq!(tcp_packet.get_destination(), remote_addr.port()); + assert_eq!(tcp_packet.payload(), payload); + } + + #[test] + fn build_and_parse_ipv6_packet_round_trip() { + let src_mac = MacAddr::new(0x02, 0, 0, 0, 0, 3); + let dst_mac = MacAddr::new(0x02, 0, 0, 0, 0, 4); + let local_addr: SocketAddr = "[2001:db8::1]:12345".parse().unwrap(); + let remote_addr: SocketAddr = "[2001:db8::2]:23456".parse().unwrap(); + let payload = b"ipv6 payload"; + + let packet = build_tcp_packet( + src_mac, + dst_mac, + local_addr, + remote_addr, + 30, + 40, + tcp::TcpFlags::ACK, + Some(payload), + ); + + let ethernet = EthernetPacket::new(packet.as_ref()).unwrap(); + assert_eq!(ethernet.get_ethertype(), EtherTypes::Ipv6); + + let (parsed_src_mac, parsed_dst_mac, ip_packet, tcp_packet) = + parse_ip_packet(&packet).unwrap(); + + assert_eq!(parsed_src_mac, src_mac); + assert_eq!(parsed_dst_mac, dst_mac); + assert_eq!(ip_packet.get_source(), local_addr.ip()); + assert_eq!(ip_packet.get_destination(), remote_addr.ip()); + assert_eq!(tcp_packet.get_source(), local_addr.port()); + assert_eq!(tcp_packet.get_destination(), remote_addr.port()); + assert_eq!(tcp_packet.payload(), payload); + } + + #[test] + fn parse_rejects_short_ethernet_frame() { + let packet = Bytes::from_static(&[0u8; ETH_HDR_LEN - 1]); + assert!(parse_ip_packet(&packet).is_none()); + } + + #[test] + fn parse_rejects_truncated_ipv4_tcp_packet() { + let packet = build_tcp_packet( + MacAddr::new(0x02, 0, 0, 0, 0, 5), + MacAddr::new(0x02, 0, 0, 0, 0, 6), + "192.0.2.10:1111".parse().unwrap(), + "198.51.100.20:2222".parse().unwrap(), + 1, + 2, + tcp::TcpFlags::ACK, + None, + ); + let truncated = Bytes::copy_from_slice(&packet[..ETH_HDR_LEN + IPV4_HEADER_LEN + 10]); + + assert!(parse_ip_packet(&truncated).is_none()); + } + + #[test] + fn parse_rejects_truncated_ipv6_header() { + let packet = build_tcp_packet( + MacAddr::new(0x02, 0, 0, 0, 0, 7), + MacAddr::new(0x02, 0, 0, 0, 0, 8), + "[2001:db8::10]:1111".parse().unwrap(), + "[2001:db8::20]:2222".parse().unwrap(), + 1, + 2, + tcp::TcpFlags::ACK, + None, + ); + let truncated = Bytes::copy_from_slice(&packet[..ETH_HDR_LEN + IPV6_HEADER_LEN - 1]); + + assert!(parse_ip_packet(&truncated).is_none()); } } diff --git a/easytier/src/tunnel/fake_tcp/stack.rs b/easytier/src/tunnel/fake_tcp/stack.rs index 3173c383..b3c311f8 100644 --- a/easytier/src/tunnel/fake_tcp/stack.rs +++ b/easytier/src/tunnel/fake_tcp/stack.rs @@ -223,8 +223,12 @@ impl Socket { return None; }; - let (src_mac, dst_mac, _v4_packet, tcp_packet) = - parse_ip_packet(&raw_buf).unwrap(); + let Some((src_mac, dst_mac, _v4_packet, tcp_packet)) = + parse_ip_packet(&raw_buf) + else { + trace!("Dropping malformed fake tcp packet for established socket"); + continue; + }; tracing::trace!( "Socket received TCP packet from {}({:?}) to {}({:?}): {:?}", @@ -307,8 +311,11 @@ impl Socket { info!("Waiting for client SYN + ACK timed out"); return None; }; - let (src_mac, _dst_mac, _v4_packet, tcp_packet) = - parse_ip_packet(&buf).unwrap(); + let Some((src_mac, _dst_mac, _v4_packet, tcp_packet)) = parse_ip_packet(&buf) + else { + trace!("Dropping malformed fake tcp packet during handshake"); + continue; + }; if (tcp_packet.get_flags() & tcp::TcpFlags::RST) != 0 { tracing::trace!("Connection {} reset by peer", self); From daa53e516849379cfba3fffc2bf5fad24e44934d Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Sun, 12 Apr 2026 07:04:21 +0200 Subject: [PATCH 10/24] log: auto-init log for tests (#2073) --- easytier/Cargo.toml | 1 + easytier/src/common/log.rs | 306 ++++++++++++++++++----------- easytier/src/gateway/quic_proxy.rs | 6 - easytier/src/tests/mod.rs | 17 -- easytier/src/tunnel/common.rs | 12 -- 5 files changed, 197 insertions(+), 145 deletions(-) diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index b7e53f6f..4d254fbd 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -347,6 +347,7 @@ rstest = "0.25.0" futures-util = "0.3.31" maplit = "1.0.2" tempfile = "3.22.0" +ctor = "0.8.0" [target.'cfg(target_os = "linux")'.dev-dependencies] defguard_wireguard_rs = "0.4.2" diff --git a/easytier/src/common/log.rs b/easytier/src/common/log.rs index 9dad049a..19eccc03 100644 --- a/easytier/src/common/log.rs +++ b/easytier/src/common/log.rs @@ -1,16 +1,18 @@ use std::io::IsTerminal as _; -use crate::common::config::LoggingConfigLoader; +use crate::common::config::{FileLoggerConfig, LoggingConfigLoader}; use crate::common::get_logger_timer_rfc3339; use crate::common::tracing_rolling_appender::{FileAppenderWrapper, RollingFileAppenderBase}; use crate::rpc_service::logger::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER}; use anyhow::Context; +use cfg_if::cfg_if; use paste::paste; use regex::Regex; use tracing::level_filters::LevelFilter; use tracing::{Level, Metadata}; use tracing_subscriber::Registry; use tracing_subscriber::filter::{FilterExt, filter_fn}; +use tracing_subscriber::fmt::format::FmtSpan; use tracing_subscriber::fmt::layer; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; @@ -86,127 +88,70 @@ macro_rules! log_layer { pub fn init( config: impl LoggingConfigLoader, - need_reload: bool, + reload: bool, ) -> Result, anyhow::Error> { let mut layers = Vec::new(); - let file_config = config.get_file_logger_config(); - let file_level = file_config - .level - .map(|s| s.parse().unwrap()) - .unwrap_or(LevelFilter::OFF); + let console_layers = console_layers( + config + .get_console_logger_config() + .level + .map(|s| s.parse().unwrap()) + .unwrap_or(LevelFilter::OFF), + )?; + layers.extend(console_layers); - let mut ret_sender: Option = None; + let sender = if cfg!(not(test)) { + let (file_layers, sender) = file_layers(config.get_file_logger_config(), reload)?; + layers.extend(file_layers); + sender + } else { + None + }; - // logger to a rolling file - if file_level != LevelFilter::OFF || need_reload { - let dir = file_config.dir.as_deref().unwrap_or("."); - let file = file_config.file.as_deref().unwrap_or("easytier.log"); - let path = std::path::Path::new(dir).join(file); - let path_str = path.to_string_lossy().into_owned(); + Registry::default() + .with(layers) + .try_init() + .map(|_| sender) + .map_err(Into::into) +} - let builder = RollingFileAppenderBase::builder(); - let file_appender = builder - .filename(path_str) - .condition_daily() - .max_filecount(file_config.count.unwrap_or(10)) - .condition_max_file_size(file_config.size_mb.unwrap_or(100) * 1024 * 1024) - .build() - .unwrap(); +type BoxLayer = Box + Send + Sync>; - // Create a simple wrapper that implements MakeWriter - let wrapper = FileAppenderWrapper::new(file_appender); +fn console_layers(default_level: LevelFilter) -> anyhow::Result> { + let mut layers = Vec::new(); + if default_level == LevelFilter::OFF { + return Ok(layers); + } - let (file_filter, file_filter_reloader) = - tracing_subscriber::reload::Layer::<_, Registry>::new(parse_env_filter(file_level)?); + let (console_filter, _) = + tracing_subscriber::reload::Layer::new(parse_env_filter(default_level)?); - let layer = |wrapper| { - layer() - .with_ansi(false) - .with_writer(wrapper) - .with_timer(get_logger_timer_rfc3339()) - }; - - layers.push( - vec![ - tracing_layer!(layer(wrapper.clone())), - log_layer!(layer(wrapper.clone())), - ] - .with_filter(file_filter) - .boxed(), - ); - - if need_reload { - let (sender, recver) = std::sync::mpsc::channel(); - ret_sender = Some(sender.clone()); - - // 初始化全局状态 - let _ = LOGGER_LEVEL_SENDER.set(std::sync::Mutex::new(sender)); - let _ = CURRENT_LOG_LEVEL.set(std::sync::Mutex::new(file_level.to_string())); - - std::thread::spawn(move || { - while let Ok(lf) = recver.recv() { - let parsed_level = match lf.parse::() { - Ok(level) => level, - Err(e) => { - error!("Failed to parse new log level {:?}: {}", lf, e); - continue; - } - }; - - let mut new_filter = match EnvFilter::builder() - .with_default_directive(parsed_level.into()) - .from_env() - .with_context(|| "failed to create file filter") - { - Ok(filter) => Some(filter), - Err(e) => { - error!("Failed to build new log filter for {:?}: {:?}", lf, e); - continue; - } - }; - - match file_filter_reloader.modify(|f| { - *f = new_filter - .take() - .expect("log filter reloader only applies one filter per reload"); - }) { - Ok(()) => { - info!("Reload log filter succeed, new filter level: {:?}", lf); - } - Err(e) => { - error!("Failed to reload log filter: {:?}", e); - } - } - } - info!("Stop log filter reloader"); - }); + cfg_if! { + if #[cfg(test)] { + let w = tracing_subscriber::fmt::TestWriter::new; + let (stdout, stderr) = (w, w); + } else { + let (stdout, stderr) = (std::io::stdout, std::io::stderr); } } - // logger to console - let console_config = config.get_console_logger_config(); - let console_level = console_config - .level - .map(|s| s.parse().unwrap()) - .unwrap_or(LevelFilter::OFF); - - let (console_filter, _) = - tracing_subscriber::reload::Layer::new(parse_env_filter(console_level)?); + let ansi = std::io::stderr().is_terminal() || cfg!(test); let layer = || { layer() .compact() - .with_ansi(std::io::stderr().is_terminal()) .with_timer(get_logger_timer_rfc3339()) - .with_writer(std::io::stderr) + .with_ansi(ansi) + .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) + .with_writer(stderr) }; layers.push( vec![ tracing_layer!(layer()), log_layer!(layer()).with_filter(LevelFilter::WARN).boxed(), - log_layer!(layer().with_writer(std::io::stdout)) + log_layer!(layer().with_writer(stdout)) .with_filter(filter_fn(|metadata| *metadata.level() > Level::WARN)) .boxed(), ] @@ -219,23 +164,164 @@ pub fn init( layers.push(console_subscriber::ConsoleLayer::builder().spawn().boxed()); } - Registry::default().with(layers).init(); + Ok(layers) +} - Ok(ret_sender) +fn file_layers( + config: FileLoggerConfig, + reload: bool, +) -> anyhow::Result<(Vec, Option)> { + let mut layers = Vec::new(); + + let level = config + .level + .map(|s| s.parse().unwrap()) + .unwrap_or(LevelFilter::OFF); + + if level == LevelFilter::OFF && !reload { + return Ok((layers, None)); + } + + let path = { + let dir = config.dir.as_deref().unwrap_or("."); + let file = config.file.as_deref().unwrap_or("easytier.log"); + let path = std::path::Path::new(dir).join(file); + path.to_string_lossy().into_owned() + }; + + let builder = RollingFileAppenderBase::builder(); + let file_appender = builder + .filename(path) + .condition_daily() + .max_filecount(config.count.unwrap_or(10)) + .condition_max_file_size(config.size_mb.unwrap_or(100) * 1024 * 1024) + .build() + .unwrap(); + + // Create a simple wrapper that implements MakeWriter + let wrapper = FileAppenderWrapper::new(file_appender); + + let (file_filter, file_filter_reloader) = + tracing_subscriber::reload::Layer::<_, Registry>::new(parse_env_filter(level)?); + + let layer = |wrapper| { + layer() + .with_ansi(false) + .with_writer(wrapper) + .with_timer(get_logger_timer_rfc3339()) + }; + + layers.push( + vec![ + tracing_layer!(layer(wrapper.clone())), + log_layer!(layer(wrapper.clone())), + ] + .with_filter(file_filter) + .boxed(), + ); + + if !reload { + return Ok((layers, None)); + } + + let (tx, rx) = std::sync::mpsc::channel(); + + // 初始化全局状态 + let _ = LOGGER_LEVEL_SENDER.set(std::sync::Mutex::new(tx.clone())); + let _ = CURRENT_LOG_LEVEL.set(std::sync::Mutex::new(level.to_string())); + + std::thread::spawn(move || { + while let Ok(lf) = rx.recv() { + let parsed_level = match lf.parse::() { + Ok(level) => level, + Err(e) => { + error!("Failed to parse new log level {:?}: {}", lf, e); + continue; + } + }; + + let mut new_filter = match EnvFilter::builder() + .with_default_directive(parsed_level.into()) + .from_env() + .with_context(|| "failed to create file filter") + { + Ok(filter) => Some(filter), + Err(e) => { + error!("Failed to build new log filter for {:?}: {:?}", lf, e); + continue; + } + }; + + match file_filter_reloader.modify(|f| { + *f = new_filter + .take() + .expect("log filter reloader only applies one filter per reload"); + }) { + Ok(()) => { + info!("Reload log filter succeed, new filter level: {:?}", lf); + } + Err(e) => { + error!("Failed to reload log filter: {:?}", e); + } + } + } + info!("Stop log filter reloader"); + }); + + Ok((layers, Some(tx))) } #[cfg(test)] mod tests { use super::*; - use crate::common::config::{self}; + use crate::common::config::FileLoggerConfig; - async fn test_logger_reload() { - println!("current working dir: {:?}", std::env::current_dir()); - let config = config::LoggingConfigBuilder::default().build().unwrap(); - let s = init(&config, true).unwrap(); - tracing::debug!("test not display debug"); - s.unwrap().send(LevelFilter::DEBUG.to_string()).unwrap(); - tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - tracing::debug!("test display debug"); + #[ctor::ctor] + fn init() { + let _ = Registry::default() + .with(console_layers(LevelFilter::DEBUG).unwrap()) + .try_init(); + } + + #[test] + fn test_logger_reload() { + let temp_dir = tempfile::tempdir().unwrap(); + let log_file_name = "reload-test.log".to_string(); + let log_path = temp_dir.path().join(&log_file_name); + + let cfg = FileLoggerConfig { + level: Some(LevelFilter::INFO.to_string()), + file: Some(log_file_name), + dir: Some(temp_dir.path().to_string_lossy().to_string()), + size_mb: Some(10), + count: Some(1), + }; + + let (layers, sender) = file_layers(cfg, true).unwrap(); + let sender = sender.expect("reload=true should return a sender"); + + let before_marker = "reload-before-debug-marker"; + let after_marker = "reload-after-debug-marker"; + let subscriber = Registry::default().with(layers); + + tracing::subscriber::with_default(subscriber, || { + tracing::debug!("{}", before_marker); + + sender.send(LevelFilter::DEBUG.to_string()).unwrap(); + std::thread::sleep(std::time::Duration::from_millis(300)); + + tracing::debug!("{}", after_marker); + std::thread::sleep(std::time::Duration::from_millis(300)); + }); + + let content = std::fs::read_to_string(&log_path).unwrap_or_default(); + assert!( + !content.contains(before_marker), + "debug log should be filtered before reload" + ); + assert!( + content.contains(after_marker), + "debug log should be visible after reload" + ); } } diff --git a/easytier/src/gateway/quic_proxy.rs b/easytier/src/gateway/quic_proxy.rs index c959efc8..dfd88d95 100644 --- a/easytier/src/gateway/quic_proxy.rs +++ b/easytier/src/gateway/quic_proxy.rs @@ -965,12 +965,6 @@ mod tests { use super::*; use bytes::Buf; - fn init() { - let _ = tracing_subscriber::fmt() - .with_env_filter("debug") - .try_init(); - } - /// Helper function: Create a pair of interconnected QuicSockets. /// Data sent by socket_a will enter socket_b's rx, and vice versa. fn make_socket_pair() -> (QuicSocket, QuicSocket) { diff --git a/easytier/src/tests/mod.rs b/easytier/src/tests/mod.rs index 7f48a63b..4c983252 100644 --- a/easytier/src/tests/mod.rs +++ b/easytier/src/tests/mod.rs @@ -6,8 +6,6 @@ mod ipv6_test; #[cfg(target_os = "linux")] mod credential_tests; -use std::io::IsTerminal as _; - use crate::common::PeerId; use crate::peers::peer_manager::PeerManager; @@ -133,21 +131,6 @@ pub fn add_ns_to_bridge(br_name: &str, ns_name: &str) { .unwrap(); } -pub fn enable_log() { - let filter = tracing_subscriber::EnvFilter::builder() - .with_default_directive(tracing::level_filters::LevelFilter::TRACE.into()) - .from_env() - .unwrap() - .add_directive("tarpc=error".parse().unwrap()); - let use_ansi = std::io::stderr().is_terminal(); - tracing_subscriber::fmt::fmt() - .pretty() - .with_ansi(use_ansi) - .with_env_filter(filter) - .with_writer(std::io::stderr) - .init(); -} - fn check_route(ipv4: &str, dst_peer_id: PeerId, routes: Vec) { let mut found = false; for r in routes.iter() { diff --git a/easytier/src/tunnel/common.rs b/easytier/src/tunnel/common.rs index 92766a29..05938d58 100644 --- a/easytier/src/tunnel/common.rs +++ b/easytier/src/tunnel/common.rs @@ -691,18 +691,6 @@ pub mod tests { bps as usize } - pub fn enable_log() { - let filter = tracing_subscriber::EnvFilter::builder() - .with_default_directive(tracing::level_filters::LevelFilter::TRACE.into()) - .from_env() - .unwrap() - .add_directive("tarpc=error".parse().unwrap()); - tracing_subscriber::fmt::fmt() - .pretty() - .with_env_filter(filter) - .init(); - } - pub async fn wait_for_condition(mut condition: F, timeout: std::time::Duration) where F: FnMut() -> FRet + Send, From 83010861bac8ee377521b28ce704dbdc3a8d6670 Mon Sep 17 00:00:00 2001 From: deddey Date: Sun, 12 Apr 2026 21:00:59 +0800 Subject: [PATCH 11/24] Optimize network interface configuration for macOS and FreeBSD to avoid hard-coded IP addresses (#1853) Co-authored-by: KKRainbow <443152178@qq.com> --- easytier/src/common/ifcfg/darwin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/easytier/src/common/ifcfg/darwin.rs b/easytier/src/common/ifcfg/darwin.rs index b556b186..0412d9e2 100644 --- a/easytier/src/common/ifcfg/darwin.rs +++ b/easytier/src/common/ifcfg/darwin.rs @@ -53,8 +53,8 @@ impl IfConfiguerTrait for MacIfConfiger { ) -> Result<(), Error> { run_shell_cmd( format!( - "ifconfig {} {:?}/{:?} 10.8.8.8 up", - name, address, cidr_prefix, + "ifconfig {} {:?}/{:?} {:?} up", + name, address, cidr_prefix, address, ) .as_str(), ) From c6cb1a77d06ed952ead897a6abf0610893760b75 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:13:58 +0200 Subject: [PATCH 12/24] chore: clippy fix some code on Windows (#2106) --- easytier/src/arch/windows.rs | 2 +- easytier/src/common/ifcfg/windows.rs | 11 +++--- .../dns_server/system_config/windows.rs | 7 ++-- easytier/src/service_manager/mod.rs | 8 ++-- .../tunnel/fake_tcp/netfilter/windivert.rs | 37 ++++++++----------- 5 files changed, 28 insertions(+), 37 deletions(-) diff --git a/easytier/src/arch/windows.rs b/easytier/src/arch/windows.rs index d709d499..abf14b23 100644 --- a/easytier/src/arch/windows.rs +++ b/easytier/src/arch/windows.rs @@ -345,7 +345,7 @@ fn add_protocol_firewall_rules( SafeArrayPutElement( interface_array, - &index as *const _ as *const i32, + &index as *const _, &variant_interface as *const _ as *const std::ffi::c_void, )?; diff --git a/easytier/src/common/ifcfg/windows.rs b/easytier/src/common/ifcfg/windows.rs index 35ef12f7..aa995e54 100644 --- a/easytier/src/common/ifcfg/windows.rs +++ b/easytier/src/common/ifcfg/windows.rs @@ -448,12 +448,11 @@ impl RegistryManager { for guid in network_key.enum_keys().map_while(Result::ok) { if let Ok(guid_key) = network_key.open_subkey_with_flags(&guid, KEY_READ) { // 检查 Connection/Name 是否匹配目标接口名 - if let Ok(conn_key) = guid_key.open_subkey_with_flags("Connection", KEY_READ) { - if let Ok(name) = conn_key.get_value::("Name") { - if name == interface_name { - return Ok(guid); - } - } + if let Ok(conn_key) = guid_key.open_subkey_with_flags("Connection", KEY_READ) + && let Ok(name) = conn_key.get_value::("Name") + && name == interface_name + { + return Ok(guid); } } } diff --git a/easytier/src/instance/dns_server/system_config/windows.rs b/easytier/src/instance/dns_server/system_config/windows.rs index 94f014d4..3c298cf9 100644 --- a/easytier/src/instance/dns_server/system_config/windows.rs +++ b/easytier/src/instance/dns_server/system_config/windows.rs @@ -202,13 +202,12 @@ mod tests { .arg("1") .arg("-w") .arg("100") - .arg(&fake_ip.to_string()) + .arg(fake_ip.to_string()) .output() .await + && o.status.success() { - if o.status.success() { - break; - } + break; } } diff --git a/easytier/src/service_manager/mod.rs b/easytier/src/service_manager/mod.rs index c1944504..9587c38c 100644 --- a/easytier/src/service_manager/mod.rs +++ b/easytier/src/service_manager/mod.rs @@ -491,10 +491,10 @@ mod win_service_manager { { Ok(s) => s, Err(e) => { - if let windows_service::Error::Winapi(ref win_err) = e { - if win_err.raw_os_error() == Some(0x424) { - return Ok(ServiceStatus::NotInstalled); - } + if let windows_service::Error::Winapi(ref win_err) = e + && win_err.raw_os_error() == Some(0x424) + { + return Ok(ServiceStatus::NotInstalled); } return Err(io::Error::other(e)); } diff --git a/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs b/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs index 1d58f235..fdbe0877 100644 --- a/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs +++ b/easytier/src/tunnel/fake_tcp/netfilter/windivert.rs @@ -68,10 +68,10 @@ pub struct WinDivertTun { impl Drop for WinDivertTun { fn drop(&mut self) { - if let Ok(mut sender) = self.sender.lock() { - if let Err(e) = sender.close(windivert::CloseAction::Nothing) { - tracing::error!("WinDivertSender close failed: {:?}", e); - } + if let Ok(mut sender) = self.sender.lock() + && let Err(e) = sender.close(windivert::CloseAction::Nothing) + { + tracing::error!("WinDivertSender close failed: {:?}", e); } if let Err(e) = self.reader.shutdown() { tracing::error!("WinDivertReader shutdown failed: {:?}", e); @@ -94,8 +94,7 @@ impl WinDivertTun { // Layer: Network (0) // Priority: 0 let flags = WinDivertFlags::default().set_sniff(); - let reader = WinDivert::network(&filter, 0, flags) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + let reader = WinDivert::network(&filter, 0, flags).map_err(io::Error::other)?; let reader = Arc::new(WinDivertReader::new(reader)); let reader_clone = reader.clone(); @@ -109,7 +108,7 @@ impl WinDivertTun { let mut eth_data = vec![0u8; 14 + data.len()]; // Set EtherType - if data.len() > 0 && data[0] >> 4 == 4 { + if !data.is_empty() && data[0] >> 4 == 4 { eth_data[12] = 0x08; eth_data[13] = 0x00; } else { @@ -118,12 +117,12 @@ impl WinDivertTun { } eth_data[14..].copy_from_slice(data); - if let Err(_) = tx.blocking_send(eth_data) { + if tx.blocking_send(eth_data).is_err() { break; } } - Err(_) => { - // log error? + Err(error) => { + tracing::error!(?error, "WinDivert recv failed"); break; } } @@ -133,8 +132,8 @@ impl WinDivertTun { // Sender: non-sniff, empty filter? // Use "false" to avoid capturing anything. // Flags: 0 - let sender = WinDivert::network("false", 0, WinDivertFlags::default()) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + let sender = + WinDivert::network("false", 0, WinDivertFlags::default()).map_err(io::Error::other)?; Ok(Self { recv_queue: Mutex::new(rx), @@ -171,21 +170,15 @@ impl stack::Tun for WinDivertTun { let ip_data = &packet[14..]; let Ok(sender) = self.sender.try_lock() else { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "WinDivert sender lock failed", - )); + return Err(std::io::Error::other("WinDivert sender lock failed")); }; let mut pkt = unsafe { WinDivertPacket::::new(ip_data.to_vec()) }; pkt.address.set_outbound(true); - sender.send(&pkt).map_err(|e| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("WinDivert send failed: {}", e), - ) - })?; + sender + .send(&pkt) + .map_err(|e| std::io::Error::other(format!("WinDivert send failed: {}", e)))?; Ok(()) } From 9e0a3b6936194a2f7c76ad7e49147200aa47e800 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:14:41 +0200 Subject: [PATCH 13/24] ci: rewrite build workflows (#2089) --- .cargo/config.toml | 89 ++++---- .github/actions/prepare-build/action.yml | 75 +++++-- .github/workflows/core.yml | 252 ++++++++++------------- .github/workflows/gui.yml | 107 +++------- .github/workflows/install_gui_dep.sh | 11 - .github/workflows/install_rust.sh | 61 ------ .github/workflows/mobile.yml | 61 +++--- .github/workflows/ohos.yml | 38 ++-- .github/workflows/test.yml | 15 +- Cargo.lock | 6 +- easytier-gui/src-tauri/Cargo.toml | 17 +- easytier-gui/src-tauri/build.rs | 24 +-- easytier-web/Cargo.toml | 12 +- easytier-web/build.rs | 10 +- easytier/Cargo.toml | 14 +- easytier/build.rs | 8 +- 16 files changed, 338 insertions(+), 462 deletions(-) delete mode 100644 .github/workflows/install_gui_dep.sh delete mode 100644 .github/workflows/install_rust.sh diff --git a/.cargo/config.toml b/.cargo/config.toml index 17288931..2548b156 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,29 +1,40 @@ -[target.x86_64-unknown-linux-musl] -linker = "rust-lld" -rustflags = ["-C", "linker-flavor=ld.lld"] +# region Native + +[target.x86_64-unknown-linux-gnu] +rustflags = ["-C", "link-arg=-fuse-ld=mold"] [target.aarch64-unknown-linux-gnu] -linker = "aarch64-linux-gnu-gcc" +rustflags = ["-C", "link-arg=-fuse-ld=mold"] -[target.aarch64-unknown-linux-ohos] -ar = "/usr/local/ohos-sdk/linux/native/llvm/bin/llvm-ar" -linker = "/home/runner/sdk/native/llvm/aarch64-unknown-linux-ohos-clang.sh" +[target.'cfg(all(windows, target_env = "msvc"))'] +rustflags = ["-C", "target-feature=+crt-static"] -[target.aarch64-unknown-linux-ohos.env] -PKG_CONFIG_PATH = "/usr/local/ohos-sdk/linux/native/sysroot/usr/lib/pkgconfig:/usr/local/ohos-sdk/linux/native/sysroot/usr/local/lib/pkgconfig" -PKG_CONFIG_LIBDIR = "/usr/local/ohos-sdk/linux/native/sysroot/usr/lib:/usr/local/ohos-sdk/linux/native/sysroot/usr/local/lib" -PKG_CONFIG_SYSROOT_DIR = "/usr/local/ohos-sdk/linux/native/sysroot" -SYSROOT = "/usr/local/ohos-sdk/linux/native/sysroot" +# region + +# region CI + +[target.x86_64-unknown-linux-musl] +rustflags = ["-C", "target-feature=+crt-static"] [target.aarch64-unknown-linux-musl] -linker = "aarch64-unknown-linux-musl-gcc" rustflags = ["-C", "target-feature=+crt-static"] [target.riscv64gc-unknown-linux-musl] -linker = "riscv64-unknown-linux-musl-gcc" rustflags = ["-C", "target-feature=+crt-static"] -[target.'cfg(all(windows, target_env = "msvc"))'] +[target.armv7-unknown-linux-musleabihf] +rustflags = ["-C", "target-feature=+crt-static"] + +[target.armv7-unknown-linux-musleabi] +rustflags = ["-C", "target-feature=+crt-static"] + +[target.arm-unknown-linux-musleabihf] +rustflags = ["-C", "target-feature=+crt-static"] + +[target.arm-unknown-linux-musleabi] +rustflags = ["-C", "target-feature=+crt-static"] + +[target.loongarch64-unknown-linux-musl] rustflags = ["-C", "target-feature=+crt-static"] [target.mipsel-unknown-linux-musl] @@ -64,44 +75,14 @@ rustflags = [ "gcc", ] -[target.armv7-unknown-linux-musleabihf] -linker = "armv7-unknown-linux-musleabihf-gcc" -rustflags = ["-C", "target-feature=+crt-static"] +[target.aarch64-unknown-linux-ohos] +ar = "/usr/local/ohos-sdk/linux/native/llvm/bin/llvm-ar" +linker = "/home/runner/sdk/native/llvm/aarch64-unknown-linux-ohos-clang.sh" -[target.armv7-unknown-linux-musleabi] -linker = "armv7-unknown-linux-musleabi-gcc" -rustflags = ["-C", "target-feature=+crt-static"] +[target.aarch64-unknown-linux-ohos.env] +PKG_CONFIG_PATH = "/usr/local/ohos-sdk/linux/native/sysroot/usr/lib/pkgconfig:/usr/local/ohos-sdk/linux/native/sysroot/usr/local/lib/pkgconfig" +PKG_CONFIG_LIBDIR = "/usr/local/ohos-sdk/linux/native/sysroot/usr/lib:/usr/local/ohos-sdk/linux/native/sysroot/usr/local/lib" +PKG_CONFIG_SYSROOT_DIR = "/usr/local/ohos-sdk/linux/native/sysroot" +SYSROOT = "/usr/local/ohos-sdk/linux/native/sysroot" -[target.loongarch64-unknown-linux-musl] -linker = "loongarch64-unknown-linux-musl-gcc" -rustflags = ["-C", "target-feature=+crt-static"] - -[target.arm-unknown-linux-musleabihf] -linker = "arm-unknown-linux-musleabihf-gcc" -rustflags = [ - "-C", - "target-feature=+crt-static", - "-L", - "./musl_gcc/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/lib", - "-L", - "./musl_gcc/arm-unknown-linux-musleabihf/lib/gcc/arm-unknown-linux-musleabihf/15.1.0", - "-l", - "atomic", - "-l", - "gcc", -] - -[target.arm-unknown-linux-musleabi] -linker = "arm-unknown-linux-musleabi-gcc" -rustflags = [ - "-C", - "target-feature=+crt-static", - "-L", - "./musl_gcc/arm-unknown-linux-musleabi/arm-unknown-linux-musleabi/lib", - "-L", - "./musl_gcc/arm-unknown-linux-musleabi/lib/gcc/arm-unknown-linux-musleabi/15.1.0", - "-l", - "atomic", - "-l", - "gcc", -] +# endregion diff --git a/.github/actions/prepare-build/action.yml b/.github/actions/prepare-build/action.yml index 33885c6d..57699603 100644 --- a/.github/actions/prepare-build/action.yml +++ b/.github/actions/prepare-build/action.yml @@ -2,10 +2,17 @@ name: prepare-build author: Luna description: Prepare build environment inputs: - web: - description: 'Whether to prepare the web build environment' + target: + description: 'The target to build for' + required: false + pnpm: + description: 'Whether to run pnpm build' required: true default: 'true' + pnpm-build-filter: + description: 'The filter argument for pnpm build (e.g. ./easytier-web/*)' + required: false + default: './easytier-web/*' gui: description: 'Whether to prepare the GUI build environment' required: true @@ -19,21 +26,63 @@ runs: - run: mkdir -p easytier-gui/dist shell: bash - - name: Setup Frontend Environment - if: ${{ inputs.web == 'true' }} - uses: ./.github/actions/prepare-pnpm - with: - build-filter: './easytier-web/*' - - - name: Install GUI dependencies (Used by clippy) - if: ${{ inputs.gui == 'true' }} + - name: Install dependencies + if: ${{ runner.os == 'Linux' }} run: | - bash ./.github/workflows/install_gui_dep.sh + sudo apt-get update + sudo apt-get install -qqy build-essential mold musl-tools shell: bash - - name: Install Rust + - name: Setup Frontend Environment + if: ${{ inputs.pnpm == 'true' }} + uses: ./.github/actions/prepare-pnpm + with: + build-filter: ${{ inputs.pnpm-build-filter }} + + - name: Install GUI dependencies (Linux) + if: ${{ inputs.gui == 'true' && runner.os == 'Linux' }} run: | - bash ./.github/workflows/install_rust.sh + sudo apt-get install -qq xdg-utils \ + libappindicator3-dev \ + libgtk-3-dev \ + librsvg2-dev \ + libwebkit2gtk-4.1-dev \ + libxdo-dev + shell: bash + + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + target: ${{ !contains(inputs.target, 'mips') && inputs.target || '' }} + cache: false + rustflags: '' + + - name: Install Rust (MIPS) + if: ${{ contains(inputs.target, 'mips') }} + run: | + rustup toolchain install nightly-2026-02-02-x86_64-unknown-linux-gnu + rustup component add rust-src --toolchain nightly-2026-02-02-x86_64-unknown-linux-gnu + + MUSL_TARGET=${{ inputs.target }}sf + mkdir -p ./musl_gcc + wget --inet4-only -c https://github.com/cross-tools/musl-cross/releases/download/20250520/${MUSL_TARGET}.tar.xz -P ./musl_gcc/ + tar xf ./musl_gcc/${MUSL_TARGET}.tar.xz -C ./musl_gcc/ + sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/bin/*gcc /usr/bin/ + sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/include/ /usr/include/musl-cross + sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/${MUSL_TARGET}/sysroot/ ./musl_gcc/sysroot + sudo chmod -R a+rwx ./musl_gcc + + if [[ -d "./musl_gcc/sysroot" ]]; then + echo "BINDGEN_EXTRA_CLANG_ARGS=--sysroot=$(readlink -f ./musl_gcc/sysroot)" >> $GITHUB_ENV + fi + + cd "$PWD/musl_gcc/${MUSL_TARGET}/lib/gcc/${MUSL_TARGET}/15.1.0" || exit 255 + # for panic-abort + cp libgcc_eh.a libunwind.a + + # for mimalloc + ar x libgcc.a _ctzsi2.o _clz.o _bswapsi2.o + ar rcs libctz.a _ctzsi2.o _clz.o _bswapsi2.o shell: bash - name: Setup protoc diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index f2df8fb5..e2f5cb39 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -2,10 +2,10 @@ name: EasyTier Core on: push: - branches: ["develop", "main", "releases/**"] + branches: [ "develop", "main", "releases/**" ] pull_request: - branches: ["develop", "main"] - types: [opened, synchronize, reopened, ready_for_review] + branches: [ "develop", "main" ] + types: [ opened, synchronize, reopened, ready_for_review ] concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -36,7 +36,7 @@ jobs: concurrent_skipping: 'same_content_newer' skip_after_successful_duplicate: 'true' cancel_others: 'true' - paths: '["Cargo.toml", "Cargo.lock", "easytier/**", ".github/workflows/core.yml", ".github/workflows/install_rust.sh", "easytier-web/**"]' + paths: '["Cargo.toml", "Cargo.lock", "easytier/**", ".github/workflows/core.yml", ".github/actions/**", "easytier-web/**"]' build_web: runs-on: ubuntu-latest needs: pre_job @@ -60,38 +60,45 @@ jobs: fail-fast: true matrix: include: - - TARGET: aarch64-unknown-linux-musl - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-aarch64 - TARGET: x86_64-unknown-linux-musl - OS: ubuntu-22.04 + OS: ubuntu-24.04 ARTIFACT_NAME: linux-x86_64 - - TARGET: riscv64gc-unknown-linux-musl - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-riscv64 - - TARGET: mips-unknown-linux-musl - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-mips - - TARGET: mipsel-unknown-linux-musl - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-mipsel - - TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-armv7hf - - TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-armv7 - - TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-armhf - - TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested - OS: ubuntu-22.04 - ARTIFACT_NAME: linux-arm + - TARGET: aarch64-unknown-linux-musl + OS: ubuntu-24.04-arm + ARTIFACT_NAME: linux-aarch64 + - TARGET: riscv64gc-unknown-linux-musl + OS: ubuntu-24.04 + ARTIFACT_NAME: linux-riscv64 - TARGET: loongarch64-unknown-linux-musl OS: ubuntu-24.04 ARTIFACT_NAME: linux-loongarch64 + - TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested + OS: ubuntu-24.04 + ARTIFACT_NAME: linux-armv7hf + - TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested + OS: ubuntu-24.04 + ARTIFACT_NAME: linux-armv7 + - TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested + OS: ubuntu-24.04 + ARTIFACT_NAME: linux-armhf + - TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested + OS: ubuntu-24.04 + ARTIFACT_NAME: linux-arm + + - TARGET: mips-unknown-linux-musl + OS: ubuntu-24.04 + ARTIFACT_NAME: linux-mips + - TARGET: mipsel-unknown-linux-musl + OS: ubuntu-24.04 + ARTIFACT_NAME: linux-mipsel + + - TARGET: x86_64-unknown-freebsd + OS: ubuntu-24.04 + ARTIFACT_NAME: freebsd-13.2-x86_64 + BSD_VERSION: 13.2 + - TARGET: x86_64-apple-darwin OS: macos-latest ARTIFACT_NAME: macos-x86_64 @@ -102,17 +109,12 @@ jobs: - TARGET: x86_64-pc-windows-msvc OS: windows-latest ARTIFACT_NAME: windows-x86_64 - - TARGET: aarch64-pc-windows-msvc - OS: windows-latest - ARTIFACT_NAME: windows-arm64 - TARGET: i686-pc-windows-msvc OS: windows-latest ARTIFACT_NAME: windows-i686 - - - TARGET: x86_64-unknown-freebsd - OS: ubuntu-22.04 - ARTIFACT_NAME: freebsd-13.2-x86_64 - BSD_VERSION: 13.2 + - TARGET: aarch64-pc-windows-msvc + OS: windows-11-arm + ARTIFACT_NAME: windows-arm64 runs-on: ${{ matrix.OS }} env: @@ -137,8 +139,15 @@ jobs: name: easytier-web-dashboard path: easytier-web/frontend/dist/ + - name: Prepare build environment + uses: ./.github/actions/prepare-build + with: + target: ${{ matrix.TARGET }} + gui: true + pnpm: true + token: ${{ secrets.GITHUB_TOKEN }} + - uses: Swatinem/rust-cache@v2 - if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }} with: # The prefix cache key, this can be changed to start a new cache manually. # default: "v0-rust" @@ -146,96 +155,49 @@ jobs: shared-key: "core-registry" cache-targets: "false" - - name: Setup protoc - uses: arduino/setup-protoc@v3 + - uses: mlugg/setup-zig@v2 + if: ${{ contains(matrix.OS, 'ubuntu') }} + + - uses: taiki-e/install-action@v2 + if: ${{ contains(matrix.OS, 'ubuntu') }} with: - # GitHub repo token to use to avoid rate limiter - repo-token: ${{ secrets.GITHUB_TOKEN }} + tool: cargo-zigbuild - - name: Build Core & Cli - if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }} - run: | - bash ./.github/workflows/install_rust.sh - - # loongarch need llvm-18 - if [[ $TARGET =~ ^loongarch.*$ ]]; then - sudo apt-get install -qq llvm-18 clang-18 - export LLVM_CONFIG_PATH=/usr/lib/llvm-18/bin/llvm-config - fi - # we set the sysroot when sysroot is a dir - # this dir is a soft link generated by install_rust.sh - # kcp-sys need this to gen ffi bindings. without this clang may fail to find some libc headers such as bits/libc-header-start.h - if [[ -d "./musl_gcc/sysroot" ]]; then - export BINDGEN_EXTRA_CLANG_ARGS=--sysroot=$(readlink -f ./musl_gcc/sysroot) - fi - - if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then - cargo +nightly-2026-02-02 build -r --target $TARGET -Z build-std=std,panic_abort --package=easytier --features=jemalloc + - name: Build + if: ${{ !contains(matrix.TARGET, 'mips') }} + run: | + if [[ "$TARGET" == *windows* ]]; then + SUFFIX=.exe else - if [[ $OS =~ ^windows.*$ ]]; then - SUFFIX=.exe - CORE_FEATURES="--features=mimalloc" - elif [[ $TARGET =~ ^riscv64.*$ || $TARGET =~ ^loongarch64.*$ || $TARGET =~ ^aarch64.*$ ]]; then - CORE_FEATURES="--features=mimalloc" - else - CORE_FEATURES="--features=jemalloc" - fi - cargo build --release --target $TARGET --package=easytier-web --features=embed - mv ./target/$TARGET/release/easytier-web"$SUFFIX" ./target/$TARGET/release/easytier-web-embed"$SUFFIX" - cargo build --release --target $TARGET $CORE_FEATURES + SUFFIX="" fi - # Copied and slightly modified from @lmq8267 (https://github.com/lmq8267) - - name: Build Core & Cli (X86_64 FreeBSD) - uses: vmactions/freebsd-vm@670398e4236735b8b65805c3da44b7a511fb8b27 - if: ${{ endsWith(matrix.TARGET, 'freebsd') }} - env: - TARGET: ${{ matrix.TARGET }} - with: - envs: TARGET - release: ${{ matrix.BSD_VERSION }} - arch: x86_64 - usesh: true - mem: 6144 - cpu: 4 - run: | - uname -a - echo $SHELL - pwd - ls -lah - whoami - env | sort + if [[ "$TARGET" =~ (x86_64-unknown-linux-musl|aarch64-unknown-linux-musl|windows|darwin) ]]; then + BUILD=build + else + BUILD=zigbuild + fi - pkg install -y git protobuf llvm-devel sudo curl - curl --proto 'https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - . $HOME/.cargo/env + if [[ "$TARGET" =~ ^(riscv64|loongarch64|aarch64).*$ || "$TARGET" =~ windows ]]; then + FEATURES="mimalloc" + else + FEATURES="jemalloc" + fi + + cargo $BUILD --release --target $TARGET --package=easytier-web --features=embed + mv ./target/$TARGET/release/easytier-web"$SUFFIX" ./target/$TARGET/release/easytier-web-embed"$SUFFIX" + + cargo $BUILD --release --target $TARGET --features=$FEATURES - rustup set auto-self-update disable - - rustup install 1.93 - rustup default 1.93 - - export CC=clang - export CXX=clang++ - export CARGO_TERM_COLOR=always - - cargo build --release --verbose --target $TARGET --package=easytier-web --features=embed - mv ./target/$TARGET/release/easytier-web ./target/$TARGET/release/easytier-web-embed - cargo build --release --verbose --target $TARGET --features=mimalloc - - mkdir -p built-bins/$TARGET/release/ - mv ./target/$TARGET/release/easytier-web-embed ./built-bins/$TARGET/release/easytier-web-embed - mv ./target/$TARGET/release/easytier-web ./built-bins/$TARGET/release/easytier-web - mv ./target/$TARGET/release/easytier-core ./built-bins/$TARGET/release/easytier-core - mv ./target/$TARGET/release/easytier-cli ./built-bins/$TARGET/release/easytier-cli - - # remove dirs to avoid copy many files back - rm -rf ./target ~/.cargo - mv ./built-bins ./target + - name: Build (MIPS) + if: ${{ contains(matrix.TARGET, 'mips') }} + run: | + cargo +nightly-2026-02-02 build -r --target $TARGET -Z build-std=std,panic_abort --package=easytier --features=jemalloc - name: Compress run: | mkdir -p ./artifacts/objects/ + # windows is the only OS using a different convention for executable file name if [[ $OS =~ ^windows.*$ ]]; then SUFFIX=.exe @@ -248,26 +210,37 @@ jobs: find "easytier/third_party/${ARCH_DIR}" -maxdepth 1 -type f \( -name "*.dll" -o -name "*.sys" \) -exec cp {} ./artifacts/objects/ \; fi fi + if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then TAG=$GITHUB_REF_NAME else TAG=$GITHUB_SHA fi + + if [[ $OS =~ ^ubuntu.*$ && ! $TARGET =~ (loongarch|freebsd) ]]; then + HOST_ARCH=$(uname -m) + case $HOST_ARCH in + x86_64) UPX_ARCH="amd64" ;; + aarch64) UPX_ARCH="arm64" ;; + *) UPX_ARCH="amd64" ;; + esac - if [[ $OS =~ ^ubuntu.*$ && ! $TARGET =~ ^.*freebsd$ && ! $TARGET =~ ^loongarch.*$ && ! $TARGET =~ ^riscv64.*$ ]]; then - UPX_VERSION=4.2.4 - curl -L https://github.com/upx/upx/releases/download/v${UPX_VERSION}/upx-${UPX_VERSION}-amd64_linux.tar.xz -s | tar xJvf - - cp upx-${UPX_VERSION}-amd64_linux/upx . - ./upx --lzma --best ./target/$TARGET/release/easytier-core"$SUFFIX" - ./upx --lzma --best ./target/$TARGET/release/easytier-cli"$SUFFIX" + UPX_VERSION=5.1.1 + UPX_PKG="upx-${UPX_VERSION}-${UPX_ARCH}_linux" + curl -L "https://github.com/upx/upx/releases/download/v${UPX_VERSION}/${UPX_PKG}.tar.xz" -s | tar xJvf - + cp "${UPX_PKG}/upx" . + UPX_BIN=./upx fi - mv ./target/$TARGET/release/easytier-core"$SUFFIX" ./artifacts/objects/ - mv ./target/$TARGET/release/easytier-cli"$SUFFIX" ./artifacts/objects/ - if [[ ! $TARGET =~ ^mips.*$ ]]; then - mv ./target/$TARGET/release/easytier-web"$SUFFIX" ./artifacts/objects/ - mv ./target/$TARGET/release/easytier-web-embed"$SUFFIX" ./artifacts/objects/ - fi + for BIN in ./target/$TARGET/release/easytier-{core,cli,web,web-embed}"$SUFFIX"; do + if [[ -f "$BIN" ]]; then + if [[ -n "$UPX_BIN" ]]; then + $UPX_BIN --lzma --best "$BIN" || true + fi + + mv "$BIN" ./artifacts/objects/ + fi + done mv ./artifacts/objects/* ./artifacts/ rm -rf ./artifacts/objects/ @@ -279,16 +252,7 @@ jobs: path: | ./artifacts/* - core-result: - runs-on: ubuntu-latest - needs: [ pre_job, build_web, build ] - if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() - steps: - - name: Mark result as failed - if: contains(needs.*.result, 'failure') - run: exit 1 - - magisk_build: + build_magisk: runs-on: ubuntu-latest needs: [ pre_job, build_web, build ] if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() @@ -311,7 +275,6 @@ jobs: cp ./downloaded-binaries/easytier-cli ./easytier-contrib/easytier-magisk/ cp ./downloaded-binaries/easytier-web ./easytier-contrib/easytier-magisk/ - # 上传生成的模块 - name: Upload Magisk Module uses: actions/upload-artifact@v5 @@ -322,3 +285,12 @@ jobs: !./easytier-contrib/easytier-magisk/build.sh !./easytier-contrib/easytier-magisk/magisk_update.json if-no-files-found: error + + core-result: + runs-on: ubuntu-latest + needs: [ pre_job, build_web, build, build_magisk ] + if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled() + steps: + - name: Mark result as failed + if: contains(needs.*.result, 'failure') + run: exit 1 diff --git a/.github/workflows/gui.yml b/.github/workflows/gui.yml index 77c75496..39a27759 100644 --- a/.github/workflows/gui.yml +++ b/.github/workflows/gui.yml @@ -35,20 +35,20 @@ jobs: concurrent_skipping: 'same_content_newer' skip_after_successful_duplicate: 'true' cancel_others: 'true' - paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", ".github/workflows/gui.yml", ".github/workflows/install_rust.sh", ".github/workflows/install_gui_dep.sh", "easytier-web/frontend-lib/**"]' + paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", ".github/workflows/gui.yml", ".github/actions/**", "easytier-web/frontend-lib/**"]' build-gui: strategy: fail-fast: true matrix: include: - - TARGET: aarch64-unknown-linux-musl - OS: ubuntu-22.04 - GUI_TARGET: aarch64-unknown-linux-gnu - ARTIFACT_NAME: linux-aarch64 - TARGET: x86_64-unknown-linux-musl - OS: ubuntu-22.04 + OS: ubuntu-24.04 GUI_TARGET: x86_64-unknown-linux-gnu ARTIFACT_NAME: linux-x86_64 + - TARGET: aarch64-unknown-linux-musl + OS: ubuntu-24.04-arm + GUI_TARGET: aarch64-unknown-linux-gnu + ARTIFACT_NAME: linux-aarch64 - TARGET: x86_64-apple-darwin OS: macos-latest @@ -63,16 +63,14 @@ jobs: OS: windows-latest GUI_TARGET: x86_64-pc-windows-msvc ARTIFACT_NAME: windows-x86_64 - - - TARGET: aarch64-pc-windows-msvc - OS: windows-latest - GUI_TARGET: aarch64-pc-windows-msvc - ARTIFACT_NAME: windows-arm64 - - TARGET: i686-pc-windows-msvc OS: windows-latest GUI_TARGET: i686-pc-windows-msvc ARTIFACT_NAME: windows-i686 + - TARGET: aarch64-pc-windows-msvc + OS: windows-11-arm + GUI_TARGET: aarch64-pc-windows-msvc + ARTIFACT_NAME: windows-arm64 runs-on: ${{ matrix.OS }} env: @@ -86,75 +84,29 @@ jobs: steps: - uses: actions/checkout@v5 - - name: Install GUI dependencies (x86 only) - if: ${{ matrix.TARGET == 'x86_64-unknown-linux-musl' }} - run: bash ./.github/workflows/install_gui_dep.sh - - - name: Install GUI cross compile (aarch64 only) - if: ${{ matrix.TARGET == 'aarch64-unknown-linux-musl' }} - run: | - # see https://tauri.app/v1/guides/building/linux/ - echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy main restricted" | sudo tee /etc/apt/sources.list - echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy universe" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy-updates universe" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy multiverse" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://security.ubuntu.com/ubuntu/ jammy-security main restricted" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://security.ubuntu.com/ubuntu/ jammy-security universe" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=amd64] http://security.ubuntu.com/ubuntu/ jammy-security multiverse" | sudo tee -a /etc/apt/sources.list - - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy main restricted" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy universe" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates universe" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy multiverse" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates multiverse" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security universe" | sudo tee -a /etc/apt/sources.list - echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security multiverse" | sudo tee -a /etc/apt/sources.list - - sudo dpkg --add-architecture arm64 - sudo apt update - sudo apt install aptitude - sudo aptitude install -y libgstreamer1.0-0:arm64 gstreamer1.0-plugins-base:arm64 gstreamer1.0-plugins-good:arm64 \ - libgstreamer-gl1.0-0:arm64 libgstreamer-plugins-base1.0-0:arm64 libgstreamer-plugins-good1.0-0:arm64 libwebkit2gtk-4.1-0:arm64 \ - libwebkit2gtk-4.1-dev:arm64 libssl-dev:arm64 gcc-aarch64-linux-gnu libsoup-3.0-dev:arm64 libjavascriptcoregtk-4.1-dev:arm64 - echo "PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu/" >> "$GITHUB_ENV" - echo "PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig/" >> "$GITHUB_ENV" - - - name: Install rpm package (Linux target only) - if: ${{ contains(matrix.TARGET, '-linux-') }} - run: | - sudo apt update - sudo apt install -y rpm - - name: Set current ref as env variable run: | echo "GIT_DESC=$(git log -1 --format=%cd.%h --date=format:%Y-%m-%d_%H:%M:%S)" >> $GITHUB_ENV - - name: Setup Frontend Environment - uses: ./.github/actions/prepare-pnpm + - name: Prepare build environment + uses: ./.github/actions/prepare-build + with: + target: ${{ matrix.TARGET }} + gui: true + pnpm: true + pnpm-build-filter: '' + token: ${{ secrets.GITHUB_TOKEN }} - uses: Swatinem/rust-cache@v2 with: # The prefix cache key, this can be changed to start a new cache manually. # default: "v0-rust" prefix-key: "" - - - name: Install rust target - run: bash ./.github/workflows/install_rust.sh - - - name: Setup protoc - uses: arduino/setup-protoc@v3 - with: - # GitHub repo token to use to avoid rate limiter - repo-token: ${{ secrets.GITHUB_TOKEN }} + shared-key: "gui-registry" + cache-targets: "false" - name: copy correct DLLs - if: ${{ matrix.OS == 'windows-latest' }} + if: ${{ contains(matrix.GUI_TARGET, 'windows') }} run: | case $TARGET in x86_64*) ARCH_DIR=x86_64 ;; @@ -170,10 +122,9 @@ jobs: uses: tauri-apps/tauri-action@v0 with: projectPath: ./easytier-gui - # https://tauri.app/v1/guides/building/linux/#cross-compiling-tauri-applications-for-arm-based-devices - args: --verbose --target ${{ matrix.GUI_TARGET }} ${{ contains(matrix.TARGET, '-linux-') && contains(matrix.TARGET, 'aarch64') && '--bundles deb,rpm' || '' }} + args: --verbose --target ${{ matrix.GUI_TARGET }} - - name: Compress + - name: Collect artifact run: | mkdir -p ./artifacts/objects/ @@ -182,18 +133,16 @@ jobs: else TAG=$GITHUB_SHA fi + # copy gui bundle, gui is built without specific target - if [[ $OS =~ ^windows.*$ ]]; then + if [[ $GUI_TARGET =~ windows ]]; then mv ./target/$GUI_TARGET/release/bundle/nsis/*.exe ./artifacts/objects/ - elif [[ $OS =~ ^macos.*$ ]]; then + elif [[ $GUI_TARGET =~ darwin ]]; then mv ./target/$GUI_TARGET/release/bundle/dmg/*.dmg ./artifacts/objects/ - elif [[ $OS =~ ^ubuntu.*$ && ! $TARGET =~ ^mips.*$ ]]; then + elif [[ $GUI_TARGET =~ linux ]]; then mv ./target/$GUI_TARGET/release/bundle/deb/*.deb ./artifacts/objects/ mv ./target/$GUI_TARGET/release/bundle/rpm/*.rpm ./artifacts/objects/ - if [[ $GUI_TARGET =~ ^x86_64.*$ ]]; then - # currently only x86 appimage is supported - mv ./target/$GUI_TARGET/release/bundle/appimage/*.AppImage ./artifacts/objects/ - fi + mv ./target/$GUI_TARGET/release/bundle/appimage/*.AppImage ./artifacts/objects/ fi mv ./artifacts/objects/* ./artifacts/ diff --git a/.github/workflows/install_gui_dep.sh b/.github/workflows/install_gui_dep.sh deleted file mode 100644 index aa61b198..00000000 --- a/.github/workflows/install_gui_dep.sh +++ /dev/null @@ -1,11 +0,0 @@ -sudo apt update -sudo apt install -qq libwebkit2gtk-4.1-dev \ - build-essential \ - curl \ - wget \ - file \ - libgtk-3-dev \ - librsvg2-dev \ - libxdo-dev \ - libssl-dev \ - patchelf \ No newline at end of file diff --git a/.github/workflows/install_rust.sh b/.github/workflows/install_rust.sh deleted file mode 100644 index 0074e4ac..00000000 --- a/.github/workflows/install_rust.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash - -# env needed: -# - TARGET -# - GUI_TARGET -# - OS - -# dependencies are only needed on ubuntu as that's the only place where -# we make cross-compilation -if [[ $OS =~ ^ubuntu.*$ ]]; then - sudo apt-get update && sudo apt-get install -qq musl-tools libappindicator3-dev llvm clang - # https://github.com/cross-tools/musl-cross/releases - # if "musl" is a substring of TARGET, we assume that we are using musl - MUSL_TARGET=$TARGET - # if target is mips or mipsel, we should use soft-float version of musl - if [[ $TARGET =~ ^mips.*$ || $TARGET =~ ^mipsel.*$ ]]; then - MUSL_TARGET=${TARGET}sf - elif [[ $TARGET =~ ^riscv64gc-.*$ ]]; then - MUSL_TARGET=${TARGET/#riscv64gc-/riscv64-} - fi - if [[ $MUSL_TARGET =~ musl ]]; then - mkdir -p ./musl_gcc - wget --inet4-only -c https://github.com/cross-tools/musl-cross/releases/download/20250520/${MUSL_TARGET}.tar.xz -P ./musl_gcc/ - tar xf ./musl_gcc/${MUSL_TARGET}.tar.xz -C ./musl_gcc/ - sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/bin/*gcc /usr/bin/ - sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/include/ /usr/include/musl-cross - sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/${MUSL_TARGET}/sysroot/ ./musl_gcc/sysroot - sudo chmod -R a+rwx ./musl_gcc - fi -fi - -# see https://github.com/rust-lang/rustup/issues/3709 -rustup set auto-self-update disable -rustup install 1.93 -rustup default 1.93 - -# mips/mipsel cannot add target from rustup, need compile by ourselves -if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then - cd "$PWD/musl_gcc/${MUSL_TARGET}/lib/gcc/${MUSL_TARGET}/15.1.0" || exit 255 - # for panic-abort - cp libgcc_eh.a libunwind.a - - # for mimalloc - ar x libgcc.a _ctzsi2.o _clz.o _bswapsi2.o - ar rcs libctz.a _ctzsi2.o _clz.o _bswapsi2.o - - rustup toolchain install nightly-2026-02-02-x86_64-unknown-linux-gnu - rustup component add rust-src --toolchain nightly-2026-02-02-x86_64-unknown-linux-gnu - - # https://github.com/rust-lang/rust/issues/128808 - # remove it after Cargo or rustc fix this. - RUST_LIB_SRC=$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/ - if [[ -f $RUST_LIB_SRC/library/Cargo.lock && ! -f $RUST_LIB_SRC/Cargo.lock ]]; then - cp -f $RUST_LIB_SRC/library/Cargo.lock $RUST_LIB_SRC/Cargo.lock - fi -else - rustup target add $TARGET - if [[ $GUI_TARGET != '' ]]; then - rustup target add $GUI_TARGET - fi -fi diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml index 4276f404..e8caa484 100644 --- a/.github/workflows/mobile.yml +++ b/.github/workflows/mobile.yml @@ -35,20 +35,25 @@ jobs: concurrent_skipping: 'same_content_newer' skip_after_successful_duplicate: 'true' cancel_others: 'true' - paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", "tauri-plugin-vpnservice/**", ".github/workflows/mobile.yml", ".github/workflows/install_rust.sh"]' + paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", "tauri-plugin-vpnservice/**", ".github/workflows/mobile.yml", ".github/actions/**"]' build-mobile: strategy: fail-fast: true matrix: include: - - TARGET: android - OS: ubuntu-22.04 - ARTIFACT_NAME: android - runs-on: ${{ matrix.OS }} + - TARGET: aarch64-linux-android + ARCH: aarch64 + - TARGET: armv7-linux-androideabi + ARCH: armv7 + - TARGET: i686-linux-android + ARCH: i686 + - TARGET: x86_64-linux-android + ARCH: x86_64 + runs-on: ubuntu-latest env: NAME: easytier TARGET: ${{ matrix.TARGET }} - OS: ${{ matrix.OS }} + ARCH: ${{ matrix.ARCH }} OSS_BUCKET: ${{ secrets.ALIYUN_OSS_BUCKET }} needs: pre_job if: needs.pre_job.outputs.should_skip != 'true' @@ -67,47 +72,41 @@ jobs: - name: Setup Android SDK uses: android-actions/setup-android@v3 with: - cmdline-tools-version: 11076708 - packages: 'build-tools;34.0.0 ndk;26.0.10792818 tools platform-tools platforms;android-34 ' + cmdline-tools-version: 12.0 + packages: 'build-tools;34.0.0 ndk;26.0.10792818 platform-tools platforms;android-34 ' - name: Setup Android Environment run: | echo "$ANDROID_HOME/platform-tools" >> $GITHUB_PATH echo "$ANDROID_HOME/ndk/26.0.10792818/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH - echo "NDK_HOME=$ANDROID_HOME/ndk/26.0.10792818/" > $GITHUB_ENV + echo "NDK_HOME=$ANDROID_HOME/ndk/26.0.10792818/" >> $GITHUB_ENV - - name: Setup Frontend Environment - uses: ./.github/actions/prepare-pnpm + - name: Prepare build environment + uses: ./.github/actions/prepare-build + with: + target: ${{ matrix.TARGET }} + gui: false + pnpm: true + pnpm-build-filter: '' + token: ${{ secrets.GITHUB_TOKEN }} - uses: Swatinem/rust-cache@v2 with: # The prefix cache key, this can be changed to start a new cache manually. # default: "v0-rust" prefix-key: "" + shared-key: "gui-registry" + cache-targets: "false" - - name: Install rust target - run: | - bash ./.github/workflows/install_rust.sh - rustup target add aarch64-linux-android - rustup target add armv7-linux-androideabi - rustup target add i686-linux-android - rustup target add x86_64-linux-android - - - name: Setup protoc - uses: arduino/setup-protoc@v3 - with: - # GitHub repo token to use to avoid rate limiter - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Build Android + - name: Build run: | cd easytier-gui - pnpm tauri android build + pnpm tauri android build --apk --target "$ARCH" --split-per-abi - - name: Compress + - name: Collect artifact run: | mkdir -p ./artifacts/objects/ - mv easytier-gui/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk ./artifacts/objects/ + mv easytier-gui/src-tauri/gen/android/app/build/outputs/apk/*/release/*.apk ./artifacts/objects/ if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then TAG=$GITHUB_REF_NAME @@ -115,13 +114,13 @@ jobs: TAG=$GITHUB_SHA fi - mv ./artifacts/objects/* ./artifacts + mv ./artifacts/objects/* ./artifacts/ rm -rf ./artifacts/objects/ - name: Archive artifact uses: actions/upload-artifact@v5 with: - name: easytier-gui-${{ matrix.ARTIFACT_NAME }} + name: easytier-mobile-android-${{ matrix.ARCH }} path: | ./artifacts/* diff --git a/.github/workflows/ohos.yml b/.github/workflows/ohos.yml index 39371112..6c4d2951 100644 --- a/.github/workflows/ohos.yml +++ b/.github/workflows/ohos.yml @@ -29,12 +29,21 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - name: fmt check + + - name: Prepare build environment + uses: ./.github/actions/prepare-build + with: + gui: false + pnpm: false + + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: rustfmt + + - name: Check formatting working-directory: ./easytier-contrib/easytier-ohrs - run: | - bash ../../.github/workflows/install_rust.sh - rustup component add rustfmt - cargo fmt --all -- --check + run: cargo fmt --all -- --check + pre_job: # continue-on-error: true # Uncomment once integration is finished runs-on: ubuntu-latest @@ -51,7 +60,8 @@ jobs: concurrent_skipping: "same_content_newer" skip_after_successful_duplicate: "true" cancel_others: "true" - paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-contrib/easytier-ohrs/**", ".github/workflows/ohos.yml", ".github/workflows/install_rust.sh"]' + paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-contrib/easytier-ohrs/**", ".github/workflows/ohos.yml", ".github/actions/**"]' + build-ohos: runs-on: ubuntu-latest needs: pre_job @@ -63,13 +73,12 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y \ + sudo apt-get install -qq \ build-essential \ wget \ unzip \ git \ pkg-config curl libgl1-mesa-dev expect - sudo apt-get clean - name: Resolve easytier version run: | @@ -141,6 +150,15 @@ jobs: run: | echo "TARGET_ARCH=aarch64-linux-ohos" >> $GITHUB_ENV + rustup install stable + rustup default stable + + rustup target add aarch64-unknown-linux-ohos + + - uses: taiki-e/install-action@v2 + with: + tool: ohrs + - name: Create clang wrapper script run: | sudo mkdir -p $OHOS_NDK_HOME/native/llvm @@ -159,11 +177,7 @@ jobs: run: | sudo apt-get install -y llvm clang lldb lld sudo apt-get install -y protobuf-compiler - bash ../../.github/workflows/install_rust.sh source env.sh - cargo install ohrs - rustup target add aarch64-unknown-linux-ohos - cargo update easytier ohrs doctor ohrs build --release --arch aarch ohrs artifact diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5f624d4f..df1c490a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,7 @@ jobs: # All of these options are optional, so you can remove them if you are happy with the defaults concurrent_skipping: 'never' skip_after_successful_duplicate: 'true' - paths: '["Cargo.toml", "Cargo.lock", "easytier/**", ".github/workflows/test.yml", ".github/workflows/install_gui_dep.sh", ".github/workflows/install_rust.sh"]' + paths: '["Cargo.toml", "Cargo.lock", "easytier/**", ".github/workflows/test.yml", ".github/actions/**"]' check: name: Run linters & check @@ -48,15 +48,12 @@ jobs: uses: ./.github/actions/prepare-build with: gui: true - web: true + pnpm: true token: ${{ secrets.GITHUB_TOKEN }} - - uses: Swatinem/rust-cache@v2 - - - name: Install rustfmt and clippy - run: | - rustup component add rustfmt - rustup component add clippy + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: rustfmt,clippy - uses: taiki-e/install-action@cargo-hack @@ -89,7 +86,7 @@ jobs: uses: ./.github/actions/prepare-build with: gui: true - web: true + pnpm: true token: ${{ secrets.GITHUB_TOKEN }} - uses: Swatinem/rust-cache@v2 diff --git a/Cargo.lock b/Cargo.lock index a72d6dd0..37e59923 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5118,13 +5118,13 @@ dependencies = [ [[package]] name = "network-interface" -version = "2.0.0" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433419f898328beca4f2c6c73a1b52540658d92b0a99f0269330457e0fd998d5" +checksum = "4ddcb8865ad3d9950f22f42ffa0ef0aecbfbf191867b3122413602b0a360b2a6" dependencies = [ "cc", "libc", - "thiserror 1.0.63", + "thiserror 2.0.11", "winapi", ] diff --git a/easytier-gui/src-tauri/Cargo.toml b/easytier-gui/src-tauri/Cargo.toml index f49aa3a2..3dfb9498 100644 --- a/easytier-gui/src-tauri/Cargo.toml +++ b/easytier-gui/src-tauri/Cargo.toml @@ -11,15 +11,6 @@ edition.workspace = true name = "app_lib" crate-type = ["staticlib", "cdylib", "rlib"] -[build-dependencies] -tauri-build = { version = "2.0.0-rc", features = [] } - -# enable thunk-rs when compiling for x86_64 or i686 windows -[target.x86_64-pc-windows-msvc.build-dependencies] -thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = ["win7"] } - -[target.i686-pc-windows-msvc.build-dependencies] -thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = ["win7"] } [dependencies] # wry 0.47 may crash on android, see https://github.com/EasyTier/EasyTier/issues/527 @@ -66,6 +57,14 @@ libc = "0.2" [target.'cfg(target_os = "macos")'.dependencies] security-framework-sys = "2.9.0" + +[build-dependencies] +tauri-build = { version = "2.0.0-rc", features = [] } +thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ + "win7", +] } + + [features] # This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!! custom-protocol = ["tauri/custom-protocol"] diff --git a/easytier-gui/src-tauri/build.rs b/easytier-gui/src-tauri/build.rs index 2fda40fe..ab290968 100644 --- a/easytier-gui/src-tauri/build.rs +++ b/easytier-gui/src-tauri/build.rs @@ -1,12 +1,12 @@ -fn main() { - // enable thunk-rs when target os is windows and arch is x86_64 or i686 - #[cfg(target_os = "windows")] - if !std::env::var("TARGET") - .unwrap_or_default() - .contains("aarch64") - { - thunk::thunk(); - } - - tauri_build::build(); -} +use std::env; + +fn main() { + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); + // enable thunk-rs when target os is windows and arch is x86_64 or i686 + if target_os == "windows" && (target_arch == "x86" || target_arch == "x86_64") { + thunk::thunk(); + } + + tauri_build::build(); +} diff --git a/easytier-web/Cargo.toml b/easytier-web/Cargo.toml index 96883b54..b681dc5b 100644 --- a/easytier-web/Cargo.toml +++ b/easytier-web/Cargo.toml @@ -69,13 +69,11 @@ subtle = "2.6" mimalloc = { version = "*" } +[build-dependencies] +thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ + "win7", +] } + [features] default = [] embed = ["dep:axum-embed"] - -# enable thunk-rs when compiling for x86_64 or i686 windows -[target.x86_64-pc-windows-msvc.build-dependencies] -thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = ["win7"] } - -[target.i686-pc-windows-msvc.build-dependencies] -thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = ["win7"] } diff --git a/easytier-web/build.rs b/easytier-web/build.rs index 3de4b90a..9772f9cd 100644 --- a/easytier-web/build.rs +++ b/easytier-web/build.rs @@ -1,10 +1,10 @@ +use std::env; + fn main() { + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); // enable thunk-rs when target os is windows and arch is x86_64 or i686 - #[cfg(target_os = "windows")] - if !std::env::var("TARGET") - .unwrap_or_default() - .contains("aarch64") - { + if target_os == "windows" && (target_arch == "x86" || target_arch == "x86_64") { thunk::thunk(); } } diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 4d254fbd..972da260 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -324,22 +324,14 @@ easytier-rpc-build = { path = "../easytier-rpc-build", features = [ "internal-namespace", ] } prost-reflect-build = { version = "0.14.0" } +thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ + "win7", +] } [target.'cfg(windows)'.build-dependencies] reqwest = { version = "0.12.12", features = ["blocking"] } zip = "4.0.0" -# enable thunk-rs when compiling for x86_64 or i686 windows -[target.x86_64-pc-windows-msvc.build-dependencies] -thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ - "win7", -] } - -[target.i686-pc-windows-msvc.build-dependencies] -thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ - "win7", -] } - [dev-dependencies] serial_test = "3.0.0" diff --git a/easytier/build.rs b/easytier/build.rs index 5f6a74d8..0cc372df 100644 --- a/easytier/build.rs +++ b/easytier/build.rs @@ -143,12 +143,10 @@ fn main() -> Result<(), Box> { } } + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); // enable thunk-rs when target os is windows and arch is x86_64 or i686 - #[cfg(target_os = "windows")] - if !std::env::var("TARGET") - .unwrap_or_default() - .contains("aarch64") - { + if target_os == "windows" && (target_arch == "x86" || target_arch == "x86_64") { thunk::thunk(); } From 869e1b89f52a4980a5a24157bbded10ef6abd8bb Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:16:30 +0200 Subject: [PATCH 14/24] fix: remove log (file) when level is explicitly set to OFF (#2083) * fix level filter for OFF * remove unwrap of file appender creation --- easytier/src/common/log.rs | 83 +++++++++---------- .../common/tracing_rolling_appender/base.rs | 7 +- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/easytier/src/common/log.rs b/easytier/src/common/log.rs index 19eccc03..e546b5a2 100644 --- a/easytier/src/common/log.rs +++ b/easytier/src/common/log.rs @@ -1,5 +1,3 @@ -use std::io::IsTerminal as _; - use crate::common::config::{FileLoggerConfig, LoggingConfigLoader}; use crate::common::get_logger_timer_rfc3339; use crate::common::tracing_rolling_appender::{FileAppenderWrapper, RollingFileAppenderBase}; @@ -7,7 +5,7 @@ use crate::rpc_service::logger::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER}; use anyhow::Context; use cfg_if::cfg_if; use paste::paste; -use regex::Regex; +use std::io::IsTerminal; use tracing::level_filters::LevelFilter; use tracing::{Level, Metadata}; use tracing_subscriber::Registry; @@ -49,18 +47,16 @@ macro_rules! __log__ { __log__!(const LOG_TARGET = "CORE"); -fn parse_env_filter(default_level: LevelFilter) -> Result { - let mut filter = EnvFilter::builder() - .with_default_directive(default_level.into()) +fn parse_env_filter(default_level: Option) -> Result { + let directive = match default_level { + Some(level) => level.into(), + None => format!("{LOG_TARGET}=info").parse()?, + }; + + EnvFilter::builder() + .with_default_directive(directive) .from_env() - .with_context(|| "failed to create env filter")?; - - let pattern = Regex::new(&format!(r"(^|,){}\s*=", regex::escape(LOG_TARGET)))?; - if !pattern.is_match(&filter.to_string()) { - filter = filter.add_directive(format!("{LOG_TARGET}=info").parse()?); - } - - Ok(filter) + .with_context(|| "failed to create env filter") } fn is_log(meta: &Metadata) -> bool { @@ -96,8 +92,7 @@ pub fn init( config .get_console_logger_config() .level - .map(|s| s.parse().unwrap()) - .unwrap_or(LevelFilter::OFF), + .map(|s| s.parse().unwrap()), )?; layers.extend(console_layers); @@ -118,9 +113,9 @@ pub fn init( type BoxLayer = Box + Send + Sync>; -fn console_layers(default_level: LevelFilter) -> anyhow::Result> { +fn console_layers(default_level: Option) -> anyhow::Result> { let mut layers = Vec::new(); - if default_level == LevelFilter::OFF { + if matches!(default_level, Some(LevelFilter::OFF)) { return Ok(layers); } @@ -173,34 +168,12 @@ fn file_layers( ) -> anyhow::Result<(Vec, Option)> { let mut layers = Vec::new(); - let level = config - .level - .map(|s| s.parse().unwrap()) - .unwrap_or(LevelFilter::OFF); + let level = config.level.map(|s| s.parse().unwrap()); - if level == LevelFilter::OFF && !reload { + if matches!(level, Some(LevelFilter::OFF)) && !reload { return Ok((layers, None)); } - let path = { - let dir = config.dir.as_deref().unwrap_or("."); - let file = config.file.as_deref().unwrap_or("easytier.log"); - let path = std::path::Path::new(dir).join(file); - path.to_string_lossy().into_owned() - }; - - let builder = RollingFileAppenderBase::builder(); - let file_appender = builder - .filename(path) - .condition_daily() - .max_filecount(config.count.unwrap_or(10)) - .condition_max_file_size(config.size_mb.unwrap_or(100) * 1024 * 1024) - .build() - .unwrap(); - - // Create a simple wrapper that implements MakeWriter - let wrapper = FileAppenderWrapper::new(file_appender); - let (file_filter, file_filter_reloader) = tracing_subscriber::reload::Layer::<_, Registry>::new(parse_env_filter(level)?); @@ -211,6 +184,26 @@ fn file_layers( .with_timer(get_logger_timer_rfc3339()) }; + let wrapper = { + let path = { + let dir = config.dir.as_deref().unwrap_or("."); + let file = config.file.as_deref().unwrap_or("easytier.log"); + let path = std::path::Path::new(dir).join(file); + path.to_string_lossy().into_owned() + }; + + let builder = RollingFileAppenderBase::builder(); + let file_appender = builder + .filename(path) + .condition_daily() + .max_filecount(config.count.unwrap_or(10)) + .condition_max_file_size(config.size_mb.unwrap_or(100) * 1024 * 1024) + .build() + .with_context(|| "failed to initialize rolling file appender")?; + + FileAppenderWrapper::new(file_appender) + }; + layers.push( vec![ tracing_layer!(layer(wrapper.clone())), @@ -228,7 +221,9 @@ fn file_layers( // 初始化全局状态 let _ = LOGGER_LEVEL_SENDER.set(std::sync::Mutex::new(tx.clone())); - let _ = CURRENT_LOG_LEVEL.set(std::sync::Mutex::new(level.to_string())); + if let Some(level) = level { + let _ = CURRENT_LOG_LEVEL.set(std::sync::Mutex::new(level.to_string())); + } std::thread::spawn(move || { while let Ok(lf) = rx.recv() { @@ -279,7 +274,7 @@ mod tests { #[ctor::ctor] fn init() { let _ = Registry::default() - .with(console_layers(LevelFilter::DEBUG).unwrap()) + .with(console_layers(Some(LevelFilter::DEBUG)).unwrap()) .try_init(); } diff --git a/easytier/src/common/tracing_rolling_appender/base.rs b/easytier/src/common/tracing_rolling_appender/base.rs index ababc18f..2e4d8c50 100644 --- a/easytier/src/common/tracing_rolling_appender/base.rs +++ b/easytier/src/common/tracing_rolling_appender/base.rs @@ -1,4 +1,5 @@ use super::*; +use anyhow::anyhow; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct RollingConditionBase { @@ -135,9 +136,11 @@ impl RollingFileAppenderBaseBuilder { /// Builds a RollingFileAppenderBase instance from the current settings. /// /// Returns an error if the filename is empty. - pub fn build(self) -> Result { + pub fn build(self) -> anyhow::Result { if self.filename.is_empty() { - return Err("A filename is required to be set and can not be blank"); + return Err(anyhow!( + "A filename is required to be set and can not be blank" + )); } Ok(RollingFileAppenderBase { condition: self.condition, From 6f3e7086799d367e00134877a0697d6b95a6c381 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:16:58 +0200 Subject: [PATCH 15/24] tunnel(bind): gather all bind logic to a single function (#2070) * extract a Bindable trait for binding TcpSocket, TcpListener, and UdpSocket --- Cargo.lock | 5647 +---------------------------- easytier/Cargo.toml | 1 + easytier/src/gateway/socks5.rs | 67 +- easytier/src/gateway/udp_proxy.rs | 30 +- easytier/src/tunnel/common.rs | 181 +- easytier/src/tunnel/quic.rs | 50 +- easytier/src/tunnel/tcp.rs | 41 +- easytier/src/tunnel/udp.rs | 55 +- easytier/src/tunnel/websocket.rs | 46 +- easytier/src/tunnel/wireguard.rs | 98 +- 10 files changed, 370 insertions(+), 5846 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37e59923..07268683 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,18 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "ab_glyph_rasterizer" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +version = 4 [[package]] name = "adler2" @@ -55,29 +43,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.15", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -87,27 +52,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "allocator-api2" version = "0.2.18" @@ -120,24 +64,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" -[[package]] -name = "android_log-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" - -[[package]] -name = "android_logger" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f" -dependencies = [ - "android_log-sys", - "env_logger", - "log", - "once_cell", -] - [[package]] name = "android_system_properties" version = "0.1.5" @@ -202,15 +128,6 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - [[package]] name = "arbitrary" version = "1.4.1" @@ -220,152 +137,18 @@ dependencies = [ "derive_arbitrary", ] -[[package]] -name = "arboard" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" -dependencies = [ - "clipboard-win", - "core-graphics 0.23.2", - "image 0.25.2", - "log", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", - "parking_lot", - "windows-sys 0.48.0", - "wl-clipboard-rs", - "x11rb", -] - [[package]] name = "arc-swap" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" -[[package]] -name = "argon2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" -dependencies = [ - "base64ct", - "blake2", - "cpufeatures", - "password-hash", -] - [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-compression" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" -dependencies = [ - "brotli 7.0.0", - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "zstd", - "zstd-safe", -] - -[[package]] -name = "async-executor" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-io" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 0.38.34", - "slab", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-process" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a07789659a4d385b79b18b9127fc27e1a59e1e89117c78c5ea3b806f016374" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.38.34", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "async-recursion" version = "1.1.1" @@ -387,24 +170,6 @@ dependencies = [ "ringbuf", ] -[[package]] -name = "async-signal" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.34", - "signal-hook-registry", - "slab", - "windows-sys 0.59.0", -] - [[package]] name = "async-stream" version = "0.3.5" @@ -427,12 +192,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.89" @@ -444,38 +203,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "atk" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - [[package]] name = "atomic-shim" version = "0.2.0" @@ -521,67 +248,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", - "axum-core 0.4.5", - "axum-macros 0.4.2", + "axum-core", "bytes", "futures-util", "http", "http-body", "http-body-util", - "hyper", - "hyper-util", "itoa", - "matchit 0.7.3", + "matchit", "memchr", "mime", "percent-encoding", "pin-project-lite", "rustversion", "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", "sync_wrapper", - "tokio", "tower 0.5.2", "tower-layer", "tower-service", - "tracing", -] - -[[package]] -name = "axum" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" -dependencies = [ - "axum-core 0.5.2", - "axum-macros 0.5.0", - "bytes", - "form_urlencoded", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit 0.8.4", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower 0.5.2", - "tower-layer", - "tower-service", - "tracing", ] [[package]] @@ -602,133 +286,8 @@ dependencies = [ "sync_wrapper", "tower-layer", "tower-service", - "tracing", ] -[[package]] -name = "axum-core" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-embed" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077959a7f8cf438676af90b483304528eb7e16eadadb7f44e9ada4f9dceb9e62" -dependencies = [ - "axum-core 0.4.5", - "chrono", - "http", - "mime_guess", - "rust-embed", - "tower-service", -] - -[[package]] -name = "axum-extra" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d" -dependencies = [ - "axum 0.8.4", - "axum-core 0.5.2", - "bytes", - "form_urlencoded", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "serde", - "serde_html_form", - "serde_path_to_error", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-login" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5260ed0ecc8ace8e7e61a7406672faba598c8a86b8f4742fcdde0ddc979a318f" -dependencies = [ - "async-trait", - "axum 0.7.7", - "form_urlencoded", - "serde", - "subtle", - "thiserror 1.0.63", - "tower-cookies", - "tower-layer", - "tower-service", - "tower-sessions", - "tracing", - "urlencoding", -] - -[[package]] -name = "axum-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "axum-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "axum-messages" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40e85c86a8bd84f54833bca296a0204bd865958ade62bacadeae92dda34cfb8a" -dependencies = [ - "async-trait", - "axum-core 0.4.5", - "http", - "parking_lot", - "serde", - "serde_json", - "tower 0.4.13", - "tower-sessions-core", - "tracing", -] - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - [[package]] name = "base62" version = "2.0.2" @@ -753,26 +312,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bigdecimal" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" -dependencies = [ - "autocfg", - "libm", - "num-bigint", - "num-integer", - "num-traits", - "serde", -] - [[package]] name = "bindgen" version = "0.72.1" @@ -802,21 +341,6 @@ name = "bitflags" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" -dependencies = [ - "serde", -] - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] [[package]] name = "blake2" @@ -837,34 +361,28 @@ dependencies = [ ] [[package]] -name = "block2" -version = "0.5.1" +name = "bon" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" dependencies = [ - "objc2 0.5.2", + "bon-macros", + "rustversion", ] [[package]] -name = "block2" -version = "0.6.1" +name = "bon-macros" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" +checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" dependencies = [ - "objc2 0.6.1", -] - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", + "darling", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", ] [[package]] @@ -892,71 +410,6 @@ dependencies = [ "x25519-dalek", ] -[[package]] -name = "borsh" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" -dependencies = [ - "borsh-derive", - "cfg_aliases 0.2.1", -] - -[[package]] -name = "borsh-derive" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b668d39970baad5356d7c83a86fee3a539e6f93bf6764c97368243e17a0487" -dependencies = [ - "once_cell", - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "brotli" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 4.0.1", -] - -[[package]] -name = "brotli" -version = "8.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 5.0.0", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "brotli-decompressor" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bstr" version = "1.10.0" @@ -973,28 +426,6 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "bytecodec" version = "0.4.15" @@ -1023,20 +454,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - [[package]] name = "bytes" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" -dependencies = [ - "serde", -] [[package]] name = "bzip2" @@ -1077,73 +499,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.8.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.63", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "camino" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 2.0.11", -] - -[[package]] -name = "cargo_toml" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257" -dependencies = [ - "serde", - "toml 0.8.19", -] - [[package]] name = "cc" version = "1.2.10" @@ -1170,39 +525,12 @@ dependencies = [ "nom", ] -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.1" @@ -1276,7 +604,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading 0.8.5", + "libloading", ] [[package]] @@ -1341,15 +669,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" -[[package]] -name = "clipboard-win" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" -dependencies = [ - "error-code", -] - [[package]] name = "codepage" version = "0.1.2" @@ -1359,12 +678,6 @@ dependencies = [ "encoding_rs", ] -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" version = "1.0.2" @@ -1381,15 +694,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "console-api" version = "0.8.1" @@ -1429,33 +733,12 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - [[package]] name = "constant_time_eq" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -dependencies = [ - "custom_derive", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "convert_case" version = "0.10.0" @@ -1465,22 +748,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "base64 0.22.1", - "hmac", - "percent-encoding", - "rand 0.8.5", - "sha2", - "subtle", - "time", - "version_check", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -1507,54 +774,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.10.0", - "libc", -] - [[package]] name = "cpufeatures" version = "0.2.13" @@ -1650,18 +869,6 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -1673,43 +880,22 @@ dependencies = [ "typenum", ] -[[package]] -name = "cssparser" -version = "0.29.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.87", -] - [[package]] name = "ctor" -version = "0.2.8" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" dependencies = [ - "quote", - "syn 2.0.87", + "ctor-proc-macro", + "dtor", ] +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + [[package]] name = "ctr" version = "0.9.2" @@ -1728,7 +914,6 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest", "fiat-crypto", "rustc_version", "subtle", @@ -1746,12 +931,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" - [[package]] name = "darling" version = "0.20.10" @@ -1876,17 +1055,6 @@ dependencies = [ "thiserror 1.0.63", ] -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - [[package]] name = "deranged" version = "0.4.0" @@ -1894,7 +1062,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", - "serde", ] [[package]] @@ -1908,17 +1075,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive-new" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "derive_arbitrary" version = "1.4.1" @@ -1961,19 +1117,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.87", -] - [[package]] name = "derive_more" version = "2.1.1" @@ -1989,7 +1132,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case 0.10.0", + "convert_case", "proc-macro2", "quote", "rustc_version", @@ -2004,7 +1147,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", "subtle", ] @@ -2050,22 +1192,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dispatch2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags 2.8.0", - "objc2 0.6.1", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -2078,81 +1204,19 @@ dependencies = [ ] [[package]] -name = "dlopen2" -version = "0.7.0" +name = "dtor" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", + "dtor-proc-macro", ] [[package]] -name = "dlopen2_derive" -version = "0.4.0" +name = "dtor-proc-macro" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "downcast" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "dpi" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" -dependencies = [ - "serde", -] - -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" [[package]] name = "easytier" @@ -2170,12 +1234,13 @@ dependencies = [ "auto_impl", "base64 0.22.1", "bitflags 2.8.0", + "bon", "boringtun-easytier", "bytecodec", "byteorder", "bytes", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "chrono", "cidr", "clap", @@ -2183,19 +1248,20 @@ dependencies = [ "clap_complete_nushell", "console-subscriber", "crossbeam", + "ctor", "dashmap", "dbus", "defguard_wireguard_rs", "derivative", "derive_builder", - "derive_more 2.1.1", + "derive_more", "easytier-rpc-build", "encoding", - "flume 0.12.0", + "flume", "forwarded-header-value", "futures", "futures-util", - "gethostname 0.5.0", + "gethostname", "git-version", "globwalk", "hashbrown 0.15.3", @@ -2208,7 +1274,7 @@ dependencies = [ "http_req", "humansize", "humantime-serde", - "idna 1.0.3", + "idna", "indoc", "itertools 0.14.0", "kcp-sys", @@ -2260,7 +1326,7 @@ dependencies = [ "smoltcp", "snow", "socket2 0.5.10", - "strum 0.27.2", + "strum", "stun_codec", "sys-locale", "tabled", @@ -2302,64 +1368,6 @@ dependencies = [ "zstd", ] -[[package]] -name = "easytier-android-jni" -version = "0.1.0" -dependencies = [ - "android_logger", - "easytier", - "jni", - "log", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "easytier-ffi" -version = "0.1.0" -dependencies = [ - "dashmap", - "easytier", - "once_cell", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "easytier-gui" -version = "2.6.0" -dependencies = [ - "anyhow", - "async-trait", - "chrono", - "dashmap", - "dunce", - "easytier", - "gethostname 1.0.2", - "libc", - "once_cell", - "security-framework-sys", - "serde", - "serde_json", - "tauri", - "tauri-build", - "tauri-plugin-clipboard-manager", - "tauri-plugin-os", - "tauri-plugin-positioner", - "tauri-plugin-process", - "tauri-plugin-shell", - "tauri-plugin-single-instance", - "tauri-plugin-vpnservice", - "thunk-rs", - "tokio", - "url", - "uuid", - "winapi", - "windows 0.52.0", -] - [[package]] name = "easytier-rpc-build" version = "0.1.0" @@ -2368,177 +1376,11 @@ dependencies = [ "prost-build", ] -[[package]] -name = "easytier-uptime" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "axum 0.8.4", - "axum-extra", - "chrono", - "clap", - "dashmap", - "easytier", - "futures", - "jsonwebtoken", - "mimalloc", - "mockall", - "once_cell", - "parking_lot", - "reqwest", - "sea-orm", - "sea-orm-migration", - "serde", - "serde_json", - "serde_yaml", - "sqlx", - "tempfile", - "thiserror 1.0.63", - "tokio", - "tokio-test", - "tokio-util", - "toml 0.8.19", - "tower 0.5.2", - "tower-http", - "tracing", - "tracing-subscriber", - "uuid", - "validator", -] - -[[package]] -name = "easytier-web" -version = "2.6.0" -dependencies = [ - "anyhow", - "async-trait", - "axum 0.7.7", - "axum-embed", - "axum-login", - "axum-messages", - "base64 0.22.1", - "chrono", - "clap", - "dashmap", - "easytier", - "image 0.24.9", - "imageproc", - "maxminddb", - "mimalloc", - "once_cell", - "openidconnect", - "password-auth", - "rand 0.8.5", - "reqwest", - "rust-embed", - "rust-i18n", - "rusttype", - "sea-orm", - "sea-orm-migration", - "serde", - "serde_json", - "sqlx", - "subtle", - "sys-locale", - "thiserror 1.0.63", - "thunk-rs", - "tokio", - "tower-http", - "tower-sessions", - "tower-sessions-sqlx-store", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" -dependencies = [ - "curve25519-dalek", - "ed25519", - "serde", - "sha2", - "subtle", - "zeroize", -] - [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -dependencies = [ - "serde", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "hkdf", - "pem-rfc7468", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "embed-resource" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6d81016d6c977deefb2ef8d8290da019e27cc26167e102185da528e6c0ab38" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml 0.9.2", - "vswhom", - "winreg 0.55.0", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" [[package]] name = "encoding" @@ -2624,12 +1466,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - [[package]] name = "endian-type" version = "0.1.2" @@ -2648,43 +1484,12 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "enumflags2" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "env_home" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "log", - "regex", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -2711,23 +1516,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "error-code" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" - -[[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - [[package]] name = "etherparse" version = "0.13.0" @@ -2737,27 +1525,6 @@ dependencies = [ "arrayvec", ] -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" -dependencies = [ - "event-listener", - "pin-project-lite", -] - [[package]] name = "fastbloom" version = "0.9.0" @@ -2766,7 +1533,7 @@ checksum = "27cea6e7f512d43b098939ff4d5a5d6fe3db07971e1d05176fe26c642d33f5b8" dependencies = [ "getrandom 0.3.2", "rand 0.9.1", - "siphasher 1.0.1", + "siphasher", "wide", ] @@ -2779,41 +1546,12 @@ dependencies = [ "getrandom 0.2.15", ] -[[package]] -name = "fdeflate" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "fiat-crypto" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - [[package]] name = "fixedbitset" version = "0.4.2" @@ -2834,18 +1572,7 @@ checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "libz-rs-sys", - "miniz_oxide 0.8.8", -] - -[[package]] -name = "flume" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" -dependencies = [ - "futures-core", - "futures-sink", - "spin", + "miniz_oxide", ] [[package]] @@ -2878,28 +1605,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[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 0.3.1", -] - -[[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.87", + "foreign-types-shared", ] [[package]] @@ -2908,12 +1614,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2933,28 +1633,6 @@ dependencies = [ "thiserror 1.0.63", ] -[[package]] -name = "fragile" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures" version = "0.3.30" @@ -2997,36 +1675,12 @@ dependencies = [ "futures-util", ] -[[package]] -name = "futures-intrusive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot", -] - [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-lite" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "futures-macro" version = "0.3.31" @@ -3074,114 +1728,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2ea8a4909d530f79921290389cbd7c34cb9d623bfe970eaae65ca5f9cd9cce" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - [[package]] name = "generator" version = "0.8.4" @@ -3203,17 +1749,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", -] - -[[package]] -name = "gethostname" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" -dependencies = [ - "libc", - "windows-targets 0.48.5", ] [[package]] @@ -3226,27 +1761,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "gethostname" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" -dependencies = [ - "rustix 1.0.7", - "windows-targets 0.52.6", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -3284,38 +1798,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.63", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - [[package]] name = "git-version" version = "0.3.9" @@ -3336,53 +1818,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.8.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.63", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - [[package]] name = "glob" version = "0.3.1" @@ -3413,80 +1848,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "gtk" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "h2" version = "0.4.7" @@ -3520,19 +1881,12 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.11", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -3545,15 +1899,6 @@ dependencies = [ "foldhash", ] -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "hdrhistogram" version = "7.5.4" @@ -3595,12 +1940,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - [[package]] name = "hex" version = "0.4.3" @@ -3639,7 +1978,7 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 1.0.3", + "idna", "ipnet", "once_cell", "rand 0.9.1", @@ -3698,15 +2037,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - [[package]] name = "hmac" version = "0.12.1" @@ -3725,18 +2055,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "html5ever" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" -dependencies = [ - "log", - "mac", - "markup5ever", - "match_token", -] - [[package]] name = "http" version = "1.1.0" @@ -3860,7 +2178,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 0.26.3", ] [[package]] @@ -3934,16 +2251,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ico" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" -dependencies = [ - "byteorder", - "png", -] - [[package]] name = "icu_collections" version = "1.5.0" @@ -4068,16 +2375,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "1.0.3" @@ -4115,50 +2412,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-traits", - "png", -] - -[[package]] -name = "image" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" -dependencies = [ - "bytemuck", - "byteorder-lite", - "num-traits", - "png", - "tiff", -] - -[[package]] -name = "imageproc" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aee993351d466301a29655d628bfc6f5a35a0d062b6160ca0808f425805fd7" -dependencies = [ - "approx", - "conv", - "image 0.24.9", - "itertools 0.10.5", - "nalgebra", - "num", - "rand 0.7.3", - "rand_distr", - "rayon", - "rusttype", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -4167,7 +2420,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -4178,7 +2430,6 @@ checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.3", - "serde", ] [[package]] @@ -4190,26 +2441,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "infer" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" -dependencies = [ - "cfb", -] - -[[package]] -name = "inherent" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "inout" version = "0.1.3" @@ -4280,40 +2511,12 @@ dependencies = [ "serde", ] -[[package]] -name = "is-docker" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" -dependencies = [ - "once_cell", -] - -[[package]] -name = "is-wsl" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" -dependencies = [ - "is-docker", - "once_cell", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.11.0" @@ -4347,29 +2550,6 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - [[package]] name = "jni" version = "0.21.1" @@ -4401,12 +2581,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" - [[package]] name = "js-sys" version = "0.3.77" @@ -4417,43 +2591,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "json-patch" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" -dependencies = [ - "jsonptr", - "serde", - "serde_json", - "thiserror 1.0.63", -] - -[[package]] -name = "jsonptr" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "jsonwebtoken" -version = "9.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" -dependencies = [ - "base64 0.22.1", - "js-sys", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", -] - [[package]] name = "kcp-sys" version = "0.1.0" @@ -4476,61 +2613,11 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.8.0", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 2.7.1", - "selectors", -] - [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] [[package]] name = "libc" @@ -4548,16 +2635,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.5" @@ -4614,17 +2691,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libsqlite3-sys" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - [[package]] name = "libyml" version = "0.0.4" @@ -4666,7 +2732,6 @@ checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", - "serde", ] [[package]] @@ -4694,12 +2759,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - [[package]] name = "machine-uid" version = "0.5.3" @@ -4722,31 +2781,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "markup5ever" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" -dependencies = [ - "log", - "phf 0.11.2", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "matchers" version = "0.1.0" @@ -4756,56 +2790,12 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matchit" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - -[[package]] -name = "matrixmultiply" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" -dependencies = [ - "autocfg", - "rawpointer", -] - -[[package]] -name = "maxminddb" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6087e5d8ea14861bb7c7f573afbc7be3798d3ef0fae87ec4fd9a4de9a127c3c" -dependencies = [ - "ipnetwork", - "log", - "memchr", - "serde", -] - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - [[package]] name = "md5" version = "0.7.0" @@ -4842,32 +2832,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", - "simd-adler32", -] - [[package]] name = "miniz_oxide" version = "0.8.8" @@ -4883,39 +2853,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] -[[package]] -name = "mockall" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive", - "predicates", - "predicates-tree", -] - -[[package]] -name = "mockall_derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "moka" version = "0.12.10" @@ -4935,27 +2878,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "muda" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b89bf91c19bf036347f1ab85a81c560f08c0667c8601bece664d860a600988" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.11", - "windows-sys 0.59.0", -] - [[package]] name = "multimap" version = "0.10.1" @@ -4965,21 +2887,6 @@ dependencies = [ "serde", ] -[[package]] -name = "nalgebra" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb2d0de08694bed883320212c18ee3008576bfe8c306f4c3c4a58b4876998be" -dependencies = [ - "approx", - "matrixmultiply", - "num-complex", - "num-rational", - "num-traits", - "simba", - "typenum", -] - [[package]] name = "native-tls" version = "0.2.12" @@ -4997,36 +2904,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.8.0", - "jni-sys", - "log", - "ndk-sys", - "num_enum", - "raw-window-handle", - "thiserror 1.0.63", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.6.0+11769913" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] - [[package]] name = "netlink-packet-core" version = "0.7.0" @@ -5128,12 +3005,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nibble_vec" version = "0.1.0" @@ -5167,18 +3038,6 @@ dependencies = [ "memoffset", ] -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.8.0", - "cfg-if", - "cfg_aliases 0.1.1", - "libc", -] - [[package]] name = "nix" version = "0.29.0" @@ -5187,20 +3046,7 @@ checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.8.0", "cfg-if", - "cfg_aliases 0.2.1", - "libc", - "memoffset", -] - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.8.0", - "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", "memoffset", ] @@ -5211,12 +3057,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nom" version = "7.1.3" @@ -5252,92 +3092,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -5345,28 +3105,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.87", ] [[package]] @@ -5378,281 +3116,6 @@ dependencies = [ "libc", ] -[[package]] -name = "oauth2" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" -dependencies = [ - "base64 0.22.1", - "chrono", - "getrandom 0.2.15", - "http", - "rand 0.8.5", - "reqwest", - "serde", - "serde_json", - "serde_path_to_error", - "sha2", - "thiserror 1.0.63", - "url", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - -[[package]] -name = "objc2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" -dependencies = [ - "objc2-encode", - "objc2-exception-helper", -] - -[[package]] -name = "objc2-app-kit" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", - "objc2-core-data 0.2.2", - "objc2-core-image 0.2.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", -] - -[[package]] -name = "objc2-app-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" -dependencies = [ - "bitflags 2.8.0", - "block2 0.6.1", - "libc", - "objc2 0.6.1", - "objc2-cloud-kit", - "objc2-core-data 0.3.1", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image 0.3.1", - "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.1", -] - -[[package]] -name = "objc2-cloud-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" -dependencies = [ - "bitflags 2.8.0", - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-core-data" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-core-data" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" -dependencies = [ - "bitflags 2.8.0", - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" -dependencies = [ - "bitflags 2.8.0", - "dispatch2", - "objc2 0.6.1", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" -dependencies = [ - "bitflags 2.8.0", - "dispatch2", - "objc2 0.6.1", - "objc2-core-foundation", - "objc2-io-surface", -] - -[[package]] -name = "objc2-core-image" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-core-image" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" -dependencies = [ - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-exception-helper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" -dependencies = [ - "cc", -] - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "dispatch", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" -dependencies = [ - "bitflags 2.8.0", - "block2 0.6.1", - "libc", - "objc2 0.6.1", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" -dependencies = [ - "bitflags 2.8.0", - "objc2 0.6.1", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" -dependencies = [ - "bitflags 2.8.0", - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" -dependencies = [ - "bitflags 2.8.0", - "objc2 0.6.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-web-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" -dependencies = [ - "bitflags 2.8.0", - "block2 0.6.1", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -5669,48 +3132,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "open" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" -dependencies = [ - "is-wsl", - "libc", - "pathdiff", -] - -[[package]] -name = "openidconnect" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c6709ba2ea764bbed26bce1adf3c10517113ddea6f2d4196e4851757ef2b2" -dependencies = [ - "base64 0.21.7", - "chrono", - "dyn-clone", - "ed25519-dalek", - "hmac", - "http", - "itertools 0.10.5", - "log", - "oauth2", - "p256", - "p384", - "rand 0.8.5", - "rsa", - "serde", - "serde-value", - "serde_json", - "serde_path_to_error", - "serde_plain", - "serde_with", - "sha2", - "subtle", - "thiserror 1.0.63", - "url", -] - [[package]] name = "openssl" version = "0.10.66" @@ -5719,7 +3140,7 @@ checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.8.0", "cfg-if", - "foreign-types 0.3.2", + "foreign-types", "libc", "once_cell", "openssl-macros", @@ -5771,34 +3192,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ordered-float" -version = "3.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "ordered_hash_map" version = "0.5.0" @@ -5808,116 +3201,12 @@ dependencies = [ "hashbrown 0.15.3", ] -[[package]] -name = "os_info" -version = "3.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" -dependencies = [ - "log", - "serde", - "windows-sys 0.52.0", -] - -[[package]] -name = "os_pipe" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "ouroboros" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" -dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", -] - -[[package]] -name = "ouroboros_macro" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" -dependencies = [ - "heck 0.4.1", - "itertools 0.12.1", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.87", -] - [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "owned_ttf_parser" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e6affeb1632d6ff6a23d2cd40ffed138e82f1532571a26f527c8a284bb2fbb" -dependencies = [ - "ttf-parser", -] - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - [[package]] name = "papergrid" version = "0.12.0" @@ -5929,12 +3218,6 @@ dependencies = [ "unicode-width 0.1.11", ] -[[package]] -name = "parking" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" - [[package]] name = "parking_lot" version = "0.12.3" @@ -5958,41 +3241,12 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "password-auth" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2a4764cc1f8d961d802af27193c6f4f0124bd0e76e8393cf818e18880f0524" -dependencies = [ - "argon2", - "getrandom 0.2.15", - "password-hash", - "rand_core 0.6.4", -] - -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - [[package]] name = "pbkdf2" version = "0.12.2" @@ -6013,15 +3267,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -6050,140 +3295,6 @@ dependencies = [ "serde", ] -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher 0.3.11", -] - [[package]] name = "pin-project" version = "1.1.10" @@ -6216,38 +3327,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.30" @@ -6262,7 +3341,7 @@ checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", "indexmap 2.7.1", - "quick-xml 0.32.0", + "quick-xml", "serde", "time", ] @@ -6360,34 +3439,6 @@ dependencies = [ "pnet_sys", ] -[[package]] -name = "png" -version = "0.17.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide 0.7.4", -] - -[[package]] -name = "polling" -version = "3.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.34", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "poly1305" version = "0.8.0" @@ -6432,38 +3483,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "predicates" -version = "3.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" -dependencies = [ - "anstyle", - "predicates-core", -] - -[[package]] -name = "predicates-core" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" - -[[package]] -name = "predicates-tree" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" -dependencies = [ - "predicates-core", - "termtree", -] - [[package]] name = "prefix-trie" version = "0.7.0" @@ -6485,34 +3504,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -6546,56 +3537,15 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "version_check", - "yansi", -] - [[package]] name = "prost" version = "0.13.5" @@ -6613,7 +3563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.14.0", "log", "multimap", "once_cell", @@ -6633,7 +3583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.87", @@ -6727,26 +3677,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "quick-xml" version = "0.32.0" @@ -6756,15 +3686,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "quick-xml" -version = "0.37.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" -dependencies = [ - "memchr", -] - [[package]] name = "quinn" version = "0.11.8" @@ -6772,7 +3693,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -6848,12 +3769,6 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "radix_trie" version = "0.2.1" @@ -6864,20 +3779,6 @@ dependencies = [ "nibble_vec", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - [[package]] name = "rand" version = "0.8.5" @@ -6899,16 +3800,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -6929,15 +3820,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" @@ -6956,65 +3838,6 @@ dependencies = [ "getrandom 0.3.2", ] -[[package]] -name = "rand_distr" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" -dependencies = [ - "rand 0.7.3", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "rcgen" version = "0.12.1" @@ -7108,15 +3931,6 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - [[package]] name = "reqwest" version = "0.12.12" @@ -7145,10 +3959,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", "rustls-pemfile", - "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -7156,16 +3967,12 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls", - "tokio-util", "tower 0.5.2", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", - "webpki-roots 0.26.3", "windows-registry", ] @@ -7175,16 +3982,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7c8f7f733062b66dc1c63f9db168ac0b97a9210e247fa90fdc9ad08f51b302" -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - [[package]] name = "ring" version = "0.17.14" @@ -7208,77 +4005,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rmp" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - -[[package]] -name = "rsa" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", -] - [[package]] name = "rstest" version = "0.25.0" @@ -7299,7 +4025,7 @@ checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" dependencies = [ "cfg-if", "glob", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "regex", @@ -7309,41 +4035,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "rust-embed" -version = "8.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0" -dependencies = [ - "rust-embed-impl", - "rust-embed-utils", - "walkdir", -] - -[[package]] -name = "rust-embed-impl" -version = "8.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478" -dependencies = [ - "proc-macro2", - "quote", - "rust-embed-utils", - "syn 2.0.87", - "walkdir", -] - -[[package]] -name = "rust-embed-utils" -version = "8.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" -dependencies = [ - "globset", - "sha2", - "walkdir", -] - [[package]] name = "rust-i18n" version = "3.1.2" @@ -7393,27 +4084,11 @@ dependencies = [ "serde", "serde_json", "serde_yml", - "siphasher 1.0.1", + "siphasher", "toml 0.7.8", "triomphe", ] -[[package]] -name = "rust_decimal" -version = "1.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", -] - [[package]] name = "rustc-hash" version = "2.1.0" @@ -7537,21 +4212,11 @@ dependencies = [ "untrusted", ] -[[package]] -name = "rusttype" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff8374aa04134254b7995b63ad3dc41c7f7236f69528b28553da7d72efaa967" -dependencies = [ - "ab_glyph_rasterizer", - "owned_ttf_parser", -] - [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -7595,33 +4260,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "schemars" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", - "url", - "uuid", -] - -[[package]] -name = "schemars_derive" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.87", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -7640,185 +4278,12 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0495e4577c672de8254beb68d01a9b62d0e8a13c099edecdbedccce3223cd29f" -[[package]] -name = "sea-bae" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" -dependencies = [ - "heck 0.4.1", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "sea-orm" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4872675cc5d5d399a2a202c60f3a393ec8d3f3307c36adb166517f348e4db5" -dependencies = [ - "async-stream", - "async-trait", - "bigdecimal", - "chrono", - "futures", - "log", - "ouroboros", - "rust_decimal", - "sea-orm-macros", - "sea-query", - "sea-query-binder", - "serde", - "serde_json", - "sqlx", - "strum 0.26.3", - "thiserror 1.0.63", - "time", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "sea-orm-cli" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646647444d3a0366e30f26ff39f1656cc062b3dbf1f2e3d70cd9dc244b62cf7" -dependencies = [ - "chrono", - "clap", - "dotenvy", - "glob", - "regex", - "sea-schema", - "tracing", - "tracing-subscriber", - "url", -] - -[[package]] -name = "sea-orm-macros" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85f714906b72e7265c0b2077d0ad8f235dabebda513c92f1326d5d40cef0dd01" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "sea-bae", - "syn 2.0.87", - "unicode-ident", -] - -[[package]] -name = "sea-orm-migration" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0" -dependencies = [ - "async-trait", - "clap", - "dotenvy", - "futures", - "sea-orm", - "sea-orm-cli", - "sea-schema", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "sea-query" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" -dependencies = [ - "bigdecimal", - "chrono", - "inherent", - "ordered-float 3.9.2", - "rust_decimal", - "sea-query-derive", - "serde_json", - "time", - "uuid", -] - -[[package]] -name = "sea-query-binder" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" -dependencies = [ - "bigdecimal", - "chrono", - "rust_decimal", - "sea-query", - "serde_json", - "sqlx", - "time", - "uuid", -] - -[[package]] -name = "sea-query-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" -dependencies = [ - "darling", - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.87", - "thiserror 1.0.63", -] - -[[package]] -name = "sea-schema" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e" -dependencies = [ - "futures", - "sea-query", - "sea-schema-derive", -] - -[[package]] -name = "sea-schema-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "seahash" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - [[package]] name = "security-framework" version = "2.11.1" @@ -7855,32 +4320,11 @@ dependencies = [ "libc", ] -[[package]] -name = "selectors" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more 0.99.18", - "fxhash", - "log", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", -] - [[package]] name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] [[package]] name = "serde" @@ -7892,27 +4336,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-untagged" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" -dependencies = [ - "erased-serde", - "serde", - "typeid", -] - -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float 2.10.1", - "serde", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -7933,30 +4356,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "serde_html_form" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" -dependencies = [ - "form_urlencoded", - "indexmap 2.7.1", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_json" version = "1.0.125" @@ -7969,36 +4368,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_plain" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "serde_spanned" version = "0.6.7" @@ -8008,15 +4377,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -8029,49 +4389,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.7.1", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap 2.7.1", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "serde_yml" version = "0.0.11" @@ -8114,28 +4431,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "serialize-to-javascript" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "service-manager" version = "0.8.0" @@ -8151,16 +4446,6 @@ dependencies = [ "xml-rs", ] -[[package]] -name = "servo_arc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - [[package]] name = "sha1" version = "0.10.6" @@ -8192,16 +4477,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shared_child" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "shellexpand" version = "3.1.1" @@ -8226,29 +4501,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - -[[package]] -name = "simba" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176" -dependencies = [ - "approx", - "num-complex", - "num-traits", - "paste", - "wide", -] - [[package]] name = "simd-adler32" version = "0.3.7" @@ -8261,24 +4513,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" -[[package]] -name = "simple_asn1" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror 2.0.11", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "siphasher" version = "1.0.1" @@ -8299,9 +4533,6 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -dependencies = [ - "serde", -] [[package]] name = "smoltcp" @@ -8353,55 +4584,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "softbuffer" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d623bff5d06f60d738990980d782c8c866997d9194cfe79ecad00aa2f76826dd" -dependencies = [ - "bytemuck", - "cfg_aliases 0.2.1", - "core-graphics 0.23.2", - "foreign-types 0.5.0", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", - "raw-window-handle", - "redox_syscall", - "wasm-bindgen", - "web-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - [[package]] name = "spin" version = "0.9.8" @@ -8411,303 +4593,18 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlformat" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" -dependencies = [ - "nom", - "unicode_categories", -] - -[[package]] -name = "sqlx" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", -] - -[[package]] -name = "sqlx-core" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" -dependencies = [ - "atoi", - "bigdecimal", - "byteorder", - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "either", - "event-listener", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashbrown 0.14.5", - "hashlink", - "hex", - "indexmap 2.7.1", - "log", - "memchr", - "once_cell", - "paste", - "percent-encoding", - "rust_decimal", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlformat", - "thiserror 1.0.63", - "time", - "tokio", - "tokio-stream", - "tracing", - "url", - "uuid", - "webpki-roots 0.26.3", -] - -[[package]] -name = "sqlx-macros" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 2.0.87", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" -dependencies = [ - "dotenvy", - "either", - "heck 0.5.0", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", - "syn 2.0.87", - "tempfile", - "tokio", - "url", -] - -[[package]] -name = "sqlx-mysql" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" -dependencies = [ - "atoi", - "base64 0.22.1", - "bigdecimal", - "bitflags 2.8.0", - "byteorder", - "bytes", - "chrono", - "crc", - "digest", - "dotenvy", - "either", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "percent-encoding", - "rand 0.8.5", - "rsa", - "rust_decimal", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 1.0.63", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-postgres" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" -dependencies = [ - "atoi", - "base64 0.22.1", - "bigdecimal", - "bitflags 2.8.0", - "byteorder", - "chrono", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "num-bigint", - "once_cell", - "rand 0.8.5", - "rust_decimal", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 1.0.63", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-sqlite" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" -dependencies = [ - "atoi", - "chrono", - "flume 0.11.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", - "serde", - "serde_urlencoded", - "sqlx-core", - "time", - "tracing", - "url", - "uuid", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "stringprep" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", - "unicode-properties", -] - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - [[package]] name = "strum" version = "0.27.2" @@ -8750,17 +4647,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "swift-rs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" -dependencies = [ - "base64 0.21.7", - "serde", - "serde_json", -] - [[package]] name = "syn" version = "1.0.109" @@ -8843,19 +4729,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml 0.8.19", - "version-compare", -] - [[package]] name = "tabled" version = "0.16.0" @@ -8885,401 +4758,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" -[[package]] -name = "tao" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.10.0", - "core-graphics 0.24.0", - "crossbeam-channel", - "dispatch", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "once_cell", - "parking_lot", - "raw-window-handle", - "scopeguard", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "tauri" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "352a4bc7bf6c25f5624227e3641adf475a6535707451b09bb83271df8b7a6ac7" -dependencies = [ - "anyhow", - "bytes", - "dirs 6.0.0", - "dunce", - "embed_plist", - "getrandom 0.3.2", - "glob", - "gtk", - "heck 0.5.0", - "http", - "image 0.25.2", - "jni", - "libc", - "log", - "mime", - "muda", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "percent-encoding", - "plist", - "raw-window-handle", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "thiserror 2.0.11", - "tokio", - "tray-icon", - "url", - "urlpattern", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows 0.61.3", -] - -[[package]] -name = "tauri-build" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "182d688496c06bf08ea896459bf483eb29cdff35c1c4c115fb14053514303064" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs 6.0.0", - "glob", - "heck 0.5.0", - "json-patch", - "schemars", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml 0.8.19", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54a99a6cd8e01abcfa61508177e6096a4fe2681efecee9214e962f2f073ae4a" -dependencies = [ - "base64 0.22.1", - "brotli 8.0.1", - "ico", - "json-patch", - "plist", - "png", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2", - "syn 2.0.87", - "tauri-utils", - "thiserror 2.0.11", - "time", - "url", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7945b14dc45e23532f2ded6e120170bbdd4af5ceaa45784a6b33d250fbce3f9e" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.87", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd5c1e56990c70a906ef67a9851bbdba9136d26075ee9a2b19c8b46986b3e02" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars", - "serde", - "serde_json", - "tauri-utils", - "toml 0.8.19", - "walkdir", -] - -[[package]] -name = "tauri-plugin-clipboard-manager" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adddd9e9275b20e77af3061d100a25a884cced3c4c9ef680bd94dd0f7e26c1ca" -dependencies = [ - "arboard", - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.11", -] - -[[package]] -name = "tauri-plugin-os" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05bccb4c6de4299beec5a9b070878a01bce9e2c945aa7a75bcea38bcba4c675d" -dependencies = [ - "gethostname 1.0.2", - "log", - "os_info", - "serde", - "serde_json", - "serialize-to-javascript", - "sys-locale", - "tauri", - "tauri-plugin", - "thiserror 2.0.11", -] - -[[package]] -name = "tauri-plugin-positioner" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a01e373ea3f3f5f46d40f434ba13bd12fa4833aabab50dfc09f6362bad27c95" -dependencies = [ - "log", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "thiserror 2.0.11", -] - -[[package]] -name = "tauri-plugin-process" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7461c622a5ea00eb9cd9f7a08dbd3bf79484499fd5c21aa2964677f64ca651ab" -dependencies = [ - "tauri", - "tauri-plugin", -] - -[[package]] -name = "tauri-plugin-shell" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b9ffadec5c3523f11e8273465cacb3d86ea7652a28e6e2a2e9b5c182f791d25" -dependencies = [ - "encoding_rs", - "log", - "open", - "os_pipe", - "regex", - "schemars", - "serde", - "serde_json", - "shared_child", - "tauri", - "tauri-plugin", - "thiserror 2.0.11", - "tokio", -] - -[[package]] -name = "tauri-plugin-single-instance" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50a0e5a4ce43cb3a733c3aef85e8478bc769dac743c615e26639cbf5d953faf7" -dependencies = [ - "serde", - "serde_json", - "tauri", - "thiserror 2.0.11", - "tracing", - "windows-sys 0.60.2", - "zbus", -] - -[[package]] -name = "tauri-plugin-vpnservice" -version = "0.0.0" -dependencies = [ - "serde", - "tauri", - "tauri-plugin", - "thiserror 1.0.63", -] - -[[package]] -name = "tauri-runtime" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b1cc885be806ea15ff7b0eb47098a7b16323d9228876afda329e34e2d6c4676" -dependencies = [ - "cookie", - "dpi", - "gtk", - "http", - "jni", - "objc2 0.6.1", - "objc2-ui-kit", - "raw-window-handle", - "serde", - "serde_json", - "tauri-utils", - "thiserror 2.0.11", - "url", - "windows 0.61.3", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe653a2fbbef19fe898efc774bc52c8742576342a33d3d028c189b57eb1d2439" -dependencies = [ - "gtk", - "http", - "jni", - "log", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "once_cell", - "percent-encoding", - "raw-window-handle", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330c15cabfe1d9f213478c9e8ec2b0c76dab26bb6f314b8ad1c8a568c1d186e" -dependencies = [ - "anyhow", - "brotli 8.0.1", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever", - "http", - "infer", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.2", - "proc-macro2", - "quote", - "regex", - "schemars", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.11", - "toml 0.8.19", - "url", - "urlpattern", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-winres" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d321dbc6f998d825ab3f0d62673e810c861aac2d0de2cc2c395328f1d113b4" -dependencies = [ - "embed-resource", - "indexmap 2.7.1", - "toml 0.8.19", -] - [[package]] name = "tempfile" version = "3.22.0" @@ -9293,17 +4771,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - [[package]] name = "terminal_size" version = "0.4.1" @@ -9314,12 +4781,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "termtree" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" - [[package]] name = "thiserror" version = "1.0.63" @@ -9375,17 +4836,6 @@ name = "thunk-rs" version = "0.3.5" source = "git+https://github.com/easytier/thunk.git#cbbeec75a66b7b3cf0824ae890d9d06bcfb9d1f3" -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - [[package]] name = "tikv-jemalloc-ctl" version = "0.6.0" @@ -9554,19 +5004,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-test" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" -dependencies = [ - "async-stream", - "bytes", - "futures-core", - "tokio", - "tokio-stream", -] - [[package]] name = "tokio-util" version = "0.7.13" @@ -9575,12 +5012,8 @@ checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", - "futures-io", "futures-sink", - "futures-util", - "hashbrown 0.14.5", "pin-project-lite", - "slab", "tokio", ] @@ -9613,8 +5046,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", - "serde_spanned 0.6.7", - "toml_datetime 0.6.8", + "serde_spanned", + "toml_datetime", "toml_edit 0.19.15", ] @@ -9625,26 +5058,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", - "serde_spanned 0.6.7", - "toml_datetime 0.6.8", + "serde_spanned", + "toml_datetime", "toml_edit 0.22.20", ] -[[package]] -name = "toml" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac" -dependencies = [ - "indexmap 2.7.1", - "serde", - "serde_spanned 1.0.0", - "toml_datetime 0.7.0", - "toml_parser", - "toml_writer", - "winnow 0.7.10", -] - [[package]] name = "toml_datetime" version = "0.6.8" @@ -9654,15 +5072,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_datetime" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" -dependencies = [ - "serde", -] - [[package]] name = "toml_edit" version = "0.19.15" @@ -9671,19 +5080,8 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.7.1", "serde", - "serde_spanned 0.6.7", - "toml_datetime 0.6.8", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.7.1", - "toml_datetime 0.6.8", + "serde_spanned", + "toml_datetime", "winnow 0.5.40", ] @@ -9695,26 +5093,11 @@ checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap 2.7.1", "serde", - "serde_spanned 0.6.7", - "toml_datetime 0.6.8", + "serde_spanned", + "toml_datetime", "winnow 0.6.18", ] -[[package]] -name = "toml_parser" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" -dependencies = [ - "winnow 0.7.10", -] - -[[package]] -name = "toml_writer" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" - [[package]] name = "tonic" version = "0.12.3" @@ -9723,7 +5106,7 @@ checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum 0.7.7", + "axum", "base64 0.22.1", "bytes", "h2", @@ -9791,43 +5174,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", -] - -[[package]] -name = "tower-cookies" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd0118512cf0b3768f7fcccf0bef1ae41d68f2b45edc1e77432b36c97c56c6d" -dependencies = [ - "async-trait", - "axum-core 0.4.5", - "cookie", - "futures-util", - "http", - "parking_lot", - "pin-project-lite", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" -dependencies = [ - "async-compression", - "bitflags 2.8.0", - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", ] [[package]] @@ -9842,71 +5188,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" -[[package]] -name = "tower-sessions" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65856c81ee244e0f8a55ab0f7b769b72fbde387c235f0a73cd97c579818d05eb" -dependencies = [ - "async-trait", - "http", - "time", - "tokio", - "tower-cookies", - "tower-layer", - "tower-service", - "tower-sessions-core", - "tower-sessions-memory-store", - "tracing", -] - -[[package]] -name = "tower-sessions-core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb6abbfcaf6436ec5a772cd9f965401da12db793e404ae6134eac066fa5a04f3" -dependencies = [ - "async-trait", - "axum-core 0.4.5", - "base64 0.22.1", - "futures", - "http", - "parking_lot", - "rand 0.8.5", - "serde", - "serde_json", - "thiserror 1.0.63", - "time", - "tokio", - "tracing", -] - -[[package]] -name = "tower-sessions-memory-store" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fad75660c8afbe74f4e7cbbe8e9090171a056b57370ea4d7d5e9eb3e4af3092" -dependencies = [ - "async-trait", - "time", - "tokio", - "tower-sessions-core", -] - -[[package]] -name = "tower-sessions-sqlx-store" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81096d43c87c3bfa559116ac2b02d4a8398f0718be33e63685c467890ff4194" -dependencies = [ - "async-trait", - "rmp-serde", - "sqlx", - "thiserror 1.0.63", - "time", - "tower-sessions-core", -] - [[package]] name = "tracing" version = "0.1.41" @@ -9999,41 +5280,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "tray-icon" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da75ec677957aa21f6e0b361df0daab972f13a5bee3606de0638fd4ee1c666a" -dependencies = [ - "crossbeam-channel", - "dirs 6.0.0", - "libappindicator", - "muda", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.11", - "windows-sys 0.59.0", -] - -[[package]] -name = "tree_magic_mini" -version = "3.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac5e8971f245c3389a5a76e648bfc80803ae066a1243a75db0064d7c1129d63" -dependencies = [ - "fnv", - "memchr", - "nom", - "once_cell", - "petgraph 0.6.5", -] - [[package]] name = "triomphe" version = "0.1.13" @@ -10051,12 +5297,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "ttf-parser" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" - [[package]] name = "tun-easytier" version = "1.1.1" @@ -10067,7 +5307,7 @@ dependencies = [ "futures-core", "ipnet", "libc", - "libloading 0.8.5", + "libloading", "log", "nix 0.29.0", "thiserror 1.0.63", @@ -10113,91 +5353,18 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "uds_windows" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" -dependencies = [ - "memoffset", - "tempfile", - "winapi", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - [[package]] name = "unicase" version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-properties" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" - [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -10222,12 +5389,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "universal-hash" version = "0.5.1" @@ -10238,12 +5399,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "untrusted" version = "0.9.0" @@ -10257,35 +5412,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 1.0.3", + "idna", "percent-encoding", "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "urlpattern" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" -dependencies = [ - "regex", - "serde", - "unic-ucd-ident", - "url", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf16_iter" version = "1.0.5" @@ -10329,36 +5460,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "validator" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db79c75af171630a3148bd3e6d7c4f42b6a9a014c2945bc5ed0020cbb8d9478e" -dependencies = [ - "idna 0.5.0", - "once_cell", - "regex", - "serde", - "serde_derive", - "serde_json", - "url", - "validator_derive", -] - -[[package]] -name = "validator_derive" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0bcf92720c40105ac4b2dda2a4ea3aa717d4d6a862cc217da653a4bd5c6b10" -dependencies = [ - "darling", - "once_cell", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "valuable" version = "0.1.0" @@ -10383,26 +5484,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "walkdir" version = "2.5.0" @@ -10422,12 +5503,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -10443,12 +5518,6 @@ dependencies = [ "wit-bindgen-rt", ] -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -10519,90 +5588,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-streams" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wayland-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" -dependencies = [ - "cc", - "downcast-rs", - "rustix 0.38.34", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" -dependencies = [ - "bitflags 2.8.0", - "rustix 0.38.34", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" -dependencies = [ - "bitflags 2.8.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" -dependencies = [ - "bitflags 2.8.0", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" -dependencies = [ - "proc-macro2", - "quick-xml 0.37.5", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" -dependencies = [ - "pkg-config", -] - [[package]] name = "web-sys" version = "0.3.70" @@ -10623,50 +5608,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webkit2gtk" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - [[package]] name = "webpki" version = "0.22.4" @@ -10713,48 +5654,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "webview2-com" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-implement 0.60.0", - "windows-interface 0.59.1", -] - -[[package]] -name = "webview2-com-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "webview2-com-sys" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" -dependencies = [ - "thiserror 2.0.11", - "windows 0.61.3", - "windows-core 0.61.2", -] - -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - [[package]] name = "which" version = "4.4.2" @@ -10779,16 +5678,6 @@ dependencies = [ "winsafe", ] -[[package]] -name = "whoami" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" -dependencies = [ - "redox_syscall", - "wasite", -] - [[package]] name = "wide" version = "0.7.28" @@ -10863,21 +5752,6 @@ dependencies = [ "windows 0.48.0", ] -[[package]] -name = "window-vibrancy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" -dependencies = [ - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "raw-window-handle", - "windows-sys 0.59.0", - "windows-version", -] - [[package]] name = "windows" version = "0.48.0" @@ -10907,28 +5781,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core 0.61.2", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - [[package]] name = "windows-core" version = "0.52.0" @@ -10944,37 +5796,13 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", - "windows-threading", -] - [[package]] name = "windows-implement" version = "0.58.0" @@ -10986,17 +5814,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "windows-interface" version = "0.58.0" @@ -11008,47 +5825,20 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", -] - [[package]] name = "windows-registry" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result 0.2.0", - "windows-strings 0.1.0", + "windows-result", + "windows-strings", "windows-targets 0.52.6", ] @@ -11061,15 +5851,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows-service" version = "0.7.0" @@ -11087,19 +5868,10 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-targets 0.52.6", ] -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -11151,7 +5923,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -11216,24 +5988,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-version" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -11432,15 +6186,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winnow" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" -dependencies = [ - "memchr", -] - [[package]] name = "winreg" version = "0.50.0" @@ -11461,16 +6206,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.55.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" -dependencies = [ - "cfg-if", - "windows-sys 0.59.0", -] - [[package]] name = "winsafe" version = "0.0.19" @@ -11484,7 +6219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b196f9328341b035820c54beebca487823e2e20a5977f284f2af2a0ee8f04400" dependencies = [ "c2rust-bitfields", - "libloading 0.8.5", + "libloading", "log", "thiserror 1.0.63", "windows-sys 0.52.0", @@ -11499,26 +6234,6 @@ dependencies = [ "bitflags 2.8.0", ] -[[package]] -name = "wl-clipboard-rs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b41773911497b18ca8553c3daaf8ec9fe9819caf93d451d3055f69de028adb" -dependencies = [ - "derive-new", - "libc", - "log", - "nix 0.28.0", - "os_pipe", - "tempfile", - "thiserror 1.0.63", - "tree_magic_mini", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-wlr", -] - [[package]] name = "write16" version = "1.0.0" @@ -11531,97 +6246,6 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -[[package]] -name = "wry" -version = "0.52.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9" -dependencies = [ - "base64 0.22.1", - "block2 0.6.1", - "cookie", - "crossbeam-channel", - "dpi", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "ndk", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "objc2-web-kit", - "once_cell", - "percent-encoding", - "raw-window-handle", - "sha2", - "soup3", - "tao-macros", - "thiserror 2.0.11", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "x11rb" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" -dependencies = [ - "gethostname 0.4.3", - "rustix 0.38.34", - "x11rb-protocol", -] - -[[package]] -name = "x11rb-protocol" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" - [[package]] name = "x25519-dalek" version = "2.0.1" @@ -11640,12 +6264,6 @@ version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - [[package]] name = "yasna" version = "0.5.2" @@ -11679,66 +6297,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zbus" -version = "5.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb4f9a464286d42851d18a605f7193b8febaf5b0919d71c6399b7b26e5b0aad" -dependencies = [ - "async-broadcast", - "async-executor", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-lite", - "hex", - "nix 0.30.1", - "ordered-stream", - "serde", - "serde_repr", - "tracing", - "uds_windows", - "windows-sys 0.59.0", - "winnow 0.7.10", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "5.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef9859f68ee0c4ee2e8cde84737c78e3f4c54f946f2a38645d0d4c7a95327659" -dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.87", - "zbus_names", - "zvariant", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" -dependencies = [ - "serde", - "static_assertions", - "winnow 0.7.10", - "zvariant", -] - [[package]] name = "zerocopy" version = "0.7.35" @@ -11894,44 +6452,3 @@ dependencies = [ "cc", "pkg-config", ] - -[[package]] -name = "zvariant" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d30786f75e393ee63a21de4f9074d4c038d52c5b1bb4471f955db249f9dffb1" -dependencies = [ - "endi", - "enumflags2", - "serde", - "winnow 0.7.10", - "zvariant_derive", - "zvariant_utils", -] - -[[package]] -name = "zvariant_derive" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75fda702cd42d735ccd48117b1630432219c0e9616bf6cb0f8350844ee4d9580" -dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.87", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "static_assertions", - "syn 2.0.87", - "winnow 0.7.10", -] diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 972da260..9594d135 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -242,6 +242,7 @@ hickory-server = { version = "0.25.2", features = [ "resolver", ], optional = true } +bon = "3.9.1" derive_builder = "0.20.2" humantime-serde = "1.1.1" multimap = "0.10.1" diff --git a/easytier/src/gateway/socks5.rs b/easytier/src/gateway/socks5.rs index 728bd131..3bdceaf1 100644 --- a/easytier/src/gateway/socks5.rs +++ b/easytier/src/gateway/socks5.rs @@ -18,7 +18,7 @@ use crate::gateway::kcp_proxy::NatDstKcpConnector; use crate::{ common::{ config::PortForwardConfig, global_ctx::GlobalCtxEvent, join_joinset_background, - netns::NetNS, scoped_task::ScopedTask, + scoped_task::ScopedTask, }, gateway::{ fast_socks5::{ @@ -30,10 +30,7 @@ use crate::{ ip_reassembler::IpReassembler, tokio_smoltcp::{BufferSize, Net, NetConfig, channel_device}, }, - tunnel::{ - common::setup_socket2, - packet_def::{PacketType, ZCPacket}, - }, + tunnel::packet_def::{PacketType, ZCPacket}, }; use anyhow::Context; use dashmap::DashMap; @@ -42,21 +39,21 @@ use pnet::packet::{ }; use tokio::{ io::{AsyncRead, AsyncWrite}, - net::{TcpListener, TcpSocket, UdpSocket}, + net::{TcpListener, UdpSocket}, select, sync::{Mutex, Notify, mpsc}, task::JoinSet, time::timeout, }; +#[cfg(feature = "kcp")] +use super::tcp_proxy::NatDstConnector as _; +use crate::tunnel::common::bind; use crate::{ common::{error::Error, global_ctx::GlobalCtx}, peers::{PeerPacketFilter, peer_manager::PeerManager}, }; -#[cfg(feature = "kcp")] -use super::tcp_proxy::NatDstConnector as _; - enum SocksUdpSocket { UdpSocket(Arc), SmolUdpSocket(super::tokio_smoltcp::UdpSocket), @@ -328,38 +325,6 @@ impl AsyncTcpConnector for Socks5AutoConnector { } } -fn bind_tcp_socket(addr: SocketAddr, net_ns: NetNS) -> Result { - let _g = net_ns.guard(); - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; - - setup_socket2(&socket2_socket, &addr, true)?; - - let socket = TcpSocket::from_std_stream(socket2_socket.into()); - - if let Err(e) = socket.set_nodelay(true) { - tracing::warn!(?e, "set_nodelay fail in listen"); - } - - Ok(socket.listen(1024)?) -} - -fn bind_udp_socket(addr: SocketAddr, net_ns: NetNS) -> Result { - let _g = net_ns.guard(); - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - - setup_socket2(&socket2_socket, &addr, true)?; - - Ok(UdpSocket::from_std(socket2_socket.into())?) -} - struct Socks5ServerNet { ipv4_addr: cidr::Ipv4Inet, auth: Option, @@ -702,10 +667,10 @@ impl Socks5Server { proxy_url.port().unwrap() ); - let listener = bind_tcp_socket( - bind_addr.parse::().unwrap(), - self.global_ctx.net_ns.clone(), - )?; + let listener = bind::() + .addr(bind_addr.parse::().unwrap()) + .net_ns(self.global_ctx.net_ns.clone()) + .call()?; let entries = self.entries.clone(); let entry_count = self.entry_count.clone(); @@ -838,7 +803,10 @@ impl Socks5Server { pub async fn add_tcp_port_forward(&self, cfg: &PortForwardConfig) -> Result<(), Error> { let (bind_addr, dst_addr) = (cfg.bind_addr, cfg.dst_addr); - let listener = bind_tcp_socket(bind_addr, self.global_ctx.net_ns.clone())?; + let listener = bind::() + .addr(bind_addr) + .net_ns(self.global_ctx.net_ns.clone()) + .call()?; let net = self.net.clone(); let entries = self.entries.clone(); @@ -906,7 +874,12 @@ impl Socks5Server { #[tracing::instrument(name = "add_udp_port_forward", skip(self))] pub async fn add_udp_port_forward(&self, cfg: &PortForwardConfig) -> Result<(), Error> { let (bind_addr, dst_addr) = (cfg.bind_addr, cfg.dst_addr); - let socket = Arc::new(bind_udp_socket(bind_addr, self.global_ctx.net_ns.clone())?); + let socket = Arc::new( + bind::() + .addr(bind_addr) + .net_ns(self.global_ctx.net_ns.clone()) + .call()?, + ); let entries = self.entries.clone(); let entry_count = self.entry_count.clone(); diff --git a/easytier/src/gateway/udp_proxy.rs b/easytier/src/gateway/udp_proxy.rs index ab6ecc95..5da5cb09 100644 --- a/easytier/src/gateway/udp_proxy.rs +++ b/easytier/src/gateway/udp_proxy.rs @@ -24,18 +24,18 @@ use tokio::{ use tracing::Level; +use super::{CidrSet, ip_reassembler::IpReassembler}; +use crate::tunnel::common::bind; use crate::{ common::{PeerId, error::Error, global_ctx::ArcGlobalCtx, scoped_task::ScopedTask}, gateway::ip_reassembler::{ComposeIpv4PacketArgs, compose_ipv4_packet}, peers::{PeerPacketFilter, peer_manager::PeerManager}, tunnel::{ - common::{reserve_buf, setup_socket2}, + common::reserve_buf, packet_def::{PacketType, ZCPacket}, }, }; -use super::{CidrSet, ip_reassembler::IpReassembler}; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct UdpNatKey { src_socket: SocketAddr, @@ -63,18 +63,9 @@ impl UdpNatEntry { denied: bool, ) -> Result { // TODO: try use src port, so we will be ip restricted nat type - let socket = if denied { - None - } else { - let socket2_socket = socket2::Socket::new( - socket2::Domain::IPV4, - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - let dst_socket_addr = "0.0.0.0:0".parse().unwrap(); - setup_socket2(&socket2_socket, &dst_socket_addr, true)?; - Some(UdpSocket::from_std(socket2_socket.into())?) - }; + let socket = (!denied) + .then(|| bind().addr("0.0.0.0:0".parse().unwrap()).call()) + .transpose()?; Ok(Self { src_peer_id, @@ -403,11 +394,10 @@ impl UdpProxy { #[async_trait::async_trait] impl PeerPacketFilter for UdpProxy { async fn try_process_packet_from_peer(&self, packet: ZCPacket) -> Option { - if self.try_handle_packet(&packet).await.is_some() { - return None; - } else { - return Some(packet); - } + self.try_handle_packet(&packet) + .await + .is_none() + .then_some(packet) } } diff --git a/easytier/src/tunnel/common.rs b/easytier/src/tunnel/common.rs index 05938d58..f73e53e7 100644 --- a/easytier/src/tunnel/common.rs +++ b/easytier/src/tunnel/common.rs @@ -1,3 +1,7 @@ +use bon::builder; +use futures::{Future, Sink, Stream, stream::FuturesUnordered}; +use network_interface::NetworkInterfaceConfig as _; +use pin_project_lite::pin_project; use std::{ any::Any, net::{IpAddr, SocketAddr}, @@ -5,26 +9,21 @@ use std::{ sync::{Arc, Mutex}, task::{Poll, ready}, }; - -use futures::{Future, Sink, Stream, stream::FuturesUnordered}; -use network_interface::NetworkInterfaceConfig as _; -use pin_project_lite::pin_project; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use tokio_stream::StreamExt; -use tokio_util::io::poll_write_buf; -use zerocopy::FromBytes as _; - use super::TunnelInfo; - -use crate::tunnel::packet_def::{PEER_MANAGER_HEADER_SIZE, ZCPacket}; - use super::{ SinkItem, StreamItem, Tunnel, TunnelError, ZCPacketSink, ZCPacketStream, buf::BufList, packet_def::{TCP_TUNNEL_HEADER_SIZE, TCPTunnelHeader, ZCPacketType}, }; +use crate::common::netns::NetNS; +use crate::tunnel::packet_def::{PEER_MANAGER_HEADER_SIZE, ZCPacket}; +use bytes::{Buf, BufMut, Bytes, BytesMut}; +use tokio::net::{TcpListener, TcpSocket, UdpSocket}; +use tokio_stream::StreamExt; +use tokio_util::io::poll_write_buf; +use zerocopy::FromBytes as _; pub struct TunnelWrapper { reader: Arc>>, @@ -344,7 +343,70 @@ pub(crate) fn get_interface_name_by_ip(local_ip: &IpAddr) -> Option { None } -pub(crate) fn setup_socket2_ext( +pub(crate) async fn wait_for_connect_futures( + mut futures: FuturesUnordered, +) -> Result +where + Fut: Future> + Send, + E: std::error::Error + Into + Send + 'static, +{ + // return last error + let mut last_err = None; + + while let Some(ret) = futures.next().await { + if let Err(e) = ret { + last_err = Some(e.into()); + } else { + return ret.map_err(|e| e.into()); + } + } + + Err(last_err.unwrap_or(TunnelError::Shutdown)) +} + +// region bind + +pub trait Bindable: Sized { + const TYPE: socket2::Type; + const PROTOCOL: Option; + + fn finalize(socket: socket2::Socket) -> Result; +} + +impl Bindable for TcpSocket { + const TYPE: socket2::Type = socket2::Type::STREAM; + const PROTOCOL: Option = Some(socket2::Protocol::TCP); + + fn finalize(socket: socket2::Socket) -> Result { + let socket = TcpSocket::from_std_stream(socket.into()); + + if let Err(error) = socket.set_nodelay(true) { + tracing::warn!(?error, "set_nodelay failed for tcp socket"); + } + + Ok(socket) + } +} + +impl Bindable for TcpListener { + const TYPE: socket2::Type = socket2::Type::STREAM; + const PROTOCOL: Option = Some(socket2::Protocol::TCP); + + fn finalize(socket: socket2::Socket) -> Result { + Ok(TcpSocket::finalize(socket)?.listen(1024)?) + } +} + +impl Bindable for UdpSocket { + const TYPE: socket2::Type = socket2::Type::DGRAM; + const PROTOCOL: Option = Some(socket2::Protocol::UDP); + + fn finalize(socket: socket2::Socket) -> Result { + Ok(UdpSocket::from_std(socket.into())?) + } +} + +fn setup_socket2_ext( socket2_socket: &socket2::Socket, bind_addr: &SocketAddr, #[allow(unused_variables)] bind_dev: Option, @@ -408,38 +470,69 @@ pub(crate) fn setup_socket2_ext( Ok(()) } -pub(crate) async fn wait_for_connect_futures( - mut futures: FuturesUnordered, -) -> Result -where - Fut: Future> + Send, - E: std::error::Error + Into + Send + 'static, -{ - // return last error - let mut last_err = None; - - while let Some(ret) = futures.next().await { - if let Err(e) = ret { - last_err = Some(e.into()); - } else { - return ret.map_err(|e| e.into()); - } - } - - Err(last_err.unwrap_or(TunnelError::Shutdown)) +#[derive(Debug, Default, Clone)] +pub enum BindDev { + #[default] + Auto, + Disabled, + Custom(String), } -pub(crate) fn setup_socket2( - socket2_socket: &socket2::Socket, - bind_addr: &SocketAddr, - only_v6: bool, -) -> Result<(), TunnelError> { - setup_socket2_ext( - socket2_socket, - bind_addr, - super::common::get_interface_name_by_ip(&bind_addr.ip()), - only_v6, - ) +impl From for BindDev { + fn from(value: String) -> Self { + if value.is_empty() { + Self::Disabled + } else { + Self::Custom(value) + } + } +} + +impl From<&str> for BindDev { + fn from(value: &str) -> Self { + value.to_string().into() + } +} + +/// Binds a socket to a specific address and optionally a network interface. +/// +/// This function creates a new socket, applies specific configurations (such as +/// binding to a device or setting IPv6-only flags), and finalizes it into the +/// requested [`Bindable`] type. +/// +/// # Arguments +/// +/// * `addr` - The `SocketAddr` to bind the socket to. +/// * `dev` - The name of the network interface to bind to: +/// * **(default) `BindDev::Auto`**: Enables **auto-discovery**. The function will attempt to automatically +/// resolve the interface name associated with the provided `addr.ip()`. +/// * **empty string or `BindDev::Disabled`**: **Disables** auto-discovery and +/// explicitly chooses **not** to bind to any specific device. The routing will be +/// left entirely to the OS. +/// * **non-empty string or `BindDev::Custom(..)`**: Skips auto-discovery and explicitly binds to +/// the specified interface. +/// * `net_ns` - An optional network namespace to switch into before creating the socket. +/// * `only_v6` - If `true`, sets the `IPV6_V6ONLY` flag on the socket. +/// +/// # Errors +/// +/// Returns a [`TunnelError`] if socket creation, configuration, or finalization fails. +#[builder] +pub fn bind( + addr: SocketAddr, + #[builder(default, into)] dev: BindDev, + net_ns: Option, + #[builder(default)] only_v6: bool, +) -> Result { + let _g = net_ns.map(|n| n.guard()); + let dev = match dev { + BindDev::Auto => get_interface_name_by_ip(&addr.ip()), + BindDev::Disabled => None, + BindDev::Custom(s) => Some(s), + }; + let socket = socket2::Socket::new(socket2::Domain::for_address(addr), B::TYPE, B::PROTOCOL)?; + setup_socket2_ext(&socket, &addr, dev, only_v6)?; + B::finalize(socket) } pub fn reserve_buf(buf: &mut BytesMut, min_size: usize, max_size: usize) { @@ -448,6 +541,8 @@ pub fn reserve_buf(buf: &mut BytesMut, min_size: usize, max_size: usize) { } } +// endregion + pub mod tests { use atomic_shim::AtomicU64; use std::{sync::Arc, time::Instant}; diff --git a/easytier/src/tunnel/quic.rs b/easytier/src/tunnel/quic.rs index 5263ce3c..4cfb90ca 100644 --- a/easytier/src/tunnel/quic.rs +++ b/easytier/src/tunnel/quic.rs @@ -4,9 +4,10 @@ use super::{FromUrl, IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener}; use crate::common::global_ctx::ArcGlobalCtx; +use crate::tunnel::common::bind; use crate::tunnel::{ TunnelInfo, - common::{FramedReader, FramedWriter, TunnelWrapper, setup_socket2}, + common::{FramedReader, FramedWriter, TunnelWrapper}, }; use anyhow::Context; use derivative::Derivative; @@ -19,6 +20,7 @@ use quinn::{ use std::net::{Ipv4Addr, Ipv6Addr}; use std::sync::OnceLock; use std::{net::SocketAddr, sync::Arc, time::Duration}; +use tokio::net::UdpSocket; // region config pub fn transport_config() -> Arc { @@ -179,27 +181,28 @@ pub struct QuicEndpointManager { static QUIC_ENDPOINT_MANAGER: OnceLock = OnceLock::new(); impl QuicEndpointManager { - fn try_create(addr: SocketAddr, dual_stack: bool) -> std::io::Result { - let socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - setup_socket2(&socket, &addr, addr.is_ipv6() && !dual_stack) - .map_err(std::io::Error::other)?; - let socket = std::net::UdpSocket::from(socket); - let runtime = default_runtime().ok_or(std::io::Error::other("no async runtime found"))?; + fn try_create(addr: SocketAddr, dual_stack: bool) -> Result { + let socket = bind::() + .addr(addr) + .only_v6(addr.is_ipv6() && !dual_stack) + .call()?; + let runtime = default_runtime().ok_or(TunnelError::InternalError( + "no async runtime found".to_owned(), + ))?; let mut endpoint = Endpoint::new_with_abstract_socket( endpoint_config(), None, - runtime.wrap_udp_socket(socket)?, + runtime.wrap_udp_socket(socket.into_std()?)?, runtime, )?; endpoint.set_default_client_config(client_config()); Ok(endpoint) } - fn create(&self, mut selector: F) -> std::io::Result<(&RwPool, Option)> + fn create( + &self, + mut selector: F, + ) -> Result<(&RwPool, Option), TunnelError> where F: FnMut(&QuicEndpointManager) -> (&RwPool, Option<(SocketAddr, bool)>), { @@ -210,10 +213,10 @@ impl QuicEndpointManager { }; let endpoint = Self::try_create(addr, dual_stack); - if let Err(e) = endpoint.as_ref() + if let Err(error) = endpoint.as_ref() && dual_stack { - tracing::warn!("create dual stack quic endpoint failed: {:?}", e); + tracing::warn!(?error, "create dual stack quic endpoint failed"); self.both.disable(); self.ipv4.enable(); self.ipv6.enable(); @@ -263,7 +266,7 @@ impl QuicEndpointManager { /// /// # Arguments /// * `addr`: listen address - fn server(global_ctx: &ArcGlobalCtx, addr: SocketAddr) -> std::io::Result { + fn server(global_ctx: &ArcGlobalCtx, addr: SocketAddr) -> Result { let mgr = Self::load(global_ctx); let (pool, endpoint) = mgr.create(|mgr| { @@ -289,7 +292,7 @@ impl QuicEndpointManager { /// /// # Arguments /// * `ip_version`: the IP version of the remote address - fn client(global_ctx: &ArcGlobalCtx, ip_version: IpVersion) -> std::io::Result { + fn client(global_ctx: &ArcGlobalCtx, ip_version: IpVersion) -> Result { let mgr = Self::load(global_ctx); let (pool, endpoint) = mgr.create(|mgr| { @@ -318,7 +321,7 @@ impl QuicEndpointManager { async fn connect( global_ctx: &ArcGlobalCtx, addr: SocketAddr, - ) -> std::io::Result<(Endpoint, Connection)> { + ) -> Result<(Endpoint, Connection), TunnelError> { let ip_version = if addr.ip().is_ipv4() { IpVersion::V4 } else { @@ -327,8 +330,9 @@ impl QuicEndpointManager { let endpoint = Self::client(global_ctx, ip_version)?; let connection = endpoint .connect(addr, "localhost") - .map_err(std::io::Error::other)? - .await?; + .with_context(|| format!("failed to create connection to {}", addr))? + .await + .with_context(|| format!("failed to connect to {}", addr))?; Ok((endpoint, connection)) } @@ -585,10 +589,10 @@ mod tests { async fn invalid_peer_addr_impl() { let mut connector = QuicTunnelConnector::new("quic://127.0.0.1:0".parse().unwrap(), global_ctx()); - let err = connector.connect().await.unwrap_err(); + let err = format!("{:?}", connector.connect().await.unwrap_err()); assert!( - err.to_string().contains("invalid remote address"), - "unexpected error: {:?}", + err.contains("invalid remote address"), + "unexpected error: {}", err ); } diff --git a/easytier/src/tunnel/tcp.rs b/easytier/src/tunnel/tcp.rs index 2061c2fe..fd501558 100644 --- a/easytier/src/tunnel/tcp.rs +++ b/easytier/src/tunnel/tcp.rs @@ -1,7 +1,7 @@ use std::net::SocketAddr; use super::{FromUrl, TunnelInfo}; -use crate::tunnel::common::setup_socket2; +use crate::tunnel::common::bind; use async_trait::async_trait; use futures::stream::FuturesUnordered; use tokio::net::{TcpListener, TcpSocket, TcpStream}; @@ -59,25 +59,15 @@ impl TcpTunnelListener { impl TunnelListener for TcpTunnelListener { async fn listen(&mut self) -> Result<(), TunnelError> { self.listener = None; + let addr = SocketAddr::from_url(self.addr.clone(), IpVersion::Both).await?; - - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; - setup_socket2(&socket2_socket, &addr, true)?; - let socket = TcpSocket::from_std_stream(socket2_socket.into()); - - if let Err(e) = socket.set_nodelay(true) { - tracing::warn!(?e, "set_nodelay fail in listen"); - } + let listener = bind::().addr(addr).only_v6(true).call()?; self.addr - .set_port(Some(socket.local_addr()?.port())) + .set_port(Some(listener.local_addr()?.port())) .unwrap(); + self.listener = Some(listener); - self.listener = Some(socket.listen(1024)?); Ok(()) } @@ -167,21 +157,14 @@ impl TcpTunnelConnector { let futures = FuturesUnordered::new(); for bind_addr in self.bind_addrs.iter() { - tracing::info!(bind_addr = ?bind_addr, ?addr, "bind addr"); - - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; - - if let Err(e) = setup_socket2(&socket2_socket, bind_addr, true) { - tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); - continue; + tracing::info!(?bind_addr, ?addr, "bind addr"); + match bind::().addr(*bind_addr).only_v6(true).call() { + Ok(socket) => futures.push(socket.connect(addr)), + Err(error) => { + tracing::error!(?bind_addr, ?addr, ?error, "bind addr fail"); + continue; + } } - - let socket = TcpSocket::from_std_stream(socket2_socket.into()); - futures.push(socket.connect(addr)); } let ret = wait_for_connect_futures(futures).await; diff --git a/easytier/src/tunnel/udp.rs b/easytier/src/tunnel/udp.rs index 7119d143..dde69c7e 100644 --- a/easytier/src/tunnel/udp.rs +++ b/easytier/src/tunnel/udp.rs @@ -18,16 +18,16 @@ use tokio::{ sync::mpsc::{Receiver, Sender, UnboundedReceiver, UnboundedSender}, task::JoinSet, }; - use tracing::{Instrument, instrument}; use super::{ FromUrl, IpVersion, Tunnel, TunnelConnCounter, TunnelError, TunnelInfo, TunnelListener, TunnelUrl, - common::{setup_socket2, setup_socket2_ext, wait_for_connect_futures}, + common::wait_for_connect_futures, packet_def::{UDP_TUNNEL_HEADER_SIZE, UDPTunnelHeader, V6HolePunchPacket}, ring::{RingSink, RingStream}, }; +use crate::tunnel::common::bind; use crate::{ common::{join_joinset_background, scoped_task::ScopedTask, shrink_dashmap}, tunnel::{ @@ -536,21 +536,14 @@ impl UdpTunnelListener { impl TunnelListener for UdpTunnelListener { async fn listen(&mut self) -> Result<(), TunnelError> { let addr = SocketAddr::from_url(self.addr.clone(), IpVersion::Both).await?; - - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - let tunnel_url: TunnelUrl = self.addr.clone().into(); - if let Some(bind_dev) = tunnel_url.bind_dev() { - setup_socket2_ext(&socket2_socket, &addr, Some(bind_dev), true)?; - } else { - setup_socket2(&socket2_socket, &addr, true)?; - } - - self.socket = Some(Arc::new(UdpSocket::from_std(socket2_socket.into())?)); + self.socket = Some(Arc::new( + bind() + .addr(addr) + .only_v6(true) + .maybe_dev(tunnel_url.bind_dev()) + .call()?, + )); self.data.socket = self.socket.clone(); self.addr @@ -833,17 +826,14 @@ impl UdpTunnelConnector { let futures = FuturesUnordered::new(); for bind_addr in self.bind_addrs.iter() { - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(*bind_addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - if let Err(e) = setup_socket2(&socket2_socket, bind_addr, true) { - tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); - continue; + tracing::info!(?bind_addr, ?addr, "bind addr"); + match bind().addr(*bind_addr).only_v6(true).call() { + Ok(socket) => futures.push(self.try_connect_with_socket(Arc::new(socket), addr)), + Err(error) => { + tracing::error!(?error, ?bind_addr, ?addr, "bind addr fail"); + continue; + } } - let socket = UdpSocket::from_std(socket2_socket.into())?; - futures.push(self.try_connect_with_socket(Arc::new(socket), addr)); } wait_for_connect_futures(futures).await } @@ -1034,13 +1024,12 @@ mod tests { ) .await .unwrap(); - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - ) - .unwrap(); - setup_socket2_ext(&socket2_socket, &addr, bind_dev.clone(), true).unwrap(); + let _ = bind::() + .addr(addr) + .maybe_dev(bind_dev.clone()) + .only_v6(true) + .call() + .unwrap(); } } diff --git a/easytier/src/tunnel/websocket.rs b/easytier/src/tunnel/websocket.rs index 2772dad7..e561c834 100644 --- a/easytier/src/tunnel/websocket.rs +++ b/easytier/src/tunnel/websocket.rs @@ -1,9 +1,10 @@ use super::{ FromUrl, IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelListener, - common::{TunnelWrapper, setup_socket2, wait_for_connect_futures}, + common::{TunnelWrapper, wait_for_connect_futures}, insecure_tls::{get_insecure_tls_cert, init_crypto_provider}, packet_def::{ZCPacket, ZCPacketType}, }; +use crate::tunnel::common::bind; use crate::{proto::common::TunnelInfo, tunnel::insecure_tls::get_insecure_tls_client_config}; use anyhow::Context; use bytes::BytesMut; @@ -160,20 +161,16 @@ impl WsTunnelListener { #[async_trait::async_trait] impl TunnelListener for WsTunnelListener { async fn listen(&mut self) -> Result<(), TunnelError> { + self.listener = None; + let addr = SocketAddr::from_url(self.addr.clone(), IpVersion::Both).await?; - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; - setup_socket2(&socket2_socket, &addr, true)?; - let socket = TcpSocket::from_std_stream(socket2_socket.into()); + let listener = bind::().addr(addr).only_v6(true).call()?; self.addr - .set_port(Some(socket.local_addr()?.port())) + .set_port(Some(listener.local_addr()?.port())) .unwrap(); + self.listener = Some(listener); - self.listener = Some(socket.listen(1024)?); Ok(()) } @@ -283,25 +280,18 @@ impl WsTunnelConnector { let futures = FuturesUnordered::new(); for bind_addr in self.bind_addrs.iter() { - tracing::info!(bind_addr = ?bind_addr, ?addr, "bind addr"); - - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; - - if let Err(e) = setup_socket2(&socket2_socket, bind_addr, true) { - tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); - continue; + tracing::info!(?bind_addr, ?addr, "bind addr"); + match bind().addr(*bind_addr).only_v6(true).call() { + Ok(socket) => futures.push(Self::connect_with( + self.addr.clone(), + self.ip_version, + socket, + )), + Err(error) => { + tracing::error!(?bind_addr, ?addr, ?error, "bind addr fail"); + continue; + } } - - let socket = TcpSocket::from_std_stream(socket2_socket.into()); - futures.push(Self::connect_with( - self.addr.clone(), - self.ip_version, - socket, - )) } wait_for_connect_futures(futures).await diff --git a/easytier/src/tunnel/wireguard.rs b/easytier/src/tunnel/wireguard.rs index 844f384b..66fba55a 100644 --- a/easytier/src/tunnel/wireguard.rs +++ b/easytier/src/tunnel/wireguard.rs @@ -6,6 +6,23 @@ use std::{ time::Duration, }; +use super::{ + FromUrl, IpVersion, Tunnel, TunnelError, TunnelInfo, TunnelListener, TunnelUrl, ZCPacketSink, + ZCPacketStream, + common::wait_for_connect_futures, + generate_digest_from_str, + packet_def::{PEER_MANAGER_HEADER_SIZE, ZCPacketType}, + ring::create_ring_tunnel_pair, +}; +use crate::tunnel::common::{BindDev, bind}; +use crate::{ + common::shrink_dashmap, + tunnel::{ + build_url_from_socket_addr, + common::TunnelWrapper, + packet_def::{WG_TUNNEL_HEADER_SIZE, ZCPacket}, + }, +}; use anyhow::Context; use async_recursion::async_recursion; use async_trait::async_trait; @@ -20,23 +37,6 @@ use futures::{SinkExt, StreamExt, stream::FuturesUnordered}; use rand::RngCore; use tokio::{net::UdpSocket, sync::Mutex, task::JoinSet}; -use super::{ - FromUrl, IpVersion, Tunnel, TunnelError, TunnelInfo, TunnelListener, TunnelUrl, ZCPacketSink, - ZCPacketStream, - common::{setup_socket2, setup_socket2_ext, wait_for_connect_futures}, - generate_digest_from_str, - packet_def::{PEER_MANAGER_HEADER_SIZE, ZCPacketType}, - ring::create_ring_tunnel_pair, -}; -use crate::{ - common::shrink_dashmap, - tunnel::{ - build_url_from_socket_addr, - common::TunnelWrapper, - packet_def::{WG_TUNNEL_HEADER_SIZE, ZCPacket}, - }, -}; - const MAX_PACKET: usize = 2048; #[derive(Debug, Clone)] @@ -555,20 +555,14 @@ impl WgTunnelListener { impl TunnelListener for WgTunnelListener { async fn listen(&mut self) -> Result<(), TunnelError> { let addr = SocketAddr::from_url(self.addr.clone(), IpVersion::Both).await?; - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - let tunnel_url: TunnelUrl = self.addr.clone().into(); - if let Some(bind_dev) = tunnel_url.bind_dev() { - setup_socket2_ext(&socket2_socket, &addr, Some(bind_dev), true)?; - } else { - setup_socket2(&socket2_socket, &addr, true)?; - } - - self.udp = Some(Arc::new(UdpSocket::from_std(socket2_socket.into())?)); + self.udp = Some(Arc::new( + bind() + .addr(addr) + .only_v6(true) + .maybe_dev(tunnel_url.bind_dev()) + .call()?, + )); self.addr .set_port(Some(self.udp.as_ref().unwrap().local_addr()?.port())) .unwrap(); @@ -695,13 +689,11 @@ impl WgTunnelConnector { } async fn connect_with_ipv6(&self, addr: SocketAddr) -> Result, TunnelError> { - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - setup_socket2_ext(&socket2_socket, &"[::]:0".parse().unwrap(), None, true)?; - let socket = UdpSocket::from_std(socket2_socket.into())?; + let socket = bind() + .addr("[::]:0".parse().unwrap()) + .dev(BindDev::Disabled) + .only_v6(true) + .call()?; Self::connect_with_socket(self.addr.clone(), self.config.clone(), socket, addr).await } } @@ -723,29 +715,19 @@ impl super::TunnelConnector for WgTunnelConnector { }; let futures = FuturesUnordered::new(); for bind_addr in bind_addrs.into_iter() { - let socket2_socket = socket2::Socket::new( - socket2::Domain::for_address(bind_addr), - socket2::Type::DGRAM, - Some(socket2::Protocol::UDP), - )?; - if let Err(e) = setup_socket2(&socket2_socket, &bind_addr, true) { - tracing::error!(bind_addr = ?bind_addr, ?addr, "bind addr fail: {:?}", e); - continue; - } - let socket = match UdpSocket::from_std(socket2_socket.into()) { - Ok(s) => s, - Err(e) => { - tracing::error!(bind_addr = ?bind_addr, ?addr, "create udp socket fail: {:?}", e); + tracing::info!(?bind_addr, ?addr, "bind addr"); + match bind().addr(bind_addr).only_v6(true).call() { + Ok(socket) => futures.push(Self::connect_with_socket( + self.addr.clone(), + self.config.clone(), + socket, + addr, + )), + Err(error) => { + tracing::error!(?error, ?bind_addr, ?addr, "bind addr fail"); continue; } - }; - tracing::info!(?bind_addr, ?self.addr, "prepare wg connect task"); - futures.push(Self::connect_with_socket( - self.addr.clone(), - self.config.clone(), - socket, - addr, - )); + } } wait_for_connect_futures(futures).await From ec7ddd3bad1b95315b509a23a643d21b4a8db9cc Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:18:54 +0200 Subject: [PATCH 16/24] fix: filter overlapped proxy cidrs in ProxyCidrsMonitor (#2079) * feat(route): add async methods to list proxy CIDRs for IPv4 and IPv6 * refactor(ProxyCidrsMonitor): get proxy cidrs from list_proxy_cidrs --- easytier/src/instance/proxy_cidrs_monitor.rs | 36 ++++++++------------ easytier/src/peers/peer_manager.rs | 19 +++++++---- easytier/src/peers/peer_ospf_route.rs | 20 +++++++++++ easytier/src/peers/route_trait.rs | 21 ++++++++++-- 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/easytier/src/instance/proxy_cidrs_monitor.rs b/easytier/src/instance/proxy_cidrs_monitor.rs index 2e03c138..3ae5c3f5 100644 --- a/easytier/src/instance/proxy_cidrs_monitor.rs +++ b/easytier/src/instance/proxy_cidrs_monitor.rs @@ -32,35 +32,27 @@ impl ProxyCidrsMonitor { Vec, Vec, ) { - // Collect proxy_cidrs from routes - let mut proxy_cidrs = BTreeSet::new(); - let routes = peer_mgr.list_routes().await; - for r in routes { - for cidr in r.proxy_cidrs { - let Ok(cidr) = cidr.parse::() else { - continue; - }; - proxy_cidrs.insert(cidr); + let proxy_cidrs = if let Some(routes) = global_ctx.config.get_routes() { + // If manual routes exist, override entire proxy_cidrs + routes.into_iter().collect() + } else { + // Collect proxy_cidrs from routes + let mut proxy_cidrs = peer_mgr.list_proxy_cidrs().await; + + // Add VPN portal cidr to proxy_cidrs + if let Some(vpn_cfg) = global_ctx.config.get_vpn_portal_config() { + proxy_cidrs.insert(vpn_cfg.client_cidr); } - } - // Add VPN portal cidr to proxy_cidrs - if let Some(vpn_cfg) = global_ctx.config.get_vpn_portal_config() { - proxy_cidrs.insert(vpn_cfg.client_cidr); - } - - // If has manual routes, override entire proxy_cidrs - if let Some(routes) = global_ctx.config.get_routes() { - proxy_cidrs = routes.into_iter().collect(); - } + proxy_cidrs + }; // Calculate diff if cur_proxy_cidrs == &proxy_cidrs { return (proxy_cidrs, Vec::new(), Vec::new()); } - let added: Vec = proxy_cidrs.difference(cur_proxy_cidrs).cloned().collect(); - let removed: Vec = - cur_proxy_cidrs.difference(&proxy_cidrs).cloned().collect(); + let added = proxy_cidrs.difference(cur_proxy_cidrs).cloned().collect(); + let removed = cur_proxy_cidrs.difference(&proxy_cidrs).cloned().collect(); (proxy_cidrs, added, removed) } diff --git a/easytier/src/peers/peer_manager.rs b/easytier/src/peers/peer_manager.rs index 8379cad6..e428aeb8 100644 --- a/easytier/src/peers/peer_manager.rs +++ b/easytier/src/peers/peer_manager.rs @@ -1,3 +1,8 @@ +use anyhow::Context; +use async_trait::async_trait; +use cidr::{Ipv4Cidr, Ipv6Cidr}; +use dashmap::DashMap; +use std::collections::BTreeSet; use std::{ fmt::Debug, net::{IpAddr, Ipv4Addr, Ipv6Addr}, @@ -5,11 +10,6 @@ use std::{ time::{Duration, Instant, SystemTime}, }; -use anyhow::Context; -use async_trait::async_trait; - -use dashmap::DashMap; - use tokio::{ sync::{ Mutex, RwLock, @@ -1254,6 +1254,14 @@ impl PeerManager { self.get_route().get_peer_info_last_update_time().await } + pub async fn list_proxy_cidrs(&self) -> BTreeSet { + self.get_route().list_proxy_cidrs().await + } + + pub async fn list_proxy_cidrs_v6(&self) -> BTreeSet { + self.get_route().list_proxy_cidrs_v6().await + } + pub async fn dump_route(&self) -> String { self.get_route().dump().await } @@ -1985,7 +1993,6 @@ impl PeerManager { #[cfg(test)] mod tests { - use std::{ fmt::Debug, sync::Arc, diff --git a/easytier/src/peers/peer_ospf_route.rs b/easytier/src/peers/peer_ospf_route.rs index f54841a7..193a98f9 100644 --- a/easytier/src/peers/peer_ospf_route.rs +++ b/easytier/src/peers/peer_ospf_route.rs @@ -3500,6 +3500,26 @@ impl Route for PeerRoute { routes } + async fn list_proxy_cidrs(&self) -> BTreeSet { + self.service_impl + .route_table + .cidr_peer_id_map + .load() + .iter() + .map(|(cidr, _)| *cidr) + .collect() + } + + async fn list_proxy_cidrs_v6(&self) -> BTreeSet { + self.service_impl + .route_table + .cidr_v6_peer_id_map + .load() + .iter() + .map(|(cidr, _)| *cidr) + .collect() + } + async fn get_peer_id_by_ipv4(&self, ipv4_addr: &Ipv4Addr) -> Option { let route_table = &self.service_impl.route_table; if let Some(p) = route_table.ipv4_peer_id_map.get(ipv4_addr) { diff --git a/easytier/src/peers/route_trait.rs b/easytier/src/peers/route_trait.rs index 55691132..fdddc6bf 100644 --- a/easytier/src/peers/route_trait.rs +++ b/easytier/src/peers/route_trait.rs @@ -1,10 +1,11 @@ +use cidr::{Ipv4Cidr, Ipv6Cidr}; +use dashmap::DashMap; use std::{ + collections::BTreeSet, net::{Ipv4Addr, Ipv6Addr}, sync::Arc, }; -use dashmap::DashMap; - use crate::{ common::{PeerId, global_ctx::NetworkIdentity}, proto::peer_rpc::{ @@ -86,6 +87,12 @@ pub trait Route { async fn list_routes(&self) -> Vec; + // TODO: rewrite route management, remove this + async fn list_proxy_cidrs(&self) -> BTreeSet; + + // TODO: rewrite route management, remove this + async fn list_proxy_cidrs_v6(&self) -> BTreeSet; + async fn get_peer_id_by_ipv4(&self, _ipv4: &Ipv4Addr) -> Option { None } @@ -175,6 +182,16 @@ impl Route for MockRoute { panic!("mock route") } + // TODO: rewrite route management, remove this + async fn list_proxy_cidrs(&self) -> BTreeSet { + unimplemented!() + } + + // TODO: rewrite route management, remove this + async fn list_proxy_cidrs_v6(&self) -> BTreeSet { + unimplemented!() + } + async fn get_peer_info(&self, _peer_id: PeerId) -> Option { panic!("mock route") } From 5b35c51da99a6744a86df81008486c367f047da2 Mon Sep 17 00:00:00 2001 From: KKRainbow <443152178@qq.com> Date: Mon, 13 Apr 2026 11:03:09 +0800 Subject: [PATCH 17/24] fix packet split on udp tunnel and avoid tcp proxy access rpc portal (#2107) * distinct control / data when forward packets * fix rpc split for udp tunnel * feat(easytier-web): pass public ip in validate token webhook * protect rpc port from subnet proxy --- easytier-web/src/client_manager/session.rs | 1 + easytier-web/src/webhook.rs | 1 + easytier/src/common/global_ctx.rs | 19 ++ easytier/src/common/stats_manager.rs | 10 + easytier/src/peers/foreign_network_manager.rs | 104 ++++++- easytier/src/peers/peer_manager.rs | 162 ++++++++++- easytier/src/peers/traffic_metrics.rs | 38 +-- easytier/src/proto/rpc_impl/packet.rs | 266 +++++++++++++++--- easytier/src/rpc_service/api.rs | 18 +- easytier/src/rpc_service/mod.rs | 1 + easytier/src/rpc_service/protected_port.rs | 61 ++++ 11 files changed, 602 insertions(+), 79 deletions(-) create mode 100644 easytier/src/rpc_service/protected_port.rs diff --git a/easytier-web/src/client_manager/session.rs b/easytier-web/src/client_manager/session.rs index 3a2e527f..ab0f4fb6 100644 --- a/easytier-web/src/client_manager/session.rs +++ b/easytier-web/src/client_manager/session.rs @@ -233,6 +233,7 @@ impl SessionRpcService { let webhook_req = crate::webhook::ValidateTokenRequest { token: req.user_token.clone(), machine_id: machine_id.to_string(), + public_ip: data.client_url.host_str().map(str::to_string), hostname: req.hostname.clone(), version: req.easytier_version.clone(), os_type: req.device_os.as_ref().map(|info| info.os_type.clone()), diff --git a/easytier-web/src/webhook.rs b/easytier-web/src/webhook.rs index f93a14ea..be252b11 100644 --- a/easytier-web/src/webhook.rs +++ b/easytier-web/src/webhook.rs @@ -49,6 +49,7 @@ impl WebhookConfig { pub struct ValidateTokenRequest { pub token: String, pub machine_id: String, + pub public_ip: Option, pub hostname: String, pub version: String, pub os_type: Option, diff --git a/easytier/src/common/global_ctx.rs b/easytier/src/common/global_ctx.rs index ed3a2286..b6af900b 100644 --- a/easytier/src/common/global_ctx.rs +++ b/easytier/src/common/global_ctx.rs @@ -28,6 +28,7 @@ use crate::{ common::{PeerFeatureFlag, PortForwardConfigPb}, peer_rpc::PeerGroupInfo, }, + rpc_service::protected_port, tunnel::matches_protocol, }; use crossbeam::atomic::AtomicCell; @@ -658,6 +659,7 @@ impl GlobalCtx { if dst_is_local_virtual_ip || dst_is_local_phy_ip { // if is local ip, make sure the port is not one of the listening ports self.is_port_in_running_listeners(dst_addr.port(), is_udp) + || (!is_udp && protected_port::is_protected_tcp_port(dst_addr.port())) } else { false } @@ -765,6 +767,23 @@ pub mod tests { assert!(feature_flags.is_public_server); } + #[tokio::test] + async fn should_deny_proxy_for_process_wide_rpc_port() { + protected_port::clear_protected_tcp_ports_for_test(); + protected_port::register_protected_tcp_port(15888); + + let config = TomlConfigLoader::default(); + let global_ctx = GlobalCtx::new(config); + let rpc_addr = SocketAddr::from(([127, 0, 0, 1], 15888)); + let other_tcp_addr = SocketAddr::from(([127, 0, 0, 1], 15889)); + + assert!(global_ctx.should_deny_proxy(&rpc_addr, false)); + assert!(!global_ctx.should_deny_proxy(&rpc_addr, true)); + assert!(!global_ctx.should_deny_proxy(&other_tcp_addr, false)); + + protected_port::clear_protected_tcp_ports_for_test(); + } + pub fn get_mock_global_ctx_with_network( network_identy: Option, ) -> ArcGlobalCtx { diff --git a/easytier/src/common/stats_manager.rs b/easytier/src/common/stats_manager.rs index d5355759..01f018f1 100644 --- a/easytier/src/common/stats_manager.rs +++ b/easytier/src/common/stats_manager.rs @@ -42,6 +42,8 @@ pub enum MetricName { TrafficControlBytesRxByInstance, /// Traffic bytes forwarded TrafficBytesForwarded, + /// Control-plane traffic bytes forwarded + TrafficControlBytesForwarded, /// Traffic bytes sent to self TrafficBytesSelfTx, /// Traffic bytes received from self @@ -71,6 +73,8 @@ pub enum MetricName { TrafficControlPacketsRxByInstance, /// Traffic packets forwarded TrafficPacketsForwarded, + /// Control-plane traffic packets forwarded + TrafficControlPacketsForwarded, /// Traffic packets sent to self TrafficPacketsSelfTx, /// Traffic packets received from self @@ -117,6 +121,9 @@ impl fmt::Display for MetricName { write!(f, "traffic_control_bytes_rx_by_instance") } MetricName::TrafficBytesForwarded => write!(f, "traffic_bytes_forwarded"), + MetricName::TrafficControlBytesForwarded => { + write!(f, "traffic_control_bytes_forwarded") + } MetricName::TrafficBytesSelfTx => write!(f, "traffic_bytes_self_tx"), MetricName::TrafficBytesSelfRx => write!(f, "traffic_bytes_self_rx"), MetricName::TrafficBytesForeignForwardRx => { @@ -146,6 +153,9 @@ impl fmt::Display for MetricName { write!(f, "traffic_control_packets_rx_by_instance") } MetricName::TrafficPacketsForwarded => write!(f, "traffic_packets_forwarded"), + MetricName::TrafficControlPacketsForwarded => { + write!(f, "traffic_control_packets_forwarded") + } MetricName::TrafficPacketsSelfTx => write!(f, "traffic_packets_self_tx"), MetricName::TrafficPacketsSelfRx => write!(f, "traffic_packets_self_rx"), MetricName::TrafficPacketsForeignForwardRx => { diff --git a/easytier/src/peers/foreign_network_manager.rs b/easytier/src/peers/foreign_network_manager.rs index 3edd9603..c9693e16 100644 --- a/easytier/src/peers/foreign_network_manager.rs +++ b/easytier/src/peers/foreign_network_manager.rs @@ -55,8 +55,8 @@ use super::{ relay_peer_map::RelayPeerMap, route_trait::NextHopPolicy, traffic_metrics::{ - InstanceLabelKind, LogicalTrafficMetrics, TrafficMetricRecorder, - route_peer_info_instance_id, + InstanceLabelKind, LogicalTrafficMetrics, TrafficKind, TrafficMetricRecorder, + route_peer_info_instance_id, traffic_kind, }, }; @@ -419,12 +419,19 @@ impl ForeignNetworkEntry { let label_set = LabelSet::new().with_label_type(LabelType::NetworkName(network_name.clone())); - let forward_bytes = self + let forward_data_bytes = self .stats_mgr .get_counter(MetricName::TrafficBytesForwarded, label_set.clone()); - let forward_packets = self + let forward_data_packets = self .stats_mgr .get_counter(MetricName::TrafficPacketsForwarded, label_set.clone()); + let forward_control_bytes = self + .stats_mgr + .get_counter(MetricName::TrafficControlBytesForwarded, label_set.clone()); + let forward_control_packets = self.stats_mgr.get_counter( + MetricName::TrafficControlPacketsForwarded, + label_set.clone(), + ); let rx_bytes = self .stats_mgr .get_counter(MetricName::TrafficBytesSelfRx, label_set.clone()); @@ -502,8 +509,16 @@ impl ForeignNetworkEntry { } } - forward_bytes.add(buf_len as u64); - forward_packets.inc(); + match traffic_kind(packet_type) { + TrafficKind::Data => { + forward_data_bytes.add(buf_len as u64); + forward_data_packets.inc(); + } + TrafficKind::Control => { + forward_control_bytes.add(buf_len as u64); + forward_control_packets.inc(); + } + } let gateway_peer_id = peer_map .get_gateway_peer_id(to_peer_id, NextHopPolicy::LeastHop) @@ -1293,6 +1308,11 @@ pub mod tests { MetricName::TrafficBytesForwarded, network_labels.clone(), ); + let forwarded_packets_before = metric_value( + &pm_center, + MetricName::TrafficPacketsForwarded, + network_labels.clone(), + ); let rx_bytes_before = metric_value( &pm_center, MetricName::TrafficBytesRx, @@ -1320,6 +1340,7 @@ pub mod tests { pmb_net1.my_peer_id(), PacketType::Data as u8, ); + let transit_pkt_len = transit_pkt.buf_len() as u64; pma_net1 .get_foreign_network_client() .send_msg(transit_pkt, center_peer_id) @@ -1334,7 +1355,12 @@ pub mod tests { &pm_center, MetricName::TrafficBytesForwarded, network_labels.clone(), - ) > forwarded_bytes_before + ) >= forwarded_bytes_before + transit_pkt_len + && metric_value( + &pm_center, + MetricName::TrafficPacketsForwarded, + network_labels.clone(), + ) > forwarded_packets_before } }, Duration::from_secs(5), @@ -1371,6 +1397,70 @@ pub mod tests { ); } + #[tokio::test] + async fn foreign_network_transit_control_forwarding_records_control_forwarded_metrics() { + let pm_center = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await; + let pma_net1 = create_mock_peer_manager_for_foreign_network("net1").await; + let pmb_net1 = create_mock_peer_manager_for_foreign_network("net1").await; + + connect_peer_manager(pma_net1.clone(), pm_center.clone()).await; + connect_peer_manager(pmb_net1.clone(), pm_center.clone()).await; + wait_route_appear(pma_net1.clone(), pmb_net1.clone()) + .await + .unwrap(); + + let center_peer_id = pm_center + .get_foreign_network_manager() + .get_network_peer_id("net1") + .unwrap(); + let network_labels = + LabelSet::new().with_label_type(LabelType::NetworkName("net1".to_string())); + let forwarded_bytes_before = metric_value( + &pm_center, + MetricName::TrafficControlBytesForwarded, + network_labels.clone(), + ); + let forwarded_packets_before = metric_value( + &pm_center, + MetricName::TrafficControlPacketsForwarded, + network_labels.clone(), + ); + + let mut transit_pkt = ZCPacket::new_with_payload(b"foreign-control-transit"); + transit_pkt.fill_peer_manager_hdr( + pma_net1.my_peer_id(), + pmb_net1.my_peer_id(), + PacketType::RpcReq as u8, + ); + let transit_pkt_len = transit_pkt.buf_len() as u64; + pma_net1 + .get_foreign_network_client() + .send_msg(transit_pkt, center_peer_id) + .await + .unwrap(); + + wait_for_condition( + || { + let pm_center = pm_center.clone(); + let network_labels = network_labels.clone(); + async move { + metric_value( + &pm_center, + MetricName::TrafficControlBytesForwarded, + network_labels.clone(), + ) >= forwarded_bytes_before + transit_pkt_len + && metric_value( + &pm_center, + MetricName::TrafficControlPacketsForwarded, + network_labels.clone(), + ) > forwarded_packets_before + } + }, + Duration::from_secs(5), + ) + .await; + } + #[tokio::test] async fn foreign_network_encapsulated_forwarding_records_tx_metrics() { set_global_var!(OSPF_UPDATE_MY_GLOBAL_FOREIGN_NETWORK_INTERVAL_SEC, 1); diff --git a/easytier/src/peers/peer_manager.rs b/easytier/src/peers/peer_manager.rs index e428aeb8..c2dcbc0f 100644 --- a/easytier/src/peers/peer_manager.rs +++ b/easytier/src/peers/peer_manager.rs @@ -37,8 +37,8 @@ use crate::{ recv_packet_from_chan, route_trait::{ForeignNetworkRouteInfoMap, MockRoute, NextHopPolicy, RouteInterface}, traffic_metrics::{ - InstanceLabelKind, LogicalTrafficMetrics, TrafficMetricRecorder, - route_peer_info_instance_id, + InstanceLabelKind, LogicalTrafficMetrics, TrafficKind, TrafficMetricRecorder, + route_peer_info_instance_id, traffic_kind, }, }, proto::{ @@ -888,10 +888,16 @@ impl PeerManager { stats_mgr.get_counter(MetricName::TrafficBytesSelfRx, label_set.clone()); let self_rx_packets = stats_mgr.get_counter(MetricName::TrafficPacketsSelfRx, label_set.clone()); - let forward_tx_bytes = + let forward_data_tx_bytes = stats_mgr.get_counter(MetricName::TrafficBytesForwarded, label_set.clone()); - let forward_tx_packets = + let forward_data_tx_packets = stats_mgr.get_counter(MetricName::TrafficPacketsForwarded, label_set.clone()); + let forward_control_tx_bytes = + stats_mgr.get_counter(MetricName::TrafficControlBytesForwarded, label_set.clone()); + let forward_control_tx_packets = stats_mgr.get_counter( + MetricName::TrafficControlPacketsForwarded, + label_set.clone(), + ); let compress_tx_bytes_before = self.self_tx_counters.compress_tx_bytes_before.clone(); let compress_tx_bytes_after = self.self_tx_counters.compress_tx_bytes_after.clone(); @@ -966,8 +972,16 @@ impl PeerManager { self_tx_bytes.add(ret.buf_len() as u64); self_tx_packets.inc(); } else { - forward_tx_bytes.add(buf_len as u64); - forward_tx_packets.inc(); + match traffic_kind(packet_type) { + TrafficKind::Data => { + forward_data_tx_bytes.add(buf_len as u64); + forward_data_tx_packets.inc(); + } + TrafficKind::Control => { + forward_control_tx_bytes.add(buf_len as u64); + forward_control_tx_packets.inc(); + } + } } tracing::trace!(?to_peer_id, ?my_peer_id, "need forward"); @@ -2053,6 +2067,12 @@ mod tests { .unwrap_or(0) } + fn network_labels(peer_mgr: &PeerManager) -> LabelSet { + LabelSet::new().with_label_type(LabelType::NetworkName( + peer_mgr.get_global_ctx().get_network_name(), + )) + } + #[test] fn recent_traffic_fanout_policy_only_marks_single_peer() { assert!(PeerManager::should_mark_recent_traffic_for_fanout(0)); @@ -2439,6 +2459,136 @@ mod tests { ); } + #[tokio::test] + async fn send_msg_internal_records_data_forwarded_metrics_for_transit_peer() { + let peer_mgr_a = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await; + let peer_mgr_b = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await; + let peer_mgr_c = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await; + + connect_peer_manager(peer_mgr_a.clone(), peer_mgr_b.clone()).await; + connect_peer_manager(peer_mgr_b.clone(), peer_mgr_c.clone()).await; + wait_route_appear(peer_mgr_a.clone(), peer_mgr_c.clone()) + .await + .unwrap(); + + let b_network_labels = network_labels(&peer_mgr_b); + let forwarded_bytes_before = metric_value( + &peer_mgr_b, + MetricName::TrafficBytesForwarded, + &b_network_labels, + ); + let forwarded_packets_before = metric_value( + &peer_mgr_b, + MetricName::TrafficPacketsForwarded, + &b_network_labels, + ); + + let mut pkt = ZCPacket::new_with_payload(b"forward-data"); + pkt.fill_peer_manager_hdr( + peer_mgr_a.my_peer_id(), + peer_mgr_c.my_peer_id(), + PacketType::Data as u8, + ); + let pkt_len = pkt.buf_len() as u64; + + PeerManager::send_msg_internal( + &peer_mgr_a.peers, + &peer_mgr_a.foreign_network_client, + &peer_mgr_a.relay_peer_map, + Some(&peer_mgr_a.traffic_metrics), + pkt, + peer_mgr_c.my_peer_id(), + ) + .await + .unwrap(); + + wait_for_condition( + || { + let peer_mgr_b = peer_mgr_b.clone(); + let b_network_labels = b_network_labels.clone(); + async move { + metric_value( + &peer_mgr_b, + MetricName::TrafficBytesForwarded, + &b_network_labels, + ) >= forwarded_bytes_before + pkt_len + && metric_value( + &peer_mgr_b, + MetricName::TrafficPacketsForwarded, + &b_network_labels, + ) > forwarded_packets_before + } + }, + Duration::from_secs(5), + ) + .await; + } + + #[tokio::test] + async fn send_msg_internal_records_control_forwarded_metrics_for_transit_peer() { + let peer_mgr_a = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await; + let peer_mgr_b = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await; + let peer_mgr_c = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await; + + connect_peer_manager(peer_mgr_a.clone(), peer_mgr_b.clone()).await; + connect_peer_manager(peer_mgr_b.clone(), peer_mgr_c.clone()).await; + wait_route_appear(peer_mgr_a.clone(), peer_mgr_c.clone()) + .await + .unwrap(); + + let b_network_labels = network_labels(&peer_mgr_b); + let forwarded_bytes_before = metric_value( + &peer_mgr_b, + MetricName::TrafficControlBytesForwarded, + &b_network_labels, + ); + let forwarded_packets_before = metric_value( + &peer_mgr_b, + MetricName::TrafficControlPacketsForwarded, + &b_network_labels, + ); + + let mut pkt = ZCPacket::new_with_payload(b"forward-control"); + pkt.fill_peer_manager_hdr( + peer_mgr_a.my_peer_id(), + peer_mgr_c.my_peer_id(), + PacketType::RpcReq as u8, + ); + let pkt_len = pkt.buf_len() as u64; + + PeerManager::send_msg_internal( + &peer_mgr_a.peers, + &peer_mgr_a.foreign_network_client, + &peer_mgr_a.relay_peer_map, + Some(&peer_mgr_a.traffic_metrics), + pkt, + peer_mgr_c.my_peer_id(), + ) + .await + .unwrap(); + + wait_for_condition( + || { + let peer_mgr_b = peer_mgr_b.clone(); + let b_network_labels = b_network_labels.clone(); + async move { + metric_value( + &peer_mgr_b, + MetricName::TrafficControlBytesForwarded, + &b_network_labels, + ) >= forwarded_bytes_before + pkt_len + && metric_value( + &peer_mgr_b, + MetricName::TrafficControlPacketsForwarded, + &b_network_labels, + ) > forwarded_packets_before + } + }, + Duration::from_secs(5), + ) + .await; + } + #[tokio::test] async fn recent_traffic_tolerates_future_timestamps() { let peer_mgr_a = create_lazy_peer_manager().await; diff --git a/easytier/src/peers/traffic_metrics.rs b/easytier/src/peers/traffic_metrics.rs index a75006b8..ecd5c5d4 100644 --- a/easytier/src/peers/traffic_metrics.rs +++ b/easytier/src/peers/traffic_metrics.rs @@ -220,12 +220,27 @@ impl LogicalTrafficMetrics { } } -#[derive(Clone, Copy)] -enum TrafficKind { +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum TrafficKind { Data, Control, } +pub(crate) fn traffic_kind(packet_type: u8) -> TrafficKind { + if packet_type == PacketType::Data as u8 + || packet_type == PacketType::KcpSrc as u8 + || packet_type == PacketType::KcpDst as u8 + || packet_type == PacketType::QuicSrc as u8 + || packet_type == PacketType::QuicDst as u8 + || packet_type == PacketType::DataWithKcpSrcModified as u8 + || packet_type == PacketType::DataWithQuicSrcModified as u8 + { + TrafficKind::Data + } else { + TrafficKind::Control + } +} + #[derive(Clone)] struct TrafficMetricGroup { data: Arc, @@ -282,7 +297,7 @@ impl TrafficMetricRecorder { return; } self.tx_metrics - .select(Self::traffic_kind(packet_type)) + .select(traffic_kind(packet_type)) .record_with_resolver(peer_id, bytes, || self.resolve_instance_id(peer_id)) .await; } @@ -292,7 +307,7 @@ impl TrafficMetricRecorder { return; } self.rx_metrics - .select(Self::traffic_kind(packet_type)) + .select(traffic_kind(packet_type)) .record_with_resolver(peer_id, bytes, || self.resolve_instance_id(peer_id)) .await; } @@ -314,21 +329,6 @@ impl TrafficMetricRecorder { fn resolve_instance_id(&self, peer_id: PeerId) -> BoxFuture<'static, Option> { (self.resolve_instance_id)(peer_id) } - - fn traffic_kind(packet_type: u8) -> TrafficKind { - if packet_type == PacketType::Data as u8 - || packet_type == PacketType::KcpSrc as u8 - || packet_type == PacketType::KcpDst as u8 - || packet_type == PacketType::QuicSrc as u8 - || packet_type == PacketType::QuicDst as u8 - || packet_type == PacketType::DataWithKcpSrcModified as u8 - || packet_type == PacketType::DataWithQuicSrcModified as u8 - { - TrafficKind::Data - } else { - TrafficKind::Control - } - } } pub(crate) fn route_peer_info_instance_id(route_peer_info: &RoutePeerInfo) -> Option { diff --git a/easytier/src/proto/rpc_impl/packet.rs b/easytier/src/proto/rpc_impl/packet.rs index 4f8b62b7..a03085df 100644 --- a/easytier/src/proto/rpc_impl/packet.rs +++ b/easytier/src/proto/rpc_impl/packet.rs @@ -1,4 +1,4 @@ -use prost::Message as _; +use prost::{Message as _, length_delimiter_len}; use crate::{ common::{PeerId, compressor::DefaultCompressor}, @@ -6,12 +6,15 @@ use crate::{ common::{CompressionAlgoPb, RpcCompressionInfo, RpcDescriptor, RpcPacket}, rpc_types::error::Error, }, - tunnel::packet_def::{CompressorAlgo, PacketType, ZCPacket}, + tunnel::packet_def::{CompressorAlgo, PacketType, TAIL_RESERVED_SIZE, ZCPacket, ZCPacketType}, }; use super::RpcTransactId; -const RPC_PACKET_CONTENT_MTU: usize = 1300; +// Budget the final UDP payload size on the wire for peer RPC over `udp://`. +// This includes EasyTier's UDP tunnel header, peer header, and reserved tail +// space for encryption/compression metadata, but excludes the outer IP header. +const RPC_PACKET_UDP_PAYLOAD_BUDGET: usize = 1300; pub async fn compress_packet( accepted_compression_algo: CompressionAlgoPb, @@ -150,44 +153,166 @@ pub struct BuildRpcPacketArgs<'a> { pub compression_info: RpcCompressionInfo, } +// Fixed transport overhead for peer RPC carried by EasyTier's UDP tunnel: +// +// UDP payload budget +// +-------------------------------------------------------------------------+ +// | EasyTier UDP tunnel hdr | PeerManager hdr | RpcPacket bytes | tail room | +// +-------------------------------------------------------------------------+ +// |<------ ZCPacketType::UDP payload_offset ------>|<-- TAIL_RESERVED_SIZE -->| +// +// `udp_rpc_tunnel_overhead()` is everything except `RpcPacket bytes`. +fn udp_rpc_tunnel_overhead() -> usize { + ZCPacketType::UDP.get_packet_offsets().payload_offset + TAIL_RESERVED_SIZE +} + +// Maximum encoded RpcPacket size we can admit before adding it to a UDP tunnel. +// This budget excludes the outer UDP/IP headers because the caller only controls +// the EasyTier payload carried inside the UDP datagram. +fn max_rpc_packet_encoded_len_for_udp() -> usize { + RPC_PACKET_UDP_PAYLOAD_BUDGET.saturating_sub(udp_rpc_tunnel_overhead()) +} + +// Build one logical RpcPacket piece. This is reused both for the actual output +// packets and for sizing templates that estimate worst-case protobuf overhead. +fn build_rpc_piece( + args: &BuildRpcPacketArgs<'_>, + total_pieces: u32, + piece_idx: u32, + body: &[u8], +) -> RpcPacket { + RpcPacket { + from_peer: args.from_peer, + to_peer: args.to_peer, + descriptor: if piece_idx == 0 + || args.compression_info.algo == CompressionAlgoPb::None as i32 + { + // old version must have descriptor on every piece + Some(args.rpc_desc.clone()) + } else { + None + }, + is_request: args.is_req, + total_pieces, + piece_idx, + transaction_id: args.transaction_id, + body: body.to_vec(), + trace_id: args.trace_id, + compression_info: if piece_idx == 0 { + Some(args.compression_info) + } else { + None + }, + } +} + +fn pick_piece_len_for_budget( + base_encoded_len_without_body: usize, + remaining: usize, + max_encoded_len: usize, +) -> usize { + if remaining == 0 { + return 0; + } + + // Minimum non-empty body field encoding cost: + // body tag (1 byte) + body length (1 byte) + body data (1 byte) + if base_encoded_len_without_body + 3 > max_encoded_len { + tracing::warn!( + base_encoded_len_without_body, + max_encoded_len, + "rpc metadata exceeds udp payload budget; falling back to a minimal piece" + ); + return 1; + } + + // `budget` is what remains for the protobuf `body` field after all fixed + // RpcPacket metadata has been accounted for. + let budget = max_encoded_len - base_encoded_len_without_body; + // Reserve the bytes field wrapper conservatively, then use the rest for + // the body itself. + // + // Encoded RpcPacket layout relevant to `body`: + // + // +------------------------------- max_encoded_len -------------------------------+ + // | fixed RpcPacket fields | body tag (1B) | body len varint (worst-case) | body | + // +--------------------------------------------------------------------------- --+ + // ^ ^ + // | `- reserve by using the varint width of `budget` + // `- base_encoded_len_without_body + // + // This is intentionally conservative. A few bytes may be left unused, but + // every piece stays within the UDP payload budget without iterative sizing. + let reserved_for_body_header = 1 + length_delimiter_len(budget); + remaining + .min(budget.saturating_sub(reserved_for_body_header)) + .max(1) +} + +// Pre-split the raw RPC content using conservative worst-case protobuf sizing. +// We compute separate base sizes for the first piece and later pieces because +// only the first piece carries `compression_info`, and old compatibility rules +// may also force `descriptor` to appear on every piece. +// +// Split flow: +// +// raw RPC content +// +--------------------------------------------------------------+ +// | args.content | +// +--------------------------------------------------------------+ +// | first piece uses first_piece_base_len +// | later pieces use other_piece_base_len +// v +// +-----------+-----------+-----------+----- ... +// | offset,len| offset,len| offset,len| +// +-----------+-----------+-----------+----- ... +// +// The result is only a slicing plan. Actual RpcPacket objects are built later +// with the real `total_pieces`. +fn split_rpc_content_for_udp_budget(args: &BuildRpcPacketArgs<'_>) -> Vec<(usize, usize)> { + if args.content.is_empty() { + return vec![(0, 0)]; + } + + let max_encoded_len = max_rpc_packet_encoded_len_for_udp().max(1); + // Use the worst-case varint width for piece counters so the budget remains + // valid without iterating on `total_pieces`/`piece_idx`. + let first_piece_base_len = build_rpc_piece(args, u32::MAX, 0, &[]).encoded_len(); + let other_piece_base_len = build_rpc_piece(args, u32::MAX, u32::MAX, &[]).encoded_len(); + + let mut pieces = Vec::new(); + let mut offset = 0usize; + while offset < args.content.len() { + // First and subsequent pieces have different metadata shapes, so they + // use different fixed-size templates. + let base_len = if pieces.is_empty() { + first_piece_base_len + } else { + other_piece_base_len + }; + let piece_len = + pick_piece_len_for_budget(base_len, args.content.len() - offset, max_encoded_len); + pieces.push((offset, piece_len)); + offset += piece_len; + } + + pieces +} + +// Build the final transport packets after the payload has been split. We do the +// actual `total_pieces` assignment only here so the wire packet stays accurate, +// while the earlier sizing step remains simple and conservatively safe. pub fn build_rpc_packet(args: BuildRpcPacketArgs<'_>) -> Vec { let mut ret = Vec::new(); - let content_mtu = RPC_PACKET_CONTENT_MTU; - let total_pieces = args.content.len().div_ceil(content_mtu); - let mut cur_offset = 0; - while cur_offset < args.content.len() || args.content.is_empty() { - let mut cur_len = content_mtu; - if cur_offset + cur_len > args.content.len() { - cur_len = args.content.len() - cur_offset; - } - - let mut cur_content = Vec::new(); - cur_content.extend_from_slice(&args.content[cur_offset..cur_offset + cur_len]); - - let cur_packet = RpcPacket { - from_peer: args.from_peer, - to_peer: args.to_peer, - descriptor: if cur_offset == 0 - || args.compression_info.algo == CompressionAlgoPb::None as i32 - { - // old version must have descriptor on every piece - Some(args.rpc_desc.clone()) - } else { - None - }, - is_request: args.is_req, - total_pieces: total_pieces as u32, - piece_idx: (cur_offset / RPC_PACKET_CONTENT_MTU) as u32, - transaction_id: args.transaction_id, - body: cur_content, - trace_id: args.trace_id, - compression_info: if cur_offset == 0 { - Some(args.compression_info) - } else { - None - }, - }; - cur_offset += cur_len; + let pieces = split_rpc_content_for_udp_budget(&args); + let total_pieces = pieces.len() as u32; + for (piece_idx, (offset, len)) in pieces.into_iter().enumerate() { + let cur_packet = build_rpc_piece( + &args, + total_pieces, + piece_idx as u32, + &args.content[offset..offset + len], + ); let packet_type = if args.is_req { PacketType::RpcReq @@ -200,11 +325,66 @@ pub fn build_rpc_packet(args: BuildRpcPacketArgs<'_>) -> Vec { let mut zc_packet = ZCPacket::new_with_payload(&buf); zc_packet.fill_peer_manager_hdr(args.from_peer, args.to_peer, packet_type as u8); ret.push(zc_packet); - - if args.content.is_empty() { - break; - } } ret } + +#[cfg(test)] +mod tests { + use super::*; + + fn build_test_args<'a>( + content: &'a [u8], + compression_algo: CompressionAlgoPb, + ) -> BuildRpcPacketArgs<'a> { + BuildRpcPacketArgs { + from_peer: 11, + to_peer: 22, + rpc_desc: RpcDescriptor { + domain_name: "very-long-domain-name-for-rpc-packet-budget-check".repeat(2), + proto_name: "extremely.verbose.proto.name.for.rpc.packet.tests".repeat(2), + service_name: "LargeMetadataServiceForRpcPacketBudget".repeat(2), + method_index: 7, + }, + transaction_id: 33, + is_req: true, + content, + trace_id: 44, + compression_info: RpcCompressionInfo { + algo: compression_algo.into(), + accepted_algo: CompressionAlgoPb::Zstd.into(), + }, + } + } + + fn udp_packet_size_after_tail(packet: &ZCPacket) -> usize { + ZCPacketType::UDP.get_packet_offsets().payload_offset + + packet.payload_len() + + TAIL_RESERVED_SIZE + } + + #[test] + fn build_rpc_packet_respects_udp_budget_with_large_metadata() { + let content = vec![0x5a; 4096]; + let packets = build_rpc_packet(build_test_args(&content, CompressionAlgoPb::None)); + + assert!(packets.len() > 1); + for packet in packets { + assert!( + udp_packet_size_after_tail(&packet) <= RPC_PACKET_UDP_PAYLOAD_BUDGET, + "packet size {} exceeded budget {}", + udp_packet_size_after_tail(&packet), + RPC_PACKET_UDP_PAYLOAD_BUDGET + ); + } + } + + #[test] + fn build_rpc_packet_respects_udp_budget_for_empty_payload() { + let packets = build_rpc_packet(build_test_args(&[], CompressionAlgoPb::Zstd)); + + assert_eq!(1, packets.len()); + assert!(udp_packet_size_after_tail(&packets[0]) <= RPC_PACKET_UDP_PAYLOAD_BUDGET); + } +} diff --git a/easytier/src/rpc_service/api.rs b/easytier/src/rpc_service/api.rs index 77aafd0d..4aedca31 100644 --- a/easytier/src/rpc_service/api.rs +++ b/easytier/src/rpc_service/api.rs @@ -27,8 +27,8 @@ use crate::{ instance_manage::InstanceManageRpcService, logger::LoggerRpcService, mapped_listener_manage::MappedListenerManageRpcService, peer_center::PeerCenterManageRpcService, peer_manage::PeerManageRpcService, - port_forward_manage::PortForwardManageRpcService, proxy::TcpProxyRpcService, - stats::StatsRpcService, vpn_portal::VpnPortalRpcService, + port_forward_manage::PortForwardManageRpcService, protected_port, + proxy::TcpProxyRpcService, stats::StatsRpcService, vpn_portal::VpnPortalRpcService, }, tunnel::{TunnelListener, tcp::TcpTunnelListener}, web_client::{DefaultHooks, WebClientHooks}, @@ -36,6 +36,7 @@ use crate::{ pub struct ApiRpcServer { rpc_server: StandAloneServer, + protected_tcp_port: Option, } impl ApiRpcServer { @@ -44,14 +45,17 @@ impl ApiRpcServer { rpc_portal_whitelist: Option>, instance_manager: Arc, ) -> anyhow::Result { + let rpc_addr = parse_rpc_portal(rpc_portal)?; let mut server = Self::from_tunnel( TcpTunnelListener::new( - format!("tcp://{}", parse_rpc_portal(rpc_portal)?) + format!("tcp://{}", rpc_addr) .parse() .context("failed to parse rpc portal address")?, ), instance_manager, ); + protected_port::register_protected_tcp_port(rpc_addr.port()); + server.protected_tcp_port = Some(rpc_addr.port()); server .rpc_server @@ -65,7 +69,10 @@ impl ApiRpcServer { pub fn from_tunnel(tunnel: T, instance_manager: Arc) -> Self { let rpc_server = StandAloneServer::new(tunnel); register_api_rpc_service(&instance_manager, rpc_server.registry(), None); - Self { rpc_server } + Self { + rpc_server, + protected_tcp_port: None, + } } } @@ -83,6 +90,9 @@ impl ApiRpcServer { impl Drop for ApiRpcServer { fn drop(&mut self) { + if let Some(port) = self.protected_tcp_port.take() { + protected_port::unregister_protected_tcp_port(port); + } self.rpc_server.registry().unregister_all(); } } diff --git a/easytier/src/rpc_service/mod.rs b/easytier/src/rpc_service/mod.rs index a51cd987..b9af8285 100644 --- a/easytier/src/rpc_service/mod.rs +++ b/easytier/src/rpc_service/mod.rs @@ -6,6 +6,7 @@ mod mapped_listener_manage; mod peer_center; mod peer_manage; mod port_forward_manage; +pub(crate) mod protected_port; mod proxy; mod stats; mod vpn_portal; diff --git a/easytier/src/rpc_service/protected_port.rs b/easytier/src/rpc_service/protected_port.rs new file mode 100644 index 00000000..b44216b5 --- /dev/null +++ b/easytier/src/rpc_service/protected_port.rs @@ -0,0 +1,61 @@ +use std::collections::HashMap; +use std::sync::Mutex; + +use once_cell::sync::Lazy; + +static PROTECTED_TCP_PORTS: Lazy>> = + Lazy::new(|| Mutex::new(HashMap::new())); + +pub fn register_protected_tcp_port(port: u16) { + let mut ports = PROTECTED_TCP_PORTS.lock().unwrap(); + *ports.entry(port).or_default() += 1; +} + +pub fn unregister_protected_tcp_port(port: u16) { + let mut ports = PROTECTED_TCP_PORTS.lock().unwrap(); + if let Some(ref_count) = ports.get_mut(&port) { + *ref_count -= 1; + if *ref_count == 0 { + ports.remove(&port); + } + } +} + +pub fn is_protected_tcp_port(port: u16) -> bool { + PROTECTED_TCP_PORTS.lock().unwrap().contains_key(&port) +} + +#[cfg(test)] +pub fn clear_protected_tcp_ports_for_test() { + PROTECTED_TCP_PORTS.lock().unwrap().clear(); +} + +#[cfg(test)] +mod tests { + use super::{ + clear_protected_tcp_ports_for_test, is_protected_tcp_port, register_protected_tcp_port, + unregister_protected_tcp_port, + }; + + #[test] + fn protected_tcp_port_registry_is_ref_counted() { + clear_protected_tcp_ports_for_test(); + + register_protected_tcp_port(15888); + register_protected_tcp_port(15888); + assert!(is_protected_tcp_port(15888)); + + unregister_protected_tcp_port(15888); + assert!(is_protected_tcp_port(15888)); + + unregister_protected_tcp_port(15888); + assert!(!is_protected_tcp_port(15888)); + } + + #[test] + fn unregistering_unknown_port_is_a_noop() { + clear_protected_tcp_ports_for_test(); + unregister_protected_tcp_port(15888); + assert!(!is_protected_tcp_port(15888)); + } +} From 1cfc135df3aab4a4e7660276ebc73fe2195b1e50 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Tue, 14 Apr 2026 06:35:05 +0200 Subject: [PATCH 18/24] ci: remove -D warnings from test (#2109) Co-authored-by: KKRainbow <443152178@qq.com> --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index df1c490a..45f345f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,6 +54,7 @@ jobs: - uses: actions-rust-lang/setup-rust-toolchain@v1 with: components: rustfmt,clippy + rustflags: '' - uses: taiki-e/install-action@cargo-hack From 3a4ac5946710461a527b33231c662295a8b2824f Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Tue, 14 Apr 2026 12:10:38 +0200 Subject: [PATCH 19/24] log: change default log level of tests to WARNING (#2113) --- easytier/src/common/log.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easytier/src/common/log.rs b/easytier/src/common/log.rs index e546b5a2..5657aa9b 100644 --- a/easytier/src/common/log.rs +++ b/easytier/src/common/log.rs @@ -274,7 +274,7 @@ mod tests { #[ctor::ctor] fn init() { let _ = Registry::default() - .with(console_layers(Some(LevelFilter::DEBUG)).unwrap()) + .with(console_layers(Some(LevelFilter::WARN)).unwrap()) .try_init(); } From 3687519ef3c0aafe5a49d7e480fcaffc38116f53 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Wed, 15 Apr 2026 13:38:27 +0200 Subject: [PATCH 20/24] turn off ansi for file log (#2110) Co-authored-by: KKRainbow <443152178@qq.com> --- easytier/src/common/log.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/easytier/src/common/log.rs b/easytier/src/common/log.rs index 5657aa9b..dceab889 100644 --- a/easytier/src/common/log.rs +++ b/easytier/src/common/log.rs @@ -76,7 +76,6 @@ macro_rules! log_layer { $layer .with_file(false) .with_line_number(false) - .with_ansi(true) .with_filter(filter_fn(is_log)) .boxed() }; From 6d319cba1dea4518e82224a8b74bb47a01bf0f1f Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Wed, 15 Apr 2026 13:39:00 +0200 Subject: [PATCH 21/24] tests(relay_peer_e2e_encryption): wait for the key of inst3 before ping test (#2069) --- easytier/src/tests/three_node.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/easytier/src/tests/three_node.rs b/easytier/src/tests/three_node.rs index 8436c0a3..5832771f 100644 --- a/easytier/src/tests/three_node.rs +++ b/easytier/src/tests/three_node.rs @@ -3150,6 +3150,20 @@ pub async fn relay_peer_e2e_encryption(#[values("tcp", "udp")] proto: &str) { .map(|i| i.noise_static_pubkey.len()) ); + // Wait until relay route info includes inst3 static pubkey for IK handshake. + wait_for_condition( + || async { + insts[0] + .get_peer_manager() + .get_peer_map() + .get_route_peer_info(inst3_peer_id) + .await + .is_some_and(|info| !info.noise_static_pubkey.is_empty()) + }, + Duration::from_secs(10), + ) + .await; + // Test basic connectivity through relay println!("Starting ping test from net_a to 10.144.144.3..."); From 2ef3b722241a93bcbb5402ed7abecfd2a5315be5 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Wed, 15 Apr 2026 13:39:24 +0200 Subject: [PATCH 22/24] proto: add some conversion for Url (#2067) --- easytier/src/proto/common.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/easytier/src/proto/common.rs b/easytier/src/proto/common.rs index 89473192..067560ce 100644 --- a/easytier/src/proto/common.rs +++ b/easytier/src/proto/common.rs @@ -257,15 +257,21 @@ impl FromStr for IpInet { impl From for Url { fn from(value: url::Url) -> Self { - Url { - url: value.to_string(), - } + Url { url: value.into() } + } +} + +impl TryFrom<&Url> for url::Url { + type Error = url::ParseError; + + fn try_from(value: &Url) -> Result { + value.url.parse() } } impl From for url::Url { fn from(value: Url) -> Self { - url::Url::parse(&value.url).unwrap() + (&value).try_into().expect("failed to parse url") } } @@ -273,9 +279,7 @@ impl FromStr for Url { type Err = url::ParseError; fn from_str(s: &str) -> Result { - Ok(Url { - url: s.parse::()?.to_string(), - }) + url::Url::try_from(s).map(Into::into) } } From 82ca04a8a7e22d1b3526b6365d5289b657ef68b7 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Wed, 15 Apr 2026 13:40:09 +0200 Subject: [PATCH 23/24] proto(utils): add MessageModel & RepeatedMessageModel (#2068) * add FromIterator, Extend, AsRef, AsMut, TryFrom<[Message]> --- easytier/Cargo.toml | 1 + easytier/src/proto/utils.rs | 93 +++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 9594d135..cfa67e98 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -51,6 +51,7 @@ toml = "0.8.12" chrono = { version = "0.4.37", features = ["serde"] } cfg-if = "1.0" +delegate = "0.13.5" itertools = "0.14.0" diff --git a/easytier/src/proto/utils.rs b/easytier/src/proto/utils.rs index c75e57c2..c9ab016e 100644 --- a/easytier/src/proto/utils.rs +++ b/easytier/src/proto/utils.rs @@ -1,4 +1,8 @@ +use delegate::delegate; +use derivative::Derivative; +use derive_more::{Deref, DerefMut, From, IntoIterator}; use prost::Message; +use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; /// Generates a stable digest strictly within the lifecycle of the current process. @@ -18,3 +22,92 @@ pub trait TransientDigest: Message { } impl TransientDigest for S {} + +pub trait MessageModel: + Into + for<'m> TryFrom<&'m Message> +{ +} + +impl MessageModel for Model +where + Message: prost::Message, + Model: Into + for<'m> TryFrom<&'m Message>, +{ +} + +#[derive( + Derivative, + Debug, + Clone, + PartialEq, + Eq, + Hash, + From, + Deref, + DerefMut, + Serialize, + Deserialize, + IntoIterator, +)] +#[derivative(Default(bound = ""))] +#[serde(transparent)] +#[into_iterator(owned, ref, ref_mut)] +pub struct RepeatedMessageModel(Vec); + +impl RepeatedMessageModel { + pub fn into_inner(self) -> Vec { + self.0 + } +} + +impl FromIterator for RepeatedMessageModel { + fn from_iter>(iter: I) -> Self { + Self(iter.into_iter().collect()) + } +} + +impl Extend for RepeatedMessageModel { + delegate! { + to self.0 { + fn extend>(&mut self, iter: T); + } + } +} + +impl AsRef<[Model]> for RepeatedMessageModel { + delegate! { + to self.0 { + fn as_ref(&self) -> &[Model]; + } + } +} + +impl AsMut<[Model]> for RepeatedMessageModel { + delegate! { + to self.0 { + fn as_mut(&mut self) -> &mut [Model]; + } + } +} + +impl<'m, Message, Model> TryFrom<&'m [Message]> for RepeatedMessageModel +where + Message: prost::Message, + Model: MessageModel, +{ + type Error = >::Error; + + fn try_from(value: &'m [Message]) -> Result { + value.iter().map(TryInto::try_into).collect() + } +} + +impl From> for Vec +where + Message: prost::Message, + Model: MessageModel, +{ + fn from(value: RepeatedMessageModel) -> Self { + value.into_iter().map(Into::into).collect() + } +} From bcb2e512d480db94265adff9784701babaa28756 Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:32:07 +0200 Subject: [PATCH 24/24] utils: move code to a dedicated mod; add AsyncRuntime (#2072) --- easytier-gui/src-tauri/src/lib.rs | 4 +- easytier-web/src/main.rs | 2 +- easytier/src/common/ifcfg/mod.rs | 4 +- easytier/src/common/scoped_task.rs | 25 +--- easytier/src/core.rs | 2 +- easytier/src/easytier-cli.rs | 2 +- easytier/src/utils/mod.rs | 30 +++++ easytier/src/{utils.rs => utils/panic.rs} | 58 +-------- easytier/src/utils/string.rs | 26 ++++ easytier/src/utils/task.rs | 140 ++++++++++++++++++++++ 10 files changed, 211 insertions(+), 82 deletions(-) create mode 100644 easytier/src/utils/mod.rs rename easytier/src/{utils.rs => utils/panic.rs} (68%) create mode 100644 easytier/src/utils/string.rs create mode 100644 easytier/src/utils/task.rs diff --git a/easytier-gui/src-tauri/src/lib.rs b/easytier-gui/src-tauri/src/lib.rs index 2b6c613b..d4dd6a4d 100644 --- a/easytier-gui/src-tauri/src/lib.rs +++ b/easytier-gui/src-tauri/src/lib.rs @@ -24,7 +24,7 @@ use easytier::{ tunnel::TunnelListener, tunnel::ring::RingTunnelListener, tunnel::tcp::TcpTunnelListener, - utils::{self}, + utils::panic::setup_panic_handler, }; use std::ops::Deref; use std::sync::Arc; @@ -1120,7 +1120,7 @@ pub fn run_gui() -> std::process::ExitCode { process::exit(0); } - utils::setup_panic_handler(); + setup_panic_handler(); let mut builder = tauri::Builder::default(); diff --git a/easytier-web/src/main.rs b/easytier-web/src/main.rs index 6c741727..10404d3c 100644 --- a/easytier-web/src/main.rs +++ b/easytier-web/src/main.rs @@ -17,7 +17,7 @@ use easytier::{ network::{local_ipv4, local_ipv6}, }, tunnel::{TunnelListener, tcp::TcpTunnelListener, udp::UdpTunnelListener}, - utils::setup_panic_handler, + utils::panic::setup_panic_handler, }; use easytier::tunnel::IpScheme; diff --git a/easytier/src/common/ifcfg/mod.rs b/easytier/src/common/ifcfg/mod.rs index 568e71bc..a8e4085f 100644 --- a/easytier/src/common/ifcfg/mod.rs +++ b/easytier/src/common/ifcfg/mod.rs @@ -119,8 +119,8 @@ async fn run_shell_cmd(cmd: &str) -> Result<(), Error> { .creation_flags(CREATE_NO_WINDOW) .output() .await?; - stdout = crate::utils::utf8_or_gbk_to_string(cmd_out.stdout.as_slice()); - stderr = crate::utils::utf8_or_gbk_to_string(cmd_out.stderr.as_slice()); + stdout = crate::utils::string::utf8_or_gbk_to_string(cmd_out.stdout.as_slice()); + stderr = crate::utils::string::utf8_or_gbk_to_string(cmd_out.stderr.as_slice()); }; #[cfg(not(target_os = "windows"))] diff --git a/easytier/src/common/scoped_task.rs b/easytier/src/common/scoped_task.rs index 56690087..b87a1f19 100644 --- a/easytier/src/common/scoped_task.rs +++ b/easytier/src/common/scoped_task.rs @@ -4,40 +4,25 @@ //! For example, if task A spawned task B but is doing something else, and task B is waiting for task C to join, //! aborting A will also abort both B and C. +use derive_more::{Deref, DerefMut, From}; use std::future::Future; -use std::ops::Deref; use std::pin::Pin; use std::task::{Context, Poll}; use tokio::task::JoinHandle; -#[derive(Debug)] -pub struct ScopedTask { - inner: JoinHandle, -} +#[derive(Debug, From, Deref, DerefMut)] +pub struct ScopedTask(JoinHandle); impl Drop for ScopedTask { fn drop(&mut self) { - self.inner.abort() + self.abort() } } impl Future for ScopedTask { type Output = as Future>::Output; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.inner).poll(cx) - } -} - -impl From> for ScopedTask { - fn from(inner: JoinHandle) -> Self { - Self { inner } - } -} - -impl Deref for ScopedTask { - type Target = JoinHandle; - fn deref(&self) -> &Self::Target { - &self.inner + Pin::new(&mut self.0).poll(cx) } } diff --git a/easytier/src/core.rs b/easytier/src/core.rs index 218d87af..634f36bb 100644 --- a/easytier/src/core.rs +++ b/easytier/src/core.rs @@ -23,7 +23,7 @@ use crate::{ launcher::add_proxy_network_to_config, proto::common::{CompressionAlgoPb, SecureModeConfig}, rpc_service::ApiRpcServer, - utils::setup_panic_handler, + utils::panic::setup_panic_handler, web_client, }; use anyhow::Context; diff --git a/easytier/src/easytier-cli.rs b/easytier/src/easytier-cli.rs index af55343d..f18a131e 100644 --- a/easytier/src/easytier-cli.rs +++ b/easytier/src/easytier-cli.rs @@ -76,7 +76,7 @@ use easytier::{ rpc_types::controller::BaseController, }, tunnel::{TunnelScheme, tcp::TcpTunnelConnector}, - utils::{PeerRoutePair, cost_to_str}, + utils::{PeerRoutePair, string::cost_to_str}, }; rust_i18n::i18n!("locales", fallback = "en"); diff --git a/easytier/src/utils/mod.rs b/easytier/src/utils/mod.rs new file mode 100644 index 00000000..1339c10d --- /dev/null +++ b/easytier/src/utils/mod.rs @@ -0,0 +1,30 @@ +pub mod panic; +pub mod string; +pub mod task; + +use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener}; +use std::sync::{Arc, Weak}; + +pub type PeerRoutePair = crate::proto::api::instance::PeerRoutePair; + +pub fn check_tcp_available(port: u16) -> bool { + let s = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port); + TcpListener::bind(s).is_ok() +} + +pub fn find_free_tcp_port(mut range: std::ops::Range) -> Option { + range.find(|&port| check_tcp_available(port)) +} + +pub fn weak_upgrade(weak: &Weak) -> anyhow::Result> { + weak.upgrade() + .ok_or_else(|| anyhow::anyhow!("{} not available", std::any::type_name::())) +} + +pub trait BoxExt: Sized { + fn boxed(self) -> Box { + Box::new(self) + } +} + +impl BoxExt for T {} diff --git a/easytier/src/utils.rs b/easytier/src/utils/panic.rs similarity index 68% rename from easytier/src/utils.rs rename to easytier/src/utils/panic.rs index e2b35676..6421824b 100644 --- a/easytier/src/utils.rs +++ b/easytier/src/utils/panic.rs @@ -1,43 +1,14 @@ use crate::common::log; use indoc::formatdoc; -use std::sync::Arc; -use std::{fs::OpenOptions, str::FromStr}; - -pub type PeerRoutePair = crate::proto::api::instance::PeerRoutePair; - -pub fn cost_to_str(cost: i32) -> String { - if cost == 1 { - "p2p".to_string() - } else { - format!("relay({})", cost) - } -} - -pub fn float_to_str(f: f64, precision: usize) -> String { - format!("{:.1$}", f, precision) -} - -#[cfg(target_os = "windows")] -pub fn utf8_or_gbk_to_string(s: &[u8]) -> String { - use encoding::{DecoderTrap, Encoding, all::GBK}; - if let Ok(utf8_str) = String::from_utf8(s.to_vec()) { - utf8_str - } else { - // 如果解码失败,则尝试使用GBK解码 - if let Ok(gbk_str) = GBK.decode(s, DecoderTrap::Strict) { - gbk_str - } else { - String::from_utf8_lossy(s).to_string() - } - } -} +use std::fs::OpenOptions; +use std::str::FromStr; +use std::{backtrace, io::Write}; thread_local! { static PANIC_COUNT : std::cell::RefCell = const { std::cell::RefCell::new(0) }; } pub fn setup_panic_handler() { - use std::{backtrace, io::Write}; std::panic::set_hook(Box::new(|info| { let mut stderr = std::io::stderr(); let sep = format!("{}\n", "=======".repeat(10)); @@ -126,26 +97,3 @@ pub fn setup_panic_handler() { std::process::exit(1); })); } - -pub fn check_tcp_available(port: u16) -> bool { - use std::net::TcpListener; - let s = std::net::SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED), port); - TcpListener::bind(s).is_ok() -} - -pub fn find_free_tcp_port(mut range: std::ops::Range) -> Option { - range.find(|&port| check_tcp_available(port)) -} - -pub fn weak_upgrade(weak: &std::sync::Weak) -> anyhow::Result> { - weak.upgrade() - .ok_or_else(|| anyhow::anyhow!("{} not available", std::any::type_name::())) -} - -pub trait BoxExt: Sized { - fn boxed(self) -> Box { - Box::new(self) - } -} - -impl BoxExt for T {} diff --git a/easytier/src/utils/string.rs b/easytier/src/utils/string.rs new file mode 100644 index 00000000..8dab764f --- /dev/null +++ b/easytier/src/utils/string.rs @@ -0,0 +1,26 @@ +pub fn cost_to_str(cost: i32) -> String { + if cost == 1 { + "p2p".to_string() + } else { + format!("relay({})", cost) + } +} + +pub fn float_to_str(f: f64, precision: usize) -> String { + format!("{:.1$}", f, precision) +} + +#[cfg(target_os = "windows")] +pub fn utf8_or_gbk_to_string(s: &[u8]) -> String { + use encoding::{DecoderTrap, Encoding, all::GBK}; + if let Ok(utf8_str) = String::from_utf8(s.to_vec()) { + utf8_str + } else { + // 如果解码失败,则尝试使用GBK解码 + if let Ok(gbk_str) = GBK.decode(s, DecoderTrap::Strict) { + gbk_str + } else { + String::from_utf8_lossy(s).to_string() + } + } +} diff --git a/easytier/src/utils/task.rs b/easytier/src/utils/task.rs new file mode 100644 index 00000000..db25df64 --- /dev/null +++ b/easytier/src/utils/task.rs @@ -0,0 +1,140 @@ +use crate::common::scoped_task::ScopedTask; +use derivative::Derivative; +use derive_more::{Deref, DerefMut}; +use parking_lot::Mutex; +use std::future::Future; +use std::mem::take; +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::Notify; +use tokio::task::{AbortHandle, JoinError}; +use tokio_util::sync::CancellationToken; + +#[derive(Derivative, Debug)] +#[derivative(Default(bound = ""))] +enum AsyncRuntimeState { + #[derivative(Default)] + Idle, + Running { + id: tokio::task::Id, + task: ScopedTask, + token: CancellationToken, + }, + Stopping(AbortHandle), +} + +#[derive(Derivative, Debug)] +#[derivative(Default(bound = ""))] +pub struct AsyncRuntimeInner { + state: Mutex>, + idle: Notify, +} + +#[derive(Derivative, Deref, DerefMut)] +#[derivative(Debug = "transparent", Default(bound = ""), Clone(bound = ""))] +pub struct AsyncRuntime(Arc>); + +impl AsyncRuntime { + pub fn token(&self) -> Option { + if let AsyncRuntimeState::Running { token, .. } = &*self.state.lock() { + Some(token.clone()) + } else { + None + } + } + + pub fn start(&self, token: Option, factory: F) -> anyhow::Result<()> + where + F: FnOnce(CancellationToken) -> Fut, + Fut: Future + Send + 'static, + { + let mut state = self.state.lock(); + if !matches!(*state, AsyncRuntimeState::Idle) { + return Err(anyhow::anyhow!("task is already running/stopping")); + } + + let token = token.unwrap_or_default(); + + let task = { + let f = factory(token.clone()); + let this = (*self).clone(); + tokio::spawn(async move { + let result = f.await; + let mut state = this.state.lock(); + if let AsyncRuntimeState::Running { id, .. } = &*state + && *id == tokio::task::id() + { + take(&mut *state); + } + result + }) + }; + + *state = AsyncRuntimeState::Running { + id: task.id(), + task: task.into(), + token, + }; + + Ok(()) + } + + pub async fn stop(&self, timeout: Duration) -> Option> { + let state = { + let mut state = self.state.lock(); + match &*state { + AsyncRuntimeState::Running { .. } => { + let AsyncRuntimeState::Running { task, token, .. } = take(&mut *state) else { + unreachable!() + }; + *state = AsyncRuntimeState::Stopping(task.abort_handle()); + Ok((task, token)) + } + AsyncRuntimeState::Stopping(_) => Err(self.idle.notified()), + AsyncRuntimeState::Idle => return None, + } + }; + + let (mut task, token) = match state { + Ok(running) => running, + Err(stopping) => { + stopping.await; + return None; + } + }; + + token.cancel(); + let result = if let Ok(result) = tokio::time::timeout(timeout, &mut task).await { + result + } else { + task.abort(); + tracing::warn!("task stop timeout after {:?}, aborted", timeout); + task.await + }; + + { + let mut state = self.state.lock(); + if matches!(*state, AsyncRuntimeState::Stopping(_)) { + *state = AsyncRuntimeState::Idle; + drop(state); + self.idle.notify_waiters(); + } + } + + Some(result) + } + + pub fn abort(&self) { + let mut state = self.state.lock(); + match &*state { + AsyncRuntimeState::Running { task, .. } => { + task.abort(); + *state = AsyncRuntimeState::Idle; + drop(state); + self.idle.notify_waiters(); + } + AsyncRuntimeState::Stopping(handle) => handle.abort(), + _ => {} + } + } +}