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

Greetings Monks, I am having a hard time tracking down this issue I am having with the Net::SSH2 module. Basically, my code will read in a file containing information to be programmed into a menu-driven network device. The code will iterate through about 21 lines before simply exiting in the middle of a print statement. I am positive it is not due to faulty file input as I can replicate the issue with any file exceeding 21 lines. I'd like to know if there is any kind of debugging I can do that will show why the program is crashing. All code is contained below:
#!/usr/bin/perl use 5.010; use strict; use warnings; use Net::SSH2; use Data::Validate::IP; #Variables my $host = $ARGV[0]; my $tacacsusername = $ARGV[1]; my $tacacspassword = $ARGV[2]; my $fh = $ARGV[3]; my $validator = Data::Validate::IP->new; if (@ARGV != 4 || !$validator->is_ipv4($host)) { print "Invalid arguments, exiting."; exit; } open(my $data, '<', $fh) or die "Could not open '$fh' $!\n"; my $ssh = Net::SSH2->new(); $ssh->connect($host, 22); $ssh->auth_password($tacacsusername, $tacacspassword); if($ssh->auth_ok) { my $channel = $ssh->channel(); $channel->blocking(0); $channel->shell(); print $channel "network\n"; #Enter network context print $channel "ddelete\n"; #Clear DAT table print $channel "yes\n"; #Confirm clearing DAT sessions print $channel "b\n"; #Return to main context print "$_" while <$channel>; #Print output to console #Iterate the CSV file line by line while (my $line = <$data>) { chomp $line; my @fields = split "," , $line; print $channel "subscribers\n"; #Enter subscriber context print $channel "add\n"; #Add subscriber print $channel "$fields[1]\n"; #Mac Address print $channel "$fields[0]\n"; #Hostname print $channel "1\n"; # Type of Profile 1=Device print $channel "$fields[2]\n"; #IP Address print $channel "\n"; #Subnet print $channel "\n"; #User Definable 1 print $channel "\n"; #User Definable 2 print $channel "\n"; #Upstream Bandwidth in kbps print $channel "\n"; #Downstream Bandwidth in kbps print $channel "\n"; #QOS Policy print $channel "$fields[3]\n"; #VLAN print $channel "\n"; #Proxy arp print $channel "\n"; #SMTP Redirection print $channel "b\n"; #Exit subscriber context print "$_" while <$channel>; #Print output to console if(scalar(@fields) > 5 && $fields[4] ne ''){ print $channel "system\n"; #Enter system context print $channel "static\n"; #Enter static portmap context print $channel "add port\n"; #Add new portmap print $channel "$fields[2]\n"; #IP Address print $channel "$fields[4]\n"; #SNMP Internal port print $channel "$fields[1]\n"; #Mac Address print $channel "$fields[5]\n"; #SNMP External port print $channel "UDP\n"; #UDP on first pass for SNMP print $channel "\n\n"; #Remote IP, port print $channel "enable\n"; #Use access control print $channel "b\nb\n"; #Return to main context print "$_" while <$channel>; #Print output to console } if(scalar(@fields) > 7 && $fields[6] ne ''){ print $channel "system\n"; #Enter system context print $channel "static\n"; #Enter static portmap context print $channel "add port\n"; #Add new portmap print $channel "$fields[2]\n"; #IP Address print $channel "$fields[6]\n"; #MGMT Internal port print $channel "$fields[1]\n"; #Mac Address print $channel "$fields[7]\n"; #MGMT External port print $channel "TCP\n"; #TCP on second pass for MGMT print $channel "\n\n"; #Remote IP, port print $channel "enable\n"; #Use access control print $channel "b\nb\n"; #Return to main context print "$_" while <$channel>; #Print output to console } if(scalar(@fields) > 9 && $fields[8] ne ''){ print $channel "system\n"; #Enter system context print $channel "static\n"; #Enter static portmap context print $channel "add port\n"; #Add new portmap print $channel "$fields[2]\n"; #IP Address print $channel "$fields[8]\n"; #MGMT Internal port print $channel "$fields[1]\n"; #Mac Address print $channel "$fields[9]\n"; #MGMT External port print $channel "TCP\n"; #TCP on second pass for MGMT print $channel "\n\n"; #Remote IP, port print $channel "enable\n"; #Use access control print $channel "b\nb\n"; #Return to main context print "$_" while <$channel>; #Print output to console } else { print $channel "b\nb\n"; #Return to main context } print "$_" while <$channel>; #Print output to console } print $channel "b\n"; print $channel "logout\n"; print "$_" while <$channel>; print "\n"; $channel->send_eof(); $channel->close(); $ssh->disconnect(); } else { print "ERROR: Please verify credentials as the connection to the +gateway failed\n"; }

Replies are listed 'Best First'.
Re: Net::SSH2 limitation?
by salva (Canon) on Jul 30, 2015 at 21:30 UTC
    Ensure you are using the latest version of libssh2 and try also the version of Net::SSH2 from GutHub as several bugs were fixed there.

    In any case, as you seem to be on a Linux/Unix box, consider also using Net::OpenSSH instead.

      Thanks for the tip, salva. I am in the process of changing over to OpenSSH now to see if that resolves it. Looks like there is some weirdness happening due to the nature of the remote shell (very proprietary, does not adhere to any known standard of man or beast).
        Update in case anyone else runs into this same problem in the future: I tried porting my code to use Net::OpenSSH but due to the platform I am targeting, I just could not get it working properly. The entire connection would sever and then re-establish and prompt for password after each command. I also had the same issue with Net::SSH::Expect. The solution I came up with was to implement a counter and after 20 iterations, sever the connection cleanly and re-establish for another 20 lines indefinitely. Everything now seems to be in working order. Added code snippet below. Thanks Monks!
        if($i == 20){ print $channel "logout\n"; print "$_" while <$channel>; print "\n"; $channel->send_eof(); $channel->close(); $ssh->disconnect(); undef $ssh; $ssh = Net::SSH2->new(); $ssh->connect($host, 22); $ssh->auth_password($tacacsusername, $tacacspassword); $channel = $ssh->channel(); $channel->blocking(0); $channel->shell(); $i = 0; }