mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-10-15 17:16:14 -08:00
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.
This commit is contained in:
1 parent
99fce327d5
commit
32dc7f1f40
42 files changed
+10052
-702
No files matched your search
@@ -413,6 +413,73 @@ Process-global capability objects may contain stateless or shared platform
|
||||
mechanisms. They must not contain instance-specific peer, route,
|
||||
configuration, or connectivity state.
|
||||
|
||||
### Native shared TUN ownership
|
||||
|
||||
The native composition owns `SharedVirtualNicRegistry`. Named desktop TUNs
|
||||
are shared within a network namespace; mobile instances attach to one supplied
|
||||
TUN descriptor. Members own address, route, and MTU claims, not the physical
|
||||
device. Bootstrap route cleanup runs only when that device is created. Mobile
|
||||
IPv6 claims are initialized before forwarding and follow public IPv6 updates.
|
||||
Mobile VPN configuration is projected from admitted members' native claims.
|
||||
Admission keeps unchanged attached members ahead of conflicting newcomers or
|
||||
reconfigured members. Rejected members are reported individually, while the
|
||||
remaining members stay attached. Each member's initial claims are applied as
|
||||
one batch before it can open or replace the shared descriptor.
|
||||
Mobile claims update dispatcher tables without configuring the OS interface;
|
||||
the platform VPN owns its addresses, routes, and MTU.
|
||||
If applying native claims fails, the shared NIC is invalidated and its
|
||||
dispatcher is stopped so every member can recreate the device. Restoring only
|
||||
the recorded claims would leave partially applied OS configuration in use.
|
||||
TUN replacement and I/O failures also invalidate the shared NIC. TUN writes
|
||||
have bounded waits so a stalled device cannot indefinitely block claim updates
|
||||
or member cleanup.
|
||||
|
||||
Desktop and mobile shared TUNs use the same lazily initialized native Tokio
|
||||
runtime, independent of every member's executor. It creates the device's async
|
||||
I/O registration, drives dispatchers, and completes member claim cleanup even
|
||||
after the member executor stops or the registration is dropped outside Tokio.
|
||||
The runtime has two workers on desktop to allow independent TUN dispatchers
|
||||
to run concurrently, and retains one worker on mobile. It owns no registry or
|
||||
member claims; those remain with each shared NIC. Cleanup remains asynchronous,
|
||||
and the last member's cleanup stops the dispatcher and releases the desktop
|
||||
device. A process-lifetime runtime does not extend the device's lifetime.
|
||||
Unnamed desktop TUNs and instance-local work retain their existing executors.
|
||||
|
||||
Only the member running the Magic DNS resolver claims its shared fake-IP
|
||||
route. The claim is removed before resolver shutdown and acquired by the next
|
||||
serving member after takeover. Client-only runners do not claim that route.
|
||||
|
||||
The dispatcher preserves desktop kernel-forwarded subnet sources. It corrects
|
||||
wrong-member local sources and, on mobile, synthetic sources. Native local
|
||||
flows and translated flows reserve member-scoped transport tuples so address
|
||||
translation cannot merge sockets using the same port and remote endpoint.
|
||||
Collisions remap the source port or ICMP Echo identifier; replies restore the
|
||||
original tuple. Unrelated route updates and member removals retain mappings.
|
||||
All Echo sequence numbers for one identifier share a reservation; translation
|
||||
preserves the sequence field in each request and reply.
|
||||
Removing an involved address or member releases its mappings. A full member
|
||||
queue drops that packet without blocking other members or control messages.
|
||||
|
||||
With one attached member, packets go directly to that member without destination
|
||||
matching or new source translations. Native flow reservations remain active so
|
||||
later members cannot reuse their tuples. Existing translations continue in both
|
||||
directions after other members leave. Unmodified IPv4 fragments and IPv6
|
||||
extension headers pass through the single-member path unchanged.
|
||||
|
||||
Reservations are bounded at 4096 flows. Activity in either direction refreshes
|
||||
them; table pressure reclaims reservations idle for at least 180 seconds. If
|
||||
all slots remain active, new tracked flows are dropped rather than evicting a
|
||||
live mapping. Desktop external-source forwarding bypasses this table. As with
|
||||
other idle-expiring NAT state, very late replies after tuple reuse cannot be
|
||||
distinguished from replies to the new flow.
|
||||
|
||||
Translation supports unfragmented IPv4 and ordinary IPv6 TCP, UDP, and ICMP
|
||||
Echo traffic. IPv4 fragment and IPv6 extension-header translation remain
|
||||
unsupported. ICMP errors quoting a translated flow are not reverse-translated;
|
||||
in particular, a smaller downstream MTU can prevent PMTU discovery for such
|
||||
flows. This limitation does not affect unmodified flows and is intentionally
|
||||
retained rather than extending the dispatcher into a full ICMP/fragment NAT.
|
||||
|
||||
## Runtime configuration authority
|
||||
|
||||
`TomlConfig` is the authoritative desired configuration used for management
|
||||
|
||||
Reference in new issue
Block a user