mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-10-08 10:56:13 -08:00
main
15
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4837468d43 | fix(gui/web): 修复丢包率和 NAT 类型显示 (#2643) | ||
|
|
651a8d9e25 |
feat(web): add central network management console (#2622)
Persist central network intent and compile complete per-device configs with secure credentials, ACL policy, and dedicated Gateway runtimes. Expose network, credential, device registry, and runtime observation APIs. Treat central management and external Console as alternative consumers of the upstream ClientManager. Register central devices through a local webhook handler and publish through existing runtime reconciliation. Serialize public mutations with enrollment, reject direct credential changes to managed instances, and retain REST revision invalidation. Keep Gateway lifecycle publication in the central service and remove obsolete incremental result bookkeeping. Restore persisted networks and retire orphan runtimes through the same serialized publisher. Add Core and protocol support for Gateway and WireGuard management, including GUI bindings and serialized GUI config writes. Bootstrap IPv4 for DHCP-only networks and retain assigned addresses without peer IPv4. Cover intent transactions, complete configuration publication, offline recovery, authentication, revocation, Gateway lifecycle, and DHCP. Validate central candidates before persistence using Core URL, config, and portal-client rules. Reject unsupported peer schemes, unconvertible proxy subnets, and invalid portal clients without changing live intent. Expose existing pure Core validators without changing runtime behavior. Gate API-facing credential validation on API-enabled Core builds so minimal WASM targets do not reference omitted management types. Preserve session-backed device views in external Console mode. Bound Gateway admissions without cancelling transport upgrades, and cancel pending peer handshakes before retiring runtimes. Batch registry reads and bound runtime observation concurrency. Randomize DHCP bootstrap and conflict retries, keep an advertised current subnet, and select fallback subnets deterministically. Cover concurrent startup, Gateway admission lifetime, and external Console regressions. Allow DHCP bootstrap with no remote routes. Count network members through one tenant-scoped query without write transactions. Cover zero- peer allocation and tenant/empty-network counts. Preserve direct Web configurations and disabled states in central device snapshots. Remove obsolete central rows atomically with membership changes. Stop online managed instances before deleting or blocking devices, retaining intent when shutdown or deletion fails. Persist automatic IPv4 allocations separately from manual overrides so subnet changes reallocate only automatic members. Normalize mapped proxy routes to their advertised CIDRs when granting temporary credentials. Cover publication, deletion rollback, subnet migration, and grant updates. Read central intent in deferred transactions so polling does not reserve the SQLite writer lock. Test reads with an active writer and assert the temporary-member secret constraint using a valid device fixture. Persist patched WireGuard clients from the saved Web or GUI candidate without a follow-up RPC. Preserve pending settings and ownership, and cover disconnects and failed patches. Resolve named credential and config mutations against the live Core instance before checking central ownership. Forward authorized mutations by UUID on the same session, including while network renames are pending. Cover all mutation methods and preserve direct Console behavior. * feat(web-ui): add central network console and WireGuard management Add network and device views with central membership, credentials, ACL policy, temporary peers, and per-instance runtime details. Update console navigation, styling, theme handling, and API clients. Extend shared configuration and status components for central networks. Add a WireGuard portal dialog for setup and running-device management, with matching translations and network configuration types. Use secure UUID generation on HTTP, discard stale member configuration responses, and stop node-detail polling when the component unmounts. Update frontend workspace dependencies and include component, dashboard, configuration serialization, and central console end-to-end tests. Add isolated real-Core E2E coverage for central data-plane traffic, ACL, DHCP, recovery, device lifecycle, and native WireGuard clients. Record all 59 functional checks with evidence and confirmed validation/UI defects; keep runtime artifacts and test credentials out of Git. Normalize protobuf logger levels and render translated labels correctly. Cover all six levels across setting, reload, and language changes. Add real configuration-rejection E2E checks for database and Core stability and uninterrupted traffic, and record the resolved audit findings. Gate central navigation and registry actions by console mode. Refresh WireGuard settings on mounted status views and preserve explicit portal listener endpoints. Explain the trusted permanent-member ACL boundary. Cover external Console rendering, portal refresh retries and teardown, and explicit IPv4/IPv6 listener exports. Preserve PublicServer discovery when saving its settings, including when its URL matches the Gateway. Cover renaming and endpoint edits in the browser. Display automatic member addresses without converting them to manual overrides during edits. Derive offline address prefixes from the network subnet. Add browser regression coverage and real-Core checks for direct configuration preservation, temporary proxy mappings, automatic subnet migration, and shutdown before device deletion. Build enrollment commands from the configured API hostname, including IPv6 and relative endpoints. Use the PublicServer connector in temporary credential CLI and TOML exports. Add browser regression coverage. Preserve form credentials across repeated normalization and GUI storage reloads. Keep explicit form values authoritative over backend keys and cover JSON persistence, idempotence, replacement, and clearing. |
||
|
|
ebf0b947b9 |
fix(ospf): resync missing peer data after metadata expiry (#2599)
Report missing peer metadata and connection rows in sync responses. Resend those records through the existing per-session pending queues without resetting the incremental cursor or rebuilding sessions. Keep requests across lost responses, distinguish missing connection rows from metadata, and avoid requesting non-relaying credential rows. Deduplicate records selected by both incremental and pending paths. Cover selective expiry, multihop recovery, retries, partial availability, and unchanged-record suppression. All 40 route module tests pass. Fixes #2597 |
||
|
|
7223677264 |
cargo: upgrade (#2116)
update dependencies |
||
|
|
c96b6c1961 |
fix(web): harden managed config sync between console and clients (#2567)
* fix(web): fence managed config runtime reconciliation Keep runtime reconciliation tied to the currently authorized session so stale connections cannot mutate a replacement session runtime. Accumulate only contiguous dirty IDs and load their latest SQLite state. Require the applied revision to match the earliest Patch base and the persisted revision to match the latest target. Otherwise, reconcile the full desired state. Use separate runtime-state and config-cache epochs. Managed updates can reuse observed configs; direct mutations invalidate them. Update sync documentation to match. * fix(web): interrupt validation retry on state changes Track meaningful validation state changes separately from periodic dirty signals. Applied revision changes wake a failed validation immediately, while heartbeat-driven revalidation retains the retry backoff. Treat Notify as a wake-up hint and recheck the state-change epoch after every wake so stored permits and periodic heartbeats cannot cause retry storms. * fix(web): retry unconfirmed connected webhooks Retry node-connected webhook delivery on retryable errors with a short 100ms/500ms backoff and give up immediately on non-retryable errors. Re-check that the session still owns the connection before every attempt and before recording the delivery, so a replaced session can no longer record a stale connected binding. * fix(web): fence disconnects by session ownership Return whether session removal actually removed the current route owner, and emit disconnected only for that owner. Replaced sessions can no longer invalidate a newer connected route. * fix(web): hot-patch managed hostnames Include hostname changes in the hot-patch path instead of falling back to a full restart. When a full overwrite run is required and the desired config has no hostname, inherit the current runtime hostname so an unmanaged value survives until it is explicitly cleared. Read back the runtime config after an overwrite run and verify it converged instead of assuming the desired state was applied. * fix(web): retry transient runtime reconciliation failures Keep the per-session managed runtime reconciliation worker alive when a single database round fails. Retry from the next heartbeat so persisted managed revisions can still converge after restart-time contention. Reserve terminal worker shutdown for destroyed session or storage state, and cover recovery after a transient revision read failure. * fix(web): accept omitted hostname after runtime apply Release 2.6.4 omits hostname from config readback when it matches the device hostname. Trust a successful hostname mutation only when the returned field is absent, while continuing to verify every other field and rejecting explicit mismatches. * fix(web): ignore unmanaged runtime device names Windows release 2.6.4 generates a random interface name when the managed config leaves dev_name empty. Exclude that runtime-owned value from reconciliation unless the desired config explicitly sets a non-empty device name, preventing endless overwrite restarts. * feat(web): report failed network instances to console Expose stopped Core instances with startup errors in heartbeats. Merge Core failures with direct managed-run RPC failures in easytier-web. Send failed instance IDs during token validation without error text. Prune local run failures when managed configs are deleted. * fix(web): distinguish unknown runtime application state Track whether the current session has observed its applied revision separately from the optional revision value. Report this fact through validate-token so Console can preserve application state across receiver restarts while recognizing deliberate pending mutations. * feat(web): configure heartbeat timing from server Heartbeat responses now provide the interval and RPC timeout. Legacy servers use local defaults and remote values are clamped. Web configuration and session receive timeout follow the policy. * fix(web): reject inactive control sessions Route control RPCs by machine id only to sessions whose RPC manager is still running, so a session that has been stopped or replaced can no longer receive control traffic addressed to the device. * fix(core): filter network info before collection When a collect-network-info request names specific instances, collect those instances only instead of collecting every instance and filtering the result afterwards, so unrequested instances no longer run per-collection work on every request. * feat(web): enable focused runtime diagnostics Enable easytier-web info logs by default while preserving explicit log configuration. Record startup settings, session lifecycle, failed instance changes, webhook queue and request latency, and managed runtime operation timings for production diagnosis. * fix(web): preserve managed revision across reconnects Keep one runtime identifier for each Core WebClient lifetime. Reuse its managed runtime state after transport reconnects. Retain applied revisions and reconcile hints while disconnected. Preserve runtime epochs so stale work cannot mark a revision applied. Reject stale sessions from reclaiming routes after reconnect. Core or Web restarts and legacy clients still use unknown state. Immediately revalidate a restored revision after authentication. Document local management RPC drift as an accepted trade-off. This lets Console converge without waiting for periodic validation. * fix(web): satisfy clippy across managed config sync tests Scope managed runtime guards to blocks in runtime revision tests so no std MutexGuard is held across await points, return the applied revision directly instead of through a let binding, and pass WebhookValidationInput to request_heartbeat_validation instead of expanding it into eight separate arguments. * fix(core): stop reporting failed instances as running in heartbeats A stopped instance with a startup error appeared in both running_network_instances and failed_network_instances, so the server treated it as running and never re-ran its managed config. Exclude failed instance ids when building the running list so the reconciler restarts them. * fix(core): close missed-wakeup race in instance state changes wait_for_change created the Notified future before reading the generation but only registered it when awaited. A change landing in between fired notify_waiters with no registered waiter and delayed the heartbeat by a full interval. Enable the future before reading the generation so every change wakes a waiting heartbeat. * fix(web): address review findings Fence webhook validation and connection transitions against stale state, redact credentials from default-level logs, and stabilize runtime reconciliation: - Record connected bindings only while the session still owns the machine route, and skip disconnect compensation once a replacement owns the route so a stale disconnect cannot revoke it. - Discard webhook validation results when the change epoch moved during the HTTP round, so a stale rejection cannot invalidate the current session. - Drop user_token fields from info and warn logs that became visible with info-level defaults. - Restore a hostname omitted by the 2.6.4 readback into the cached runtime config after a successful mutation, so later rounds stop re-sending the same hostname patch. - Reconcile running web configs when no revision is tracked so legacy unrevisioned updates converge, and wake sessions for unrevisioned full updates instead of waiting for the next heartbeat. * chore(go): regenerate web proto bindings for heartbeat fields Add failed_network_instances, support_heartbeat_policy, and the heartbeat policy response fields to the checked-in Go bindings. Other proto packages are left as-is because their drift predates this change. * fix(web): redact user tokens from positional log arguments Three runtime reconciliation info logs and the user lookup error contexts printed user_token through format arguments, which the earlier field-syntax redaction missed. The reconcile log now fires every round for unrevisioned machines, so remove the token from these messages as well. * fix(web): fence stale validation and runtime reconcile rounds Check webhook validation epochs while holding the session write lock, so stale success and rejection responses cannot change session state. Advance the runtime epoch for unrevisioned full config updates, and exclude failed instances from heartbeat and RPC reconciliation lists so stopped instances are restarted instead of repeatedly hot-patched. Release test read guards before awaiting validation apply calls. Set up the no-pending condition before asserting that an applied revision is a no-op, and verify that its runtime epoch remains unchanged. Validation: all 137 client_manager tests passed. * test(credentials): cover P2P with active VPN portal Model an admin and temporary credential peer connected as a foreign network through a public server with data relay disabled. Verify their direct connection can be replaced after a WireGuard portal client comes online. * test(credentials): stabilize two-admins failover assertions The two-admins non-reusable credential test could fail on slow convergence: after dropping the winning peer it relied on a single route sample passing a bare AND condition, then re-asserted the same expectations through one-shot checks seconds later. A transient route flap in that window (for example a briefly resurrected winner route from stale conn info) turned a passing convergence into a hard assert failure. This matches the 48.9s CI flake of credential_non_reusable_across_two_admins_allows_only_one_peer observed on 2026-08-12. Changes: - wait for bidirectional admin connectivity (AND) with a 20s budget before issuing the credential, instead of a one-directional OR - replace the failover wait_for_condition with wait_stable_failover_visibility_on_admins, which requires three consecutive samples of loser-present and winner-absent on both admins within the same 60s budget and logs every sample - enrich the stable-single-winner timeout message with per-admin visibility flags and elapsed time for triage All existing contracts are preserved; only observation windows and diagnostics change. Validated in the rust container: three passes at normal speed (54.1s / 53.8s / 53.1s) plus one slow-convergence round (172.7s) that would have raced the old one-shot sampling; it now passes with failover samples logged. cargo fmt and clippy -D warnings clean. |
||
|
|
19e5c49ba3 |
chore: bump version to 2.7.0 (#2566)
* chore: bump version to 2.7.0 Update version strings across the workspace: - crate versions and internal dependency requirements for easytier, easytier-core, easytier-proto, easytier-web, easytier-gui, and easytier-mini, plus Cargo.lock - GUI package.json and tauri.conf.json - Magisk module.prop - default release/docker workflow tags (v2.7.0) * fix(ohos): sync easytier-ohrs Cargo.lock with bumped workspace versions The ohos workflow builds easytier-ohrs with --locked, so its lockfile must record the new 2.7.0 versions of the easytier, easytier-core, and easytier-proto path dependencies. |
||
|
|
4a10d1c2b9 |
feat(mobile): add embedded runtime and managed network updates (#2532)
* feat(mobile): add embedded iOS runtime API Add a thin panic-safe C ABI crate for embedding no-TUN instances on iOS. Expose lifecycle, status, JSON-RPC, string ownership, and error handling. Build device and simulator XCFramework static libraries on macOS. Add exact named-instance deletion to the iOS and Android wrappers. Cover wrapper lifecycle and the port-forward patch flow on host targets. * fix(gateway): recover TCP port-forward listeners Release an unusable TCP port-forward listener after an accept failure. Retry binding until the forward is cancelled. Keep the old listener released while rebinding so mobile sockets can recover. Expose opt-in iOS diagnostics for listener and connection events. Trace configuration removal and adapter shutdown. Add tests for recovery, release-before-rebind, and cancellation. * feat(web): persist incremental managed config patches Add a revision-CAS PATCH contract for managed configs while keeping the existing Full PUT path for compatibility and recovery. Apply Full and Patch mutations with their revision in one SQLite transaction. Reject ownership conflicts and invalidate revisions on alternate web-owned writes. Document limits, failure semantics, rollout order, and verification. Cover delta updates, conflicts, idempotency, and transaction rollback. * feat(web): apply managed config patches to live sessions Carry Patch fences and touched instance IDs into live sessions. Reconcile only those instances when the applied revision matches the Patch base. Fall back to Full reconciliation for gaps and restarts. Invalidate the applied revision around every direct runtime mutation. Fence revision advancement with the runtime cache epoch so stale reconcile rounds cannot overwrite a newer invalidation. Require deletion responses to confirm each requested instance before advancing the revision. Raise the managed PUT and PATCH body limit to 32 MiB and return typed conflicts for publisher recovery. * fix(core): retry transient accepted TCP errors Keep TCP tunnel listeners alive when an accepted socket fails during upgrade with a retryable connection-state error. Share the retryable I/O classifier with the socket listener. Cover a rejected connection followed by success and propagation of permanent errors. * feat(core): add internal Peer Relay edge projection Derive the local advertised OSPF row from physical adjacency and transport-authenticated credential relay coverage. Keep full local adjacency only in the temporary SPF snapshot so direct destinations retain a fallback route. Leave Peer Relay disabled at the public configuration seam. A follow-up change can expose the preference without coupling route projection to credential reauthorization. feat(config): expose Peer Relay routing preference Add prefer_peer_relay to public protobuf, TOML, management patch, and hosted runtime surfaces. Read the preference from live peer context so runtime config updates take effect. Refresh authenticated peer metadata when the option is enabled. Cover dynamic enable and disable in a five-node, dual-admin credential topology, including forwarded relay coverage and local fallback. |
||
|
|
3fe427bc99 |
feat(credentials): manage declarative credentials through TOML (#2515)
* feat(credentials): manage declarative credentials through TOML Make managed credentials part of the canonical TOML configuration and load them before peers can authenticate. Reuse ConfigRpc hot patches to durably replace the configured credential set without restarting the instance. Serialize credential mutations so base, managed, and ephemeral keys cannot race into conflicts. Remove the managed overlay file format, digest protocol, capability negotiation, force reconciliation, and database CAS machinery. Redact credential secrets from debug output and management events. Write credential-bearing files atomically with private permissions. * fix(core): release JoinSet reapers with their owners Pass weak task-set references into background reapers so they cannot retain the JoinSet they are meant to collect. This lets stale smoltcp bridge tasks terminate when an IPv4 generation is replaced. Add ownership and TCP generation-replacement regressions covering the production port-forward failure. |
||
|
|
8794e12a26 |
feat(vpn): hot add/remove WireGuard portal clients without restart (#2514)
* feat(vpn): hot add/remove WireGuard portal clients without restart WireGuard portal clients were frozen at instance construction: the engine slot maps, host key table, and PortalModule state were all immutable after startup, so any client change required recreating the whole instance and dropping every established session. Wire dynamic client management through the existing config-patch channel (ConfigRpc.patch_config -> apply_config_patch), following the same pattern as connectors, port forwards, and proxy networks: - proto: InstanceConfigPatch gains repeated VpnPortalClientPatch (Add/Remove/Clear by client name) - engine: slot maps move under an RwLock with a free-index allocator; add_client/remove_client recycle indices, mark removed slots retired, and expire active sessions so Core tears down the attached peer via the regular channel-close path (credential revocation and disconnect events included); untouched clients keep their sessions intact. The retired flag is re-checked under the session lock so a datagram that races with removal cannot resurrect a session - host: WireGuardPortalHost derives keys deterministically per name (HKDF), keeps a mutable client table for render_client_config, and forwards updates to the live engine; changed clients are re-added so they re-handshake into a fresh generation with the new virtual IP or groups - PortalModule: client set, statuses, and session locks become shared mutable state; run_session resolves clients from the shared map at accept time; update_clients() validates against a caller-supplied runtime snapshot. An empty client set is legal in every lifecycle stage, so clearing all clients never produces a configuration that fails instance recreation - config_patch: apply_vpn_portal_client_patches mutates the candidate TOML; the sub-patch runs last and is deep-validated and hot-applied before the candidate commits, so a rejected client set leaves neither the shared model nor the live portal changed, and validation sees the fully patched state including routes and node IPv4 from the same request. Rejects patches when no portal is configured or a removed client does not exist - cli: vpn-portal add-client/remove-client/clear-clients subcommands Tests: engine index recycling, module update validation/state/host notification, TOML patch application, and a three-node integration test that adds a second WireGuard client live, removes the first while the second stays online, and asserts rejected patches leave the shared model unchanged. * feat(web): reconcile WireGuard portal client edits as hot patches The web console reconciles desired network config against the running instance and patches it in place when possible. VPN portal changes were not part of that: any client edit made the base configs differ, so every save recreated the instance and dropped all established sessions. Exclude vpn_portal_config from the base comparison and diff its clients by name instead. Client add/remove/change now produces VpnPortalClientPatch entries (removals first, changed clients as remove+add) applied through the existing PatchConfig channel. Listener identity changes (address or private key) and enabling or disabling the portal still fall back to a full instance recreate, since those change the listener lifecycle. * feat(web/gui): map portal client patches to frontend RPC backends Extend the RemoteClient seam with add/remove/clear VPN portal client operations so frontend hosts can drive the same PatchConfig channel as the CLI. There is deliberately no dedicated editing UI: the config form stays the single editing surface (aligned with port forwards), and these methods exist for programmatic and future use. - web console: JSON proxy-rpc to ConfigRpcService.patch_config with VpnPortalClientPatch entries (pbjson string enum actions) - desktop GUI: patch_vpn_portal_clients tauri command forwarding the same patch through the typed ConfigRpc client |
||
|
|
62e4fd15e9 |
feat(vpn): multi-client WireGuard portal with attached peers (#2502)
* feat(peer): support protocol-agnostic attached peers Add locally attached peers backed by independent, peer-level portable managers and authenticated in-process ring connections. Carry trusted connection provenance through packet admission so attached relay privileges cannot be forged through packet headers. Let every peer manager own ACL loading, sanitized policy updates, route refresh, and runtime cleanup. In Secure Mode, grant attached identities ephemeral credentials instead of sharing administrator and group secrets. * feat(vpn): add reusable attached-peer portal runtime Add a protocol-neutral portal runtime that converts authenticated client sessions into attached EasyTier peers. Own per-client generations, status, packet forwarding, address translation, and peer cleanup without knowing the transport protocol. Add transactional IPv4 source and destination rewriting with correct IPv4, TCP, UDP, ICMP, and quoted-packet checksum updates. Keep the old production portal path temporarily active until the WireGuard adapter is migrated in the next change. * feat(wireguard): attach named clients through peer portal Replace the monolithic WireGuard portal with a native adapter that owns key derivation, UDP demultiplexing, reauthentication, roaming, and bounded per-client packet queues. Hand authenticated sessions to the generic portal runtime for peer lifecycle and IPv4 translation. Move portal configuration into the core instance model, require a dedicated server key, and preserve existing listener, CLI, and runtime configuration behavior. Reject runtime address conflicts before publishing shared configuration. * feat(vpn): expose per-client portal status Project configured clients and their runtime state through the portal RPC, including generated client configuration, listener, peer identity, endpoint, tunnel address, ACL groups, and errors. Keep private client configuration out of the broad instance-info response and expose the explicit RPC through the CLI and Tauri bridge. * feat(vpn): add portal configuration to web clients Expose WireGuard portal listener, key, client, ACL group, and runtime status fields in the shared frontend library, Web dashboard, and Tauri client. Preserve UUID and uint64 values across protobuf JSON boundaries, keep dynamic client editor rows stable, and document the portal workflow. * test(vpn): cover multi-client and roaming WireGuard portals Add two three-node integration tests for the WireGuard VPN portal. The multi-client test connects two kernel WireGuard clients from separate network namespaces, verifies per-client connectivity to mesh nodes, and exercises cross-client traffic that runs the IPv4 source and destination translation in both directions. A TCP echo exchange through the portal additionally covers the TCP pseudo-header checksum rewrite path that ICMP-only ping tests miss, and portal status snapshots must report both clients online with distinct peer ids and correctly learned tunnel addresses. The roaming test swaps the client namespace address (delete the old address, then add the new one) so the kernel WireGuard source cache is invalidated and the client keeps sending under the same session from the new source, exactly like a real network change. The portal must update the client endpoint on the same peer id via the data path (same generation, no re-handshake, no detach/reconnect) while connectivity to mesh nodes is preserved. Supporting changes: run_wireguard_client now takes an interface name, and the shared namespace topology gains net_f (10.1.2.5) on the portal bridge for the second client. |
||
|
|
636390ec38 |
feat(peer): echo liveness probes on data traffic (#2497)
* feat(peer): echo liveness probes on data traffic Advertise a liveness-echo capability during classic and Noise handshakes. After a ping failure, tag outgoing peer packets with a short probe token and accept only the matching echoed token as round-trip proof. Keep one ping request outstanding and coalesce scheduler triggers so high traffic cannot reorder timeout results. Preserve one-way failure detection because unrelated ingress never clears the loss counter. * test(three_node): relax disconnect wait for sequential pingpong proxy_three_node_disconnect_test assumed the old pingpong timing, where overlapping pings failed fast and the connection closed well inside the 11s wait (see the old [4, 9)s comment). The liveness-echo change keeps one ping outstanding: each failure now takes a full 2s timeout, so the fifth consecutive failure and the connection close land at ~11s. Both proto variants timed out at the 11s bound in CI. Widen the wait to 15s and update the timing comment. |
||
|
|
0b27ac2885 |
feat(credentials): support managed credential synchronization (#2490)
* feat(credentials): support managed credential synchronization Allow managed callers to upsert credentials with an exact ID, secret, permissions, reuse policy, and expiry. Return non-secret attributes plus a public-key fingerprint so callers can verify relay credential consistency. Persist imported credentials atomically and preserve identity and expiry across restarts. * fix(credentials): make managed upserts durable Write the candidate credential snapshot before committing it to memory. Propagate storage failures so controllers can retry instead of observing false convergence. Cover a transient storage failure to verify that memory stays unchanged and the retry persists the credential. * fix(credentials): atomically replace stored snapshots Define CredentialStorage::store as an atomic replacement boundary and use atomic-write-file in the management adapter. This keeps the last committed credential JSON readable when a replacement fails. Cover replacement of an existing credential snapshot and keep the dependency scoped to the management feature. |
||
|
|
1e40350c89 |
feat(wasi): expose protobuf RPC request ABI (#2477)
* feat(wasi): expose protobuf RPC request ABI Add an instance-scoped asynchronous RPC session backed by the shared operation broker. Reuse the existing dispatcher and management handlers. WASI hosts can call PeerManageRpc and ConnectorManageRpc with the same protobuf payloads as easytier-cli. Export ABI version, submit, take, and free functions. Bind selectors to the WASM instance handle and keep method errors in RpcResponse. Enable management RPC explicitly in the Go-host WASM build. * fix(gateway): serialize UDP client eviction Serialize UDP client admission across forwarding rules so only one eviction can claim and wait for a released semaphore permit. Retry when cleanup concurrently removes the selected client. Add a multithreaded regression test for the permit handoff while the evicted client is still referenced. * fix(gateway): publish UDP client admission atomically Hold the admission guard through client and response-task publication so a concurrent eviction cannot leave an orphan task holding the slot permit. Open the data-plane flow before entering the critical section and extend the multithreaded regression test across the publication window. |
||
|
|
df874b85be |
refactor(core): use linearizable lazy token bucket (#2421)
Replace periodic refill tasks with on-demand accounting to avoid waking idle token buckets. Keep balance, refill time, and fractional credit in one locked state so concurrent consumers cannot observe partially published refills or exceed the configured burst capacity. Track credit in nanoseconds and discard excess credit at capacity to preserve precise limiter behavior. Use a one-second default burst capacity to preserve the existing limiter behavior while supporting explicit capacity configuration. Keep limiter capacity and fill rate in a local config instead of an unused protobuf message. Charge only logical EasyTier data payload, unwrap foreign network packets before accounting, and leave control traffic outside the limiter. Reject forged payload lengths by accounting from actual packet boundaries. Split oversized blocking consumes into capacity-sized chunks and cover concurrency, refill precision, burst caps, payload accounting, and bandwidth integration behavior. |
||
|
|
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. |