The SSH packages provide complete client and server implementation of the SSH protocol, including transport security, authentication, and application-level protocols like remote command execution, port forwarding, and agent protocol support.
Complete SSH protocol implementation supporting both client and server operations.
const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
InsecureCertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com"
CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com"
)
const (
UserCert = 1
HostCert = 2
)
const CertTimeInfinity = 1<<64 - 1const (
CipherAES128GCM = "aes128-gcm@openssh.com"
CipherAES256GCM = "aes256-gcm@openssh.com"
CipherChaCha20Poly1305 = "chacha20-poly1305@openssh.com"
CipherAES128CTR = "aes128-ctr"
CipherAES192CTR = "aes192-ctr"
CipherAES256CTR = "aes256-ctr"
InsecureCipherAES128CBC = "aes128-cbc"
InsecureCipherTripleDESCBC = "3des-cbc"
InsecureCipherRC4 = "arcfour"
InsecureCipherRC4128 = "arcfour128"
InsecureCipherRC4256 = "arcfour256"
)const (
InsecureKeyExchangeDH1SHA1 = "diffie-hellman-group1-sha1"
InsecureKeyExchangeDH14SHA1 = "diffie-hellman-group14-sha1"
KeyExchangeDH14SHA256 = "diffie-hellman-group14-sha256"
KeyExchangeDH16SHA512 = "diffie-hellman-group16-sha512"
KeyExchangeECDHP256 = "ecdh-sha2-nistp256"
KeyExchangeECDHP384 = "ecdh-sha2-nistp384"
KeyExchangeECDHP521 = "ecdh-sha2-nistp521"
KeyExchangeCurve25519 = "curve25519-sha256"
InsecureKeyExchangeDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
KeyExchangeDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
KeyExchangeMLKEM768X25519 = "mlkem768x25519-sha256"
)const (
HMACSHA256ETM = "hmac-sha2-256-etm@openssh.com"
HMACSHA512ETM = "hmac-sha2-512-etm@openssh.com"
HMACSHA256 = "hmac-sha2-256"
HMACSHA512 = "hmac-sha2-512"
HMACSHA1 = "hmac-sha1"
InsecureHMACSHA196 = "hmac-sha1-96"
)const (
KeyAlgoRSA = "ssh-rsa"
InsecureKeyAlgoDSA = "ssh-dss"
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
KeyAlgoED25519 = "ssh-ed25519"
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
KeyAlgoRSASHA256 = "rsa-sha2-256"
KeyAlgoRSASHA512 = "rsa-sha2-512"
)var ErrNoAuth = errors.New("ssh: no auth passed yet")// Client is an authenticated SSH client connection.
type Client struct {
Conn
// contains unexported fields
}
// Dial starts a client connection to the given SSH server.
func Dial(network, addr string, config *ClientConfig) (*Client, error)
// NewClient creates a Client on top of the given connection.
func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client
// NewSession opens a new Session for the client.
func (c *Client) NewSession() (*Session, error)
// Close closes the client connection.
func (c *Client) Close() error
// Wait waits for the remote end to close the connection.
func (c *Client) Wait() error
// HandleChannelOpen registers a Handler for a particular channel type.
func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel
// Dial initiates a connection to the addr from the remote host.
// Used for port forwarding from the remote side.
func (c *Client) Dial(n, addr string) (net.Conn, error)
// DialContext is like Dial but uses a context.
func (c *Client) DialContext(ctx context.Context, n, addr string) (net.Conn, error)
// DialTCP connects to the remote address raddr on the network net
// through the secure channel.
func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error)
// Listen initiates a tcpip-forward on the remote side.
// Used for port forwarding from the client side.
func (c *Client) Listen(n, addr string) (net.Listener, error)
// ListenTCP requests the remote peer open a listening socket on raddr.
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error)
// ListenUnix requests a Unix socket from the remote side.
func (c *Client) ListenUnix(socketPath string) (net.Listener, error)// ClientConfig holds configuration for SSH clients.
type ClientConfig struct {
Config
// User contains the username to authenticate as.
User string
// Auth contains authentication methods.
Auth []AuthMethod
// HostKeyCallback is called during the cryptographic handshake
// to validate the server's host key.
HostKeyCallback HostKeyCallback
// BannerCallback is called when the server sends a banner message.
BannerCallback BannerCallback
// ClientVersion contains the version identification string
// to send to the server.
ClientVersion string
// HostKeyAlgorithms lists the key types that the client will accept
// from the server.
HostKeyAlgorithms []string
// Timeout is the maximum time for the TCP connection to establish.
Timeout time.Duration
}
// Config contains common configuration for SSH clients and servers.
type Config struct {
// Rand provides a source of entropy for cryptographic primitives.
Rand io.Reader
// RekeyThreshold is the number of bytes transmitted or received
// after which the session key is renegotiated.
RekeyThreshold uint64
// KeyExchanges specifies the allowed key exchange algorithms.
KeyExchanges []string
// Ciphers specifies the allowed ciphers.
Ciphers []string
// MACs specifies the allowed MAC algorithms.
MACs []string
}
// SetDefaults sets sensible values for unset fields in config.
func (c *Config) SetDefaults()// AuthMethod is the interface implemented by different authentication methods.
type AuthMethod interface {
// contains unexported methods
}
// Password returns an AuthMethod using the given password.
func Password(secret string) AuthMethod
// PasswordCallback returns an AuthMethod that interactively fetches a password.
func PasswordCallback(prompt func() (secret string, err error)) AuthMethod
// PublicKeys returns an AuthMethod that uses the given signers to authenticate.
func PublicKeys(signers ...Signer) AuthMethod
// PublicKeysCallback returns an AuthMethod that dynamically fetches signers.
func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod
// KeyboardInteractive returns an AuthMethod using a function to handle challenges.
func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod
// KeyboardInteractiveChallenge is the function signature for keyboard-interactive challenges.
type KeyboardInteractiveChallenge func(name, instruction string, questions []string, echos []bool) (answers []string, err error)
// GSSAPIWithMICAuthMethod returns an AuthMethod using GSSAPI authentication.
func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod
// RetryableAuthMethod wraps an AuthMethod to retry on failure.
func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod// HostKeyCallback is called during the cryptographic handshake
// to validate the server's host key.
type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
// InsecureIgnoreHostKey returns a function that accepts any host key.
// WARNING: This should only be used for testing.
func InsecureIgnoreHostKey() HostKeyCallback
// FixedHostKey returns a function that only accepts the given host key.
func FixedHostKey(key PublicKey) HostKeyCallback// Session is a remote execution session.
type Session struct {
Stdin io.WriteCloser
Stdout io.Reader
Stderr io.Reader
// contains unexported fields
}
// Run runs cmd on the remote host.
func (s *Session) Run(cmd string) error
// Start starts the execution of cmd on the remote host.
func (s *Session) Start(cmd string) error
// Wait waits for the remote command to exit.
func (s *Session) Wait() error
// Output runs cmd on the remote host and returns its stdout.
func (s *Session) Output(cmd string) ([]byte, error)
// CombinedOutput runs cmd and returns its combined stdout and stderr.
func (s *Session) CombinedOutput(cmd string) ([]byte, error)
// Shell starts a login shell on the remote host.
func (s *Session) Shell() error
// Close closes the session.
func (s *Session) Close() error
// RequestPty requests a pseudo-terminal with the given dimensions.
func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error
// WindowChange informs the remote host about a terminal resize.
func (s *Session) WindowChange(h, w int) error
// Signal sends a signal to the remote process.
func (s *Session) Signal(sig Signal) error
// SendRequest sends an out-of-band channel request.
func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error)
// StdinPipe returns a pipe that will be connected to the remote command's stdin.
func (s *Session) StdinPipe() (io.WriteCloser, error)
// StdoutPipe returns a pipe that will be connected to the remote command's stdout.
func (s *Session) StdoutPipe() (io.Reader, error)
// StderrPipe returns a pipe that will be connected to the remote command's stderr.
func (s *Session) StderrPipe() (io.Reader, error)
// Setenv sets an environment variable for the session.
func (s *Session) Setenv(name, value string) error// ServerConfig holds server specific configuration data.
type ServerConfig struct {
Config
// NoClientAuth determines whether a client must authenticate.
NoClientAuth bool
// MaxAuthTries specifies the maximum authentication attempts.
MaxAuthTries int
// PasswordCallback is called when a user attempts password authentication.
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
// PublicKeyCallback is called when a client offers a public key.
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
// KeyboardInteractiveCallback is called for keyboard-interactive authentication.
KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
// AuthLogCallback is called to log authentication attempts.
AuthLogCallback func(conn ConnMetadata, method string, err error)
// ServerVersion is the version identification string.
ServerVersion string
// BannerCallback is called before authentication to display a banner.
BannerCallback func(conn ConnMetadata) string
// GSSAPIWithMICConfig contains GSSAPI configuration.
GSSAPIWithMICConfig *GSSAPIWithMICConfig
}
// NewServerConn starts a server connection over the given transport.
func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error)
// ServerConn is an authenticated SSH server connection.
type ServerConn struct {
Conn
// contains unexported fields
}
// Permissions represents permissions that may be applied to users.
type Permissions struct {
// CriticalOptions indicate restrictions to the default permissions.
CriticalOptions map[string]string
// Extensions are extra functionality that the user is allowed to access.
Extensions map[string]string
}// PublicKey is an abstraction of different types of public keys.
type PublicKey interface {
Type() string
Marshal() []byte
Verify(data []byte, sig *Signature) error
}
// Signer is an interface for signing data with a private key.
type Signer interface {
PublicKey() PublicKey
Sign(rand io.Reader, data []byte) (*Signature, error)
}
// AlgorithmSigner allows specifying a signature algorithm.
type AlgorithmSigner interface {
Signer
SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
}
// Signature represents a cryptographic signature.
type Signature struct {
Format string
Blob []byte
Rest []byte
}
// NewSignerFromKey returns a Signer from a crypto.PrivateKey.
func NewSignerFromKey(key interface{}) (Signer, error)
// NewSignerFromSigner returns a Signer from a crypto.Signer.
func NewSignerFromSigner(signer crypto.Signer) (Signer, error)
// ParsePrivateKey parses an SSH private key.
func ParsePrivateKey(pemBytes []byte) (Signer, error)
// ParsePrivateKeyWithPassphrase parses an encrypted SSH private key.
func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error)
// ParsePublicKey parses an SSH public key in authorized_keys format.
func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error)
// ParseKnownHosts parses a known_hosts file line.
func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error)
// MarshalAuthorizedKey serializes a key for authorized_keys file.
func MarshalAuthorizedKey(key PublicKey) []byte
// FingerprintSHA256 returns the SHA256 fingerprint of the public key.
func FingerprintSHA256(pubKey PublicKey) string
// FingerprintLegacyMD5 returns the legacy MD5 fingerprint.
func FingerprintLegacyMD5(pubKey PublicKey) string// Certificate represents an OpenSSH certificate.
type Certificate struct {
Nonce []byte
Key PublicKey
Serial uint64
CertType uint32
KeyId string
ValidPrincipals []string
ValidAfter uint64
ValidBefore uint64
Permissions
Reserved []byte
SignatureKey PublicKey
Signature *Signature
}
// SignCert signs the certificate with the given signer.
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error
// Marshal serializes the certificate.
func (c *Certificate) Marshal() []byte
// Type returns the certificate type string.
func (c *Certificate) Type() string
// Verify checks the certificate's signature.
func (c *Certificate) Verify(data []byte, sig *Signature) error
// NewCertSigner returns a Signer that includes a certificate.
func NewCertSigner(cert *Certificate, signer Signer) (Signer, error)// Channel represents a duplex connection over SSH.
type Channel interface {
Read(data []byte) (int, error)
Write(data []byte) (int, error)
Close() error
CloseWrite() error
SendRequest(name string, wantReply bool, payload []byte) (bool, error)
Stderr() io.ReadWriter
}
// NewChannel represents an incoming channel request.
type NewChannel interface {
Accept() (Channel, <-chan *Request, error)
Reject(reason RejectionReason, message string) error
ChannelType() string
ExtraData() []byte
}
// RejectionReason is an enumeration for channel rejection reasons.
type RejectionReason uint32
const (
Prohibited RejectionReason = iota + 1
ConnectionFailed
UnknownChannelType
ResourceShortage
)
// Request represents a channel or connection-level request.
type Request struct {
Type string
WantReply bool
Payload []byte
}
// DiscardRequests consumes and rejects all requests from the channel.
func DiscardRequests(in <-chan *Request)// Algorithms contains configurable algorithm sets.
type Algorithms struct {
KeyExchanges []string
Ciphers []string
MACs []string
HostKeys []string
PublicKeyAuths []string
}
// SupportedAlgorithms returns the supported secure algorithms.
func SupportedAlgorithms() Algorithms
// InsecureAlgorithms returns deprecated insecure algorithms.
func InsecureAlgorithms() Algorithms// Marshal serializes a value to SSH wire format.
func Marshal(msg interface{}) []byte
// Unmarshal parses SSH wire format into a value.
func Unmarshal(data []byte, out interface{}) error
// ParseDSAPrivateKey parses a DSA private key.
func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error)
// ParseRawPrivateKey parses a raw private key.
func ParseRawPrivateKey(pemBytes []byte) (interface{}, error)
// ParseRawPrivateKeyWithPassphrase parses an encrypted raw private key.
func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{}, error)
// MarshalPrivateKey marshals a private key to OpenSSH format.
func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error)
// MarshalPrivateKeyWithPassphrase marshals an encrypted private key.
func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error)SSH agent protocol implementation for client and server.
// Agent represents capabilities of an ssh-agent.
type Agent interface {
// List returns the identities known to the agent.
List() ([]*Key, error)
// Sign signs data with the given key.
Sign(key PublicKey, data []byte) (*Signature, error)
// Add adds a private key to the agent.
Add(key AddedKey) error
// Remove removes a key from the agent.
Remove(key PublicKey) error
// RemoveAll removes all keys from the agent.
RemoveAll() error
// Lock locks the agent with a passphrase.
Lock(passphrase []byte) error
// Unlock unlocks the agent.
Unlock(passphrase []byte) error
// Signers returns Signers for all known keys.
Signers() ([]Signer, error)
}
// ExtendedAgent provides additional agent capabilities.
type ExtendedAgent interface {
Agent
// SignWithFlags signs data with additional signature algorithm flags.
SignWithFlags(key PublicKey, data []byte, flags SignatureFlags) (*Signature, error)
// Extension processes an extension request.
Extension(extensionType string, contents []byte) ([]byte, error)
}
// AddedKey represents an SSH key being added to an agent.
type AddedKey struct {
// PrivateKey is the private key to add.
PrivateKey interface{}
// Certificate is an optional certificate.
Certificate *Certificate
// Comment is a user comment about the key.
Comment string
// LifetimeSecs is the time in seconds that the key should be kept.
LifetimeSecs uint32
// ConfirmBeforeUse requires user confirmation before each use.
ConfirmBeforeUse bool
// ConstraintExtensions are additional constraints.
ConstraintExtensions []ConstraintExtension
}
// Key represents an SSH public key in the agent.
type Key struct {
Format string
Blob []byte
Comment string
}
// Marshal serializes the key.
func (k *Key) Marshal() []byte
// Type returns the key type.
func (k *Key) Type() string
// Verify verifies a signature.
func (k *Key) Verify(data []byte, sig *Signature) error
// String returns a string representation.
func (k *Key) String() string
// ConstraintExtension represents a user-defined constraint.
type ConstraintExtension struct {
ExtensionName string
ExtensionDetails []byte
}
// SignatureFlags provides additional signature flags.
type SignatureFlags uint32
const (
SignatureFlagReserved SignatureFlags = 1 << iota
SignatureFlagRsaSha256
SignatureFlagRsaSha512
)// NewClient creates a new agent client.
func NewClient(rw io.ReadWriter) ExtendedAgent
// NewKeyring creates an in-memory keyring.
func NewKeyring() Agent
// ForwardToAgent routes agent requests from a client to an agent.
func ForwardToAgent(client *Client, keyring Agent) error
// ForwardToRemote routes agent requests to a remote agent.
func ForwardToRemote(client *Client, addr string) error
// RequestAgentForwarding sets up agent forwarding for a session.
func RequestAgentForwarding(session *Session) error
// ServeAgent serves the agent protocol on the given connection.
func ServeAgent(agent Agent, c io.ReadWriter) errorvar ErrExtensionUnsupported = errors.New("agent: extension unsupported")OpenSSH known_hosts file parser.
// New creates a HostKeyCallback from known_hosts files.
func New(files ...string) (HostKeyCallback, error)
// Normalize normalizes an address for known_hosts format.
func Normalize(address string) string
// Line returns a known_hosts line for the given addresses and key.
func Line(addresses []string, key PublicKey) string
// HashHostname returns a hashed hostname for known_hosts.
func HashHostname(hostname string) string// KeyError represents a host key mismatch.
type KeyError struct {
Want []KnownKey
}
func (u *KeyError) Error() string
// KnownKey represents a key from known_hosts.
type KnownKey struct {
Key PublicKey
Filename string
Line int
}
func (k *KnownKey) String() string
// RevokedError represents a revoked key.
type RevokedError struct {
Revoked KnownKey
}
func (r *RevokedError) Error() stringTerminal handling functions for SSH sessions.
Deprecation Notice: This package is deprecated and has been moved to golang.org/x/term. All types and functions are re-exported from that package.
var ErrPasteIndicator = term.ErrPasteIndicator// GetSize returns the dimensions of the terminal.
func GetSize(fd int) (width, height int, err error)
// GetState returns the current state of a terminal.
func GetState(fd int) (*State, error)
// IsTerminal reports whether fd is a terminal.
func IsTerminal(fd int) bool
// MakeRaw puts the terminal into raw mode.
func MakeRaw(fd int) (*State, error)
// ReadPassword reads a line of input from fd without local echo.
func ReadPassword(fd int) ([]byte, error)
// Restore restores the terminal to a previous state.
func Restore(fd int, oldState *State) error// EscapeCodes is a type alias for terminal escape code handling.
type EscapeCodes = term.EscapeCodes
// State represents the state of a terminal.
type State = term.State
// Terminal provides line editing and history for interactive terminals.
type Terminal = term.Terminal
// NewTerminal creates a new Terminal.
func NewTerminal(c io.ReadWriter, prompt string) *Terminalpackage main
import (
"fmt"
"io"
"log"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
)
func main() {
// Setup known_hosts checking
hostKeyCallback, err := knownhosts.New("~/.ssh/known_hosts")
if err != nil {
log.Fatal(err)
}
// Configure SSH client
config := &ssh.ClientConfig{
User: "username",
Auth: []ssh.AuthMethod{
ssh.Password("password"),
},
HostKeyCallback: hostKeyCallback,
}
// Connect to server
client, err := ssh.Dial("tcp", "example.com:22", config)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Create session
session, err := client.NewSession()
if err != nil {
log.Fatal(err)
}
defer session.Close()
// Run command
output, err := session.Output("ls -l")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Output:\n%s\n", output)
}package main
import (
"io/ioutil"
"log"
"golang.org/x/crypto/ssh"
)
func main() {
// Read private key
key, err := ioutil.ReadFile("~/.ssh/id_rsa")
if err != nil {
log.Fatal(err)
}
// Parse private key
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
log.Fatal(err)
}
// Configure client
config := &ssh.ClientConfig{
User: "username",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(), // Use knownhosts.New() in production
}
// Connect
client, err := ssh.Dial("tcp", "example.com:22", config)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Use connection
session, _ := client.NewSession()
defer session.Close()
session.Run("echo 'Connected!'")
}package main
import (
"io"
"log"
"net"
"golang.org/x/crypto/ssh"
)
func main() {
// Setup SSH client (config omitted for brevity)
config := &ssh.ClientConfig{ /* ... */ }
client, _ := ssh.Dial("tcp", "example.com:22", config)
defer client.Close()
// Listen on remote server
listener, err := client.Listen("tcp", "localhost:8080")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
// Forward connections
for {
remote, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
go func(remote net.Conn) {
defer remote.Close()
// Connect to local service
local, err := net.Dial("tcp", "localhost:80")
if err != nil {
return
}
defer local.Close()
// Forward traffic
go io.Copy(local, remote)
io.Copy(remote, local)
}(remote)
}
}package main
import (
"fmt"
"io"
"log"
"net"
"golang.org/x/crypto/ssh"
)
func main() {
// Generate server key
key, _ := ssh.ParsePrivateKey(serverKeyPEM)
// Configure server
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "user" && string(pass) == "password" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
}
config.AddHostKey(key)
// Listen for connections
listener, err := net.Listen("tcp", "0.0.0.0:2022")
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("accept error: %v", err)
continue
}
go handleConnection(conn, config)
}
}
func handleConnection(conn net.Conn, config *ssh.ServerConfig) {
defer conn.Close()
serverConn, chans, reqs, err := ssh.NewServerConn(conn, config)
if err != nil {
log.Printf("handshake error: %v", err)
return
}
defer serverConn.Close()
go ssh.DiscardRequests(reqs)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
continue
}
go func(in <-chan *ssh.Request) {
for req := range in {
if req.Type == "exec" {
// Handle command execution
io.WriteString(channel, "Command executed\n")
channel.Close()
}
if req.WantReply {
req.Reply(true, nil)
}
}
}(requests)
}
}package main
import (
"log"
"net"
"os"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
func main() {
// Connect to SSH agent
socket := os.Getenv("SSH_AUTH_SOCK")
conn, err := net.Dial("unix", socket)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
agentClient := agent.NewClient(conn)
// Get signers from agent
signers, err := agentClient.Signers()
if err != nil {
log.Fatal(err)
}
// Use with SSH client
config := &ssh.ClientConfig{
User: "username",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signers...),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, _ := ssh.Dial("tcp", "example.com:22", config)
defer client.Close()
// Forward agent to remote server
session, _ := client.NewSession()
agent.RequestAgentForwarding(session)
session.Run("ssh another-server")
}