Skip to content

feat(ios): open connections through SSH jump hosts - #3683

Merged
datlechin merged 2 commits into
mainfrom
feat/ios-ssh-jump-hosts
Oct 20, 2026
Merged

datlechin merged 2 commits into
mainfrom
feat/ios-ssh-jump-hosts

Conversation

@datlechin

Copy link
Copy Markdown
Member

Summary

  • iPhone and iPad dial each jump host in order, each session tunneled through the one before it, as the Mac does. Every hop's host key goes through the same prompt as the SSH server's.
  • New Jump Hosts section in the connection form: add, remove, reorder, and an editor per hop (host, port, username, Same Key as SSH Server or its own key from a file or pasted, passphrase). No password for a hop, as on the Mac.
  • Hop keys live in one Keychain item per connection (com.TablePro.jumphostkeys.<id>), synced like the tunnel key and never exported. Duplicate, delete and the sync purge reach them through the connection id. Import Replace keeps a hop's key when host, port and username match.
  • The Mac's hop fields (authMethod, privateKeyPath) round-trip untouched. Save merges with hops another device changed while the form was open.
  • A hop with no key on this device, or a target with no username, is named before anything is dialed. A failed hop names its host.
  • Fixed: an SSH Agent tunnel could not sign in on iOS. It now signs in with a key on the device and keeps the Mac's method.
  • Fixed: a tunnel turned on in the iOS form stayed off on the Mac (enabled was never written).
  • Fixed: a missing SSH username was reported as a wrong password or key.
  • Fixed: a port above 65535 crashed the app at Int32(port), the database port included. It is now refused before dialing.
  • Shared code: SSHJumpRelayFence moves to TableProSSHTransport, the hop relay start to LibSSH2JumpRelay.swift, both compiled by the Mac and iOS apps. Only Mac change: SSHChannelRelay sends with MSG_NOSIGNAL, so a local peer that closed first ends the relay instead of killing the process with SIGPIPE.
Light Dark
Before Before, light Before, dark
After After, light After, dark
Jump host editor Jump host editor, light Jump host editor, dark

Test plan

  • Fail on main, pass here: SSHTunnelFactoryTests (two hops dial, verify and sign in in order; refusals before dialing; Same Key; agent server; out-of-range port), SSHJumpChainTeardownTests, JumpHostCredentialTests, ConnectionFormViewModelJumpHostTests, ConnectionFormEditsTests (hop edits keep Mac fields, merge with another device, enabled written), ConnectionFormViewModelSSHKeyTests, ConnectionErrorClassifierTests, SSHChannelRelayTests (on main the process dies on SIGPIPE), SSHConfigurationTests.
  • Changed on purpose: jumpHostsAreRefused replaced (hops now dial); unsupportedAuthMethodDiscards uses Keyboard Interactive (agent is now supported); prefixesMatchStoredAccounts lists the new prefix; iosCreatedConfigOmitsMacKeys retitled; proxyJumpCleanupDrainsRelayBeforeFree and proxyJumpCompletionDisarmsLateStop move from SSHTunnelErrorTests to SSHJumpRelayFenceTests.
  • Real build on the iOS 27 simulator against three OpenSSH 9.7 containers: two concurrent clients reach the server through two hops, a wrong key on the second hop names that hop, no descriptor or sshd child left after three open and close cycles.
  • Simulator form: a two-hop record from the Mac shows both hops, long-press drag reorders them, Save keeps each hop's Mac fields.
  • Not measured: the iOS 18 runtime (only iOS 27 runtimes installed) and reordering with VoiceOver.

Fixes #3635

Not in this PR

  • Mac teardown closes the final descriptor before stopping hop relays (LibSSH2Tunnel.swift:234-245). Harmless once the send is flagged; order left as is.
  • The top-level sshEnabled the sync mapper writes can go stale.
  • No keyboard-interactive sign-in on iOS.
  • ProxyJump from the Mac's ~/.ssh/config and SSH profiles never reaches iOS.
  • The import analyzer still warns about hop key paths (ConnectionImportAnalyzer.swift:162-164).

@datlechin
datlechin enabled auto-merge (squash) October 20, 2026 02:35
@datlechin
datlechin merged commit 39566df into main Oct 20, 2026
8 checks passed
@datlechin
datlechin deleted the feat/ios-ssh-jump-hosts branch October 20, 2026 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSH jump hosts on iPhone and iPad

1 participant