diff options
| author | Brad Fitzpatrick <bradfitz@tailscale.com> | 2026-03-11 01:18:45 +0000 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@tailscale.com> | 2026-03-10 18:37:50 -0700 |
| commit | ac63d82bcc254e6ded4f57a746e5028f6f4fd590 (patch) | |
| tree | fe07d979f68ca76b3dcd188f4120f9f240bd6ccf /tsnet/tsnet.go | |
| parent | f905871fb1b10ae7c75c5850b04e18b7bea09b36 (diff) | |
| download | tailscale-bradfitz/ssh_tsnet.tar.xz tailscale-bradfitz/ssh_tsnet.zip | |
tsnet: add opt-in SSH supportbradfitz/ssh_tsnet
This adds tsnet.Server.ListenSSH which, if the SSH feature is linked,
returns a net.Listener whose Accept yields *tailssh.Session values (as
net.Conn). This lets tsnet apps accept incoming SSH connections to
implement custom TUI applications.
Basic apps can use net.Conn directly (Read/Write/Close). Rich apps
import ssh/tailssh and type-assert for peer identity, PTY, signals,
etc. If feature/ssh isn't imported, ListenSSH returns an error.
Includes a demo guess-the-number game in tsnet/example/ssh-game.
Change-Id: I4e7c3c96afb030cdf4da8f2d8b2253820628129a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Diffstat (limited to 'tsnet/tsnet.go')
| -rw-r--r-- | tsnet/tsnet.go | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/tsnet/tsnet.go b/tsnet/tsnet.go index 4a116cf34..57cd5a004 100644 --- a/tsnet/tsnet.go +++ b/tsnet/tsnet.go @@ -1074,6 +1074,33 @@ func (s *Server) Listen(network, addr string) (net.Listener, error) { return s.listen(network, addr, listenOnTailnet) } +// ListenSSH listens on the Tailscale network for SSH connections at the given +// addr (e.g. ":2222"). The returned listener's Accept method yields net.Conn +// values that are actually *tailssh.Session, providing access to the +// connecting peer's Tailscale identity, PTY information, signals, and more. +// +// Basic applications can use the returned connections as plain net.Conn +// (Read/Write/Close). Applications that need richer SSH semantics should +// type-assert to *tailssh.Session. +// +// SSH support must be linked into the binary by importing +// _ "tailscale.com/feature/ssh". Without that import, ListenSSH returns an +// error. +// +// If s has not been started yet, it will be started. +func (s *Server) ListenSSH(addr string) (net.Listener, error) { + rawLn, err := s.Listen("tcp", addr) + if err != nil { + return nil, err + } + sshLn, err := s.lb.ListenSSH(rawLn, s.logf) + if err != nil { + rawLn.Close() + return nil, err + } + return sshLn, nil +} + // ListenPacket announces on the Tailscale network. // // The network must be "udp", "udp4" or "udp6". The addr must be of the form |
