fix: wireguard port/subnet/domain propagate to peer configs and new peer IPs
Backend: - wireguard_manager: _get_configured_port/address/network() read from wg0.conf instead of module-level constants; get_split_tunnel_ips() derives VPN network from configured Address; get_server_config() returns configured port, dns_ip, split_tunnel_ips, vpn_network - add_peer() and get_peer_config() use configured port (not hardcoded 51820) - _next_peer_ip() derives subnet from wireguard_manager._get_configured_address() so new peers are allocated IPs from the correct VPN range after address change - refresh-ip and check-port API endpoints return configured port, not 51820 - PUT /api/config: when wireguard port/address changes, all peers are marked config_needs_reinstall so users know to re-download tunnel configs - get_peer_config endpoint: uses configured split tunnel IPs (not hardcoded) Frontend: - Peers.jsx: SERVICES domains use live domain from ConfigContext; generateConfig() uses serverConf.dns_ip and serverConf.split_tunnel_ips; vpn_network shown in peer-access description; DNS hint uses live domain; server config loaded at mount time so it is available without re-fetching on every peer action; handleUpdatePeer uses /32 for server-side AllowedIPs (was incorrectly using full/split tunnel CIDRs which the backend rejects) - WireGuard.jsx: generateWireGuardConfig() uses serverConfig.dns_ip, split_tunnel_ips from server-config API; split-tunnel description shows live IPs Tests: 9 new tests in TestWireGuardConfigReads verify all config reads Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -322,5 +322,93 @@ PersistentKeepalive = 30
|
||||
success = self.wg_manager.update_peer_ip('non_existent_key', '10.0.0.9/32')
|
||||
self.assertFalse(success)
|
||||
|
||||
|
||||
class TestWireGuardConfigReads(unittest.TestCase):
|
||||
"""Test that port/address/network are read from wg0.conf, not hardcoded."""
|
||||
|
||||
def setUp(self):
|
||||
self.test_dir = tempfile.mkdtemp()
|
||||
self.data_dir = os.path.join(self.test_dir, 'data')
|
||||
self.config_dir = os.path.join(self.test_dir, 'config')
|
||||
os.makedirs(self.data_dir, exist_ok=True)
|
||||
os.makedirs(self.config_dir, exist_ok=True)
|
||||
patcher = patch.object(WireGuardManager, '_syncconf', return_value=None)
|
||||
self.mock_sync = patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
self.wg = WireGuardManager(self.data_dir, self.config_dir)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.test_dir)
|
||||
|
||||
def _write_wg_conf(self, port=51820, address='10.0.0.1/24', extra=''):
|
||||
conf = (
|
||||
f'[Interface]\n'
|
||||
f'PrivateKey = dummykey\n'
|
||||
f'Address = {address}\n'
|
||||
f'ListenPort = {port}\n'
|
||||
f'{extra}'
|
||||
)
|
||||
cf = self.wg._config_file()
|
||||
os.makedirs(os.path.dirname(cf), exist_ok=True)
|
||||
with open(cf, 'w') as f:
|
||||
f.write(conf)
|
||||
|
||||
def test_get_configured_port_reads_from_wg_conf(self):
|
||||
self._write_wg_conf(port=54321)
|
||||
self.assertEqual(self.wg._get_configured_port(), 54321)
|
||||
|
||||
def test_get_configured_port_fallback_when_no_file(self):
|
||||
# No wg0.conf exists — fall back to DEFAULT_PORT
|
||||
self.assertEqual(self.wg._get_configured_port(), 51820)
|
||||
|
||||
def test_get_configured_address_reads_from_wg_conf(self):
|
||||
self._write_wg_conf(address='10.1.0.1/24')
|
||||
self.assertEqual(self.wg._get_configured_address(), '10.1.0.1/24')
|
||||
|
||||
def test_get_configured_network_derives_from_address(self):
|
||||
self._write_wg_conf(address='10.1.0.1/24')
|
||||
self.assertEqual(self.wg._get_configured_network(), '10.1.0.0/24')
|
||||
|
||||
def test_get_split_tunnel_ips_uses_configured_network(self):
|
||||
self._write_wg_conf(address='10.1.0.1/24')
|
||||
split = self.wg.get_split_tunnel_ips()
|
||||
self.assertIn('10.1.0.0/24', split)
|
||||
self.assertIn('172.20.0.0/16', split)
|
||||
self.assertNotIn('10.0.0.0/24', split)
|
||||
|
||||
def test_get_server_config_uses_configured_port(self):
|
||||
self._write_wg_conf(port=54321)
|
||||
with patch.object(self.wg, 'get_external_ip', return_value='1.2.3.4'):
|
||||
cfg = self.wg.get_server_config()
|
||||
self.assertEqual(cfg['port'], 54321)
|
||||
self.assertIn(':54321', cfg['endpoint'])
|
||||
|
||||
def test_get_server_config_includes_dns_and_split_tunnel(self):
|
||||
self._write_wg_conf(address='10.2.0.1/24')
|
||||
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)
|
||||
self.assertIn('split_tunnel_ips', cfg)
|
||||
self.assertIn('10.2.0.0/24', cfg['split_tunnel_ips'])
|
||||
|
||||
def test_get_peer_config_uses_configured_port_in_endpoint(self):
|
||||
self._write_wg_conf(port=54321)
|
||||
result = self.wg.get_peer_config(
|
||||
peer_name='alice',
|
||||
peer_ip='10.0.0.2',
|
||||
peer_private_key='privkeyalice=',
|
||||
server_endpoint='5.6.7.8',
|
||||
)
|
||||
self.assertIn(':54321', result)
|
||||
self.assertNotIn(':51820', result)
|
||||
|
||||
def test_add_peer_uses_configured_port_in_endpoint(self):
|
||||
self._write_wg_conf(port=54321)
|
||||
self.wg.add_peer('alice', 'pubkeyalice=', '5.6.7.8', '10.0.0.2/32')
|
||||
content = self.wg._read_config()
|
||||
self.assertIn('Endpoint = 5.6.7.8:54321', content)
|
||||
self.assertNotIn(':51820', content)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user