Commit Graph

6 Commits

Author SHA1 Message Date
Kuzz007 738163699e fix(amneziawgnet): stop resetting live peer sessions on every reconcile tick
Real production bug, found via a live test connection that reset every
~10 seconds: ensureLocked's reconfigure-in-place branch called IpcSet
unconditionally on every Ensure, including AmneziaWGJob's routine 10s
reconcile tick even when nothing in the DB had changed. amneziawg-go's
IpcSet always includes replace_peers=true (buildUAPIConfig), and its own
handling of that op is device.RemoveAllPeers() -- unconditional, even
when the new peer list is byte-identical to the old one. So every tick
tore down and recreated every peer's live handshake/session state, and
no connection could ever survive past one reconcile cycle.

Root-caused with AMNEZIAWGNET_DEBUG (previous commit) showing "UAPI:
Removing all peers" + peer Stopping/Starting exactly ~10s after a real
handshake completed, matching AmneziaWGJob's own cadence precisely.

Fixed by comparing the freshly rendered UAPI config string against what
was last actually applied and skipping IpcSet entirely when identical --
reusing buildUAPIConfig's own exhaustive field coverage instead of a
hand-maintained fingerprint that could drift out of sync with it.

TestEnsureUnchangedInstanceDoesNotResetLivePeers verifies via
device.LookupPeer pointer identity (confirmed to fail without this fix,
not just pass trivially with it).
2026-08-04 01:46:32 +03:00
Kuzz007 b0c29b7caa feat(amneziawgnet): opt-in verbose device logging via AMNEZIAWGNET_DEBUG
The embedded amneziawg-go Device is silent by design (DeviceOptions'
Logger defaults to LogLevelSilent) -- real protocol-level diagnostics
(handshake progress, decrypt/MAC errors, keepalive state) were completely
unavailable while debugging a live "handshake happens, then goes silent"
report on a real test box, with nothing useful in the panel's own logs.
Setting AMNEZIAWGNET_DEBUG on the host now switches every embedded
interface to LogLevelVerbose. Deliberately env-var-gated, not a permanent
level bump: this logging has no per-peer filtering, so it's meant for
targeted investigation, not routine operation.
2026-08-04 01:35:36 +03:00
Kuzz007 1d39de4d13 feat(amneziawg): restore per-client public IPv6 identity (Phase 3.5)
Adds internal/amneziawg.FirstIPv6 and a new internal/amneziawgnet/v6alias.go
that aliases each IPv6-enabled peer's own address onto the host NIC
(ip -6 addr add), wired into the Manager's Ensure/Remove/Reconcile/StopAll
lifecycle. internal/web/service/xray.go's new injectAmneziawgV6Egress gives
each such peer a dedicated freedom outbound (sendThrough) plus a routing
rule matching its own email, so its outbound connections carry a distinct
public source address again -- restoring what the embedded-architecture
hard cutover temporarily dropped. Scoped to outbound source identity only
(not unsolicited inbound/port-forwarding, which stays the separate Phase
3.6); no frontend changes needed since IPv6Enabled/IPv6ExternalInterface
were already in the UI and per-peer opt-in is just an IPv6 AllowedIPs entry,
same as today.
2026-08-03 10:41:58 +03:00
Kuzz007 f78dfa6f67 feat(amneziawg): swap the app's integration points to the embedded manager
Hard cutover, part 2: every real call site that used to drive
internal/amneziawg's kernel-module Manager now drives
internal/amneziawgnet's instead --

- internal/web/job/amneziawg_job.go: the reconcile cron job. Traffic/
  online-status accounting is dropped entirely (not ported) -- once a
  peer's traffic is relayed through Xray's own SOCKS5 inbound, it's an
  ordinary Xray user and XrayTrafficJob's existing generic stats polling
  already handles it, with zero AmneziaWG-specific code.
- internal/web/runtime/local.go: the immediate-apply CRUD path
  (AddInbound/DelInbound/updateAmneziaWGInbound).
- internal/web/web.go: panel shutdown's StopAll.

internal/amneziawgnet.Manager gains Remove(id) to match the kernel-module
Manager's shape at these call sites (Reconcile alone doesn't cover a
single-inbound removal outside a full reconcile pass).

internal/web/service/inbound_amneziawg.go's applyLocalAmneziaWG needed no
change: it already goes through runtime.Runtime.UpdateInbound, which now
resolves to the updated local.go path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 15:04:51 +03:00
Kuzz007 124665c5ef feat(amneziawg): auto-wire the SOCKS5 relay into every embedded Device
Manager.ensureLocked now attaches AttachTCPForwarder/AttachUDPHandler to
every Device it builds, relaying into that instance's own loopback SOCKS5
inbound automatically -- no caller needs to know relay.go exists at all.
Peer identity is re-looked-up via Manager.Lookup on every connection rather
than captured once at attach time, so a reconfigure-in-place (peers added/
removed without a full rebuild) doesn't leave the forwarder working off a
stale peer index.

Added TestManagerEnsureAutomaticallyWiresRelay: drives this through the
real Manager.Ensure entry point (not manual wiring like the existing
relay_e2e_test.go) against a real xray-core process, confirming the
automatic attachment and the port/password Manager derives internally
actually agree with what a real SOCKS5 inbound expects.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 14:42:00 +03:00
Kuzz007 58671533bb feat(amneziawg): add embedded amneziawg-go device package (Phase 1)
New internal/amneziawgnet package: builds a real amneziawg-go Device over a
gVisor netstack from an existing amneziawg.Instance, with a TCP/UDP
forwarder that recovers each tunnel connection's real destination and a
peer-identity index keyed by AllowedIPs. This is the foundation for
migrating AmneziaWG off the kernel-module+TPROXY path (see the AmneziaWG-go
vs kernel-module decision) -- nothing wires into live traffic yet, that's
Phase 2 (relay into Xray's own SOCKS5 inbound).

Covered by three real end-to-end tests: a genuine handshake + TCP forwarder
+ identity resolution, the same for UDP (including a reply routed back
through the tunnel), and the manager's reconfigure-in-place vs. rebuild
lifecycle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 13:48:13 +03:00