feat: allow selecting the VPN protocol from the CLI - #27
Open
aislandener wants to merge 1 commit into
Open
Conversation
The CLI always connected with the protocol stored in settings.json and offered no way to change it, so it was effectively locked to the default (WireGuard over UDP). On networks that drop VPN UDP traffic - public hotspots, hotels, some corporate WiFi - the tunnel interface comes up and gets an address, but the WireGuard handshake never gets a reply. The local agent lives inside the tunnel, so it can never answer either, and the connection fails with a generic "Connection failed" message. There was no way to recover from the CLI; the only workaround was hand-editing settings.json. Everything needed was already in place: the api-core registry provides the openvpn and wireguard backends, VPNConnector.connect() takes a protocol argument, and Settings.protocol is already persisted. This only exposes it. protonvpn config set protocol wireguard protonvpn config set protocol openvpn-udp protonvpn config set protocol openvpn-tcp The protocol also shows up in 'protonvpn config list'. Changing the protocol requires an inactive connection, following the same pattern already used by the kill switch command, since the setting only takes effect when the tunnel is established. The protun-* protocols are deliberately left out: they cannot currently be established at all, because the bundled nm-protun.name does not declare supports-safe-private-file-access, which NetworkManager requires for the in-memory connections this client creates. That is tracked separately. OPENVPN_UDP/OPENVPN_TCP move to feature_setting_definitions so the new choices and the existing OpenVPN warning share one definition. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014uK1QX6VfA9kJt43DFubBM
|
hi! will it also be possible to use the Stealth protocol via the CLI with this commit? other protocols are being blocked by so many sites/apps now. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #26.
What this does
Exposes the VPN protocol as a configurable setting, so it can be changed
without hand-editing
settings.json:It also shows up in
protonvpn config list:Why
On a public WiFi that drops VPN UDP traffic,
protonvpn connectalways failed withthe generic
Connection failed. Try connecting to a different server or check your network settings.The tunnel came up and got an address, but the WireGuard handshakenever got a reply:
148 bytes is exactly one WireGuard handshake initiation; two were sent and nothing came
back. TCP/443 to the same server IP worked fine, and arbitrary outbound UDP worked
(STUN on 3478/19302 responded) — the network selectively drops UDP on the ports Proton
uses. Since the local agent lives inside the tunnel, it can never answer, and the CLI
times out.
Because the protocol was not selectable, there was no way to recover from the CLI.
Switching to
openvpn-tcpconnects on that same network.Implementation notes
Everything needed was already in place, so this is mostly wiring:
create_registry()in api-core already registers the openvpn and wireguard backendsVPNConnector.connect()already takes aprotocolargumentSettings.protocolis already persisted tosettings.json_connect()in the controller already passessettings.protocolthroughSo this adds a
ProtocolTypeclick arg type and aPROTOCOL_FEATURE, and registers theconfig set protocolcommand.get_feature_setting/save_feature_settingworkunchanged via
setting_path="protocol".Changing the protocol requires an inactive connection, following the same pattern the
kill switch command already uses — the setting only takes effect when the tunnel is
established, and
save_settings()otherwise waits for aCONNECTEDevent that aprotocol change never produces.
OPENVPN_UDP/OPENVPN_TCPmoved fromserver.pyintofeature_setting_definitions.pyso the new choices and the existing OpenVPN warning share one definition rather than
duplicating the strings.
On the protun-* protocols
protun-udp,protun-tcp,protun-tlsandprotun-smartare deliberately notoffered, because they cannot currently be established at all:
The
nm-protun.nameshipped bypython-proton-vpn-api-coredoes not declaresupports-safe-private-file-access=true, which NetworkManager requires for thein-memory connections this client creates (the bundled
nm-openvpn-service.namedoesdeclare it). Adding that key locally makes NetworkManager accept the connection and
nm-protun-servicestart, but it then stops at:because
protun.pyusesSTORE_PRIVATE_KEY_IN_KEYRING = "1"(AGENT_OWNED), soNetworkManager asks a registered secret agent for the private key — and on a desktop
without
nm-applet/plasma-nmnothing answers.That is a separate bug and likely belongs in
python-proton-vpn-api-core. It is worthflagging here because
protun-tcp/protun-tlsare exactly the protocols that wouldbest solve the blocked-UDP case. They can be added to
ProtocolTypein a one-line changeonce they work.
Testing
pytest tests/unit— 271 passed (6 new)flake8 proton/— cleanpylint— 9.95/10; the two remainingR0917inserver.pyare pre-existing andpresent on
stableunchanged--helpoutput,config list, thedisconnect-required guard, case-insensitive values (
OpenVPN-UDP), and that eachvalue is persisted to
settings.jsonNew tests cover the disconnect-required guard (parametrised over connected/disconnected),
persistence of the chosen value, and rejection of unknown protocols. The existing
ALL_FEATURES-driven tests cover the new setting automatically.