ssh-tunnel.bash

 1 #!/bin/bash
 2 # This script accepts a hostname, a list of ports or port ranges and an 
 3 # optional command, it creates an SSH connection to the specified host and 
 4 # forwards the specified ports to the local machine, then it runs a shell or
 5 # the specified command if one was given, leaving the SSH tunnel open until
 6 # the command exits
 7 #
 8 # Known bugs and Limitations:
 9 # 1. We assume the SSH will "just work", no way of letting the user enter
10 #    a password or a passprase, however, this should work fine in GUI 
11 #    environments where gtk-askpass can be used (no tested)
12 # 2. We do not detect the case where the SSH connection failed nor do we wait
13 #    until the tunnel is properly setup before running the client process
14 # 3. We do not detect the case where the background SSH connection terminates
15 #    before the client process, the is a design question as to what should be 
16 #    done in that case, reconnect? terminate client? ask user?
17 # 4. If the given command's name is made entierly of digits, it will be
18 #    mistaken for a port number, this is mitigated by the fact that the command
19 #    is tested to be an executable file, hence it must be specified with 
20 #    full-path
21 # 5. Syslog seems to get filles with these messages, no idea why:
22 #    sshd[####]: channel ###: open failed: connect failed: Connection refused
23 #
24 
25 LHOST=127.0.0.1
26 SSH=/usr/bin/ssh
27 #SSHCMD=read
28 
29 usage() {
30         cat 1>&2 <<EOF
31 Usage: 
32   $(basename "$0") HOST PORT[-PORT]... [COMMAND] [ARGS]...
33 SSH to HOST forwarding given port ranges to localhost, then executes COMMAND
34 with ARGS or \$SHELL if none was specified, the SSH connection is closed when
35 the COMMAND or shell exits
36 EOF
37         exit 1
38 }
39 
40 COMMAND="$SHELL"
41 
42 [[ $# -lt 2 ]] && usage
43 HOST="$1"
44 shift
45 
46 while [[ $# -gt 0 ]]; do
47         PAIR=($(echo "$1" | \
48                 sed -n 's/^\([0-9][0-9]*\)\(-\([0-9][0-9]*\)\)\?$/\1 \3/p' \
49         ))
50         if [[ ${#PAIR[*]} -gt 1 ]]; then
51                 PORTS[${#PORTS[*]}]=${PAIR[0]}
52                 PORTS[${#PORTS[*]}]=${PAIR[1]}
53         elif [[ ${#PAIR[*]} -gt 0 ]]; then
54                 PORTS[${#PORTS[*]}]=${PAIR[0]}
55                 PORTS[${#PORTS[*]}]=${PAIR[0]}
56         else
57                 break
58         fi
59         shift
60 done
61 
62 [[ ${#PORTS[*]} -lt 1 ]] && usage
63 
64 if [[ $# -gt 0 ]]; then
65         COMMAND="$1"
66         shift
67 fi
68 [[ -x "$COMMAND" ]] || {
69         echo Given command isn\'t executable 1>&2
70         usage
71 }
72 
73 TUNNELS="$(
74         echo ${PORTS[@]} | \
75         xargs -n 2 seq | \
76         sort -nu | \
77         xargs -iP printf "-R P:$LHOST:P "
78 )"
79 
80 #"$SSH" -qttt "$HOST" $TUNNELS "$SSHCMD" &
81 "$SSH" -qNttt "$HOST" $TUNNELS &
82 "$COMMAND" "$@"
83 kill -SIGHUP $!
84 
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s