wg-config: use ip rules instead of tungate
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									09c726a72f
								
							
						
					
					
						commit
						87abf354f1
					
				@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -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 $?
 | 
					 | 
				
			||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user