#!/bin/sh BP_SYSCTL="${SYSCTL_CONF_FILE:-/etc/sysctl.d/bypasser-forwarding.conf}" BP_WG_INTERFACE_PREFIX="bp-" BP_WG_DIR="${BP_WG_DIR:-/etc/wireguard}" BP_WG_PEERS_DIR="$BP_WG_DIR"/peers BP_WG_DEFAULT_MIN_PORT="${BP_WG_DEFAULT_MIN_PORT:-55107}" BP_WG_DEFAULT_MAX_PORT="${BP_WG_DEFAULT_MAX_PORT:-55207}" BG_WG_SUBNET_PREFIX="69.0" BG_WG_INTERFACE_SUBNET_MASK="24" BG_WG_PEER_SUBNET_MASK="32" _IPV4_RULE="net.ipv4.ip_forward" _IPV6_RULE="net.ipv6.conf.all.forwarding" OPT_TARGET="$1" OPT_ACTION="$2" OPT_ARG="$3" if [ "$(whoami)" != "root" ]; then echo "Error, must run as root" exit 1 fi _print_help() { echo "Usage:" echo " bypasser [vpn|peer] [|:]" echo echo "Examples:" echo echo "Add a new VPN:" echo " bypasser vpn new myvpn" echo echo "Add a new peer:" echo " bypasser peer new myvpn:mypeer" } _get_vpn_name() { printf "Enter a name for the new virtual network" read -r _name if [ -z $_name ]; then return 1 fi echo "$_name" } _vpn_name_available() { _vpn_name="$1" [ -z $_vpn_name ] && return 1 _vpn_file="$BP_WG_DIR"/"$BP_WG_INTERFACE_PREFIX$_vpn_name".conf ! [ -f "$_vpn_file" ] } _enable_forwarding() { printf "%s = 1\n%s = 1" "$_IPV4_RULE" "$_IPV6_RULE" >"$BP_SYSCTL" sysctl -p >/dev/null 2>&1 sysctl --system >/dev/null 2>&1 } _check_forwarding() { _v4="$(sysctl "$_IPV4_RULE")" _v4="${_v4##*= }" _v6="$(sysctl "$_IPV6_RULE")" _v6="${_v6##*= }" if [ "$_v4" = 0 ] || [ "$_v6" = 0 ]; then return 1 fi } _vpn_list() { echo "Available VPNs in '$BP_WG_DIR':" if ! [ -d "$BP_WG_DIR" ] || [ -z "$BP_WG_DIR" ]; then return 0 fi for f in "$BP_WG_DIR"/*; do if [ -f "$f" ]; then vpn="${f##*/}" vpn="${vpn#${BP_WG_INTERFACE_PREFIX}}" vpn="${vpn%.conf}" echo " - $vpn" fi done } _peer_list() { echo "Available Peers in '$BP_WG_PEERS_DIR':" if ! [ -d "$BP_WG_PEERS_DIR" ] || [ -z "$BP_WG_PEERS_DIR" ]; then return 0 fi for f in "$BP_WG_PEERS_DIR"/*; do if [ -f "$f" ]; then peer="${f##*/}" peer="${peer#${BP_WG_INTERFACE_PREFIX}}" peer="${peer%.conf}" peer="${peer%.conf}" vpn="${peer%%-*}" peer="${peer##*-}" echo " - $vpn:$peer" fi done } _vpn_restart() { _vpn_name="$1" _vpn_interface="$BP_WG_INTERFACE_PREFIX$_vpn_name" wg-quick down "$_vpn_interface" systemctl restart wg-quick@"$_vpn_interface" } _vpn_enable() { _vpn_name="$1" _vpn_interface="$BP_WG_INTERFACE_PREFIX$_vpn_name" wg-quick down "$_vpn_interface" systemctl enable --now wg-quick@"$_vpn_interface" } _vpn_disable() { _vpn_name="$1" _vpn_interface="$BP_WG_INTERFACE_PREFIX$_vpn_name" wg-quick down "$_vpn_interface" systemctl disable --now wg-quick@"$_vpn_interface" } _get_available_port() { _avail_port="$((BP_WG_DEFAULT_MIN_PORT - 1))" for f in "$BP_WG_DIR"/*; do if [ -f "$f" ]; then while read -r line; do case "$line" in *ListenPort*) _port="${line##* = }" if [ -n "$_port" ] && [ "$_port" -gt "$_avail_port" ]; then _avail_port="$_port" fi ;; esac done <"$f" fi done echo "$((_avail_port + 1))" } _vpn_new() { if ! [ -d "$BP_WG_DIR" ] || [ -z "$BP_WG_DIR" ]; then echo "Error: directory '$BP_WG_DIR' nonexistent, create it (and set 600 permissions) to add new VPNs" return 1 fi _vpn_name="$1" _vpn_file="$BP_WG_DIR"/"$BP_WG_INTERFACE_PREFIX$_vpn_name".conf if [ -f "$_vpn_file" ]; then echo "Error: vpn name '$_vpn_name' already exists in '$_vpn_file'" return 1 fi _port="$(_get_available_port)" if [ "$?" != 0 ] || [ -z "$_port" ]; then echo "Error: could not get an available port" return 1 fi _server_sec_key=$(wg genkey) if [ "$?" != 0 ]; then echo "Error: could not generate private key" return 1 fi _highest="$(_highest_interface)" _new=$((_highest + 1)) echo "[Interface] PrivateKey = ${_server_sec_key} ListenPort = ${_port} Address = ${BG_WG_SUBNET_PREFIX}.${_new}.1/${BG_WG_INTERFACE_SUBNET_MASK}" >"$_vpn_file" chmod 600 "$_vpn_file" _vpn_enable "$_vpn_name" } _vpn_rm() { if ! [ -d "$BP_WG_DIR" ] || [ -z "$BP_WG_DIR" ]; then return 1 fi _vpn_name="$1" _vpn_file="$BP_WG_DIR"/"$BP_WG_INTERFACE_PREFIX$_vpn_name".conf _vpn_disable "$_vpn_name" if [ -f "$_vpn_file" ]; then sudo rm -f "$_vpn_file" else echo "Error: file '$_vpn_file' nonexistent" return 1 fi } _peer_rm() { if ! [ -d "$BP_WG_PEERS_DIR" ] || [ -z "$BP_WG_PEERS_DIR" ]; then return 1 fi _peer_name="$1" _vpn_name="${_peer_name%%:*}" _peer_name="${_peer_name##*:}" _peer_file="$BP_WG_PEERS_DIR"/"$BP_WG_INTERFACE_PREFIX$_vpn_name-$_peer_name".conf if ! [ -f "$_peer_file" ]; then echo "Error: peer file '$_peer_file' nonexistent" return 1 fi if [ -f "$_peer_file" ]; then sudo rm -f "$_peer_file" else echo "Error: file '$_peer_file' nonexistent" return 1 fi _vpn_restart "$_vpn_name" } _get_host_addr() { _addr="$1" _addr="${_addr%%/*}" _host="${_addr#${BG_WG_SUBNET_PREFIX}.}" echo "$_host" } _get_interface_octet() { _host="$(_get_host_addr "$1")" echo "${_host%.*}" } _get_peer_octet() { _host="$(_get_host_addr "$1")" echo "${_host#*.}" } _highest_interface() { _highest=0 for f in "$BP_WG_DIR"/*; do if [ -f "$f" ]; then while read -r line; do case "$line" in *Address*) _addr="${line##* = }" _interface_octet="$(_get_interface_octet "$_addr")" if [ -n "$_interface_octet" ] && [ "$_interface_octet" -gt "$_highest" ]; then _highest="$_interface_octet" fi ;; esac done <"$f" fi done echo "$_highest" } _highest_peer_in_vpn() { _highest=1 _interface_conf="$BP_WG_DIR"/"$BP_WG_INTERFACE_PREFIX$1".conf if [ -f "$_interface_conf" ]; then while read -r line; do case "$line" in *AllowedIPs*) _addr="${line##* = }" _peer_octet="$(_get_peer_octet "$_addr")" if [ -n "$_peer_octet" ] && [ "$_peer_octet" -gt "$_highest" ]; then _highest="$_peer_octet" fi ;; esac done <"$_interface_conf" fi echo "$_highest" } _vpn_exists() { [ -f "$BP_WG_DIR"/"$1" ] } _get_interface_address() { _interface_file="$BP_WG_DIR"/"$BP_WG_INTERFACE_PREFIX$1".conf if [ -f "$_interface_file" ]; then while read -r line; do case "$line" in *Address*) _addr="${line##* = }" echo "$(_get_interface_octet "$_addr")" break ;; esac done <"$_interface_file" else return 1 fi } _peer_new() { _arg="$1" if ! [ -d "$BP_WG_DIR" ] || [ -z "$BP_WG_DIR" ]; then echo "Error: directory '$BP_WG_DIR' nonexistent, create it (and set 600 permissions) to add new VPNs" return 1 fi if ! [ -d "$BP_WG_PEERS_DIR" ] || [ -z "$BP_WG_PEERS_DIR" ]; then echo "Error: directory '$BP_WG_PEERS_DIR' nonexistent, create it (and set 600 permissions) to add new VPNs" return 1 fi _vpn_name="${_arg%%:*}" _peer_name="${_arg##*:}" _vpn_file="$BP_WG_DIR"/"$BP_WG_INTERFACE_PREFIX$_vpn_name".conf _peer_file="$BP_WG_PEERS_DIR"/"$BP_WG_INTERFACE_PREFIX$_vpn_name"-"$_peer_name".conf if [ -z "$_vpn_name" ] || [ -z "$_peer_name" ]; then echo "Error: invalid vpn or peer name" return 1 fi if [ -f "$_peer_file" ]; then echo "Error: peer file '$_peer_file' already exists" return 1 fi _server_sec_key= while read -r line; do case "$line" in *PrivateKey*) _server_sec_key="${line##* = }" break ;; esac done <"$_vpn_file" if [ -z "$_server_sec_key" ]; then echo "Error: could not find interface private key" return 1 fi _server_pub_key=$(echo "${_server_sec_key}" | wg pubkey) _server_port= while read -r line; do case "$line" in *ListenPort*) _server_port="${line##* = }" break ;; esac done <"$_vpn_file" if [ -z "$_server_port" ]; then echo "Error: could not find interface ListenPort" return 1 fi _highest="$(_highest_peer_in_vpn "$_vpn_name")" _new_octet=$((_highest + 1)) _addr="$(_get_interface_address "$_vpn_name")" _vpn_octet="$(_get_interface_octet "$_addr")" if [ -z "$_vpn_octet" ]; then echo "Error: invalid vpn name" return 1 fi _peer_sec_key=$(wg genkey) _peer_pub_key=$(echo "${_peer_sec_key}" | wg pubkey) _peer_pre_key=$(wg genpsk) _server_ipv4="$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | awk '{print $1}' | head -1)" echo "[Peer] PublicKey = ${_peer_pub_key} PresharedKey = ${_peer_pre_key} AllowedIPs = ${BG_WG_SUBNET_PREFIX}.${_vpn_octet}.${_new_octet}/${BG_WG_PEER_SUBNET_MASK}" >>"$_vpn_file" echo echo "=== NEW CLIENT CONFIGURATION ===" echo "Location: $_peer_file" echo "================================" echo echo "[Interface] PrivateKey = ${_peer_sec_key} Address = ${BG_WG_SUBNET_PREFIX}.${_vpn_octet}.${_new_octet}" >"$_peer_file" echo "[Peer] PublicKey = ${_server_pub_key} PresharedKey = ${_peer_pre_key} AllowedIPs = ${BG_WG_SUBNET_PREFIX}.${_vpn_octet}.0/${BG_WG_INTERFACE_SUBNET_MASK} Endpoint = ${_server_ipv4}:${_server_port} PersistentKeepalive = 25" >>"$_peer_file" while read -r line; do echo "$line" done <"$_peer_file" echo echo "================================" echo _vpn_restart "$_vpn_name" } if ! _check_forwarding; then printf "Forwarding is not enabled, enable in '$BP_SYSCTL'? [y/n]: " read -r _opt case "$_opt" in y | Y) _enable_forwarding ;; *) exit 1 ;; esac fi case "$OPT_TARGET" in vpn) case "$OPT_ACTION" in new) _vpn_new "$OPT_ARG" ;; rm) _vpn_rm "$OPT_ARG" ;; list) _vpn_list ;; "") _vpn_list ;; *) _vpn_new "$OPT_ACTION" ;; esac ;; peer) case "$OPT_ACTION" in new) _peer_new "$OPT_ARG" ;; rm) _peer_rm "$OPT_ARG" ;; list) _peer_list ;; "") _peer_list ;; *) _print_help ;; esac ;; *) _print_help ;; esac