mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-03 09:35:41 +00:00
Add a native EasyTier proof-of-concept binary with TCP and UDP transports, TUN, UDP hole punching, AES-GCM, and a read-only RPC portal. Introduce a release-derived mini profile and musl linker policy so x86_64, big-endian MIPS, and little-endian MIPS stay below the strict 5,000,000-byte target without UPX.
219 lines
7.7 KiB
Rust
219 lines
7.7 KiB
Rust
use std::sync::Arc;
|
|
|
|
use easytier_core::{
|
|
config::peers::HostRoutingPolicy, instance::CoreInstanceHostConfig,
|
|
peers::credential_manager::CredentialStorage,
|
|
};
|
|
use strum::VariantArray as _;
|
|
|
|
#[cfg(feature = "management")]
|
|
use crate::common::credential_manager::runtime_credential_storage;
|
|
#[cfg(test)]
|
|
use crate::common::global_ctx::GlobalCtxEvent;
|
|
use crate::{
|
|
common::{constants::EASYTIER_VERSION, global_ctx::ArcGlobalCtx},
|
|
tunnel::IpScheme,
|
|
};
|
|
|
|
/// Projects only native Host policy and build capabilities. All TOML-derived
|
|
/// Instance configuration is normalized by `easytier-core`.
|
|
pub(crate) fn runtime_core_host_config() -> CoreInstanceHostConfig {
|
|
let hostname = gethostname::gethostname().to_string_lossy().to_string();
|
|
CoreInstanceHostConfig {
|
|
hostname_fallback: (!hostname.is_empty()).then_some(hostname),
|
|
host_routing: HostRoutingPolicy {
|
|
local_exit_node_fallback: cfg!(target_env = "ohos"),
|
|
},
|
|
force_exit_node: cfg!(target_env = "ohos"),
|
|
allow_interface_bind: !cfg!(any(
|
|
target_os = "android",
|
|
target_os = "ios",
|
|
all(target_os = "macos", feature = "macos-ne"),
|
|
target_env = "ohos"
|
|
)),
|
|
smoltcp_available: cfg!(feature = "smoltcp"),
|
|
requires_smoltcp: cfg!(any(
|
|
target_os = "android",
|
|
target_os = "ios",
|
|
all(target_os = "macos", feature = "macos-ne"),
|
|
target_env = "ohos"
|
|
)),
|
|
icmp_failure_is_fatal: cfg!(not(any(
|
|
target_os = "android",
|
|
target_os = "ios",
|
|
all(target_os = "macos", feature = "macos-ne"),
|
|
target_env = "ohos"
|
|
))),
|
|
public_ipv6_provider_supported: cfg!(all(
|
|
target_os = "linux",
|
|
feature = "public-ipv6-provider"
|
|
)),
|
|
gateway_enabled: cfg!(feature = "socks5"),
|
|
proxy_enabled: cfg!(any(feature = "kcp", feature = "quic")),
|
|
vpn_portal_enabled: cfg!(feature = "wireguard"),
|
|
magic_dns_enabled: cfg!(feature = "magic-dns"),
|
|
kcp_enabled: cfg!(feature = "kcp"),
|
|
quic_enabled: cfg!(feature = "quic"),
|
|
udp_broadcast_enabled: cfg!(all(target_os = "windows", feature = "tun")),
|
|
upnp_enabled: cfg!(feature = "upnp"),
|
|
tcp_hole_punching_enabled: cfg!(feature = "tcp-hole-punch"),
|
|
ignore_unsupported_config: false,
|
|
easytier_version: EASYTIER_VERSION.to_owned(),
|
|
endpoint_protocols: IpScheme::VARIANTS.iter().map(ToString::to_string).collect(),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn compact_runtime_core_host_config() -> CoreInstanceHostConfig {
|
|
let mut config = runtime_core_host_config();
|
|
config.force_exit_node = false;
|
|
config.host_routing.local_exit_node_fallback = false;
|
|
config.public_ipv6_provider_supported = false;
|
|
config.gateway_enabled = false;
|
|
config.proxy_enabled = false;
|
|
config.vpn_portal_enabled = false;
|
|
config.magic_dns_enabled = false;
|
|
config.kcp_enabled = false;
|
|
config.quic_enabled = false;
|
|
config.udp_broadcast_enabled = false;
|
|
config.upnp_enabled = false;
|
|
config.tcp_hole_punching_enabled = false;
|
|
config.ignore_unsupported_config = true;
|
|
config.endpoint_protocols = vec!["tcp".to_owned(), "udp".to_owned()];
|
|
config
|
|
}
|
|
|
|
pub(crate) fn runtime_peer_credential_storage(
|
|
global_ctx: &ArcGlobalCtx,
|
|
) -> Option<Arc<dyn CredentialStorage>> {
|
|
#[cfg(not(feature = "management"))]
|
|
{
|
|
let _ = global_ctx;
|
|
None
|
|
}
|
|
#[cfg(feature = "management")]
|
|
runtime_credential_storage(global_ctx.config.get_credential_file())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub(crate) fn test_core_instance_config(
|
|
global_ctx: &ArcGlobalCtx,
|
|
) -> easytier_core::instance::CoreInstanceConfig {
|
|
use easytier_core::config::toml::{ConfigLoader as _, TomlConfig};
|
|
|
|
let config = TomlConfig::new_from_str(&global_ctx.config.dump())
|
|
.expect("test configuration should round-trip through TOML");
|
|
config.set_ipv4(global_ctx.get_ipv4());
|
|
config.set_ipv6(global_ctx.get_ipv6());
|
|
config.set_flags(global_ctx.get_flags());
|
|
let mut host = runtime_core_host_config();
|
|
let hostname = global_ctx.get_hostname();
|
|
host.hostname_fallback = (!hostname.is_empty()).then_some(hostname);
|
|
easytier_core::instance::CoreInstanceConfig::from_toml_with_host(&config, &host)
|
|
.expect("test configuration should normalize")
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub(crate) fn test_runtime_instance_config(
|
|
global_ctx: &ArcGlobalCtx,
|
|
) -> easytier_core::config::runtime::CoreInstanceRuntimeConfig {
|
|
let config = test_core_instance_config(global_ctx);
|
|
easytier_core::config::runtime::CoreInstanceRuntimeConfig {
|
|
services: config.connectivity.runtime,
|
|
peer: Arc::new(config.peer.snapshot),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use easytier_core::{
|
|
config::toml::TomlConfig,
|
|
events::{CoreEvent, CoreEventSink},
|
|
};
|
|
|
|
use crate::common::global_ctx::tests::get_mock_global_ctx;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn native_host_config_contains_only_platform_policy() {
|
|
let config = runtime_core_host_config();
|
|
let hostname = gethostname::gethostname().to_string_lossy().to_string();
|
|
|
|
assert_eq!(
|
|
config.hostname_fallback,
|
|
(!hostname.is_empty()).then_some(hostname)
|
|
);
|
|
assert_eq!(config.gateway_enabled, cfg!(feature = "socks5"));
|
|
assert_eq!(config.smoltcp_available, cfg!(feature = "smoltcp"));
|
|
assert_eq!(
|
|
config.public_ipv6_provider_supported,
|
|
cfg!(all(target_os = "linux", feature = "public-ipv6-provider"))
|
|
);
|
|
assert_eq!(config.easytier_version, EASYTIER_VERSION);
|
|
}
|
|
|
|
#[test]
|
|
fn clearing_configured_hostname_does_not_reuse_the_old_value() {
|
|
let host = runtime_core_host_config();
|
|
let initial = TomlConfig::new_from_str("hostname = \"configured-host\"").unwrap();
|
|
let cleared = TomlConfig::new_from_str("hostname = \"\"").unwrap();
|
|
|
|
let initial =
|
|
easytier_core::instance::CoreInstanceConfig::from_toml_with_host(&initial, &host)
|
|
.unwrap();
|
|
let cleared =
|
|
easytier_core::instance::CoreInstanceConfig::from_toml_with_host(&cleared, &host)
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
initial.peer.snapshot.runtime.core.node.hostname.as_deref(),
|
|
Some("configured-host")
|
|
);
|
|
assert_ne!(
|
|
cleared.peer.snapshot.runtime.core.node.hostname.as_deref(),
|
|
Some("configured-host")
|
|
);
|
|
assert_eq!(
|
|
cleared.peer.snapshot.runtime.core.node.hostname.as_deref(),
|
|
host.hostname_fallback.as_deref()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_config_uses_current_global_context_hostname_as_fallback() {
|
|
let global_ctx = get_mock_global_ctx();
|
|
global_ctx.set_hostname("test-hostname".to_owned());
|
|
|
|
let config = test_core_instance_config(&global_ctx);
|
|
|
|
assert_eq!(
|
|
config.peer.snapshot.runtime.core.node.hostname.as_deref(),
|
|
Some("test-hostname")
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn core_event_sink_projects_peer_events_to_global_context() {
|
|
let global_ctx = get_mock_global_ctx();
|
|
let mut events = global_ctx.subscribe();
|
|
CoreEventSink::emit(global_ctx.as_ref(), CoreEvent::PeerAdded(7));
|
|
|
|
assert!(matches!(
|
|
events.recv().await.unwrap(),
|
|
GlobalCtxEvent::PeerAdded(7)
|
|
));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn core_event_sink_projects_credential_changes_to_global_context() {
|
|
let global_ctx = get_mock_global_ctx();
|
|
let mut events = global_ctx.subscribe();
|
|
CoreEventSink::emit(global_ctx.as_ref(), CoreEvent::CredentialChanged);
|
|
|
|
assert!(matches!(
|
|
events.recv().await.unwrap(),
|
|
GlobalCtxEvent::CredentialChanged
|
|
));
|
|
}
|
|
}
|