Я пытаюсь начать использовать модуль Net::OpenSSH и столкнулся с проблемами. Я попробовал несколько разных методов, которые нашел в Интернете, но, похоже, мне не удалось получить выходные данные команды на удаленном устройстве (в данном случае маршрутизаторах Nokia).
Я вижу «сообщение» для входа (предупреждение о несанкционированном доступе и т. д.) при подключении, но не вижу никаких запросов на вход (должны ли они быть видны с помощью Net::OpenSSH?).
Затем я вижу это сообщение «Соединение с удаленным хостом закрыто».
Я не могу сказать, что он делает, поскольку он больше ничего не выводит на экран и не заполняет $fh. Есть идеи?
#!/usr/bin/perl
use strict;
use warnings;
use Net::OpenSSH;
my $ip = "";
my $username = "";
my $passwd = "";
my $ssh = connect_to_device($ip);
my $fh = $ssh->pipe_out('show card state') or die "unable to run command\n";
while (<$fh>) {
print "$_";
}
close $fh;
undef $ssh;
sub connect_to_device {
my $deviceIpAddr = shift;
$Net::OpenSSH::debug = ~0; # Enable comprehensive debug output
my $ssh = Net::OpenSSH->new($deviceIpAddr,
user => $username,
password => $passwd,
timeout => 3,
strict_mode => 0,
master_opts => ['-o UserKnownHostsFile=/dev/null']
);
$ssh->error and die "Couldn't establish SSH connection: ". $ssh->error;
return $ssh;
}
Отладочный вывод:
# open_ex: ['ssh','-V']
# io3 mloop, cin: 0, cout: 1, cerr: 0
# io3 fast, cin: 0, cout: 1, cerr: 0
# stdout, bytes read: 48 at offset 0
#> 4f 70 65 6e 53 53 48 5f 37 2e 34 70 31 2c 20 4f 70 65 6e 53 53 4c 20 31 2e 30 2e 32 6b 2d 66 69 | OpenSSH_7.4p1, OpenSSL 1.0.2k-fi
#> 70 73 20 20 32 36 20 4a 61 6e 20 32 30 31 37 0a | ps 26 Jan 2017.
# io3 fast, cin: 0, cout: 1, cerr: 0
# stdout, bytes read: 0 at offset 48
# leaving _io3()
# _waitpid(14149) => pid: 14149, rc: 0, err:
# OpenSSH version is 7.4p1,
# ctl_path: /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, ctl_dir: /root/.libnet-openssh-perl/
# set_error(0 - 0)
# call args: ['ssh','-o UserKnownHostsFile=/dev/null','-o','ServerAliveInterval=10','-o','ControlPersist=no','-2MNx','-o','NumberOfPasswordPrompts=1','-o','PreferredAuthentications=keyboard-interactive,password','-S','/root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad','-l','<username>','<ipaddress>','--']
# master state jumping from _STATE_START to _STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# tracer attached, ssh pid: 14150, tracer pid: 14151
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
Warning: Permanently added '<ipaddress>' (RSA) to the list of known hosts.
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
TiMOS-C-16.0.R11 cpm/hops64 Nokia 7450 ESS Copyright (c) 2000-2020 Nokia.
All rights reserved. All use subject to applicable license agreements.
Built on Wed Jan 29 11:57:40 PST 2020 by builder in /builds/c/160B/R11/panos/main
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_LOGIN
# passwd/passphrase requested (<username>@<ipaddress>'s password:)
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_AWAITING_MUX
# file object not yet found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad, state:_STATE_AWAITING_MUX
# file object found at /root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad
# master state jumping from _STATE_AWAITING_MUX to _STATE_RUNNING
# call args: ['ssh','-O','check','-T','-S','/root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad','-l','<username>@<ipaddress>','--']
# open_ex: ['ssh','-O','check','-T','-S','/root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad','-l','<username>@<ipaddress>','--']
# 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 31 34 31 35 30 29 0d 0a | Master running (pid=14150)..
# io3 fast, cin: 0, cout: 1, cerr: 0
# stdout, bytes read: 0 at offset 28
# leaving _io3()
# _waitpid(14161) => pid: 14161, rc: 0, err:
# call args: ['ssh','-S','/root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad','-l','<username>@<ipaddress>','--','show card state']
# pipe_out: 'ssh''-S''/root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad''-l''<username>@<ipaddress>''--''show card state'
Connection to <ipaddress> closed by remote host.
# DESTROY(Net::OpenSSH=HASH(0xd7fd58), pid: 14150)
# sending exit control to master
# set_error(1 - control command failed: master SSH connection broken)
# master state jumping from _STATE_RUNNING to _STATE_KILLING
# killing master
# _master_kill: 14150
# waitpid(master: 14150) => pid: 0, rc: No such file or directory
# waitpid(master: 14150) => pid: 14150, rc: Interrupted system call
# master state jumping from _STATE_KILLING to _STATE_GONE
# master state jumping from _STATE_GONE to _STATE_GONE
Они определены глобально.
должны ли они быть видимы с помощью Net::OpenSSH?" : Я не думаю, что вы должны что-то видеть, если Net::OpenSSH->new()
успешен. Можете ли вы попробовать включить вывод отладки? Кроме того, можете ли вы успешно подключиться из оболочки, используя ssh user@ip_addr
?
Я могу подключиться через обычный SSH (с сервера, который я использую, или напрямую с моего компьютера) и через другие сценарии, использующие Net::SSH:Expect. Этот новый тест предназначен для того, чтобы попытаться заставить Net::OpenSSH работать. Я считаю, что этот сценарий подключается, но после этого что-то, похоже, не работает.
# аргументы вызова: ['ssh','-S','/root/.libnet-openssh-perl/7d29d81a517f00787fb9ba9ca54353ad','-l','<имя пользователя>@<ipaddress>', '--','показать состояние карты']" Что означает "показать состояние карты" в выводе отладки?
«показать состояние карты» — это команда, которую нужно запустить на устройстве.
Чтобы отладить это, попробуйте включить отладочный вывод из Net::OpenSSH. Например:
use v5.38;
use Net::OpenSSH;
$Net::OpenSSH::debug = ~0; # Enable comprehensive debug output
my $user = "hakonh";
my $host = "172.17.0.2";
my $port = 2222;
my $ssh = Net::OpenSSH->new(
$host,
user => $user,
port => $port,
passwd => '????'
);
$ssh->error and
die "Couldn't establish SSH connection: ". $ssh->error;
say "Successfully connected ";
# Shut down the connection by letting the `$ssh` object go out of scope
Пожалуйста, обновите свой вопрос, указав такие отладочные данные. Это может помочь нам сузить проблему.
Я опубликовал вывод отладки
@JasonM Спасибо, также обновите вопрос, указав точный сценарий, который вы использовали для создания отладочных результатов.
Обновил его дополнительной строкой отладки.
Спасибо за обновление. Так вот эта строка не работает: my $fh = $ssh->pipe_out('show card state') or die "unable to run command\n"
? Можете ли вы это проверить?
Это не удается, поскольку, похоже, он на самом деле не заполняет эту команду или, возможно, не запускает ее. Однако он не «умирает», поскольку нигде не печатает это сообщение о смерти. Я проверил в журнале устройства, что вход в систему произошел, но нет ничего, указывающего на то, что произошло с этой командой.
Вместо этого: $ssh->pipe_out('show card state')
попробуйте создать такой массив my $fh = $ssh->pipe_out('show', 'card', 'state')
Я поменял местами эту строку, и вывод отладки выглядит идентичным. Даже та часть, где показаны строки «call args» и «pipe_out», выглядят одинаково. И до сих пор нет вывода команды.
Что произойдет, если вместо этого вы запустите стандартную команду, например «echo»? Пример: my $pipe = $ssh->pipe_out('echo', '1', '2');
Никакой разницы, по-прежнему нет вывода команды. Я попробовал довольно много команд разных типов, и у всех одна и та же проблема.
А если удалить $ssh->pipe_out()
и следующие 4 строки, в которых используется $fh
? Вы все еще получаете ошибки?
В любом случае я не получаю ошибок, просто нет вывода команды. Если я оставлю эти линии вне поля, единственная разница в том, что они то соединяются, то отключаются.
Хорошо, хорошо, значит, проблема в выводе? Когда вы запускаете ssh из оболочки, вы получаете результат?
Да, все работает нормально, если я подключаюсь к устройству напрямую из оболочки или Securecrt. Это также отлично работает, если я использую «net::ssh::expect», а не net::openssh.
Давайте проверим, не является ли проблема командой pipe()
: если вы запустите «ls» на пульте дистанционного управления, вы получите вывод? В скрипте вы можете попробовать использовать команду system()
: Пример: $ssh->system("ls") or die "remote command failed: " . $ssh->error;
ls не является допустимой командой на удаленном устройстве, но я и раньше пробовал «систему». В отладке единственная разница в том, что это «open_ex» вместо «pipe_out» # open_ex: ['ssh','- S','/root/.libnet-openssh-perl/a3610065525649864c26673faadc75b5','-l','<имя пользователя>','<ipaddress>','--','показать состояние карты' ]
Вы пробовали использовать «показать», «карту», «состояние» (3 аргумента), а не «показать состояние карты» (один аргумент)? Пример: my ($in, $out, $err, $pid) = $ssh->open_ex('show', 'card', 'state'); print "out = $out\n"
Я так пробовал, разницы нет.
Может быть, попробовать получить больше отладочных данных от самого ssh
, передав master_opts => ['-vvv']
вызову Net::OpenSSH->new()
?
Вы также можете попытаться определить, связана ли проблема с ssh-сервером маршрутизаторов Nokia, запустив ее на других ssh-серверах.
У меня нет другого устройства, отличного от Nokia, к которому можно было бы подключиться по SSH отсюда. Когда я использую «-vvv», я вижу, что он проходит аутентификацию, и вижу, что он пытается отправить команду, которую я предоставляю, но я не получаю ни ошибки, ни какого-либо вывода.
Поскольку Net::OpenSSH — это всего лишь оболочка для команды ssh, а ssh работает с терминала. Я бы также проверил это -vvv в терминале и проверил, что вы передаете точно те же аргументы, которые показывает -vvv в Perl-скрипте.
В качестве теста я попытался указать сценарию запустить «интерактивный режим», добавив эту строку $ssh->system; Он вошел в систему и вывел меня в командную строку устройства, хотя и не пытался выполнить команду. Для такого взаимодействия может потребоваться использование «ожидания» или чего-то подобного. По крайней мере, это говорит мне о том, что вход в систему действительно работает (подтверждая то, что я вижу в журналах), но что-то заставляет его «отключаться» при использовании любого из вариантов отправки команды (system, capture, capture2, Pipe_out). Не уверен, что с этим делать. Это
См. раздел «Подключение к свитчам, роутерам и т.п.». в FAQ: Metacpan.org/pod/Net::OpenSSH#FAQ : ".... Лучшим инструментом для этой задачи, вероятно, является Expect, используемый отдельно или в сочетании с Net::OpenSSH"
Я рассмотрю возможность использования openssh+expect. Возможно, это единственный вариант, поскольку более прямой метод не работает с этими устройствами. Я ценю вашу помощь в этом.
В вашем сабе
$username
и$passw
не определены. Пожалуйста, покажите полный минимальный пример. См. минимальный воспроизводимый пример для получения дополнительной информации.