From 1f505752aecc4c8b7c14f979349211b76a1363bf Mon Sep 17 00:00:00 2001 From: xream Date: Thu, 24 Aug 2023 10:02:03 +0800 Subject: [PATCH] fix: trojan uri and tls --- backend/package.json | 2 +- backend/src/core/proxy-utils/index.js | 29 +++++++++++++++---- .../proxy-utils/parsers/peggy/trojan-uri.js | 11 ++++++- .../proxy-utils/parsers/peggy/trojan-uri.peg | 12 +++++++- backend/src/core/proxy-utils/producers/qx.js | 12 +++++--- backend/src/core/proxy-utils/producers/uri.js | 23 ++++++++++++++- 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/backend/package.json b/backend/package.json index cc617cd9c..2225c6920 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "sub-store", - "version": "2.14.21", + "version": "2.14.22", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.", "main": "src/main.js", "scripts": { diff --git a/backend/src/core/proxy-utils/index.js b/backend/src/core/proxy-utils/index.js index 72ca5cb4b..1f0447865 100644 --- a/backend/src/core/proxy-utils/index.js +++ b/backend/src/core/proxy-utils/index.js @@ -36,11 +36,7 @@ function parse(raw) { if (lastParser) { const [proxy, error] = tryParse(lastParser, line); if (!error) { - // 前面已经处理过普通情况下的 SNI, 这里显式设置 SNI, 防止之后解析成 IP 后丢失域名 SNI - if (proxy.tls && !proxy.sni && !isIP(proxy.server)) { - proxy.sni = proxy.server; - } - proxies.push(proxy); + proxies.push(lastParse(proxy)); success = true; } } @@ -50,7 +46,7 @@ function parse(raw) { for (const parser of PROXY_PARSERS) { const [proxy, error] = tryParse(parser, line); if (!error) { - proxies.push(proxy); + proxies.push(lastParse(proxy)); lastParser = parser; success = true; $.info(`${parser.name} is activated`); @@ -187,6 +183,27 @@ function safeMatch(parser, line) { } } +function lastParse(proxy) { + if (proxy.type === 'trojan') { + proxy.tls = true; + } + if (proxy.tls && !proxy.sni) { + if (proxy.network) { + let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; + transportHost = Array.isArray(transportHost) + ? transportHost[0] + : transportHost; + if (transportHost) { + proxy.sni = transportHost; + } + } + if (!proxy.sni && !isIP(proxy.server)) { + proxy.sni = proxy.server; + } + } + return proxy; +} + function isIP(ip) { return isIPv4(ip) || isIPv6(ip); } diff --git a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js index 72c058174..2cf36155e 100644 --- a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js +++ b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js @@ -79,7 +79,7 @@ port = digits:[0-9]+ { } } -params = "?" head:param tail:("&"@param)* { +params = "/"? "?" head:param tail:("&"@param)* { proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); proxy.sni = params["sni"] || params["peer"]; @@ -87,6 +87,15 @@ params = "?" head:param tail:("&"@param)* { proxy.network = "ws"; $set(proxy, "ws-opts.path", params["wspath"]); } + if (params["type"]) { + proxy.network = params["type"] + if (params["path"]) { + $set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"])); + } + if (params["host"]) { + $set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"])); + } + } proxy.udp = toBool(params["udp"]); proxy.tfo = toBool(params["tfo"]); diff --git a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg index 15cb1a0c9..0f4619d96 100644 --- a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg +++ b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg @@ -77,7 +77,7 @@ port = digits:[0-9]+ { } } -params = "?" head:param tail:("&"@param)* { +params = "/"? "?" head:param tail:("&"@param)* { proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); proxy.sni = params["sni"] || params["peer"]; @@ -85,6 +85,16 @@ params = "?" head:param tail:("&"@param)* { proxy.network = "ws"; $set(proxy, "ws-opts.path", params["wspath"]); } + + if (params["type"]) { + proxy.network = params["type"] + if (params["path"]) { + $set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"])); + } + if (params["host"]) { + $set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"])); + } + } proxy.udp = toBool(params["udp"]); proxy.tfo = toBool(params["tfo"]); diff --git a/backend/src/core/proxy-utils/producers/qx.js b/backend/src/core/proxy-utils/producers/qx.js index b924333fa..4b2a8512c 100644 --- a/backend/src/core/proxy-utils/producers/qx.js +++ b/backend/src/core/proxy-utils/producers/qx.js @@ -210,14 +210,18 @@ function vmess(proxy) { } else { throw new Error(`network ${proxy.network} is unsupported`); } - let httpPath = proxy[`${proxy.network}-opts`]?.path; - let httpHost = proxy[`${proxy.network}-opts`]?.headers?.Host; + let transportPath = proxy[`${proxy.network}-opts`]?.path; + let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; appendIfPresent( - `,obfs-uri=${Array.isArray(httpPath) ? httpPath[0] : httpPath}`, + `,obfs-uri=${ + Array.isArray(transportPath) ? transportPath[0] : transportPath + }`, `${proxy.network}-opts.path`, ); appendIfPresent( - `,obfs-host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`, + `,obfs-host=${ + Array.isArray(transportHost) ? transportHost[0] : transportHost + }`, `${proxy.network}-opts.headers.Host`, ); } else { diff --git a/backend/src/core/proxy-utils/producers/uri.js b/backend/src/core/proxy-utils/producers/uri.js index fbd5462ea..fe43704c8 100644 --- a/backend/src/core/proxy-utils/producers/uri.js +++ b/backend/src/core/proxy-utils/producers/uri.js @@ -78,11 +78,32 @@ export default function URI_Producer() { result = 'vmess://' + Base64.encode(JSON.stringify(result)); break; case 'trojan': + let transport = ''; + if (proxy.network) { + transport = `&type=${proxy.network}`; + let transportPath = proxy[`${proxy.network}-opts`]?.path; + let transportHost = + proxy[`${proxy.network}-opts`]?.headers?.Host; + if (transportPath) { + transport += `&path=${encodeURIComponent( + Array.isArray(transportPath) + ? transportPath[0] + : transportPath, + )}`; + } + if (transportHost) { + transport += `&host=${encodeURIComponent( + Array.isArray(transportHost) + ? transportHost[0] + : transportHost, + )}`; + } + } result = `trojan://${proxy.password}@${proxy.server}:${ proxy.port }?sni=${encodeURIComponent(proxy.sni || proxy.server)}${ proxy['skip-cert-verify'] ? '&allowInsecure=1' : '' - }#${encodeURIComponent(proxy.name)}`; + }${transport}#${encodeURIComponent(proxy.name)}`; break; } return result;