fix: 拆分 starssh 的拨号超时与认证超时语义
- 为 LoginInput 新增 DialTimeout,明确区分【TCP/proxy/ssh-agent 拨号超时】和【SSH 握手/认证超时】 - 将 Timeout 收口为握手/认证阶段超时,0 表示不限制,不再在登录入口自动回填默认值 - 新增 effectiveLoginTimeout/effectiveDialTimeout,统一超时决策逻辑 - 调整 login 流程,仅对 login context、ssh.ClientConfig 和握手阶段连接 deadline 使用认证超时 - 调整 transport 拨号链路,默认 TCP dial、proxy dial 与 ssh-agent 建连统一改用 DialTimeout - 修正 agent forwarding 初始化仍错误复用 LoginInfo.Timeout 的问题 - 保持 LoginSimple 的直观行为:传入 timeout 时同时映射到 Timeout 和 DialTimeout - 新增 login_timeout_test,覆盖零值不回填、DialTimeout 优先级,以及 ssh-agent 认证路径使用拨号超时的回归测试
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
var ErrHostKeyCallbackRequired = errors.New("host key callback is required; use DefaultAllowHostKeyCallback to explicitly allow any host key")
|
||||
var errSSHAgentUnavailable = errors.New("ssh-agent unavailable")
|
||||
var buildSSHAgentAuthMethodFunc = buildSSHAgentAuthMethod
|
||||
|
||||
var defaultAuthOrder = []AuthMethodKind{
|
||||
AuthMethodSSHAgent,
|
||||
@@ -42,7 +43,8 @@ func loginWithContext(ctx context.Context, info LoginInput) (*StarSSH, error) {
|
||||
return nil, ErrHostKeyCallbackRequired
|
||||
}
|
||||
|
||||
loginCtx, cancel := contextWithLoginTimeout(ctx, info.Timeout)
|
||||
authTimeout := effectiveLoginTimeout(info)
|
||||
loginCtx, cancel := contextWithLoginTimeout(ctx, authTimeout)
|
||||
defer cancel()
|
||||
|
||||
sshInfo := &StarSSH{
|
||||
@@ -76,7 +78,7 @@ func loginWithContext(ctx context.Context, info LoginInput) (*StarSSH, error) {
|
||||
clientConfig := &ssh.ClientConfig{
|
||||
User: info.User,
|
||||
Auth: auth,
|
||||
Timeout: info.Timeout,
|
||||
Timeout: authTimeout,
|
||||
HostKeyCallback: hostKeyCallback,
|
||||
BannerCallback: bannerCallback,
|
||||
}
|
||||
@@ -93,7 +95,7 @@ func loginWithContext(ctx context.Context, info LoginInput) (*StarSSH, error) {
|
||||
if err != nil {
|
||||
return sshInfo, err
|
||||
}
|
||||
restoreDeadline := applyConnDeadline(rawConn, loginCtx, info.Timeout)
|
||||
restoreDeadline := applyConnDeadline(rawConn, loginCtx, authTimeout)
|
||||
defer restoreDeadline()
|
||||
|
||||
clientConn, chans, reqs, err := ssh.NewClientConn(rawConn, targetAddr, clientConfig)
|
||||
@@ -130,6 +132,7 @@ func LoginSimple(host string, user string, passwd string, prikeyPath string, por
|
||||
Addr: host,
|
||||
Port: port,
|
||||
Timeout: timeout,
|
||||
DialTimeout: timeout,
|
||||
User: user,
|
||||
HostKeyCallback: DefaultAllowHostKeyCallback,
|
||||
}
|
||||
@@ -154,12 +157,29 @@ func normalizeLoginInput(info LoginInput) LoginInput {
|
||||
if info.Port <= 0 {
|
||||
info.Port = defaultSSHPort
|
||||
}
|
||||
if info.Timeout <= 0 {
|
||||
info.Timeout = defaultLoginTimeout
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func effectiveLoginTimeout(info LoginInput) time.Duration {
|
||||
if info.Timeout <= 0 {
|
||||
return 0
|
||||
}
|
||||
return info.Timeout
|
||||
}
|
||||
|
||||
func effectiveDialTimeout(info LoginInput) time.Duration {
|
||||
switch {
|
||||
case info.DialTimeout < 0:
|
||||
return 0
|
||||
case info.DialTimeout > 0:
|
||||
return info.DialTimeout
|
||||
case info.Timeout > 0:
|
||||
return info.Timeout
|
||||
default:
|
||||
return defaultLoginTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func buildAuthMethods(info LoginInput) ([]ssh.AuthMethod, func(), error) {
|
||||
order, err := normalizeAuthOrder(info.AuthOrder)
|
||||
if err != nil {
|
||||
@@ -194,7 +214,7 @@ func buildAuthMethods(info LoginInput) ([]ssh.AuthMethod, func(), error) {
|
||||
if info.DisableSSHAgent {
|
||||
continue
|
||||
}
|
||||
agentMethod, cleanup, err := buildSSHAgentAuthMethod(info.Timeout)
|
||||
agentMethod, cleanup, err := buildSSHAgentAuthMethodFunc(effectiveDialTimeout(info))
|
||||
if err != nil {
|
||||
agentErr = err
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user