mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-11 05:40:59 +00:00
fix(sub): include native WireGuard clients in Clash and JSON subscriptions (#5676)
The Clash (buildProxy) and JSON (getConfig) subscription generators had no WireGuard branch, so a native WireGuard inbound's clients were silently dropped: buildProxy hit its default nil case, and getConfig emitted a config with no proxy outbound. Only the raw subscription (genWireguardLink) and external-link Clash path handled WireGuard. Add a WireGuard case to both generators, mirroring genWireguardLink: the peer public key is derived from the inbound secretKey, while the private key, tunnel address (mihomo ip/ipv6, Xray settings.address), pre-shared key and keep-alive come from the client. The peer routes the full tunnel (0.0.0.0/0, ::/0), which both mihomo and Xray also default to. Field names verified against the mihomo WireGuardOption source (private-key, public-key, pre-shared-key, persistent-keepalive, ip, ipv6, mtu, dns) and the Xray wireguard outbound schema (secretKey, address, peers[].publicKey/endpoint/ preSharedKey/keepAlive/allowedIPs, mtu).
This commit is contained in:
@@ -2,9 +2,11 @@ package sub
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
wgutil "github.com/mhsanaei/3x-ui/v3/internal/util/wireguard"
|
||||
)
|
||||
|
||||
func hasDirectOutOutbound(svc *SubJsonService) bool {
|
||||
@@ -331,3 +333,76 @@ func TestSubJsonServiceRealityDataSpiderXFallsBackWhenNoClientKey(t *testing.T)
|
||||
t.Fatalf("spiderX fallback = %q, want random 16-char /-prefixed value", spx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubJsonServiceWireguard(t *testing.T) {
|
||||
serverPriv, serverPub, err := wgutil.GenerateWireguardKeypair()
|
||||
if err != nil {
|
||||
t.Fatalf("server keypair: %v", err)
|
||||
}
|
||||
clientPriv, _, err := wgutil.GenerateWireguardKeypair()
|
||||
if err != nil {
|
||||
t.Fatalf("client keypair: %v", err)
|
||||
}
|
||||
|
||||
inbound := &model.Inbound{
|
||||
Listen: "203.0.113.9",
|
||||
Port: 51820,
|
||||
Protocol: model.WireGuard,
|
||||
Settings: `{"secretKey":"` + serverPriv + `","mtu":1420}`,
|
||||
}
|
||||
client := model.Client{
|
||||
Email: "user",
|
||||
PrivateKey: clientPriv,
|
||||
PreSharedKey: "psk-value",
|
||||
KeepAlive: 25,
|
||||
AllowedIPs: []string{"10.0.0.2/32", "fd00::2/128"},
|
||||
}
|
||||
|
||||
raw := NewSubJsonService("", "", "", nil).genWireguard(inbound, client)
|
||||
if raw == nil {
|
||||
t.Fatal("genWireguard returned nil for a valid wireguard client")
|
||||
}
|
||||
settings := outboundSettings(t, raw)
|
||||
|
||||
if settings["secretKey"] != clientPriv {
|
||||
t.Fatalf("secretKey = %v, want client private key", settings["secretKey"])
|
||||
}
|
||||
address, _ := settings["address"].([]any)
|
||||
if len(address) != 2 || address[0] != "10.0.0.2/32" || address[1] != "fd00::2/128" {
|
||||
t.Fatalf("address = %v, want client tunnel addresses", settings["address"])
|
||||
}
|
||||
if settings["mtu"] != float64(1420) {
|
||||
t.Fatalf("mtu = %v, want 1420", settings["mtu"])
|
||||
}
|
||||
|
||||
peers, _ := settings["peers"].([]any)
|
||||
if len(peers) != 1 {
|
||||
t.Fatalf("peers len = %d, want 1", len(peers))
|
||||
}
|
||||
peer, _ := peers[0].(map[string]any)
|
||||
if peer["publicKey"] != serverPub {
|
||||
t.Fatalf("peer publicKey = %v, want %v (derived from inbound secretKey)", peer["publicKey"], serverPub)
|
||||
}
|
||||
if peer["endpoint"] != "203.0.113.9:51820" {
|
||||
t.Fatalf("peer endpoint = %v, want 203.0.113.9:51820", peer["endpoint"])
|
||||
}
|
||||
if peer["preSharedKey"] != "psk-value" {
|
||||
t.Fatalf("peer preSharedKey = %v, want psk-value", peer["preSharedKey"])
|
||||
}
|
||||
if peer["keepAlive"] != float64(25) {
|
||||
t.Fatalf("peer keepAlive = %v, want 25", peer["keepAlive"])
|
||||
}
|
||||
allowed, _ := peer["allowedIPs"].([]any)
|
||||
if !reflect.DeepEqual(allowed, []any{"0.0.0.0/0", "::/0"}) {
|
||||
t.Fatalf("peer allowedIPs = %v, want full tunnel", peer["allowedIPs"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubJsonServiceWireguardNoKey(t *testing.T) {
|
||||
inbound := &model.Inbound{Listen: "203.0.113.9", Port: 51820, Protocol: model.WireGuard, Settings: `{}`}
|
||||
client := model.Client{Email: "user"}
|
||||
|
||||
if raw := NewSubJsonService("", "", "", nil).genWireguard(inbound, client); raw != nil {
|
||||
t.Fatalf("genWireguard = %s, want nil for a keyless wireguard client", raw)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user