iptables-restore <iptables_save has a nice atomic property, it'll parse the rules and swap them in all at once (...per-table and COMMIT command, at least). However, Gentoo's /etc/init.d/iptables script, since it was first added in 2004, has this behavior in its reload(): reload() { ... for a in $(cat ${iptables_proc}) ; do ${iptables_bin} --wait ${iptables_lock_wait_time} -F -t $a ... ${iptables_bin} --wait ${iptables_lock_wait_time} -X -t $a ... start start() in turn uses iptables-restore to import the cooked save file, as created by save() or generated externally. As a result, there is a race during which tables have been flushed and deleted, before they have been repopulated by "start". If the default policy is ACCEPT, then that creates a tiny window when shields are down. If the default policy is DROP, then this will drop all traffic during the brief window. As I read its manpage, iptables-restore will take care of flushing any table it is replacing, so manually/explicitly doing so ahead of time should be overkill. ..._except_ if there is a table not referenced in the policy-to-load: suppose it only contains a *filter section for some reason; skipping -F/-X would mean that an existing *raw or *nat for example, are left behind. So, I think we could do something more like: for a in $(cat ${iptables_proc}) ; do grep -q "^\*${a}$" "${iptables_save}" || ${iptables_bin} --wait ${iptables_lock_wait_time} -F -t $a ... As in: we only nuke tables that are not about to be reloaded. Maybe we could test out an atomic_reload() function first if people want to be able to get this exercised w/o changing the default behavior.
See PR for an implementation that only -F/-X's tables that are not listed in the save file, if any. (iptables-save produces empty sections for the main tables even when they have no rules, but we could anticipate some tool cooking up a save file and omitting unused tables.) Note that our systemd files for iptables-restore and ip6tables-restore make no attempt at -F/-X, they simply call *-restore and call it a day.
The bug has been closed via the following commit(s): https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=2198b9a1fd9d0d66b4e0e37915dfcd5c052a1160 commit 2198b9a1fd9d0d66b4e0e37915dfcd5c052a1160 Author: Hank Leininger <hlein@korelogic.com> AuthorDate: 2024-12-03 00:13:17 +0000 Commit: Sam James <sam@gentoo.org> CommitDate: 2024-12-08 07:15:43 +0000 net-firewall/iptables: fix race condition in init script When doing a reload, we only need to flush+delete any table that is _not_ included in what we are about to feed iptables-restore, which does its own flush. Signed-off-by: Hank Leininger <hlein@korelogic.com> Closes: https://bugs.gentoo.org/945762 Closes: https://github.com/gentoo/gentoo/pull/39573 Signed-off-by: Sam James <sam@gentoo.org> net-firewall/iptables/files/iptables-r4.init | 167 ++++++++++++++++++++++ net-firewall/iptables/iptables-1.8.11-r1.ebuild | 176 ++++++++++++++++++++++++ 2 files changed, 343 insertions(+)