#!/bin/bash set -euo pipefail _="${DEBUG:=}" _="${GOW_IP_DELAY:=0}" ip_hook() { ip "$@" sleep "$GOW_IP_DELAY" } strstrip() { sed -E -e 's/^\s*//' -e 's/\s*$//' } create_br() { local name name="$1" $DEBUG ip link add "$name" type bridge } create_gre() { local name local_ip remote_ip name="$1" local_ip="$(sed 's_/.*$__' <<< "$2")" remote_ip="$(sed 's_/.*$__' <<< "$3")" $DEBUG ip_hook link add "$name" type gretap local "$local_ip" remote "$remote_ip" $DEBUG ip_hook link set up "$name" } add_gre_to_br() { local br_name gre_name br_name="$1" gre_name="$2" $DEBUG ip_hook link set "$gre_name" master "$br_name" } finish_br() { local name local_ip name="$1" local_ip="$2" $DEBUG ip_hook addr add "$local_ip" dev "$name" $DEBUG ip_hook link set up "$name" } read_wg_conf() { local filepath local local_ip remote_ips mode line filepath="$1" local_ip= remote_ips= mode= while read -r line; do line="$(strstrip <<< "$line")" if [[ "$line" = '[Interface]' ]]; then mode=interface continue elif [[ "$line" = '[Peer]' ]]; then mode=peer continue fi if [[ "$mode" = 'interface' ]] && [[ "$line" =~ ^Address\ *=\ * ]]; then local_ip="$(awk -F= '{print $2}' <<< "$line" | strstrip)" elif [[ "$mode" = 'peer' ]] && [[ "$line" =~ ^AllowedIPs\ *=\ * ]]; then remote_ips="$remote_ips $(awk -F= '{print $2}' <<< "$line" | strstrip)" fi done < "$filepath" remote_ips="$(strstrip <<< "$remote_ips")" echo "$local_ip" echo "$remote_ips" } create_networks() { local wg_name local_ip local_ip_trans remote_ips local br_name n wg_name="$1" local_ip="$2" local_ip_trans="$3" remote_ips="$4" br_name="${wg_name}br1" n=1 create_br "$br_name" for remote_ip in $remote_ips ; do create_gre "${wg_name}gre$n" "$local_ip" "$remote_ip" add_gre_to_br "$br_name" "${wg_name}gre$n" n=$((n+1)) done finish_br "$br_name" "$local_ip_trans" } up() { local filepath translation_filepath local r local_ip remote_ips local_ip_trans filepath="$1" translation_filepath= if [[ "$filepath" =~ .*/.* ]]; then # path, not a name, leave as is : else if [[ $# -eq 1 ]]; then translation_filepath="$filepath" fi filepath="/etc/wireguard/$filepath.conf" fi if [[ -z "$translation_filepath" ]]; then translation_filepath="$2" fi if [[ "$translation_filepath" =~ .*/.* ]]; then # path, not a name, leave as is : else translation_filepath="/etc/gre-on-wg/$translation_filepath.conf" fi r="$(read_wg_conf "$filepath")" local_ip="$(head -n1 <<< "$r")" remote_ips="$(tail -n1 <<< "$r")" unset r local_ip_trans="$(grep -E "$(sed 's_\._\\._g' <<< "$local_ip")" "$translation_filepath" | awk '{print $2}')" create_networks "$(basename --suffix='.conf' "$filepath")" "$local_ip" "$local_ip_trans" "$remote_ips" } down() { local filepath local wg_name link filepath="$1" if [[ "$filepath" =~ .*/.* ]]; then # path, not a name, leave as is : else filepath="/etc/wireguard/$filepath.conf" fi wg_name="$(basename --suffix=.conf "$filepath")" for link in $(ip_hook link list | grep -Eo '^[0-9]+:\s+'"$wg_name"'[^:@]+' | sed -E 's/[0-9]+:\s+//' | tac); do $DEBUG ip_hook link del "$link" done } "$@"