fix: Fix disconnect handler not working in production
All checks were successful
Release code / build (push) Successful in 8m28s
All checks were successful
Release code / build (push) Successful in 8m28s
This commit is contained in:
parent
24b165c9bb
commit
959718163e
1 changed files with 93 additions and 17 deletions
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -18,6 +19,32 @@ import (
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ConnWithTimeout struct {
|
||||||
|
net.Conn
|
||||||
|
ReadTimeout time.Duration
|
||||||
|
WriteTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWithTimeout) Read(b []byte) (int, error) {
|
||||||
|
err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Conn.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWithTimeout) Write(b []byte) (int, error) {
|
||||||
|
err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Conn.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
type SSHListener struct {
|
type SSHListener struct {
|
||||||
SourceIP string
|
SourceIP string
|
||||||
SourcePort uint16
|
SourcePort uint16
|
||||||
|
@ -76,16 +103,34 @@ func (backend *SSHBackend) StartBackend(bytes []byte) (bool, error) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", backendData.IP, backendData.Port), config)
|
addr := fmt.Sprintf("%s:%d", backendData.IP, backendData.Port)
|
||||||
|
timeout := time.Duration(10 * time.Second)
|
||||||
|
|
||||||
|
rawTCPConn, err := net.DialTimeout("tcp", addr, timeout)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
backend.conn = conn
|
connWithTimeout := &ConnWithTimeout{
|
||||||
|
Conn: rawTCPConn,
|
||||||
|
ReadTimeout: timeout,
|
||||||
|
WriteTimeout: timeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
c, chans, reqs, err := ssh.NewClientConn(connWithTimeout, addr, config)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := ssh.NewClient(c, chans, reqs)
|
||||||
|
backend.conn = client
|
||||||
|
|
||||||
|
go backend.backendDisconnectHandler()
|
||||||
|
go backend.backendKeepaliveHandler()
|
||||||
|
|
||||||
log.Info("SSHBackend has initialized successfully.")
|
log.Info("SSHBackend has initialized successfully.")
|
||||||
go backend.backendDisconnectHandler()
|
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -203,8 +248,7 @@ func (backend *SSHBackend) StartProxy(command *commonbackend.AddProxy) (bool, er
|
||||||
// Splice out the clientInstance by clientIndex
|
// Splice out the clientInstance by clientIndex
|
||||||
|
|
||||||
// TODO: change approach. It works but it's a bit wonky imho
|
// TODO: change approach. It works but it's a bit wonky imho
|
||||||
// I asked AI to do this as it's a relatively simple task and I forgot how to do this effectively
|
backend.clients = slices.Delete(backend.clients, clientIndex, clientIndex+1)
|
||||||
backend.clients = append(backend.clients[:clientIndex], backend.clients[clientIndex+1:]...)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,10 +332,8 @@ func (backend *SSHBackend) StopProxy(command *commonbackend.RemoveProxy) (bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splice out the proxy instance by proxyIndex
|
// Splice out the proxy instance by proxyIndex
|
||||||
|
|
||||||
// TODO: change approach. It works but it's a bit wonky imho
|
// TODO: change approach. It works but it's a bit wonky imho
|
||||||
// I asked AI to do this as it's a relatively simple task and I forgot how to do this effectively
|
backend.proxies = slices.Delete(backend.proxies, proxyIndex, proxyIndex+1)
|
||||||
backend.proxies = append(backend.proxies[:proxyIndex], backend.proxies[proxyIndex+1:]...)
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,17 +383,31 @@ func (backend *SSHBackend) CheckParametersForBackend(arguments []byte) *commonba
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *SSHBackend) backendDisconnectHandler() {
|
func (backend *SSHBackend) backendKeepaliveHandler() {
|
||||||
for {
|
for {
|
||||||
if backend.conn != nil {
|
if backend.conn != nil {
|
||||||
err := backend.conn.Wait()
|
_, _, err := backend.conn.SendRequest("keepalive@openssh.com", true, nil)
|
||||||
|
|
||||||
if err == nil || err.Error() != "EOF" {
|
if err != nil {
|
||||||
continue
|
log.Warn("Keepalive message failed!")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Disconnected from the remote SSH server. Attempting to reconnect in 5 seconds...")
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (backend *SSHBackend) backendDisconnectHandler() {
|
||||||
|
for {
|
||||||
|
if backend.conn != nil {
|
||||||
|
backend.conn.Wait()
|
||||||
|
backend.conn.Close()
|
||||||
|
|
||||||
|
log.Info("Disconnected from the remote SSH server. Attempting to reconnect in 5 seconds...")
|
||||||
|
} else {
|
||||||
|
log.Info("Retrying reconnection in 5 seconds...")
|
||||||
|
}
|
||||||
|
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
@ -376,14 +432,34 @@ func (backend *SSHBackend) backendDisconnectHandler() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", backend.config.IP, backend.config.Port), config)
|
addr := fmt.Sprintf("%s:%d", backend.config.IP, backend.config.Port)
|
||||||
|
timeout := time.Duration(10 * time.Second)
|
||||||
|
|
||||||
|
rawTCPConn, err := net.DialTimeout("tcp", addr, timeout)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to connect to the server: %s", err.Error())
|
log.Errorf("Failed to establish connection to the server: %s", err.Error())
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
backend.conn = conn
|
connWithTimeout := &ConnWithTimeout{
|
||||||
|
Conn: rawTCPConn,
|
||||||
|
ReadTimeout: timeout,
|
||||||
|
WriteTimeout: timeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
c, chans, reqs, err := ssh.NewClientConn(connWithTimeout, addr, config)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to create SSH client connection: %s", err.Error())
|
||||||
|
rawTCPConn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
client := ssh.NewClient(c, chans, reqs)
|
||||||
|
backend.conn = client
|
||||||
|
|
||||||
|
go backend.backendKeepaliveHandler()
|
||||||
|
|
||||||
log.Info("SSHBackend has reconnected successfully. Attempting to set up proxies again...")
|
log.Info("SSHBackend has reconnected successfully. Attempting to set up proxies again...")
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue