如何使用perl和Net :: OpenSSH来检测远程端是否只处理协议1?

时间:2014-11-21 20:58:33

标签: perl stderr openssh

tl; dr; 如何从脚本中捕获stderr以获取更具体的错误,而不仅仅是依赖Net :: OpenSSH中的一般错误?

我有一个棘手的问题,我正试图解决。 Net :: OpenSSH仅适用于协议版本2.但是我们有许多网络设备只支持版本1.我试图找到一种优雅的方法来检测远程端是否是错误的版本。

连接到版本1设备时,stderr上会显示以下消息

  

协议主要版本不同:2对1

然而,Net :: OpenSSH返回的错误如下

  

无法建立主SSH连接:错误密码或主进程意外退出

此特定错误过于笼统,并不仅仅解决协议版本差异。我需要通过切换到另一个库来处理协议差异,我不想为每个连接错误执行此操作。

我们使用一个相当复杂的过程,该过程最初仅用于访问telnet。我们加载一个“comm”对象,然后确定类似路由器类型等东西.com通信对象调用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。

任何想法都会受到赞赏。

1 个答案:

答案 0 :(得分:2)

捕获主stderr流并在之后检查它。

请参阅here如何操作。

您可以使用的另一种方法是打开远程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);

更新:回应以下关于在同一会话中发送多个命令的问题的Bill评论:

通过同一会话发送命令的问题是你必须与远程shell通信,并且没有办法以通用的方式可靠地做到这一点,因为每个shell都以不同的方式做事,特别是对于网络设备那些非常自动化的炮弹。

无论如何,CPAN上有几个模块试图这样做,为每种shell(或OS)实现一个处理程序。例如,查看Oliver Gorwits的模块Net::CLI::InteractNet::Appliance::SessionNet::Appliance::Phrasebook。短语手册似乎非常合适。