Created
May 19, 2024 04:27
-
-
Save RedDocMD/0cec7ae6f7970a2b03abcf033d771097 to your computer and use it in GitHub Desktop.
OpenBSD Wireguard VPN setup script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -e | |
# Script to setup Wireguard and make this a VPN server | |
# Additionally, create client configurations and remove them | |
function setup() { | |
pushd "/etc/wireguard" | |
# Make key | |
umask 077 | |
wg genkey | tee private.key | wg pubkey > public.key | |
PRIVATE_KEY=$(cat private.key) | |
# Make conf file | |
touch ${WGDEV}.conf | |
echo "[Interface] | |
PrivateKey = ${PRIVATE_KEY} | |
ListenPort = ${PUBLIC_PORT} | |
" > ${WGDEV}.conf | |
cp ${WGDEV}.conf ${WGDEV}.conf.part | |
popd | |
umask 133 | |
# Add forwarding | |
sysctl net.inet.ip.forwarding=1 | |
sysctl net.inet6.ip6.forwarding=1 | |
cp /etc/sysctl.conf /etc/sysctl.conf.old | |
echo "net.inet.ip.forwarding=1" >> /etc/sysctl.conf | |
echo "net.inet6.ip6.forwarding=1" >> /etc/sysctl.conf | |
# Setup packet filtering | |
cp /etc/pf.conf /etc/pf.conf.old | |
echo "pass in on ${WGDEV} | |
pass in inet proto udp from any to any port ${PUBLIC_PORT} | |
pass out on egress inet from (${WGDEV}:network) nat-to (${INTERFACE}:0)" >> /etc/pf.conf | |
pfctl -f /etc/pf.conf | |
# Setup networking | |
echo "inet 10.0.0.1 255.255.255.0 NONE | |
up | |
!/usr/local/bin/wg setconf ${WGDEV} /etc/wireguard/${WGDEV}.conf" > /etc/hostname.${WGDEV} | |
chmod 640 /etc/hostname.${WGDEV} | |
sh /etc/netstart ${WGDEV} | |
# Set status | |
echo "setup 0 ${PUBLIC_IP} ${PUBLIC_PORT}" > ${STATUS_FILE} | |
} | |
function teardown() { | |
sysctl net.inet.ip.forwarding=0 | |
sysctl net.inet6.ip6.forwarding=0 | |
mv /etc/sysctl.conf.old /etc/sysctl.conf | |
mv /etc/pf.conf.old /etc/pf.conf | |
pfctl -f /etc/pf.conf | |
ifconfig wg0 down | |
rm /etc/hostname.${WGDEV} | |
echo "nothing" > ${STATUS_FILE} | |
} | |
function joinConf() { | |
CONF=$1 | |
NEW_CLIENT=$2 | |
CLIENTS=$(tail -n +2 ${STATUS_FILE} | tr "\n" " ") | |
echo $CLIENTS | |
cp ${WGDEV}.conf.part ${CONF} | |
for OLD_CLIENT in ${CLIENTS}; do | |
if [[ "${OLD_CLIENT}" == "" ]]; then | |
continue | |
fi | |
cat ${OLD_CLIENT}.conf.part >> ${CONF} | |
done | |
} | |
function clientExists() { | |
NEW_CLIENT=$2 | |
CLIENTS=$(tail -n +2 ${STATUS_FILE}) | |
for OLD_CLIENT in "${CLIENTS}"; do | |
if [[ ${OLD_CLIENT} == ${NEW_CLIENT} ]]; then | |
return 1 | |
fi | |
done | |
return 0 | |
} | |
function addClient() { | |
local ret=clientExists "$CLIENT" | |
if [[ $ret -eq 1 ]]; then | |
echo "client ${CLIENT} already exists" | |
exit 1 | |
fi | |
pushd /etc/wireguard | |
umask 077 | |
wg genkey | tee ${CLIENT}_private.key | wg pubkey > ${CLIENT}_public.key | |
CLIENT_PRIVATE_KEY=$(cat ${CLIENT}_private.key) | |
CLIENT_PUBLIC_KEY=$(cat ${CLIENT}_public.key) | |
PUBLIC_KEY=$(cat public.key) | |
CLIENT_IP="10.0.0.$((${CLIENT_CNT} + 2))" | |
umask 133 | |
echo "[Peer] | |
PublicKey = ${CLIENT_PUBLIC_KEY} | |
AllowedIPs = ${CLIENT_IP}/32 | |
PersistentKeepalive = 25" > ${CLIENT}.conf.part | |
NEW_CLIENT_CNT=$((${CLIENT_CNT} + 1)) | |
OLD_CLIENTS=$(tail -n +2 ${STATUS_FILE}) | |
echo "setup ${NEW_CLIENT_CNT} ${PUBLIC_IP} ${PUBLIC_PORT}" > ${STATUS_FILE} | |
for OLD_CLIENT in "${OLD_CLIENTS}"; do | |
if [[ ${OLD_CLIENT} == "" ]]; then | |
continue | |
fi | |
echo ${OLD_CLIENT} >> ${STATUS_FILE} | |
done | |
echo ${CLIENT} >> ${STATUS_FILE} | |
TMP_CONF=$(mktemp -t ${WGDEV}.conf.XXXXXX) | |
joinConf ${TMP_CONF} ${CLIENT} | |
mv ${TMP_CONF} ${WGDEV}.conf | |
popd | |
sh /etc/netstart ${WGDEV} | |
echo "[Interface] | |
PrivateKey = ${CLIENT_PRIVATE_KEY} | |
Address = ${CLIENT_IP}/24 | |
[Peer] | |
PublicKey = ${PUBLIC_KEY} | |
Endpoint = ${PUBLIC_IP}:${PUBLIC_PORT} | |
AllowedIPs = 0.0.0.0/0, ::/0" > ${CLIENT}-wg.conf | |
echo "Created ${CLIENT}-wg.conf" | |
} | |
function delClient() { | |
local ret=clientExists $CLIENT | |
if [[ $ret -ne 1 ]]; then | |
echo "client ${CLIENT} doesn't exist" | |
exit 1 | |
fi | |
pushd /etc/wireguard | |
rm ${CLIENT}_private.key | |
rm ${CLIENT}_public.key | |
rm ${CLIENT}.conf.part | |
NEW_CLIENT_CNT=$((${CLIENT_CNT} - 1)) | |
OLD_CLIENTS=$(tail -n +2 ${STATUS_FILE}) | |
echo "setup ${NEW_CLIENT_CNT} ${PUBLIC_IP} ${PUBLIC_PORT}" > ${STATUS_FILE} | |
for OLD_CLIENT in "${OLD_CLIENTS}"; do | |
if [[ ${OLD_CLIENT} == "" || ${OLD_CLIENT} == ${CLIENT} ]]; then | |
continue | |
fi | |
echo ${OLD_CLIENT} >> ${STATUS_FILE} | |
done | |
TMP_CONF=$(mktemp -t ${WGDEV}.conf.XXXXXX) | |
joinConf ${TMP_CONF} ${CLIENT} | |
mv ${TMP_CONF} ${WGDEV}.conf | |
sh /etc/netstart ${WGDEV} | |
popd | |
} | |
if [[ ${EUID} -ne 0 ]]; then | |
echo "Run as root" | |
exit 1 | |
fi | |
STATUS_FILE="/root/wg-status" | |
if [[ ! -f ${STATUS_FILE} ]]; then | |
echo "nothing" > ${STATUS_FILE} | |
fi | |
STATUS=$(head -n 1 ${STATUS_FILE} | cut -d ' ' -f 1) | |
if [[ ! -d "/etc/wireguard" ]]; then | |
mkdir /etc/wireguard | |
echo "Created /etc/wireguard" | |
fi | |
command -v wg &>/dev/null | |
if [[ ! $? ]]; then | |
pkg_add wireguard-tools | |
echo "Installed Wireguard" | |
fi | |
WGDEV=wg0 | |
if [[ $# -lt 1 ]]; then | |
echo "Expected: $0 <cmd>" | |
exit 1 | |
fi | |
CMD=$1 | |
case "${CMD}" in | |
"setup") | |
if [[ ${STATUS} != "nothing" ]]; then | |
echo "Already setup" | |
exit 1 | |
fi | |
if [[ $# != 4 ]]; then | |
echo "Expected: $0 setup <interface> <public-ip> <port>" | |
exit 1 | |
fi | |
INTERFACE="$2" | |
PUBLIC_IP="$3" | |
PUBLIC_PORT="$4" | |
setup | |
;; | |
"teardown") | |
teardown | |
;; | |
"add") | |
if [[ ${STATUS} != "setup" ]]; then | |
echo "First run \"setup\"" | |
exit 1 | |
fi | |
if [[ $# != 2 ]]; then | |
echo "Expected: $0 add <client>" | |
exit 1 | |
fi | |
CLIENT="$2" | |
CLIENT_CNT=$(head -n 1 ${STATUS_FILE} | cut -d ' ' -f 2) | |
PUBLIC_IP=$(head -n 1 ${STATUS_FILE} | cut -d ' ' -f 3) | |
PUBLIC_PORT=$(head -n 1 ${STATUS_FILE} | cut -d ' ' -f 4) | |
addClient | |
;; | |
"del") | |
if [[ ${STATUS} != "setup" ]]; then | |
echo "First run \"setup\"" | |
exit 1 | |
fi | |
CLIENT="$2" | |
CLIENT_CNT=$(head -n 1 ${STATUS_FILE} | cut -d ' ' -f 2) | |
PUBLIC_IP=$(head -n 1 ${STATUS_FILE} | cut -d ' ' -f 3) | |
PUBLIC_PORT=$(head -n 1 ${STATUS_FILE} | cut -d ' ' -f 4) | |
delClient | |
;; | |
*) | |
echo "Invalid cmd" | |
exit 1 | |
;; | |
esac | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment