C# 多跳 SSH(SSH 通过 SSH)
C# multi-hop SSH (SSH through SSH)
我编写了一个 C# 控制台程序,通过 SSH 从 A(Windows 10,控制台 C# 应用程序)连接到 B(Linux 服务器),然后从那里连接到 C(Linux 服务器),但我无法从 B 连接到 C(从 A 到 B 可以)。
当我通过 Windows 终端从 A 连接到 B 以及从 B 的终端连接到 C 时,它工作正常,所以我证明我的凭据没问题。
我正在为 C# 使用 Renci.SshNet
我用 .Connect()
、.Disconnect()
和 .Execute()
扩展方法创建了 class Server
,然后是两个 class 个实例 Broker
和 Destination
我的代码如下:
if (Broker.Connect())
{
Broker.Execute("pwd");
if (Destination.Connect())
{
Destination.Execute("pwd");
Destination.Disconnect();
}
Broker.Disconnect();
}
Ssh
连接对象的创建类似于 var broker = new SftpClient("Ip", Port, "User", "Pass")
然后我在内部使用 broker.Connect()
和 broker.Disconnect()
在 Renci.Ssh.Net
lib given methods
要broker.Execute("cmd")
我基本都这样
var output = host.Ssh.RunCommand(str);
var res0 = output.ExitStatus;
var res1 = output.Result;
var res2 = output.Error;
我的代码适用于第一部分,因为我设法获得了 Broker.Execute("pwd")
的输出,但它没有在 Destination.Connect()
上连接并返回消息 A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
我的目标是使用 C# 中的自动化进程进行多跳:用户 不得 与任何控制台交互,我 不能 修改或存储 Linux 站点上的任何文件
知道问题出在哪里吗?
提前致谢,
我想在这里总结一下我是如何借助从网上和@jeb 收集的一些有价值的提示来解决这个问题的:
打开一个cmd.exe控制台,输入ssh userC@hostC -p portC-J userB@hostB - p portB
(portB
和portC
可以省略,如果它们是默认端口22)然后你会被提示依次输入 passwordB
和 passwordC
。
如果连接成功,您将进入 hostC
控制台,并设法执行您想要执行的任何操作。
您需要的代码是:
static void RunSshHop(params string[] cmds)
{
try
{
using (Process p = new Process())
{
p.StartInfo = new ProcessStartInfo("cmd.exe")
{
RedirectStandardInput = true,
UseShellExecute = false,
//WorkingDirectory = @"d:\" // dir of your "cmd.exe"
};
p.OutputDataReceived += p_DataReceived;
p.ErrorDataReceived += p_DataReceived;
p.Start();
// way 1: works
foreach (var e in cmds)
p.StandardInput.Write($"{e}\n"); // cannot use 'WriteLine' because Windows is '\r' and Linux is '\n'
/* way 2: works as well
using (var sw = p.StandardInput)
{
foreach (var e in cmds)
if (sw.BaseStream.CanWrite)
sw.Write($"{e}\n"); // cannot use 'WriteLine' because Windows is '\r' and Linux is '\n'
}
//*/
p.WaitForExit();
if (p.HasExited)
{
Console.WriteLine($"ExitCode: {p.ExitCode}");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
你可以这样称呼它:
static void Main(string[] args)
{
RunSshHop(
"ssh userC@hostC -p portC-J userB@hostB - p portB",
"pwd",
//"...",
"ls"
);
}
为避免为每个主机输入密码,您还可以创建一个 SSH 密钥对,如下所示:
- 打开
cmd.exe
控制台
- 输入
ssh-keygen -t rsa
- 选择要生成的 public 和私钥的保存路径(按
enter
使用默认目标)
- 复制目的地,稍后您将需要它来取回您的密钥:-)
- 要管理自动化流程,您必须将
passphrase
留空
- 生成密钥后,通过 ssh 登录第一台主机,例如 ssh youruser@firsthost -p hostport
(如果端口是默认端口 22
,则 -p hostport
部分可以忽略)
- 输入
ssh-copy-id youruser@firsthost -p hostport
- 接受
- 为第二个主机重复该过程
我编写了一个 C# 控制台程序,通过 SSH 从 A(Windows 10,控制台 C# 应用程序)连接到 B(Linux 服务器),然后从那里连接到 C(Linux 服务器),但我无法从 B 连接到 C(从 A 到 B 可以)。 当我通过 Windows 终端从 A 连接到 B 以及从 B 的终端连接到 C 时,它工作正常,所以我证明我的凭据没问题。
我正在为 C# 使用 Renci.SshNet
我用
.Connect()
、.Disconnect()
和.Execute()
扩展方法创建了 classServer
,然后是两个 class 个实例Broker
和Destination
我的代码如下:
if (Broker.Connect()) { Broker.Execute("pwd"); if (Destination.Connect()) { Destination.Execute("pwd"); Destination.Disconnect(); } Broker.Disconnect(); }
Ssh
连接对象的创建类似于var broker = new SftpClient("Ip", Port, "User", "Pass")
然后我在内部使用
broker.Connect()
和broker.Disconnect()
在Renci.Ssh.Net
lib given methods要
broker.Execute("cmd")
我基本都这样var output = host.Ssh.RunCommand(str); var res0 = output.ExitStatus; var res1 = output.Result; var res2 = output.Error;
我的代码适用于第一部分,因为我设法获得了
Broker.Execute("pwd")
的输出,但它没有在Destination.Connect()
上连接并返回消息A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
我的目标是使用 C# 中的自动化进程进行多跳:用户 不得 与任何控制台交互,我 不能 修改或存储 Linux 站点上的任何文件
知道问题出在哪里吗?
提前致谢,
我想在这里总结一下我是如何借助从网上和@jeb 收集的一些有价值的提示来解决这个问题的:
打开一个cmd.exe控制台,输入ssh userC@hostC -p portC-J userB@hostB - p portB
(portB
和portC
可以省略,如果它们是默认端口22)然后你会被提示依次输入 passwordB
和 passwordC
。
如果连接成功,您将进入 hostC
控制台,并设法执行您想要执行的任何操作。
您需要的代码是:
static void RunSshHop(params string[] cmds)
{
try
{
using (Process p = new Process())
{
p.StartInfo = new ProcessStartInfo("cmd.exe")
{
RedirectStandardInput = true,
UseShellExecute = false,
//WorkingDirectory = @"d:\" // dir of your "cmd.exe"
};
p.OutputDataReceived += p_DataReceived;
p.ErrorDataReceived += p_DataReceived;
p.Start();
// way 1: works
foreach (var e in cmds)
p.StandardInput.Write($"{e}\n"); // cannot use 'WriteLine' because Windows is '\r' and Linux is '\n'
/* way 2: works as well
using (var sw = p.StandardInput)
{
foreach (var e in cmds)
if (sw.BaseStream.CanWrite)
sw.Write($"{e}\n"); // cannot use 'WriteLine' because Windows is '\r' and Linux is '\n'
}
//*/
p.WaitForExit();
if (p.HasExited)
{
Console.WriteLine($"ExitCode: {p.ExitCode}");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
你可以这样称呼它:
static void Main(string[] args)
{
RunSshHop(
"ssh userC@hostC -p portC-J userB@hostB - p portB",
"pwd",
//"...",
"ls"
);
}
为避免为每个主机输入密码,您还可以创建一个 SSH 密钥对,如下所示:
- 打开
cmd.exe
控制台 - 输入
ssh-keygen -t rsa
- 选择要生成的 public 和私钥的保存路径(按
enter
使用默认目标) - 复制目的地,稍后您将需要它来取回您的密钥:-)
- 要管理自动化流程,您必须将
passphrase
留空 - 生成密钥后,通过 ssh 登录第一台主机,例如ssh youruser@firsthost -p hostport
(如果端口是默认端口22
,则-p hostport
部分可以忽略) - 输入
ssh-copy-id youruser@firsthost -p hostport
- 接受
- 为第二个主机重复该过程