From 27b9b5f6939faaa82579644ec6659cf00edf6f26 Mon Sep 17 00:00:00 2001 From: tavo Date: Tue, 16 Sep 2025 22:42:01 -0600 Subject: [PATCH] bypasser --- README.md | 22 +++ bypasser | 461 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 483 insertions(+) create mode 100644 README.md create mode 100755 bypasser diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e83515 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# bypasser + +Bypass CGNAT using wireguard + +## Usage + +```sh +# Create an example interface +bypasser vpn new myvpn +# This will output the required client configuration +# to connect to the new interface +bypasser peer new myvpn:mypeer + +# This is another VPN, this time with two users. +bypasser vpn new othervpn +bypasser peer new othervpn:u1 # Can ping u2's ip' +bypasser peer new othervpn:u2 # Can ping u1's ip' + +# Then use caddy (or your preferred reverse proxy) to redirect traffic from one +# ip to another. You can also ship a sidecar wireguard container with a client +# config, to expose a docker service to other peers connected to an interface. +``` diff --git a/bypasser b/bypasser new file mode 100755 index 0000000..cf4b56b --- /dev/null +++ b/bypasser @@ -0,0 +1,461 @@ +#!/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_name" ]; then + echo "Error: peer file '$_peer_file' nonexistent" + 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}.1/${BG_WG_PEER_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