mirror of
https://github.com/2dust/v2rayN.git
synced 2025-11-29 03:02:53 +00:00
perf: Shadowsocks
This commit is contained in:
parent
30e663cd4f
commit
ffd4249d43
2 changed files with 208 additions and 64 deletions
|
|
@ -41,7 +41,58 @@ public class ShadowsocksFmt : BaseFmt
|
|||
//url = Utile.Base64Encode(url);
|
||||
//new Sip002
|
||||
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}", true);
|
||||
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, null, remark);
|
||||
|
||||
// plugin
|
||||
var plugin = string.Empty;
|
||||
var pluginArgs = string.Empty;
|
||||
|
||||
if (item.Network == nameof(ETransport.tcp) && item.HeaderType == Global.TcpHeaderHttp)
|
||||
{
|
||||
plugin = "obfs-local";
|
||||
pluginArgs = $"obfs=http;obfs-host={item.RequestHost};";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.Network == nameof(ETransport.ws))
|
||||
{
|
||||
pluginArgs += "mode=websocket;";
|
||||
pluginArgs += $"host={item.RequestHost};";
|
||||
pluginArgs += $"path={item.Path};";
|
||||
}
|
||||
else if (item.Network == nameof(ETransport.quic))
|
||||
{
|
||||
pluginArgs += "mode=quic;";
|
||||
}
|
||||
if (item.StreamSecurity == Global.StreamSecurity)
|
||||
{
|
||||
pluginArgs += "tls;";
|
||||
var certs = CertPemManager.ParsePemChain(item.Cert);
|
||||
if (certs.Count > 0)
|
||||
{
|
||||
var cert = certs.First();
|
||||
const string beginMarker = "-----BEGIN CERTIFICATE-----\n";
|
||||
const string endMarker = "\n-----END CERTIFICATE-----";
|
||||
|
||||
var base64Start = beginMarker.Length;
|
||||
var endIndex = cert.IndexOf(endMarker, base64Start, StringComparison.Ordinal);
|
||||
var base64Content = cert.Substring(base64Start, endIndex - base64Start);
|
||||
|
||||
pluginArgs += $"certRaw={base64Content};";
|
||||
}
|
||||
}
|
||||
if (pluginArgs.Length > 0)
|
||||
{
|
||||
plugin = "v2ray-plugin";
|
||||
}
|
||||
}
|
||||
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (plugin.IsNotEmpty())
|
||||
{
|
||||
dicQuery["plugin"] = plugin + (pluginArgs.IsNotEmpty() ? (";" + pluginArgs) : "");
|
||||
}
|
||||
|
||||
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, dicQuery, remark);
|
||||
}
|
||||
|
||||
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
|
@ -124,19 +175,71 @@ public class ShadowsocksFmt : BaseFmt
|
|||
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||
if (queryParameters["plugin"] != null)
|
||||
{
|
||||
//obfs-host exists
|
||||
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||
if (queryParameters["plugin"].Contains("obfs=http") && obfsHost.IsNotEmpty())
|
||||
{
|
||||
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||
item.Network = Global.DefaultNetwork;
|
||||
item.HeaderType = Global.TcpHeaderHttp;
|
||||
item.RequestHost = obfsHost ?? "";
|
||||
}
|
||||
else
|
||||
var pluginStr = queryParameters["plugin"];
|
||||
var pluginParts = pluginStr.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (pluginParts.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pluginName = pluginParts[0];
|
||||
|
||||
// Parse obfs-local plugin
|
||||
if (pluginName == "obfs-local")
|
||||
{
|
||||
var obfsMode = pluginParts.FirstOrDefault(t => t.StartsWith("obfs="));
|
||||
var obfsHost = pluginParts.FirstOrDefault(t => t.StartsWith("obfs-host="));
|
||||
|
||||
if ((!obfsMode.IsNullOrEmpty()) && obfsMode.Contains("obfs=http") && obfsHost.IsNotEmpty())
|
||||
{
|
||||
obfsHost = obfsHost.Replace("obfs-host=", "");
|
||||
item.Network = Global.DefaultNetwork;
|
||||
item.HeaderType = Global.TcpHeaderHttp;
|
||||
item.RequestHost = obfsHost;
|
||||
}
|
||||
}
|
||||
// Parse v2ray-plugin
|
||||
else if (pluginName == "v2ray-plugin")
|
||||
{
|
||||
var mode = pluginParts.FirstOrDefault(t => t.StartsWith("mode="), "websocket");
|
||||
var host = pluginParts.FirstOrDefault(t => t.StartsWith("host="));
|
||||
var path = pluginParts.FirstOrDefault(t => t.StartsWith("path="));
|
||||
var hasTls = pluginParts.Any(t => t == "tls");
|
||||
var certRaw = pluginParts.FirstOrDefault(t => t.StartsWith("certRaw="));
|
||||
|
||||
var modeValue = mode.Replace("mode=", "");
|
||||
if (modeValue == "websocket")
|
||||
{
|
||||
item.Network = nameof(ETransport.ws);
|
||||
if (!host.IsNullOrEmpty())
|
||||
{
|
||||
item.RequestHost = host.Replace("host=", "");
|
||||
}
|
||||
if (!path.IsNullOrEmpty())
|
||||
{
|
||||
item.Path = path.Replace("path=", "");
|
||||
}
|
||||
}
|
||||
else if (modeValue == "quic")
|
||||
{
|
||||
item.Network = nameof(ETransport.quic);
|
||||
}
|
||||
|
||||
if (hasTls)
|
||||
{
|
||||
item.StreamSecurity = Global.StreamSecurity;
|
||||
|
||||
if (!certRaw.IsNullOrEmpty())
|
||||
{
|
||||
var certBase64 = certRaw.Replace("certRaw=", "");
|
||||
const string beginMarker = "-----BEGIN CERTIFICATE-----\n";
|
||||
const string endMarker = "\n-----END CERTIFICATE-----";
|
||||
var certPem = beginMarker + certBase64 + endMarker;
|
||||
item.Cert = certPem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public partial class CoreConfigSingboxService
|
|||
}
|
||||
|
||||
await GenOutboundMux(node, outbound);
|
||||
await GenOutboundTransport(node, outbound);
|
||||
break;
|
||||
}
|
||||
case EConfigType.Shadowsocks:
|
||||
|
|
@ -33,6 +34,48 @@ public partial class CoreConfigSingboxService
|
|||
outbound.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(node.Security) ? node.Security : Global.None;
|
||||
outbound.password = node.Id;
|
||||
|
||||
if (node.Network == nameof(ETransport.tcp) && node.HeaderType == Global.TcpHeaderHttp)
|
||||
{
|
||||
outbound.plugin = "obfs-local";
|
||||
outbound.plugin_opts = $"obfs=http;obfs-host={node.RequestHost};";
|
||||
}
|
||||
else
|
||||
{
|
||||
var pluginArgs = string.Empty;
|
||||
if (node.Network == nameof(ETransport.ws))
|
||||
{
|
||||
pluginArgs += "mode=websocket;";
|
||||
pluginArgs += $"host={node.RequestHost};";
|
||||
pluginArgs += $"path={node.Path};";
|
||||
}
|
||||
else if (node.Network == nameof(ETransport.quic))
|
||||
{
|
||||
pluginArgs += "mode=quic;";
|
||||
}
|
||||
if (node.StreamSecurity == Global.StreamSecurity)
|
||||
{
|
||||
pluginArgs += "tls;";
|
||||
var certs = CertPemManager.ParsePemChain(node.Cert);
|
||||
if (certs.Count > 0)
|
||||
{
|
||||
var cert = certs.First();
|
||||
const string beginMarker = "-----BEGIN CERTIFICATE-----\n";
|
||||
const string endMarker = "\n-----END CERTIFICATE-----";
|
||||
|
||||
var base64Start = beginMarker.Length;
|
||||
var endIndex = cert.IndexOf(endMarker, base64Start, StringComparison.Ordinal);
|
||||
var base64Content = cert.Substring(base64Start, endIndex - base64Start);
|
||||
|
||||
pluginArgs += $"certRaw={base64Content};";
|
||||
}
|
||||
}
|
||||
if (pluginArgs.Length > 0)
|
||||
{
|
||||
outbound.plugin = "v2ray-plugin";
|
||||
outbound.plugin_opts = pluginArgs;
|
||||
}
|
||||
}
|
||||
|
||||
await GenOutboundMux(node, outbound);
|
||||
break;
|
||||
}
|
||||
|
|
@ -71,6 +114,8 @@ public partial class CoreConfigSingboxService
|
|||
{
|
||||
outbound.flow = node.Flow;
|
||||
}
|
||||
|
||||
await GenOutboundTransport(node, outbound);
|
||||
break;
|
||||
}
|
||||
case EConfigType.Trojan:
|
||||
|
|
@ -78,6 +123,7 @@ public partial class CoreConfigSingboxService
|
|||
outbound.password = node.Id;
|
||||
|
||||
await GenOutboundMux(node, outbound);
|
||||
await GenOutboundTransport(node, outbound);
|
||||
break;
|
||||
}
|
||||
case EConfigType.Hysteria2:
|
||||
|
|
@ -127,8 +173,6 @@ public partial class CoreConfigSingboxService
|
|||
}
|
||||
|
||||
await GenOutboundTls(node, outbound);
|
||||
|
||||
await GenOutboundTransport(node, outbound);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -232,8 +276,14 @@ public partial class CoreConfigSingboxService
|
|||
{
|
||||
try
|
||||
{
|
||||
if (node.StreamSecurity is Global.StreamSecurityReality or Global.StreamSecurity)
|
||||
if (node.StreamSecurity is not (Global.StreamSecurityReality or Global.StreamSecurity))
|
||||
{
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
if (node.ConfigType is EConfigType.Shadowsocks or EConfigType.SOCKS or EConfigType.WireGuard)
|
||||
{
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
var server_name = string.Empty;
|
||||
if (node.Sni.IsNotEmpty())
|
||||
{
|
||||
|
|
@ -280,7 +330,6 @@ public partial class CoreConfigSingboxService
|
|||
}
|
||||
outbound.tls = tls;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
|
|
@ -304,19 +353,11 @@ public partial class CoreConfigSingboxService
|
|||
|
||||
case nameof(ETransport.tcp): //http
|
||||
if (node.HeaderType == Global.TcpHeaderHttp)
|
||||
{
|
||||
if (node.ConfigType == EConfigType.Shadowsocks)
|
||||
{
|
||||
outbound.plugin = "obfs-local";
|
||||
outbound.plugin_opts = $"obfs=http;obfs-host={node.RequestHost};";
|
||||
}
|
||||
else
|
||||
{
|
||||
transport.type = nameof(ETransport.http);
|
||||
transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost);
|
||||
transport.path = node.Path.IsNullOrEmpty() ? null : node.Path;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ETransport.ws):
|
||||
|
|
|
|||
Loading…
Reference in a new issue