Skip to content

Commit 5050316

Browse files
Added global lock to linux wg quick, fixed race condition when 2 wg interfaces wanted to have the same table number. 1. You are creating multiple wg interfaces and starting them in parallel. 2. All wg interfaces is trying to use table number 51820. 3. The first wg interface succeeds, other interfaces fail. What is the problem in wg quick? It is not globaly locking calculation of next table number. How to fix it? We need to add global flock.
1 parent 13f4ac4 commit 5050316

File tree

1 file changed

+26
-3
lines changed

1 file changed

+26
-3
lines changed

src/wg-quick/linux.bash

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ CONFIG_FILE=""
2727
PROGRAM="${0##*/}"
2828
ARGS=( "$@" )
2929

30+
LOCK_DIR_PATH="/var/lock"
31+
mkdir -p "$LOCK_DIR_PATH"
32+
33+
WG_QUICK_LOCK_PATH="${LOCK_DIR_PATH}/wg-quick.lock"
34+
35+
get_lock() {
36+
exec {FD}>"$WG_QUICK_LOCK_PATH" || exit 1
37+
flock -x "$FD" || exit 1
38+
trap "rm -f $WG_QUICK_LOCK_PATH" EXIT
39+
}
40+
3041
cmd() {
3142
echo "[#] $*" >&2
3243
"$@"
@@ -210,16 +221,22 @@ remove_firewall() {
210221

211222
HAVE_SET_FIREWALL=0
212223
add_default() {
213-
local table line
224+
local proto=-4 iptables=iptables pf=ip
225+
[[ $1 == *:* ]] && proto=-6 iptables=ip6tables pf=ip6
226+
227+
local table
214228
if ! get_fwmark table; then
229+
# We are trying to get next global table number and use it with default route.
230+
# This process should be globaly locked.
231+
get_lock
232+
215233
table=51820
216234
while [[ -n $(ip -4 route show table $table 2>/dev/null) || -n $(ip -6 route show table $table 2>/dev/null) ]]; do
217235
((table++))
218236
done
219237
cmd wg set "$INTERFACE" fwmark $table
220238
fi
221-
local proto=-4 iptables=iptables pf=ip
222-
[[ $1 == *:* ]] && proto=-6 iptables=ip6tables pf=ip6
239+
223240
cmd ip $proto rule add not fwmark $table table $table
224241
cmd ip $proto rule add table main suppress_prefixlength 0
225242
cmd ip $proto route add "$1" dev "$INTERFACE" table $table
@@ -229,20 +246,26 @@ add_default() {
229246
printf -v nftcmd '%sadd chain %s %s preraw { type filter hook prerouting priority -300; }\n' "$nftcmd" "$pf" "$nftable"
230247
printf -v nftcmd '%sadd chain %s %s premangle { type filter hook prerouting priority -150; }\n' "$nftcmd" "$pf" "$nftable"
231248
printf -v nftcmd '%sadd chain %s %s postmangle { type filter hook postrouting priority -150; }\n' "$nftcmd" "$pf" "$nftable"
249+
250+
local line
232251
while read -r line; do
233252
[[ $line =~ .*inet6?\ ([0-9a-f:.]+)/[0-9]+.* ]] || continue
234253
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"
235254
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]}"
236255
done < <(ip -o $proto addr show dev "$INTERFACE" 2>/dev/null)
256+
237257
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"
238258
printf -v nftcmd '%sadd rule %s %s postmangle meta l4proto udp mark %d ct mark set mark \n' "$nftcmd" "$pf" "$nftable" $table
239259
printf -v nftcmd '%sadd rule %s %s premangle meta l4proto udp meta mark set ct mark \n' "$nftcmd" "$pf" "$nftable"
260+
240261
[[ $proto == -4 ]] && cmd sysctl -q net.ipv4.conf.all.src_valid_mark=1
262+
241263
if type -p nft >/dev/null; then
242264
cmd nft -f <(echo -n "$nftcmd")
243265
else
244266
echo -n "$restore" | cmd $iptables-restore -n
245267
fi
268+
246269
HAVE_SET_FIREWALL=1
247270
return 0
248271
}

0 commit comments

Comments
 (0)