If you’ve done any networking configuration on Linux, you probably used iptables
. If you have, you probably know that iptables does not persist rules, and so all your rule mangling is lost on a reboot.
This isn’t exactly a new problem, and so there are many ways to ‘save’ state, the most commonly cited one being iptables-save
to dump the rules to a file:
$ iptables-save > /etc/iptables/rules.v4
and then iptables-restore
to bring them back again, like so:
$ iptables-restore < /etc/iptables/rules.v4
This is the defacto file in Debian/Ubuntu. For RHEL/CentOS, the file is /etc/sysconfig/iptables.
Taking this a step further, netfilter-persistent
is another useful tool (which seems to have been renamed/split from the old iptables-persistent
).
This allows you to write a plugin (i.e. a script) that is called by netfilter-persistent
on certain events.
The possible events are start, restart, reload, force-reload, save, and flush.
The event name - one of the above - is passed as the first argument to any script that is present in /usr/share/netfilter-persistent/plugins.d
.
Simon Richter and Jonathan Wiltshire have a great reference script within netfilter-persistent
that demonstrates what it can do.
If you have an application that requires some rules in iptables
, you simply need to place a similar script in the plugins directory.
#!/bin/sh
# This file is part of netfilter-persistent
# (was iptables-persistent)
# Copyright (C) 2009, Simon Richter <[email protected]>
# Copyright (C) 2010, 2014 Jonathan Wiltshire <[email protected]>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3
# of the License, or (at your option) any later version.
exit 0
set -e
rc=0
load_rules()
{
#load IPv6 rules
if [ ! -f /etc/iptables/rules.v6 ]; then
echo "Warning: skipping IPv6 (no rules to load)"
exit 0
else
ip6tables-restore < /etc/iptables/rules.v6 2> /dev/null
if [ $? -ne 0 ]; then
rc=1
fi
fi
}
save_rules()
{
#save IPv6 rules
#need at least ip6table_filter loaded:
/sbin/modprobe -q ip6table_filter
if [ ! -f /proc/net/ip6_tables_names ]; then
log_action_cont_msg "Warning: skipping IPv6 (no modules loaded)"
elif [ -x /sbin/ip6tables-save ]; then
touch /etc/iptables/rules.v6
chmod 0640 /etc/iptables/rules.v6
ip6tables-save > /etc/iptables/rules.v6
if [ $? -ne 0 ]; then
rc=1
fi
fi
}
flush_rules()
{
if [ ! -f /proc/net/ip6_tables_names ]; then
echo "Warning: skipping IPv6 (no module loaded)"
elif [ -x /sbin/ip6tables ]; then
for param in F Z X; do /sbin/ip6tables -$param; done
for table in $(cat /proc/net/ip6_tables_names)
do
/sbin/ip6tables -t $table -F
/sbin/ip6tables -t $table -Z
/sbin/ip6tables -t $table -X
done
for chain in INPUT FORWARD OUTPUT
do
/sbin/ip6tables -P $chain ACCEPT
done
fi
}
case "$1" in
start|restart|reload|force-reload)
load_rules
;;
save)
save_rules
;;
stop)
# Why? because if stop is used, the firewall gets flushed for a variable
# amount of time during package upgrades, leaving the machine vulnerable
# It's also not always desirable to flush during purge
echo "Automatic flushing disabled, use \"flush\" instead of \"stop\""
;;
flush)
flush_rules
;;
*)
echo "Usage: $0 {start|restart|reload|force-reload|save|flush}" >&2
exit 1
;;
esac
exit $rc