fix: convert Clash network to sing-box transport for vless/vmess
vless outbound was passing Clash's network field (ws/grpc/h2) directly to sing-box's network field (which only accepts tcp/udp). Extract clashToSingBoxTransport() to convert ws/grpc/h2/quic/httpupgrade into sing-box transport objects. Apply to both vless and vmess outbounds.
This commit is contained in:
+81
-22
@@ -93,6 +93,85 @@ func RenderSingBoxJson(proxies []model.ProxyNode) string {
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// clashToSingBoxTransport converts a Clash proxy node's network/transport
|
||||
// fields into a sing-box transport object. Returns nil for tcp (no transport).
|
||||
func clashToSingBoxTransport(proxy model.ProxyNode) any {
|
||||
network := getString(proxy, "network")
|
||||
switch network {
|
||||
case "ws":
|
||||
wsOpts, _ := proxy["ws-opts"].(map[string]any)
|
||||
path := "/"
|
||||
if wsOpts != nil {
|
||||
if p, ok := wsOpts["path"].(string); ok && p != "" {
|
||||
path = p
|
||||
}
|
||||
}
|
||||
transportMap := map[string]any{
|
||||
"type": "ws",
|
||||
"path": path,
|
||||
}
|
||||
if wsOpts != nil {
|
||||
if h, ok := wsOpts["headers"]; ok && h != nil {
|
||||
transportMap["headers"] = h
|
||||
}
|
||||
}
|
||||
return transportMap
|
||||
|
||||
case "grpc":
|
||||
grpcOpts, _ := proxy["grpc-opts"].(map[string]any)
|
||||
serviceName := ""
|
||||
if grpcOpts != nil {
|
||||
if s, ok := grpcOpts["grpc-service-name"].(string); ok {
|
||||
serviceName = s
|
||||
}
|
||||
}
|
||||
return map[string]any{
|
||||
"type": "grpc",
|
||||
"service_name": serviceName,
|
||||
}
|
||||
|
||||
case "h2", "http":
|
||||
h2Opts, _ := proxy["h2-opts"].(map[string]any)
|
||||
transportMap := map[string]any{
|
||||
"type": "http",
|
||||
}
|
||||
if h2Opts != nil {
|
||||
if host, ok := h2Opts["host"].([]any); ok && len(host) > 0 {
|
||||
hosts := make([]string, 0, len(host))
|
||||
for _, h := range host {
|
||||
if s, ok := h.(string); ok && s != "" {
|
||||
hosts = append(hosts, s)
|
||||
}
|
||||
}
|
||||
transportMap["host"] = hosts
|
||||
}
|
||||
if p, ok := h2Opts["path"].(string); ok && p != "" {
|
||||
transportMap["path"] = p
|
||||
}
|
||||
}
|
||||
return transportMap
|
||||
|
||||
case "quic":
|
||||
return map[string]any{
|
||||
"type": "quic",
|
||||
}
|
||||
|
||||
case "httpupgrade":
|
||||
wsOpts, _ := proxy["ws-opts"].(map[string]any)
|
||||
path := "/"
|
||||
if wsOpts != nil {
|
||||
if p, ok := wsOpts["path"].(string); ok && p != "" {
|
||||
path = p
|
||||
}
|
||||
}
|
||||
return map[string]any{
|
||||
"type": "httpupgrade",
|
||||
"path": path,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToSingBoxOutbound converts a proxy node to a sing-box outbound map.
|
||||
// Returns nil for unsupported proxy types.
|
||||
func ToSingBoxOutbound(proxy model.ProxyNode) map[string]any {
|
||||
@@ -127,9 +206,9 @@ func ToSingBoxOutbound(proxy model.ProxyNode) map[string]any {
|
||||
"server_port": port,
|
||||
"uuid": proxy["uuid"],
|
||||
"flow": proxy["flow"],
|
||||
"network": strOr(proxy, "network", "tcp"),
|
||||
"packet_encoding": "xudp",
|
||||
"tls": tls,
|
||||
"transport": clashToSingBoxTransport(proxy),
|
||||
})
|
||||
|
||||
case "hysteria2":
|
||||
@@ -261,26 +340,6 @@ func ToSingBoxOutbound(proxy model.ProxyNode) map[string]any {
|
||||
if getBool(proxy, "tls") {
|
||||
tls = map[string]any{"enabled": true, "server_name": proxy["servername"]}
|
||||
}
|
||||
var transport any
|
||||
if getString(proxy, "network") == "ws" {
|
||||
wsOpts, _ := proxy["ws-opts"].(map[string]any)
|
||||
path := "/"
|
||||
if wsOpts != nil {
|
||||
if p, ok := wsOpts["path"].(string); ok && p != "" {
|
||||
path = p
|
||||
}
|
||||
}
|
||||
transportMap := map[string]any{
|
||||
"type": "ws",
|
||||
"path": path,
|
||||
}
|
||||
if wsOpts != nil {
|
||||
if h, ok := wsOpts["headers"]; ok && h != nil {
|
||||
transportMap["headers"] = h
|
||||
}
|
||||
}
|
||||
transport = transportMap
|
||||
}
|
||||
return util.StripUndefined(map[string]any{
|
||||
"type": "vmess",
|
||||
"tag": name,
|
||||
@@ -290,7 +349,7 @@ func ToSingBoxOutbound(proxy model.ProxyNode) map[string]any {
|
||||
"security": strOr(proxy, "cipher", "auto"),
|
||||
"alter_id": proxy["alterId"],
|
||||
"tls": tls,
|
||||
"transport": transport,
|
||||
"transport": clashToSingBoxTransport(proxy),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user