Files
kubevpn/pkg/ssh/reverse.go
2025-04-24 22:41:24 +08:00

76 lines
2.1 KiB
Go

/*
SSH Reverse Tunnel, the equivalent of below SSH command:
ssh -R 8080:127.0.0.1:8080 operatore@146.148.22.123
which opens a tunnel between the two endpoints and permit to exchange information on this direction:
server:8080 -----> client:8080
once authenticated a process on the SSH server can interact with the service answering to port 8080 of the client
without any NAT rule via firewall
*/
package ssh
import (
"context"
"net"
"net/netip"
"time"
"golang.org/x/crypto/ssh"
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
)
// ExposeLocalPortToRemote
// remote forwarding port (on remote SSH server network)
// local service to be forwarded
func ExposeLocalPortToRemote(ctx context.Context, remoteSSHServer, remotePort, localPort netip.AddrPort) error {
// refer to https://godoc.org/golang.org/x/crypto/ssh for other authentication types
sshConfig := &ssh.ClientConfig{
Auth: []ssh.AuthMethod{},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: time.Second * 10,
}
// Connect to SSH remote server using serverEndpoint
serverConn, err := ssh.Dial("tcp", remoteSSHServer.String(), sshConfig)
if err != nil {
plog.G(ctx).Errorf("Dial into remote server error: %s", err)
return err
}
defer serverConn.Close()
// Listen on remote server port
listener, err := serverConn.Listen("tcp", remotePort.String())
if err != nil {
plog.G(ctx).Errorf("Listen open port on remote server error: %s", err)
return err
}
defer listener.Close()
go func() {
<-ctx.Done()
listener.Close()
serverConn.Close()
}()
// handle incoming connections on reverse forwarded tunnel
for {
client, err := listener.Accept()
if err != nil {
plog.G(ctx).Errorf("Accept on remote service error: %s", err)
return err
}
go func(client net.Conn) {
defer client.Close()
// Open a (local) connection to localEndpoint whose content will be forwarded so serverEndpoint
local, err := net.Dial("tcp", localPort.String())
if err != nil {
plog.G(ctx).Errorf("Dial INTO local service error: %s", err)
return
}
defer local.Close()
copyStream(ctx, client, local)
}(client)
}
}