fix: embed DNAT rules in wg0.conf PostUp for persistence + fix dns_ip in server config
DNAT rules applied via docker exec are lost whenever wg-easy reloads the WireGuard interface (PostDown flushes the nat table then PostUp only re-adds static rules). Fix: embed DNS (port 53) and service (port 80) DNAT rules directly in wg0.conf PostUp/PostDown so they reapply on every interface restart. ensure_postup_dnat() patches existing configs on startup. get_server_config() now returns the WG server IP (e.g. 10.0.0.1) for dns_ip instead of the cell-dns container IP (172.20.0.3). This makes the value consistent with what get_peer_config() writes into the .conf file, and fixes the stale hint text in Peers.jsx and WireGuard.jsx. UI: fallback dns_ip changed from 172.20.0.3 to 10.0.0.1; split-tunnel fallback drops the 172.20.0.0/16 stale range. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -434,6 +434,8 @@ class TestWireGuardConfigReads(unittest.TestCase):
|
||||
with patch.object(self.wg, 'get_external_ip', return_value='1.2.3.4'):
|
||||
cfg = self.wg.get_server_config()
|
||||
self.assertIn('dns_ip', cfg)
|
||||
# dns_ip must be the WG server IP, not the container IP
|
||||
self.assertEqual(cfg['dns_ip'], '10.2.0.1')
|
||||
self.assertIn('split_tunnel_ips', cfg)
|
||||
self.assertIn('10.2.0.0/24', cfg['split_tunnel_ips'])
|
||||
|
||||
@@ -486,6 +488,70 @@ class TestWireGuardSysctlAndPortCheck(unittest.TestCase):
|
||||
self.assertIn('FORWARD -i %i -j DROP', cfg)
|
||||
self.assertNotIn('FORWARD -i %i -j ACCEPT', cfg)
|
||||
|
||||
def test_generate_config_includes_dns_dnat_in_postup(self):
|
||||
cfg = self.wg.generate_config()
|
||||
self.assertIn('--dport 53 -j DNAT', cfg)
|
||||
self.assertIn('--dport 80 -j DNAT', cfg)
|
||||
|
||||
def test_generate_config_postdown_removes_dnat(self):
|
||||
cfg = self.wg.generate_config()
|
||||
postdown_line = [l for l in cfg.splitlines() if l.startswith('PostDown')][0]
|
||||
self.assertIn('--dport 53 -j DNAT', postdown_line)
|
||||
self.assertIn('--dport 80 -j DNAT', postdown_line)
|
||||
|
||||
# ── ensure_postup_dnat ────────────────────────────────────────────────────
|
||||
|
||||
def _write_wg_conf_postup(self, address='10.0.0.1/24', extra_postup=''):
|
||||
import os
|
||||
wg_dir = os.path.join(self.test_dir, 'wireguard', 'wg_confs')
|
||||
os.makedirs(wg_dir, exist_ok=True)
|
||||
conf_path = os.path.join(wg_dir, 'wg0.conf')
|
||||
postup = (
|
||||
'iptables -A FORWARD -i %i -j DROP; '
|
||||
'iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE'
|
||||
)
|
||||
if extra_postup:
|
||||
postup += f'; {extra_postup}'
|
||||
postdown = (
|
||||
'iptables -D FORWARD -i %i -j DROP; '
|
||||
'iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE'
|
||||
)
|
||||
content = (
|
||||
'[Interface]\n'
|
||||
f'Address = {address}\n'
|
||||
f'PostUp = {postup}\n'
|
||||
f'PostDown = {postdown}\n'
|
||||
)
|
||||
with open(conf_path, 'w') as f:
|
||||
f.write(content)
|
||||
return conf_path
|
||||
|
||||
@patch('subprocess.run')
|
||||
def test_ensure_postup_dnat_adds_rules_when_missing(self, mock_run):
|
||||
mock_run.return_value.returncode = 0
|
||||
mock_run.return_value.stdout = '172.20.0.3'
|
||||
self._write_wg_conf_postup()
|
||||
changed = self.wg.ensure_postup_dnat()
|
||||
self.assertTrue(changed)
|
||||
with open(self.wg._config_file()) as f:
|
||||
content = f.read()
|
||||
self.assertIn('--dport 53 -j DNAT', content)
|
||||
self.assertIn('--dport 80 -j DNAT', content)
|
||||
|
||||
@patch('subprocess.run')
|
||||
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)
|
||||
|
||||
def test_ensure_postup_dnat_returns_false_when_no_conf(self):
|
||||
changed = self.wg.ensure_postup_dnat()
|
||||
self.assertFalse(changed)
|
||||
|
||||
# ── check_port_open ───────────────────────────────────────────────────────
|
||||
|
||||
@patch('subprocess.run')
|
||||
|
||||
Reference in New Issue
Block a user