Как с помощью perl и Net::OpenSSH определить, обрабатывает ли удаленная сторона только протокол 1?

tl;dr; Как перехватить stderr из сценария, чтобы получить более конкретную ошибку, а не просто полагаться на общую ошибку из Net::OpenSSH?

У меня есть сложная проблема, которую я пытаюсь решить. Net::OpenSSH работает только с протоколом версии 2. Однако у нас есть ряд устройств в сети, которые поддерживают только версию 1. Я пытаюсь найти элегантный способ определить, является ли удаленный конец неправильной версией.

При подключении к устройству версии 1 в stderr появляется следующее сообщение.

Основные версии протокола отличаются: 2 против 1

Однако ошибка, возвращаемая Net::OpenSSH, выглядит следующим образом.

не удалось установить главное SSH-соединение: неверный пароль или главный процесс неожиданно завершился

Эта конкретная ошибка носит слишком общий характер и касается не только разницы в версии протокола. Мне нужно обрабатывать различия протоколов, переключаясь на другую библиотеку, я не хочу делать это для каждой ошибки подключения.

Мы используем довольно сложный процесс, изначально предназначенный для доступа только через telnet. Мы загружаем объект «comm», который затем определяет такие вещи, как тип маршрутизатора и т. д. Этот объект связи вызывает Net::OpenSSH для передачи команд.

Пример:

my $sshHandle = eval { $commsObject->go($router) };
my $sshError = $sshHandle->{ssh}->error;

if ($sshError) {
    $sshHandle->{connect_error} = $sshError;
    return $sshHandle;
}

Где ошибка протокола появляется на stderr здесь

    $args->{ssh} = eval {
        Net::OpenSSH->new(
            $args->{node_name},
            user        => $args->{user},
            password    => $args->{tacacs},
            timeout     => $timeout,
            master_opts => [ -o => "StrictHostKeyChecking=no" ]
        );
    };

Что я хотел бы сделать, так это передать ошибку протокола stderr вместо общей ошибки, возвращаемой Net:: OpenSSH. Я хотел бы сделать это в сценарии, но я не уверен, как захватить stderr из сценария.

Любые идеи были бы хорошы.


person Bill    schedule 21.11.2014    source источник


Ответы (1)


Захватите основной поток stderr и проверьте его потом.

См. здесь, как это сделать.

Другой подход, который вы можете использовать, — просто открыть сокет для удаленного SSH-сервера. Первое, что он отправляет обратно, это строка версии. Например:

$ nc localhost 22
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-8
^C

Из этой информации вы сможете сделать вывод, поддерживает ли сервер SSH v2 или нет.

Наконец, если вам также нужно общаться с серверами SSH v1, версия разработки моего другого модуля Net ::SSH::Any может сделать это с помощью собственного SSH-клиента ОС, хотя он устанавливает новое SSH-соединение для каждой команды.

use Net::SSH::Any;

my $ssh = Net::SSH::Any->new($args->{node_name},
                             user        => $args->{user},
                             password    => $args->{tacacs},
                             timeout     => $timeout,
                             backends    => 'SSH_Cmd',
                             strict_host_key_checking => 0);

Обновление: в ответ на приведенный ниже комментарий Билла по поводу отправки нескольких команд в рамках одного сеанса:

Проблема с отправкой команд в рамках одного и того же сеанса заключается в том, что вам нужно общаться с удаленной оболочкой, и нет надежного способа сделать это общим способом, поскольку каждая оболочка делает что-то по-своему, и особенно для оболочек сетевого оборудования, которые довольно автоматизация недружественная.

Во всяком случае, в CPAN есть несколько модулей, которые пытаются это сделать, реализуя обработчик для каждого типа оболочки (или ОС). Например, проверьте модули Оливера Горвитса Net::CLI::Interact, Net::Appliance::Session и Net::Appliance::Разговорник. Разговорный подход кажется вполне подходящим.

person salva    schedule 21.11.2014
comment
Интересные идеи. Я действительно не хочу иметь дело с накладными расходами на запись в файл, но второй подход интригует. Я могу просто написать зонд для обработки обнаружения. В третьем варианте Net::OpenSSH открывает новую сессию для каждой команды. Мне пришлось обернуть команду в telnet, чтобы обойти это (см. некоторые из моих предыдущих вопросов по этому поводу). Если бы вы могли разработать библиотеку ssh, которой не нужно было бы использовать telnet для отправки нескольких команд, это было бы очень ценно. - person Bill; 22.11.2014