如何使用 perl 和 Net::OpenSSH 检测远程端是不是只处理协议 1?
Posted
技术标签:
【中文标题】如何使用 perl 和 Net::OpenSSH 检测远程端是不是只处理协议 1?【英文标题】:How with perl and Net::OpenSSH can I detect if the remote side only handles protocol 1?如何使用 perl 和 Net::OpenSSH 检测远程端是否只处理协议 1? 【发布时间】:2015-01-20 02:56:31 【问题描述】:tl;dr; 如何从脚本中捕获 stderr 以获得更具体的错误,而不是仅仅依赖来自 Net::OpenSSH 的一般错误?
我正在尝试解决一个棘手的问题。 Net::OpenSSH 仅适用于协议版本 2。但是我们有许多网络设备仅支持版本 1。我正在尝试寻找一种优雅的方法来检测远程端是否是错误的版本。
连接到版本 1 设备时,stderr 上会显示以下消息
协议主要版本不同:2 与 1
但是 Net::OpenSSH 返回的错误如下
无法建立主 SSH 连接:密码错误或主进程意外退出
这个特定的错误太笼统了,并不仅仅解决协议版本的差异。我需要通过切换到另一个库来处理协议差异,我不想为每个连接错误都这样做。
我们使用了一个相当复杂的过程,该过程最初仅用于 telnet 访问。我们加载一个“comm”对象,然后确定路由器类型等内容。该 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" ]
);
;
我想做的是传入标准错误协议错误,而不是 Net::OpenSSH 传回的一般错误。我想在脚本中执行此操作,但我不确定如何从脚本中捕获 stderr。
任何想法都将不胜感激。
【问题讨论】:
【参考方案1】:捕获主 stderr 流并在之后检查它。
看here怎么做。
您可以使用的另一种方法是打开一个到远程 SSH 服务器的套接字。它发回的第一件事是它的版本字符串。例如:
$ nc localhost 22
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-8
^C
根据这些信息,您应该能够推断出服务器是否支持 SSH v2。
最后,如果你还需要与 SSH v1 服务器通信,我的另一个模块 Net::SSH::Any 的开发版本可以使用 OS 本地 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 上有几个模块试图做到这一点,为每种外壳(或操作系统)实现一个处理程序。例如,查看 Oliver Gorwits 的模块 Net::CLI::Interact、Net::Appliance::Session 和 Net::Appliance::Phrasebook。短语手册的方法似乎很合适。
【讨论】:
有趣的想法。我真的不想处理写入文件的开销,但第二种方法很有趣。我可能只写一个探针来处理检测。在第三个选项中,Net::OpenSSH 为每个命令打开一个新会话。我不得不在 telnet 中包装命令来解决这个问题(参考我之前的一些问题)。如果你可以开发一个不需要使用 telnet 发送多个命令的 ssh 库,那将增加很多价值。以上是关于如何使用 perl 和 Net::OpenSSH 检测远程端是不是只处理协议 1?的主要内容,如果未能解决你的问题,请参考以下文章
Perl:使用 Net::OpenSSH 的 scp_put 拒绝权限
在 Perl 的 ssh 连接中捕获错误主机名的错误消息(使用 Net::OpenSSH)
ctl_dir /root/.libnet-openssh-perl/ 在 /usr/local/share/perl/5.18.2/Net/OpenSSH/Compat/Perl.pm 第 123