sshconn

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package sshconn reaches a server over SSH for the channel's minion (docs: contracts/agentless-channels/): it dials the server, directly or through a proxy, logs in with the target's credentials (a key, a password) in turn, checks the host key it presents, and tells what came of it apart: nothing reached, something that is not an SSH server, a host key other than the one given, every login refused.

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New("the connection closed")

ErrClosed is an open given up on because the connection closed.

View Source
var OpenWait = 15 * time.Second

OpenWait bounds opening a channel (a session, the SFTP client): a server answers an open at once, and a connection that went away under one can leave it unanswered for good (x/crypto/ssh: an open queued during a key exchange the connection did not live through).

Functions

func CallFailure

func CallFailure(ctx context.Context, err error, peer string) linkclient.Answer

CallFailure is Failure for a call, which can say what answered when it is not an SSH server: core shows the target "not the minion", with it.

func Failure

func Failure(ctx context.Context, err error) linkclient.Answer

Failure is the answer for a call or an open that met err: a failure of its kind (login and host_key ones an agentless channel's own).

func ReadableKey

func ReadableKey(text string) (string, error)

ReadableKey is a private key as the key parser reads it, from what a paste may have left of it: a one-line box drops a key's line breaks (Chrome) or makes them spaces (Firefox), JSON writes them "\n". The body is base64, which ignores where its lines break, so the block is made again: its markers on lines of their own, the body in lines of 70. A key with headers (the old encrypted PEM: Proc-Type, DEK-Info) is left as it is, as headers that lost their lines cannot be told from the body. The keys people paste by mistake are told apart: a public key, a PuTTY key.

Types

type Conn

type Conn struct {
	SSH *ssh.Client
	// HostKey is the key the server presented; Version the version string
	// it sent (SSH-2.0-OpenSSH_9.6p1 …).
	HostKey ssh.PublicKey
	Version string
	// Peer is the IP address the channel connected to: the session's
	// external address. Empty through a proxy that resolved a name.
	Peer string
	// User is who the connection logged in as; Password the password it
	// logged in with, when the login was a password's (a PLAINTEXT
	// credential's): what a become's sudo asks for unless the task gives
	// another. Never logged.
	User     string
	Password string
	// contains filtered or unexported fields
}

Conn is a server's SSH connection, logged in.

func Dial

Dial reaches the target's server and logs in with its logins in turn, a connection each, until one is taken; each try within the target's connect timeout. Logins say how those tried fared: the refused ones, then the one taken. A refusal (or a credential that does not read) moves on to the next; anything else ends the dial, as the next would meet it too: the server not reached, another host key, not an SSH server.

func (*Conn) Alive

func (c *Conn) Alive(wait time.Duration) bool

Alive reports whether the server answers a keepalive within wait.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the connection, its SFTP client with it; what waits on the server (an open, an SFTP request, a command's output) gives up.

func (*Conn) Closed

func (c *Conn) Closed() <-chan struct{}

Closed is closed once the connection is.

func (*Conn) Dial added in v0.6.0

func (c *Conn) Dial(ctx context.Context, network, address string) (net.Conn, error)

Dial connects to address from the server (network "tcp": direct-tcpip, host:port; "unix": OpenSSH's direct-streamlocal, a socket's path), within ctx: the server connects as slowly as its destination answers, so OpenWait does not bound it, nor does it close the connection. It gives up with the connection too. A refusal is an *ssh.OpenChannelError.

func (*Conn) Fingerprint

func (c *Conn) Fingerprint() string

Fingerprint is the presented host key's SHA-256 fingerprint, as ssh-keygen -l prints it.

func (*Conn) Listen added in v0.6.0

func (c *Conn) Listen(network, address string) (net.Listener, error)

Listen has the server listen at a tcp address (a remote forward, tcpip-forward: on the server's loopback unless its GatewayPorts lets it listen where asked; port 0, one it picks), within OpenWait.

func (*Conn) SFTP

func (c *Conn) SFTP() (*sftp.Client, error)

SFTP is the connection's SFTP client, opened the first time it is asked for, within OpenWait.

func (*Conn) Session

func (c *Conn) Session() (*ssh.Session, error)

Session opens a session (an exec channel), within OpenWait.

func (*Conn) State added in v0.5.0

func (c *Conn) State(key any, create func() any) any

State is the connection's value for key, made by create the first time it is asked for: what outlives each call on a connection kept for the next (a become's elevated shells), and goes with it.

func (*Conn) Wait

func (c *Conn) Wait() error

Wait returns once the connection closed, from either side.

type HostKeyError

type HostKeyError struct{ Presented, Want string }

HostKeyError: the server presented a host key other than the one the target gives.

func (*HostKeyError) Error

func (e *HostKeyError) Error() string

type LoginError

type LoginError struct{ Why string }

LoginError: the server refused the login, or the target gives none that can be tried.

func (*LoginError) Error

func (e *LoginError) Error() string

type NotSSHError

type NotSSHError struct {
	First []byte
	Err   error
}

NotSSHError: what answered is not an SSH server; First is the start of what it sent.

func (*NotSSHError) Error

func (e *NotSSHError) Error() string

type Pool

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

Pool keeps calls' SSH connections for the next call to the same server, each for its target's Reuse: a file goes a chunk a call, and a login for each would cost a handshake and a line in the server's log every time.

func NewPool

func NewPool() *Pool

NewPool is an empty pool, closing what it keeps once its time is up.

func (*Pool) Close

func (p *Pool) Close()

Close closes every connection the pool keeps, and stops it.

func (*Pool) CloseIdle

func (p *Pool) CloseIdle() int

CloseIdle closes every connection the pool keeps now.

func (*Pool) Get

Get is a connection to t's server, logged in: the one a call before kept, while it still answers, or a new one, with how its logins fared (none for one kept: nothing was tried).

func (*Pool) Idle

func (p *Pool) Idle() int

Idle is how many connections the pool keeps now.

func (*Pool) Put

func (p *Pool) Put(t connection.Target, c *Conn, ok bool)

Put gives a call's connection back: kept for the target's Reuse, or closed when it has none, or when the call left it broken (ok false).

Jump to

Keyboard shortcuts

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