SSH в .NET
От: Cynic Россия  
Дата: 08.09.16 09:42
Оценка:
Подскажите библиотеку для работы в SSH из .NET. Пробовал SSH.net, но чего то странно она себя ведет. Все время в выводе получаю, больше чем ожидал. То перевод строки вставит, то первую строку продублирует и прочая дьявольщина Мне нужно отправлять команды на устройство и получать результат.
:)
Отредактировано 08.09.2016 9:45 Cynic . Предыдущая версия .
Re: SSH в .NET
От: Sinix  
Дата: 08.09.16 09:50
Оценка:
Здравствуйте, Cynic, Вы писали:

C>Подскажите библиотеку для работы в SSH из .NET. Пробовал SSH.net, но чего то странно она себя ведет. Все время в выводе получаю, больше чем ожидал. То перевод строки вставит, то первую строку продублирует и прочая дьявольщина Мне нужно отправлять команды на устройство и получать результат.


А нету больше. Только старый Tamir SSH и непонятная мелочёвка. Проверить легко, поиском в nuget.org.

В issues ssh.net есть вот это. Если не оно — заводите новый и прикладывайте пруфы, починят.
Re: Вопрос от новичка, .NET, защита
От: Nonmanual Worker  
Дата: 08.09.16 12:47
Оценка:
Здравствуйте, Cynic, Вы писали:

C>Подскажите библиотеку для работы в SSH из .NET. Пробовал SSH.net, но чего то странно она себя ведет. Все время в выводе получаю, больше чем ожидал. То перевод строки вставит, то первую строку продублирует и прочая дьявольщина Мне нужно отправлять команды на устройство и получать результат.


SSH.net использую для создания SSH tunnels несколько лет, в том числе и в массовых приложениях. Все нормально. Вчера перешел на новую версию, все ОК.
Re[2]: Вопрос от новичка, .NET, защита
От: Cynic Россия  
Дата: 09.09.16 08:16
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>SSH.net использую для создания SSH tunnels несколько лет, в том числе и в массовых приложениях. Все нормально. Вчера перешел на новую версию, все ОК.


Ну может тогда подскажите в чём проблема.
Мне нужно опрашивать сетевые устройства Cisco и анализируя вывод команд проверять соответствие конфигурации определенным политикам. Для этого мне нужно подключиться к устройству, сделать выводы нужных команд, распарсить их и проанализировать. Используя SSH.net это можно сделать двумя способами (возможно их больше):
1) Использовать SshClient.RunCommand(string). В этом случае приходится закрывать соединение после выполнения каждой команды:
using (var sshClient = new SshClient(deviceName, login, password))
{
    sshClient.Connect();
    var cmdOut = sshClient.RunCommand("cmd#1").Result;
    sshClient.Disconnect();

    sshClient.Connect();
    var cmdOut = sshClient.RunCommand("cmd#2").Result;
    sshClient.Disconnect();

    // и т.д.
}

2) Читать/писать из SSH-потока:
using (var sshClient = new SshClient(deviceName, login, password))
{
    sshClient.Connect();

    using (var shellStream = sshClient.CreateShellStream("commandTerminal", 80, 20000, 800, 600, 1024))
    {
        shellStream.WriteLine("cmd");

        string output = string.Empty;
                var result = new List<string>();
        
        // Ожидание необходимо поскольку устройство отвечает с задержкой
        while ((output = shellStream.ReadLine(TimeSpan.FromMilliseconds(1000))) != null)
        {
            // Проверки ...
            result.Add(output);
        }
    }

    sshClient.Disconnect();
}

Первый способ мне не подходит, т.к. большое количество открываний/закрываний сессии генерирует событие безопасности, поэтому я использую второй.
Проблема в том, что в некоторых случаях метод ReadLine часто не возвращает тех строк которые я вижу когда использую Putty или SecureCRT. Например, некоторые роутеры Cisco имеют встроенный модуль шифрования для управления которым нужно из консоли роутера выполнить команду 'service sp 1/0 session', после чего модуль шифрования сначала выводит информационный текст, а потом приглашение на ввод логина и пароля. Так вот когда посылаешь эту команду методом WriteLine и начинаешь читать вывод, ReadLine читает баннер, а приглашение на ввод логина нет (ReadLine всё время возвращает null).
Пытаясь побороть проблему пробовал:
  1. Менять время ожидания в команде ReadLine
  2. Читать поток по байтам командой ReadByte
  3. Создавать потоки StreamWriter и StreamReader производные от shellStream и читать вывод их методами
Ни чего не помогло результат тот-же. Возможно конечно, что я не верно обрабатываю вывод, а Putty и SecureCRT делают это правильно, но я ума не приложу чего ещё делать
:)
Re[3]: Вопрос от новичка, .NET, защита
От: Слава  
Дата: 09.09.16 09:35
Оценка:
Здравствуйте, Cynic, Вы писали:

C>Ни чего не помогло результат тот-же. Возможно конечно, что я не верно обрабатываю вывод, а Putty и SecureCRT делают это правильно, но я ума не приложу чего ещё делать


Не знаю вопроса почти совсем, но — вы не замечали в putty странной формулировки про "keyboard-interactive-что-то там"? Когда логинитесь.

Быть может, там несколько каналов IO?
Re[4]: Вопрос от новичка, .NET, защита
От: Cynic Россия  
Дата: 09.09.16 11:13
Оценка:
Здравствуйте, Слава, Вы писали:

С>Не знаю вопроса почти совсем, но — вы не замечали в putty странной формулировки про "keyboard-interactive-что-то там"? Когда логинитесь.


Оно сообщает что используется метод аутентификации через ввод данных с клавиатуры. Просто можно ещё по сертификату например.

С>Быть может, там несколько каналов IO?


Не вроде один только. Я думаю, что устройство что-то кидает в поток, что обработать ShellStream не может.
:)
Re[3]: Вопрос от новичка, .NET, защита
От: LWhisper  
Дата: 09.09.16 13:36
Оценка:
Во-первых, действительно возможно несколько вариантов аутентификации:
По паролю, интерактивный ввод, по ключу.

Соответственно:
PasswordConnectionInfo
KeyboardInteractiveConnectionInfo
PrivateKeyConnectionInfo

Передаём нужную в SshClient.
Если аутентификация прошла, то запроса пароля ты, очевидно, не получишь.
В случае KeyboardInteractiveConnectionInfo, необходимо подписаться на событие AuthenticationPrompt.
Обработчик AuthenticationPromtReceived(Object sender, AuthenticationPromptEventArgs e) в коллекции e.Prompts содержится Request, который ты должен проверить на приглашение о вводе пароля и Response, которому ты и должен задать пароль.

Есть мнение, что Слава прав, и в твоём случае подойдёт именно KeyboardInteractiveConnectionInfo.
На всякий случай подпишись и на событие ErrorOccurred. Вполне возможно, что произошла какая-то ошибка.
Re[4]: Вопрос от новичка, .NET, защита
От: Cynic Россия  
Дата: 09.09.16 14:02
Оценка:
Здравствуйте, LWhisper, Вы писали:

LW>Во-первых, действительно возможно несколько вариантов аутентификации:

LW>По паролю, интерактивный ввод, по ключу.

LW>Соответственно:

LW>PasswordConnectionInfo
LW>KeyboardInteractiveConnectionInfo
LW>PrivateKeyConnectionInfo

LW>Передаём нужную в SshClient.

LW>Если аутентификация прошла, то запроса пароля ты, очевидно, не получишь.
LW>В случае KeyboardInteractiveConnectionInfo, необходимо подписаться на событие AuthenticationPrompt.
LW>Обработчик AuthenticationPromtReceived(Object sender, AuthenticationPromptEventArgs e) в коллекции e.Prompts содержится Request, который ты должен проверить на приглашение о вводе пароля и Response, которому ты и должен задать пароль.

LW>Есть мнение, что Слава прав, и в твоём случае подойдёт именно KeyboardInteractiveConnectionInfo.

LW>На всякий случай подпишись и на событие ErrorOccurred. Вполне возможно, что произошла какая-то ошибка.

Вы не поняли. Просто залогиниться на устройство и читать вывод я могу. Проблема в том, что на самом устройстве можно сделать ещё один логин на внутренний модуль. Т.е. вы логинитесь на устройство, получаете приглашение командной строки, потом вводите команду и вылезает ещё одно приглашение для логина внутри установленной сессии и вот с этого момент начинаются проблемы. Но за советы спасибо попробую
:)
Re[5]: Вопрос от новичка, .NET, защита
От: LWhisper  
Дата: 09.09.16 14:19
Оценка:
Здравствуйте, Cynic, Вы писали:

C>Вы не поняли. Просто залогиниться на устройство и читать вывод я могу. Проблема в том, что на самом устройстве можно сделать ещё один логин на внутренний модуль. Т.е. вы логинитесь на устройство, получаете приглашение командной строки, потом вводите команду и вылезает ещё одно приглашение для логина внутри установленной сессии и вот с этого момент начинаются проблемы. Но за советы спасибо попробую


Ага, понятно.
Таким не занимался, но, подозреваю, что тебе нужно получить сессию и подписаться на сообщения от неё:
MessageReceived
RegisterMessage

Но это лишь предположение.
Re: SSH в .NET
От: #John https://github.com/ichensky
Дата: 12.09.16 20:08
Оценка: :)
Здравствуйте, Cynic, Вы писали:

C>Подскажите библиотеку для работы в SSH из .NET. Пробовал SSH.net, но чего то странно она себя ведет. Все время в выводе получаю, больше чем ожидал. То перевод строки вставит, то первую строку продублирует и прочая дьявольщина Мне нужно отправлять команды на устройство и получать результат.


Почему просто не создать процесс c openssh client без всяких сомнительных враперов?
П.С. для взаимодействия с командной строкой можно накидать скрипт с http://linux.die.net/man/1/expect
Re[2]: SSH в .NET
От: Cynic Россия  
Дата: 12.09.16 21:23
Оценка:
Здравствуйте, #John, Вы писали:

J>Здравствуйте, Cynic, Вы писали:


C>>Подскажите библиотеку для работы в SSH из .NET. Пробовал SSH.net, но чего то странно она себя ведет. Все время в выводе получаю, больше чем ожидал. То перевод строки вставит, то первую строку продублирует и прочая дьявольщина Мне нужно отправлять команды на устройство и получать результат.


J>Почему просто не создать процесс c openssh client без всяких сомнительных враперов?

J>П.С. для взаимодействия с командной строкой можно накидать скрипт с http://linux.die.net/man/1/expect

А можно поподробнее ...
:)
Re[3]: SSH в .NET
От: #John https://github.com/ichensky
Дата: 13.09.16 09:58
Оценка: 2 (1)
Здравствуйте, Cynic, Вы писали:

J>>Почему просто не создать процесс c openssh client без всяких сомнительных враперов?

J>>П.С. для взаимодействия с командной строкой можно накидать скрипт с http://linux.die.net/man/1/expect

C>А можно поподробнее ...

1. openssh-client & expect & sh можно достать из cygwin как уже готовые бинарники(+просмотреть их с dependency walker -ом и забрать вместе с зависимыми либами), либо забрать их из mingw(или скомпилить с mingw), -если ненужны зависимости ввиде либ от cygwin.
Или если надо совсем по быстрому и простому: просто поставить на сервер: cygwin(или mingw) c openssh-client и expect.
2. Накидываем скрипт, который напр., по ssh будет запускать какой-то скрипт на удаленном сервере, myscript.sh:
#!/usr/bin/expect -f
spawn ssh username@1.2.3.4 -p 22222
expect "assword:"
send "mypass\r"
expect "$ "
send "cd /home/username/scripts && ./coolscript_on_remote_server.sh && exit\r"

3. И из .net запускаем скрипт: Process.Start("sh.exe", "myscript.sh");
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.