enhancement: refine prepare env script#1793
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors prepare_network_env.sh to initialize firewall state by generating iptables/ip6tables/ipset restore files and applying them via iptables-restore, ip6tables-restore, and ipset restore instead of issuing many individual iptables/ipset commands.
Changes:
- Generate temporary restore files for iptables (v4/v6) and ipset, append baseline FR_* chains/rules/sets into them, and apply via restore utilities.
- Re-add jump hooks from base chains (PREROUTING/POSTROUTING/INPUT/FORWARD/OUTPUT) into the FR_* chains after the restore is applied.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| sudo iptables-restore -w -n "$IPTABLES_RESTORE_FILE" | ||
| sudo ip6tables-restore -w -n "$IP6TABLES_RESTORE_FILE" |
There was a problem hiding this comment.
iptables-restore/ip6tables-restore are invoked without --noflush, which replaces the entire ruleset for the referenced tables. Since the restore files only define FR_* chains, this will flush/delete any pre-existing non-FR rules/chains (e.g., FW_* chains from Firewalla or other system components) and can break the later FW_FORWARD existence checks and any preconfigured firewall rules. If the intent is only to reset FR_* chains, avoid full-table restore (or use a strategy that preserves existing rules, such as --noflush combined with explicit FR_* chain management, or sticking with per-chain -N/-F operations).
| sudo iptables-restore -w -n "$IPTABLES_RESTORE_FILE" | |
| sudo ip6tables-restore -w -n "$IP6TABLES_RESTORE_FILE" | |
| sudo iptables-restore -w -n --noflush "$IPTABLES_RESTORE_FILE" | |
| sudo ip6tables-restore -w -n --noflush "$IP6TABLES_RESTORE_FILE" |
| sudo iptables -w -t nat -C POSTROUTING -j FR_SNAT_TMP &>/dev/null && sudo iptables -w -t nat -D POSTROUTING -j FR_SNAT_TMP &>/dev/null | ||
| sudo iptables -w -t nat -X FR_SNAT_TMP &> /dev/null | ||
| sudo iptables -w -t nat -E FR_SNAT FR_SNAT_TMP &>/dev/null | ||
| if sudo iptables -w -t nat -L FR_SNAT_TMP &>/dev/null; then | ||
| sudo iptables -w -t nat -A POSTROUTING -j FR_SNAT_TMP &>/dev/null |
There was a problem hiding this comment.
The FR_SNAT -> FR_SNAT_TMP rename/jump is intended to keep SNAT active during setup, but the later iptables-restore (without --noflush) will flush the nat table and delete FR_SNAT_TMP (and its POSTROUTING jump) before setup completes. That can reintroduce a SNAT outage during environment preparation; consider applying the restore in a way that preserves FR_SNAT_TMP until new SNAT rules are in place.
scripts/prepare_network_env.sh
Outdated
| IPTABLES_RESTORE_FILE="/tmp/fr_prepare_network_env.iptables.restore.$(date +%s)" | ||
| IP6TABLES_RESTORE_FILE="/tmp/fr_prepare_network_env.ip6tables.restore.$(date +%s)" | ||
| IPSET_RESTORE_FILE="/tmp/fr_prepare_network_env.ipset.restore.$(date +%s)" | ||
|
|
There was a problem hiding this comment.
The restore files are created in /tmp with a predictable name based only on date +%s. If the script runs twice within the same second, filenames can collide; and predictable /tmp paths also increase exposure to symlink/race issues. Consider using mktemp (and a restrictive umask) plus a trap to delete the temp files on exit.
| IPTABLES_RESTORE_FILE="/tmp/fr_prepare_network_env.iptables.restore.$(date +%s)" | |
| IP6TABLES_RESTORE_FILE="/tmp/fr_prepare_network_env.ip6tables.restore.$(date +%s)" | |
| IPSET_RESTORE_FILE="/tmp/fr_prepare_network_env.ipset.restore.$(date +%s)" | |
| umask 077 | |
| IPTABLES_RESTORE_FILE="$(mktemp /tmp/fr_prepare_network_env.iptables.restore.XXXXXX)" || { echo "Failed to create temporary iptables restore file" >&2; exit 1; } | |
| IP6TABLES_RESTORE_FILE="$(mktemp /tmp/fr_prepare_network_env.ip6tables.restore.XXXXXX)" || { echo "Failed to create temporary ip6tables restore file" >&2; exit 1; } | |
| IPSET_RESTORE_FILE="$(mktemp /tmp/fr_prepare_network_env.ipset.restore.XXXXXX)" || { echo "Failed to create temporary ipset restore file" >&2; exit 1; } | |
| trap 'rm -f "$IPTABLES_RESTORE_FILE" "$IP6TABLES_RESTORE_FILE" "$IPSET_RESTORE_FILE"' EXIT |
| sudo ipset restore -! < "$IPSET_RESTORE_FILE" | ||
| sudo iptables-restore -w -n "$IPTABLES_RESTORE_FILE" | ||
| sudo ip6tables-restore -w -n "$IP6TABLES_RESTORE_FILE" | ||
|
|
There was a problem hiding this comment.
The script doesn’t check whether ipset restore / iptables-restore / ip6tables-restore succeed before proceeding to insert jumps into base chains. A restore failure (e.g., due to an unsupported match/module) could leave the system in a partially-initialized state. Consider failing fast on restore errors (explicit exit-code checks or set -e around these critical steps) and logging stderr for troubleshooting.
| sudo ipset restore -! < "$IPSET_RESTORE_FILE" | |
| sudo iptables-restore -w -n "$IPTABLES_RESTORE_FILE" | |
| sudo ip6tables-restore -w -n "$IP6TABLES_RESTORE_FILE" | |
| if ! sudo ipset restore -! < "$IPSET_RESTORE_FILE"; then | |
| echo "ERROR: ipset restore failed from $IPSET_RESTORE_FILE" >&2 | |
| exit 1 | |
| fi | |
| if ! sudo iptables-restore -w -n "$IPTABLES_RESTORE_FILE"; then | |
| echo "ERROR: iptables-restore failed from $IPTABLES_RESTORE_FILE" >&2 | |
| exit 1 | |
| fi | |
| if ! sudo ip6tables-restore -w -n "$IP6TABLES_RESTORE_FILE"; then | |
| echo "ERROR: ip6tables-restore failed from $IP6TABLES_RESTORE_FILE" >&2 | |
| exit 1 | |
| fi |
| sudo ipset restore -! < "$IPSET_RESTORE_FILE" | ||
| sudo iptables-restore -w -n "$IPTABLES_RESTORE_FILE" | ||
| sudo ip6tables-restore -w -n "$IP6TABLES_RESTORE_FILE" |
There was a problem hiding this comment.
Given the switch from incremental iptables commands to full iptables-restore/ipset restore, add automated tests to catch regressions: (1) verify running the script does not delete pre-existing non-FR chains/rules (e.g., a sentinel chain/rule in filter/nat remains), (2) verify FR_SNAT_TMP remains in place during the transition until new SNAT rules are installed, and (3) verify repeated runs are idempotent. This PR introduces multiple failure modes that are hard to spot without an integration-style test harness (e.g., using a network namespace in CI).
0240a76 to
cadddcb
Compare
refine prepare env script with iptables-restre and ipset-restore
refine prepare env script with iptables-restre and ipset-restore