#!/usr/bin/env perl use Cwd qw(realpath); use IO::Socket; use IPC::Open2; $SSH = 'ssh -a -x -oFallBackToRsh=no'; $Xeq = "/tmp/netchk.$$"; $Ppath = realpath($0); chomp($myHost=`hostname`); $| = 1; # 1st token is what to do # $Op = shift(@ARGV); $Initial = ($Op eq 'ssh' || $Op eq 'tcp'); $Inter = ($Op eq 'SSH' || $Op eq 'TCP'); Usage("Operation (ssh or tcp) not specified.") if !$Op; Usage("Operation '$Op' is neither 'ssh' nor 'tcp'.") if !($Initial||$Inter); $Op = uc($Op); $doTCP = ($Op eq 'TCP'); # Get port to listen on and validate it # if ($doTCP && $Inter) {($Src, $Lport) = split(/:/, shift(@ARGV), 2); ValPort('listen', $myHost, $Lport, 1); } # Get the first hop and rest of the hops and construct command line # $Hop = shift(@ARGV); ($Hop, $Port) = split(/:/, $Hop, 2); if ($Hop) {($Usr, $Hop) = split(/@/, $Hop, 2); if (!$Hop) {$Hop = $Usr;} else {$Lgn = "-l $Usr";} } else {Usage("Target host not specified.") if $Initial;} ValPort('tcp', $Hop, $Port) if $doTCP && $Hop; while($HPval = shift(@ARGV)) {($Hval, $Pval) = split(/:/, $HPval, 2); if ($doTCP) {ValPort('tcp', $Hval, $Pval);} else {$HPval = $Hval;} $Rest .= $HPval.' '; } chop($Rest); $Op .= " $myHost:$Port" if $doTCP; # Tell user where we are # if ($Inter) {if ($doTCP) {Accept($Src, $Lport);} else {print "Reached $myHost via ssh!\n";} } # Send program if we have a hop # if ($Hop) {$Cmd = "$SSH $Lgn $Hop 'cat > $Xeq; chmod +x $Xeq; $Xeq $Op $Rest; exit'"; Usage("Cannot open $Ppath; $!",1) if !open(PGM, $Ppath); @Prog = ; close(PGM); $myProg = join("", @Prog); print "Moving on to $Hop. . .\n"; Usage("Unable to launch $CMD; $!",1) if !open2(*README, *WRITEME, $Cmd); print WRITEME "$myProg"; close(WRITEME); Connect($Hop, $Port) if $doTCP; while($Output = ) {print $Output;} } unlink($Xeq); exit(0); sub Accept {my($Src, $Port) = @_; my $sock = new IO::Socket::INET (LocalHost => $myHost, LocalPort => $Port, Proto => 'tcp', Listen => 1, Reuse => 1,); # If socket created, tell waiter to connect, and accept the connection # Usage("Could not create socket on $myHost; $!",1) unless $sock; print "$myHost is listening on port $Lport for $Src\nOK\n"; my $new_sock = $sock->accept(); Usage("Accept failed on $myHost; $!") unless $new_sock; $Src = $new_sock->peerhost() if !$Src; $new_sock->autoflush(1); $new_sock->recv($Ack, 256); if ($Ack) {$new_sock->send("$Ack");} else {print "$Src connect to $myHost but did not send ack.\n";} close($sock); close($new_sock); } sub Connect {my($Host, $Port) = @_; my($Output, $Resp, $Msg); # Wait until dest sends an OK to connect # while(($Output = ) && ($Output ne "OK\n")) {print $Output;} Usage("Unable to connect to $Host:$Port; lost ssh connection.",1) if !$Output; # Now connect and tell the acceptor who we are # my $sock = new IO::Socket::INET (PeerAddr => $Host, PeerPort => $Port, Proto => 'tcp',); Usage("Could not create socket on $myHost; $!",1) unless $sock; $sock->autoflush(1); $Msg = getppid().".$$"; $sock->send($Msg); $sock->recv($Resp, 256); if (!$Resp) {print "Connected to $Host:$Port but no ack received.\n";} {if ($Resp eq $Msg) {print "$myHost can communicate with $Host\n";} else {print "Connected to $Host:$Port but message exhange failed.";} } close($sock); } sub ValPort {my($What, $Host, $Port, $Snuff) = @_; Usage(ucfirst($What)." port not specified for $Host", $Snuff) if !$Port; Usage("'$Port' is an invalid $What port for $Host.", $Snuff) if !($Port =~ m/^\d+$/); } sub Usage {my($txt, $kll) = @_; print "netchk: $txt\n"; if (!$kll) {print "Usage: netchk {ssh|tcp} [@]: [[@]: [...]]\n"; print " ssh only checks if you can ssh through the nodes and is ignored.\n"; print " tcp checks for end-to-end message transitivety and is required.\n"; } exit(8); }