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 ?= DESTDIR ?=
SBINDIR ?= $(PREFIX)/sbin SBINDIR ?= $(PREFIX)/sbin
SCRIPTS := wg-config tungate
all: 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:
@install -v -m0755 -D -t$(DESTDIR)$(SBINDIR) $(SCRIPTS) @install -v -m0755 -D -t$(DESTDIR)$(SBINDIR) wg-config
.PHONY: all install .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, 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. pre_del, and post_del, which will be called at their respective times.
== Basic Example ==
== Helper Tool == This basic example might be used by a server.
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 ==
/etc/wireguard/wg-server.conf: /etc/wireguard/wg-server.conf:
@ -83,36 +75,11 @@ Run at startup:
Run at shutdown: Run at shutdown:
# wg-config del wgserver0 --env-file=/etc/wireguard/wg-server.env # 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 == == 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: /etc/wireguard/wg-vpn-gateway.env:
CONFIG_FILE_CONTENTS=" 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 # wg-config add wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env
Run to flip off the VPN: Run to flip off the VPN:
# wg-config del wgvpn0 --env-file=/etc/wireguard/wg-vpn-gateway.env # 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() { unwind() {
set +e 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 exit
} }
@ -26,6 +26,9 @@ add_if() {
del_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; } [[ -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" cmd ip link delete dev "$INTERFACE"
} }
@ -38,23 +41,20 @@ add_addr() {
} }
add_route() { 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() { add_default() {
if [[ $1 == ::/0 ]]; then [[ $(join <(wg show "$INTERFACE" allowed-ips) <(wg show "$INTERFACE" endpoints)) =~ .*\ ${1//./\\.}\ ([0-9.:a-f]+):[0-9]+$ ]] && local endpoint="${BASH_REMATCH[1]}"
echo "tungate: does not yet support IPv6, skipping ::/0" >&2 [[ -n $endpoint ]] || return 0
return 0 local table=51820
elif [[ $1 == 0.0.0.0/0 ]]; then while [[ -n $(ip route show table $table) ]]; do ((table++)); done
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')" cmd ip route add "$1" dev "$INTERFACE" table $table
add_route 0/1 cmd ip rule add not to "$endpoint" table $table
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
} }
set_config() { set_config() {
@ -130,16 +130,12 @@ cmd_add() {
done done
up_if up_if
if [[ $AUTO_ROUTE -eq 1 ]]; then 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 for i in $(wg show "$INTERFACE" allowed-ips | grep -Po '(?<=[\t ])[0-9.:/a-f]+' | sort -nr -k 2 -t /); do
if ! add_default "$i" && [[ $(ip route get "$i") != *dev\ $INTERFACE\ * ]]; then [[ $(ip route get "$i" 2>/dev/null) == *dev\ $INTERFACE\ * ]] || add_route "$i"
add_route "$i"
fi
done done
fi fi
for i in "${ADDITIONAL_ROUTES[@]}"; do for i in "${ADDITIONAL_ROUTES[@]}"; do
if ! add_default "$i"; then add_route "$i"
add_route "$i"
fi
done done
[[ $(type -t post_add) != function ]] || post_add [[ $(type -t post_add) != function ]] || post_add
trap - INT TERM EXIT trap - INT TERM EXIT
@ -148,7 +144,6 @@ cmd_add() {
cmd_del() { cmd_del() {
auto_su auto_su
[[ $(type -t pre_del) != function ]] || pre_del [[ $(type -t pre_del) != function ]] || pre_del
killall tungate 2>/dev/null || true
[[ -n $CONFIG_FILE ]] && save_config [[ -n $CONFIG_FILE ]] && save_config
del_if del_if
[[ $(type -t post_del) != function ]] || post_del [[ $(type -t post_del) != function ]] || post_del