cargo: upgrade (#2116)

update dependencies
This commit is contained in:
Luna Yao authored and GitHub committed 2026-09-16 20:50:43 +08:00
1 parent 5477d4bca2
commit 7223677264
45 files changed
+5152 -4997

No files matched your search

Generated
+2887 -2934
View File
File diff suppressed because it is too large. Load diff
+70
View File
@@ -21,6 +21,76 @@ exclude = [
edition = "2024" edition = "2024"
rust-version = "1.95" rust-version = "1.95"
[workspace.dependencies]
# Shared versions and sources; members select features and optional dependencies.
anyhow = "1.0"
arc-swap = "1.9"
async-trait = "0.1.92"
atomic-shim = "0.2.0"
auto_impl = "1.3.0"
base64 = "0.23"
bon = "3.10.1"
bytecodec = "0.5.0"
bytes = "1.12.1"
chrono = "0.4.45"
cidr = "0.3.2"
clap = "4.6.7"
crossbeam = "0.8.5"
dashmap = "6.2.1"
easytier = { version = "2.7.0", path = "easytier", default-features = false }
easytier-core = { version = "2.7.0", path = "easytier-core", default-features = false }
easytier-ffi = { path = "easytier-contrib/easytier-ffi", default-features = false }
easytier-proto = { version = "2.7.0", path = "easytier-proto", default-features = false }
futures = "0.3"
guarden = "0.3"
hmac = "0.13.0"
http-body-util = "0.1"
hyper = { version = "1", default-features = false }
hyper-util = { version = "0.1", default-features = false }
indoc = "2.0.7"
log = "0.4"
mimalloc = "*"
once_cell = "1.21"
parking_lot = "0.12.5"
percent-encoding = "2.3.2"
pin-project-lite = "0.2.17"
prost = "0.14.4"
prost-types = "0.14.4"
quanta = "0.12"
# rand 0.10 / x25519-dalek 3 require a coordinated RNG trait migration.
rand = "0.8.8"
reqwest = { version = "0.13.5", default-features = false }
rust-i18n = "4"
rustls = { version = "0.23.45", default-features = false }
# tower-sessions-sqlx-store 0.15 requires SQLx 0.8; SeaORM 2 requires SQLx 0.9.
sea-orm = "1.1.20"
sea-orm-migration = "1.1.20"
serde = "1.0.229"
serde_json = "1.0"
sha2 = "0.11.0"
smoltcp = { version = "0.14.0", default-features = false }
sqlx = "0.8.6"
strum = "0.28.0"
stun_codec = "0.4.0"
sys-locale = "0.3"
tauri = "2.11.5"
tempfile = "3.27.0"
thiserror = "2.0"
thunk-rs = { git = "https://github.com/EasyTier/thunk.git", default-features = false }
tokio = { version = "1.53", default-features = false }
tokio-rustls = { version = "0.26", default-features = false }
tokio-util = "0.7.19"
toml = "1.1.6"
tower-http = "0.7"
tracing = "0.1"
tracing-subscriber = { version = "0.3", default-features = false }
url = "2.5"
uuid = "1.26.1"
winapi = "0.3.9"
x25519-dalek = "2.0.1"
# zerocopy 0.8 requires migrating the packet layout and casting APIs.
zerocopy = "0.7.35"
[profile.dev] [profile.dev]
panic = "unwind" panic = "unwind"
debug = 2 debug = 2
@@ -7,11 +7,11 @@ edition.workspace = true
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
jni = "0.21" # JNI 0.22 changes native entry points to EnvUnowned and Env.
once_cell = "1.18.0" jni = "0.21.1"
log = "0.4" once_cell.workspace = true
android_logger = "0.13" log.workspace = true
serde = { version = "1.0.220", features = ["derive"] } android_logger = "0.15"
serde_json = "1.0" serde_json.workspace = true
easytier = { path = "../../easytier" } easytier = { workspace = true, default-features = true }
easytier-ffi = { path = "../easytier-ffi", default-features = false } easytier-ffi.workspace = true
+14 -10
View File
@@ -15,20 +15,24 @@ ffi-dataplane = [
] ]
[dependencies] [dependencies]
easytier = { path = "../../easytier", features = ["tracing-log"] } easytier = { workspace = true, default-features = true, features = ["tracing-log"] }
easytier-core = { path = "../../easytier-core" } easytier-core = { workspace = true, default-features = true }
once_cell = "1.18.0" once_cell.workspace = true
tokio = { version = "1", features = ["rt-multi-thread", "io-util", "time", "sync", "macros"] } tokio = { workspace = true, default-features = true, features = ["rt-multi-thread", "io-util", "time", "sync", "macros"] }
async-trait = "0.1" async-trait.workspace = true
log = "0.4" log.workspace = true
serde = { version = "1.0", features = ["derive"] } serde_json.workspace = true
serde_json = "1" uuid.workspace = true
uuid = "1.17.0"
[build-dependencies] [build-dependencies]
thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ thunk-rs = { workspace = true, features = [
"win7", "win7",
] } ] }
[package.metadata.cargo-machete]
ignored = [
# Windows-only build.rs setup calls thunk::thunk().
"thunk-rs",
]
+7 -8
View File
@@ -7,18 +7,17 @@ edition.workspace = true
crate-type = ["staticlib", "rlib"] crate-type = ["staticlib", "rlib"]
[dependencies] [dependencies]
serde_json = "1.0" serde_json.workspace = true
tracing = "0.1" tracing.workspace = true
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { workspace = true, default-features = true, features = ["env-filter"] }
easytier-ffi = { path = "../easytier-ffi", default-features = false, features = [ easytier-ffi = { workspace = true, features = [
"c-abi", "c-abi",
] } ] }
[dev-dependencies] [dev-dependencies]
uuid = "1" uuid.workspace = true
tokio = { version = "1", features = ["io-util"] } easytier-core = { workspace = true, default-features = true }
easytier-core = { path = "../../easytier-core" } easytier-ffi = { workspace = true, features = [
easytier-ffi = { path = "../easytier-ffi", default-features = false, features = [
"c-abi", "c-abi",
"ffi-dataplane", "ffi-dataplane",
] } ] }
+3 -3
View File
@@ -8,8 +8,8 @@ license-file = "../../LICENSE"
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
anyhow = "1.0" anyhow.workspace = true
easytier = { path = "../../easytier", version = "2.7.0", default-features = false, features = [ easytier = { workspace = true, features = [
"aes-gcm", "aes-gcm",
"dhcp-ipv4", "dhcp-ipv4",
"logging", "logging",
@@ -18,4 +18,4 @@ easytier = { path = "../../easytier", version = "2.7.0", default-features = fals
"tun", "tun",
"web-client", "web-client",
] } ] }
tokio = { version = "1", default-features = false, features = ["macros", "rt", "signal"] } tokio = { workspace = true, features = ["macros", "rt", "signal"] }
+1673 -1615
View File
File diff suppressed because it is too large. Load diff
@@ -40,7 +40,6 @@ napi-ohos = { version = "1.1", default-features = false, features = [
"tokio_io_util", "tokio_io_util",
"deferred_trace", "deferred_trace",
"napi8", "napi8",
"node_version_detect",
"web_stream", "web_stream",
] } ] }
once_cell = "1.21.3" once_cell = "1.21.3"
+23 -41
View File
@@ -4,24 +4,22 @@ version = "0.1.0"
edition.workspace = true edition.workspace = true
[dependencies] [dependencies]
tokio = { version = "1.0", features = ["full"] } tokio = { workspace = true, default-features = true, features = ["full"] }
tracing = "0.1" tracing.workspace = true
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { workspace = true, default-features = true, features = ["env-filter"] }
anyhow = "1.0" anyhow.workspace = true
serde = { version = "1.0", features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = "1.0" serde_json.workspace = true
chrono = { version = "0.4", features = ["serde"] } chrono = { workspace = true, features = ["serde"] }
uuid = { version = "1.0", features = ["v4", "serde"] } uuid = { workspace = true, features = ["v4", "serde"] }
guarden = "0.1"
# Axum web framework # Axum web framework
axum = { version = "0.8.4", features = ["macros"] } axum = { version = "0.8.9", features = ["macros"] }
axum-extra = { version = "0.10", features = ["query"] } axum-extra = { version = "0.12", features = ["query"] }
tower-http = { version = "0.6", features = ["cors", "compression-full"] } tower-http = { workspace = true, features = ["cors", "compression-full"] }
tower = "0.5"
# SeaORM dependencies # SeaORM dependencies
sea-orm = { version = "1.1", features = [ sea-orm = { workspace = true, features = [
"sqlx-sqlite", "sqlx-sqlite",
"runtime-tokio-rustls", "runtime-tokio-rustls",
"macros", "macros",
@@ -29,39 +27,23 @@ sea-orm = { version = "1.1", features = [
"with-uuid", "with-uuid",
"with-json" "with-json"
] } ] }
sea-orm-migration = { version = "1.1" } sea-orm-migration.workspace = true
sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls", "chrono", "uuid"] } sqlx = { workspace = true, features = ["sqlite", "runtime-tokio-rustls", "chrono", "uuid"] }
# Validation # Validation
validator = { version = "0.18", features = ["derive"] } validator = { version = "0.21", features = ["derive"] }
thiserror = "1.0" thiserror.workspace = true
jsonwebtoken = "9.0" jsonwebtoken = { version = "11.0", features = ["rust_crypto"] }
# Configuration and serialization
serde_yaml = "0.9"
toml = "0.8"
# Network and async # Network and async
async-trait = "0.1" async-trait.workspace = true
futures = "0.3" tokio-util = { workspace = true, features = ["full"] }
tokio-util = { version = "0.7", features = ["full"] }
# Filesystem operations
tempfile = "3.8"
# Additional utilities # Additional utilities
dashmap = "6.1.0" dashmap.workspace = true
clap = { version = "4.0", features = ["derive"] } clap = { workspace = true, features = ["derive"] }
parking_lot = "0.12"
once_cell = "1.19"
# EasyTier core # EasyTier core
easytier = { path = "../../easytier" } easytier = { workspace = true, default-features = true }
mimalloc = { version = "*" } mimalloc.workspace = true
# Testing
[dev-dependencies]
mockall = "0.12"
tokio-test = "0.4"
reqwest = "0.12"
@@ -383,7 +383,14 @@ mod tests {
assert_eq!(node.name, "Test Node"); assert_eq!(node.name, "Test Node");
assert_eq!(node.host, "test.example.com"); assert_eq!(node.host, "test.example.com");
assert_eq!(node.port, 11010); assert_eq!(node.port, 11010);
assert!(!node.is_active);
assert!(!node.is_approved);
let node = NodeOperations::update_node_status(&db, node.id, true, Some(1))
.await
.unwrap();
assert!(node.is_active); assert!(node.is_active);
assert_eq!(node.current_connections, 1);
// 测试获取节点 // 测试获取节点
let found_node = NodeOperations::get_node_by_id(&db, node.id).await.unwrap(); let found_node = NodeOperations::get_node_by_id(&db, node.id).await.unwrap();
+67 -60
View File
@@ -18,76 +18,76 @@ crate-type = ["rlib", "cdylib"]
wasm-opt = ["-Oz", "--enable-bulk-memory", "--enable-nontrapping-float-to-int"] wasm-opt = ["-Oz", "--enable-bulk-memory", "--enable-nontrapping-float-to-int"]
[dependencies] [dependencies]
anyhow = "1.0" anyhow.workspace = true
ariadne = { version = "0.5", optional = true } ariadne = { version = "0.6", optional = true }
arc-swap = "1.7" arc-swap.workspace = true
async-ringbuf = "0.3.1" async-ringbuf = "0.3.9"
async-trait = "0.1.74" async-trait.workspace = true
auto_impl = "1.1.0" auto_impl.workspace = true
base64 = "0.22" base64.workspace = true
bitflags = "2.5" bitflags = "2.13"
bytecodec = "0.4.15" bytecodec.workspace = true
bytes = "1.5.0" bytes.workspace = true
chrono = { version = "0.4.37", features = ["clock"] } chrono = { workspace = true, features = ["clock"] }
cidr = { version = "0.3.1", features = ["serde"] } cidr = { workspace = true, features = ["serde"] }
crossbeam = "0.8.4" crossbeam.workspace = true
dashmap = "6.0" dashmap.workspace = true
derive_builder = "0.20.2" bon.workspace = true
easytier-proto = { path = "../easytier-proto", default-features = false, features = ["core"] } easytier-proto = { workspace = true, features = ["core"] }
futures = "0.3" futures.workspace = true
guarden = "0.2" guarden.workspace = true
hmac = "0.12.1" hmac.workspace = true
http-body-util = { version = "0.1", optional = true } http-body-util = { workspace = true, optional = true }
hyper = { version = "1", default-features = false, features = ["client", "http1"], optional = true } hyper = { workspace = true, features = ["client", "http1"], optional = true }
hyper-util = { version = "0.1", default-features = false, features = ["tokio"], optional = true } hyper-util = { workspace = true, features = ["tokio"], optional = true }
idna = "1.0" idna = "1.1"
atomic-shim = "0.2.0" atomic-shim.workspace = true
ordered_hash_map = "0.5.0" ordered_hash_map = "0.6.1"
parking_lot = "0.12.1" parking_lot.workspace = true
percent-encoding = "2.3.1" percent-encoding.workspace = true
petgraph = "0.8.1" petgraph = "0.8.3"
pin-project-lite = "0.2.13" pin-project-lite.workspace = true
prefix-trie = { version = "0.7.0", features = ["cidr"] } prefix-trie = { version = "0.10.1", features = ["cidr"] }
prost = "0.14.3" prost.workspace = true
prost-types = "0.14.3" prost-types.workspace = true
rand = "0.8.5" rand.workspace = true
quanta = "0.12" quanta.workspace = true
ring = { version = "0.17", optional = true } ring = { version = "0.17", optional = true }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"], optional = true } rustls = { workspace = true, features = ["ring", "std", "tls12"], optional = true }
serde = { version = "1.0", features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = "1" serde_json.workspace = true
sha2 = "0.10.8" sha2.workspace = true
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp.git", rev = "0a926767a68bc88d5512afefa7529c5ecdade4ea", optional = true, default-features = false } smoltcp = { workspace = true, optional = true }
stun_codec = "0.3.4" stun_codec.workspace = true
thiserror = "1.0" thiserror.workspace = true
tracing = "0.1" tracing.workspace = true
strum = { version = "0.27.2", features = ["derive"] } strum = { workspace = true, features = ["derive"] }
toml = "0.8.12" toml.workspace = true
tokio = { version = "1", default-features = false, features = [ tokio = { workspace = true, features = [
"rt", "rt",
"time", "time",
"sync", "sync",
"macros", "macros",
"io-util", "io-util",
] } ] }
tokio-util = { version = "0.7", features = ["io", "rt"] } tokio-util = { workspace = true, features = ["io", "rt"] }
tokio-rustls = { version = "0.26", default-features = false, optional = true } tokio-rustls = { workspace = true, optional = true }
url = { version = "2.5", features = ["serde"] } url = { workspace = true, features = ["serde"] }
wildmatch = "2.3.4" wildmatch = "2.6.1"
uuid = { version = "1.5.0", features = ["v4", "fast-rng", "serde"] } uuid = { workspace = true, features = ["v4", "fast-rng", "serde"] }
webpki-roots = { version = "0.26", optional = true } webpki-roots = { version = "1.0", optional = true }
x25519-dalek = { version = "2.0", features = ["static_secrets"] } x25519-dalek = { workspace = true, features = ["static_secrets"] }
zerocopy = { version = "0.7.32", features = ["derive", "simd"] } zerocopy = { workspace = true, features = ["derive", "simd"] }
zstd = { version = "0.13", optional = true } zstd = { version = "0.14", optional = true }
aes-gcm = { version = "0.10.3", optional = true } aes-gcm = { version = "0.11.1", optional = true }
chacha20poly1305 = { version = "0.10.1", optional = true } chacha20poly1305 = { version = "0.11.0", optional = true }
openssl = { version = "0.10", optional = true, features = ["vendored"] } openssl = { version = "0.10", optional = true, features = ["vendored"] }
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
getrandom-02 = { package = "getrandom", version = "0.2.15", features = ["js"] } getrandom-02 = { package = "getrandom", version = "0.2.17", features = ["js"] }
getrandom-03 = { package = "getrandom", version = "0.3.2", features = ["wasm_js"] } getrandom-03 = { package = "getrandom", version = "0.3.4", features = ["wasm_js"] }
snow = { version = "0.10.0", default-features = false, features = ["default-resolver", "default-resolver-crypto"] } snow = { version = "0.10.0", default-features = false, features = ["default-resolver", "default-resolver-crypto"] }
uuid = { version = "1.5.0", features = ["js"] } uuid = { workspace = true, features = ["js"] }
wasm-bindgen = "0.2" wasm-bindgen = "0.2"
[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies] [target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies]
@@ -153,4 +153,11 @@ tracing-log = ["tracing/log"]
zstd = ["dep:zstd"] zstd = ["dep:zstd"]
[target.'cfg(not(target_os = "wasi"))'.dev-dependencies] [target.'cfg(not(target_os = "wasi"))'.dev-dependencies]
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } tokio = { workspace = true, features = ["rt-multi-thread"] }
[package.metadata.cargo-machete]
ignored = [
# Enable browser entropy backends for transitive rand/snow dependencies.
"getrandom-02",
"getrandom-03",
]
+3 -3
View File
@@ -428,11 +428,11 @@ pub struct ConsoleLoggerConfig {
pub level: Option<String>, pub level: Option<String>,
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_builder::Builder)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, bon::Builder)]
pub struct LoggingConfig { pub struct LoggingConfig {
#[builder(setter(into, strip_option), default = None)] #[builder(into)]
pub file_logger: Option<FileLoggerConfig>, pub file_logger: Option<FileLoggerConfig>,
#[builder(setter(into, strip_option), default = None)] #[builder(into)]
pub console_logger: Option<ConsoleLoggerConfig>, pub console_logger: Option<ConsoleLoggerConfig>,
} }
@@ -474,7 +474,7 @@ mod tests {
!try_process_wrapped_tcp_packet_from_nic( !try_process_wrapped_tcp_packet_from_nic(
&mut packet, &mut packet,
context(transport), context(transport),
|_| false, |_, _| false,
|_| async { true }, |_| async { true },
) )
.await .await
+1 -1
View File
@@ -16,7 +16,7 @@ use easytier_proto::{
common::{FlagsInConfig, PeerFeatureFlag, SecureModeConfig, StunInfo, TunnelInfo}, common::{FlagsInConfig, PeerFeatureFlag, SecureModeConfig, StunInfo, TunnelInfo},
peer_rpc::{PeerGroupInfo, TrustedCredentialPubkeyProof}, peer_rpc::{PeerGroupInfo, TrustedCredentialPubkeyProof},
}; };
use hmac::{Hmac, Mac}; use hmac::{Hmac, KeyInit, Mac};
use sha2::Sha256; use sha2::Sha256;
pub use crate::config::{NetworkIdentity, NetworkSecretDigest}; pub use crate::config::{NetworkIdentity, NetworkSecretDigest};
@@ -12,7 +12,7 @@ use std::{
use dashmap::{DashMap, DashSet}; use dashmap::{DashMap, DashSet};
use easytier_proto::common::FlagsInConfig; use easytier_proto::common::FlagsInConfig;
use guarden::{Guard, defer}; use guarden::defer;
use tokio::sync::{ use tokio::sync::{
Mutex, RwLock, RwLockReadGuard, Mutex, RwLock, RwLockReadGuard,
mpsc::{self, UnboundedReceiver, UnboundedSender}, mpsc::{self, UnboundedReceiver, UnboundedSender},
@@ -702,7 +702,7 @@ impl OspfRouteTable {
.load() .load()
.iter() .iter()
.filter(|(_, pv)| pv.peer_id != peer_id) .filter(|(_, pv)| pv.peer_id != peer_id)
.map(|(cidr, _)| *cidr) .map(|(cidr, _)| cidr)
.collect() .collect()
} }
@@ -711,7 +711,7 @@ impl OspfRouteTable {
.load() .load()
.iter() .iter()
.filter(|(_, pv)| pv.peer_id != peer_id) .filter(|(_, pv)| pv.peer_id != peer_id)
.map(|(cidr, _)| *cidr) .map(|(cidr, _)| cidr)
.collect() .collect()
} }
} }
+18 -10
View File
@@ -1,5 +1,5 @@
use aes_gcm::{AeadCore, AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit}; use aes_gcm::{AeadInOut, Aes128Gcm, Aes256Gcm, Key, KeyInit};
use rand::rngs::OsRng; use rand::{RngCore, rngs::OsRng};
use zerocopy::{AsBytes, FromBytes}; use zerocopy::{AsBytes, FromBytes};
use crate::packet::{StandardAeadTail, ZCPacket}; use crate::packet::{StandardAeadTail, ZCPacket};
@@ -54,16 +54,16 @@ impl Encryptor for AesGcmCipher {
let tag = aes_tail.tag.into(); let tag = aes_tail.tag.into();
let rs = match &self.cipher { let rs = match &self.cipher {
AesGcmEnum::AES128GCM(aes_gcm) => aes_gcm.decrypt_in_place_detached( AesGcmEnum::AES128GCM(aes_gcm) => aes_gcm.decrypt_inout_detached(
&nonce, &nonce,
&[], &[],
&mut zc_packet.mut_payload()[..text_len], (&mut zc_packet.mut_payload()[..text_len]).into(),
&tag, &tag,
), ),
AesGcmEnum::AES256GCM(aes_gcm) => aes_gcm.decrypt_in_place_detached( AesGcmEnum::AES256GCM(aes_gcm) => aes_gcm.decrypt_inout_detached(
&nonce, &nonce,
&[], &[],
&mut zc_packet.mut_payload()[..text_len], (&mut zc_packet.mut_payload()[..text_len]).into(),
&tag, &tag,
), ),
}; };
@@ -107,16 +107,24 @@ impl Encryptor for AesGcmCipher {
let (tag, nonce) = match &self.cipher { let (tag, nonce) = match &self.cipher {
AesGcmEnum::AES128GCM(aes_gcm) => { AesGcmEnum::AES128GCM(aes_gcm) => {
let nonce = nonce.unwrap_or_else(|| Aes128Gcm::generate_nonce(&mut OsRng)); let nonce = nonce.unwrap_or_else(|| {
let mut nonce = [0u8; StandardAeadTail::NONCE_SIZE];
OsRng.fill_bytes(&mut nonce);
nonce.into()
});
( (
aes_gcm.encrypt_in_place_detached(&nonce, &[], zc_packet.mut_payload()), aes_gcm.encrypt_inout_detached(&nonce, &[], zc_packet.mut_payload().into()),
nonce, nonce,
) )
} }
AesGcmEnum::AES256GCM(aes_gcm) => { AesGcmEnum::AES256GCM(aes_gcm) => {
let nonce = nonce.unwrap_or_else(|| Aes256Gcm::generate_nonce(&mut OsRng)); let nonce = nonce.unwrap_or_else(|| {
let mut nonce = [0u8; StandardAeadTail::NONCE_SIZE];
OsRng.fill_bytes(&mut nonce);
nonce.into()
});
( (
aes_gcm.encrypt_in_place_detached(&nonce, &[], zc_packet.mut_payload()), aes_gcm.encrypt_inout_detached(&nonce, &[], zc_packet.mut_payload().into()),
nonce, nonce,
) )
} }
+14 -5
View File
@@ -1,5 +1,5 @@
use chacha20poly1305::{AeadCore, AeadInPlace, ChaCha20Poly1305, Key, KeyInit}; use chacha20poly1305::{AeadInOut, ChaCha20Poly1305, Key, KeyInit};
use rand::rngs::OsRng; use rand::{RngCore, rngs::OsRng};
use zerocopy::{AsBytes, FromBytes}; use zerocopy::{AsBytes, FromBytes};
use crate::packet::{StandardAeadTail, ZCPacket}; use crate::packet::{StandardAeadTail, ZCPacket};
@@ -42,7 +42,12 @@ impl Encryptor for ChaCha20Cipher {
let tag = tail.tag.into(); let tag = tail.tag.into();
self.cipher self.cipher
.decrypt_in_place_detached(&nonce, &[], &mut zc_packet.mut_payload()[..text_len], &tag) .decrypt_inout_detached(
&nonce,
&[],
(&mut zc_packet.mut_payload()[..text_len]).into(),
&tag,
)
.map_err(|_| Error::DecryptionFailed)?; .map_err(|_| Error::DecryptionFailed)?;
let pm_header = zc_packet.mut_peer_manager_header().unwrap(); let pm_header = zc_packet.mut_peer_manager_header().unwrap();
@@ -76,11 +81,15 @@ impl Encryptor for ChaCha20Cipher {
.map_err(|_| Error::EncryptionFailed) .map_err(|_| Error::EncryptionFailed)
}) })
.transpose()? .transpose()?
.unwrap_or_else(|| ChaCha20Poly1305::generate_nonce(&mut OsRng)); .unwrap_or_else(|| {
let mut nonce = [0u8; StandardAeadTail::NONCE_SIZE];
OsRng.fill_bytes(&mut nonce);
nonce.into()
});
let tag = self let tag = self
.cipher .cipher
.encrypt_in_place_detached(&nonce, &[], zc_packet.mut_payload()) .encrypt_inout_detached(&nonce, &[], zc_packet.mut_payload().into())
.map_err(|_| Error::EncryptionFailed)?; .map_err(|_| Error::EncryptionFailed)?;
let tail = StandardAeadTail { let tail = StandardAeadTail {
+1 -1
View File
@@ -8,7 +8,7 @@ use std::{
use anyhow::anyhow; use anyhow::anyhow;
use atomic_shim::AtomicU64; use atomic_shim::AtomicU64;
use hmac::{Hmac, Mac as _}; use hmac::{Hmac, KeyInit as _, Mac as _};
use rand::RngCore as _; use rand::RngCore as _;
use sha2::Sha256; use sha2::Sha256;
use zerocopy::FromBytes; use zerocopy::FromBytes;
+29 -26
View File
@@ -14,54 +14,50 @@ crate-type = ["staticlib", "cdylib", "rlib"]
[dependencies] [dependencies]
# wry 0.47 may crash on android, see https://github.com/EasyTier/EasyTier/issues/527 # wry 0.47 may crash on android, see https://github.com/EasyTier/EasyTier/issues/527
tauri = { version = "2.7.0", features = [ tauri = { workspace = true, features = [
"tray-icon", "tray-icon",
"image-png", "image-png",
"image-ico", "image-ico",
"devtools", "devtools",
] } ] }
serde = { version = "1", features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = "1" serde_json.workspace = true
easytier = { path = "../../easytier" } easytier = { workspace = true, default-features = true }
easytier-core = { path = "../../easytier-core" } easytier-core = { workspace = true, default-features = true }
tokio = { version = "1", features = ["full"] } tokio = { workspace = true, default-features = true, features = ["full"] }
anyhow = "1.0" anyhow.workspace = true
chrono = { version = "0.4.37", features = ["serde"] }
once_cell = "1.18.0" once_cell.workspace = true
dashmap = "6.0" dashmap.workspace = true
gethostname = "1.0.2"
dunce = "1.0.4"
tauri-plugin-shell = "2.3.0" tauri-plugin-shell = "2.3.6"
tauri-plugin-process = "2.3.0" tauri-plugin-process = "2.3.1"
tauri-plugin-clipboard-manager = "2.3.0" tauri-plugin-clipboard-manager = "2.3.3"
tauri-plugin-positioner = { version = "2.3.0", features = ["tray-icon"] }
tauri-plugin-vpnservice = { path = "../../tauri-plugin-vpnservice" } tauri-plugin-vpnservice = { path = "../../tauri-plugin-vpnservice" }
tauri-plugin-os = "2.3.0" tauri-plugin-os = "2.3.2"
uuid = "1.17.0" uuid.workspace = true
async-trait = "0.1.89" async-trait.workspace = true
url = { version = "2.5", features = ["serde"] } url = { workspace = true, features = ["serde"] }
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.52", features = ["Win32_Foundation", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] } windows = { version = "0.62", features = ["Win32_Foundation", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
winapi = { version = "0.3.9", features = ["securitybaseapi", "processthreadsapi"] } winapi = { workspace = true, features = ["securitybaseapi", "processthreadsapi"] }
[target.'cfg(target_family = "unix")'.dependencies] [target.'cfg(target_family = "unix")'.dependencies]
libc = "0.2" libc = "0.2"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
security-framework-sys = "2.9.0" security-framework-sys = "2.17.0"
[build-dependencies] [build-dependencies]
tauri-build = { version = "2.0.0-rc", features = [] } tauri-build = { version = "2.6.3", features = [] }
thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ thunk-rs = { workspace = true, features = [
"win7", "win7",
] } ] }
@@ -71,4 +67,11 @@ thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = f
custom-protocol = ["tauri/custom-protocol"] custom-protocol = ["tauri/custom-protocol"]
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2.3.2" tauri-plugin-single-instance = "2.4.4"
[package.metadata.cargo-machete]
ignored = [
# Called by build.rs; thunk is only used on Windows.
"tauri-build",
"thunk-rs",
]
@@ -5,7 +5,7 @@ buildscript {
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:8.3.2") classpath("com.android.tools.build:gradle:8.3.2")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.21")
} }
} }
@@ -19,4 +19,3 @@ allprojects {
tasks.register("clean").configure { tasks.register("clean").configure {
delete("build") delete("build")
} }
@@ -12,7 +12,6 @@ use winapi::shared::minwindef::{DWORD, LPVOID};
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
use winapi::um::securitybaseapi::GetTokenInformation; use winapi::um::securitybaseapi::GetTokenInformation;
use winapi::um::winnt::{HANDLE, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation}; 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::Shell::ShellExecuteW;
use windows::Win32::UI::WindowsAndMessaging::SW_HIDE; use windows::Win32::UI::WindowsAndMessaging::SW_HIDE;
use windows::core::{HSTRING, PCWSTR, w}; use windows::core::{HSTRING, PCWSTR, w};
@@ -97,7 +96,7 @@ impl Command {
// the cwd always point to %SystemRoot%\System32 and cannot be changed by settting lpdirectory param // the cwd always point to %SystemRoot%\System32 and cannot be changed by settting lpdirectory param
let r = unsafe { let r = unsafe {
ShellExecuteW( ShellExecuteW(
HWND(0), None,
w!("runas"), w!("runas"),
&HSTRING::from(self.cmd.get_program()), &HSTRING::from(self.cmd.get_program()),
&HSTRING::from(parameters), &HSTRING::from(parameters),
+3 -6
View File
@@ -23,9 +23,7 @@ use easytier::web_client::{self, WebClient};
use easytier::{ use easytier::{
common::config::{NetworkConfig, NetworkConfigExt}, common::config::{NetworkConfig, NetworkConfigExt},
common::{ common::{
config::{ config::{ConfigLoader, ConfigSource, FileLoggerConfig, LoggingConfig, TomlConfigLoader},
ConfigLoader, ConfigSource, FileLoggerConfig, LoggingConfigBuilder, TomlConfigLoader,
},
log, log,
}, },
instance::factory::{NativeInstanceManager, native_instance_manager}, instance::factory::{NativeInstanceManager, native_instance_manager},
@@ -1463,7 +1461,7 @@ pub fn run_gui() -> std::process::ExitCode {
let Ok(log_dir) = get_log_dir(app.app_handle()) else { let Ok(log_dir) = get_log_dir(app.app_handle()) else {
return Ok(()); return Ok(());
}; };
let config = LoggingConfigBuilder::default() let config = LoggingConfig::builder()
.file_logger(FileLoggerConfig { .file_logger(FileLoggerConfig {
dir: Some(log_dir.to_string_lossy().to_string()), dir: Some(log_dir.to_string_lossy().to_string()),
level: None, level: None,
@@ -1471,8 +1469,7 @@ pub fn run_gui() -> std::process::ExitCode {
size_mb: None, size_mb: None,
count: None, count: None,
}) })
.build() .build();
.map_err(|e| e.to_string())?;
let Ok(_) = log::init(&config, true) else { let Ok(_) = log::init(&config, true) else {
return Ok(()); return Ok(());
}; };
+41 -25
View File
@@ -13,44 +13,44 @@ license-file = "../LICENSE"
build = "build/main.rs" build = "build/main.rs"
[dependencies] [dependencies]
anyhow = { version = "1.0", optional = true } anyhow = { workspace = true, optional = true }
async-trait = { version = "0.1.74", optional = true } async-trait = { workspace = true, optional = true }
auto_impl = { version = "1.1.0", optional = true } auto_impl = { workspace = true, optional = true }
base64 = { version = "0.22", optional = true } base64 = { workspace = true, optional = true }
bytes = { version = "1.5.0", optional = true } bytes = { workspace = true, optional = true }
chrono = { version = "0.4.37", features = ["serde"], optional = true } chrono = { workspace = true, features = ["serde"], optional = true }
cidr = { version = "0.3.1", features = ["serde"], optional = true } cidr = { workspace = true, features = ["serde"], optional = true }
hmac = { version = "0.12.1", optional = true } hmac = { workspace = true, optional = true }
prost = { version = "0.14.3", optional = true } prost = { workspace = true, optional = true }
prost-types = { version = "0.14.3", optional = true } prost-types = { workspace = true, optional = true }
prost-wkt-types = { version = "0.7.1", optional = true } prost-wkt-types = { version = "0.7.2", optional = true }
pbjson = { version = "0.9.0", optional = true } pbjson = { version = "0.9.0", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true } serde = { workspace = true, features = ["derive"], optional = true }
serde_json = { version = "1", optional = true } serde_json = { workspace = true, optional = true }
sha2 = { version = "0.10.8", optional = true } sha2 = { workspace = true, optional = true }
thiserror = { version = "1.0", optional = true } thiserror = { workspace = true, optional = true }
tokio = { version = "1", default-features = false, features = ["time"], optional = true } tokio = { workspace = true, features = ["time"], optional = true }
url = { version = "2.5", features = ["serde"], optional = true } url = { workspace = true, features = ["serde"], optional = true }
uuid = { version = "1.5.0", features = ["serde"], optional = true } uuid = { workspace = true, features = ["serde"], optional = true }
x25519-dalek = { version = "2.0", features = ["static_secrets"], optional = true } x25519-dalek = { workspace = true, features = ["static_secrets"], optional = true }
[build-dependencies] [build-dependencies]
indoc = "2.0" indoc.workspace = true
pbjson-build = "0.9.0" pbjson-build = "0.9.0"
proc-macro2 = "1" proc-macro2 = "1"
prost-build = "0.14.3" prost-build = "0.14.4"
quote = "1" quote = "1"
[target.'cfg(windows)'.build-dependencies] [target.'cfg(windows)'.build-dependencies]
reqwest = { version = "0.12.12", features = ["blocking"] } reqwest = { workspace = true, default-features = true, features = ["blocking"] }
zip = "4.0.0" zip = "8.6.0"
[dev-dependencies] [dev-dependencies]
tokio = { version = "1", default-features = false, features = [ tokio = { workspace = true, features = [
"macros", "macros",
"rt", "rt",
] } ] }
uuid = { version = "1.5.0", features = [ uuid = { workspace = true, features = [
"v4", "v4",
"fast-rng", "fast-rng",
] } ] }
@@ -99,3 +99,19 @@ websocket = []
wireguard = [] wireguard = []
zstd = [] zstd = []
json-rpc = ["dep:prost-wkt-types"] json-rpc = ["dep:prost-wkt-types"]
[package.metadata.cargo-machete]
ignored = [
# Used by build/main.rs and build/rpc.rs, including the Windows protoc download.
"indoc",
"pbjson-build",
"proc-macro2",
"prost-build",
"quote",
"reqwest",
"zip",
# Referenced by generated protobuf, serde and RPC code.
"auto_impl",
"pbjson",
"serde",
]
+1 -1
View File
@@ -1,4 +1,4 @@
use hmac::{Hmac, Mac}; use hmac::{Hmac, KeyInit, Mac};
use prost::Message; use prost::Message;
use sha2::Sha256; use sha2::Sha256;
#[cfg(feature = "api")] #[cfg(feature = "api")]
+44 -37
View File
@@ -5,78 +5,85 @@ edition.workspace = true
description = "Config server for easytier. easytier-core gets config from this and web frontend use it as restful api server." description = "Config server for easytier. easytier-core gets config from this and web frontend use it as restful api server."
[dependencies] [dependencies]
easytier = { path = "../easytier" } easytier = { workspace = true, default-features = true }
easytier-core = { path = "../easytier-core" } easytier-core = { workspace = true, default-features = true }
tracing = "0.1" tracing.workspace = true
anyhow = { version = "1.0" } anyhow.workspace = true
thiserror = "1.0" thiserror.workspace = true
tokio = { version = "1", features = ["full"] } tokio = { workspace = true, default-features = true, features = ["full"] }
tokio-util = { version = "0.7", features = ["rt"] } tokio-util = { workspace = true, features = ["rt"] }
dashmap = "6.1" dashmap.workspace = true
url = "2.2" url.workspace = true
async-trait = "0.1" async-trait.workspace = true
maxminddb = "0.24" maxminddb = "0.32"
once_cell = "1.18"
axum = { version = "0.7", features = ["macros"] } axum = { version = "0.8", features = ["macros"] }
axum-login = { version = "0.16" } axum-login = { version = "0.18" }
password-auth = { version = "1.0.0" } password-auth = { version = "1.0.0" }
axum-messages = "0.7.0" axum-messages = "0.8.0"
axum-embed = { version = "0.1.0", optional = true } axum-embed = { version = "0.1.0", optional = true }
tower-sessions-sqlx-store = { version = "0.14.1", features = ["sqlite"] } tower-sessions-sqlx-store = { version = "0.15.0", features = ["sqlite"] }
tower-sessions = { version = "0.13.0", default-features = false, features = [ # Match axum-login 0.18 and the SQLx session store.
tower-sessions = { version = "0.14.0", default-features = false, features = [
"signed", "signed",
"axum-core",
] } ] }
tower-http = { version = "0.6", features = ["cors", "compression-full"] } tower-http = { workspace = true, features = ["cors", "compression-full"] }
sqlx = { version = "0.8", features = ["sqlite"] } sqlx = { workspace = true, features = ["sqlite"] }
sea-orm = { version = "1.1", features = [ sea-orm = { workspace = true, features = [
"sqlx-sqlite", "sqlx-sqlite",
"runtime-tokio-rustls", "runtime-tokio-rustls",
"macros", "macros",
] } ] }
sea-orm-migration = { version = "1.1" } sea-orm-migration.workspace = true
# for captcha # for captcha
rust-embed = { version = "8.5.0", features = ["debug-embed", "include-exclude"] } rust-embed = { version = "8.12.0", features = ["debug-embed", "include-exclude"] }
base64 = "0.22" base64.workspace = true
rand = "0.8" rand.workspace = true
image = { version = "0.24", default-features = false, features = ["png"] } image = { version = "0.25", default-features = false, features = ["png"] }
rusttype = "0.9.3" ab_glyph = "0.2.32"
imageproc = "0.23.0" imageproc = { version = "0.27.0", default-features = false, features = ["text"] }
rust-i18n = "3" rust-i18n.workspace = true
sys-locale = "0.3" sys-locale.workspace = true
clap = { version = "4.4.8", features = [ clap = { workspace = true, features = [
"string", "string",
"unicode", "unicode",
"derive", "derive",
"wrap_help", "wrap_help",
"env", "env",
] } ] }
serde = { version = "1.0", features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = "1.0" serde_json.workspace = true
uuid = { version = "1.5.0", features = [ uuid = { workspace = true, features = [
"v4", "v4",
"fast-rng", "fast-rng",
"macro-diagnostics", "macro-diagnostics",
"serde", "serde",
] } ] }
chrono = { version = "0.4.37", features = ["serde"] } chrono = { workspace = true, features = ["serde"] }
openidconnect = { version = "4.0", default-features = false, features = ["accept-rfc3339-timestamps", "reqwest"] } openidconnect = { version = "4.0", default-features = false, features = ["accept-rfc3339-timestamps", "reqwest"] }
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } reqwest = { workspace = true, features = ["json", "rustls"] }
subtle = "2.6" subtle = "2.6"
mimalloc = { version = "*" } mimalloc.workspace = true
[build-dependencies] [build-dependencies]
thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ thunk-rs = { workspace = true, features = [
"win7", "win7",
] } ] }
[features] [features]
default = [] default = []
embed = ["dep:axum-embed"] embed = ["dep:axum-embed"]
[package.metadata.cargo-machete]
ignored = [
# Windows-only build.rs setup calls thunk::thunk().
"thunk-rs",
]
@@ -485,9 +485,7 @@ mod tests {
common::config::{ConfigLoader as _, ConfigSource, NetworkConfigExt}, common::config::{ConfigLoader as _, ConfigSource, NetworkConfigExt},
proto::api::manage::{ConfigSource as RpcConfigSource, NetworkConfig, NetworkMeta}, proto::api::manage::{ConfigSource as RpcConfigSource, NetworkConfig, NetworkMeta},
}; };
use easytier_core::management::remote_client::{ use easytier_core::management::remote_client::ListNetworkProps;
ListNetworkProps, PersistentConfig as _, Storage as _,
};
use serde_json::json; use serde_json::json;
use super::*; use super::*;
+30 -21
View File
@@ -430,29 +430,33 @@ impl ClientManager {
} }
let location = if let Some(db) = &*geoip_db { let location = if let Some(db) = &*geoip_db {
match db.lookup::<geoip2::City>(ip) { match db
Ok(city) => { .lookup(ip)
.and_then(|result| result.decode::<geoip2::City>())
{
Ok(Some(city)) => {
let country = city let country = city
.country .country
.and_then(|c| c.names) .names
.and_then(|n| { .simplified_chinese
n.get("zh-CN") .or(city.country.names.english)
.or_else(|| n.get("en")) .unwrap_or("海外")
.map(|s| s.to_string()) .to_string();
}) let city_name = city
.unwrap_or_else(|| "海外".to_string()); .city
.names
let city_name = city.city.and_then(|c| c.names).and_then(|n| { .simplified_chinese
n.get("zh-CN") .or(city.city.names.english)
.or_else(|| n.get("en")) .map(str::to_string);
.map(|s| s.to_string()) let region = (!city.subdivisions.is_empty()).then(|| {
}); city.subdivisions
.iter()
let region = city.subdivisions.map(|r| { .filter_map(|subdivision| {
r.iter() subdivision
.filter_map(|x| x.names.as_ref()) .names
.filter_map(|x| x.get("zh-CN").or_else(|| x.get("en"))) .simplified_chinese
.map(|x| x.to_string()) .or(subdivision.names.english)
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(",") .join(",")
}); });
@@ -463,6 +467,11 @@ impl ClientManager {
region, region,
} }
} }
Ok(None) => Location {
country: "海外".to_string(),
city: None,
region: None,
},
Err(err) => { Err(err) => {
tracing::debug!("GeoIP lookup failed for {}: {}", ip, err); tracing::debug!("GeoIP lookup failed for {}: {}", ip, err);
Location { Location {
@@ -5,7 +5,7 @@ use super::super::utils::font;
use base64::Engine; use base64::Engine;
use base64::prelude::BASE64_STANDARD; use base64::prelude::BASE64_STANDARD;
use rusttype::Font; use ab_glyph::FontArc;
use std::fmt::Debug; use std::fmt::Debug;
use std::io::Write; use std::io::Write;
use std::sync::Arc; use std::sync::Arc;
@@ -142,7 +142,7 @@ impl Captcha {
} }
} }
pub fn get_font(&'_ mut self) -> Arc<Font<'_>> { pub fn get_font(&'_ mut self) -> Arc<FontArc> {
if let Some(font) = font::get_font(&self.font_name) { if let Some(font) = font::get_font(&self.font_name) {
font font
} else { } else {
@@ -7,10 +7,10 @@ use super::super::base::captcha::{AbstractCaptcha, Captcha};
use super::super::{CaptchaFont, NewCaptcha}; use super::super::{CaptchaFont, NewCaptcha};
use ab_glyph::{FontArc, PxScale};
use image::{ImageBuffer, Rgba}; use image::{ImageBuffer, Rgba};
use imageproc::drawing; use imageproc::drawing;
use rand::{Rng, rngs::ThreadRng}; use rand::{Rng, rngs::ThreadRng};
use rusttype::{Font, Scale};
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
use std::sync::Arc; use std::sync::Arc;
@@ -40,7 +40,7 @@ mod color {
} }
///the builder of captcha ///the builder of captcha
pub struct CaptchaBuilder<'a, 'b> { pub struct CaptchaBuilder<'b> {
///captcha image width ///captcha image width
pub width: u32, pub width: u32,
///captcha image height ///captcha image height
@@ -55,7 +55,7 @@ pub struct CaptchaBuilder<'a, 'b> {
///image background color (optional) ///image background color (optional)
pub background_color: Option<Rgba<u8>>, pub background_color: Option<Rgba<u8>>,
///fonts collection for text ///fonts collection for text
pub fonts: &'b [Arc<Font<'a>>], pub fonts: &'b [Arc<FontArc>],
///The maximum number of lines to draw behind of the image ///The maximum number of lines to draw behind of the image
pub max_behind_lines: Option<u32>, pub max_behind_lines: Option<u32>,
///The maximum number of lines to draw in front of the image ///The maximum number of lines to draw in front of the image
@@ -64,7 +64,7 @@ pub struct CaptchaBuilder<'a, 'b> {
pub max_ellipse_lines: Option<u32>, pub max_ellipse_lines: Option<u32>,
} }
impl<'a, 'b> Default for CaptchaBuilder<'a, 'b> { impl<'b> Default for CaptchaBuilder<'b> {
fn default() -> Self { fn default() -> Self {
Self { Self {
width: 150, width: 150,
@@ -80,7 +80,7 @@ impl<'a, 'b> Default for CaptchaBuilder<'a, 'b> {
} }
} }
impl<'a, 'b> CaptchaBuilder<'a, 'b> { impl<'b> CaptchaBuilder<'b> {
fn write_phrase( fn write_phrase(
&self, &self,
image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>, image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>,
@@ -90,25 +90,13 @@ impl<'a, 'b> CaptchaBuilder<'a, 'b> {
//println!("phrase={}", phrase); //println!("phrase={}", phrase);
//println!("width={}, height={}", self.width, self.height); //println!("width={}, height={}", self.width, self.height);
let font_size = (self.width as f32) / (self.length as f32) - rng.gen_range(1.0..=4.0); let font_size = (self.width as f32) / (self.length as f32) - rng.gen_range(1.0..=4.0);
let scale = Scale::uniform(font_size); let scale = PxScale::from(font_size);
if self.fonts.is_empty() { if self.fonts.is_empty() {
panic!("no fonts loaded"); panic!("no fonts loaded");
} }
let font_index = rng.gen_range(0..self.fonts.len()); let font_index = rng.gen_range(0..self.fonts.len());
let font = &self.fonts[font_index]; let font = self.fonts[font_index].as_ref();
let glyphs: Vec<_> = font let (text_width, text_height) = drawing::text_size(scale, font, phrase);
.layout(phrase, scale, rusttype::point(0.0, 0.0))
.collect();
let text_height = {
let v_metrics = font.v_metrics(scale);
(v_metrics.ascent - v_metrics.descent).ceil() as u32
};
let text_width = {
let min_x = glyphs.first().unwrap().pixel_bounding_box().unwrap().min.x;
let max_x = glyphs.last().unwrap().pixel_bounding_box().unwrap().max.x;
let last_x_pos = glyphs.last().unwrap().position().x as i32;
(max_x + last_x_pos - min_x) as u32
};
let node_width = text_width / self.length; let node_width = text_width / self.length;
//println!("text_width={}, text_height={}", text_width, text_height); //println!("text_width={}, text_height={}", text_width, text_height);
let mut x = ((self.width as i32) - (text_width as i32)) / 2; let mut x = ((self.width as i32) - (text_width as i32)) / 2;
@@ -291,7 +279,7 @@ impl AbstractCaptcha for SpecCaptcha {
..Default::default() ..Default::default()
}; };
let image = builder.build_image(phrase.iter().collect()); let image = builder.build_image(phrase.iter().collect());
let format = image::ImageOutputFormat::Png; let format = image::ImageFormat::Png;
let mut raw_data: Vec<u8> = Vec::new(); let mut raw_data: Vec<u8> = Vec::new();
image.write_to(&mut Cursor::new(&mut raw_data), format)?; image.write_to(&mut Cursor::new(&mut raw_data), format)?;
out.write_all(&raw_data)?; out.write_all(&raw_data)?;
@@ -313,6 +301,22 @@ impl AbstractCaptcha for SpecCaptcha {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
#[test] #[test]
fn it_works() {} fn captcha_renders_text_and_encodes_png() {
let mut captcha = SpecCaptcha::with_size_and_len(150, 48, 5);
let mut png = Vec::new();
captcha.out(&mut png).unwrap();
let decoded = image::load_from_memory_with_format(&png, image::ImageFormat::Png)
.unwrap()
.to_rgba8();
assert_eq!(decoded.dimensions(), (150, 48));
assert_eq!(captcha.get_chars().len(), 5);
assert!(
decoded
.pixels()
.any(|pixel| pixel[0] < 160 && pixel[1] < 160 && pixel[2] < 160)
);
}
} }
@@ -1,5 +1,5 @@
use ab_glyph::FontArc;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use rusttype::Font;
use std::error::Error; use std::error::Error;
use std::sync::Arc; use std::sync::Arc;
@@ -11,7 +11,7 @@ struct FontAssets;
// pub(crate) static ref FONTS: RwLock<HashMap<String, Arc<Font>>> = Default::default(); // pub(crate) static ref FONTS: RwLock<HashMap<String, Arc<Font>>> = Default::default();
// } // }
pub fn get_font(font_name: &'_ str) -> Option<Arc<Font<'_>>> { pub fn get_font(font_name: &'_ str) -> Option<Arc<FontArc>> {
// let fonts_cell = FONTS.get_or_init(|| Default::default()); // let fonts_cell = FONTS.get_or_init(|| Default::default());
// let guard = fonts_cell.read(); // let guard = fonts_cell.read();
// //
@@ -31,10 +31,10 @@ pub fn get_font(font_name: &'_ str) -> Option<Arc<Font<'_>>> {
// } // }
} }
pub fn load_font(font_name: &'_ str) -> Result<Option<Font<'_>>, Box<dyn Error>> { pub fn load_font(font_name: &'_ str) -> Result<Option<FontArc>, Box<dyn Error>> {
match FontAssets::get(font_name) { match FontAssets::get(font_name) {
Some(assets) => { Some(assets) => {
let font = Font::try_from_vec(Vec::from(assets.data)).unwrap(); let font = FontArc::try_from_vec(Vec::from(assets.data))?;
Ok(Some(font)) Ok(Some(font))
} }
None => { None => {
+1 -1
View File
@@ -252,7 +252,7 @@ impl RestfulServer {
get(Self::handle_list_all_sessions_internal), get(Self::handle_list_all_sessions_internal),
) )
.route( .route(
"/api/internal/users/:user-id/sessions/:machine-id", "/api/internal/users/{user-id}/sessions/{machine-id}",
delete(Self::handle_disconnect_session_internal), delete(Self::handle_disconnect_session_internal),
) )
.merge(NetworkApi::build_route_internal()) .merge(NetworkApi::build_route_internal())
+10 -10
View File
@@ -505,7 +505,7 @@ impl NetworkApi {
pub fn build_route_internal() -> Router<AppStateInner> { pub fn build_route_internal() -> Router<AppStateInner> {
Router::new() Router::new()
.route( .route(
"/api/internal/users/:user-id/machines/:machine-id/networks", "/api/internal/users/{user-id}/machines/{machine-id}/networks",
put(Self::handle_reconcile_managed_network_configs_internal) put(Self::handle_reconcile_managed_network_configs_internal)
.patch(Self::handle_patch_managed_network_configs_internal) .patch(Self::handle_patch_managed_network_configs_internal)
.layer(DefaultBodyLimit::max(MAX_MANAGED_CONFIG_REQUEST_BODY_SIZE)) .layer(DefaultBodyLimit::max(MAX_MANAGED_CONFIG_REQUEST_BODY_SIZE))
@@ -513,11 +513,11 @@ impl NetworkApi {
.get(Self::handle_list_network_instance_ids_internal), .get(Self::handle_list_network_instance_ids_internal),
) )
.route( .route(
"/api/internal/users/:user-id/machines/:machine-id/networks/:inst-id", "/api/internal/users/{user-id}/machines/{machine-id}/networks/{inst-id}",
delete(Self::handle_remove_network_instance_internal), delete(Self::handle_remove_network_instance_internal),
) )
.route( .route(
"/api/internal/users/:user-id/machines/:machine-id/networks/info", "/api/internal/users/{user-id}/machines/{machine-id}/networks/info",
get(Self::handle_collect_network_info_internal), get(Self::handle_collect_network_info_internal),
) )
} }
@@ -526,31 +526,31 @@ impl NetworkApi {
Router::new() Router::new()
.route("/api/v1/machines", get(Self::handle_list_machines)) .route("/api/v1/machines", get(Self::handle_list_machines))
.route( .route(
"/api/v1/machines/:machine-id/validate-config", "/api/v1/machines/{machine-id}/validate-config",
post(Self::handle_validate_config), post(Self::handle_validate_config),
) )
.route( .route(
"/api/v1/machines/:machine-id/networks", "/api/v1/machines/{machine-id}/networks",
post(Self::handle_run_network_instance).get(Self::handle_list_network_instance_ids), post(Self::handle_run_network_instance).get(Self::handle_list_network_instance_ids),
) )
.route( .route(
"/api/v1/machines/:machine-id/networks/:inst-id", "/api/v1/machines/{machine-id}/networks/{inst-id}",
delete(Self::handle_remove_network_instance).put(Self::handle_update_network_state), delete(Self::handle_remove_network_instance).put(Self::handle_update_network_state),
) )
.route( .route(
"/api/v1/machines/:machine-id/networks/info", "/api/v1/machines/{machine-id}/networks/info",
get(Self::handle_collect_network_info), get(Self::handle_collect_network_info),
) )
.route( .route(
"/api/v1/machines/:machine-id/networks/info/:inst-id", "/api/v1/machines/{machine-id}/networks/info/{inst-id}",
get(Self::handle_collect_one_network_info), get(Self::handle_collect_one_network_info),
) )
.route( .route(
"/api/v1/machines/:machine-id/networks/config/:inst-id", "/api/v1/machines/{machine-id}/networks/config/{inst-id}",
get(Self::handle_get_network_config).put(Self::handle_save_network_config), get(Self::handle_get_network_config).put(Self::handle_save_network_config),
) )
.route( .route(
"/api/v1/machines/:machine-id/networks/metas", "/api/v1/machines/{machine-id}/networks/metas",
post(Self::handle_get_network_metas), post(Self::handle_get_network_metas),
) )
} }
+1
View File
@@ -1,3 +1,4 @@
use openidconnect::reqwest;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
+2 -2
View File
@@ -205,7 +205,7 @@ pub async fn handle_proxy_rpc(
pub fn router() -> Router<super::AppStateInner> { pub fn router() -> Router<super::AppStateInner> {
Router::new().route( Router::new().route(
"/api/v1/machines/:machine-id/proxy-rpc", "/api/v1/machines/{machine-id}/proxy-rpc",
post(handle_proxy_rpc), post(handle_proxy_rpc),
) )
} }
@@ -227,7 +227,7 @@ pub async fn handle_proxy_rpc_internal(
pub fn router_internal() -> Router<super::AppStateInner> { pub fn router_internal() -> Router<super::AppStateInner> {
Router::new().route( Router::new().route(
"/api/internal/users/:user-id/machines/:machine-id/proxy-rpc", "/api/internal/users/{user-id}/machines/{machine-id}/proxy-rpc",
post(handle_proxy_rpc_internal), post(handle_proxy_rpc_internal),
) )
} }
-3
View File
@@ -1,6 +1,5 @@
use std::collections::HashSet; use std::collections::HashSet;
use async_trait::async_trait;
use axum_login::{AuthUser, AuthnBackend, AuthzBackend, UserId}; use axum_login::{AuthUser, AuthnBackend, AuthzBackend, UserId};
use password_auth::verify_password; use password_auth::verify_password;
use sea_orm::{ use sea_orm::{
@@ -148,7 +147,6 @@ pub enum Error {
TaskJoin(#[from] task::JoinError), TaskJoin(#[from] task::JoinError),
} }
#[async_trait]
impl AuthnBackend for Backend { impl AuthnBackend for Backend {
type User = User; type User = User;
type Credentials = Credentials; type Credentials = Credentials;
@@ -208,7 +206,6 @@ impl From<&str> for Permission {
} }
} }
#[async_trait]
impl AuthzBackend for Backend { impl AuthzBackend for Backend {
type Permission = Permission; type Permission = Permission;
+111 -97
View File
@@ -24,7 +24,7 @@ required-features = ["management"]
[[bin]] [[bin]]
name = "easytier-cli" name = "easytier-cli"
path = "src/easytier-cli.rs" path = "src/easytier-cli.rs"
required-features = ["management"] required-features = ["management", "cli"]
[lib] [lib]
name = "easytier" name = "easytier"
@@ -35,36 +35,35 @@ name = "packet_bytes_extraction"
harness = false harness = false
[dependencies] [dependencies]
easytier-core = { path = "../easytier-core", version = "2.7.0", default-features = false } easytier-core.workspace = true
easytier-proto = { path = "../easytier-proto", version = "2.7.0", default-features = false, features = ["api", "core"] } easytier-proto = { workspace = true, features = ["api", "core"] }
git-version = "0.3.9" git-version = "0.3.9"
tracing = "0.1" tracing.workspace = true
log = { version = "0.4", features = ["std"] } log = { workspace = true, features = ["std"] }
tracing-subscriber = { version = "0.3", default-features = false, features = [ tracing-subscriber = { workspace = true, features = [
"registry", "registry",
], optional = true } ], optional = true }
derive_more = { version = "2.1.1", features = ["full"] } derive_more = { version = "2.1.1", features = ["full"] }
console-subscriber = { version = "0.4.1", optional = true } console-subscriber = { version = "0.5.0", optional = true }
indoc = "2.0.7" indoc.workspace = true
paste = "1.0" paste = "1.0"
thiserror = "1.0" thiserror.workspace = true
auto_impl = "1.1.0" crossbeam.workspace = true
crossbeam = "0.8.4" arc-swap.workspace = true
arc-swap = "1.7" toml.workspace = true
toml = "0.8.12" chrono = { workspace = true, features = ["serde"] }
chrono = { version = "0.4.37", features = ["serde"] }
guarden = "0.2" guarden.workspace = true
quanta = "0.12" quanta.workspace = true
strum = { version = "0.27.2", features = ["derive"] } strum = { workspace = true, features = ["derive"] }
gethostname = "0.5.0" gethostname = "1.1.0"
futures = { version = "0.3", features = ["bilock", "unstable"] } futures = { workspace = true, features = ["bilock", "unstable"] }
tokio = { version = "1", default-features = false, features = [ tokio = { workspace = true, features = [
"fs", "fs",
"io-util", "io-util",
"macros", "macros",
@@ -75,27 +74,27 @@ tokio = { version = "1", default-features = false, features = [
"sync", "sync",
"time", "time",
] } ] }
tokio-util = { version = "0.7.9", features = ["codec", "net", "io", "rt"] } tokio-util = { workspace = true, features = ["codec", "net", "io", "rt"] }
async-trait = "0.1.74" async-trait.workspace = true
dashmap = "6.0" dashmap.workspace = true
moka = { version = "0.12", features = ["future"] } moka = { version = "0.12", features = ["future"] }
# for full-path zero-copy # for full-path zero-copy
zerocopy = { version = "0.7.32", features = ["derive", "simd"] } zerocopy = { workspace = true, features = ["derive", "simd"] }
bytes = "1.5.0" bytes.workspace = true
pin-project-lite = "0.2.13" pin-project-lite.workspace = true
atomic_refcell = "0.1.13" atomic_refcell = "0.1.14"
atomic-write-file = { version = "0.2.3", optional = true } atomic-write-file = { version = "0.3.1", optional = true }
quinn = { version = "0.11.8", optional = true, features = ["ring"] } quinn = { version = "0.11.12", optional = true, features = ["ring"] }
quinn-proto = { version = "0.11.12", optional = true } quinn-proto = { version = "0.11.18", optional = true }
seahash = { version = "4.1.0", optional = true } seahash = { version = "4.1.0", optional = true }
rustls = { version = "0.23.0", features = [ rustls = { workspace = true, features = [
"ring", "tls12" "ring", "tls12"
], default-features = false, optional = true } ], optional = true }
# for websocket # for websocket
tokio-websockets = { version = "0.13.2", git = "https://github.com/EasyTier/tokio-websockets", optional = true, features = [ tokio-websockets = { version = "0.13.2", git = "https://github.com/EasyTier/tokio-websockets", optional = true, features = [
@@ -109,15 +108,15 @@ forwarded-header-value = { version = "0.1.1", optional = true }
http = { version = "1", default-features = false, features = [ http = { version = "1", default-features = false, features = [
"std", "std",
], optional = true } ], optional = true }
rcgen = { version = "0.12.1", optional = true } rcgen = { version = "0.14.10", optional = true }
tokio-rustls = { version = "0.26", default-features = false, optional = true } tokio-rustls = { workspace = true, optional = true }
# for tap device # for tap device
tun = { package = "tun-easytier", git = "https://github.com/EasyTier/rust-tun", features = [ tun = { package = "tun-easytier", git = "https://github.com/EasyTier/rust-tun", features = [
"async", "async",
], optional = true } ], optional = true }
# for net ns # for net ns
nix = { version = "0.29.0", features = [ nix = { version = "0.31.3", features = [
"sched", "sched",
"socket", "socket",
"ioctl", "ioctl",
@@ -125,7 +124,7 @@ nix = { version = "0.29.0", features = [
"fs", "fs",
] } ] }
uuid = { version = "1.5.0", features = [ uuid = { workspace = true, features = [
"v4", "v4",
"fast-rng", "fast-rng",
"macro-diagnostics", "macro-diagnostics",
@@ -133,73 +132,73 @@ uuid = { version = "1.5.0", features = [
] } ] }
# for ring tunnel # for ring tunnel
once_cell = "1.18.0" once_cell.workspace = true
# for rpc # for rpc
prost = "0.14.3" prost.workspace = true
anyhow = "1.0" anyhow.workspace = true
url = { version = "2.5", features = ["serde"] } url = { workspace = true, features = ["serde"] }
percent-encoding = "2.3.1" percent-encoding.workspace = true
# for tun packet # for tun packet
byteorder = "1.5.0" byteorder = "1.5.0"
# for proxy # for proxy
cidr = { version = "0.3.1", features = ["serde"] } cidr = { workspace = true, features = ["serde"] }
socket2 = { version = "0.5.10", features = ["all"] } socket2 = { version = "0.6.5", features = ["all"] }
# for hole punching # for hole punching
rand = "0.8.5" rand.workspace = true
serde = { version = "1.0", features = ["derive"] } serde = { workspace = true, features = ["derive"] }
pnet_datalink = { version = "0.35.0", optional = true } pnet_datalink = { version = "0.35.0", optional = true }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp.git", rev = "0a926767a68bc88d5512afefa7529c5ecdade4ea", optional = true, default-features = false, features = [ smoltcp = { workspace = true, optional = true, features = [
"std", "std",
"medium-ethernet", "medium-ethernet",
"proto-ipv4", "proto-ipv4",
"proto-ipv6", "proto-ipv6",
"socket-raw", "socket-raw",
] } ] }
serde_json = "1" serde_json.workspace = true
clap = { version = "4.5.30", features = [ clap = { workspace = true, features = [
"string", "string",
"unicode", "unicode",
"derive", "derive",
"wrap_help", "wrap_help",
"env", "env",
] } ] }
clap_complete = { version = "4.5.55" } clap_complete = { version = "4.6.10" }
clap_complete_nushell = { version = "4.5.10" } clap_complete_nushell = { version = "4.6.2" }
async-recursion = "1.0.5" async-recursion = "1.1.1"
network-interface = "2.0.5" network-interface = "2.0.5"
# for wireguard # for wireguard
boringtun = { package = "boringtun-easytier", version = "0.6.1", optional = true } boringtun = { package = "boringtun-easytier", version = "0.6.1", optional = true }
hkdf = { version = "0.12", optional = true } hkdf = { version = "0.13", optional = true }
sha2 = { version = "0.10", optional = true } sha2 = { workspace = true, optional = true }
# for cli # for cli
tabled = "0.16" tabled = { version = "0.22", optional = true }
humansize = "2.1.3" humansize = { version = "2.1.3", optional = true }
terminal_size = "0.4" terminal_size = { version = "0.4", optional = true }
unicode-width = "0.1" unicode-width = { version = "0.2", optional = true }
base64 = "0.22" base64.workspace = true
mimalloc = { version = "*", optional = true } mimalloc = { workspace = true, optional = true }
# mips # mips
atomic-shim = "0.2.0" atomic-shim.workspace = true
parking_lot = { version = "0.12.0" } parking_lot.workspace = true
rust-i18n = "3" rust-i18n.workspace = true
sys-locale = "0.3" sys-locale.workspace = true
service-manager = { git = "https://github.com/EasyTier/service-manager-rs.git", branch = "main" } service-manager = { git = "https://github.com/EasyTier/service-manager-rs.git", branch = "main" }
@@ -216,26 +215,26 @@ hickory-server = { version = "0.25.2", features = [
"resolver", "resolver",
], optional = true } ], optional = true }
bon = "3.9.1" bon.workspace = true
derive_builder = "0.20.2" derive_builder = { version = "0.20.2", optional = true }
humantime-serde = "1.1.1" humantime-serde = { version = "1.1.1", optional = true }
shellexpand = "3.1.1" shellexpand = "3.1.2"
# for fake tcp # for fake tcp
flume = { version = "0.12", optional = true } flume = { version = "0.12", optional = true }
# for upnp # for upnp
http-body-util = { version = "0.1", optional = true } http-body-util = { workspace = true, optional = true }
hyper = { version = "1", default-features = false, features = ["client", "http1"], optional = true } hyper = { workspace = true, features = ["client", "http1"], optional = true }
hyper-util = { version = "0.1", default-features = false, features = ["tokio"], optional = true } hyper-util = { workspace = true, features = ["tokio"], optional = true }
natpmp = { version = "0.5.0", optional = true } natpmp = { version = "0.5.0", optional = true }
xmltree = { version = "0.10", optional = true } xmltree = { version = "0.12", optional = true }
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd"))'.dependencies]
machine-uid = "0.5.3" machine-uid = "0.6.0"
[target.'cfg(any(target_os = "linux"))'.dependencies] [target.'cfg(any(target_os = "linux"))'.dependencies]
netlink-sys = { version = "0.8.7", optional = true } netlink-sys = { version = "0.9.0", optional = true }
[target.'cfg(all(windows, any(target_arch = "x86_64", target_arch = "x86")))'.dependencies] [target.'cfg(all(windows, any(target_arch = "x86_64", target_arch = "x86")))'.dependencies]
windivert = { git = "https://github.com/EasyTier/windivert-rust.git", rev = "adcc56d1550f7b5377ec2b3429f413ee24a77375", features = [ windivert = { git = "https://github.com/EasyTier/windivert-rust.git", rev = "adcc56d1550f7b5377ec2b3429f413ee24a77375", features = [
"static", "static",
@@ -257,52 +256,50 @@ windows = { version = "0.62.2", features = [
"Win32_System_IO", "Win32_System_IO",
] } ] }
encoding = "0.2" encoding = "0.2"
winreg = "0.52" winreg = "0.56"
windows-service = "0.7.0" windows-service = "0.8.1"
winapi = { version = "0.3.9", features = ["impl-default"] } winapi = { workspace = true, features = ["impl-default"] }
[target.'cfg(not(windows))'.dependencies] [target.'cfg(not(windows))'.dependencies]
jemallocator = { package = "tikv-jemallocator", version = "0.6.0", optional = true, features = [ jemallocator = { package = "tikv-jemallocator", version = "0.7.0", optional = true, features = [
"unprefixed_malloc_on_supported_platforms", "unprefixed_malloc_on_supported_platforms",
] } ] }
jemalloc-ctl = { package = "tikv-jemalloc-ctl", version = "0.6.0", optional = true, features = [ jemalloc-ctl = { package = "tikv-jemalloc-ctl", version = "0.7.0", optional = true, features = [
"use_std", "use_std",
] } ] }
[target.'cfg(not(target_os = "macos"))'.dependencies] [target.'cfg(not(target_os = "macos"))'.dependencies]
jemalloc-sys = { package = "tikv-jemalloc-sys", version = "0.6.0", features = [ jemalloc-sys = { package = "tikv-jemalloc-sys", version = "0.7.1", features = [
"background_threads_runtime_support", "background_threads_runtime_support",
"background_threads", "background_threads",
], optional = true } ], optional = true }
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
jemalloc-sys = { package = "tikv-jemalloc-sys", version = "0.6.0", features = [ jemalloc-sys = { package = "tikv-jemalloc-sys", version = "0.7.1", features = [
], optional = true } ], optional = true }
[build-dependencies] [build-dependencies]
cfg_aliases = "0.2.1" cfg_aliases = "0.2.2"
globwalk = "0.8.1" globwalk = "0.9.1"
regex = "1" regex = "1"
thunk-rs = { git = "https://github.com/easytier/thunk.git", default-features = false, features = [ thunk-rs = { workspace = true, features = [
"win7", "win7",
] } ] }
[dev-dependencies] [dev-dependencies]
criterion = "0.5.1" criterion = "0.8.2"
easytier-core = { path = "../easytier-core", version = "2.7.0", default-features = false, features = [ easytier-core = { workspace = true, features = [
"test-utils", "test-utils",
] } ] }
serial_test = "3.0.0" serial_test = "4.0.1"
rstest = "0.25.0" rstest = "0.27.0"
futures-util = "0.3.31"
maplit = "1.0.2" maplit = "1.0.2"
tempfile = "3.22.0" tempfile.workspace = true
ctor = "0.8.0" stun_codec.workspace = true
stun_codec = "0.3.4" bytecodec.workspace = true
bytecodec = "0.4.15" x25519-dalek = { workspace = true, features = ["static_secrets"] }
x25519-dalek = { version = "2.0", features = ["static_secrets"] } smoltcp = { workspace = true, features = [
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp.git", rev = "0a926767a68bc88d5512afefa7529c5ecdade4ea", default-features = false, features = [
"std", "std",
"medium-ethernet", "medium-ethernet",
"proto-ipv4", "proto-ipv4",
@@ -311,12 +308,13 @@ smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp.git", rev = "0a926767a6
] } ] }
[target.'cfg(target_os = "linux")'.dev-dependencies] [target.'cfg(target_os = "linux")'.dev-dependencies]
defguard_wireguard_rs = "0.4.2" defguard_wireguard_rs = "0.12.0"
tokio-socks = "0.5.2" tokio-socks = "0.5.3"
[features] [features]
default = [ default = [
"cli",
"wireguard", "wireguard",
"websocket", "websocket",
"smoltcp", "smoltcp",
@@ -336,6 +334,7 @@ default = [
"tcp-hole-punch", "tcp-hole-punch",
] ]
full = [ full = [
"cli",
"websocket", "websocket",
"wireguard", "wireguard",
"aes-gcm", "aes-gcm",
@@ -355,6 +354,7 @@ full = [
"extended-services", "extended-services",
"tcp-hole-punch", "tcp-hole-punch",
] ]
cli = ["management", "dep:tabled", "dep:humansize", "dep:terminal_size", "dep:unicode-width"]
wireguard = ["vpn-portal", "dep:boringtun", "dep:hkdf", "dep:sha2", "ring-crypto", "easytier-proto/wireguard"] wireguard = ["vpn-portal", "dep:boringtun", "dep:hkdf", "dep:sha2", "ring-crypto", "easytier-proto/wireguard"]
quic = ["wrapped-transport", "easytier-core/proxy-packet", "dep:quinn", "dep:quinn-proto", "dep:seahash", "dep:rustls", "easytier-proto/quic"] quic = ["wrapped-transport", "easytier-core/proxy-packet", "dep:quinn", "dep:quinn-proto", "dep:seahash", "dep:rustls", "easytier-proto/quic"]
kcp = ["wrapped-transport", "easytier-core/proxy-packet", "dep:kcp-sys"] kcp = ["wrapped-transport", "easytier-core/proxy-packet", "dep:kcp-sys"]
@@ -378,7 +378,7 @@ smoltcp = ["easytier-core/proxy-smoltcp-stack"]
icmp-proxy = ["easytier-core/proxy-packet"] icmp-proxy = ["easytier-core/proxy-packet"]
socks5 = ["smoltcp"] socks5 = ["smoltcp"]
ffi-dataplane = ["socks5"] ffi-dataplane = ["socks5"]
jemalloc = ["dep:jemallocator", "dep:jemalloc-sys"] jemalloc = ["dep:jemallocator"]
jemalloc-prof = [ jemalloc-prof = [
"jemalloc", "jemalloc",
"dep:jemalloc-ctl", "dep:jemalloc-ctl",
@@ -391,6 +391,8 @@ tracing-log = ["tracing/log", "easytier-core/tracing-log"]
logging = [] logging = []
dns-resolver = ["dep:hickory-proto", "dep:hickory-resolver"] dns-resolver = ["dep:hickory-proto", "dep:hickory-resolver"]
magic-dns = [ magic-dns = [
"dep:derive_builder",
"dep:humantime-serde",
"dns-resolver", "dns-resolver",
"dep:hickory-client", "dep:hickory-client",
"dep:hickory-server", "dep:hickory-server",
@@ -446,3 +448,15 @@ hotpath-cpu = ["hotpath"]
hotpath-alloc = ["hotpath"] hotpath-alloc = ["hotpath"]
# For Network Extension on macOS # For Network Extension on macOS
macos-ne = [] macos-ne = []
[package.metadata.cargo-machete]
ignored = [
# Used by build/main.rs, including the Windows-only thunk setup.
"cfg_aliases",
"globwalk",
"regex",
"thunk-rs",
# Referenced by serde attributes or enabled for allocator feature unification.
"humantime-serde",
"jemalloc-sys",
]
+5 -3
View File
@@ -1,3 +1,5 @@
#![cfg(feature = "cli")]
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
ffi::OsString, ffi::OsString,
@@ -22,7 +24,7 @@ use easytier_core::connectivity::stun::StunInfoProvider as _;
use humansize::format_size; use humansize::format_size;
use rust_i18n::t; use rust_i18n::t;
use service_manager::*; use service_manager::*;
use tabled::settings::{Disable, Modify, Style, Width, location::ByColumnName, object::Columns}; use tabled::settings::{Modify, Remove, Style, Width, location::ByColumnName, object::Columns};
use terminal_size::{Width as TerminalWidth, terminal_size}; use terminal_size::{Width as TerminalWidth, terminal_size};
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
@@ -1845,7 +1847,7 @@ impl<'a> CommandHandler<'a> {
struct RouteTableItem { struct RouteTableItem {
ipv4: String, ipv4: String,
hostname: String, hostname: String,
#[tabled(display_with = "format_proxy_cidrs")] #[tabled(display("format_proxy_cidrs"))]
proxy_cidrs: String, proxy_cidrs: String,
next_hop_ipv4: String, next_hop_ipv4: String,
@@ -3127,7 +3129,7 @@ fn apply_column_drops(table: &mut tabled::Table, drop_indices: &[usize]) {
let mut indices = drop_indices.to_vec(); let mut indices = drop_indices.to_vec();
indices.sort_unstable_by(|a, b| b.cmp(a)); indices.sort_unstable_by(|a, b| b.cmp(a));
for index in indices { for index in indices {
table.with(Disable::column(Columns::single(index))); table.with(Remove::column(Columns::one(index)));
} }
} }
+1 -1
View File
@@ -124,7 +124,7 @@ impl Service {
let status = self.status()?; let status = self.status()?;
if status == service_manager::ServiceStatus::NotInstalled { if status == service_manager::ServiceStatus::NotInstalled {
return Err(anyhow::anyhow!("Service is not installed"))?; return Err(anyhow::anyhow!("Service is not installed"));
} }
if status == service_manager::ServiceStatus::Running { if status == service_manager::ServiceStatus::Running {
@@ -221,11 +221,7 @@ fn build_tcp_filter(
b.set_label(l_v4_proto_ok); b.set_label(l_v4_proto_ok);
let l_v4_fragment_ok = b.new_label(); let l_v4_fragment_ok = b.new_label();
b.push(stmt(BPF_LD | BPF_H | BPF_ABS, 6)); b.push(stmt(BPF_LD | BPF_H | BPF_ABS, 6));
b.push_jset( b.push_jset(IPV4_FRAGMENT_OFFSET_MASK, l_reject, l_v4_fragment_ok);
IPV4_FRAGMENT_OFFSET_MASK,
l_reject,
l_v4_fragment_ok,
);
b.set_label(l_v4_fragment_ok); b.set_label(l_v4_fragment_ok);
let dst_ip = match dst_addr.ip() { let dst_ip = match dst_addr.ip() {
@@ -271,9 +267,9 @@ fn build_tcp_filter(
IpAddr::V6(ip) => ip.octets(), IpAddr::V6(ip) => ip.octets(),
_ => unreachable!(), _ => unreachable!(),
}; };
for (i, chunk) in dst_ip.chunks_exact(4).enumerate() { for (i, chunk) in dst_ip.as_chunks::<4>().0.iter().enumerate() {
let off = 24 + (i * 4); let off = 24 + (i * 4);
let v = u32::from_be_bytes(chunk.try_into().unwrap()); let v = u32::from_be_bytes(*chunk);
let l_v6_dstip_word_ok = b.new_label(); let l_v6_dstip_word_ok = b.new_label();
b.push(stmt(BPF_LD | BPF_W | BPF_ABS, off as u32)); b.push(stmt(BPF_LD | BPF_W | BPF_ABS, off as u32));
b.push_jeq(v, l_v6_dstip_word_ok, l_reject); b.push_jeq(v, l_v6_dstip_word_ok, l_reject);
@@ -285,9 +281,9 @@ fn build_tcp_filter(
IpAddr::V6(ip) => ip.octets(), IpAddr::V6(ip) => ip.octets(),
_ => unreachable!(), _ => unreachable!(),
}; };
for (i, chunk) in src_ip.chunks_exact(4).enumerate() { for (i, chunk) in src_ip.as_chunks::<4>().0.iter().enumerate() {
let off = 8 + (i * 4); let off = 8 + (i * 4);
let v = u32::from_be_bytes(chunk.try_into().unwrap()); let v = u32::from_be_bytes(*chunk);
let l_v6_srcip_word_ok = b.new_label(); let l_v6_srcip_word_ok = b.new_label();
b.push(stmt(BPF_LD | BPF_W | BPF_ABS, off as u32)); b.push(stmt(BPF_LD | BPF_W | BPF_ABS, off as u32));
b.push_jeq(v, l_v6_srcip_word_ok, l_reject); b.push_jeq(v, l_v6_srcip_word_ok, l_reject);
@@ -747,7 +743,7 @@ mod tests {
packet[10..12].fill(0); packet[10..12].fill(0);
let mut sum = 0u32; let mut sum = 0u32;
for word in packet[..header_len].chunks_exact(2) { for word in packet[..header_len].as_chunks::<2>().0 {
sum += u32::from(u16::from_be_bytes([word[0], word[1]])); sum += u32::from(u16::from_be_bytes([word[0], word[1]]));
} }
while sum > u16::MAX as u32 { while sum > u16::MAX as u32 {
+1 -1
View File
@@ -350,7 +350,7 @@ pub(crate) fn prepare_proxy_tcp_socket(stream: &TcpStream) -> io::Result<()> {
let socket = SockRef::from(stream); let socket = SockRef::from(stream);
socket.set_tcp_keepalive(&keepalive)?; socket.set_tcp_keepalive(&keepalive)?;
if let Err(error) = socket.set_nodelay(true) { if let Err(error) = socket.set_tcp_nodelay(true) {
tracing::warn!(?error, "set_nodelay failed, ignore it"); tracing::warn!(?error, "set_nodelay failed, ignore it");
} }
+15 -4
View File
@@ -1781,7 +1781,8 @@ pub async fn foreign_network_forward_nic_data() {
use std::{net::SocketAddr, str::FromStr}; use std::{net::SocketAddr, str::FromStr};
use defguard_wireguard_rs::{ use defguard_wireguard_rs::{
InterfaceConfiguration, WGApi, WireguardInterfaceApi, host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, Kernel, WGApi, WireguardInterfaceApi, key::Key, net::IpAddrMask,
peer::Peer,
}; };
pub(super) fn wireguard_ifname(base: &str) -> String { pub(super) fn wireguard_ifname(base: &str) -> String {
@@ -1802,7 +1803,7 @@ pub(super) fn run_wireguard_client(
client_ip: String, client_ip: String,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
// Create new API object for interface // Create new API object for interface
let wgapi = WGApi::new(ifname.to_owned(), false)?; let mut wgapi = WGApi::<Kernel>::new(ifname.to_owned())?;
// create interface // create interface
wgapi.create_interface()?; wgapi.create_interface()?;
@@ -1822,16 +1823,26 @@ pub(super) fn run_wireguard_client(
let interface_config = InterfaceConfiguration { let interface_config = InterfaceConfiguration {
name: ifname.to_owned(), name: ifname.to_owned(),
prvkey: client_private_key.to_string(), prvkey: client_private_key.to_string(),
address: client_ip, addresses: vec![IpAddrMask::from_str(client_ip.as_str())?],
port: 12345, port: 12345,
peers: vec![peer], peers: vec![peer],
mtu: None,
fwmark: None,
}; };
#[cfg(not(windows))] #[cfg(not(windows))]
wgapi.configure_interface(&interface_config)?; wgapi.configure_interface(&interface_config)?;
#[cfg(windows)] #[cfg(windows)]
wgapi.configure_interface(&interface_config, &[])?; wgapi.configure_interface(&interface_config, &[])?;
wgapi.configure_peer_routing(&interface_config.peers)?; // These split-tunnel clients reach the endpoint through an existing route.
// defguard 0.12 also rewrites endpoint routes (or blackholes them without a
// default gateway), so pass only the allowed IPs to its routing helper.
// The actual WireGuard peer above retains its endpoint.
let mut routing_peers = interface_config.peers.clone();
for peer in &mut routing_peers {
peer.endpoint = None;
}
wgapi.configure_peer_routing(&routing_peers)?;
Ok(()) Ok(())
} }
+3 -3
View File
@@ -204,10 +204,10 @@ fn get_insecure_tls_cert<'a>() -> (
rustls::pki_types::PrivateKeyDer<'a>, rustls::pki_types::PrivateKeyDer<'a>,
) { ) {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap();
let cert_der = cert.serialize_der().unwrap(); let cert_der = cert.cert.der().clone();
let private_key = cert.serialize_private_key_der(); let private_key = cert.signing_key.serialize_der();
let private_key = rustls::pki_types::PrivatePkcs8KeyDer::from(private_key); let private_key = rustls::pki_types::PrivatePkcs8KeyDer::from(private_key);
(vec![cert_der.into()], private_key.into()) (vec![cert_der], private_key.into())
} }
pub(crate) async fn upgrade_accepted<S>( pub(crate) async fn upgrade_accepted<S>(
Generated
+3 -3
View File
@@ -48,11 +48,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1776395632, "lastModified": 1789457514,
"narHash": "sha256-Mi1uF5f2FsdBIvy+v7MtsqxD3Xjhd0ARJdwoqqqPtJo=", "narHash": "sha256-Aggle++fTyAifBy+QBPxjM+obO5iepKW/8MDxQtgGvI=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "8087ff1f47fff983a1fba70fa88b759f2fd8ae97", "rev": "89e99bf0778a8f2cd18c9360c3f19c1ee47fc739",
"type": "github" "type": "github"
}, },
"original": { "original": {
+10 -4
View File
@@ -8,9 +8,15 @@ exclude = ["/examples", "/webview-dist", "/webview-src", "/node_modules"]
links = "tauri-plugin-vpnservice" links = "tauri-plugin-vpnservice"
[dependencies] [dependencies]
tauri = { version = "2.0.0-rc" } tauri.workspace = true
serde = "1.0" serde.workspace = true
thiserror = "1.0" thiserror.workspace = true
[build-dependencies] [build-dependencies]
tauri-plugin = { version = "2.0.0-rc", features = ["build"] } tauri-plugin = { version = "2.6.3", features = ["build"] }
[package.metadata.cargo-machete]
ignored = [
# Called by build.rs to generate plugin permissions and bindings.
"tauri-plugin",
]