wg-config: use ip rules instead of tungate

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2016-12-30 17:50:19 +01:00
parent 09c726a72f
commit 87abf354f1
4 changed files with 58 additions and 108 deletions

View file

@ -2,12 +2,10 @@ PREFIX ?= /usr
DESTDIR ?=
SBINDIR ?= $(PREFIX)/sbin
SCRIPTS := wg-config tungate
all:
@echo "These are shell scripts, so there is nothing to do. Try \"make install\" instead."
@echo "This is a shell script, so there is nothing to do. Try \"make install\" instead."
install:
@install -v -m0755 -D -t$(DESTDIR)$(SBINDIR) $(SCRIPTS)
@install -v -m0755 -D -t$(DESTDIR)$(SBINDIR) wg-config
.PHONY: all install

View file

@ -43,17 +43,9 @@ options described above, and variables that may be declared in ENV_FILE:
Additionally, ENV_FILE may define the bash functions pre_add, post_add,
pre_del, and post_del, which will be called at their respective times.
== Basic Example ==
== Helper Tool ==
tungate is a separate utility, developed originally not explicitly for
WireGuard, which acts as a poor man's way of ensuring 0/1 and 128/1 default
route overrides still work with an endpoint going over the original default
route. It's quite handy, and wg-config makes use of it for dealing with
0.0.0.0/0 routes. At the moment it only supports IPv4, but adding IPv6
should be pretty easy.
== Example ==
This basic example might be used by a server.
/etc/wireguard/wg-server.conf:
@ -83,36 +75,11 @@ Run at startup:
Run at shutdown:
# wg-config del wgserver0 --env-file=/etc/wireguard/wg-server.env
== Advanced Example ==
/etc/wireguard/wg-vpn-gateway.conf:
[Interface]
PrivateKey = 6JiA3fa+NG+x5m6aq7+lxlVaVqVf1mxK6/pDOZdNuXc=
[Peer]
PublicKey = 6NagfTu+s8+TkEKpxX7pNjJuTf4zYtoJme7iQFYIw0A=
AllowedIPs = 0.0.0.0/0
Endpoint = demo.wireguard.io:29912
/etc/wireguard/wg-vpn-gateway.env:
[[ $SUBCOMMAND == add ]] && CONFIG_FILE="$(dirname "${BASH_SOURCE[0]}")/demo-vpn.conf" || true
ADDRESSES=( 10.200.100.2/32 )
post_add() {
printf 'nameserver 10.200.100.1' | cmd resolvconf -a "$INTERFACE" -m 0
}
post_del() {
cmd resolvconf -d "$INTERFACE"
}
Run to flip on the VPN:
# wg-config add wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env
The config file is not overwritten on shutdown, due to the conditional in the env file:
# wg-config del wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env
== Single File Advanced Example ==
This type of configuration might be desirable for a personal access gateway
VPN, connecting to a server like in the example above.
/etc/wireguard/wg-vpn-gateway.env:
CONFIG_FILE_CONTENTS="
@ -138,3 +105,36 @@ Run to flip on the VPN:
# wg-config add wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env
Run to flip off the VPN:
# wg-config del wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env
== Advanced Example ==
This achieves the same as the above, but with an external file. It only sets the
configuration file when the subcommand is add, to prevent it from being overwritten.
The above is much simpler and probably preferred, but this example shows how powerful
the tool can be.
/etc/wireguard/wg-vpn-gateway.conf:
[Interface]
PrivateKey = 6JiA3fa+NG+x5m6aq7+lxlVaVqVf1mxK6/pDOZdNuXc=
[Peer]
PublicKey = 6NagfTu+s8+TkEKpxX7pNjJuTf4zYtoJme7iQFYIw0A=
AllowedIPs = 0.0.0.0/0
Endpoint = demo.wireguard.io:29912
/etc/wireguard/wg-vpn-gateway.env:
[[ $SUBCOMMAND == add ]] && CONFIG_FILE="$(dirname "${BASH_SOURCE[0]}")/demo-vpn.conf" || true
ADDRESSES=( 10.200.100.2/32 )
post_add() {
printf 'nameserver 10.200.100.1' | cmd resolvconf -a "$INTERFACE" -m 0
}
post_del() {
cmd resolvconf -d "$INTERFACE"
}
Run to flip on the VPN:
# wg-config add wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env
The config file is not overwritten on shutdown, due to the conditional in the env file:
# wg-config del wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env

View file

@ -1,43 +0,0 @@
#!/bin/bash
unwind() {
ip route del "$1/32" 2>/dev/null
exit
}
short_route() {
ip route | sed -n "s/$1 \\(.* dev [^ ]\\+\\).*/\\1/p" | head -n 1
}
resolve_ip() {
local filter='/^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$/{p;q;}'
[[ $(sed -n "$filter" <<<"$1") == "$1" ]] && echo "$1" ||
host -t a "$1" | cut -d ' ' -f 4 | sed -n "$filter"
}
set_route() {
local default_route="$(short_route default)"
[[ -n $default_route ]] || { echo "[-] Could not determine default route"; return; }
echo "[+] Adding route for $1 to be $default_route"
ip route del "$1/32" 2>/dev/null
ip route add "$1/32" $default_route
}
check_loop() {
local ip="$(resolve_ip "$1")"
[[ -n $ip ]] || { echo "[-] Could not determine IP of '$1'" && return 1; }
echo "[+] Making sure $ip goes over the default (non-0/1,128/1) route"
set_route "$ip"
trap unwind INT TERM EXIT
while read -r; do
[[ $(short_route "$ip") != "$(short_route default)" ]] && set_route "$ip"
done < <(exec ip monitor route)
}
[[ $# -ne 1 ]] && { echo "Usage: $0 IP|HOST" >&2; exit 1; }
[[ $UID -ne 0 ]] && exec sudo "$(readlink -f "$0")" "$@"
check_loop "$1"
exit $?

View file

@ -15,7 +15,7 @@ auto_su() {
unwind() {
set +e
[[ -n $INTERFACE && -n $(ip link show dev "$INTERFACE" type wireguard 2>/dev/null) ]] && cmd ip link delete dev "$INTERFACE"
[[ -n $INTERFACE && -n $(ip link show dev "$INTERFACE" type wireguard 2>/dev/null) ]] && del_if
exit
}
@ -26,6 +26,9 @@ add_if() {
del_if() {
[[ -n $(ip link show dev "$INTERFACE" type wireguard 2>/dev/null) ]] || { echo "$PROGRAM: \`$INTERFACE' is not a WireGuard interface" >&2; exit 1; }
if [[ $(ip route show table all) =~ .*\ dev\ $INTERFACE\ table\ ([0-9]+)\ .* ]]; then
cmd ip rule delete table ${BASH_REMATCH[1]}
fi
cmd ip link delete dev "$INTERFACE"
}
@ -38,23 +41,20 @@ add_addr() {
}
add_route() {
cmd ip route add "$1" dev "$INTERFACE"
if [[ $1 == 0.0.0.0/0 || $1 == ::/0 ]]; then
add_default "$1"
else
cmd ip route add "$1" dev "$INTERFACE"
fi
}
add_default() {
if [[ $1 == ::/0 ]]; then
echo "tungate: does not yet support IPv6, skipping ::/0" >&2
return 0
elif [[ $1 == 0.0.0.0/0 ]]; then
local endpoint="$(join <(wg show "$INTERFACE" allowed-ips) <(wg show "$INTERFACE" endpoints) | sed -n 's/.* 0\.0\.0\.0\/0.* \([0-9.:\/a-z]\+\):[0-9]\+$/\1/p')"
add_route 0/1
add_route 128/1
killall tungate 2>/dev/null || true
echo "[&] Forking \`tungate' for $endpoint to background" >&2
tungate "$endpoint" >/dev/null 2>&1 & disown
return 0
fi
return 1
[[ $(join <(wg show "$INTERFACE" allowed-ips) <(wg show "$INTERFACE" endpoints)) =~ .*\ ${1//./\\.}\ ([0-9.:a-f]+):[0-9]+$ ]] && local endpoint="${BASH_REMATCH[1]}"
[[ -n $endpoint ]] || return 0
local table=51820
while [[ -n $(ip route show table $table) ]]; do ((table++)); done
cmd ip route add "$1" dev "$INTERFACE" table $table
cmd ip rule add not to "$endpoint" table $table
}
set_config() {
@ -130,16 +130,12 @@ cmd_add() {
done
up_if
if [[ $AUTO_ROUTE -eq 1 ]]; then
for i in $(wg show "$INTERFACE" allowed-ips | grep -Po '(?<=[\t ])[0-9.:/a-z]+' | sort -nr -k 2 -t /); do
if ! add_default "$i" && [[ $(ip route get "$i") != *dev\ $INTERFACE\ * ]]; then
add_route "$i"
fi
for i in $(wg show "$INTERFACE" allowed-ips | grep -Po '(?<=[\t ])[0-9.:/a-f]+' | sort -nr -k 2 -t /); do
[[ $(ip route get "$i" 2>/dev/null) == *dev\ $INTERFACE\ * ]] || add_route "$i"
done
fi
for i in "${ADDITIONAL_ROUTES[@]}"; do
if ! add_default "$i"; then
add_route "$i"
fi
add_route "$i"
done
[[ $(type -t post_add) != function ]] || post_add
trap - INT TERM EXIT
@ -148,7 +144,6 @@ cmd_add() {
cmd_del() {
auto_su
[[ $(type -t pre_del) != function ]] || pre_del
killall tungate 2>/dev/null || true
[[ -n $CONFIG_FILE ]] && save_config
del_if
[[ $(type -t post_del) != function ]] || post_del