mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-08 19:27:14 +00:00
db8253421a
Simplifies RouteViaXray after realizing the panel already has everything needed: the Routing page already lets an admin pick a source inbound tag and a target outbound (plus, if they want it, a specific source IP) for any protocol. Bolting a parallel routeThroughXray/routeOutboundTag pair onto both the client and inbound forms duplicated that mechanism instead of using it. Removed entirely: Client/ClientRecord/ServerSettings/Peer's RouteThroughXray + RouteOutboundTag fields, the effective-routing OR/ fallback logic in InstanceFromInbound, and the Switch+Select UI on both forms. Nothing configures "route via Xray" as a setting anymore. In its place, every enabled AmneziaWG inbound now gets its own Xray TPROXY bridge unconditionally, by default, no toggle: - internal/amneziawg: every peer's traffic is always TPROXY'd into that instance's own bridge (defaultPostUpDown, port derived from the inbound's id via EgressPortForInbound so the kernel side and the Xray-config side never need to negotiate a runtime value). Since the TPROXY rule is now tied to a peer's mere presence rather than an opt-in flag, hostRulesFingerprint now covers every peer unconditionally (add/remove/re-IP forces a restart, the same way ForwardedPorts always did) instead of skipping peers with nothing to opt into. - internal/web/service/xray.go's injectAmneziawgEgress creates one dokodemo-door bridge per qualifying inbound, tagged with that inbound's own real tag — the same trick injectMtprotoEgress already uses (reusing a real inbound's tag), which is why it's already selectable in the panel's Routing page: InboundService.GetInboundTags() is a plain, protocol-blind SELECT over every inbound row's tag, no dedicated UI plumbing needed. The function never generates a routing rule itself anymore — where (if anywhere) that traffic goes is entirely up to whatever rules the admin adds through the existing Routing UI. Frontend: no new UI at all. Tests rewritten to match — one bridge per inbound with its own tag/port, no rule generation, no opt-in gating. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
83 lines
3.6 KiB
Go
83 lines
3.6 KiB
Go
package amneziawg
|
|
|
|
import (
|
|
"fmt"
|
|
"hash/fnv"
|
|
)
|
|
|
|
// EgressBasePort is the first loopback port used for an AmneziaWG inbound's
|
|
// own Xray TPROXY bridge. Every enabled inbound gets one bridge, always
|
|
// present by default (no opt-in flag): defaultPostUpDown's TPROXY rules
|
|
// redirect every peer's traffic there unconditionally, and
|
|
// internal/web/service's injectAmneziawgEgress creates the matching
|
|
// dokodemo-door inbound, tagged with the AmneziaWG inbound's own real tag so
|
|
// it's already selectable in the panel's stock Routing page (the same
|
|
// mechanism that already makes an mtproto inbound's own bridge routable
|
|
// there — see injectMtprotoEgress). Whether — and where — that traffic
|
|
// actually goes anywhere beyond Xray's default routing is entirely up to
|
|
// whatever rules the admin adds on that page; this package and
|
|
// injectAmneziawgEgress never generate a routing rule themselves.
|
|
//
|
|
// EgressPortForInbound derives each inbound's own port deterministically
|
|
// from its id, so the two independent reconcile loops (this package's
|
|
// PostUp generator and the Xray-config generator, in a different package)
|
|
// never have to agree on a runtime-negotiated value.
|
|
const EgressBasePort = 63100
|
|
|
|
// EgressPortForInbound returns the loopback port of one AmneziaWG inbound's
|
|
// own Xray TPROXY bridge.
|
|
func EgressPortForInbound(inboundID int) int {
|
|
return EgressBasePort + inboundID
|
|
}
|
|
|
|
// EgressFwmark and EgressTable are the fwmark and policy-routing table
|
|
// TPROXY needs to deliver a peer's packets to a local socket even though
|
|
// their destination is never one of this host's own addresses. Shared by
|
|
// every AmneziaWG instance's bridge — only the port differs per instance.
|
|
// Chosen to be distinctive; if either happens to collide with something else
|
|
// already using fwmarks/routing tables on the host, change the values here —
|
|
// nothing outside this package and its own PostUp/PostDown output depends on
|
|
// the actual numbers.
|
|
const (
|
|
EgressFwmark = 0x2377
|
|
EgressTable = 87
|
|
)
|
|
|
|
// routeEgressComment returns a short, shell-safe iptables comment tag for one
|
|
// peer's TPROXY rule, so PostDown removes exactly what PostUp added
|
|
// regardless of ordering. Derived from a hash of the peer's email for the
|
|
// same reason portForwardComment is: email is admin/API-supplied free text
|
|
// that ends up embedded in a shell-executed PostUp/PostDown line, and a hash
|
|
// can never carry a shell metacharacter through.
|
|
func routeEgressComment(email string) string {
|
|
if email == "" {
|
|
return "awg-route"
|
|
}
|
|
h := fnv.New32a()
|
|
_, _ = h.Write([]byte(email))
|
|
return fmt.Sprintf("awg-route-%08x", h.Sum32())
|
|
}
|
|
|
|
// routeEgressLines returns the PostUp ("-A") or PostDown ("-D") mangle-table
|
|
// TPROXY lines that redirect one peer's traffic — matched by its tunnel
|
|
// source IP, arriving on tunIface — into that instance's own Xray bridge on
|
|
// port. Both TCP and UDP are covered since every peer's whole traffic is
|
|
// meant to reach the bridge, not just a specific protocol or port; which
|
|
// outbound (if any) it then takes is entirely up to the admin's own Routing
|
|
// rules. Returns nil when clientIP is empty.
|
|
func routeEgressLines(action, tunIface, clientIP, email string, port int) []string {
|
|
clientIP = stripCIDRMask(clientIP)
|
|
if clientIP == "" {
|
|
return nil
|
|
}
|
|
comment := routeEgressComment(email)
|
|
lines := make([]string, 0, 2)
|
|
for _, proto := range []string{"tcp", "udp"} {
|
|
lines = append(lines, fmt.Sprintf(
|
|
"iptables -t mangle %s PREROUTING -i %s -s %s -p %s -m comment --comment %s -j TPROXY --on-port %d --on-ip 127.0.0.1 --tproxy-mark %#x/%#x",
|
|
action, tunIface, clientIP, proto, comment, port, EgressFwmark, EgressFwmark,
|
|
))
|
|
}
|
|
return lines
|
|
}
|