From 9e47640eeb60a196526c1e7c95517638aa96c467 Mon Sep 17 00:00:00 2001 From: jocayn <1579649885@qq.com> Date: Sat, 13 Jun 2026 20:12:06 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3=20singbox=20=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E6=97=B6=E5=85=B3=E4=BA=8E=20client-fingerprint=20?= =?UTF-8?q?=E7=9A=84=E6=8A=A5=E9=94=99=E5=B9=B6=E4=BC=98=E5=8C=96=20tls=20?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sub2proxy.js | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/sub2proxy.js b/sub2proxy.js index 3bbde5a..f5c3489 100644 --- a/sub2proxy.js +++ b/sub2proxy.js @@ -53,6 +53,12 @@ function clashToSingbox(node) { if (node.sni) tls.server_name = node.sni; if (node.hasOwnProperty('skip-cert-verify')) tls.insecure = !!node['skip-cert-verify']; if (node.alpn) tls.alpn = node.alpn; + if (node['client-fingerprint']) { + tls.utls = { + enabled: true, + fingerprint: node['client-fingerprint'] + }; + } sb.tls = tls; } else if (t === 'vless') { sb.type = 'vless'; @@ -109,6 +115,12 @@ function clashToSingbox(node) { if (node.sni) tls.server_name = node.sni; if (node.hasOwnProperty('skip-cert-verify')) tls.insecure = !!node['skip-cert-verify']; if (node.alpn) tls.alpn = node.alpn; + if (node['client-fingerprint']) { + tls.utls = { + enabled: true, + fingerprint: node['client-fingerprint'] + }; + } sb.tls = tls; } else if (t === 'vmess') { sb.type = 'vmess'; @@ -121,6 +133,12 @@ function clashToSingbox(node) { tls.enabled = true; if (node.servername) tls.server_name = node.servername; if (node.hasOwnProperty('skip-cert-verify')) tls.insecure = !!node['skip-cert-verify']; + if (node['client-fingerprint']) { + tls.utls = { + enabled: true, + fingerprint: node['client-fingerprint'] + }; + } } sb.tls = tls; @@ -134,8 +152,32 @@ function clashToSingbox(node) { } } else { sb.type = t; + + // Process generic TLS conversion if any TLS feature is detected + const hasTls = node.tls || node.servername || node.sni || node['client-fingerprint'] || node['skip-cert-verify']; + if (hasTls) { + const tls = { enabled: true }; + if (node.servername || node.sni) tls.server_name = node.servername || node.sni; + if (node.hasOwnProperty('skip-cert-verify')) tls.insecure = !!node['skip-cert-verify']; + if (node.alpn) tls.alpn = node.alpn; + if (node['client-fingerprint']) { + tls.utls = { + enabled: true, + fingerprint: node['client-fingerprint'] + }; + } + sb.tls = tls; + } + + // Copy other fields but filter out Clash proprietary/incompatible fields + const excludeKeys = [ + 'name', 'port', 'type', 'server', 'tls', 'servername', 'sni', + 'skip-cert-verify', 'client-fingerprint', 'alpn', 'udp', + 'reality-opts', 'ws-opts', 'grpc-opts', 'h2-opts', 'http-opts', + 'packet-encoding' + ]; for (const k in node) { - if (!['name', 'port', 'type', 'server'].includes(k)) { + if (!excludeKeys.includes(k)) { sb[k] = node[k]; } }