Skip to content

[Bug]: Desktop SSH remote reconnect loop opens many short sessions and trips host UFW LIMIT (locks out other SSH) #11287

Open

Description

@godoppl

Summary

On macOS desktop with a remote SSH environment, T3 Code opens a managed local-forward tunnel and then repeatedly starts new short-lived SSH sessions to the same host (~every 40s, often 3 accepts per burst). That is enough to trip a common ufw limit on port 22, after which all SSH from that client IP gets Connection refused — including a normal interactive ssh outside T3.

Killing T3 Code (Alpha) stopped the live tunnel process. Leaving UFW alone and waiting for the limit window to cool restored normal SSH.

Environment

  • Client: macOS, T3 Code (Alpha) 0.0.40 (com.t3tools.t3code)
  • Remote: Linux (Omarchy), OpenSSH sshd, UFW active with default Omarchy rule:
    • 22/tcp LIMIT IN Anywhere # omarchy-sshd
  • SSH target: host alias dell → 192.168.8.57, user agentr (standard ~/.ssh/config)
  • Remote T3 port: 3773 (matches DEFAULT_REMOTE_PORT / desktop-managed SSH docs)

Observed client process (while T3 was open)

Exact argv from the Mac (matches packages/ssh/src/tunnel.ts startSshTunnel flags):

ssh -o BatchMode=yes -o ConnectTimeout=10 -p 22 \
  -o ExitOnForwardFailure=yes \
  -o ControlMaster=no -o ControlPath=none -o ControlPersist=no \
  -o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
  -n -N -L 52580:127.0.0.1:3773 agentr@dell

Notes:

  • Explicitly disables ControlMaster multiplexing (ControlMaster=no / ControlPath=none).
  • Forwards a dynamic local port → remote 127.0.0.1:3773.

Evidence on the SSH host (Europe/Oslo, 2026-09-11)

1. UFW rate-limit rejects from the Mac (192.168.8.58) about every 20s once the limit is hot

Example:

[UFW LIMIT BLOCK] ... SRC=192.168.8.58 DST=192.168.8.57 ... DPT=22 ... SYN

~29 UFW LIMIT BLOCK lines in the 21:30–21:40 window alone. From the client this surfaces as:

ssh: connect to host 192.168.8.57 port 22: Connection refused

(even though sshd is up and listening on 0.0.0.0:22).

2. Interleaved sshd accepts show reconnect bursts (often 3 publickey accepts in the same second), ~every 40s

21:30:43 Accepted publickey ... from 192.168.8.58
21:30:44 Accepted publickey ... from 192.168.8.58
21:30:44 Accepted publickey ... from 192.168.8.58
21:31:24 Accepted ... (×3)
21:32:24 Accepted ... (×3)
21:33:05 Accepted ... (×3)
21:33:45 Accepted ... (×3)
21:34:25 Accepted ... (×3)
21:35:05 Accepted ... (×3)
21:35:46 Accepted ... (×3)
21:36:26 Accepted ... (×3)

Sessions are very short (open then close almost immediately in several cases), which looks like launch/readiness/probe/reconnect work rather than one stable tunnel.

3. User impact

  • Interactive ssh dell failed with connection refused while T3 was (or had been) reconnecting.
  • Direct ssh agentr@192.168.8.57 could succeed intermittently when under the limit, then fail once LIMIT tripped — same IP/port as the dell Host entry (SSH config was not the bug).
  • After quitting T3, the -L …:3773 process was gone; waiting for the UFW window to cool restored SSH.

Expected

  • One stable SSH control path / tunnel for a connected remote environment.
  • Reconnects should be backoff-bounded and should reuse multiplexing (or otherwise avoid opening multiple new TCP/SSH sessions in a tight loop).
  • A flaky readiness probe should not create a connection storm that DoSes the host’s SSH rate limit and locks out the user’s other tools.

Related

Suggested directions (non-prescriptive)

  • Prefer ControlMaster / multiplexed sessions for launch + tunnel + pairing instead of ControlMaster=no for every SSH child when the host already has a live connection.
  • Back off aggressively when tunnel readiness fails or when ssh returns connection refused / UFW-style rejects.
  • Cap concurrent SSH children per remote target (the code already has a per-target lock; the host still saw multi-accept bursts).
  • Document that ufw limit on 22 + desktop-managed SSH reconnect loops can lock users out of the machine.

Happy to attach more logs if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions