9 memoize
('list_busy_ports');
16 my $gateway_host = 'sgn-devel.sgn.cornell.edu';
17 my $local_port = 3000;
20 my @allowed_gateway_ports = 8080..8090;
22 GetOptions
( 'port|p=i' => \
$local_port,
24 'remote_port|r=i' => \
$gateway_port,
26 or pod2usage
('invalid options');
28 $gateway_host = shift @ARGV if @ARGV;
30 $user .= '@' if $user;
32 ### make sure this is a valid hostname before trying the ssh commands
33 # (the error checking on the ssh commands leaves a bit to be desired)
34 validate_hostname
( $gateway_host );
36 ### find an available port
37 my $host = "$user$gateway_host";
38 $gateway_port ||= find_available_port
( $host, @allowed_gateway_ports );
40 is_port_available
( $host, $gateway_port )
41 or die "Remote port $gateway_port already in use, cannot set up gateway.\n";
43 ### open the ssh connection
44 print "Forwarding local port $local_port to http://$gateway_host:$gateway_port\n";
45 print "Press Ctrl-c to close the connection.\n";
46 exec "ssh -N -R $gateway_host:$gateway_port:localhost:$local_port '$user$gateway_host'";
49 ############ subroutines
51 sub validate_hostname
{
53 die "Could not resolve hostname $host\n" unless gethostbyname( $host );
56 sub find_available_port
{
57 my ( $ssh_host, @acceptable_ports ) = @_;
59 my $busy_ports = list_busy_ports
( $ssh_host );
61 die "Failed to connect to $user$gateway_host\n"
64 for( @acceptable_ports ) {
65 return $_ unless $busy_ports->{$_};
68 die "All remote ports seem to be busy.\n",
69 "Tried ports ".join(', ',@acceptable_ports).".\n";
73 my ( $ssh_host ) = @_;
75 ### use netstat on the remote host to find ports that are already in use
78 open( my $netstat, "ssh '$user$gateway_host' 'netstat -ltunp 2>/dev/null' |" ) or die "$! running ssh\n";
80 #no warnings 'uninitialized';
81 my $local = ( split )[3];
82 my ($busy_port) = $local =~ /:(\d+)/
84 $busy_ports{$busy_port} = 1;
87 ### busy_ports: %busy_ports
89 # hash of { port_number => 1 }
93 sub is_port_available
{
94 my ( $ssh_host, $port ) = @_;
96 my $busy_ports = list_busy_ports
( $ssh_host );
98 return ! $busy_ports->{$port};
105 dev_gateway - use C<ssh> to make a remote machine act as a gateway to a local port
109 dev_gateway foo.example.com
111 dev_gateway -u bob -p 5432 foo.example.com
113 dev_gateway --user alice --p 3000 foo.example.com
119 =item -p --port <num>
121 Port on the local machine to forward. Default 3000.
123 =item -u --user <name>
125 Username to connect as. Defaults to current local user.
127 =item -r --remote_port <number>
129 Force the remote port to use. Should usually be in the range 8080 - 8090.