#!/bin/bash set -e -o pipefail shopt -s extglob CONFIG_FILE="" WG_CONFIG="" INTERFACE="" NETNS="" ADDRESSES=( ) MTU="" DNS=( ) DNS_SEARCH=( ) die() { echo "$0: $*" >&2 exit 1 } parse_options() { local interface_section=0 line key value stripped v CONFIG_FILE="$1" [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf" [[ -e $CONFIG_FILE ]] || die "\`$CONFIG_FILE' does not exist" [[ $CONFIG_FILE =~ (^|/)([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]] || die "The config file must be a valid interface name, followed by .conf" CONFIG_FILE="$(readlink -f "$CONFIG_FILE")" ((($(stat -c '0%#a' "$CONFIG_FILE") & $(stat -c '0%#a' "${CONFIG_FILE%/*}") & 0007) == 0)) || echo "Warning: \`$CONFIG_FILE' is world accessible" >&2 INTERFACE="${BASH_REMATCH[2]}" shopt -s nocasematch while read -r line || [[ -n $line ]]; do stripped="${line%%\#*}" key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}" value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}" [[ $key == "["* ]] && interface_section=0 [[ $key == "[Interface]" ]] && interface_section=1 if [[ $interface_section -eq 1 ]]; then case "$key" in Address) ADDRESSES+=( ${value//,/ } ) continue ;; MTU) MTU="$value" continue ;; DNS) for v in ${value//,/ }; do [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v ) done continue ;; esac fi WG_CONFIG+="$line"$'\n' done < "$CONFIG_FILE" shopt -u nocasematch } add_addr() { local proto=-4 [[ $1 == *:* ]] && proto=-6 ip -n $NETNS $proto address add "$1" dev "$INTERFACE" } up() { ip netns add $NETNS ip link add wgvpn0 type wireguard ip link set wgvpn0 netns $NETNS ip netns exec $NETNS wg setconf wgvpn0 <(echo "$WG_CONFIG") for i in "${ADDRESSES[@]}"; do add_addr "$i" done if [[ -n $MTU ]]; then ip -n $NETNS link set mtu "$MTU" up dev wgvpn0 fi ip -n $NETNS link set lo up ip -n $NETNS link set wgvpn0 up ip -n $NETNS route add default dev wgvpn0 mkdir -p "/etc/netns/$NETNS" { printf 'nameserver %s\n' "${DNS[@]}" [[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}" } | tee "/etc/netns/$NETNS/resolv.conf" > /dev/null } down() { ip -n $NETNS link del wgvpn0 ip netns del $NETNS rm -rf "/etc/netns/$NETNS" } COMMAND="$1" parse_options "$2" NETNS="${3:-$INTERFACE}" echo "netns: $NETNS" INTERFACE="wgvpn0" #TODO un-hardcode this case "$COMMAND" in up) up "$@" ;; down) down "$@" ;; *) echo "Usage: $0 up|down" >&2; exit 1 ;; esac