starssh/types.go
starainrt 0c23e7d4bf
feat: 增强 ssh-agent 认证与转发可靠性
- 拆分 ssh-agent 认证、连接与 endpoint 解析逻辑
- 新增 IdentityAgent、SSHAgentTimeout、SSHAgentForwardTimeout 和调试事件
- 为 agent list/sign 操作增加独立 deadline,避免硬件 agent 卡死登录
- 支持 agent signer 失败后跳过坏 key 并重试后续 key
- 优先处理 RSA-SHA2 签名,兼容现代 OpenSSH 认证要求
- 增强 agent forwarding 的探测、通道空闲超时和关闭清理
- 补充 Windows OpenSSH pipe 与 GPG S.gpg-agent.ssh socket 文件支持
- 增加相关回归测试和 Windows 编译验证覆盖
2026-05-27 13:10:35 +08:00

238 lines
6.8 KiB
Go

package starssh
import (
"bufio"
"context"
"io"
"net"
"sync"
"sync/atomic"
"time"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
const (
defaultSSHPort = 22
defaultLoginTimeout = 5 * time.Second
defaultSSHAgentTimeout = 2 * time.Minute
defaultKeepAliveTimeout = 3 * time.Second
defaultShellPollInterval = 120 * time.Millisecond
defaultShellSetupDelay = 200 * time.Millisecond
defaultShellSetupTimeout = 3 * time.Second
defaultShellWaitTimeout = 30 * time.Second
defaultShellPromptToken = "__STARSSH_PROMPT__>"
defaultPTYTerm = "xterm"
defaultPTYRows = 500
defaultPTYColumns = 250
defaultTransferBufferSize = 1024 * 1024
defaultExecStreamMaxPendingChunks = 256
defaultExecStreamMaxPendingBytes = 4 * 1024 * 1024
)
type DialContextFunc func(ctx context.Context, network, address string) (net.Conn, error)
type ProxyType string
const (
ProxyTypeSOCKS5 ProxyType = "socks5"
ProxyTypeHTTPConnect ProxyType = "http_connect"
)
type ProxyConfig struct {
Type ProxyType
Addr string
Username string
Password string
Timeout time.Duration
}
type AuthMethodKind string
const (
AuthMethodPrivateKey AuthMethodKind = "private_key"
AuthMethodPassword AuthMethodKind = "password"
AuthMethodKeyboardInteractive AuthMethodKind = "keyboard_interactive"
AuthMethodSSHAgent AuthMethodKind = "ssh_agent"
)
type SSHAgentDebugFunc func(SSHAgentDebugEvent)
type SSHAgentDebugEvent struct {
Step string
Source string
Endpoint string
Network string
Phase string
Status string
Duration time.Duration
KeyCount int
Err error
}
type StarSSH struct {
stateMu sync.RWMutex
Client *ssh.Client
PublicKey ssh.PublicKey
PubkeyBase64 string
Hostname string
RemoteAddr net.Addr
Banner string
LoginInfo LoginInput
online bool
upstream *StarSSH
sftpClient *sftp.Client
sftpMu sync.Mutex
agentForwardMu sync.Mutex
agentForwarder io.Closer
keepaliveMu sync.Mutex
keepaliveStop chan struct{}
keepaliveDone chan struct{}
closing atomic.Bool
}
type LoginInput struct {
KeyExchanges []string
Ciphers []string
MACs []string
User string
Password string
PasswordCallback func() (string, error)
KeyboardInteractiveCallback ssh.KeyboardInteractiveChallenge
Prikey string
PrikeyPwd string
DisableSSHAgent bool
ForwardSSHAgent bool
AuthOrder []AuthMethodKind
// IdentityAgent overrides the local ssh-agent endpoint used for authentication
// and agent forwarding. Empty uses SSH_AUTH_SOCK, or the platform default where
// one exists.
IdentityAgent string
Addr string
Port int
// Timeout limits the SSH handshake/authentication phase after a TCP connection has
// already been established. Zero means no authentication timeout.
Timeout time.Duration
// DialTimeout limits outbound dial steps such as TCP connect, proxy connect, and
// local ssh-agent socket connect. Zero falls back to Timeout when set, otherwise
// uses the package default dial timeout. Negative disables the default dial timeout.
DialTimeout time.Duration
// SSHAgentTimeout limits ssh-agent protocol operations such as listing keys and
// signing challenges. Zero uses the package default, and negative disables the
// per-operation deadline. This is intentionally separate from Timeout and
// DialTimeout because hardware-backed agents may require a PIN or touch confirmation.
SSHAgentTimeout time.Duration
// SSHAgentForwardTimeout limits idle reads and writes on forwarded agent
// channels. Zero or negative leaves forwarded channels without an idle deadline.
SSHAgentForwardTimeout time.Duration
// SSHAgentDebug receives structured ssh-agent dial/protocol events. It is nil by
// default and must not log private key material.
SSHAgentDebug SSHAgentDebugFunc
DialContext DialContextFunc
Proxy *ProxyConfig
Jump *LoginInput
KeepAliveInterval time.Duration
KeepAliveTimeout time.Duration
HostKeyCallback func(string, net.Addr, ssh.PublicKey) error
BannerCallback func(string) error
}
// StarShell keeps the legacy prompt-driven helper for POSIX-style scripted shell interactions.
// It is not a generic cross-shell abstraction; for product-grade interactive terminals, prefer TerminalSession.
type StarShell struct {
Keyword string
UseWaitDefault bool
WaitTimeout time.Duration
Session *ssh.Session
in io.Writer
out *bufio.Reader
er *bufio.Reader
outbyte []byte
errbyte []byte
lastout int64
errors error
isprint bool
isfuncs bool
iscolor bool
isecho bool
rw sync.RWMutex
funcs func(string)
writeMu sync.Mutex
commandMu sync.Mutex
closeOnce sync.Once
promptToken string
}
type TerminalConfig struct {
Term string
Rows int
Columns int
Modes ssh.TerminalModes
}
type TerminalControl byte
const (
TerminalControlInterrupt TerminalControl = 0x03
TerminalControlEOF TerminalControl = 0x04
TerminalControlBell TerminalControl = 0x07
TerminalControlBackspace TerminalControl = 0x08
TerminalControlLineKill TerminalControl = 0x15
TerminalControlQuit TerminalControl = 0x1c
TerminalControlSuspend TerminalControl = 0x1a
TerminalControlPauseOutput TerminalControl = 0x13
TerminalControlResumeOutput TerminalControl = 0x11
)
type TerminalCloseReason string
const (
TerminalCloseReasonUnknown TerminalCloseReason = ""
TerminalCloseReasonExit TerminalCloseReason = "exit"
TerminalCloseReasonSignal TerminalCloseReason = "signal"
TerminalCloseReasonClosed TerminalCloseReason = "closed"
TerminalCloseReasonContextCanceled TerminalCloseReason = "context_canceled"
TerminalCloseReasonDeadlineExceeded TerminalCloseReason = "deadline_exceeded"
TerminalCloseReasonTransportError TerminalCloseReason = "transport_error"
)
type TerminalExitInfo struct {
ExitCode int
ExitSignal string
ExitMessage string
Reason TerminalCloseReason
}
type TerminalSession struct {
Session *ssh.Session
ID string
Label string
Metadata map[string]string
stdin io.WriteCloser
stdout io.Reader
stderr io.Reader
attachMu sync.RWMutex
in io.Reader
out io.Writer
errOut io.Writer
runOnce sync.Once
runDone chan struct{}
runErr error
waitOnce sync.Once
waitDone chan struct{}
stateMu sync.RWMutex
waitErr error
exitInfo TerminalExitInfo
closeReason TerminalCloseReason
closeErr error
closeOnce sync.Once
}