#!/usr/bin/perl -w # ssh-chain - ssh via a chain of intermediary hosts # # from https://github.com/ryancdotorg/ssh-chain # # Copyright (c) 2011, Ryan Castellucci # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use IPC::Open3; my $host_arg = $ARGV[0] || die "No host passed!"; my $port_arg = $ARGV[1] || die "No port passed!"; my $SSH_BIN = $ENV{'SSH_BIN'} || 'ssh'; my $DEBUG = $ENV{'DEBUG'} || 0; my ($dest_host, $bounce_host); if ($host_arg =~ /\A([^\^]+)\^([^\^].*)/) { ($dest_host, $bounce_host) = ($1, $2); } else { die "Invalid arguments!"; } # Deal with usernames $bounce_host =~ s/\A([^\^\+]+)\+/$1\@/; # Strip username+ syntax from the dest host $dest_host =~ s/\A.*\+//; if ($dest_host =~ /\A([^\^]+)_(\d+)\z/) { $dest_host = $1; $port_arg = $2; } my @SSH_CMD; print STDERR "Connecting to $dest_host:$port_arg via $bounce_host\n" if ($DEBUG); # See if the local version of ssh supports -W ('netcat mode') my $pid = open3(undef, undef, \*FH, $SSH_BIN); while(my $line = ) { if ($line =~ /\[-W\s/) { while () {}; # Consume the rest of the output so ssh exits cleanly close(FH); waitpid($pid, 0); print STDERR "Using ssh -W (netcat mode)\n" if ($DEBUG); @SSH_CMD = ($SSH_BIN, '-W', "$dest_host:$port_arg"); if ($bounce_host =~ /\A([^\^]+)_(\d+)\z/) { $bounce_host = $1; push(@SSH_CMD, '-p', $2); } push(@SSH_CMD, $bounce_host); print STDERR join(' ', @SSH_CMD) . "\n" if ($DEBUG); exec(@SSH_CMD); # Script stops here } } close(FH); waitpid($pid, 0); # Fall back to exec'ing netcat on the bounce host print STDERR "Using ssh exec netcat\n" if ($DEBUG); @SSH_CMD = ($SSH_BIN); if ($bounce_host =~ /\A([^\^]+)_(\d+)\z/) { $bounce_host = $1; push(@SSH_CMD, '-p', $2); } push(@SSH_CMD, $bounce_host); push(@SSH_CMD, 'exec', 'nc', $dest_host, $port_arg); print STDERR join(' ', @SSH_CMD) . "\n" if ($DEBUG); exec(@SSH_CMD);