#!/usr/bin/env bash set -euo pipefail ## CONSTANTS ## readonly DATA_DIR="/etc/openvpn-data" readonly EASYRSA_DIR="${DATA_DIR}/easyrsa" readonly DATA_SERVER_DIR="${DATA_DIR}/server" readonly DATA_CLIENT_DIR="${DATA_DIR}/client" ## HANDLE EXIT SIGNALS ## trap trap_exit EXIT SIGINT SIGTERM trap_exit(){ if [[ "${openvpn_pid:+x}" ]]; then kill -- $openvpn_pid 2> /dev/null || true q=0 while proc_running $openvpn_pid; do q=$(( q + 1 )) snore 1 if [[ "$q" -ge 15 ]]; then echo "Sending kill to OpenVPN" 1>&2 kill -s KILL -- $openvpn_pid 2> /dev/null || true break fi done fi exit 0 } # # LIB: Efficient sleep (does not create a new process). # snore(){ local IFS [[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:) read ${1:+-t "$1"} -u $_snore_fd || true } # # HELPER: Check whether given pid is running. # # @param $1 Process ID. # # @exit 0: Process is running # 1: Process is not running. # proc_running(){ # try reading state local state_path="/proc/$1/stat" [[ ! -f "$state_path" ]] && return 1 local state state=$(cat "$state_path" 2> /dev/null | cut -d ' ' -f3) || return 1 # parse state case "$state" in R|S|D|Z|W|W|P|I) return 0;; *) return 1;; esac } # # HELPER: Initialize iptables rules. # iptables_init(){ /sbin/iptables -t nat -I POSTROUTING -s 192.168.35.0/24 ! -d 192.168.35.0/24 -j MASQUERADE /sbin/iptables -I INPUT -i tun0 -j ACCEPT /sbin/iptables -I INPUT -p udp --dport 1194 -j ACCEPT /sbin/iptables -I INPUT -p tcp --dport 1194 -j ACCEPT /sbin/iptables -I FORWARD -s 192.168.35.0/24 -j ACCEPT /sbin/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT } # # HELPER: Set up easyrsa. # easyrsa_init(){ ## MAYBE CREATE VARS FILE ## if [[ ! -f "${EASYRSA_DIR}/vars" ]]; then touch "${EASYRSA_DIR}/vars" fi } # # HELPER: Set up server keys. # easyrsa_server_keys_create(){ ## IGNORE IF EXISTING ## [[ -d "${EASYRSA_DIR}/pki" ]] && return 0 ## SET UP CA AND SERVER KEYS (EASYRSA) ## local prev_pwd="$PWD" && cd "$EASYRSA_DIR" # new pki /usr/bin/easyrsa --batch init-pki chmod 755 pki # create ca /usr/bin/easyrsa --batch --days=7300 build-ca nopass # generate server keys /usr/bin/easyrsa --batch --days=7300 build-server-full server nopass # generate crl /usr/bin/easyrsa --batch --days=7300 gen-crl chown nobody:nobody pki/crl.pem # restore pwd cd "$prev_pwd" # create symlinks ln -s ${EASYRSA_DIR}/pki/{ca.crt,private/ca.key,issued/server.crt,private/server.key,crl.pem} "${DATA_SERVER_DIR}" ## OTHER KEYS ## # dh parameters from `IETF RFC 7919` echo "-----BEGIN DH PARAMETERS----- MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS-----" > "${DATA_SERVER_DIR}/dh2048.pem" # tls-crypt key openvpn --genkey secret "${DATA_SERVER_DIR}/tls-crypt.key" } # # HELPER: Set up openvpn server config file. # openvpn_config_init(){ ## IGNORE IF EXISTING ## [[ -f "${DATA_SERVER_DIR}/server.conf" ]] && return 0 ## WRITE SERVER CONFIG ## echo "port 1194 proto udp server 192.168.35.0 255.255.255.0 dev tun user nobody group nogroup topology subnet ca ca.crt cert server.crt key server.key dh dh2048.pem crl-verify crl.pem tls-crypt tls-crypt.key auth SHA512 client-config-dir ${DATA_CLIENT_DIR} ifconfig-pool-persist ipp.txt keepalive 300 1500 persist-key persist-tun push \"dhcp-option DNS 1.1.1.1\" push \"dhcp-option DNS 1.0.0.1\" push \"redirect-gateway def1 bypass-dhcp\" push \"block-outside-dns\" verb 3" > "${DATA_SERVER_DIR}/server.conf" } ## SET UP USED DIRECTORIES ## mkdir -p "$DATA_DIR" mkdir -p "$EASYRSA_DIR" mkdir -p "$DATA_SERVER_DIR" mkdir -p "$DATA_CLIENT_DIR" ## SET UP TUN DEVICE ## mkdir -p /dev/net [[ ! -c /dev/net/tun ]] && mknod /dev/net/tun c 10 200 ## SET UP FW AND ROUTING ## iptables_init ## INITIALIZE CONFIG ## # set up easyrsa easyrsa_init # server keys easyrsa_server_keys_create # server config openvpn_config_init ## RUN OPENVPN SERVER ## /usr/sbin/openvpn --cd "${DATA_SERVER_DIR}" --config "${DATA_SERVER_DIR}/server.conf" & openvpn_pid=$! wait $openvpn_pid