mosh

package module
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 1, 2026 License: MIT Imports: 24 Imported by: 0

README

mosh-go

Pure Go mosh. Client and server. No C dependencies, no CGO.

Wire-compatible with the standard C mosh implementation. You can use the Go client against a C mosh-server, or the Go server with a C mosh-client, or go pure Go on both ends.

Implements the full mosh wire protocol: AES-128-OCB3 authenticated encryption, SSP transport with sequencing and retransmission, datagram fragmentation, and the protobuf state sync layer.

Install

go install github.com/unixshells/mosh-go/cmd/mosh@latest
go install github.com/unixshells/mosh-go/cmd/mosh-server@latest
go install github.com/unixshells/mosh-go/cmd/mosh-client@latest

Usage

The mosh command works like the C version -- SSHs to the host, starts mosh-server, connects over UDP:

mosh user@host
mosh -p 2222 user@host            # custom SSH port
mosh -i ~/.ssh/id_ed25519 user@host

Or use the server and client separately:

# On the server:
mosh-server                       # prints MOSH CONNECT <port> <key>
mosh-server -p 60001              # specific port
mosh-server -s /bin/zsh           # specific shell

# On the client:
MOSH_KEY=<key> mosh-client <host> <port>

Library

import mosh "github.com/unixshells/mosh-go"

// Server
srv, _ := mosh.NewServer("/bin/bash", 60000, 60999)
go srv.Serve()
fmt.Println(srv.ConnectLine())

// Client
c, _ := mosh.Dial("192.168.1.5", 60001, "base64key")
c.Resize(80, 24)
c.Send([]byte("ls\n"))
out := c.Recv(time.Second)

Embedding

ServeRW runs the server protocol over an io.ReadWriteCloser instead of a PTY. No shell is spawned -- the caller provides the I/O. This is how latch bridges mosh into its session model:

srv, _ := mosh.NewServer("", 0, 0)
fmt.Println(srv.ConnectLine())
srv.ServeRW(rw, func(cols, rows uint16) {
	// handle resize
})

Compatibility

Tested against the C reference implementation:

Client Server Status
Go Go always tested
Go C mosh-server tested if installed
C mosh-client Go tested if installed

All three pass. Run go test -race ./... to verify.

Latch extensions

The protobuf layer supports optional latch extension fields. Standard mosh clients and servers ignore them (forward-compatible).

  • Capability negotiation (TransportInstruction field 8): bitfield exchanged on every datagram. Both sides AND their caps to get the intersection. No caps = classic mosh mode.
  • Session control (Host/UserInstruction field 9): list, switch, and create latch sessions over the mosh connection.

Files

  • server.go -- server, PTY lifecycle, ServeRW bridge mode
  • client.go -- client, send/recv loops
  • transport.go -- SSP sequencing, timestamps, RTT, retransmission
  • ocb.go -- AES-128-OCB3 (RFC 7253)
  • fragment.go -- datagram fragmentation and reassembly
  • pb.go -- protobuf encoding (transport, host, user, latch extensions)
  • framebuffer.go -- terminal state tracking for diff protocol

Dependencies

creack/pty and the Go standard library.

License

Copyright (c) 2026 Unix Shells. MIT license. See LICENSE.

Documentation

Index

Constants

View Source
const (
	CtrlSessionListReq  uint32 = 1
	CtrlSessionListResp uint32 = 2
	CtrlSessionSwitch   uint32 = 3
	CtrlSessionSwitched uint32 = 4
	CtrlSessionCreate   uint32 = 5
	CtrlSessionCreated  uint32 = 6
)
View Source
const (
	CapSessionControl byte = 1 << 0
)

Variables

This section is empty.

Functions

func BindUDP

func BindUDP(low, high int) (*net.UDPConn, int, error)

BindUDP binds a UDP socket on the first available port in [low, high].

func GenerateKey

func GenerateKey() ([]byte, string, error)

GenerateKey creates a random 128-bit mosh key and returns it as base64.

func MarshalHostMessage

func MarshalHostMessage(instrs []HostInstruction) []byte

MarshalHostMessage encodes a list of HostInstructions as a HostMessage protobuf.

func MarshalUserMessage

func MarshalUserMessage(instrs []UserInstruction) []byte

MarshalUserMessage encodes a list of UserInstructions as a UserMessage protobuf.

Types

type Attr

type Attr struct {
	FG      Color
	BG      Color
	Bold    bool
	Dim     bool
	Italic  bool
	Under   bool
	Blink   bool
	Reverse bool
	Strike  bool
}

Attr holds SGR attributes for a cell.

type Cell

type Cell struct {
	Rune  rune
	Width int // display width (0 for continuation cells)
	Attr  Attr
}

Cell is a single character cell with SGR attributes.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a mosh client. It connects to a mosh server over UDP, handles the SSP transport, and provides send/recv for terminal I/O.

func Dial

func Dial(host string, port int, key string) (*Client, error)

Dial connects to a mosh server over UDP. The key is the base64-encoded mosh key (with or without padding).

func DialConn added in v0.3.0

func DialConn(conn Conn, ocb *OCB) (*Client, error)

DialConn creates a mosh client over an existing datagram connection. Use this with WebTransport or other non-UDP transports.

func DialConnManual added in v0.3.0

func DialConnManual(conn Conn, ocb *OCB) (*Client, error)

DialConnManual creates a mosh client without an internal sendLoop. The caller must call Tick() periodically (e.g., every 8-16ms) to flush outgoing datagrams. Use this in WASM where Go timers are unreliable.

func DialConnRaw added in v0.4.0

func DialConnRaw(conn Conn, ocb *OCB) (*Client, error)

DialConnRaw creates a mosh client with no internal goroutines. The caller must call Tick() for sending AND RecvRaw() for receiving. Use this when the caller needs raw transport diffs (e.g., for framebuffer state tracking in the WASM client).

func (*Client) Close

func (c *Client) Close()

Close shuts down the client.

func (*Client) Recv

func (c *Client) Recv(timeout time.Duration) []byte

Recv reads accumulated terminal output, blocking until output is available or the timeout expires. Returns nil on timeout.

func (*Client) RecvRaw added in v0.4.0

func (c *Client) RecvRaw(timeout time.Duration) []byte

RecvRaw reads one datagram from the connection and processes it through the transport. Returns the raw diff payload, or nil if no complete message was received (timeout, fragment, replay). The caller can use Transport().LastRecvOldNum()/LastRecvNewNum() to get the state numbers for this diff.

func (*Client) Resize

func (c *Client) Resize(cols, rows uint16)

Resize sends a resize to the server.

func (*Client) Send

func (c *Client) Send(keys []byte)

Send sends keystrokes to the server.

func (*Client) Tick added in v0.3.0

func (c *Client) Tick()

Tick flushes pending actions as mosh datagrams. Call this periodically from an external timer (e.g., JS setInterval in WASM) when the internal sendLoop is not used.

func (*Client) Transport

func (c *Client) Transport() *Transport

Transport returns the underlying SSP transport for advanced use (e.g., capability negotiation).

type Color

type Color struct {
	Type  ColorType
	Value uint32 // index (0-255) or RGB packed as 0x00RRGGBB
}

Color represents a terminal color.

type ColorType

type ColorType byte

ColorType identifies the color encoding.

const (
	ColorDefault ColorType = iota
	ColorIndex             // 0-7 normal, 8-15 bright, 16-255 extended
	ColorRGB
)

type Conn added in v0.3.0

type Conn interface {
	// Read reads a datagram. Returns the number of bytes read.
	// Must respect deadlines set by SetReadDeadline.
	Read(b []byte) (int, error)

	// Write writes a datagram.
	Write(b []byte) (int, error)

	// SetReadDeadline sets the deadline for Read calls.
	SetReadDeadline(t time.Time) error

	// Close closes the connection.
	Close() error
}

Conn is a datagram-oriented connection used by the mosh transport. UDP, WebTransport, and other datagram transports implement this interface.

type Fragment

type Fragment struct {
	ID          uint64
	FragmentNum uint16 // 0-based
	Final       bool
	Payload     []byte
}

Fragment is a single mosh datagram fragment.

func Fragmentize

func Fragmentize(id uint64, data []byte) []Fragment

Fragmentize splits a protobuf-encoded message into fragments. Each fragment carries at most maxFragmentPayload bytes.

func UnmarshalFragment

func UnmarshalFragment(data []byte) (Fragment, error)

UnmarshalFragment decodes a fragment from wire format.

func (*Fragment) Marshal

func (f *Fragment) Marshal() []byte

Marshal encodes a fragment to wire format.

type FragmentAssembler

type FragmentAssembler struct {
	// contains filtered or unexported fields
}

FragmentAssembler reassembles fragments into complete messages.

func (*FragmentAssembler) Add

func (a *FragmentAssembler) Add(f Fragment) []byte

Add processes a fragment and returns the reassembled message when complete. Returns nil if the message is not yet complete. Drops fragments from old instruction IDs.

type Framebuffer

type Framebuffer struct {
	W, H   int
	Cells  []Cell
	CurX   int
	CurY   int
	CurVis bool
}

Framebuffer represents a terminal screen state for mosh SSP. The server captures this from the VT emulator; the diff between two Framebuffers produces the ANSI escape sequences sent as HostBytes.

func NewFramebuffer

func NewFramebuffer(w, h int) *Framebuffer

NewFramebuffer allocates a blank framebuffer.

func SnapshotEmulator added in v0.2.0

func SnapshotEmulator(emu *vt.Emulator, cursorVisible bool) *Framebuffer

SnapshotEmulator captures the VT emulator state into a Framebuffer.

func (*Framebuffer) CellAt

func (fb *Framebuffer) CellAt(x, y int) *Cell

CellAt returns a pointer to the cell at (x, y).

func (*Framebuffer) Diff

func (fb *Framebuffer) Diff(old *Framebuffer) []byte

Diff produces the minimal ANSI escape sequence to transform old into fb. This is what goes into HostBytes.hoststring in the mosh protocol.

type HostInstruction

type HostInstruction struct {
	Hoststring []byte
	Width      int32 // 0 = not present
	Height     int32 // 0 = not present
	EchoAckNum int64 // -1 = not present
	Control    *LatchControl
}

HostInstruction is one instruction within a HostMessage. Represents the extension fields of HostBuffers.Instruction:

field 2 → HostBytes { field 4: hoststring }
field 3 → ResizeMessage { field 5: width, field 6: height }
field 7 → EchoAck { field 8: echo_ack_num }

func UnmarshalHostMessage

func UnmarshalHostMessage(data []byte) ([]HostInstruction, error)

UnmarshalHostMessage decodes a HostMessage protobuf into a list of HostInstructions.

type LatchControl

type LatchControl struct {
	Type    uint32
	Payload []byte
}

LatchControl is a latch extension control message.

type OCB

type OCB struct {
	// contains filtered or unexported fields
}

OCB implements AES-128-OCB3 authenticated encryption (RFC 7253).

func NewOCB

func NewOCB(key []byte) (*OCB, error)

NewOCB creates an OCB cipher from a 16-byte AES key.

func NewOCBFromBase64

func NewOCBFromBase64(b64 string) (*OCB, error)

NewOCBFromBase64 creates an OCB cipher from a base64-encoded key.

func (*OCB) Decrypt

func (o *OCB) Decrypt(nonce, ciphertextAndTag []byte) []byte

Decrypt decrypts ciphertext+tag with the given nonce. Returns plaintext or nil if authentication fails.

func (*OCB) Encrypt

func (o *OCB) Encrypt(nonce, plaintext []byte) []byte

Encrypt encrypts plaintext with the given nonce (max 15 bytes). Returns ciphertext followed by tag (16 bytes), matching mosh's wire format.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is a native mosh server. It listens on UDP, runs a shell in a PTY, bridges data through the SSP transport, and diffs terminal framebuffers to produce HostMessage updates for the client.

func NewServer

func NewServer(shell string, portLow, portHigh int) (*Server, error)

NewServer creates a native mosh server. It binds a UDP port, generates a key, and is ready to serve.

func (*Server) Close

func (s *Server) Close()

Close shuts down the server.

func (*Server) ConnectLine

func (s *Server) ConnectLine() string

ConnectLine returns the MOSH CONNECT line that clients parse.

func (*Server) Done

func (s *Server) Done() <-chan struct{}

Done returns a channel that is closed when the server shuts down.

func (*Server) KeyBase64

func (s *Server) KeyBase64() string

KeyBase64 returns the mosh key as a base64 string (22 chars, no padding).

func (*Server) Port

func (s *Server) Port() int

Port returns the UDP port the server is listening on.

func (*Server) Serve

func (s *Server) Serve() error

Serve starts the shell and event loop. Blocks until the session ends.

func (*Server) ServeRW

func (s *Server) ServeRW(rw io.ReadWriteCloser, resize func(cols, rows uint16)) error

ServeRW runs the event loop using an external io.ReadWriteCloser instead of spawning a shell in a PTY. The caller provides terminal I/O through rw and a resize callback. When rw is closed or reaches EOF, the server shuts down.

func (*Server) WriteTo

func (s *Server) WriteTo(w io.Writer) (int64, error)

WriteTo implements io.WriterTo for streaming output to an SSH channel.

type Transport

type Transport struct {
	// contains filtered or unexported fields
}

Transport implements the mosh State Synchronization Protocol (SSP).

It manages sequence numbering, acknowledgements, retransmission timing, and the fragment/encrypt/decrypt pipeline. Both client and server use the same Transport with different direction bits.

The caller provides state diffs (server: terminal output, client: keystrokes) and receives remote state updates.

func NewTransport

func NewTransport(ocb *OCB, isServer bool) *Transport

NewTransport creates a transport. isServer determines direction bits.

func (*Transport) AckedByRemote added in v0.2.1

func (t *Transport) AckedByRemote() uint64

AckedByRemote returns the highest state number the remote has acked.

func (*Transport) ForceNextSend added in v0.2.1

func (t *Transport) ForceNextSend()

ForceNextSend forces the next tick to send, even with no pending diff.

func (*Transport) HasCap

func (t *Transport) HasCap(bit byte) bool

func (*Transport) LastRecv

func (t *Transport) LastRecv() time.Time

LastRecv returns the time of the last received datagram.

func (*Transport) LastRecvNewNum added in v0.4.0

func (t *Transport) LastRecvNewNum() uint64

LastRecvNewNum returns the newNum from the most recently received diff.

func (*Transport) LastRecvOldNum added in v0.4.0

func (t *Transport) LastRecvOldNum() uint64

LastRecvOldNum returns the oldNum from the most recently received diff.

func (*Transport) RTO

func (t *Transport) RTO() time.Duration

RTO returns the current retransmission timeout.

func (*Transport) Recv

func (t *Transport) Recv(wire []byte) []byte

Recv processes an incoming wire datagram. Returns the diff payload if a complete message was reassembled, or nil.

func (*Transport) RemoteCaps

func (t *Transport) RemoteCaps() []byte

func (*Transport) SentNum added in v0.2.1

func (t *Transport) SentNum() uint64

SentNum returns the current sent state number.

func (*Transport) SetCaps

func (t *Transport) SetCaps(caps []byte)

func (*Transport) SetPending

func (t *Transport) SetPending(diff []byte)

SetPending sets the diff payload to send on the next tick.

func (*Transport) ThrowawayNum added in v0.5.0

func (t *Transport) ThrowawayNum() uint64

ThrowawayNum returns the server's throwaway number — states below this are no longer referenced by the server and can be safely pruned.

func (*Transport) Tick

func (t *Transport) Tick() [][]byte

Tick produces outgoing wire datagrams if it's time to send. Returns nil if nothing to send.

type TransportInstruction

type TransportInstruction struct {
	ProtocolVersion uint32
	OldNum          uint64
	NewNum          uint64
	AckNum          uint64
	ThrowawayNum    uint64
	Diff            []byte
	Chaff           []byte
	LatchCaps       []byte
}

TransportInstruction is the outer transport wrapper (TransportBuffers.Instruction).

Field numbers:

1: protocol_version (uint32)
2: old_num          (uint64)
3: new_num          (uint64)
4: ack_num          (uint64)
5: throwaway_num    (uint64)
6: diff             (bytes)
7: chaff            (bytes)

func (*TransportInstruction) Marshal

func (ti *TransportInstruction) Marshal() []byte

func (*TransportInstruction) Unmarshal

func (ti *TransportInstruction) Unmarshal(data []byte) error

type UserInstruction

type UserInstruction struct {
	Keys    []byte
	Width   int32 // 0 = not present
	Height  int32 // 0 = not present
	Control *LatchControl
}

UserInstruction is one instruction within a UserMessage. Represents the extension fields of ClientBuffers.Instruction:

field 2 → Keystroke { field 4: keys }
field 3 → ResizeMessage { field 5: width, field 6: height }

Directories

Path Synopsis
cmd
mosh-wasm command
remote-test command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL