1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
#!/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 = <PGM>; 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 = <README>) {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 = <README>) && ($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} [<usr>@]<host>:<port> [[<usr>@]<host>:<port> [...]]\n";
print " ssh only checks if you can ssh through the nodes and <port> is ignored.\n";
print " tcp checks for end-to-end message transitivety and <port> is required.\n";
}
exit(8);
}
|