[Netch] Add SSH protocol support (#875)

* [Netch] Optimize code

* [Netch] Add SSH protocol support
This commit is contained in:
Hellojack
2022-07-12 01:47:23 +08:00
committed by GitHub
parent 5580969d16
commit 77e1d5a80c
6 changed files with 170 additions and 50 deletions

View File

@@ -47,6 +47,7 @@
"Address": "地址", "Address": "地址",
"Username": "用户名", "Username": "用户名",
"User": "用户",
"Password": "密码", "Password": "密码",
"Version": "版本", "Version": "版本",
"User ID": "用户 ID", "User ID": "用户 ID",
@@ -71,7 +72,7 @@
"Plugin Options": "插件参数", "Plugin Options": "插件参数",
"Remote Address": "远端地址", "Remote Address": "远端地址",
"Local Addresses": "本地地址(可多个)", "Local Addresses": "本地地址(可多个)",
"Public Key": "节点公钥", "Public Key": "公钥",
"Private Key": "私钥", "Private Key": "私钥",
"PSK": "节点预共享密钥", "PSK": "节点预共享密钥",

View File

@@ -0,0 +1,19 @@
using Netch.Forms;
namespace Netch.Servers;
[Fody.ConfigureAwait(true)]
public class SSHForm : ServerForm
{
public SSHForm(SSHServer? server = default)
{
server ??= new SSHServer();
Server = server;
CreateTextBox("User", "User", s => true, s => server.User = s, server.User);
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
CreateTextBox("PrivateKey", "Private Key", s => true, s => server.PrivateKey = s, server.PrivateKey);
CreateTextBox("PublicKey", "Public Key", s => true, s => server.PublicKey = s, server.PublicKey);
}
protected override string TypeName { get; } = "SSH";
}

View File

@@ -0,0 +1,33 @@
using Netch.Models;
namespace Netch.Servers;
public class SSHServer : Server
{
public override string Type { get; } = "SSH";
public override string MaskedData()
{
return $"{User}";
}
/// <summary>
/// 用户
/// </summary>
public string User { get; set; } = "root";
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; } = string.Empty;
/// <summary>
/// 私钥
/// </summary>
public string PrivateKey { get; set; }
/// <summary>
/// 主机公钥
/// </summary>
public string? PublicKey { get; set; }
}

View File

@@ -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 SSHUtil : IServerUtil
{
public ushort Priority { get; } = 4;
public string TypeName { get; } = "SSH";
public string FullName { get; } = "SSH";
public string ShortName { get; } = "SSH";
public string[] UriScheme { get; } = { "ssh" };
public Type ServerType { get; } = typeof(SSHServer);
public void Edit(Server s)
{
new SSHForm((SSHServer)s).ShowDialog();
}
public void Create()
{
new SSHForm().ShowDialog();
}
public string GetShareLink(Server s)
{
return V2rayUtils.GetVShareLink(s, "ssh");
}
public IServerController GetController()
{
return new V2rayController();
}
public IEnumerable<Server> ParseUri(string text)
{
return V2rayUtils.ParseVUri(text);
}
public bool CheckServer(Server s)
{
return true;
}
}

View File

@@ -44,8 +44,12 @@ public class OutboundConfiguration
public string address { get; set; } public string address { get; set; }
public string user { get; set; }
public ushort port { get; set; } public ushort port { get; set; }
public string password { get; set; }
public string packetEncoding { get; set; } public string packetEncoding { get; set; }
public string plugin { get; set; } public string plugin { get; set; }
@@ -58,6 +62,8 @@ public class OutboundConfiguration
public string peerPublicKey { get; set; } public string peerPublicKey { get; set; }
public string publicKey { get; set; }
public string privateKey { get; set; } public string privateKey { get; set; }
public string preSharedKey { get; set; } public string preSharedKey { get; set; }

View File

@@ -145,21 +145,18 @@ public static class V2rayConfigUtils
} }
case ShadowsocksServer ss: case ShadowsocksServer ss:
outbound.protocol = "shadowsocks"; outbound.protocol = "shadowsocks";
outbound.settings = new OutboundConfiguration outbound.settings.servers = new[]
{ {
servers = new[] new ShadowsocksServerItem
{ {
new ShadowsocksServerItem address = await server.AutoResolveHostnameAsync(),
{ port = server.Port,
address = await server.AutoResolveHostnameAsync(), method = ss.EncryptMethod,
port = server.Port, password = ss.Password
method = ss.EncryptMethod, }
password = ss.Password,
}
},
plugin = ss.Plugin ?? "",
pluginOpts = ss.PluginOption ?? ""
}; };
outbound.settings.plugin = ss.Plugin ?? "";
outbound.settings.pluginOpts = ss.PluginOption ?? "";
if (Global.Settings.V2RayConfig.TCPFastOpen) if (Global.Settings.V2RayConfig.TCPFastOpen)
{ {
@@ -174,27 +171,24 @@ public static class V2rayConfigUtils
break; break;
case ShadowsocksRServer ssr: case ShadowsocksRServer ssr:
outbound.protocol = "shadowsocks"; outbound.protocol = "shadowsocks";
outbound.settings = new OutboundConfiguration outbound.settings.servers = new[]
{ {
servers = new[] new ShadowsocksServerItem
{ {
new ShadowsocksServerItem address = await server.AutoResolveHostnameAsync(),
{ port = server.Port,
address = await server.AutoResolveHostnameAsync(), method = ssr.EncryptMethod,
port = server.Port, password = ssr.Password,
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 ?? ""
} }
}; };
outbound.settings.plugin = "shadowsocksr";
outbound.settings.pluginArgs = new string[]
{
"--obfs=" + ssr.OBFS,
"--obfs-param=" + ssr.OBFSParam ?? "",
"--protocol=" + ssr.Protocol,
"--protocol-param=" + ssr.ProtocolParam ?? ""
};
if (Global.Settings.V2RayConfig.TCPFastOpen) if (Global.Settings.V2RayConfig.TCPFastOpen)
{ {
@@ -209,18 +203,15 @@ public static class V2rayConfigUtils
break; break;
case TrojanServer trojan: case TrojanServer trojan:
outbound.protocol = "trojan"; outbound.protocol = "trojan";
outbound.settings = new OutboundConfiguration outbound.settings.servers = new[]
{ {
servers = new[] new ShadowsocksServerItem // I'm not serious
{ {
new ShadowsocksServerItem // I'm not serious address = await server.AutoResolveHostnameAsync(),
{ port = server.Port,
address = await server.AutoResolveHostnameAsync(), method = "",
port = server.Port, password = trojan.Password,
method = "", flow = trojan.TLSSecureType == "xtls" ? "xtls-rprx-direct" : ""
password = trojan.Password,
flow = trojan.TLSSecureType == "xtls" ? "xtls-rprx-direct" : ""
}
} }
}; };
@@ -258,16 +249,13 @@ public static class V2rayConfigUtils
break; break;
case WireGuardServer wg: case WireGuardServer wg:
outbound.protocol = "wireguard"; outbound.protocol = "wireguard";
outbound.settings = new OutboundConfiguration outbound.settings.address = await server.AutoResolveHostnameAsync();
{ outbound.settings.port = server.Port;
address = await server.AutoResolveHostnameAsync(), outbound.settings.localAddresses = wg.LocalAddresses.SplitOrDefault();
port = server.Port, outbound.settings.peerPublicKey = wg.PeerPublicKey;
localAddresses = wg.LocalAddresses.SplitOrDefault(), outbound.settings.privateKey = wg.PrivateKey;
peerPublicKey = wg.PeerPublicKey, outbound.settings.preSharedKey = wg.PreSharedKey;
privateKey = wg.PrivateKey, outbound.settings.mtu = wg.MTU;
preSharedKey = wg.PreSharedKey,
mtu = wg.MTU
};
if (Global.Settings.V2RayConfig.TCPFastOpen) if (Global.Settings.V2RayConfig.TCPFastOpen)
{ {
@@ -281,6 +269,26 @@ public static class V2rayConfigUtils
} }
break; break;
case SSHServer ssh:
outbound.protocol = "ssh";
outbound.settings.address = await server.AutoResolveHostnameAsync();
outbound.settings.port = server.Port;
outbound.settings.user = ssh.User;
outbound.settings.password = ssh.Password;
outbound.settings.privateKey = ssh.PrivateKey;
outbound.settings.publicKey = ssh.PublicKey;
if (Global.Settings.V2RayConfig.TCPFastOpen)
{
outbound.streamSettings = new StreamSettings
{
sockopt = new Sockopt
{
tcpFastOpen = true
}
};
}
break;
} }
return outbound; return outbound;