mirror of
https://github.com/netchx/netch.git
synced 2026-03-14 17:43:18 +08:00
[Netch] Add SSH protocol support (#875)
* [Netch] Optimize code * [Netch] Add SSH protocol support
This commit is contained in:
@@ -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": "节点预共享密钥",
|
||||||
|
|
||||||
|
|||||||
19
Netch/Servers/SSH/SSHForm.cs
Normal file
19
Netch/Servers/SSH/SSHForm.cs
Normal 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";
|
||||||
|
}
|
||||||
33
Netch/Servers/SSH/SSHServer.cs
Normal file
33
Netch/Servers/SSH/SSHServer.cs
Normal 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; }
|
||||||
|
}
|
||||||
53
Netch/Servers/SSH/SSHUtil.cs
Normal file
53
Netch/Servers/SSH/SSHUtil.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user