Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

SSH to remote subsystem (Net::OpenSSH?)

by sojourner9 (Initiate)
on Mar 19, 2013 at 16:02 UTC ( [id://1024329]=perlquestion: print w/replies, xml ) Need Help??

sojourner9 has asked for the wisdom of the Perl Monks concerning the following question:

Trying to create a perl script that SSHv2 to a Cisco device for their XML/NETCONF API. In order to do so, it needs to connect to a subsystem on the remote switch.

Command line example would be:
ssh username@192.168.1.1 -s xmlagent

I've been able to get this to work using Expect. But, I'm not sure that's the best way to do it.

Using expect:

## SSH TO THE SWITCH my $exp = new Expect(); $exp->raw_pty(1); $exp->spawn("ssh","-s","-2",$user."@".$switch,"xmlagent");

Using Net::OpenSSH:
I've tried to get it to work using Net::OpenSSH, but that fails on an error:

my $ssh = Net::OpenSSH->new("$host", master_opts=>[-s => "xmlagent"], +user=>$user, password=>$pass);

Debugging OpenSSH shows it is giving an SSH command formatted like this:
ssh -s xmlagent 192.168.1.1

Which SSH fails on , with the message
ssh: Could not resolve hostname xmlagent: Name or service not known

SSH appears to want the hostname first, and then the options rather than options first then hostname.

So, should I keep using Expect to SSH to the switch, or is there a better way to do this?

Replies are listed 'Best First'.
Re: SSH to remote subsystem (Net::OpenSSH?)
by salva (Canon) on Mar 19, 2013 at 16:48 UTC
    yes, for instance:
    my $ssh = Net::OpenSSH->new($host, user=>$user, password=>$pass); $ssh->error and die "unable to connect to remote host: " . $ssh->error +; my ($socket, $pid) = $ssh->open2socket({ssh_opts => '-s'}, 'xmlagent') +; talk_to_subsystem($socket); waitpid($pid, 0);

    Depending on the way the subsystem works there may be better ways to interact with it.

      Once you're logged into the subsytem, you get a hello message like this:

      <?xml version="1.0" encoding="ISO-8859-1"?> <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <capabilities> <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability> <capability>urn:ietf:params:netconf:base:1.0</capability> </capabilities> <session-id>25470</session-id> </hello> ]]>]]>

      You reply with a client hello message that is formatted very similarly, and then you send it XML/NETCONF formatted messages and it replies with XML formatted responses.

      Using your suggestion, I tried this:

      my $ssh = Net::OpenSSH->new($host, user=>$user, password=>$pass); $ssh->error and die "unable to connect to remote host: " . $ssh->error +; my ($socket, $pid) = $ssh->open2socket({ssh_opts => '-s'}, 'xmlagent') +; ($socket, $pid) = $ssh->open2socket; while (<$socket>) { print }; waitpid($pid, 0);

      Expecting to either see the XML hello message in the debug, or in the socket print. However, it appears that it first makes a connection to the main system, authenticates, and then tries to connect to the subsystem. I'm not good enough with SSH to know if that's how it works with except/shell version or not. Debug shows this:

      # call args: ['ssh','-o','ServerAliveInterval=30','-x2MN','-o','Number +OfPasswordPrompts=1','-o','PreferredAuthentications=keyboard-interact +ive,password','-S','/home/user/.libnet-openssh-perl/user-host-31054-2 +7407','-l','user','host','--']

      Then I see the banner go by and the password prompt as expected, but no XML hello. Then I see:

      # call args: ['ssh','-s','-S','/home/user/.libnet-openssh-perl/user-ho +st-31054-27407','-l','user','host','--','xmlagent'] # open_ex: ['ssh','-s','-S','/home/user/.libnet-openssh-perl/user-host +-31054-27407','-l','user','host','--','xmlagent'] # call args: ['ssh','-S','/home/user/.libnet-openssh-perl/user-host-31 +054-27407','-l','user','host','--'] # open_ex: ['ssh','-S','/home/user/.libnet-openssh-perl/user-host-3105 +4-27407','-l','user','host','--'] Pseudo-terminal will not be allocated because stdin is not a terminal. stty: standard input: Invalid argument

      And then it hangs there, probably looping on the "while". But, the important bit for this step is that it does not look this this creates a properly formatted SSH command either. The "-s" flag is at the beginning, but the "xmlagent" value is at the end - I would expect that it would need to send "-s xmlagent" in order for the -s flag to have meaning. I'm also suspecting that it needs to do so in the first connection, not later (but I'm not positive if that is how SSH should work or not).

        Using your suggestion, I tried...

        You have two calls to open2socket, the first establishes a connection to the Netconf subsystem, but then on the next line it opens a new one to a shell overwriting $socket.

        The correct way to do it is as follows:

        my $ssh = Net::OpenSSH->new($host, user=>$user, password=>$pass); $ssh->error and die "unable to connect to remote host: " . $ssh->error +; my ($socket, $pid) = $ssh->open2socket({ssh_opts => '-s'}, 'xmlagent') +; while (<$socket>) { print };
        Expecting to either see the XML hello message in the debug, or in the socket print. However, it appears that it first makes a connection to the main system, authenticates, and then tries to connect to the subsystem. I'm not good enough with SSH to know if that's how it works with except/shell version or not.

        This is how the SSH protocol works, first a TCP connection is established, then encryption and authentication are negotiated and from that point, bidirectional channels can be open freely between the client and server even in parallel (though, most servers set a limit on the number of concurrent channels, typically 10).

        When you run ssh from the command line or using Expect, the two phases are performed under the hood by the ssh client, though just one channel is open.

        The "-s" flag is at the beginning, but the "xmlagent" value is at the end

        Yes, it works that way, the subsystem name is not an argument to the -s flag but it is taken from the remote command at the end of the ssh argument list (see ssh).

        BTW, the specification for NETCONF over SSH (rfc4742) says the server must listen not at the default SSH port (22) but at port 830. Have you activated the subsystem also at port 22?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1024329]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (8)
As of 2024-04-19 12:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found