Skip to content

Instantly share code, notes, and snippets.

@rkok
Created March 23, 2022 07:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rkok/49d7e909e699833c4346b6d8148ab8a2 to your computer and use it in GitHub Desktop.
Save rkok/49d7e909e699833c4346b6d8148ab8a2 to your computer and use it in GitHub Desktop.
Persistent SSH tunnel helper
#!/usr/bin/env bash
# Quit on error
set -e
# Functions
msg() {
echo -e "\x1B[1m$1\x1B[0m"
}
usage() {
echo "Usage:"
echo " Setup: $0 -u user -h host -s srcport -d dstport [-H dsthost]"
echo " Teardown: $0 -T -u user -h host -s srcport -d dstport [-H dsthost]"
echo " Help: $0 --help"
}
help() {
echo "Examples:"
echo
echo " Tunnelling localhost:1234 to MySQL on somehost:3306"
echo " $0 -u arnold -h somehost -s 1234 -d 3306"
echo " After running the above command, you can connect to the MySQL server like so:"
echo " mysql -h 127.0.0.1 -P 1234"
echo " To close the tunnel afterwards:"
echo " $0 -T -u arnold -h somehost -s 1234 -d 3306"
echo
echo " ---"
echo
echo " Tunnelling localhost:1234 to MySQL on farawayhost:3306 THROUGH somehost"
echo " $0 -u arnold -h somehost -s 1234 -d 3306 -H farawayhost"
}
# Static value
CONTROL_SOCKET='~/.ssh/%h_%p_%r.multiplex'
# Default values
DSTHOST=localhost
TEARDOWN=false
# Start parsing arguments
if [ "$1" == "--help" ]; then
usage
echo
help
exit 0
fi
GIVEN=0
OPTIND=1
while getopts ':u:h:s:d:H:T' OPT; do
case "$OPT" in
u ) USER="$OPTARG"
GIVEN=$((GIVEN+1))
;;
h ) HOST="$OPTARG"
GIVEN=$((GIVEN+1))
;;
s ) SRCPORT="$OPTARG"
GIVEN=$((GIVEN+1))
;;
d ) DSTPORT="$OPTARG"
GIVEN=$((GIVEN+1))
;;
H ) DSTHOST="$OPTARG"
;;
T ) TEARDOWN=true
;;
\?) echo "Unknown option: -$OPTARG" >&2
usage >&2
exit 1
;;
: ) echo "Missing option argument for -$OPTARG" >&2
usage >&2
exit 1
;;
* ) usage >&2
exit 1
;;
esac
done
if [ $GIVEN -lt 4 ]; then
echo "Some mandatory options are missing. Make sure you have provided '-u', '-h', '-s' and '-d'" >&2
usage >&2
exit 1
fi
if [ "$TEARDOWN" == "true" ]; then
echo -n "Closing SSH tunnel ... "
ssh \
-o "ControlPath=$CONTROL_SOCKET" \
-TO "exit" \
$USER@$HOST
exit
fi
msg "Opening SSH tunnel $USER@$HOST $SRCPORT => $DSTHOST => $DSTPORT"
# Create SSH tunnel
# Errors will be caught by "set -e"
# -f: Go to background
# -q: Suppress MOTD
# -N: Don't execute any commands (forward only)
# -T: Don't allocate pseudo-terminal
# -M: Use as master process (so we can exit later)
ssh \
-o ExitOnForwardFailure=yes \
-o "ControlPath=$CONTROL_SOCKET" \
-fqNTML "$SRCPORT:$DSTHOST:$DSTPORT" \
$USER@$HOST
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment