#!/bin/bash # # Generate OpenVPN configs # # Convert 1.2.3.4/24 -> 255.255.255.0 cidr2mask() { local i local subnetmask="" local cidr=${1#*/} local full_octets=$(($cidr/8)) local partial_octet=$(($cidr%8)) for ((i=0;i<4;i+=1)); do if [ $i -lt $full_octets ]; then subnetmask+=255 elif [ $i -eq $full_octets ]; then subnetmask+=$((256 - 2**(8-$partial_octet))) else subnetmask+=0 fi [ $i -lt 3 ] && subnetmask+=. done echo $subnetmask } # Used often enough to justify a function getroute() { echo ${1%/*} $(cidr2mask $1) } usage() { echo "usage: $0 [-d]" echo " -u SERVER_PUBLIC_URL" echo " [-s SERVER_SUBNET]" echo " [-r ROUTE ...]" echo " [-p PUSH ...]" echo " [-n DNS_SERVER ...]" echo echo "optional arguments:" echo " -d Disable NAT routing and default route" echo " -c Enable client-to-client option" echo " -D Do not push dns servers" echo " -N Configure NAT to access external server network" echo " -m Set client MTU" echo " -t Use TAP device (instead of TUN device)" echo " -T Encrypt packets with the given cipher algorithm instead of the default one (tls-cipher)." echo " -C A list of allowable TLS ciphers delimited by a colon (cipher)." echo " -a Authenticate packets with HMAC using the given message digest algorithm (auth)." echo " -z Enable comp-lzo compression." echo " -2 Enable two factor authentication using Google Authenticator." } if [ "$DEBUG" == "1" ]; then set -x fi set -e OVPN_ENV=$OPENVPN/ovpn_env.sh OVPN_SERVER=192.168.255.0/24 OVPN_DEFROUTE=1 OVPN_NAT=0 OVPN_DNS=1 OVPN_DEVICE="tun" OVPN_DEVICEN=0 OVPN_ROUTES=() TMP_ROUTES=() OVPN_PUSH=() TMP_PUSH=() OVPN_DNS_SERVERS=("8.8.8.8" "8.8.4.4") TMP_DNS_SERVERS=() OVPN_TLS_CIPHER='' OVPN_CIPHER='' OVPN_AUTH='' # Import defaults if present [ -r "$OVPN_ENV" ] && source "$OVPN_ENV" # Parse arguments while getopts ":a:C:T:r:s:du:cp:n:DNm:tz2" opt; do case $opt in a) OVPN_AUTH="$OPTARG" ;; C) OVPN_CIPHER="$OPTARG" ;; T) OVPN_TLS_CIPHER="$OPTARG" ;; r) TMP_ROUTES+=("$OPTARG") ;; s) OVPN_SERVER=$OPTARG ;; d) OVPN_DEFROUTE=0 ;; u) OVPN_SERVER_URL=$OPTARG ;; c) OVPN_CLIENT_TO_CLIENT=1 ;; p) TMP_PUSH+=("$OPTARG") ;; n) TMP_DNS_SERVERS+=("$OPTARG") ;; D) OVPN_DNS=0 ;; N) OVPN_NAT=1 ;; m) OVPN_MTU=$OPTARG ;; t) OVPN_DEVICE="tap" ;; z) OVPN_COMP_LZO=1 ;; 2) OVPN_OTP_AUTH=1 ;; \?) set +x echo "Invalid option: -$OPTARG" >&2 usage exit 1 ;; :) set +x echo "Option -$OPTARG requires an argument." >&2 usage exit 1 ;; esac done # if new routes were not defined with -r, use default [ ${#TMP_ROUTES[@]} -gt 0 ] && OVPN_ROUTES=("${TMP_ROUTES[@]}") # if new push directives were not defined with -p, use default [ ${#TMP_PUSH[@]} -gt 0 ] && OVPN_PUSH=("${TMP_PUSH[@]}") # if dns servers were not defined with -n, use google nameservers [ ${#TMP_DNS_SERVERS[@]} -gt 0 ] && OVPN_DNS_SERVERS=("${TMP_DNS_SERVERS[@]}") # Server name is in the form "udp://vpn.example.com:1194" if [[ "$OVPN_SERVER_URL" =~ ^((udp|tcp)://)?([0-9a-zA-Z\.\-]+)(:([0-9]+))?$ ]]; then OVPN_PROTO=${BASH_REMATCH[2]}; OVPN_CN=${BASH_REMATCH[3]}; OVPN_PORT=${BASH_REMATCH[5]}; else set +x echo "Common name not specified, see '-u'" usage exit 1 fi # Apply defaults [ -z "$OVPN_PROTO" ] && OVPN_PROTO=udp [ -z "$OVPN_PORT" ] && OVPN_PORT=1194 [ ${#OVPN_ROUTES[@]} -eq 0 ] && OVPN_ROUTES=("192.168.254.0/24") export OVPN_SERVER OVPN_ROUTES OVPN_DEFROUTE export OVPN_SERVER_URL OVPN_ENV OVPN_PROTO OVPN_CN OVPN_PORT export OVPN_CLIENT_TO_CLIENT OVPN_PUSH OVPN_NAT OVPN_DNS OVPN_MTU OVPN_DEVICE export OVPN_TLS_CIPHER OVPN_CIPHER OVPN_AUTH export OVPN_COMP_LZO export OVPN_OTP_AUTH # Preserve config if [ -f "$OVPN_ENV" ]; then bak_env=$OVPN_ENV.$(date +%s).bak echo "Backing up $OVPN_ENV -> $bak_env" mv "$OVPN_ENV" "$bak_env" fi export | grep OVPN_ > "$OVPN_ENV" conf=$OPENVPN/openvpn.conf if [ -f "$conf" ]; then bak=$conf.$(date +%s).bak echo "Backing up $conf -> $bak" mv "$conf" "$bak" fi cat > "$conf" <> "$conf" [ -n "$OVPN_CIPHER" ] && echo "cipher $OVPN_CIPHER" >> "$conf" [ -n "$OVPN_AUTH" ] && echo "auth $OVPN_AUTH" >> "$conf" [ -n "$OVPN_CLIENT_TO_CLIENT" ] && echo "client-to-client" >> "$conf" [ -n "$OVPN_COMP_LZO" ] && echo "comp-lzo" >> "$conf" [ "$OVPN_DNS" == "1" ] && for i in "${OVPN_DNS_SERVERS[@]}"; do echo "push dhcp-option DNS $i" >> "$conf" done # Append Routes for i in "${OVPN_ROUTES[@]}"; do # If user passed "0" skip this, assume no extra routes [ "$i" = "0" ] && break; echo route $(getroute "$i") >> "$conf" done # Append push commands for i in "${OVPN_PUSH[@]}"; do echo push \"$i\" >> "$conf" done # Optional OTP authentication support if [ -n "$OVPN_OTP_AUTH" ]; then echo -e "\n\n# Enable OTP+PAM for user authentication" >> "$conf" echo "plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn" >> "$conf" fi set +e # Clean-up duplicate configs if diff -q "$bak_env" "$OVPN_ENV" 2>/dev/null; then echo "Removing duplicate back-up: $bak_env" rm -fv "$bak_env" fi if diff -q "$bak" "$conf" 2>/dev/null; then echo "Removing duplicate back-up: $bak" rm -fv "$bak" fi echo "Successfully generated config"