@@ -18,7 +18,7 @@ import (
18
18
"golang.org/x/sync/errgroup"
19
19
)
20
20
21
- //Config a Tunnel
21
+ // Config a Tunnel
22
22
type Config struct {
23
23
* cio.Logger
24
24
Inbound bool
@@ -27,13 +27,13 @@ type Config struct {
27
27
KeepAlive time.Duration
28
28
}
29
29
30
- //Tunnel represents an SSH tunnel with proxy capabilities.
31
- //Both chisel client and server are Tunnels.
32
- //chisel client has a single set of remotes, whereas
33
- //chisel server has multiple sets of remotes (one set per client).
34
- //Each remote has a 1:1 mapping to a proxy.
35
- //Proxies listen, send data over ssh, and the other end of the ssh connection
36
- //communicates with the endpoint and returns the response.
30
+ // Tunnel represents an SSH tunnel with proxy capabilities.
31
+ // Both chisel client and server are Tunnels.
32
+ // chisel client has a single set of remotes, whereas
33
+ // chisel server has multiple sets of remotes (one set per client).
34
+ // Each remote has a 1:1 mapping to a proxy.
35
+ // Proxies listen, send data over ssh, and the other end of the ssh connection
36
+ // communicates with the endpoint and returns the response.
37
37
type Tunnel struct {
38
38
Config
39
39
//ssh connection
@@ -47,7 +47,7 @@ type Tunnel struct {
47
47
socksServer * socks5.Server
48
48
}
49
49
50
- //New Tunnel from the given Config
50
+ // New Tunnel from the given Config
51
51
func New (c Config ) * Tunnel {
52
52
c .Logger = c .Logger .Fork ("tun" )
53
53
t := & Tunnel {
@@ -68,7 +68,7 @@ func New(c Config) *Tunnel {
68
68
return t
69
69
}
70
70
71
- //BindSSH provides an active SSH for use for tunnelling
71
+ // BindSSH provides an active SSH for use for tunnelling
72
72
func (t * Tunnel ) BindSSH (ctx context.Context , c ssh.Conn , reqs <- chan * ssh.Request , chans <- chan ssh.NewChannel ) error {
73
73
//link ctx to ssh-conn
74
74
go func () {
@@ -104,7 +104,7 @@ func (t *Tunnel) BindSSH(ctx context.Context, c ssh.Conn, reqs <-chan *ssh.Reque
104
104
return err
105
105
}
106
106
107
- //getSSH blocks while connecting
107
+ // getSSH blocks while connecting
108
108
func (t * Tunnel ) getSSH (ctx context.Context ) ssh.Conn {
109
109
//cancelled already?
110
110
if isDone (ctx ) {
@@ -140,8 +140,8 @@ func (t *Tunnel) activatingConnWait() <-chan struct{} {
140
140
return ch
141
141
}
142
142
143
- //BindRemotes converts the given remotes into proxies, and blocks
144
- //until the caller cancels the context or there is a proxy error.
143
+ // BindRemotes converts the given remotes into proxies, and blocks
144
+ // until the caller cancels the context or there is a proxy error.
145
145
func (t * Tunnel ) BindRemotes (ctx context.Context , remotes []* settings.Remote ) error {
146
146
if len (remotes ) == 0 {
147
147
return errors .New ("no remotes" )
@@ -174,16 +174,48 @@ func (t *Tunnel) BindRemotes(ctx context.Context, remotes []*settings.Remote) er
174
174
175
175
func (t * Tunnel ) keepAliveLoop (sshConn ssh.Conn ) {
176
176
//ping forever
177
+
178
+ //reply_timeout set to KeepAlive interval, if KeepAlive is less than 10s, set reply_timeout to 10s
179
+ //maybe a new config option for reply_timeout is also fine
180
+ reply_timeout := t .Config .KeepAlive
181
+
182
+ if reply_timeout < 10 * time .Second {
183
+ reply_timeout = 10 * time .Second
184
+ }
185
+
177
186
for {
178
187
time .Sleep (t .Config .KeepAlive )
179
- _ , b , err := sshConn .SendRequest ("ping" , true , nil )
188
+
189
+ errChannel := make (chan error , 2 )
190
+
191
+ timeoutTimer := time .AfterFunc (reply_timeout , func () {
192
+ errChannel <- errors .New ("KEEPALIVE REPLY TIMEOUT ERROR" )
193
+ })
194
+
195
+ go func () {
196
+ _ , b , err := sshConn .SendRequest ("ping" , true , nil )
197
+
198
+ ret_err := err
199
+
200
+ if err == nil && len (b ) > 0 && ! bytes .Equal (b , []byte ("pong" )) {
201
+ t .Debugf ("strange ping response" )
202
+ ret_err = errors .New ("strange ping response" )
203
+ }
204
+
205
+ errChannel <- ret_err
206
+ }()
207
+
208
+ err := <- errChannel
209
+
210
+ // explicitly stop the timer, as it's no longer needed at this point.
211
+ timeoutTimer .Stop ()
212
+ // errChannel should be garbage collected, as it won't be in use, even on a timeout,
213
+ // as SendRequest will be unblocked on connection closure, the goroutine will send
214
+ // an error message and finish, therefore releasing the channel.
215
+
180
216
if err != nil {
181
217
break
182
218
}
183
- if len (b ) > 0 && ! bytes .Equal (b , []byte ("pong" )) {
184
- t .Debugf ("strange ping response" )
185
- break
186
- }
187
219
}
188
220
//close ssh connection on abnormal ping
189
221
sshConn .Close ()
0 commit comments