fix: thread wg-easy v15's preshared key into the box's wg-quick config
furtka-gateway's wg-easy v15 client (wgeasy_v15.py) generates a PresharedKey per WireGuard client by default, which the server enforces even if the box's own conf omits it — dropping it here breaks the handshake silently. Include it in [Peer] when present; v14 has no preshared_key field at all, so this stays a no-op for that path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3jVwAqESRjPdW9P9nvfem
This commit is contained in:
parent
30ee044657
commit
905845187d
2 changed files with 30 additions and 0 deletions
|
|
@ -39,7 +39,16 @@ def _conf_content(wg: dict) -> str:
|
|||
subnet only), which this module passes through verbatim rather than
|
||||
widening it, so a compromised gateway can't pull the box's other
|
||||
traffic through it.
|
||||
|
||||
`preshared_key` is only present when the gateway's wg-easy is v15
|
||||
(which generates one per client by default and enforces it
|
||||
server-side) — omitted (None/missing) for v14, which has none.
|
||||
Dropping a present preshared key here would break the handshake
|
||||
silently, since the server side would still expect it.
|
||||
"""
|
||||
preshared_key_line = ""
|
||||
if wg.get("preshared_key"):
|
||||
preshared_key_line = f"PresharedKey = {wg['preshared_key']}\n"
|
||||
return (
|
||||
"[Interface]\n"
|
||||
f"PrivateKey = {wg['private_key']}\n"
|
||||
|
|
@ -47,6 +56,7 @@ def _conf_content(wg: dict) -> str:
|
|||
"\n"
|
||||
"[Peer]\n"
|
||||
f"PublicKey = {wg['server_public_key']}\n"
|
||||
f"{preshared_key_line}"
|
||||
f"Endpoint = {wg['endpoint']}\n"
|
||||
f"AllowedIPs = {wg['allowed_ips']}\n"
|
||||
"PersistentKeepalive = 25\n"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,26 @@ def test_conf_content_shape():
|
|||
assert "PersistentKeepalive = 25" in content
|
||||
|
||||
|
||||
def test_conf_content_omits_preshared_key_when_absent():
|
||||
# WG has no "preshared_key" key at all — the v14-gateway shape.
|
||||
content = wireguard._conf_content(WG)
|
||||
assert "PresharedKey" not in content
|
||||
|
||||
|
||||
def test_conf_content_includes_preshared_key_when_present():
|
||||
# v15-gateway shape (see furtka-gateway's wgeasy_v15.py) — the server
|
||||
# enforces this even if the client's own conf omits it, so dropping it
|
||||
# here would break the handshake silently.
|
||||
wg = {**WG, "preshared_key": "cHJlc2hhcmVkLWtleQ=="}
|
||||
content = wireguard._conf_content(wg)
|
||||
assert "PresharedKey = cHJlc2hhcmVkLWtleQ==" in content
|
||||
# Must sit between PublicKey and Endpoint, inside [Peer].
|
||||
peer_section = content.split("[Peer]\n", 1)[1]
|
||||
assert peer_section.index("PublicKey") < peer_section.index(
|
||||
"PresharedKey"
|
||||
) < peer_section.index("Endpoint")
|
||||
|
||||
|
||||
def test_enable_requires_wg_config(tmp_path):
|
||||
with pytest.raises(ValueError, match="wg config is required"):
|
||||
wireguard.set_tunnel_enabled(True, conf_path=tmp_path / "furtka-gw.conf")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue