Files
tunnel-please/session/session.go
bagas 69c3e78728
All checks were successful
Docker Build and Push / build-and-push (push) Successful in 5m7s
fix: correct read/write handling in CustomWriter
2025-12-06 22:18:43 +07:00

135 lines
3.0 KiB
Go

package session
import (
"bytes"
"log"
"sync"
"tunnel_pls/session/forwarder"
"tunnel_pls/session/interaction"
"tunnel_pls/session/lifecycle"
"tunnel_pls/session/slug"
"tunnel_pls/types"
"golang.org/x/crypto/ssh"
)
var (
clientsMutex sync.RWMutex
Clients = make(map[string]*SSHSession)
)
type Session interface {
HandleGlobalRequest(ch <-chan *ssh.Request)
HandleTCPIPForward(req *ssh.Request)
HandleHTTPForward(req *ssh.Request, port uint16)
HandleTCPForward(req *ssh.Request, addr string, port uint16)
}
type SSHSession struct {
Lifecycle lifecycle.SessionLifecycle
Interaction interaction.Controller
Forwarder forwarder.ForwardingController
SlugManager slug.Manager
channelOnce sync.Once
}
func New(conn *ssh.ServerConn, forwardingReq <-chan *ssh.Request, sshChan <-chan ssh.NewChannel) {
slugManager := slug.NewManager()
forwarderManager := &forwarder.Forwarder{
Listener: nil,
TunnelType: "",
ForwardedPort: 0,
SlugManager: slugManager,
}
interactionManager := &interaction.Interaction{
CommandBuffer: bytes.NewBuffer(make([]byte, 0, 20)),
EditMode: false,
EditSlug: "",
SlugManager: slugManager,
Forwarder: forwarderManager,
Lifecycle: nil,
}
lifecycleManager := &lifecycle.Lifecycle{
Status: "",
Conn: conn,
Channel: nil,
Interaction: interactionManager,
Forwarder: forwarderManager,
SlugManager: slugManager,
}
interactionManager.SetLifecycle(lifecycleManager)
interactionManager.SetSlugModificator(updateClientSlug)
forwarderManager.SetLifecycle(lifecycleManager)
lifecycleManager.SetUnregisterClient(unregisterClient)
session := &SSHSession{
Lifecycle: lifecycleManager,
Interaction: interactionManager,
Forwarder: forwarderManager,
SlugManager: slugManager,
}
go func() {
go session.Lifecycle.WaitForRunningStatus()
for channel := range sshChan {
ch, reqs, err := channel.Accept()
if err != nil {
log.Printf("failed to accept channel: %v", err)
continue
}
session.channelOnce.Do(func() {
session.Lifecycle.SetChannel(ch)
session.Interaction.SetChannel(ch)
session.Lifecycle.SetStatus(types.SETUP)
go session.HandleGlobalRequest(forwardingReq)
})
go session.HandleGlobalRequest(reqs)
}
if err := session.Lifecycle.Close(); err != nil {
log.Printf("failed to close session: %v", err)
}
}()
}
func updateClientSlug(oldSlug, newSlug string) bool {
clientsMutex.Lock()
defer clientsMutex.Unlock()
if _, exists := Clients[newSlug]; exists && newSlug != oldSlug {
return false
}
client, ok := Clients[oldSlug]
if !ok {
return false
}
delete(Clients, oldSlug)
client.SlugManager.Set(newSlug)
Clients[newSlug] = client
return true
}
func registerClient(slug string, session *SSHSession) bool {
clientsMutex.Lock()
defer clientsMutex.Unlock()
if _, exists := Clients[slug]; exists {
return false
}
Clients[slug] = session
return true
}
func unregisterClient(slug string) {
clientsMutex.Lock()
defer clientsMutex.Unlock()
delete(Clients, slug)
}