mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-30 19:22:10 +03:00
fix(amneziawg): fall back to a free egress port when 64900 is refused
The panel's SOCKS5 egress for AmneziaWG outbounds bound the fixed 127.0.0.1:64900, and every generated socks bridge dialed that constant. 64900 sits inside Windows' dynamic port range, where the OS can reserve whole blocks (this host excludes 64885-64984), so on the Windows builds release.yml ships the listener could stay down and every AmneziaWG outbound with it. Listen now tries 64900 first and falls back to any free loopback port; bridges, the outbound probe and the port-conflict check use EgressPort(), the port actually held. Bridges are generated apart from the listener, so BuildSocksBridge records the port it wrote and the AmneziaWG job requests an Xray restart while the listener holds a different one. Where 64900 is free nothing changes. The job's restart request is two lines of wiring no test reaches; the staleness it acts on is pinned by TestBridgesStaleUntilRegeneratedForTheBoundPort.
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
type AmneziaWGJob struct {
|
||||
inboundService service.InboundService
|
||||
settingService service.SettingService
|
||||
xrayService service.XrayService
|
||||
}
|
||||
|
||||
// NewAmneziaWGJob creates a new AmneziaWG reconcile job instance.
|
||||
@@ -55,6 +56,10 @@ func (j *AmneziaWGJob) Run() {
|
||||
return
|
||||
}
|
||||
amneziawgnet.GetOutboundManager().Reconcile(outboundDesired)
|
||||
// Xray's bridges are generated apart from the listener; one that moved needs them regenerated.
|
||||
if amneziawgnet.BridgesStale() {
|
||||
j.xrayService.SetToNeedRestart()
|
||||
}
|
||||
}
|
||||
|
||||
// desiredOutboundInstances derives client instances per template "amneziawg" outbound.
|
||||
|
||||
@@ -256,9 +256,9 @@ func checkPortConflictTx(db *gorm.DB, inbound *model.Inbound, ignoreId int) (*po
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Egress SOCKS server holds loopback EgressBasePort when AWG outbounds are
|
||||
// Egress SOCKS server holds loopback EgressPort when AWG outbounds are
|
||||
// active; conflict check prevents inbounds from colliding with it.
|
||||
if inbound.NodeID == nil && inbound.Port == int(amneziawgnet.EgressBasePort) &&
|
||||
if inbound.NodeID == nil && inbound.Port == amneziawgnet.EgressPort() &&
|
||||
newBits&transportTCP != 0 && listenOverlaps(loopbackBind, inboundBindAddr(inbound)) {
|
||||
return &portConflictDetail{
|
||||
Tag: "amneziawg-egress",
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"net"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -754,6 +756,30 @@ func TestCheckPortConflict_EgressPortBlockedLocal(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Where EgressBasePort is taken the egress listens on another port, and that
|
||||
// is the port an inbound must not collide with.
|
||||
func TestCheckPortConflict_EgressPortFollowsTheListener(t *testing.T) {
|
||||
setupConflictDB(t)
|
||||
if ln, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(amneziawgnet.EgressBasePort))); err == nil {
|
||||
t.Cleanup(func() { ln.Close() })
|
||||
}
|
||||
egress := amneziawgnet.GetEgressServer()
|
||||
if err := egress.Listen(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(egress.Close)
|
||||
|
||||
svc := &InboundService{}
|
||||
candidate := &model.Inbound{Tag: "vless-bridge", Listen: "0.0.0.0", Port: egress.Port(), Protocol: model.VLESS}
|
||||
got, err := svc.checkPortConflict(candidate, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("checkPortConflict: %v", err)
|
||||
}
|
||||
if got == nil || got.Tag != "amneziawg-egress" {
|
||||
t.Fatalf("an inbound on the egress's port %d must conflict with amneziawg-egress, got %+v", egress.Port(), got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckPortConflict_AmneziawgnetSocksRelayBlockedLocal(t *testing.T) {
|
||||
setupConflictDB(t)
|
||||
seedInboundConflict(t, "awg-1", "0.0.0.0", 51820, model.AmneziaWG, ``, amneziawgRoutedSettings)
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
)
|
||||
|
||||
func amneziawgnetEgressPortForTest() int { return amneziawgnet.EgressBasePort }
|
||||
func amneziawgnetEgressPortForTest() int { return amneziawgnet.EgressPort() }
|
||||
|
||||
func wgKeypairForTest() (priv, pub string, err error) {
|
||||
return wgutil.GenerateWireguardKeypair()
|
||||
|
||||
Reference in New Issue
Block a user