fix(sub): emit a bare host in Clash proxies

A Clash "server" is a bare host, not a URI authority, but the custom share
address strategy stores an IPv6 literal with brackets so the address normalizer
can hand it to the raw link generators. The Clash renderer copied that value
into every proxy verbatim, so mihomo received server: "[2001:db8::1]" and
failed to parse the node. Raw links were unaffected because joinHostPort strips
the brackets and re-adds exactly one.

Strip them once where the renderer takes the resolved dest, which is the single
place all three proxy builders read the address from.

Closes #6373
This commit is contained in:
Sanaei
2026-09-09 00:17:45 +02:00
parent 20d7f91c65
commit 246d9207a5
2 changed files with 29 additions and 1 deletions
+4 -1
View File
@@ -234,7 +234,10 @@ func (s *SubClashService) getProxies(subReq *SubService, inbound *model.Inbound,
// the synthetic/legacy entry) before it becomes the proxy name.
subReq.renderHostRemark(inbound, client, extPrxy, network)
workingInbound := *inbound
workingInbound.Listen, _ = extPrxy["dest"].(string)
// A Clash "server" is a bare host, not a URI authority, and the custom
// share address stores IPv6 literals bracketed.
dest, _ := extPrxy["dest"].(string)
workingInbound.Listen = strings.Trim(dest, "[]")
if port, ok := extPrxy["port"].(float64); ok {
workingInbound.Port = int(port)
}
+25
View File
@@ -883,3 +883,28 @@ func TestBuildWireguardProxyForClashNoKey(t *testing.T) {
t.Fatalf("buildProxy = %v, want nil for a keyless wireguard client", proxy)
}
}
// TestGetProxies_CustomIPv6ShareAddrIsUnbracketed pins that a Clash "server" is a
// bare host: the custom share address stores IPv6 literals bracketed, and mihomo
// rejects "[2001:db8::1]" there.
func TestGetProxies_CustomIPv6ShareAddrIsUnbracketed(t *testing.T) {
svc := &SubClashService{SubService: &SubService{}}
inbound := &model.Inbound{
Protocol: model.VLESS,
Port: 443,
Remark: "r",
Settings: `{"encryption":"none"}`,
StreamSettings: `{"network":"tcp","security":"none"}`,
ShareAddrStrategy: "custom",
ShareAddr: "[2001:db8::1]",
}
client := model.Client{ID: "11111111-2222-4333-8444-555555555555", Email: "a@example.com"}
proxies := svc.getProxies(svc.SubService, inbound, client, "panel.example.com")
if len(proxies) != 1 {
t.Fatalf("getProxies returned %d proxies, want 1", len(proxies))
}
if got := proxies[0]["server"]; got != "2001:db8::1" {
t.Fatalf("server = %v, want 2001:db8::1", got)
}
}