Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added global lock to linux wg quick, fixed race condition when 2 wg interfaces wanted to have the same table number #23

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions src/wg-quick/linux.bash
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ CONFIG_FILE=""
PROGRAM="${0##*/}"
ARGS=( "$@" )

LOCK_DIR_PATH="/var/lock"
mkdir -p "$LOCK_DIR_PATH"

WG_QUICK_LOCK_PATH="${LOCK_DIR_PATH}/wg-quick.lock"

get_lock() {
exec {FD}>"$WG_QUICK_LOCK_PATH" || exit 1
flock -x "$FD" || exit 1
trap "rm -f $WG_QUICK_LOCK_PATH" EXIT
}

cmd() {
echo "[#] $*" >&2
"$@"
Expand Down Expand Up @@ -210,16 +221,22 @@ remove_firewall() {

HAVE_SET_FIREWALL=0
add_default() {
local table line
local proto=-4 iptables=iptables pf=ip
[[ $1 == *:* ]] && proto=-6 iptables=ip6tables pf=ip6

local table
if ! get_fwmark table; then
# We are trying to get next global table number and use it with default route.
# This process should be globaly locked.
get_lock

table=51820
while [[ -n $(ip -4 route show table $table 2>/dev/null) || -n $(ip -6 route show table $table 2>/dev/null) ]]; do
((table++))
done
cmd wg set "$INTERFACE" fwmark $table
fi
local proto=-4 iptables=iptables pf=ip
[[ $1 == *:* ]] && proto=-6 iptables=ip6tables pf=ip6

cmd ip $proto rule add not fwmark $table table $table
cmd ip $proto rule add table main suppress_prefixlength 0
cmd ip $proto route add "$1" dev "$INTERFACE" table $table
Expand All @@ -229,20 +246,26 @@ add_default() {
printf -v nftcmd '%sadd chain %s %s preraw { type filter hook prerouting priority -300; }\n' "$nftcmd" "$pf" "$nftable"
printf -v nftcmd '%sadd chain %s %s premangle { type filter hook prerouting priority -150; }\n' "$nftcmd" "$pf" "$nftable"
printf -v nftcmd '%sadd chain %s %s postmangle { type filter hook postrouting priority -150; }\n' "$nftcmd" "$pf" "$nftable"

local line
while read -r line; do
[[ $line =~ .*inet6?\ ([0-9a-f:.]+)/[0-9]+.* ]] || continue
printf -v restore '%s-I PREROUTING ! -i %s -d %s -m addrtype ! --src-type LOCAL -j DROP %s\n' "$restore" "$INTERFACE" "${BASH_REMATCH[1]}" "$marker"
printf -v nftcmd '%sadd rule %s %s preraw iifname != "%s" %s daddr %s fib saddr type != local drop\n' "$nftcmd" "$pf" "$nftable" "$INTERFACE" "$pf" "${BASH_REMATCH[1]}"
done < <(ip -o $proto addr show dev "$INTERFACE" 2>/dev/null)

printf -v restore '%sCOMMIT\n*mangle\n-I POSTROUTING -m mark --mark %d -p udp -j CONNMARK --save-mark %s\n-I PREROUTING -p udp -j CONNMARK --restore-mark %s\nCOMMIT\n' "$restore" $table "$marker" "$marker"
printf -v nftcmd '%sadd rule %s %s postmangle meta l4proto udp mark %d ct mark set mark \n' "$nftcmd" "$pf" "$nftable" $table
printf -v nftcmd '%sadd rule %s %s premangle meta l4proto udp meta mark set ct mark \n' "$nftcmd" "$pf" "$nftable"

[[ $proto == -4 ]] && cmd sysctl -q net.ipv4.conf.all.src_valid_mark=1

if type -p nft >/dev/null; then
cmd nft -f <(echo -n "$nftcmd")
else
echo -n "$restore" | cmd $iptables-restore -n
fi

HAVE_SET_FIREWALL=1
return 0
}
Expand Down