mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-04 10:05:42 +00:00
Introduce shared NIC source ownership and dispatcher handling so a single dev_name can be shared by multiple tun-enabled instances while keeping per-member IP and route claims distinct. Pass Android VpnService fd registration with per-instance source and route claims. Keep the VPN address list limited to real member addresses and allow AF_INET6 without installing hidden fd00::1. Invalidate dispatcher flow and NAT state when source ownership changes or a member unregisters. Avoid rewriting non-first IPv4 fragment payloads, and adjust fragmented TCP/UDP checksums without recomputing over partial fragment bodies. Preserve source-owner routing for equal-prefix route conflicts, keep ICMP echo NAT entries distinct by echo id, and retry stale flow-owner send failures from the original packet. Only record NAT state after a translated packet is accepted by its member. Apply Linux IPv4 route preferred-source hints for shared routes and keep route repair paths source-aware. Keep Darwin ifcfg access scoped to cleanup-only paths where netns is not available.
163 lines
5.1 KiB
TypeScript
163 lines
5.1 KiB
TypeScript
import { invoke } from '@tauri-apps/api/core'
|
|
import { Api, NetworkTypes } from 'easytier-frontend-lib'
|
|
import { GetNetworkMetasResponse } from 'node_modules/easytier-frontend-lib/dist/modules/api'
|
|
import { type ConfigSource, normalizeConfigSource } from './config_source'
|
|
|
|
type NetworkConfig = NetworkTypes.NetworkConfig
|
|
type ValidateConfigResponse = Api.ValidateConfigResponse
|
|
type ListNetworkInstanceIdResponse = Api.ListNetworkInstanceIdResponse
|
|
interface ServiceOptions {
|
|
config_dir: string
|
|
rpc_portal: string
|
|
file_log_level: string
|
|
file_log_dir: string
|
|
config_server?: string
|
|
}
|
|
|
|
export type ServiceStatus = "Running" | "Stopped" | "NotInstalled"
|
|
|
|
interface StoredGuiConfig {
|
|
config: NetworkConfig
|
|
source: ConfigSource
|
|
}
|
|
|
|
function parseStoredConfigs(raw: string | null): StoredGuiConfig[] {
|
|
const parsed: unknown = JSON.parse(raw || '[]')
|
|
if (!Array.isArray(parsed)) {
|
|
return []
|
|
}
|
|
|
|
return parsed.flatMap((entry): StoredGuiConfig[] => {
|
|
if (entry && typeof entry === 'object' && 'config' in entry) {
|
|
const { config, source } = entry as {
|
|
config?: NetworkConfig
|
|
source?: unknown
|
|
}
|
|
if (!config) {
|
|
return []
|
|
}
|
|
return [{
|
|
config: NetworkTypes.normalizeNetworkConfig(config),
|
|
source: normalizeConfigSource(source),
|
|
}]
|
|
}
|
|
|
|
return [{
|
|
config: NetworkTypes.normalizeNetworkConfig(entry as NetworkConfig),
|
|
source: 'legacy',
|
|
}]
|
|
})
|
|
}
|
|
|
|
export async function parseNetworkConfig(cfg: NetworkConfig) {
|
|
return invoke<string>('parse_network_config', { cfg: NetworkTypes.toBackendNetworkConfig(cfg) })
|
|
}
|
|
|
|
export async function generateNetworkConfig(tomlConfig: string) {
|
|
const config = await invoke<NetworkConfig>('generate_network_config', { tomlConfig })
|
|
return NetworkTypes.normalizeNetworkConfig(config)
|
|
}
|
|
|
|
export async function runNetworkInstance(cfg: NetworkConfig, save: boolean) {
|
|
return invoke('run_network_instance', { cfg: NetworkTypes.toBackendNetworkConfig(cfg), save })
|
|
}
|
|
|
|
export async function collectNetworkInfo(instanceId: string) {
|
|
return await invoke<Api.CollectNetworkInfoResponse>('collect_network_info', { instanceId })
|
|
}
|
|
|
|
export async function setLoggingLevel(level: string) {
|
|
return await invoke('set_logging_level', { level })
|
|
}
|
|
|
|
export interface TunFdInstanceSources {
|
|
instanceId: string
|
|
ipv4Addrs: string[]
|
|
ipv6Addrs?: string[]
|
|
ipv4Routes?: string[]
|
|
ipv6Routes?: string[]
|
|
}
|
|
|
|
export async function setTunFd(fd: number, instanceIds?: string[], instanceSources?: TunFdInstanceSources[]) {
|
|
const args: { fd: number, instanceIds?: string[], instanceSources?: TunFdInstanceSources[] } = { fd }
|
|
if (instanceIds?.length) {
|
|
args.instanceIds = instanceIds
|
|
}
|
|
if (instanceSources?.length) {
|
|
args.instanceSources = instanceSources
|
|
}
|
|
return await invoke('set_tun_fd', args)
|
|
}
|
|
|
|
export async function getEasytierVersion() {
|
|
return await invoke<string>('easytier_version')
|
|
}
|
|
|
|
export async function listNetworkInstanceIds() {
|
|
return await invoke<ListNetworkInstanceIdResponse>('list_network_instance_ids')
|
|
}
|
|
|
|
export async function deleteNetworkInstance(instanceId: string) {
|
|
return await invoke('remove_network_instance', { instanceId })
|
|
}
|
|
|
|
export async function updateNetworkConfigState(instanceId: string, disabled: boolean) {
|
|
return await invoke('update_network_config_state', { instanceId, disabled })
|
|
}
|
|
|
|
export async function saveNetworkConfig(cfg: NetworkConfig) {
|
|
return await invoke('save_network_config', { cfg: NetworkTypes.toBackendNetworkConfig(cfg) })
|
|
}
|
|
|
|
export async function validateConfig(cfg: NetworkConfig) {
|
|
return await invoke<ValidateConfigResponse>('validate_config', { cfg: NetworkTypes.toBackendNetworkConfig(cfg) })
|
|
}
|
|
|
|
export async function getConfig(instanceId: string) {
|
|
const config = await invoke<NetworkConfig>('get_config', { instanceId })
|
|
return NetworkTypes.normalizeNetworkConfig(config)
|
|
}
|
|
|
|
export async function sendConfigs(enabledNetworks: string[]) {
|
|
const networkList = parseStoredConfigs(localStorage.getItem('networkList'))
|
|
return await invoke('load_configs', {
|
|
configs: networkList.map(({ config, source }) => ({
|
|
config: NetworkTypes.toBackendNetworkConfig(config),
|
|
source,
|
|
})),
|
|
enabledNetworks,
|
|
})
|
|
}
|
|
|
|
export async function getNetworkMetas(instanceIds: string[]) {
|
|
return await invoke<GetNetworkMetasResponse>('get_network_metas', { instanceIds })
|
|
}
|
|
|
|
export async function initService(opts?: ServiceOptions) {
|
|
return await invoke('init_service', { opts })
|
|
}
|
|
|
|
export async function setServiceStatus(enable: boolean) {
|
|
return await invoke('set_service_status', { enable })
|
|
}
|
|
|
|
export async function getServiceStatus() {
|
|
return await invoke<ServiceStatus>('get_service_status')
|
|
}
|
|
|
|
export async function initRpcConnection(isNormalMode: boolean, url?: string) {
|
|
return await invoke('init_rpc_connection', { isNormalMode, url })
|
|
}
|
|
|
|
export async function isClientRunning() {
|
|
return await invoke<boolean>('is_client_running')
|
|
}
|
|
|
|
export async function initWebClient(url?: string) {
|
|
return await invoke('init_web_client', { url })
|
|
}
|
|
|
|
export async function isWebClientConnected() {
|
|
return await invoke<boolean>('is_web_client_connected')
|
|
}
|