【问题标题】:Opening SSH tunnel in C# in background在后台在 C# 中打开 SSH 隧道
【发布时间】:2016-01-15 19:06:40
【问题描述】:

尝试在127.0.0.1:9999 上打开 SSH 隧道时,我在 C# 中遇到问题。

这是我的Program.cs

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Begin");

        PlinkTest plink = new PlinkTest();

        String feedback = plink.CreateTunnel("1.2.3.4", "user", "user");

        Console.WriteLine("THING:" + feedback);

        Console.Read();
    }
}

这是我的程序,PlinkTest.cs:

class PlinkTest
{
    String PATH_TO_PLINK = @"C:\plink\plink.exe";
    public PlinkTest()
    {
    }

    public string RequestInfo(string remoteHost, string userName, string password, string[] lstCommands)
    {
        m_szFeedback = "Feedback from: " + remoteHost + "\r\n";

       //  ProcessStartInfo psi = new ProcessStartInfo("echo y | C:\\plink\\plink.exe")
        ProcessStartInfo psi = new ProcessStartInfo("C:\\plink\\plink.exe")
        {
            Arguments = String.Format("-ssh -N -D 9999 user@1.2.3.4 -pw user -v"),
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            RedirectStandardInput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        Process p = Process.Start(psi);

        m_objLock = new Object();
        m_blnDoRead = true;

        AsyncReadFeedback(p.StandardOutput); // start the async read of stdout
        AsyncReadFeedback(p.StandardError); // start the async read of stderr

        StreamWriter strw = p.StandardInput;

        foreach (string cmd in lstCommands)
        {
            strw.WriteLine(cmd); // send commands 
        }
        strw.WriteLine("exit"); // send exit command at the end

        p.WaitForExit(); // block thread until remote operations are done
        return m_szFeedback;
    }


    public string CreateTunnel(string remoteHost, string userName, string password)
    {
        m_szFeedback = "Feedback from: " + remoteHost + "\r\n";

        //  ProcessStartInfo psi = new ProcessStartInfo("echo y | C:\\plink\\plink.exe")
        ProcessStartInfo psi = new ProcessStartInfo(PATH_TO_PLINK)
        {
            Arguments = String.Format("-ssh -N -D 9999 user@1.2.3.4 -pw user -v"),
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            RedirectStandardInput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        Process p = Process.Start(psi);

        m_objLock = new Object();
        m_blnDoRead = true;

        AsyncReadFeedback(p.StandardOutput); // start the async read of stdout
        AsyncReadFeedback(p.StandardError); // start the async read of stderr

        StreamWriter strw = p.StandardInput;


        // SLEEP HERE 10 SEC

        strw.WriteLine("exit"); // send exit command at the end

        p.WaitForExit(); // block thread until remote operations are done
        return m_szFeedback;
    }


    private String m_szFeedback; // hold feedback data
    private Object m_objLock; // lock object
    private Boolean m_blnDoRead; // boolean value keeping up the read (may be used to interrupt the reading process)

    public void AsyncReadFeedback(StreamReader strr)
    {
        Thread trdr = new Thread(new ParameterizedThreadStart(__ctReadFeedback));
        trdr.Start(strr);
    }
    private void __ctReadFeedback(Object objStreamReader)
    {
        StreamReader strr = (StreamReader)objStreamReader;
        string line;
        while (!strr.EndOfStream && m_blnDoRead)
        {
            line = strr.ReadLine();
            // lock the feedback buffer (since we don't want some messy stdout/err mix string in the end)
            lock (m_objLock) { m_szFeedback += line + "\r\n"; }
        }
    }
}

第一个问题

我面临的第一个问题是自动接受 RSA 密钥,我可以运行

echo y |plink.exe -ssh -N -D 9999 user@1.2.3.4 -pw user -v

但事实证明,当我在Process p = Process.Start(psi); 行使用echo y | 时出现错误,其中psi 变量是可以的。我知道如何在 Arguments = String.Format("-ssh -N -D 9999 user@1.2.3.4 -pw user -v"), 之后放置参数,但我不知道如何将它们放在命令前面。

第二个问题

第二个问题是我不想等待内容,因为当我创建隧道时它什么也没说,只是在等待。我只想在127.0.0.1:9999的后台打开一个SSH隧道,仅此而已。

我需要改变什么?

谢谢。

【问题讨论】:

  • 我会说这不是 C# 问题,这是使用 plink.exe 的问题。您可能想从文件中读取yplink blabla < yes.txt。由于您已经从为 plink 打开的流中读取,您可能会考虑将 y 写入它,因为 echo y | 有效地做同样的事情。
  • 真的吗?它将与plink blabla < yes.txt hmm 一起使用,必须尝试,我在 linux 中使用了很多 :))

标签: c# ssh public-key ssh-tunnel


【解决方案1】:
  1. 要验证 SSH 主机密钥,请使用 -hostkey switch。不要尝试跳过主机密钥验证。它可以保护您免受man-in-the-middle attacks 的侵害。

    Arguments = String.Format("-ssh -N -D 9999 user@1.2.3.4 -pw user -v -hostkey aa:bb:cc:dd:..."),
    

    无论如何,您的管道语法不能单独工作,因为它是 cmd.exe 只能理解它,所以您必须像这样运行它:

    ProcessStartInfo psi = new ProcessStartInfo("cmd.exe")
    {
        Arguments = String.Format("/C echo y | C:\\plink\\plink.exe -ssh -N -D 9999 user@1.2.3.4 -pw user -v"),
    }
    

    但同样,不要这样做!

  2. 我不想等待内容

所以,不要等待。

我们不知道,你申请的目的是什么。

如果只是为了打开隧道,那么让它无限期地等待(按键?),以保持隧道打开。

如果应用程序要使用隧道,那么只需继续其他任务,不要关闭 SSH 会话。


您最好使用本机 .NET SSH 库作为隧道,然后使用外部应用程序。

例如SSH.NET。见.NET SSH Port Forwarding

【讨论】:

  • 感谢您的完整回答,我真的很感激。我也感谢您有时间更正我的帖子,再次感谢您。现在我有一些东西要补充。 1-> 不知道-hostkeyplink.exe .. 抱歉,我可以把所有东西都放在那里吗?或者我必须生成一个特殊的?或者我必须从我的电脑的某个地方获取它? 2->我居然解决了,请看pastebin.com/ChzAu82E,你怎么看? 3-> 你会推荐我什么,puttySSH.NET?我有点喜欢plink,我相信它更快更稳定...
  • 1) 您将主机密钥指纹放在-hostkey 之后,例如-hostkey aa:bb:cc:dd...。 2) 你特别解决了什么问题?如何? 3) 当然是 SSH.NET。使用未记录的界面自动化外部控制台应用程序不是任何事情的可靠解决方案。
  • 不客气。虽然在 StackOverflow 我们thank by accepting the answer.
  • 1) 您将主机密钥指纹放在-hostkey 之后,例如-hostkey aa:bb:cc:dd...。 2) 你特别解决了什么问题?如何? 3) 当然是 SSH.NET。使用未记录的界面自动化外部控制台应用程序不是任何事情的可靠解决方案。
【解决方案2】:

显然,在您的场景中无法使用 echo 进行 io 重定向。

尝试使用您已有的strw.WriteLine(...);y 发送到plink,或者创建一个yes.txt 文件,在其中放置一个y 并让plink 使用plink < yes.txt 读取其内容。

plinks manual page 的快速扫描显示没有参数可以让您指定“全是模式”。

【讨论】:

  • 所以你可以在StreamWriter strw = p.StandardInput; 后面加上strw.WriteLine("y"); 行吗?可以吗?
  • 你可以试试,如果失败了不会杀死任何动物;-)
  • 相信我,我试过all-yes mode ...它在plink的最新版本中不可用
  • 问题是我必须以某种方式删除实际的RSA KEY 以引发“你想......缓存......(y / n)”的问题......和我现在还没有,不过我会试一试......
  • 当我登录服务器时我没有使用它,我只使用putty 但我只想创建一个隧道,即使我给你 1.2.3.4 用户用户你也不能做任何事情有了它,因为它没有附加外壳,它只是隧道,仅此而已,所以不需要没有“全是模式”。现在明白了?无论如何,我已经解决了这里的问题是链接pastebin.com/ChzAu82E ...您对此有何看法?没关系?不得不承认,你帮了我很多,谢谢!
【解决方案3】:

只需执行此代码 ....它将获取缓存键... string sPlinkPath = @" ""C:\Program Files (x86)\PuTTY\plink.exe"" ";

        string sCommandToStoreKeyInCach = "echo y |"+ sPlinkPath + clsGlobalVariables.sIpAdd + " -pw XXXX exit";

        Process GetCpuInfo = new Process();

        // Redirect the output stream of the child process.
        GetCpuInfo.StartInfo.UseShellExecute = false;
        GetCpuInfo.StartInfo.RedirectStandardInput = true;
        GetCpuInfo.StartInfo.RedirectStandardOutput = true;
        GetCpuInfo.StartInfo.RedirectStandardError = true;

        GetCpuInfo.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
        GetCpuInfo.StartInfo.Arguments = "/c " + sCommandToStoreKeyInCach;

        GetCpuInfo.StartInfo.CreateNoWindow = true;
        GetCpuInfo.Start();

        GetCpuInfo.WaitForExit();

如果这不起作用...请告诉我...

【讨论】:

    猜你喜欢
    • 2016-10-25
    • 2016-02-17
    • 2017-07-10
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 2015-02-17
    • 1970-01-01
    相关资源
    最近更新 更多