fix: advertise WireGuard endpoint by domain, and reach linked cells over HTTPS
Unit Tests / test (push) Successful in 9m50s
Unit Tests / test (push) Successful in 9m50s
Three related cell-link/peer-config fixes (the peer and cell endpoints were showing the raw external IP, which confused public-vs-internal addressing): 1. Peer WireGuard configs now embed the cell's effective domain (DDNS/ACME modes) instead of the detected external IP, via the new WireGuardManager.get_advertised_endpoint(). A name that resolves to the public IP survives IP changes and lets the datacenter forward each cell's WG port to the right host. LAN mode still falls back to the IP; an admin wireguard_endpoint override still wins. 2. Cell invites advertise <effective-domain>:<this cell's WG port> (was the external IP + a default/possibly-wrong port), so a remote cell pairs to the right host and port over the public path. 3. Cross-cell peer-sync no longer targets http://<ip>:3000 (the API binds 127.0.0.1 and is unreachable across cells). It targets the remote's Caddy on HTTPS/443 — which the WireGuard server already DNATs over the tunnel — and the initial pre-tunnel invite push goes to https://<endpoint-host>/... ; legacy http://<ip>:3000 link URLs migrate to https on load. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -885,5 +885,60 @@ class TestCellRoutes(unittest.TestCase):
|
||||
mock_route.assert_called_once_with('10.1.0.0/24')
|
||||
|
||||
|
||||
class _FakeCM:
|
||||
"""Minimal config_manager stand-in for get_advertised_endpoint tests."""
|
||||
def __init__(self, identity, effective_domain):
|
||||
self._identity = identity
|
||||
self._effective = effective_domain
|
||||
|
||||
def get_identity(self):
|
||||
return self._identity
|
||||
|
||||
def get_effective_domain(self):
|
||||
return self._effective
|
||||
|
||||
|
||||
class TestAdvertisedEndpoint(unittest.TestCase):
|
||||
"""get_advertised_endpoint prefers domain/override over the raw external IP."""
|
||||
|
||||
def setUp(self):
|
||||
self.test_dir = tempfile.mkdtemp()
|
||||
patcher = patch.object(WireGuardManager, '_syncconf', return_value=None)
|
||||
patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
self.wg = WireGuardManager(self.test_dir, self.test_dir)
|
||||
# Pin the configured port and external IP for deterministic endpoints.
|
||||
self.wg._get_configured_port = MagicMock(return_value=51821)
|
||||
self.wg.get_external_ip = MagicMock(return_value='198.51.100.7')
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.test_dir, ignore_errors=True)
|
||||
|
||||
def test_public_mode_uses_effective_domain_and_own_port(self):
|
||||
cm = _FakeCM({'domain_mode': 'pic_ngo'}, 'alice.pic.ngo')
|
||||
self.assertEqual(self.wg.get_advertised_endpoint(cm), 'alice.pic.ngo:51821')
|
||||
|
||||
def test_lan_mode_falls_back_to_external_ip(self):
|
||||
cm = _FakeCM({'domain_mode': 'lan'}, 'cell')
|
||||
self.assertEqual(self.wg.get_advertised_endpoint(cm), '198.51.100.7:51821')
|
||||
|
||||
def test_admin_override_wins(self):
|
||||
cm = _FakeCM({'domain_mode': 'pic_ngo', 'wireguard_endpoint': 'vpn.example.com'}, 'alice.pic.ngo')
|
||||
self.assertEqual(self.wg.get_advertised_endpoint(cm), 'vpn.example.com:51821')
|
||||
|
||||
def test_override_with_explicit_port_kept(self):
|
||||
cm = _FakeCM({'domain_mode': 'lan', 'wireguard_endpoint': 'vpn.example.com:7777'}, 'cell')
|
||||
self.assertEqual(self.wg.get_advertised_endpoint(cm), 'vpn.example.com:7777')
|
||||
|
||||
def test_none_when_no_domain_and_no_external_ip(self):
|
||||
self.wg.get_external_ip = MagicMock(return_value=None)
|
||||
cm = _FakeCM({'domain_mode': 'lan'}, 'cell')
|
||||
self.assertIsNone(self.wg.get_advertised_endpoint(cm))
|
||||
|
||||
def test_public_mode_without_domain_falls_back_to_ip(self):
|
||||
cm = _FakeCM({'domain_mode': 'cloudflare'}, '')
|
||||
self.assertEqual(self.wg.get_advertised_endpoint(cm), '198.51.100.7:51821')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user