Adds native dual-stack IPv6 to AmneziaWG inbounds, ported from
coinman-dev/3ax-ui's approach:
- ServerSettings gets ipv6Enabled/ipv6Subnet/ipv6ExternalInterface;
Instance carries the server's own IPv6 address (first host of the
subnet) alongside its IPv4 one.
- defaultAmneziaWGClients allocates an IPv6 host address per client
(second AllowedIPs entry) when the server has IPv6 enabled, reusing
allocateWireguardAddress — which needed a real fix along the way: it
always suffixed "/32" regardless of address family, which is wrong
for an IPv6 host address (needs /128). Now family-aware.
- generateServerConfig's PostUp/PostDown gains IPv6 forward-accept
rules, proxy_ndp sysctl, and one `ip -6 neigh add/del proxy` entry per
enabled peer with an IPv6 address — the lightweight per-client
method, not the ndppd-daemon whole-subnet method (not worth the
config-file-management complexity at this scale; ndppd itself is
still installed by install.sh in case that changes later).
- ValidateIPv6Subnet rejects a malformed subnet before save.
- Frontend: ipv6Enabled/ipv6Subnet/ipv6ExternalInterface fields on the
AmneziaWG inbound form, EN+RU translations, openapi.json/generated/*
regenerated (the latter via `go run ./tools/openapigen`, pure Go).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The WireGuard peer address was allocated server-side and shown read-only
in the client editor, so changing it required hand-editing the inbound's
raw settings JSON (#5715). The backend add/update paths already honored a
submitted allowedIPs; only the form withheld it.
Make the field editable (comma-separated, empty still auto-assigns) and
validate submissions server-side: entries must parse as an IP or CIDR,
bare addresses normalize to single-host prefixes, and an address already
used by another peer on the inbound is rejected.
Closes#5715
defaultWireguardClients always allocated new tunnel addresses from the
hardcoded 10.0.0.0/24 base, so a legacy or migrated inbound whose peers
live in a different subnet (e.g. 172.16.0.0/24) got new clients in an
unrelated, unroutable range. Derive the allocation base from the existing
peers' /24 and fall back to 10.0.0.0/24 only when there are none.
WireGuard inbounds now manage per-client peers using xray-core's native WireGuard users (AddUser/RemoveUser). Each client lives in settings.clients (canonical, like every other protocol) and is projected to peers[] only when emitting the xray config, at level 0 so the dispatcher's per-user traffic/online counters work with no extra plumbing.
Backend: internal/util/wireguard gains KeyToHex (base64 to hex for the gRPC path), PublicKeyFromPrivate and GenerateWireguardPSK; xray/api.go builds a wireguard account in AddUser with hex keys (RemoveUser already worked); client CRUD generates a keypair and allocates a unique tunnel address per client and never rotates keys on edit; an idempotent migration converts legacy settings.peers into managed clients; WireGuard is included in the raw subscription.
Frontend: WireGuard in the add-client modal with keys on the credential tab, client schema, per-client QR/link/.conf, inbound form reduced to server settings; i18n added across 13 locales.
Fix: guard the settings[clients] assertion in add/update so a legacy WireGuard inbound stored without a clients key no longer panics.