mirror of
https://github.com/tailscale/tailscale.git
synced 2026-11-03 02:28:29 +09:00
ListenSSH now documents its session trust model and takes an authorization callback. A session is accepted from any peer that the tailnet ACL's TCP rules allow and that resolves with WhoIs. The server performs no SSH client authentication, does not map the peer to a local user, and does not record the session. The application is responsible for what each session does. Set Server.SSHAuthCallback to reject unwanted sessions before they reach Accept. A rejected session is refused at open with exit status 1 and is never yielded to Accept. The callback is plumbed through LocalBackend.ListenSSH and HookListenSSH. With no callback, behavior is unchanged. The listener's SSH server runs session channels only, with no port forwarding. Closing the listener closes the accepted connections. - DisablePTYEmulation runs on every session, so a PTY session passes data through unchanged instead of translating "\n" to "\r\n". The translation corrupted binary data read through the net.Conn interface. Window changes are drained for every session, even when the application never calls Pty, because gliderssh writes window changes from the session request loop and an undrained channel blocks the session's requests. Pty drops window changes when the application is not reading them. - The handshake is bounded by TS_SSH_LOGIN_GRACE_TIME, default 120 seconds, the same as sshd's LoginGraceTime. - TS_SSH_IDLE_TIMEOUT bounds connections with no SSH traffic. It is 0 by default, and zero applies no bound, so quiet but live sessions are not closed by default. Both timeout knobs accept a Go duration such as "90s" or a bare number of seconds. - Accepted sessions wait for Accept in a bounded queue. When the queue is full, further sessions are refused, so an application that stops calling Accept parks only a bounded number of sessions. Updates tailscale/corp#50380 Signed-off-by: James Tucker <james@tailscale.com>