mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
fix: 修复 SSH 扫描 goroutine 泄漏
ssh.NewClientConn 不接受 context,context 取消后底层 TCP 连接未关闭, 导致 readLoop goroutine 永久阻塞在 conn.Read 上。大规模扫描时泄漏数万 goroutine。 - doSSHAuth 新增 goroutine 监听 context 取消并关闭底层连接 - TestSingleCredential 移除 5 秒超时放弃逻辑,改为持续等待清理
This commit is contained in:
@@ -79,18 +79,12 @@ func TestSingleCredential(ctx context.Context, cred Credential, authFn AuthFunc)
|
|||||||
case result := <-resultChan:
|
case result := <-resultChan:
|
||||||
return result
|
return result
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
// context 被取消,但 authFn goroutine 可能还阻塞在第三方库 IO 上
|
// context 被取消,等待 authFn goroutine 返回并清理连接
|
||||||
// 限时等待:超过 5 秒直接放弃,避免 goroutine 无限泄漏
|
// 各插件的 authFn 应在 context 取消时关闭底层连接使 goroutine 快速退出
|
||||||
go func() {
|
go func() {
|
||||||
timer := time.NewTimer(5 * time.Second)
|
result := <-resultChan
|
||||||
defer timer.Stop()
|
if result != nil && result.Conn != nil {
|
||||||
select {
|
_ = result.Conn.Close()
|
||||||
case result := <-resultChan:
|
|
||||||
if result != nil && result.Conn != nil {
|
|
||||||
_ = result.Conn.Close()
|
|
||||||
}
|
|
||||||
case <-timer.C:
|
|
||||||
// 第三方库不响应取消,放弃等待
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return &AuthResult{
|
return &AuthResult{
|
||||||
|
|||||||
@@ -122,10 +122,28 @@ func (p *SSHPlugin) doSSHAuth(ctx context.Context, info *common.HostInfo, cred C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 监听 context 取消,强制关闭底层连接以中断 SSH 握手和 readLoop
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
_ = conn.Close()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// 在TCP连接上创建SSH客户端
|
// 在TCP连接上创建SSH客户端
|
||||||
sshConn, chans, reqs, err := ssh.NewClientConn(conn, target, sshConfig)
|
sshConn, chans, reqs, err := ssh.NewClientConn(conn, target, sshConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return &AuthResult{
|
||||||
|
Success: false,
|
||||||
|
ErrorType: ErrorTypeNetwork,
|
||||||
|
Error: ctx.Err(),
|
||||||
|
}
|
||||||
|
}
|
||||||
return &AuthResult{
|
return &AuthResult{
|
||||||
Success: false,
|
Success: false,
|
||||||
ErrorType: classifySSHErrorType(err),
|
ErrorType: classifySSHErrorType(err),
|
||||||
|
|||||||
Reference in New Issue
Block a user