diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 91d7b478a0..9f85621060 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -55,7 +55,7 @@ jobs:
uses: actions/setup-go@v3
if: steps.check_other.outputs.files_exists == 'false'
with:
- go-version: 1.17.3
+ go-version: ^1.18.3
- name: Setup C++
uses: msys2/setup-msys2@v2
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f8df13f398..a6855dc655 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -51,7 +51,7 @@ jobs:
uses: actions/setup-go@v3
if: steps.check_other.outputs.files_exists == 'false'
with:
- go-version: 1.17.3
+ go-version: ^1.18.3
- name: Setup C++
uses: msys2/setup-msys2@v2
diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs
index b8e64c2816..4bf65ff2cc 100644
--- a/Netch/Controllers/MainController.cs
+++ b/Netch/Controllers/MainController.cs
@@ -57,7 +57,7 @@ public static async Task StartAsync(Server server, Mode mode)
// Start Server Controller to get a local socks5 server
Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}");
- ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController();
+ ServerController = new V2rayController();
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name));
TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5");
diff --git a/Netch/Controllers/UpdateChecker.cs b/Netch/Controllers/UpdateChecker.cs
index 97e2810d8d..eefff1da8a 100644
--- a/Netch/Controllers/UpdateChecker.cs
+++ b/Netch/Controllers/UpdateChecker.cs
@@ -15,7 +15,7 @@ public static class UpdateChecker
public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2022";
- public const string AssemblyVersion = @"1.9.5";
+ public const string AssemblyVersion = @"1.9.6";
private const string Suffix = @"";
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
diff --git a/Netch/Resources/zh-CN b/Netch/Resources/zh-CN
index 9c90f9ef40..d9a968efbb 100644
--- a/Netch/Resources/zh-CN
+++ b/Netch/Resources/zh-CN
@@ -69,6 +69,10 @@
"Plugin": "插件",
"Plugin Options": "插件参数",
"Remote Address": "远端地址",
+ "Local Addresses": "本地地址(可多个)",
+ "Public Key": "节点公钥",
+ "Private Key": "私钥",
+ "PSK": "节点预共享密钥",
"Subscription": "订阅",
"Manage Subscriptions": "管理订阅",
diff --git a/Netch/Servers/Shadowsocks/ShadowsocksServer.cs b/Netch/Servers/Shadowsocks/ShadowsocksServer.cs
index ff4c997986..3f1a52eb85 100644
--- a/Netch/Servers/Shadowsocks/ShadowsocksServer.cs
+++ b/Netch/Servers/Shadowsocks/ShadowsocksServer.cs
@@ -13,7 +13,7 @@ public override string MaskedData()
///
/// 加密方式
///
- public string EncryptMethod { get; set; } = SSGlobal.EncryptMethods[0];
+ public string EncryptMethod { get; set; } = SSGlobal.EncryptMethods[4];
///
/// 密码
@@ -43,24 +43,50 @@ public static class SSGlobal
///
public static readonly List EncryptMethods = new()
{
- "rc4-md5",
+ "none",
+
+ // 2022 edition cipher
+ "2022-blake3-aes-128-gcm",
+ "2022-blake3-aes-256-gcm",
+ "2022-blake3-chacha20-poly1305",
+
+ // AEAD cipher
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
- "aes-128-cfb",
- "aes-192-cfb",
- "aes-256-cfb",
+ "chacha20-ietf-poly1305",
+ "xchacha20-ietf-poly1305",
+
+ // stream cipher
+ "rc4",
+ "rc4-md5",
"aes-128-ctr",
"aes-192-ctr",
"aes-256-ctr",
+ "aes-128-cfb",
+ "aes-192-cfb",
+ "aes-256-cfb",
+ "aes-128-cfb8",
+ "aes-192-cfb8",
+ "aes-256-cfb8",
+ "aes-128-ofb",
+ "aes-192-ofb",
+ "aes-256-ofb",
+ "bf-cfb",
+ "cast5-cfb",
+ "des-cfb",
+ "idea-cfb",
+ "rc2-cfb",
+ "seed-cfb",
"camellia-128-cfb",
"camellia-192-cfb",
"camellia-256-cfb",
- "bf-cfb",
- "chacha20-ietf-poly1305",
- "xchacha20-ietf-poly1305",
+ "camellia-128-cfb8",
+ "camellia-192-cfb8",
+ "camellia-256-cfb8",
"salsa20",
"chacha20",
- "chacha20-ietf"
+ "chacha20-ietf",
+ "xchacha20"
};
}
\ No newline at end of file
diff --git a/Netch/Servers/Shadowsocks/ShadowsocksUtil.cs b/Netch/Servers/Shadowsocks/ShadowsocksUtil.cs
index 1331ebebb4..5da279a841 100644
--- a/Netch/Servers/Shadowsocks/ShadowsocksUtil.cs
+++ b/Netch/Servers/Shadowsocks/ShadowsocksUtil.cs
@@ -114,13 +114,13 @@ public ShadowsocksServer ParseSsUri(string text)
{
case "obfs-local":
case "simple-obfs":
- plugin = "simple-obfs";
+ plugin = "obfs-local";
if (!pluginopts.Contains("obfs="))
pluginopts = "obfs=http;obfs-host=" + pluginopts;
break;
case "simple-obfs-tls":
- plugin = "simple-obfs";
+ plugin = "obfs-local";
if (!pluginopts.Contains("obfs="))
pluginopts = "obfs=tls;obfs-host=" + pluginopts;
diff --git a/Netch/Servers/ShadowsocksR/ShadowsocksRServer.cs b/Netch/Servers/ShadowsocksR/ShadowsocksRServer.cs
index ba31f117de..d1bd23bdb5 100644
--- a/Netch/Servers/ShadowsocksR/ShadowsocksRServer.cs
+++ b/Netch/Servers/ShadowsocksR/ShadowsocksRServer.cs
@@ -18,7 +18,7 @@ public override string MaskedData()
///
/// 加密方式
///
- public string EncryptMethod { get; set; } = SSRGlobal.EncryptMethods[0];
+ public string EncryptMethod { get; set; } = SSRGlobal.EncryptMethods[4];
///
/// 协议
@@ -49,11 +49,11 @@ public class SSRGlobal
public static readonly List Protocols = new()
{
"origin",
- "verify_deflate",
"auth_sha1_v4",
"auth_aes128_md5",
"auth_aes128_sha1",
- "auth_chain_a"
+ "auth_chain_a",
+ "auth_chain_b"
};
///
@@ -64,36 +64,14 @@ public class SSRGlobal
"plain",
"http_simple",
"http_post",
- "tls1.2_ticket_auth"
+ "tls_simple",
+ "tls1.2_ticket_auth",
+ "tls1.2_ticket_fastauth",
+ "random_head"
};
///
/// SS/SSR 加密方式
///
- public static readonly List EncryptMethods = new()
- {
- "none",
- "table",
- "rc4",
- "rc4-md5",
- "rc4-md5-6",
- "aes-128-cfb",
- "aes-192-cfb",
- "aes-256-cfb",
- "aes-128-ctr",
- "aes-192-ctr",
- "aes-256-ctr",
- "bf-cfb",
- "camellia-128-cfb",
- "camellia-192-cfb",
- "camellia-256-cfb",
- "cast5-cfb",
- "des-cfb",
- "idea-cfb",
- "rc2-cfb",
- "seed-cfb",
- "salsa20",
- "chacha20",
- "chacha20-ietf"
- };
+ public static readonly List EncryptMethods = SSGlobal.EncryptMethods;
}
\ No newline at end of file
diff --git a/Netch/Servers/Trojan/TrojanForm.cs b/Netch/Servers/Trojan/TrojanForm.cs
index 210a3c06ef..7fcf436cbe 100644
--- a/Netch/Servers/Trojan/TrojanForm.cs
+++ b/Netch/Servers/Trojan/TrojanForm.cs
@@ -11,6 +11,7 @@ public TrojanForm(TrojanServer? server = default)
Server = server;
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
CreateTextBox("Host", "Host", s => true, s => server.Host = s, server.Host);
+ CreateComboBox("TLSSecure", "TLS Secure", VLESSGlobal.TLSSecure, s => server.TLSSecureType = s, server.TLSSecureType);
}
protected override string TypeName { get; } = "Trojan";
diff --git a/Netch/Servers/Trojan/TrojanServer.cs b/Netch/Servers/Trojan/TrojanServer.cs
index 2a2bc32f24..15cb3cb7f4 100644
--- a/Netch/Servers/Trojan/TrojanServer.cs
+++ b/Netch/Servers/Trojan/TrojanServer.cs
@@ -4,6 +4,8 @@ namespace Netch.Servers;
public class TrojanServer : Server
{
+ private string _tlsSecureType = VLESSGlobal.TLSSecure[1];
+
public override string Type { get; } = "Trojan";
public override string MaskedData()
@@ -20,4 +22,19 @@ public override string MaskedData()
/// 伪装域名
///
public string? Host { get; set; }
+
+ ///
+ /// TLS 底层传输安全
+ ///
+ public string TLSSecureType
+ {
+ get => _tlsSecureType;
+ set
+ {
+ if (value == "")
+ value = VLESSGlobal.TLSSecure[1];
+
+ _tlsSecureType = value;
+ }
+ }
}
\ No newline at end of file
diff --git a/Netch/Servers/Trojan/TrojanUtil.cs b/Netch/Servers/Trojan/TrojanUtil.cs
index 09e1f666b1..4ec4a58c40 100644
--- a/Netch/Servers/Trojan/TrojanUtil.cs
+++ b/Netch/Servers/Trojan/TrojanUtil.cs
@@ -32,7 +32,7 @@ public void Create()
public string GetShareLink(Server s)
{
var server = (TrojanServer)s;
- return $"trojan://{HttpUtility.UrlEncode(server.Password)}@{server.Hostname}:{server.Port}#{server.Remark}";
+ return $"trojan://{HttpUtility.UrlEncode(server.Password)}@{server.Hostname}:{server.Port}?sni={server.Host}#{server.Remark}";
}
public IServerController GetController()
@@ -61,8 +61,13 @@ public IEnumerable ParseUri(string text)
var peer = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("peer"));
- if (peer != null)
+ if (peer != null) {
data.Host = peer;
+ } else {
+ peer = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("sni"));
+ if (peer != null)
+ data.Host = peer;
+ }
text = regmatch.Groups["data"].Value;
}
diff --git a/Netch/Servers/V2ray/V2rayConfig.cs b/Netch/Servers/V2ray/V2rayConfig.cs
index 349c143019..7a84228cff 100644
--- a/Netch/Servers/V2ray/V2rayConfig.cs
+++ b/Netch/Servers/V2ray/V2rayConfig.cs
@@ -29,9 +29,9 @@ public class Outbound
public OutboundConfiguration settings { get; set; }
- public StreamSettings streamSettings { get; set; }
+ public StreamSettings? streamSettings { get; set; }
- public Mux mux { get; set; }
+ public Mux? mux { get; set; }
}
public class OutboundConfiguration
@@ -39,6 +39,28 @@ public class OutboundConfiguration
public VnextItem[] vnext { get; set; }
public object[] servers { get; set; }
+
+ public string address { get; set; }
+
+ public ushort port { get; set; }
+
+ public string packetEncoding { get; set; }
+
+ public string plugin { get; set; }
+
+ public string pluginOpts { get; set; }
+
+ public string[] pluginArgs { get; set; }
+
+ public string[] localAddresses { get; set; }
+
+ public string peerPublicKey { get; set; }
+
+ public string privateKey { get; set; }
+
+ public string preSharedKey { get; set; }
+
+ public int mtu { get; set; }
}
public class VnextItem
@@ -50,10 +72,23 @@ public class VnextItem
public User[] users { get; set; }
}
+public class ShadowsocksServerItem
+{
+ public string address { get; set; }
+
+ public ushort port { get; set; }
+
+ public string method { get; set; }
+
+ public string password { get; set; }
+ }
+
public class Mux
{
public bool enabled { get; set; }
+ public string packetEncoding { get; set; }
+
public int concurrency { get; set; }
}
diff --git a/Netch/Servers/V2ray/V2rayConfigUtils.cs b/Netch/Servers/V2ray/V2rayConfigUtils.cs
index 2e54838af8..5f98c7f2f1 100644
--- a/Netch/Servers/V2ray/V2rayConfigUtils.cs
+++ b/Netch/Servers/V2ray/V2rayConfigUtils.cs
@@ -20,6 +20,7 @@ public static async Task GenerateClientConfigAsync(Server server)
listen = Global.Settings.LocalAddress,
settings = new
{
+ auth = "noauth",
udp = true
}
}
@@ -89,6 +90,9 @@ private static async Task outbound(Server server)
}
};
+ outbound.settings.packetEncoding = Global.Settings.V2RayConfig.XrayCone ? vless.PacketEncoding : "none";
+ outbound.mux.packetEncoding = Global.Settings.V2RayConfig.XrayCone ? vless.PacketEncoding : "none";
+
outbound.streamSettings = boundStreamSettings(vless);
if (vless.TLSSecureType == "xtls")
@@ -107,6 +111,10 @@ private static async Task outbound(Server server)
case VMessServer vmess:
{
outbound.protocol = "vmess";
+ if (vmess.EncryptMethod == "auto" && vmess.TLSSecureType != "none" && !Global.Settings.V2RayConfig.AllowInsecure)
+ {
+ vmess.EncryptMethod = "zero";
+ }
outbound.settings.vnext = new[]
{
new VnextItem
@@ -125,12 +133,111 @@ private static async Task outbound(Server server)
}
};
+ outbound.settings.packetEncoding = Global.Settings.V2RayConfig.XrayCone ? vmess.PacketEncoding : "none";
+ outbound.mux.packetEncoding = Global.Settings.V2RayConfig.XrayCone ? vmess.PacketEncoding : "none";
+
outbound.streamSettings = boundStreamSettings(vmess);
outbound.mux.enabled = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
break;
}
+ case ShadowsocksServer ss:
+ outbound.protocol = "shadowsocks";
+ outbound.settings = new OutboundConfiguration
+ {
+ servers = new[]
+ {
+ new ShadowsocksServerItem
+ {
+ address = await server.AutoResolveHostnameAsync(),
+ port = server.Port,
+ method = ss.EncryptMethod,
+ password = ss.Password,
+ }
+ },
+ plugin = ss.Plugin ?? "",
+ pluginOpts = ss.PluginOption ?? ""
+ };
+ break;
+ case ShadowsocksRServer ssr:
+ outbound.protocol = "shadowsocks";
+ outbound.settings = new OutboundConfiguration
+ {
+ servers = new[]
+ {
+ new ShadowsocksServerItem
+ {
+ address = await server.AutoResolveHostnameAsync(),
+ port = server.Port,
+ method = ssr.EncryptMethod,
+ password = ssr.Password,
+ }
+ },
+ plugin = "shadowsocksr",
+ pluginArgs = new string[]
+ {
+ "--obfs=" + ssr.OBFS,
+ "--obfs-param=" + ssr.OBFSParam ?? "",
+ "--protocol=" + ssr.Protocol,
+ "--protocol-param=" + ssr.ProtocolParam ?? ""
+ }
+ };
+ break;
+ case TrojanServer trojan:
+ outbound.protocol = "trojan";
+ outbound.settings = new OutboundConfiguration
+ {
+ servers = new[]
+ {
+ new ShadowsocksServerItem // I'm not serious
+ {
+ address = await server.AutoResolveHostnameAsync(),
+ port = server.Port,
+ method = "",
+ password = trojan.Password
+ }
+ }
+ };
+
+ outbound.streamSettings = new StreamSettings
+ {
+ network = "tcp",
+ security = trojan.TLSSecureType
+ };
+ if (trojan.TLSSecureType != "none")
+ {
+ var tlsSettings = new TlsSettings
+ {
+ allowInsecure = Global.Settings.V2RayConfig.AllowInsecure,
+ serverName = trojan.Host ?? ""
+ };
+
+ switch (trojan.TLSSecureType)
+ {
+ case "tls":
+ outbound.streamSettings.tlsSettings = tlsSettings;
+ break;
+ case "xtls":
+ outbound.streamSettings.xtlsSettings = tlsSettings;
+ break;
+ }
+ }
+ break;
+ case WireGuardServer wg:
+ outbound.protocol = "wireguard";
+ outbound.settings = new OutboundConfiguration
+ {
+ address = await server.AutoResolveHostnameAsync(),
+ port = server.Port,
+ localAddresses = wg.LocalAddresses.SplitOrDefault(),
+ peerPublicKey = wg.PeerPublicKey,
+ privateKey = wg.PrivateKey,
+ preSharedKey = wg.PreSharedKey,
+ mtu = wg.MTU
+ };
+ break;
+
}
return outbound;
diff --git a/Netch/Servers/V2ray/V2rayController.cs b/Netch/Servers/V2ray/V2rayController.cs
index 3d9fe9b381..007b1f9adc 100644
--- a/Netch/Servers/V2ray/V2rayController.cs
+++ b/Netch/Servers/V2ray/V2rayController.cs
@@ -8,17 +8,17 @@ namespace Netch.Servers;
public class V2rayController : Guard, IServerController
{
- public V2rayController() : base("xray.exe")
+ public V2rayController() : base("v2ray-sn.exe")
{
- if (!Global.Settings.V2RayConfig.XrayCone)
- Instance.StartInfo.Environment["XRAY_CONE_DISABLED"] = "true";
+ //if (!Global.Settings.V2RayConfig.XrayCone)
+ // Instance.StartInfo.Environment["XRAY_CONE_DISABLED"] = "true";
}
protected override IEnumerable StartedKeywords => new[] { "started" };
protected override IEnumerable FailedKeywords => new[] { "config file not readable", "failed to" };
- public override string Name => "Xray";
+ public override string Name => "V2Ray (SagerNet)";
public ushort? Socks5LocalPort { get; set; }
@@ -31,7 +31,7 @@ public virtual async Task StartAsync(Server s)
await JsonSerializer.SerializeAsync(fileStream, await V2rayConfigUtils.GenerateClientConfigAsync(s), Global.NewCustomJsonSerializerOptions());
}
- await StartGuardAsync("-config ..\\data\\last.json");
+ await StartGuardAsync("run -c ..\\data\\last.json");
return new Socks5Server(IPAddress.Loopback.ToString(), this.Socks5LocalPort(), s.Hostname);
}
}
\ No newline at end of file
diff --git a/Netch/Servers/V2ray/V2rayUtils.cs b/Netch/Servers/V2ray/V2rayUtils.cs
index 8ff2f272f4..f3202cc829 100644
--- a/Netch/Servers/V2ray/V2rayUtils.cs
+++ b/Netch/Servers/V2ray/V2rayUtils.cs
@@ -22,6 +22,7 @@ public static IEnumerable ParseVUri(string text)
var parameter = HttpUtility.ParseQueryString(text.Split('?')[1]);
text = text.Substring(0, text.IndexOf("?", StringComparison.Ordinal));
server.TransferProtocol = parameter.Get("type") ?? "tcp";
+ server.PacketEncoding = parameter.Get("packetEncoding") ?? "xudp";
server.EncryptMethod = parameter.Get("encryption") ?? scheme switch { "vless" => "none", _ => "auto" };
switch (server.TransferProtocol)
{
@@ -55,7 +56,7 @@ public static IEnumerable ParseVUri(string text)
{
server.ServerName = parameter.Get("sni") ?? "";
if (server.TLSSecureType == "xtls")
- ((VLESSServer)server).Flow = parameter.Get("flow") ?? "";
+ ((VLESSServer)server).Flow = "xtls-rprx-direct"; // splice doesn't support Windows
}
}
@@ -79,6 +80,7 @@ public static string GetVShareLink(Server s, string scheme = "vmess")
// protocol-specific fields
parameter.Add("type", server.TransferProtocol);
parameter.Add("encryption", server.EncryptMethod);
+ parameter.Add("packetEncoding", server.PacketEncoding);
// transport-specific fields
switch (server.TransferProtocol)
diff --git a/Netch/Servers/VLESS/VLESSForm.cs b/Netch/Servers/VLESS/VLESSForm.cs
index fe8365ab9b..9580a3bf34 100644
--- a/Netch/Servers/VLESS/VLESSForm.cs
+++ b/Netch/Servers/VLESS/VLESSForm.cs
@@ -23,6 +23,11 @@ public VLESSForm(VLESSServer? server = default)
VLESSGlobal.TransferProtocols,
s => server.TransferProtocol = s,
server.TransferProtocol);
+ CreateComboBox("PacketEncoding",
+ "Packet Encoding",
+ VMessGlobal.PacketEncodings,
+ s => server.PacketEncoding = s,
+ server.PacketEncoding);
CreateComboBox("FakeType", "Fake Type", VLESSGlobal.FakeTypes, s => server.FakeType = s, server.FakeType);
CreateTextBox("Host", "Host", s => true, s => server.Host = s, server.Host);
diff --git a/Netch/Servers/VLESS/VLESSServer.cs b/Netch/Servers/VLESS/VLESSServer.cs
index 1ffade12e1..c89ee5a2f8 100644
--- a/Netch/Servers/VLESS/VLESSServer.cs
+++ b/Netch/Servers/VLESS/VLESSServer.cs
@@ -21,7 +21,7 @@ public class VLESSServer : VMessServer
///
///
- public string? Flow { get; set; }
+ public string? Flow { get; set; } = "xtls-rprx-direct";
}
public class VLESSGlobal
diff --git a/Netch/Servers/VMess/VMessForm.cs b/Netch/Servers/VMess/VMessForm.cs
index 956d7ba956..30df79ac63 100644
--- a/Netch/Servers/VMess/VMessForm.cs
+++ b/Netch/Servers/VMess/VMessForm.cs
@@ -18,6 +18,12 @@ public VMessForm(VMessServer? server = default)
VMessGlobal.TransferProtocols,
s => server.TransferProtocol = s,
server.TransferProtocol);
+ CreateComboBox("PacketEncoding",
+ "Packet Encoding",
+ VMessGlobal.PacketEncodings,
+ s => server.PacketEncoding = s,
+ server.PacketEncoding);
+
CreateComboBox("FakeType", "Fake Type", VMessGlobal.FakeTypes, s => server.FakeType = s, server.FakeType);
CreateTextBox("Host", "Host", s => true, s => server.Host = s, server.Host);
diff --git a/Netch/Servers/VMess/VMessServer.cs b/Netch/Servers/VMess/VMessServer.cs
index 4bc9f36a36..500ab6e600 100644
--- a/Netch/Servers/VMess/VMessServer.cs
+++ b/Netch/Servers/VMess/VMessServer.cs
@@ -10,7 +10,7 @@ public class VMessServer : Server
public override string MaskedData()
{
- var maskedData = $"{EncryptMethod} + {TransferProtocol} + {FakeType}";
+ var maskedData = $"{EncryptMethod} + {TransferProtocol} + {PacketEncoding} + {FakeType}";
switch (TransferProtocol)
{
case "tcp":
@@ -49,6 +49,11 @@ public override string MaskedData()
///
public virtual string TransferProtocol { get; set; } = VMessGlobal.TransferProtocols[0];
+ ///
+ /// 包传输格式
+ ///
+ public virtual string PacketEncoding { get; set; } = VMessGlobal.PacketEncodings[2];
+
///
/// 伪装类型
///
@@ -115,6 +120,13 @@ public class VMessGlobal
"chacha20-poly1305"
};
+ public static readonly List PacketEncodings = new()
+ {
+ "none",
+ "packet", // requires v2fly/v2ray-core v5.0.2+ or SagerNet/v2ray-core
+ "xudp" // requires XTLS/Xray-core or SagerNet/v2ray-core
+ };
+
///
/// V2Ray 传输协议
///
diff --git a/Netch/Servers/WireGuard/WireGuardForm.cs b/Netch/Servers/WireGuard/WireGuardForm.cs
new file mode 100644
index 0000000000..1a63a6be7c
--- /dev/null
+++ b/Netch/Servers/WireGuard/WireGuardForm.cs
@@ -0,0 +1,20 @@
+using Netch.Forms;
+
+namespace Netch.Servers;
+
+[Fody.ConfigureAwait(true)]
+public class WireGuardForm : ServerForm
+{
+ public WireGuardForm(WireGuardServer? server = default)
+ {
+ server ??= new WireGuardServer();
+ Server = server;
+ CreateTextBox("LocalAddresses", "Local Addresses", s => true, s => server.LocalAddresses = s, server.LocalAddresses);
+ CreateTextBox("PeerPublicKey", "Public Key", s => true, s => server.PeerPublicKey = s, server.PeerPublicKey);
+ CreateTextBox("PrivateKey", "Private Key", s => true, s => server.PrivateKey = s, server.PrivateKey);
+ CreateTextBox("PreSharedKey", "PSK", s => true, s => server.PreSharedKey = s, server.PreSharedKey);
+ CreateTextBox("MTU", "MTU", s => int.TryParse(s, out _), s => server.MTU = int.Parse(s), server.MTU.ToString(), 76);
+ }
+
+ protected override string TypeName { get; } = "WireGuard";
+}
\ No newline at end of file
diff --git a/Netch/Servers/WireGuard/WireGuardServer.cs b/Netch/Servers/WireGuard/WireGuardServer.cs
new file mode 100644
index 0000000000..7ceb8347f3
--- /dev/null
+++ b/Netch/Servers/WireGuard/WireGuardServer.cs
@@ -0,0 +1,38 @@
+using Netch.Models;
+
+namespace Netch.Servers;
+
+public class WireGuardServer : Server
+{
+ public override string Type { get; } = "WireGuard";
+
+ public override string MaskedData()
+ {
+ return $"{LocalAddresses} + {MTU}";
+ }
+
+ ///
+ /// 本地地址
+ ///
+ public string LocalAddresses { get; set; } = "172.16.0.2";
+
+ ///
+ /// 节点公钥
+ ///
+ public string PeerPublicKey { get; set; } = string.Empty;
+
+ ///
+ /// 私钥
+ ///
+ public string PrivateKey { get; set; }
+
+ ///
+ /// 节点预共享密钥
+ ///
+ public string? PreSharedKey { get; set; }
+
+ ///
+ /// MTU
+ ///
+ public int MTU { get; set; } = 1420;
+}
diff --git a/Netch/Servers/WireGuard/WireGuardUtil.cs b/Netch/Servers/WireGuard/WireGuardUtil.cs
new file mode 100644
index 0000000000..e7bcb4464b
--- /dev/null
+++ b/Netch/Servers/WireGuard/WireGuardUtil.cs
@@ -0,0 +1,53 @@
+using System.Text.Encodings.Web;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Netch.Interfaces;
+using Netch.Models;
+using Netch.Utils;
+
+namespace Netch.Servers;
+
+public class WireGuardUtil : IServerUtil
+{
+ public ushort Priority { get; } = 4;
+
+ public string TypeName { get; } = "WireGuard";
+
+ public string FullName { get; } = "WireGuard";
+
+ public string ShortName { get; } = "WG";
+
+ public string[] UriScheme { get; } = { "wireguard" };
+
+ public Type ServerType { get; } = typeof(WireGuardServer);
+
+ public void Edit(Server s)
+ {
+ new WireGuardForm((WireGuardServer)s).ShowDialog();
+ }
+
+ public void Create()
+ {
+ new WireGuardForm().ShowDialog();
+ }
+
+ public string GetShareLink(Server s)
+ {
+ return V2rayUtils.GetVShareLink(s, "wireguard");
+ }
+
+ public IServerController GetController()
+ {
+ return new V2rayController();
+ }
+
+ public IEnumerable ParseUri(string text)
+ {
+ return V2rayUtils.ParseVUri(text);
+ }
+
+ public bool CheckServer(Server s)
+ {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Other/libev-mingw/build.ps1 b/Other/libev-mingw/build.ps1
deleted file mode 100644
index 6e08551c15..0000000000
--- a/Other/libev-mingw/build.ps1
+++ /dev/null
@@ -1,10 +0,0 @@
-Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
-
-git clone https://github.com/shadowsocks/libev -b 'mingw' src
-if ( -Not $? ) {
- exit $lastExitCode
-}
-Set-Location src
-
-msys2 ..\build.sh
-exit $lastExitCode
\ No newline at end of file
diff --git a/Other/libev-mingw/build.sh b/Other/libev-mingw/build.sh
deleted file mode 100644
index a3c30b9341..0000000000
--- a/Other/libev-mingw/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-mkdir -p "${PWD}/../../build"
-
-./configure --prefix="${PWD}/../../build" || exit $?
-
-make install -j2
-exit $?
\ No newline at end of file
diff --git a/Other/shadowsocks-rust/build.ps1 b/Other/shadowsocks-rust/build.ps1
deleted file mode 100644
index 966dc8b249..0000000000
--- a/Other/shadowsocks-rust/build.ps1
+++ /dev/null
@@ -1,15 +0,0 @@
-Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
-
-git clone https://github.com/shadowsocks/shadowsocks-rust -b 'v1.12.0' src
-if ( -Not $? ) {
- exit $lastExitCode
-}
-Set-Location src
-
-cargo build --features logging,trust-dns,local,utility,local-http,local-tunnel,local-socks4,multi-threaded,stream-cipher --release
-if ( -Not $? ) {
- exit $lastExitCode
-}
-
-cp -Force '.\target\release\sslocal.exe' '..\..\release\Shadowsocks.exe'
-exit 0
\ No newline at end of file
diff --git a/Other/shadowsocksr-libev/build.ps1 b/Other/shadowsocksr-libev/build.ps1
deleted file mode 100644
index 18faea0909..0000000000
--- a/Other/shadowsocksr-libev/build.ps1
+++ /dev/null
@@ -1,15 +0,0 @@
-Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
-
-git clone https://github.com/shadowsocksrr/shadowsocksr-libev -b 'Akkariiin/develop' src
-if ( -Not $? ) {
- exit $lastExitCode
-}
-Set-Location src
-
-msys2 ..\build.sh
-if ( -Not $? ) {
- exit $lastExitCode
-}
-
-cp -Force '.\ss-local.exe' '..\..\release\ShadowsocksR.exe'
-exit 0
diff --git a/Other/shadowsocksr-libev/build.sh b/Other/shadowsocksr-libev/build.sh
deleted file mode 100644
index 8db73f91ab..0000000000
--- a/Other/shadowsocksr-libev/build.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-git submodule update --init || exit $?
-
-cd libudns
-./autogen.sh || exit $?
-./configure || exit $?
-make -j2 || exit $?
-cd ..
-
-./autogen.sh || exit $?
-CFLAGS+="-fstack-protector" ./configure --disable-documentation --with-ev="${PWD}/../../build" || exit $?
-
-sed -i "s/%I/%z/g" src/utils.h
-sed -i "s/^const/extern const/g" src/tls.h
-sed -i "s/^const/extern const/g" src/http.h
-
-make -j2 || exit $?
-
-gcc $(find src/ -name "ss_local-*.o") $(find . -name "*.a" ! -name "*.dll.a") "${PWD}/../../build/lib/libev.a" -o ss-local -fstack-protector -static -lpcre -lssl -lcrypto -lws2_32 -s
-exit $?
\ No newline at end of file
diff --git a/Other/simple-obfs/build.ps1 b/Other/simple-obfs/build.ps1
deleted file mode 100644
index 9ecb5aefd1..0000000000
--- a/Other/simple-obfs/build.ps1
+++ /dev/null
@@ -1,15 +0,0 @@
-Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
-
-git clone https://github.com/shadowsocks/simple-obfs src
-if ( -Not $? ) {
- exit $lastExitCode
-}
-Set-Location src
-
-msys2 ..\build.sh
-if ( -Not $? ) {
- exit $lastExitCode
-}
-
-cp -Force '.\obfs-local.exe' '..\..\release\simple-obfs.exe'
-exit 0
\ No newline at end of file
diff --git a/Other/simple-obfs/build.sh b/Other/simple-obfs/build.sh
deleted file mode 100644
index ff1833aa02..0000000000
--- a/Other/simple-obfs/build.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-git submodule update --init || exit $?
-
-./autogen.sh || exit $?
-./configure --disable-documentation --with-ev="${PWD}/../../build" || exit $?
-
-make -j2 || exit $?
-
-gcc $(find src/ -name "obfs_local-*.o") $(find . -name "*.a" ! -name "*.dll.a") "${PWD}/../../build/lib/libev.a" -o obfs-local -fstack-protector -static -lws2_32 -s
-exit $?
\ No newline at end of file
diff --git a/Other/trojan-go/build.ps1 b/Other/trojan-go/build.ps1
deleted file mode 100644
index 4544e44e5c..0000000000
--- a/Other/trojan-go/build.ps1
+++ /dev/null
@@ -1,15 +0,0 @@
-Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
-
-git clone https://github.com/p4gefau1t/trojan-go -b 'v0.10.6' src
-if ( -Not $? ) {
- exit $lastExitCode
-}
-Set-Location src
-
-$Env:CGO_ENABLED='0'
-$Env:GOROOT_FINAL='/usr'
-
-$Env:GOOS='windows'
-$Env:GOARCH='amd64'
-go build -a -trimpath -asmflags '-s -w' -ldflags '-s -w' -tags 'full' -o '..\..\release\Trojan.exe'
-exit $lastExitCode
\ No newline at end of file
diff --git a/Other/v2ray-sn/README.md b/Other/v2ray-sn/README.md
new file mode 100644
index 0000000000..8615db2c7a
--- /dev/null
+++ b/Other/v2ray-sn/README.md
@@ -0,0 +1,56 @@
+# Project V for SagerNet for Netch
+This is not a joke.
+Modified from [SagerNet/v2ray-core](https://github.com/SagerNet/v2ray-core).
+#### Extends all features of SagerNet/v2ray-core
+
+### Changes
+
+- embed ShadowsocksR plugin for shadowsocks
+
+```json
+{
+ "outbounds": [
+ {
+ "protocol": "shadowsocks",
+ "settings": {
+ ...
+ "plugin": "shadowsocksr",
+ "pluginArgs": [
+ "--obfs=",
+ "--obfs-param=",
+ "--protocol=",
+ "--protocol-param="
+ ]
+ }
+ }
+ ]
+}
+```
+
+- embed simple-obfs plugin for shadowsocks
+
+```json
+{
+ "outbounds": [
+ {
+ "protocol": "shadowsocks",
+ "settings": {
+ ...
+ "plugin": "obfs-local",
+ "pluginOpts": ""
+ }
+ }
+ ]
+}
+```
+
+- Re-enable ReadV
+
+### License
+
+GPL v3
+
+### Credits
+
+This repo relies on the following projects:
+- [SagerNet/LibSagerNetCore](https://github.com/SagerNet/LibSagerNetCore)
diff --git a/Other/v2ray-sn/build.ps1 b/Other/v2ray-sn/build.ps1
new file mode 100644
index 0000000000..4059c40063
--- /dev/null
+++ b/Other/v2ray-sn/build.ps1
@@ -0,0 +1,28 @@
+Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
+
+git clone https://github.com/SagerNet/v2ray-core.git -b 'v5.0.14' src
+if ( -Not $? ) {
+ exit $lastExitCode
+}
+Set-Location src
+
+# Download SSR plugin
+Invoke-WebRequest -Uri 'https://gist.githubusercontent.com/H1JK/b3165a99b635dcc06101690e4c43b5fd/raw/691b471f3b395a949d03a3d064d93d319d4997b7/ssr.go' -OutFile '.\proxy\shadowsocks\plugin\self\ssr.go'
+
+# Download Simple-Obfs plugin
+Invoke-WebRequest -Uri 'https://gist.githubusercontent.com/H1JK/b3165a99b635dcc06101690e4c43b5fd/raw/691b471f3b395a949d03a3d064d93d319d4997b7/obfs.go' -OutFile '.\proxy\shadowsocks\plugin\self\obfs.go'
+
+# Enable ReadV (Use old ReadV code)
+Remove-Item '.\common\buf\io.go'
+Remove-Item '.\common\buf\readv_reader.go'
+Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/SagerNet/v2ray-core/2711fd1/common/buf/io.go' -OutFile '.\common\buf\io.go'
+Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/SagerNet/v2ray-core/2711fd1/common/buf/readv_reader.go' -OutFile '.\common\buf\readv_reader.go'
+
+$Env:CGO_ENABLED='0'
+$Env:GOROOT_FINAL='/usr'
+
+$Env:GOOS='windows'
+$Env:GOARCH='amd64'
+go mod tidy # necessary
+go build -a -trimpath -asmflags '-s -w' -ldflags '-s -w -buildid=' -o '..\..\release\v2ray-sn.exe' '.\main'
+exit $lastExitCode
\ No newline at end of file
diff --git a/Other/xray-core/build.ps1 b/Other/xray-core/build.ps1
deleted file mode 100644
index 9cf04d7693..0000000000
--- a/Other/xray-core/build.ps1
+++ /dev/null
@@ -1,15 +0,0 @@
-Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
-
-git clone https://github.com/xtls/xray-core -b 'v1.4.5' src
-if ( -Not $? ) {
- exit $lastExitCode
-}
-Set-Location src
-
-$Env:CGO_ENABLED='0'
-$Env:GOROOT_FINAL='/usr'
-
-$Env:GOOS='windows'
-$Env:GOARCH='amd64'
-go build -a -trimpath -asmflags '-s -w' -ldflags '-s -w -buildid=' -o '..\..\release\xray.exe' '.\main'
-exit $lastExitCode
\ No newline at end of file
diff --git a/Other/xray-plugin/build.ps1 b/Other/xray-plugin/build.ps1
deleted file mode 100644
index 7b50b31af8..0000000000
--- a/Other/xray-plugin/build.ps1
+++ /dev/null
@@ -1,15 +0,0 @@
-Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent)
-
-git clone https://github.com/teddysun/xray-plugin -b 'v1.4.5' src
-if ( -Not $? ) {
- exit $lastExitCode
-}
-Set-Location src
-
-$Env:CGO_ENABLED='0'
-$Env:GOROOT_FINAL='/usr'
-
-$Env:GOOS='windows'
-$Env:GOARCH='amd64'
-go build -a -trimpath -asmflags '-s -w' -ldflags '-s -w' -o '..\..\release\xray-plugin.exe'
-exit $lastExitCode
\ No newline at end of file
diff --git a/README.md b/README.md
index 48cb6c4cb8..a8be2dd2e8 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Some features may not be implemented in version 1
- [`WireGuard`](https://www.wireguard.com)
- [`Trojan`](https://trojan-gfw.github.io/trojan)
- [`VMess`](https://www.v2fly.org)
-- [`VLess`](https://xtls.github.io)
+- [`VLESS`](https://xtls.github.io)
### Others
- UDP NAT FullCone (Limited by your server)
diff --git a/Storage/GeoLite2-Country.mmdb b/Storage/GeoLite2-Country.mmdb
deleted file mode 100644
index 578ac8db4c..0000000000
Binary files a/Storage/GeoLite2-Country.mmdb and /dev/null differ
diff --git a/build.ps1 b/build.ps1
index 4930262bef..d67d014ce8 100644
--- a/build.ps1
+++ b/build.ps1
@@ -36,7 +36,8 @@ cp -Recurse -Force '..\Storage\mode' '.' | Out-Null
cp -Recurse -Force '..\Storage\stun.txt' 'bin' | Out-Null
cp -Recurse -Force '..\Storage\nfdriver.sys' 'bin' | Out-Null
cp -Recurse -Force '..\Storage\aiodns.conf' 'bin' | Out-Null
-cp -Recurse -Force '..\Storage\GeoLite2-Country.mmdb' 'bin' | Out-Null
+Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb' -OutFile 'bin\GeoLite2-Country.mmdb'
+#cp -Recurse -Force '..\Storage\GeoLite2-Country.mmdb' 'bin' | Out-Null
cp -Recurse -Force '..\Storage\tun2socks.bin' 'bin' | Out-Null
cp -Recurse -Force '..\Storage\README.md' 'bin' | Out-Null
Pop-Location
@@ -59,7 +60,7 @@ if ( -Not ( Test-Path ".\Netch\bin\$Configuration" ) ) {
-c $Configuration `
-r 'win-x64' `
-p:Platform='x64' `
- -p:SelfContained=$SelfContained `
+ -p:SelfContained=$False `
-p:PublishTrimmed=$PublishReadyToRun `
-p:PublishSingleFile=$PublishSingleFile `
-p:PublishReadyToRun=$PublishReadyToRun `