mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-16 15:17:14 +00:00
feat(amneziawg): add AmneziaWG as an outbound protocol (#6320)
* feat(amneziawg): add AmneziaWG as an outbound protocol - AmneziaWG outbound protocol end-to-end: config schema, socks bridge, netstack, panel UI - Route amneziawg outbounds to HTTP probe in TCP mode (backend + frontend classifiers) with pinning test - Add 2-minute idle read deadline to pumpUDPEgress to reap idle egress sessions - Require SOCKS5 username/password auth on the egress server (reject NO-AUTH with 0xFF) with test - Bound the egress TCP tunnel dial with portForwardDialTimeout (10s), matching portfwd.go - Resolve UDP domain targets off the association's reader loop via deliverUDPDatagram; race-safe getOrDial starts the reply pump at session creation; client passed by value into resolver goroutines (pinned by TestEgressUDPDatagramDomainInterleavedClients) - Reconcile early-returns on an empty desired set and closes the egress listener; EgressBasePort (64900) is reserved against local inbound port conflicts like the internal API port, with pinning tests for both the port reservation (TestCheckPortConflict_EgressPortBlockedLocal) and the Reconcile empty-desired Close/Listen lifecycle (TestOutboundManagerReconcileEmptyDesiredClosesEgress) - Eliminate acceptLoop shutdown race by validating listener != nil and registering to tracked under s.mu before wg.Add; bound pre-auth handshake with deadline (pinned by TestEgressServerCloseDuringConcurrentAccepts) - Support AAAA and dual-stack domain resolution in tunnel DNS resolver with v6 default fallback (DefaultTunnelDNSServerV6); add DNS field to frontend protocol form; avoid unneeded cache flushes on unchanged SetStack ticks * fix(amneziawg): resolve IPv6-only DNS default fallback and validate required keys - Default to IPv6 tunnel DNS on IPv6-only outbounds with blank dns - Require non-empty secretKey and peer publicKey in ValidateAmneziaWGOutbound - Add end-to-end IPv6 tunnel domain resolution test and test empty key rejection - Trim comment blocks exceeding 2 lines across modified files - Fix Storybook test execution on environments with POSIX locale Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: rqzbeh <rqzbeh@users.noreply.github.com> Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -600,3 +600,30 @@ only - it changes no code), `claude-issue-analyst.yml` (issue triage).
|
||||
- **Tests live next to code** (`foo.go` ↔ `foo_test.go`), plus golden snapshots in
|
||||
`frontend/src/test/golden/fixtures/` for config generation — update fixtures intentionally,
|
||||
not blindly, when output changes.
|
||||
|
||||
## AmneziaWG outbound pseudo-protocol
|
||||
|
||||
The template stores `protocol: "amneziawg"` rows verbatim; Xray-core has no
|
||||
such proxy. At config generation (`GetXrayConfig` and the outbound latency
|
||||
probe's batch config) each row is swapped by `amneziawgnet.BuildSocksBridge`
|
||||
into a loopback socks outbound pointed at the panel's egress server (port
|
||||
`EgressBasePort`), authenticating with the row's tag as username. Sibling keys
|
||||
(`mux`, `sendThrough`, `targetStrategy`, `streamSettings.sockopt`) survive the
|
||||
swap. The embedded amneziawg-go client device lives in the panel process; an
|
||||
unbridgeable entry (unreadable settings, empty/non-string tag) fails config
|
||||
generation instead of skipping, because a skipped entry leaves
|
||||
`protocol: "amneziawg"` behind -- which makes Xray refuse the whole config.
|
||||
|
||||
Traffic flow: Xray socks client -> egress SOCKS5 server (tag = username) ->
|
||||
per-tag device netstack -> amneziawg-go tunnel. Domain targets are resolved by
|
||||
a DNS exchange through that same netstack (`resolveTunnelVia`, default server
|
||||
`DefaultTunnelDNSServer`), so names never leak to the panel host's resolver and
|
||||
answers are valid at the tunnel's location; results cache for 60s. UDP flows
|
||||
key sessions on the resolved address:port. Peer endpoints may be hostnames:
|
||||
`resolvingBind.ParseEndpoint` resolves once at configure time (kernel
|
||||
`wg setconf` semantics); a hostname whose DNS dies later needs a template
|
||||
re-save or job restart to re-resolve.
|
||||
|
||||
`randomTrailers` defaults to false wherever the panel does not control the
|
||||
peer (outbound form/schema): a receiver without 3.1 trailers silently drops
|
||||
oversized packets from a sender with it enabled.
|
||||
|
||||
Reference in New Issue
Block a user