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



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

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

连接到版本 1 设备时,标准服务器上会显示以下消息

协议主要版本不同: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。

任何想法将不胜感激。

捕获主 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);

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

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

无论如何,CPAN 上有几个模块试图做到这一点,为每种 shell(或操作系统)实现一个处理程序。例如,检查Oliver Gorwits的模块Net::CLI::Interact,Net::Appliance::session和Net::Appliance::P hrasebook。短语手册方法似乎非常合适。

最新更新