Skip to content

Commit d4a7d64

Browse files
committed
fix: missing ssh client closes
The webssh backend forgets to close ssh connects created by Sftp & CheckSSH. It can make tons of orphaned sshd processes exhausting a target host. This commit fixes the closing mechanism.
1 parent cd611d2 commit d4a7d64

File tree

4 files changed

+38
-10
lines changed

4 files changed

+38
-10
lines changed

controller/common.go

+3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ func CheckSSH(c *gin.Context) *ResponseBody {
3030
responseBody.Msg = err.Error()
3131
return &responseBody
3232
}
33+
3334
err = sshClient.GenerateClient()
35+
defer sshClient.Close()
36+
3437
if err != nil {
3538
fmt.Println(err)
3639
responseBody.Msg = err.Error()

controller/file.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func UploadFile(c *gin.Context) *ResponseBody {
112112
responseBody.Msg = err.Error()
113113
return &responseBody
114114
}
115-
defer sshClient.Sftp.Close()
115+
defer sshClient.Close()
116116
file, header, err := c.Request.FormFile("file")
117117
if err != nil {
118118
responseBody.Msg = err.Error()
@@ -157,7 +157,7 @@ func DownloadFile(c *gin.Context) *ResponseBody {
157157
responseBody.Msg = err.Error()
158158
return &responseBody
159159
}
160-
defer sshClient.Sftp.Close()
160+
defer sshClient.Close()
161161
if sftpFile, err := sshClient.Download(path); err != nil {
162162
fmt.Println(err)
163163
responseBody.Msg = err.Error()
@@ -228,7 +228,7 @@ func FileList(c *gin.Context) *ResponseBody {
228228
responseBody.Msg = err.Error()
229229
return &responseBody
230230
}
231-
defer sshClient.Sftp.Close()
231+
defer sshClient.Close()
232232
files, err := sshClient.Sftp.ReadDir(path)
233233
if err != nil {
234234
if strings.Contains(err.Error(), "exist") {

core/models.go

+29
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"github.com/pkg/sftp"
66
"golang.org/x/crypto/ssh"
77
"io"
8+
"log"
89
"unicode/utf8"
910
)
1011

@@ -67,3 +68,31 @@ func NewSSHClient() SSHClient {
6768
client.Port = 22
6869
return client
6970
}
71+
72+
// Close all closable fields of SSHClient that is opened:
73+
//
74+
// StdinPipe, Session, Sftp, Client
75+
func (sclient *SSHClient) Close() {
76+
defer func() { // just in case
77+
if err := recover(); err != nil {
78+
log.Println("SSHClient Close recover from panic: ", err)
79+
}
80+
}()
81+
82+
if sclient.StdinPipe != nil {
83+
sclient.StdinPipe.Close()
84+
sclient.StdinPipe = nil
85+
}
86+
if sclient.Session != nil {
87+
sclient.Session.Close()
88+
sclient.Session = nil
89+
}
90+
if sclient.Sftp != nil {
91+
sclient.Sftp.Close()
92+
sclient.Sftp = nil
93+
}
94+
if sclient.Client != nil {
95+
sclient.Client.Close()
96+
sclient.Client = nil
97+
}
98+
}

core/sshclient.go

+3-7
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ func (sclient *SSHClient) Connect(ws *websocket.Conn, timeout time.Duration, clo
121121
err := sclient.Session.WindowChange(rows, cols)
122122
if err != nil {
123123
log.Println(err)
124+
close(stopCh)
124125
return
125126
}
126127
continue
@@ -135,13 +136,8 @@ func (sclient *SSHClient) Connect(ws *websocket.Conn, timeout time.Duration, clo
135136

136137
defer func() {
137138
ws.Close()
138-
if sclient.Session != nil {
139-
sclient.StdinPipe.Close()
140-
sclient.Session.Close()
141-
sclient.Client.Close()
142-
sclient.Session = nil
143-
sclient.Client = nil
144-
}
139+
sclient.Close()
140+
145141
if err := recover(); err != nil {
146142
log.Println(err)
147143
}

0 commit comments

Comments
 (0)