Commit Graph
8 Commits
Author SHA1 Message Date
KKRainbow 7c8ca07812 refactor(tun): consolidate shared NIC configuration and tests (#2690)
* refactor(tun): consolidate shared NIC configuration and tests

Separate member claims from OS deltas so mobile admission updates do
not compute unused diffs. Reuse effective configurations for desktop
address, route, and MTU updates, and share the platform claims paths.

Remove redundant runtime dispatch and test-only public accessors while
preserving registration cleanup and platform device creation ordering.

Move configuration and lifecycle tests into focused modules. Reuse
setup and table-driven cases, and verify route replacement order,
source hints, stale registrations, and failed cleanup through behavior.

Validation: shared NIC unit and Docker integration tests, mobile claim
selection, TUN and public IPv6 tests, full-workspace clippy, Android
arm64 library check, and formatting of the changed files.

* docs(tun): describe shared Ring dispatch lifecycle

Document direct member Ring polling, mobile descriptor replacement,
and cooperative scheduling in the shared dispatcher. The dispatcher
implementation is already provided by the base branch in #2689.

* test(core): remove completion race from timeout budget test

Use a pending future to exercise stage-specific timeout errors.
A delayed CI runner can observe the old 20 ms sleep and 1 ms timeout
as ready together. Tokio polls the inner future first, returning Ok
instead of the error expected by the test.

Keep the timeout assertion without a competing completion timer.
Production timeout behavior is unchanged.
2026-10-13 23:53:35 +08:00
KKRainbow 32dc7f1f40 feat: add shared virtual nic (#2352)
* Add shared virtual NIC core with per-member routing

Share a named TUN across instances while keeping unnamed devices
dedicated. Track member addresses, routes, and MTU, and reject
overlapping destinations except the common Magic DNS host route.

Dispatch packets between the physical TUN and member tunnels. Keep
IPv4 and ordinary IPv6 source translation for mobile wrong-source
traffic. Update platform configuration and runtime host integration,
with unit and network namespace coverage for routing and lifecycle.

Use smoltcp for packet parsing and checksum updates. Keep core CI
matrix jobs independent.

Reserve native inbound flows before source translations allocate their
wire tuples. Keep active reservations under table pressure and leave
forwarded subnet traffic outside the local flow table.

Complete interface claim updates on the shared runtime and retain member
registrations until the transaction commits. Keep address, route, and
MTU cleanup ordered after cancelled callers, including device
initialization.

Project mobile VPN addresses, routes, and DNS from admitted native
members. Prefer unchanged attached claims and report conflicting members
individually. Apply each member's complete initial claims before opening
the shared fd, so conflicts leave healthy members usable.

Cover inbound IPv4/IPv6 collisions, cancellation during native changes
and dispatcher acknowledgments, admission priority, and atomic mobile
claim rejection with regression tests.

Use scoped TestNetwork fixtures for shared TUN bridge setup and cleanup.
Resolve public IPv6 namespace aliases through the lab's actual names so
the new tests remain isolated under parallel upstream test runs.

* Configure one mobile VPN from running TUN instances

Use admitted native members to configure VpnService and attach its
single fd to the core shared TUN. Wait for attachment completion and
record the actual attached members before refreshing VPN state. Report
rejected members in the GUI and preserve the VPN for unchanged healthy
members.

Reconcile ordinary configuration notifications without invalidating an
arbitrary member. Invalidate attachments on instance lifecycle changes,
including restarts that reuse an instance ID. Forward public IPv6
changes alongside proxy route changes to refresh the platform VPN
configuration.

Exclude confirmed IPv4-less members from readiness gating while
retaining retries for unavailable status and pending addresses. Quick
Settings stops all running TUN members and restores that group on the
next start, skipping removed configurations and no_tun networks.

Keep the FFI set_tun_fd call scoped to one instance and report
attachment errors. Cover mobile configuration, member rejection and
replacement, attachment completion, collection notifications, IPv4-less
members, and tile stop/start restoration in GUI regression tests.

Validate with 36 mobile VPN tests, vue-tsc --noEmit, Android GUI cargo
check, workspace clippy, and shared TUN network namespace tests.

* fix(tun): preserve shared NIC ownership and failure invariants

Keep mobile address and route claims in dispatcher tables without
applying desktop interface configuration to synthetic TUN names.

Limit the Magic DNS overlap exemption to route claims and remove the
shared route retry that bypassed claim accounting after invalidation.

Invalidate and stop dispatchers on failed mobile TUN replacement or I/O.
Bound TUN writes so stalled devices release pending source updates and
member cleanup instead of retaining an unusable shared dispatcher.

Treat missing Darwin and Windows addresses and routes as successful
deletions while preserving permission and other configuration errors.

Add regressions for claim conflicts, mobile configuration, failed TUN
replacement, stalled writes, and platform deletion error handling.

* fix(tun): forward single-member shared NIC traffic unchanged

Deliver TUN packets directly to the sole attached member without
destination matching or creating source translations. Keep native flow
reservations so a later member cannot collide with existing connections,
and continue applying mappings created before other members leave.

Reuse flow preparation with the original source address. Preserve the
desktop subnet forwarding bypass, including when the flow table is full.
IPv4 fragments and IPv6 extension headers remain unchanged on flows that
need no translation.

Cover unknown sources and destinations, first and later IP fragments,
native flows established before another member joins, and retained
translations after returning to one member. Document the forwarding
behavior and retain rejection coverage for multiple attached members.

* fix(tun): preserve wildcard UDP replies on shared member ports

Mark flow reservations created by incoming traffic separately from
outgoing mappings. When a wildcard UDP socket replies with another
member's source address, reuse the incoming reservation after source
correction and preserve its service port and inbound destination.

Keep exact outgoing mappings and outgoing flow collision handling ahead
of this rule. Incoming UDP sessions take priority when packet tuples
cannot distinguish a reply from a new client using identical endpoints.

Cover IPv4 and IPv6 replies, checksum updates, repeated inbound traffic,
existing outgoing mappings, TCP collisions, and single-to-shared member
transitions with regression tests.

* test(tun): wait for IPv6 activation in mobile configuration test

Assert that the configured IPv6 address is registered before forwarding
starts, then wait up to five seconds for the kernel to make it usable.
Netlink acknowledges address creation before asynchronous IPv6
activation completes, so an immediate bind can fail under CI
parallelism.

Disable automatic link-local address generation in the test namespace to
keep startup IPv6 control traffic out of member-routing assertions.

Validation: the original test failed 40 of 320 runs at 32-way
parallelism. The updated test passed all 320 runs; workspace fmt and
clippy also pass.
2026-10-13 21:00:03 +08:00
KKRainbow d31396f04c fix(hole-punch): connect UDP when STUN mapping differs (#2680)
* fix(hole-punch): connect UDP without reverse probe gating

Start cone UDP handshakes on the same punched socket without waiting
for reverse HolePunch packets. Keep outgoing probes while the existing
session layer retries SYN, allowing a reachable listener to reply to the
actual source when the STUN candidate uses a different mapping.

Register source observers on the listener's existing receive loop for
the active cone RPC. Send bounded batches to the signaled endpoint and
the first matching observed source, deduplicating equal endpoints.
Unregister observers on completion, cancellation, or listener shutdown.

Cover missing reverse probes, dropped SYN, late observed sources,
transaction isolation, and cleanup. Document socket and connectivity
ownership of observation and reply policy.

* fix(hole-punch): prepare source observation during listener selection

Carry an optional transaction ID in SelectPunchListener and echo it only
after registering the listener's existing UDP receive loop. Preserve the
first source arriving before SendPunchPacketCone, then transfer cleanup
ownership to that RPC without clearing the observed address.

Keep prepared and active registrations in the same transaction table.
Expire abandoned preparations after 30 seconds through listener cleanup;
active observers still unregister on completion or cancellation.
Preserve legacy requests without a transaction ID and tolerate older
responses without a registration acknowledgement.

Cover early packets, transaction ID zero, preparation expiry, active RPC
cleanup, legacy protobuf interoperability, and SYN retries against peers
with and without registration confirmation. Document the lifetime and
compatibility contract in the core architecture.

Validation: 820 core tests; workspace fmt and full-feature clippy
passed.
2026-10-12 23:19:46 +08:00
fanyang 83baead059 fix(runtime): restore per-instance native thread configuration (#2658)
Restore per-instance Tokio executors for standard native instances,
honoring multi_thread and multi_thread_count with a two-worker minimum
in multi-thread mode. Preserve external execution for compact hosts.

Run construction, lifecycle operations, FFI data-plane tasks, and
hot-reloaded port forwards on the selected instance executor. Keep
shutdown cleanup running when its caller is cancelled, and release
owned executors without blocking their workers on runtime teardown.

Add runtime ownership, cancellation, cross-runtime connectivity, and
hot-reload regression coverage, and document the execution model.

Validation: all 45 PR checks passed, including linting, integration
tests, and cross-platform builds.
2026-10-11 01:17:32 +08:00
KKRainbow f26c2aa147 feat(wasi): run EasyTier core on Cloudflare Workers and browsers (#2548)
* fix(core): normalize secure keys for TOML instances

* feat(wasi): run core behind Cloudflare WebSockets

Introduce the Cloudflare Worker WASI host that runs the EasyTier core
behind host-upgraded WebSockets.

- Worker package scaffold (wrangler Durable Object, build-wasm script,
  vitest config) and core-runtime/websocket-host/data-plane runtime.
- WASI host WebSocket tunnel ABI (imports, adapter, runtime exports)
  with bounded receive memory and bounded admission queue.
- Route host sockets through the portable listener plan
  (HostListenerRegistration, listener queue, admission handler split).
- Build the WASM guest with the aes-gcm feature so secure peer
  sessions have their cipher available.

* feat(wasi): add outbound browser client runtime

Add the outbound-only WASI runtime and browser connector host so
browser pages can dial EasyTier peers through WebSocket relays.

- CoreConnectivityMode::{OutboundOnly, InboundOnly} gating for
  listeners, discovery, and direct connectivity modules.
- ExternalTunnelConnector plumbing through composite/connector_host/
  manual for browser WebSocket dials.
- Browser/Node smoke entries with shared helpers
  (smoke-shared.ts).

* feat(wasi): extend browser data plane with TCP half-close

Add the data-plane pieces the browser runtime needs for full-duplex
TCP streams behind host WebSockets:

- Guest TCP shutdown_write operation with submit/take ABI pair
  (DATA_PLANE_ABI_VERSION 3 -> 4) and smoltcp half-close support.
- Worker data-plane TCP listener/stream plumbing and core-runtime
  listener registration.
- Unit coverage for the new session ops and listener wiring.

* refactor(wasi): make host tunnel ABI transport-neutral

Replace WebSocket-specific core and WASI boundaries with a
message-oriented Host Tunnel interface. Keep WebSocket framing and text
rejection in the Cloudflare host while preserving payload boundaries,
ownership, cancellation, backpressure, and EOF behavior.

Rename feature flags and guest imports and exports to the Host Tunnel
ABI. Update both Worker profiles, tests, and architecture documentation.

* feat(web): split WASI hosts into publishable npm packages

Extract the shared JSPI, WASI, Host Tunnel, and data-plane runtime
into @easytier/runtime. Keep ABI handles, guest memory, TOML, and
operation broker details behind its adapter entry point.

Add typed, auto-starting @easytier/browser and factory-based
@easytier/cloudflare packages. Ship a matching Wasm profile with
each platform package and validate its capabilities before packing.

Persist Cloudflare instance identity in Durable Object storage,
centralize WebSocket admission ownership, and add package-level
coverage for the public interfaces.

* fix(web): make public packages portable

Embed the browser Wasm artifact in the published JavaScript entry
point. This lets esbuild consumers bundle the package without an asset
loader or a copied file.

Return Cloudflare's nominal Durable Object base type and document the
named subclass export required by generated Wrangler bindings.

* docs(web): add public package walkthrough

Expand both package READMEs with installation, configuration, local
validation, health checks, and deployment instructions.

Add a standalone Vite and Wrangler example that imports only the
public Browser and Cloudflare entries. Generate Worker bindings from
configuration and keep local secrets outside version control.

* chore(go): import EasyTier Go host

Add the standalone Go host runtime as a monorepo subtree without
carrying its development branch ancestry.

Preserve its API, tests, examples, generated protobuf bindings, and
embedded WASI artifacts.

* refactor(hosts): colocate Go and JavaScript runtimes

Move the browser, Cloudflare, shared runtime, and web example into
the easytier-js subtree. Update workspace metadata, build paths, and
documentation for the new layout.

Adopt github.com/EasyTier/EasyTier/easytier-go as the Go module path.
Resolve artifact and protobuf generation from the enclosing monorepo.

* build(web): isolate JavaScript host workspace

Keep public browser and Cloudflare packages outside the legacy frontend
workspace so root installs and cross-platform builds do not pull workerd.

Make each package build generate its required WASI artifact from a clean
checkout. Add a dedicated workflow that runs the same install and check
commands documented for contributors.

Move JavaScript dependencies into a scoped lockfile and restore the root
workspace lockfile to its pre-host state.
2026-09-06 13:35:02 +08:00
KKRainbow 25f6e2dc5e feat: stabilize mobile runtime and VPN portal (#2536) 2026-08-29 13:40:56 +08:00
KKRainbow d375d7e455 feat(mini): add compact native EasyTier client (#2479)
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.
2026-08-09 19:43:30 +08:00
KKRainbow 021f523431 refactor(core): separate portable core from native runtime (#2451)
Create easytier-core as the portable owner of configuration,
connectivity, tunnels, peer and routing state, gateways, management,
the data plane, and instance lifecycle. Keep operating-system
integration, native protocol engines, process startup, and presentation
in easytier behind explicit Host capability adapters.

Create easytier-proto to own schemas, generated RPC types, descriptors,
and feature-scoped protocol slices. Remove runtime protobuf reflection
from core while preserving unknown route-peer fields across forwarding.

Normalize instance construction through CoreInstance, CoreHostAdapters,
CoreProcessRuntime, and InstanceManager. Make the runtime config store
the only authoritative mutable configuration after startup.

Move the portable TCP/UDP data plane into core and extract a generic
OperationBroker for completion, cancellation, disposal, and capacity
accounting. Expose the session-based FFI v2 completion API and keep the
WASI guest ABI, wire schemas, and adapters with core.

Migrate CLI, GUI, web, FFI, Android JNI, OHOS, uptime, and mobile
consumers to the shared manager and core state. Add explicit user/web
config ownership and revision-aware web reconciliation.

Preserve configuration, wire, and management behavior while fixing
regressions discovered by the full platform and integration matrix:

- inherit advertised relay capabilities in foreign networks;
- refresh OSPF peer state immediately after runtime config changes;
- restore CLI GlobalCtx event output without forcing GUI logging;
- retain legacy encryption names and standalone RPC tunnel metadata;
- restore ICMP host composition and fragmented UDP handling;
- use portable 64-bit atomics on 32-bit MIPS targets; and
- retain discarded operations until late cancellation completes.

Validate the refactor across 45 GitHub checks, including Linux, macOS,
Windows, FreeBSD, web, GUI, Android, OHOS, feature profiles, and
three-node and subnet-proxy integration tests.

BREAKING CHANGE: internal Rust module paths are not preserved. Legacy
native data-plane APIs are replaced by the session-based FFI v2 API.
The dedicated Android data-plane wrapper is removed.
2026-07-26 15:41:55 +08:00