Открытие SSH-туннеля в C# в фоновом режиме

У меня проблема в C# при попытке открыть туннель SSH на 127.0.0.1:9999.

Это мой 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 [email protected] -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 [email protected] -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 [email protected] -pw user -v

но оказывается, что я получаю сообщение об ошибке, когда использую echo y | в строке Process p = Process.Start(psi);, где переменная psi в порядке. Я знаю, как поставить аргументы после Arguments = String.Format("-ssh -N -D 9999 [email protected] -pw user -v"),, но я не знаю, как поставить их перед командой.

ВТОРАЯ ПРОБЛЕМА

Вторая проблема заключается в том, что я не хочу ждать контента, потому что когда я создаю туннель, он ничего не говорит, просто ждет. Я просто хочу открыть туннель SSH в фоновом режиме на 127.0.0.1:9999, вот и все.

Что мне нужно изменить?

Спасибо.


person Fitman    schedule 16.10.2015    source источник
comment
Я бы сказал, что это не проблема C#, это проблема с использованием plink.exe. Вы можете прочитать y из файла: plink blabla < yes.txt. Поскольку вы уже читаете из потока, открытого для plink, вы можете рассмотреть возможность записи в него y, потому что echo y | фактически делает то же самое.   -  person Marged    schedule 17.10.2015
comment
В самом деле? это будет работать с plink blabla < yes.txt хм, надо попробовать, я много использую в linux :))   -  person Fitman    schedule 17.10.2015


Ответы (3)


  1. Чтобы проверить ключ хоста SSH, используйте -hostkey переключатель. Не пытайтесь пропустить проверку ключа хоста. Он предназначен для защиты от атак типа "человек посередине". .

    Arguments = String.Format("-ssh -N -D 9999 [email protected] -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 [email protected] -pw user -v"),
    }
    

    Но опять же, не делайте этого!

  2. #P4#

Итак, не ждите.

Мы не знаем, какова цель вашего приложения.

Если просто открыть туннель, то заставить его ждать (нажатия клавиши?) неопределенное время, чтобы туннель оставался открытым.

Если приложение будет использовать туннель, просто продолжите выполнение других задач, не закрывая сеанс SSH.


Вам лучше использовать собственную библиотеку .NET SSH для туннеля, чем использовать внешнее приложение.

Например, SSH.NET. См. Переадресация портов SSH .NET.

person Martin Prikryl    schedule 19.10.2015
comment
Спасибо за ваш полный ответ, я действительно ценю. Также я ценю тот факт, что у вас было некоторое время, исправляя мой пост, еще раз спасибо. Теперь мне есть что добавить. 1-> Не знал о -hostkey в plink.exe .. простите, можно я туда все положу? Или я должен создать специальный? Или я должен взять его откуда-то с моего компьютера? 2-> Я на самом деле решил это, пожалуйста, посмотрите на pastebin.com/ChzAu82E , что вы думаете об этом? 3-> что бы вы мне порекомендовали, putty или SSH.NET? Мне нравится plink, я считаю, что он более быстрый и стабильный ... - person Fitman; 26.10.2015
comment
1) Вы ставите отпечаток ключа хоста после -hostkey, например -hostkey aa:bb:cc:dd.... 2) Что вы решили конкретно? Как? 3) SSH.NET конечно же. Автоматизация внешнего консольного приложения с использованием незадокументированного интерфейса ни для чего не является надежным решением. - person Martin Prikryl; 26.10.2015
comment
Пожалуйста. Хотя в StackOverflow мы благодарим, принимая ответ. - person Martin Prikryl; 26.10.2015
comment
1) Вы ставите отпечаток ключа хоста после -hostkey, например -hostkey aa:bb:cc:dd.... 2) Что вы решили конкретно? Как? 3) SSH.NET конечно же. Автоматизация внешнего консольного приложения с использованием незадокументированного интерфейса ни для чего не является надежным решением. - person Martin Prikryl; 26.10.2015

Очевидно, что в вашем сценарии невозможно выполнить перенаправление ввода-вывода с эхом.

Попробуйте отправить y в plink, используя strw.WriteLine(...);, который у вас уже есть, или создайте файл yes.txt, в который вы поместите один y, и plink прочитает его содержимое с помощью plink < yes.txt.

Быстрый просмотр страницы руководства plinks не выявил параметра, позволяющего указать "все- да режим».

person Marged    schedule 16.10.2015
comment
так что вы можете просто поставить после StreamWriter strw = p.StandardInput; строки strw.WriteLine("y"); ? это нормально? - person Fitman; 17.10.2015
comment
вы можете попробовать, это не убьет никаких животных, если это не удастся ;-) - person Marged; 17.10.2015
comment
и поверьте мне, я пробовал это all-yes mode ... это недоступно в последних версиях plink - person Fitman; 17.10.2015
comment
дело в том, что я должен каким-то образом удалить фактический RSA KEY, чтобы вызвать вопрос о том, хотите ли вы .... кэшировать ... (т / нет) ... и я еще не знаю, я дам хоть попробуй... - person Fitman; 17.10.2015
comment
когда я захожу на сервер, я не использую это, я использую только putty, но я просто хочу создать туннель, даже если я дам вам пользователя 1.2.3.4, вы ничего не сможете с ним сделать, потому что к нему не подключена оболочка, это всего лишь туннель, вот и все, поэтому нет необходимости в режиме «все да». Теперь понятно? Во всяком случае, я решил проблему, вот ссылка pastebin.com/ChzAu82E ... что вы думаете о это? Все хорошо? Должен признать, вы мне очень помогаете, спасибо! - person Fitman; 26.10.2015
comment
Вы по какой-то причине туннелируете через SSH, верно? Причина в безопасности. Если вы не подтвердите ключ хоста, никакой безопасности. Так что нет, я не понимаю. - person Martin Prikryl; 26.10.2015

Просто выполните этот код.... он потребует ключ кеша... 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();

Скажи мне, если это не... работает...

person kki    schedule 18.11.2016