diff --git a/src/wg-quick/linux.bash b/src/wg-quick/linux.bash index 4193ce58..2a8fa16c 100755 --- a/src/wg-quick/linux.bash +++ b/src/wg-quick/linux.bash @@ -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 "$@" @@ -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 @@ -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 }