#!/bin/bash

# default parameters
SSHKEYGEN_PARAMS="-t ed25519"

if [ $# -lt 1 ]; then
cat << __EOF__
Usage: $0 [command] [options]

  [command]:
    setup:
      Setup SSH tunnel.

      [options]
        --name (NAME):       Connection name.
        --user (USERNAME):   Local user ID to run ssh tunnel.
        --remote (USERNAME): Remote user ID on the remote side.
        --host (HOSTNAME):   Remote host name to connect to.
        --sshopts (OPTIONS): Other SSH options, "-R nnn:XXX:mmm" for example.

    connect:
      Connect SSH tunnel.

      [options]
        --name (NAME):       Connection name.

    remove:
      Remove SSH tunnel.

      [options]
        --name (NAME):       Connection name.
__EOF__

  exit 1;
fi

COMMAND=$1
shift

while [[ $# -gt 0 ]]; do
  case $1 in
    --name)
      NAME=$2
      shift
      shift
      ;;
    --user)
      USER=$2
      shift
      shift
      ;;
    --remote)
      REMOTE=$2
      shift
      shift
      ;;
    --host)
      HOST=$2
      shift
      shift
      ;;
    --sshopts)
      SSHOPTS=$2
      shift
      shift
      ;;
    *)
      echo "Error: unknown option \"$1\"."
      exit 1;
  esac
done

if [[ ! "$NAME" =~ ^[A-Za-z0-9_:\\.\-]+$ ]]; then
  echo "Error: illegal character or NULL in name."
  exit 1
fi

case $COMMAND in
  setup)
    # check ID
    if [ `id -u` -ne 0 ]; then
      echo "Error: setup requires root privileges."
      exit 1;
    fi

    # check local user ID
    if [[ ! "$USER" =~ ^[A-Za-z0-9_.\-]+$ ]]; then
      echo "Error: illegal character or NULL in local user ID."
      exit 1
    fi

    # check remote user ID
    if [[ ! "$REMOTE" =~ ^[A-Za-z0-9_.\-]+$ ]]; then
      echo "Error: illegal character or NULL in remote user ID."
      exit 1
    fi

    # check remote host
    if [[ ! "$HOST" =~ ^[A-Za-z0-9.\-]+$ ]]; then
      echo "Error: illegal character or NULL in remote host name."
      exit 1
    fi

    # check if instance is exist
    if [ -d /etc/sshtunnel/$NAME ]; then
      echo "Error: instance \"$NAME\" was already set up (/etc/sshtunnel/$NAME is exist)."
      exit 1
    fi

    mkdir -p /etc/sshtunnel/$NAME
    chmod 755 /etc/sshtunnel
    chmod 755 /etc/sshtunnel/$NAME

    echo -n Generating SSH key..
    /usr/bin/ssh-keygen $SSHKEYGEN_PARAMS -N "" -f /etc/sshtunnel/$NAME/sshkey > /dev/null 2> /dev/null
    chown $USER:root /etc/sshtunnel/$NAME/sshkey /etc/sshtunnel/$NAME/sshkey.pub
    echo done.

    echo -n Generating config file..
    echo "USER=\"$REMOTE\"" > /etc/sshtunnel/$NAME/config
    echo "HOST=\"$HOST\"" >> /etc/sshtunnel/$NAME/config
    echo "CMDLINE=\"$SSHOPTS\"" >> /etc/sshtunnel/$NAME/config
    chown $USER:root /etc/sshtunnel/$NAME/config
    echo done.

    echo -n Generating systemd drop-in file..
    mkdir -p /etc/systemd/system/sshtunnel\@$NAME.service.d
    echo "[Service]" > /etc/systemd/system/sshtunnel\@$NAME.service.d/override.conf
    echo "User=$USER" >> /etc/systemd/system/sshtunnel\@$NAME.service.d/override.conf
    systemctl daemon-reload
    echo done.

    echo ""
    echo Now you can start sshtunnel by \"systemctl start sshtunnel\@$NAME\".
    echo ""
    echo NOTE: SSH public key \(/etc/sshtunnel/$NAME/sshkey.pub\) must be copied to
    echo       ~$REMOTE/.ssh/authorized_keys \(chmod 600 required\) at target host \($HOST\).
    ;;
  connect)
    # check if instance is exist
    if [ ! -d /etc/sshtunnel/$NAME ]; then
      echo "Error: instance \"$NAME\" is not exist (/etc/sshtunnel/$NAME is not exist)."
      exit 1
    fi

    source /etc/sshtunnel/$NAME/config
    /usr/bin/ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -nN $CMDLINE -i /etc/sshtunnel/$NAME/sshkey -l $USER $HOST
    ;;
  remove)
    # check if instance is exist
    if [ ! -d /etc/sshtunnel/$NAME ]; then
      echo "Error: instance \"$NAME\" is not exist (/etc/sshtunnel/$NAME is not exist)."
      exit 1
    fi

    rm -fR /etc/sshtunnel/$NAME
    rm -fR /etc/systemd/system/sshtunnel\@$NAME.service.d
    ;;
  *)
    echo "Error: unknown command \"$1\"."
    exit 1;
esac
