Skip to content

Instantly share code, notes, and snippets.

@nimaid
Last active May 21, 2021 10:36
Show Gist options
  • Select an option

  • Save nimaid/8ccc99065a19f0db42bab50159acbb3a to your computer and use it in GitHub Desktop.

Select an option

Save nimaid/8ccc99065a19f0db42bab50159acbb3a to your computer and use it in GitHub Desktop.
Reverse SSH Tunnel Port Forwarding Helper
#!/bin/bash
set -e
echo
echo "Reverse SSH Tunnel Port Forwarding Helper"
echo "v0.8.2 by nimaid"
echo
function usage
{
echo "Usage: $(basename $0) -p PORTLIST -s HOST [-u USER -k KEY]"
echo " "
echo " -p | --ports Comma seperated list of ports or port pairs"
echo " Port pairs are in the format local:remote"
echo " Single ports are equivalent to port:port"
echo " Example: -p 80:1337,8080:31337,8888"
echo " -s | --server The port forwarding server address"
echo " -u | --user Username to log in with"
echo " -k | --key Path to private key file"
echo " "
echo " -h | --help Display this message"
exit
}
function parse_args
{
# positional args
args=()
# named args
while [ "$1" != "" ]; do
case "$1" in
-p | --ports ) IN_PORTS="$2"; shift;;
-s | --server ) IN_HOST="$2"; shift;;
-u | --user ) IN_USER="$2"; shift;;
-k | --key ) IN_KEY="$2"; shift;;
-h | --help ) usage; exit;; # quit and show usage
* ) args+=("$1") # if no match, add it to the positional args
esac
shift # move to next kv pair
done
# restore positional args
set -- "${args[@]}"
# don't allow extra arguments
if [ "${#args[@]}" -gt "0" ]; then
echo "Too many arguments"
echo
usage
fi
# validate required args
if [[ -z "${IN_PORTS}" || -z "${IN_HOST}" ]]; then
echo "Missing required argument(s)"
echo
usage
fi
# set defaults
if [[ -z "$IN_USER" ]]; then
IN_USER="";
fi
}
function is_valid_port() {
if [ -z "$1" ]; then
false
elif [ -n "$1" ] && [ "$1" -eq "$1" ] 2> /dev/null; then
if [ "$1" -gt "0" ] && [ "$1" -le "65535" ]; then
true
else
false
fi
else
false
fi
}
function is_valid_user_port() {
if [ -z "$1" ]; then
false
elif [ -n "$1" ] && [ "$1" -eq "$1" ] 2> /dev/null; then
if [ "$1" -ge "1024" ] && [ "$1" -le "65535" ]; then
true
else
false
fi
else
false
fi
}
function is_valid_ip()
{
local ip=$1
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS='.'
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return $stat
}
function check_ping() {
if $(ping -c 1 $1 &> /dev/null); then
true
else
false
fi
}
function resolve_ip() {
if [ -z "$1" ]; then
return
elif is_valid_ip $1; then
echo $1
elif ! check_ping $1; then
return
else
RESOLVED_IP=$(dig +short $1)
if [ -z "$RESOLVED_IP" ]; then
RESOLVED_IP=$1
fi
echo $RESOLVED_IP
return
fi
}
parse_args "$@"
IFS="," read -ra PORTSETS <<< $IN_PORTS
FWHOST=$IN_HOST
FWARGS=
FWMSG=
for PORTSET in ${PORTSETS[@]}; do
IFS=":" read -ra PORTS <<< $PORTSET
NUMPORTS=${#PORTS[@]}
if [ "$NUMPORTS" -eq "1" ]; then
LPORT=${PORTS}
RPORT=${PORTS}
elif [ "$NUMPORTS" -eq "2" ]; then
LPORT=${PORTS[0]}
RPORT=${PORTS[1]}
else
echo "Misformatted port pair(s)"
usage
fi
if ! is_valid_port $LPORT; then
echo "Local port $LPORT is not a valid integer in range 1-65535"
echo
usage
fi
if ! is_valid_user_port $RPORT; then
echo "Remote port $LPORT is not a valid integer in range 1024-65535"
echo
usage
fi
FWARGS="$FWARGS -R ${RPORT}:localhost:${LPORT}"
FWMSG="${FWMSG}Forwarding localhost:${LPORT} => ${FWHOST}:${RPORT}\n"
done
SSHUSER=$IN_USER
KEYFILE=$IN_KEY
if [ ! -z "$KEYFILE" ] && [ ! -f "$KEYFILE" ]; then
echo "Private key file is non-existent"
usage
fi
if check_ping $FWHOST; then
echo "Host $FWHOST is reachable."
else
echo "Host $FWHOST is not reachable!"
exit 1
fi
echo
printf "$FWMSG"
FWHOST_IP=$(resolve_ip $FWHOST)
if [ "$FWHOST_IP" != "$FWHOST" ]; then
echo
echo "$FWHOST => $FWHOST_IP"
fi
echo
if [ -z "$SSHUSER" ]; then
FULLFWHOST=$FWHOST
else
echo "Logging in with user account ${SSHUSER}"
FULLFWHOST=${SSHUSER}@${FWHOST}
if [ ! -z "$KEYFILE" ]; then
echo "Using private key file ${KEYFILE}"
fi
echo
fi
if $(command -v autossh &> /dev/null); then
echo "autossh found, will auto-reconnect..."
SSH_CLIENT=autossh
else
echo "autossh not found, using ssh \(will not auto-reconnect\)..."
SSH_CLIENT=ssh
fi
FWCMD="$SSH_CLIENT -nNT $FWARGS"
if [ ! -z "$KEYFILE" ]; then
FWCMD="$FWCMD -i "$KEYFILE""
fi
$FWCMD $FULLFWHOST
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment