mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-14 23:31:00 +00:00
fix(sub): wrap JSON-subscription SS/Trojan outbound in servers[] array
The flat top-level address/method/password form only parses on recent xray-core; older bundled cores (e.g. in v2rayN) reject it. Restore the standard "servers" array used through 2.9.x so the JSON subscription connects across all xray-core versions. VMess/VLESS keep the flat vnext fallback, which is long established in xray-core.
This commit is contained in:
@@ -425,16 +425,22 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_u
|
|||||||
}
|
}
|
||||||
outbound.StreamSettings = streamSettings
|
outbound.StreamSettings = streamSettings
|
||||||
|
|
||||||
settings := map[string]any{
|
// Wrap the endpoint in a "servers" array (the standard Xray schema for
|
||||||
|
// Shadowsocks/Trojan outbounds). The flat top-level form only parses on very
|
||||||
|
// recent xray-core; older bundled cores (e.g. in v2rayN) reject it, so SS
|
||||||
|
// links fail to connect. See genVnext/genVless for the VMess/VLESS shape.
|
||||||
|
server := map[string]any{
|
||||||
"address": serverData[0].Address,
|
"address": serverData[0].Address,
|
||||||
"port": serverData[0].Port,
|
"port": serverData[0].Port,
|
||||||
"password": serverData[0].Password,
|
"password": serverData[0].Password,
|
||||||
"level": 8,
|
"level": 8,
|
||||||
}
|
}
|
||||||
if inbound.Protocol == model.Shadowsocks {
|
if inbound.Protocol == model.Shadowsocks {
|
||||||
settings["method"] = serverData[0].Method
|
server["method"] = serverData[0].Method
|
||||||
|
}
|
||||||
|
outbound.Settings = map[string]any{
|
||||||
|
"servers": []any{server},
|
||||||
}
|
}
|
||||||
outbound.Settings = settings
|
|
||||||
|
|
||||||
result, _ := json.MarshalIndent(outbound, "", " ")
|
result, _ := json.MarshalIndent(outbound, "", " ")
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -128,21 +128,32 @@ func TestSubJsonServiceVmessFlattened(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSubJsonServiceServerFlattened(t *testing.T) {
|
// Shadowsocks/Trojan outbounds must use the standard "servers" array so older
|
||||||
|
// bundled xray-cores (e.g. v2rayN) parse them; the flat top-level form only
|
||||||
|
// works on very recent xray-core.
|
||||||
|
func TestSubJsonServiceServerUsesServersArray(t *testing.T) {
|
||||||
trojan := &model.Inbound{Listen: "1.2.3.4", Port: 443, Protocol: model.Trojan, Settings: `{}`}
|
trojan := &model.Inbound{Listen: "1.2.3.4", Port: 443, Protocol: model.Trojan, Settings: `{}`}
|
||||||
client := model.Client{Password: "p4ss"}
|
client := model.Client{Password: "p4ss"}
|
||||||
|
|
||||||
settings := outboundSettings(t, NewSubJsonService("", "", "", nil).genServer(trojan, nil, client, ""))
|
settings := outboundSettings(t, NewSubJsonService("", "", "", nil).genServer(trojan, nil, client, ""))
|
||||||
if _, ok := settings["servers"]; ok {
|
server := firstServer(settings)
|
||||||
t.Fatal("trojan outbound must not use servers array")
|
if server == nil {
|
||||||
|
t.Fatalf("trojan outbound must use a servers array, got: %#v", settings)
|
||||||
}
|
}
|
||||||
if settings["password"] != "p4ss" || settings["address"] != "1.2.3.4" {
|
if server["password"] != "p4ss" || server["address"] != "1.2.3.4" {
|
||||||
t.Fatalf("flat trojan settings wrong: %#v", settings)
|
t.Fatalf("trojan server entry wrong: %#v", server)
|
||||||
|
}
|
||||||
|
if _, ok := server["method"]; ok {
|
||||||
|
t.Fatalf("trojan must not carry method: %#v", server)
|
||||||
}
|
}
|
||||||
|
|
||||||
ss := &model.Inbound{Listen: "1.2.3.4", Port: 443, Protocol: model.Shadowsocks, Settings: `{"method":"aes-256-gcm"}`}
|
ss := &model.Inbound{Listen: "1.2.3.4", Port: 443, Protocol: model.Shadowsocks, Settings: `{"method":"aes-256-gcm"}`}
|
||||||
ssSettings := outboundSettings(t, NewSubJsonService("", "", "", nil).genServer(ss, nil, client, ""))
|
ssSettings := outboundSettings(t, NewSubJsonService("", "", "", nil).genServer(ss, nil, client, ""))
|
||||||
if ssSettings["method"] != "aes-256-gcm" {
|
ssServer := firstServer(ssSettings)
|
||||||
t.Fatalf("flat shadowsocks must carry method: %#v", ssSettings)
|
if ssServer == nil {
|
||||||
|
t.Fatalf("shadowsocks outbound must use a servers array, got: %#v", ssSettings)
|
||||||
|
}
|
||||||
|
if ssServer["method"] != "aes-256-gcm" {
|
||||||
|
t.Fatalf("shadowsocks server entry must carry method: %#v", ssServer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user