@@ -18,7 +18,7 @@ import (
1818 "golang.org/x/sync/errgroup"
1919)
2020
21- //Config a Tunnel
21+ // Config a Tunnel
2222type Config struct {
2323 * cio.Logger
2424 Inbound bool
@@ -27,13 +27,13 @@ type Config struct {
2727 KeepAlive time.Duration
2828}
2929
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.
3737type Tunnel struct {
3838 Config
3939 //ssh connection
@@ -47,7 +47,7 @@ type Tunnel struct {
4747 socksServer * socks5.Server
4848}
4949
50- //New Tunnel from the given Config
50+ // New Tunnel from the given Config
5151func New (c Config ) * Tunnel {
5252 c .Logger = c .Logger .Fork ("tun" )
5353 t := & Tunnel {
@@ -68,7 +68,7 @@ func New(c Config) *Tunnel {
6868 return t
6969}
7070
71- //BindSSH provides an active SSH for use for tunnelling
71+ // BindSSH provides an active SSH for use for tunnelling
7272func (t * Tunnel ) BindSSH (ctx context.Context , c ssh.Conn , reqs <- chan * ssh.Request , chans <- chan ssh.NewChannel ) error {
7373 //link ctx to ssh-conn
7474 go func () {
@@ -104,7 +104,7 @@ func (t *Tunnel) BindSSH(ctx context.Context, c ssh.Conn, reqs <-chan *ssh.Reque
104104 return err
105105}
106106
107- //getSSH blocks while connecting
107+ // getSSH blocks while connecting
108108func (t * Tunnel ) getSSH (ctx context.Context ) ssh.Conn {
109109 //cancelled already?
110110 if isDone (ctx ) {
@@ -140,8 +140,8 @@ func (t *Tunnel) activatingConnWait() <-chan struct{} {
140140 return ch
141141}
142142
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.
145145func (t * Tunnel ) BindRemotes (ctx context.Context , remotes []* settings.Remote ) error {
146146 if len (remotes ) == 0 {
147147 return errors .New ("no remotes" )
@@ -174,16 +174,48 @@ func (t *Tunnel) BindRemotes(ctx context.Context, remotes []*settings.Remote) er
174174
175175func (t * Tunnel ) keepAliveLoop (sshConn ssh.Conn ) {
176176 //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+
177186 for {
178187 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+
180216 if err != nil {
181217 break
182218 }
183- if len (b ) > 0 && ! bytes .Equal (b , []byte ("pong" )) {
184- t .Debugf ("strange ping response" )
185- break
186- }
187219 }
188220 //close ssh connection on abnormal ping
189221 sshConn .Close ()
0 commit comments