#!/bin/bash # Configures a temporary VPN tunnel (using single-use keys) to a remote host # using WireGuard: https://www.wireguard.com/ # # Author: Matt Low # HOST=$1 HOST_ADDR=$(echo ${HOST} | awk -F '@' '{ print $NF }') RAND=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 8 | head -1) INTERFACE_NAME=tun-${RAND} SERVER_ADDR=10.99.255.1/24 CLIENT_ADDR=10.99.255.2/32 DNS=8.8.8.8 #INTERFACE_NAME=${INTERFACE_PFX}-${RAND} echo "Generating keys..." SERVER_KEY=$(wg genkey) CLIENT_KEY=$(wg genkey) SERVER_PUB=$(wg pubkey <<< ${SERVER_KEY}) CLIENT_PUB=$(wg pubkey <<< ${CLIENT_KEY}) PSK=$(wg genpsk) echo " Server pubkey: ${SERVER_PUB}" echo " Client pubkey: ${CLIENT_PUB}" SERVER_LIB=$(cat << END DEFAULT_IFACE=\$(awk '\$2 == 00000000 { print \$1 }' /proc/net/route) exec_sudo() { echo "[#] \$@" sudo \$@ 2>/dev/null } deps() { if ! type -p wg iptables >/dev/null ; then echo "wireguard-tools or iptables missing, installing..." sudo apt install -y wireguard-tools iptables 2>/dev/null \ || sudo pacman -S --noconfirm wireguard-tools iptables 2>/dev/null \ || sudo dnf install -y wireguard-tools iptables 2>/dev/null if [ "\$?" -ne 0 ] ; then echo "Could not install wireguard-tools and/or iptables. Aborting." return 1 fi fi return 0 } remove_interface() { exec_sudo iptables -D FORWARD -i \$1 -j ACCEPT exec_sudo iptables -D FORWARD -o \$1 -j ACCEPT exec_sudo iptables -t nat -D POSTROUTING -s "${CLIENT_ADDR}" -o \${DEFAULT_IFACE} -j MASQUERADE exec_sudo ip link del dev \$1 } cleanup() { sudo sysctl -wq net.ipv4.ip_forward=0 EXIST_INTERFACE=\$(ip addr show to ${SERVER_ADDR} | head -1 | awk '{ print \$2 }' | cut -d':' -f1) if [ ! -z "\${EXIST_INTERFACE}" ] ; then if [ -z "\$(ip link show "\${EXIST_INTERFACE}" type wireguard)" ] ; then # bail if the existing interface isn't of type wireguard return 2 fi remove_interface \${EXIST_INTERFACE} return 0 elif ip link show ${INTERFACE_NAME} type wireguard > /dev/null 2>&1 ; then remove_interface ${INTERFACE_NAME} return 0 fi return 1 } END ) echo echo "Starting server..." ssh -T ${HOST} /bin/bash << END # include SERVER_LIB ${SERVER_LIB} # Install depends deps || exit 1 # Cleanup previous tunnel cleanup if [ "\$?" -eq 2 ] ; then echo "$SERVER_ADDR is already being used on the server." echo "Please choose another address." exit 1 fi umask 0177 exec_sudo ip link add "${INTERFACE_NAME}" type wireguard TMP=\$(mktemp) cat << EOF > \${TMP} [Interface] ListenPort = 51820 PrivateKey = ${SERVER_KEY} [Peer] # foo PublicKey = ${CLIENT_PUB} PresharedKey = ${PSK} AllowedIPs = ${CLIENT_ADDR} EOF exec_sudo wg setconf "${INTERFACE_NAME}" "\${TMP}" rm "\${TMP}" exec_sudo sysctl -wq net.ipv4.ip_forward=1 exec_sudo ip addr add "${SERVER_ADDR}" dev "${INTERFACE_NAME}" exec_sudo ip link set mtu 1420 up dev "${INTERFACE_NAME}" exec_sudo iptables -A FORWARD -i "${INTERFACE_NAME}" -j ACCEPT exec_sudo iptables -A FORWARD -o "${INTERFACE_NAME}" -j ACCEPT exec_sudo iptables -t nat -A POSTROUTING -s "${CLIENT_ADDR}" -o "\${DEFAULT_IFACE}" -j MASQUERADE END if [ "$?" -ne 0 ]; then echo "Error starting server, aborting." exit 1 fi umask 0177 FILE="/tmp/${INTERFACE_NAME}.conf" cat << CONF > "${FILE}" [Interface] Address = ${CLIENT_ADDR} PrivateKey = ${CLIENT_KEY} DNS = ${DNS} [Peer] PublicKey = ${SERVER_PUB} PresharedKey = ${PSK} Endpoint = ${HOST_ADDR}:51820 AllowedIPs = 0.0.0.0/0, ::/0 CONF echo echo "Starting client..." sudo wg-quick up "${FILE}" sleep 1 echo sudo wg show "${INTERFACE_NAME}" echo echo "Connected! Interrupt or press Enter to disconnect and stop server." # clear sensitive variables from memory PSK= CLIENT_KEY= SERVER_KEY= cleanup() { set -e echo echo "Stopping client..." sudo wg-quick down ${FILE} rm ${FILE} echo echo "Stopping server..." ssh -T ${HOST} /bin/bash <<- END ${SERVER_LIB} cleanup || echo "Server was already shut down." END echo echo "Bye!" exit } trap cleanup INT TERM read var cleanup