Fix ensure_postup_dnat to strip-and-replace all DNAT rules idempotently
_get_dnat_container_ips() used a concatenating docker inspect format that produced "invalid IP" when containers had multiple network attachments. The old ensure_postup_dnat appended rather than replacing, so each update call added a broken duplicate set of rules causing iptables to fail on startup and tear down wg0 entirely. Fix _get_dnat_container_ips to use a space separator in the format string and validate each token as a real IP before accepting it. Rewrite ensure_postup_dnat with _is_dnat_rule() helper: strips every managed DNAT/FORWARD rule (any IP, port 53/80) on semicolon-split and appends a single correct set — fully idempotent regardless of prior state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -565,11 +565,13 @@ class TestWireGuardSysctlAndPortCheck(unittest.TestCase):
|
||||
def test_ensure_postup_dnat_idempotent_when_rules_present(self, mock_run):
|
||||
mock_run.return_value.returncode = 0
|
||||
mock_run.return_value.stdout = '172.20.0.3'
|
||||
self._write_wg_conf_postup(
|
||||
extra_postup='iptables -t nat -A PREROUTING -i %i -p udp --dport 53 -j DNAT --to-destination 172.20.0.3:53'
|
||||
)
|
||||
changed = self.wg.ensure_postup_dnat()
|
||||
self.assertFalse(changed)
|
||||
self._write_wg_conf_postup()
|
||||
# First call: writes all 6 DNAT rules
|
||||
first = self.wg.ensure_postup_dnat()
|
||||
self.assertTrue(first)
|
||||
# Second call: rules already correct, no change
|
||||
second = self.wg.ensure_postup_dnat()
|
||||
self.assertFalse(second)
|
||||
|
||||
def test_ensure_postup_dnat_returns_false_when_no_conf(self):
|
||||
changed = self.wg.ensure_postup_dnat()
|
||||
|
||||
Reference in New Issue
Block a user