public inbox for development@lists.ipfire.org
 help / color / mirror / Atom feed
From: "Peter Müller" <peter.mueller@ipfire.org>
To: "IPFire: Development" <development@lists.ipfire.org>
Subject: [PATCH] initscripts: Always wait for xtables lock when running iptables commands
Date: Sun, 28 Sep 2025 19:51:00 +0000	[thread overview]
Message-ID: <2dbd27d0-92f5-4611-b7c8-a98185601f0e@ipfire.org> (raw)

If not explicitly instructed to do so, iptables by default aborts with
an error message such as

> Can't lock /run/xtables.lock: Resource temporarily unavailable
> Another app is currently holding the xtables lock. Perhaps you want to use the -w option?

if the Xtables lock is still set, i.e., another iptables operation is
currently in progress. This causes iptables commands not to be executed
at all if there are delays during the boot procedure, e.g. due to slow
PPPoE dial-up procedure or similar.

To ensure deterministic behavior, this match modifies initscripts to
always execute iptables to wait for the Xtables lock to be removed, to
make sure iptables rules are installed properly (the "firewall"
initscript is doing so already).

Fixes: #13896 - OpenVPN RW port not opened in firewall after reboot
Signed-off-by: Peter Müller <peter.mueller@ipfire.org>
Tested-by: Peter Müller <peter.mueller@ipfire.org>
---
 src/initscripts/networking/red     |  4 ++--
 src/initscripts/packages/tor       | 10 +++++-----
 src/initscripts/system/dhcp        | 16 ++++++++--------
 src/initscripts/system/openvpn-n2n | 10 +++++-----
 src/initscripts/system/openvpn-rw  |  6 +++---
 src/initscripts/system/wireguard   | 20 ++++++++++----------
 6 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/src/initscripts/networking/red b/src/initscripts/networking/red
index 6d779b365..536fc972c 100644
--- a/src/initscripts/networking/red
+++ b/src/initscripts/networking/red
@@ -162,8 +162,8 @@ case "${1}" in
 
 		elif [ "${TYPE}" == "DHCP" ]; then
 			# Add firewall rules to allow comunication with the dhcp server on red.
-			iptables -A REDINPUT -p tcp --source-port 67 --destination-port 68 -i ${DEVICE} -j ACCEPT
-			iptables -A REDINPUT -p udp --source-port 67 --destination-port 68 -i ${DEVICE} -j ACCEPT
+			iptables --wait -A REDINPUT -p tcp --source-port 67 --destination-port 68 -i ${DEVICE} -j ACCEPT
+			iptables --wait -A REDINPUT -p udp --source-port 67 --destination-port 68 -i ${DEVICE} -j ACCEPT
 
 			echo -n "${DEVICE}" > /var/ipfire/red/iface
 
diff --git a/src/initscripts/packages/tor b/src/initscripts/packages/tor
index 47797265c..eef9682f3 100644
--- a/src/initscripts/packages/tor
+++ b/src/initscripts/packages/tor
@@ -37,19 +37,19 @@ function setup_firewall() {
 	# Allow incoming traffic to Tor relay (and directory) port and
 	# all outgoing TCP connections from Tor user.
 	if [ "${TOR_RELAY_ENABLED}" = "on" -a -n "${TOR_RELAY_PORT}" ]; then
-		iptables -A TOR_INPUT -p tcp --dport "${TOR_RELAY_PORT}" -j ACCEPT
-		iptables -A TOR_OUTPUT -p tcp -m owner --uid-owner tor -j ACCEPT
+		iptables --wait -A TOR_INPUT -p tcp --dport "${TOR_RELAY_PORT}" -j ACCEPT
+		iptables --wait -A TOR_OUTPUT -p tcp -m owner --uid-owner tor -j ACCEPT
 	fi
 
 	if [ "${TOR_RELAY_ENABLED}" = "on" -a -n "${TOR_RELAY_DIRPORT}" ] && [ "${TOR_RELAY_DIRPORT}" -ne 0 ]; then
-		iptables -A TOR_INPUT -p tcp --dport "${TOR_RELAY_DIRPORT}" -j ACCEPT
+		iptables --wait -A TOR_INPUT -p tcp --dport "${TOR_RELAY_DIRPORT}" -j ACCEPT
 	fi
 }
 
 function flush_firewall() {
 	# Flush all rules.
-	iptables -F TOR_INPUT
-	iptables -F TOR_OUTPUT
+	iptables --wait -F TOR_INPUT
+	iptables --wait -F TOR_OUTPUT
 }
 
 case "${1}" in
diff --git a/src/initscripts/system/dhcp b/src/initscripts/system/dhcp
index 61b951658..826cd2dfe 100644
--- a/src/initscripts/system/dhcp
+++ b/src/initscripts/system/dhcp
@@ -28,10 +28,10 @@ eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
 eval $(/usr/local/bin/readhash /var/ipfire/dhcp/settings)
 
 function flush_chains() {
-	iptables -F DHCPGREENINPUT
-	iptables -F DHCPGREENOUTPUT
-	iptables -F DHCPBLUEINPUT
-	iptables -F DHCPBLUEOUTPUT
+	iptables --wait -F DHCPGREENINPUT
+	iptables --wait -F DHCPGREENOUTPUT
+	iptables --wait -F DHCPBLUEINPUT
+	iptables --wait -F DHCPBLUEOUTPUT
 }
 
 case "$1" in
@@ -41,14 +41,14 @@ case "$1" in
 		if [ -n "${GREEN_DEV}" -a -e "/var/ipfire/dhcp/enable_green" ]; then
 			LISTEN_INTERFACES+=" ${GREEN_DEV}"
 
-			iptables -A DHCPGREENINPUT  -i "${GREEN_DEV}" -j DHCPINPUT
-			iptables -A DHCPGREENOUTPUT -o "${GREEN_DEV}" -j DHCPOUTPUT
+			iptables --wait -A DHCPGREENINPUT  -i "${GREEN_DEV}" -j DHCPINPUT
+			iptables --wait -A DHCPGREENOUTPUT -o "${GREEN_DEV}" -j DHCPOUTPUT
 		fi
 		if [ -n "${BLUE_DEV}" -a -e "/var/ipfire/dhcp/enable_blue" ]; then
 			LISTEN_INTERFACES+=" ${BLUE_DEV}"
 
-			iptables -A DHCPBLUEINPUT  -i "${BLUE_DEV}" -j DHCPINPUT
-			iptables -A DHCPBLUEOUTPUT -o "${BLUE_DEV}" -j DHCPOUTPUT
+			iptables --wait -A DHCPBLUEINPUT  -i "${BLUE_DEV}" -j DHCPINPUT
+			iptables --wait -A DHCPBLUEOUTPUT -o "${BLUE_DEV}" -j DHCPOUTPUT
 		fi
 
 		boot_mesg "Starting DHCP Server..."
diff --git a/src/initscripts/system/openvpn-n2n b/src/initscripts/system/openvpn-n2n
index 985398379..f6d554eaf 100644
--- a/src/initscripts/system/openvpn-n2n
+++ b/src/initscripts/system/openvpn-n2n
@@ -63,10 +63,10 @@ update_firewall_rules() {
 	local local_address
 
 	# Flush the block chain
-	iptables -F OVPNBLOCK
+	iptables --wait -F OVPNBLOCK
 
 	# Flush the NAT chain
-	iptables -t nat -F OVPNNAT
+	iptables --wait -t nat -F OVPNNAT
 
 	local IFS=','
 
@@ -85,10 +85,10 @@ update_firewall_rules() {
 		fi
 
 		# Open port
-		iptables -A OVPNINPUTN2N -p "${proto}" --dport "${port}" -j ACCEPT
+		iptables --wait -A OVPNINPUTN2N -p "${proto}" --dport "${port}" -j ACCEPT
 
 		# Block all communication from transfer networks
-		iptables -A OVPNBLOCK -s "${transfer_subnet}" -j DROP
+		iptables --wait -A OVPNBLOCK -s "${transfer_subnet}" -j DROP
 
 		# Calculate NAT addresses
 		transfer_address="$(calculate_transfer_address "${transfer_subnet}" "${role}")"
@@ -96,7 +96,7 @@ update_firewall_rules() {
 
 		# NAT all outgoing connections away from the transfer net
 		if [ -n "${transfer_address}" -a -n "${local_address}" ]; then
-			iptables -t nat -A OVPNNAT -s "${transfer_address}" \
+			iptables --wait -t nat -A OVPNNAT -s "${transfer_address}" \
 				-j SNAT --to-source "${local_address}"
 		fi
 	done < /var/ipfire/ovpn/ovpnconfig
diff --git a/src/initscripts/system/openvpn-rw b/src/initscripts/system/openvpn-rw
index 6359d0d08..d506c8ebd 100644
--- a/src/initscripts/system/openvpn-rw
+++ b/src/initscripts/system/openvpn-rw
@@ -38,10 +38,10 @@ case "${1}" in
 		modprobe tun &>/dev/null
 
 		# Flush all firewall rules
-		iptables -F OVPNINPUTRW
+		iptables --wait -F OVPNINPUTRW
 
 		# Open the port
-		iptables -A OVPNINPUTRW \
+		iptables --wait -A OVPNINPUTRW \
 			-p "${DPROTOCOL}" --dport "${DDEST_PORT}" -j ACCEPT
 
 		boot_mesg "Starting OpenVPN Roadwarrior Server..."
@@ -60,7 +60,7 @@ case "${1}" in
 		killproc /usr/sbin/openvpn
 
 		# Flush all firewall rules
-		iptables -F OVPNINPUTRW
+		iptables --wait -F OVPNINPUTRW
 		;;
 
 	restart)
diff --git a/src/initscripts/system/wireguard b/src/initscripts/system/wireguard
index caaa69cb9..ead1cdce8 100644
--- a/src/initscripts/system/wireguard
+++ b/src/initscripts/system/wireguard
@@ -216,7 +216,7 @@ generate_config() {
 			ip addr add "${local_address}" dev "${intf}"
 
 			# Apply MASQUERADE
-			iptables -t nat -A WGNAT -o "${intf}" -j MASQUERADE
+			iptables --wait -t nat -A WGNAT -o "${intf}" -j MASQUERADE
 		fi
 
 		echo "[Interface]"
@@ -230,7 +230,7 @@ generate_config() {
 			echo "ListenPort = ${port}"
 
 			# Open the port
-			iptables -A WGINPUT -p udp --dport "${port}" -j ACCEPT
+			iptables --wait -A WGINPUT -p udp --dport "${port}" -j ACCEPT
 		fi
 
 		echo "[Peer]"
@@ -285,7 +285,7 @@ generate_config() {
 		# Set blocking rules
 		for local_subnet in ${local_subnets//|/ }; do
 			for remote_subnet in ${remote_subnets//|/ }; do
-				iptables -I WGBLOCK \
+				iptables --wait -I WGBLOCK \
 					-s "${remote_subnet}" -d "${local_subnet}" -j RETURN
 			done
 		done
@@ -297,23 +297,23 @@ generate_config() {
 
 reload_firewall() {
 	# Flush all previous rules
-	iptables -F WGINPUT
-	iptables -t nat -F WGNAT
+	iptables --wait -F WGINPUT
+	iptables --wait -t nat -F WGNAT
 
 	if [ "${ENABLED}" = "on" ]; then
-		iptables -A WGINPUT -p udp --dport "${PORT}" -j ACCEPT
+		iptables --wait -A WGINPUT -p udp --dport "${PORT}" -j ACCEPT
 	fi
 
-	iptables -F WGBLOCK
+	iptables --wait -F WGBLOCK
 
 	# Don't block any traffic from Roadwarrior peers
 	if [ -n "${CLIENT_POOL}" ]; then
-		iptables -A WGBLOCK -s "${CLIENT_POOL}" -i wg0 -j RETURN
-		iptables -A WGBLOCK -d "${CLIENT_POOL}" -o wg0 -j RETURN
+		iptables --wait -A WGBLOCK -s "${CLIENT_POOL}" -i wg0 -j RETURN
+		iptables --wait -A WGBLOCK -d "${CLIENT_POOL}" -o wg0 -j RETURN
 	fi
 
 	# Block all other traffic
-	iptables -A WGBLOCK -j REJECT --reject-with icmp-admin-prohibited
+	iptables --wait -A WGBLOCK -j REJECT --reject-with icmp-admin-prohibited
 
 	# Flush any custom routes
 	ip route flush table wg 2>/dev/null
-- 
2.51.0


                 reply	other threads:[~2025-09-28 19:51 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2dbd27d0-92f5-4611-b7c8-a98185601f0e@ipfire.org \
    --to=peter.mueller@ipfire.org \
    --cc=development@lists.ipfire.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox