使用 Perl 和 OpenSSH 与 Switch 交互

Posted

技术标签:

【中文标题】使用 Perl 和 OpenSSH 与 Switch 交互【英文标题】:Using Perl and OpenSSH to interact with a Switch 【发布时间】:2014-02-21 13:56:31 【问题描述】:

我正在尝试从 Linux 服务器上的 Perl 脚本登录到 HP Switch (3500)。我坚持使用 Net::OpenSSH 作为我唯一可用的模块。

不过,每次我尝试登录时它都会挂起。该代码在访问网络服务器时运行良好,而我只是登录,获取目录列表,然后退出。当碰到一个开关时,它会挂断。

手动登录时,操作如下:

$ ssh -luser_name 20.xxx.xxx.xxx
We'd like to keep you up to date about:
  * Software feature updates
  * New product announcements
  * Special events
Please register your products now at:  www.hp.com/networking/register


user_name@20.xxx.xxx.xxx's password: [I type that in, hit enter]
ProCurve J8693A Switch 3500yl-48G
Software revision K.15.04.1018m

Copyright (C) 1991-2013 Hewlett-Packard Development Company, L.P.

                   RESTRICTED RIGHTS LEGEND
 Confidential computer software.  Valid license from HP required for possession,
 use or copying. Consistent with FAR 12.211 and 12.212, Commercial Computer
 Software, Computer Software Documentation, and Technical Data for Commercial
 Items are licensed to the U.S. Government under vendor's standard commercial
 license.
                   HEWLETT-PACKARD DEVELOPMENT COMPANY, L.P.
                   20555 State Highway 249, Houston, TX 77070

[delete lots of lines here]

Press any key to continue

我写了一个简短的脚本来尝试登录并发出一个简单的命令:

use strict;
use Net::OpenSSH;

my $host = '20.xxx.xxx.xxx';
my $user = 'user_name';
my $password = 'password';

my $login_string = $user . ':' . $password . '@' . $host;
my $ssh = Net::OpenSSH->new($login_string);
$ssh->error and die "Cannot open the connection " . $ssh->error;

my @results = $ssh->capture2('show cpu');
map  print; @results;

距离不远:

$ perl testopenssh.pl
We'd like to keep you up to date about:
  * Software feature updates
  * New product announcements
  * Special events
Please register your products now at:  www.hp.com/networking/register

它就挂在那里。就好像它没有意识到它正在寻找密码并且永远不会超过那个点。我按了CTRL-C,它就死了。当我这样做时,调试模式随后会显示:

# file object not yet found at /home/xxxxxx/.libnet-openssh-perl/user_name-20.xxx.xxx.xxx-21357-620440
# passwd/passphrase requested (user_name@20.xxx.xxx.xxx's password:)
# file object not yet found at /home/xxxxxx/.libnet-openssh-perl/user_name-20.xxx.xxx.xxx-21357-620440
# file object not yet found at /home/xxxxxx/.libnet-openssh-perl/user_name-20.xxx.xxx.xxx-21357-620440
# file object found at /home/xxxxxx/.libnet-openssh-perl/app-20.xxx.xxx.xxx-21357-620440
# call args: ['ssh','-O','check','-T','-S','/home/xxxxxx/.libnet-openssh-perl/user_name-20.xxx.xxx.xxx-21357-620440','-l','user_name','20.xxx.xxx.xxx','--']
# open_ex: ['ssh','-O','check','-T','-S','/home/xxxxxx/.libnet-openssh-perl/user_name-20.xxx.xxx.xxx-21357-620440','-l','user_name','20.xxx.xxx.xxx','--']
# io3 mloop, cin: 0, cout: 1, cerr: 0
# io3 fast, cin: 0, cout: 1, cerr: 0
# stdout, bytes read: 28 at offset 0
#> 4d 61 73 74 65 72 20 72 75 6e 6e 69 6e 67 20 28 70 69 64 3d 32 31 33 35 38 29 0d 0a             | Master running (pid=21358)..
# io3 fast, cin: 0, cout: 1, cerr: 0
# stdout, bytes read: 0 at offset 28
# leaving _io3()
# _waitpid(21362) => pid: 21362, rc:
# call args: ['ssh','-S','/home/xxxxxx/.libnet-openssh-perl/user_name-20.xxx.xxx.xxx-21357-620440','-l','user_name','20.xxx.xxx.xxx','--','show cpu']
# open_ex: ['ssh','-S','/home/xxxxxx/.libnet-openssh-perl/user_name-20.xxx.xxx.xxx-21357-620440','-l','user_name','20.xxx.xxx.xxx','--','show cpu']
# io3 mloop, cin: 0, cout: 1, cerr: 1
# io3 fast, cin: 0, cout: 1, cerr: 1

这是否意味着它在寻找密码之前就已经挂起?

还有什么我可以尝试的想法吗?

谢谢!

【问题讨论】:

发布完整的调试日志,并在 ssh 程序上激活调试,将以下参数添加到构造函数调用中:master_opts => '-v' 【参考方案1】:

我正在使用 expect 和私钥身份验证来完成此操作。

我有一个简单的期望脚本,我使用 IP 和登录后要执行的命令调用它:

#!/usr/bin/expect
#
# sendswitchcmd.exp
#
set timeout 60

spawn ssh -t -t -o ConnectTimeout=5 -o StrictHostKeyChecking=no -i PATHTOYOURKEY]
expect -re "Press any key to continue"
send "X"
expect -re ".*#"
send "config\n"
expect -re ".*#"
send "[lindex $argv 1] [lindex $argv 2]\n     "
expect -re ".*#"
send "ex\n"
expect -re ".*#"
send "ex\n"
expect -re ".*>"
send "ex\n"
expect -re ".*you want to log out.*"
send "y"

有了它,我可以做类似的事情

./sendswitchcmd.exp [switch-IP] "show vlans"

我还在一些 Bash 脚本中调用了这些脚本,这些脚本是为了更简单地配置我们的开关而构建的。

也许这对你有帮助。

【讨论】:

我们已经讨论过Expect,但它目前还没有安装。这样做可能是个问题。现在使用私钥认证的问题是我们会遇到大量的交换机。我们不能进去改变他们的配置。这是我们需要模仿手工操作方式的项目之一。令人沮丧,但这就是我们所拥有的。 @AugieDB 您始终可以在本地安装 Perl 模块,即使您没有 root 访问权限。看看Net::SSH::Expect,它是您系统的ssh 的包装器,并使用Expect.pm。 @AugieDB:特别是当您处理大量交换机时,使用某种自动身份验证方式似乎是个好主意。通过公钥、身份验证或 expect。后者可以在提示符下轻松输入预设密码。如果你想试试这个,这里有一个解决方案:***.com/questions/459182/… 这也可以让你自动将你的 priv-key 导入所有这些开关,以获得更安全的 key-auth。【参考方案2】:

您可能知道,当您使用 SSH 时,无法以非交互方式显示密码,即没有命令行选项来包含密码。如果您在 SSH 中使用密码验证,则必须以交互方式提供。

Net::OpenSSH 的连接方式调用单个字符串:

my $ssh2 = Net::OpenSSH->new('jack:secret@foo.bar.com:10022');

只是程序员提供密码的好方法,但它模仿了交互式密码验证。文档说:“对于密码身份验证,必须安装 IO::Pty”

我认为 switch 的 pty 实现可能与您登录的 Web 服务器不同,因此 Net::OpenSSH 模块 - 或者更确切地说,IO::Pty - 无法通过密码验证?

我同意上述@Marlon 的观点,期望在这里很合适。任何你需要模仿人类行为的地方,expect 都是一个很好的选择。而且您没有必须使用 SSH 密钥,尽管建议不要在脚本文件中使用明文形式的密码。但是,上面的 Perl 程序也不是其中列出的密码的***安全程序。因此,您可以轻松切换到能够轻松处理交互式密码登录的 expect 脚本,其安全级别与您现在相同。

只是我的 2c。

【讨论】:

以上是关于使用 Perl 和 OpenSSH 与 Switch 交互的主要内容,如果未能解决你的问题,请参考以下文章

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

想要使用 c++ 或 perl 使用 OpenSSH 和 SFTP 通过 Internet 发送文件---Windows Vista 两者

如何在 perl 的 openssh 中指定 -v 选项

如何使用 Perl 的 OpenSSH 读取输出的每一行

Perl:使用 Net::OpenSSH 的 scp_put 拒绝权限

使用 perl openssh 传递命令服务器