Compare commits
6 Commits
50ae422de8
...
v1.1.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
| abd103b5ab | |||
| 560c98b869 | |||
| e1f5d73e03 | |||
| 19fd6d59d2 | |||
| e3988b339f | |||
| 336948a397 |
4
go.mod
4
go.mod
@@ -4,7 +4,7 @@ go 1.25.5
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
git.fossy.my.id/bagas/tunnel-please-grpc v1.5.0
|
git.fossy.my.id/bagas/tunnel-please-grpc v1.5.0
|
||||||
github.com/caddyserver/certmagic v0.25.0
|
github.com/caddyserver/certmagic v0.25.1
|
||||||
github.com/charmbracelet/bubbles v0.21.0
|
github.com/charmbracelet/bubbles v0.21.0
|
||||||
github.com/charmbracelet/bubbletea v1.3.10
|
github.com/charmbracelet/bubbletea v1.3.10
|
||||||
github.com/charmbracelet/lipgloss v1.1.0
|
github.com/charmbracelet/lipgloss v1.1.0
|
||||||
@@ -19,7 +19,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/atotto/clipboard v0.1.4 // indirect
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
github.com/caddyserver/zerossl v0.1.4 // indirect
|
||||||
github.com/charmbracelet/colorprofile v0.4.1 // indirect
|
github.com/charmbracelet/colorprofile v0.4.1 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.11.3 // indirect
|
github.com/charmbracelet/x/ansi v0.11.3 // indirect
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
|
github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -12,8 +12,12 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWp
|
|||||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||||
github.com/caddyserver/certmagic v0.25.0 h1:VMleO/XA48gEWes5l+Fh6tRWo9bHkhwAEhx63i+F5ic=
|
github.com/caddyserver/certmagic v0.25.0 h1:VMleO/XA48gEWes5l+Fh6tRWo9bHkhwAEhx63i+F5ic=
|
||||||
github.com/caddyserver/certmagic v0.25.0/go.mod h1:m9yB7Mud24OQbPHOiipAoyKPn9pKHhpSJxXR1jydBxA=
|
github.com/caddyserver/certmagic v0.25.0/go.mod h1:m9yB7Mud24OQbPHOiipAoyKPn9pKHhpSJxXR1jydBxA=
|
||||||
|
github.com/caddyserver/certmagic v0.25.1 h1:4sIKKbOt5pg6+sL7tEwymE1x2bj6CHr80da1CRRIPbY=
|
||||||
|
github.com/caddyserver/certmagic v0.25.1/go.mod h1:VhyvndxtVton/Fo/wKhRoC46Rbw1fmjvQ3GjHYSQTEY=
|
||||||
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||||
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||||
|
github.com/caddyserver/zerossl v0.1.4 h1:CVJOE3MZeFisCERZjkxIcsqIH4fnFdlYWnPYeFtBHRw=
|
||||||
|
github.com/caddyserver/zerossl v0.1.4/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||||
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||||
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||||
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type Manager interface {
|
|||||||
AddPortRange(startPort, endPort uint16) error
|
AddPortRange(startPort, endPort uint16) error
|
||||||
GetUnassignedPort() (uint16, bool)
|
GetUnassignedPort() (uint16, bool)
|
||||||
SetPortStatus(port uint16, assigned bool) error
|
SetPortStatus(port uint16, assigned bool) error
|
||||||
GetPortStatus(port uint16) (bool, bool)
|
ClaimPort(port uint16) (claimed bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
type manager struct {
|
type manager struct {
|
||||||
@@ -74,7 +74,6 @@ func (pm *manager) GetUnassignedPort() (uint16, bool) {
|
|||||||
|
|
||||||
for _, port := range pm.sortedPorts {
|
for _, port := range pm.sortedPorts {
|
||||||
if !pm.ports[port] {
|
if !pm.ports[port] {
|
||||||
pm.ports[port] = true
|
|
||||||
return port, true
|
return port, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,10 +88,21 @@ func (pm *manager) SetPortStatus(port uint16, assigned bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *manager) GetPortStatus(port uint16) (bool, bool) {
|
func (pm *manager) ClaimPort(port uint16) (claimed bool) {
|
||||||
pm.mu.RLock()
|
pm.mu.Lock()
|
||||||
defer pm.mu.RUnlock()
|
defer pm.mu.Unlock()
|
||||||
|
|
||||||
status, exists := pm.ports[port]
|
status, exists := pm.ports[port]
|
||||||
return status, exists
|
|
||||||
|
if exists && status {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
pm.ports[port] = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.ports[port] = true
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ func (s *Server) handleConnection(conn net.Conn) {
|
|||||||
user = u
|
user = u
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("SSH connection established:", sshConn.User())
|
log.Println("SSH connection established:", sshConn.User())
|
||||||
sshSession := session.New(sshConn, forwardingReqs, chans, s.sessionRegistry, user)
|
sshSession := session.New(sshConn, forwardingReqs, chans, s.sessionRegistry, user)
|
||||||
err = sshSession.Start()
|
err = sshSession.Start()
|
||||||
|
|||||||
@@ -59,143 +59,79 @@ func (s *SSHSession) HandleGlobalRequest(GlobalRequest <-chan *ssh.Request) {
|
|||||||
func (s *SSHSession) HandleTCPIPForward(req *ssh.Request) {
|
func (s *SSHSession) HandleTCPIPForward(req *ssh.Request) {
|
||||||
log.Println("Port forwarding request detected")
|
log.Println("Port forwarding request detected")
|
||||||
|
|
||||||
|
fail := func(msg string) {
|
||||||
|
log.Println(msg)
|
||||||
|
if err := req.Reply(false, nil); err != nil {
|
||||||
|
log.Println("Failed to reply to request:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := s.lifecycle.Close(); err != nil {
|
||||||
|
log.Printf("failed to close session: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reader := bytes.NewReader(req.Payload)
|
reader := bytes.NewReader(req.Payload)
|
||||||
|
|
||||||
addr, err := readSSHString(reader)
|
addr, err := readSSHString(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to read address from payload:", err)
|
fail(fmt.Sprintf("Failed to read address from payload: %v", err))
|
||||||
err := req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.lifecycle.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close session: %v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var rawPortToBind uint32
|
var rawPortToBind uint32
|
||||||
if err := binary.Read(reader, binary.BigEndian, &rawPortToBind); err != nil {
|
if err = binary.Read(reader, binary.BigEndian, &rawPortToBind); err != nil {
|
||||||
log.Println("Failed to read port from payload:", err)
|
fail(fmt.Sprintf("Failed to read port from payload: %v", err))
|
||||||
err := req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.lifecycle.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close session: %v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if rawPortToBind > 65535 {
|
if rawPortToBind > 65535 {
|
||||||
log.Printf("Port %d is larger than allowed port of 65535", rawPortToBind)
|
fail(fmt.Sprintf("Port %d is larger than allowed port of 65535", rawPortToBind))
|
||||||
err := req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.lifecycle.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close session: %v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
portToBind := uint16(rawPortToBind)
|
portToBind := uint16(rawPortToBind)
|
||||||
if isBlockedPort(portToBind) {
|
if isBlockedPort(portToBind) {
|
||||||
log.Printf("Port %d is blocked or restricted", portToBind)
|
fail(fmt.Sprintf("Port %d is blocked or restricted", portToBind))
|
||||||
err := req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.lifecycle.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close session: %v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if portToBind == 80 || portToBind == 443 {
|
switch portToBind {
|
||||||
|
case 80, 443:
|
||||||
s.HandleHTTPForward(req, portToBind)
|
s.HandleHTTPForward(req, portToBind)
|
||||||
return
|
default:
|
||||||
}
|
|
||||||
if portToBind == 0 {
|
|
||||||
unassign, success := portUtil.Default.GetUnassignedPort()
|
|
||||||
portToBind = unassign
|
|
||||||
if !success {
|
|
||||||
log.Println("No available port")
|
|
||||||
err := req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.lifecycle.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close session: %v", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if isUse, isExist := portUtil.Default.GetPortStatus(portToBind); isExist && isUse {
|
|
||||||
log.Printf("Port %d is already in use or restricted", portToBind)
|
|
||||||
err := req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.lifecycle.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close session: %v", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = portUtil.Default.SetPortStatus(portToBind, true)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to set port status:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.HandleTCPForward(req, addr, portToBind)
|
s.HandleTCPForward(req, addr, portToBind)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SSHSession) HandleHTTPForward(req *ssh.Request, portToBind uint16) {
|
func (s *SSHSession) HandleHTTPForward(req *ssh.Request, portToBind uint16) {
|
||||||
slug := random.GenerateRandomString(20)
|
fail := func(msg string, key *types.SessionKey) {
|
||||||
key := types.SessionKey{Id: slug, Type: types.HTTP}
|
log.Println(msg)
|
||||||
|
if key != nil {
|
||||||
if !s.registry.Register(key, s) {
|
s.registry.Remove(*key)
|
||||||
log.Printf("Failed to register client with slug: %s", slug)
|
}
|
||||||
err := req.Reply(false, nil)
|
if err := req.Reply(false, nil); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
log.Println("Failed to reply to request:", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slug := random.GenerateRandomString(20)
|
||||||
|
key := types.SessionKey{Id: slug, Type: types.HTTP}
|
||||||
|
if !s.registry.Register(key, s) {
|
||||||
|
fail(fmt.Sprintf("Failed to register client with slug: %s", slug), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err := binary.Write(buf, binary.BigEndian, uint32(portToBind))
|
err := binary.Write(buf, binary.BigEndian, uint32(portToBind))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to write port to buffer:", err)
|
fail(fmt.Sprintf("Failed to write port to buffer: %v", err), &key)
|
||||||
s.registry.Remove(key)
|
|
||||||
err = req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("HTTP forwarding approved on port: %d", portToBind)
|
log.Printf("HTTP forwarding approved on port: %d", portToBind)
|
||||||
|
|
||||||
err = req.Reply(true, buf.Bytes())
|
err = req.Reply(true, buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to reply to request:", err)
|
fail(fmt.Sprintf("Failed to reply to request: %v", err), &key)
|
||||||
s.registry.Remove(key)
|
|
||||||
err = req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,76 +139,80 @@ func (s *SSHSession) HandleHTTPForward(req *ssh.Request, portToBind uint16) {
|
|||||||
s.forwarder.SetForwardedPort(portToBind)
|
s.forwarder.SetForwardedPort(portToBind)
|
||||||
s.slugManager.Set(slug)
|
s.slugManager.Set(slug)
|
||||||
s.lifecycle.SetStatus(types.RUNNING)
|
s.lifecycle.SetStatus(types.RUNNING)
|
||||||
s.interaction.Start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSHSession) HandleTCPForward(req *ssh.Request, addr string, portToBind uint16) {
|
func (s *SSHSession) HandleTCPForward(req *ssh.Request, addr string, portToBind uint16) {
|
||||||
log.Printf("Requested forwarding on %s:%d", addr, portToBind)
|
fail := func(msg string) {
|
||||||
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", portToBind))
|
log.Println(msg)
|
||||||
if err != nil {
|
if err := req.Reply(false, nil); err != nil {
|
||||||
log.Printf("Port %d is already in use or restricted", portToBind)
|
|
||||||
if setErr := portUtil.Default.SetPortStatus(portToBind, false); setErr != nil {
|
|
||||||
log.Printf("Failed to reset port status: %v", setErr)
|
|
||||||
}
|
|
||||||
err = req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
log.Println("Failed to reply to request:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = s.lifecycle.Close()
|
if err := s.lifecycle.Close(); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to close session: %v", err)
|
log.Printf("failed to close session: %v", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup := func(msg string, port uint16, listener net.Listener, key *types.SessionKey) {
|
||||||
|
log.Println(msg)
|
||||||
|
if key != nil {
|
||||||
|
s.registry.Remove(*key)
|
||||||
|
}
|
||||||
|
if port != 0 {
|
||||||
|
if setErr := portUtil.Default.SetPortStatus(port, false); setErr != nil {
|
||||||
|
log.Printf("Failed to reset port status: %v", setErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if listener != nil {
|
||||||
|
if closeErr := listener.Close(); closeErr != nil {
|
||||||
|
log.Printf("Failed to close listener: %v", closeErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := req.Reply(false, nil); err != nil {
|
||||||
|
log.Println("Failed to reply to request:", err)
|
||||||
|
}
|
||||||
|
_ = s.lifecycle.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if portToBind == 0 {
|
||||||
|
unassigned, ok := portUtil.Default.GetUnassignedPort()
|
||||||
|
if !ok {
|
||||||
|
fail("No available port")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
portToBind = unassigned
|
||||||
|
}
|
||||||
|
|
||||||
|
if claimed := portUtil.Default.ClaimPort(portToBind); !claimed {
|
||||||
|
fail(fmt.Sprintf("Port %d is already in use or restricted", portToBind))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Requested forwarding on %s:%d", addr, portToBind)
|
||||||
|
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", portToBind))
|
||||||
|
if err != nil {
|
||||||
|
cleanup(fmt.Sprintf("Port %d is already in use or restricted", portToBind), portToBind, nil, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
key := types.SessionKey{Id: fmt.Sprintf("%d", portToBind), Type: types.TCP}
|
key := types.SessionKey{Id: fmt.Sprintf("%d", portToBind), Type: types.TCP}
|
||||||
|
|
||||||
if !s.registry.Register(key, s) {
|
if !s.registry.Register(key, s) {
|
||||||
log.Printf("Failed to register TCP client with id: %s", key.Id)
|
cleanup(fmt.Sprintf("Failed to register TCP client with id: %s", key.Id), portToBind, listener, nil)
|
||||||
if setErr := portUtil.Default.SetPortStatus(portToBind, false); setErr != nil {
|
|
||||||
log.Printf("Failed to reset port status: %v", setErr)
|
|
||||||
}
|
|
||||||
if closeErr := listener.Close(); closeErr != nil {
|
|
||||||
log.Printf("Failed to close listener: %s", closeErr)
|
|
||||||
}
|
|
||||||
err = req.Reply(false, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to reply to request:", err)
|
|
||||||
}
|
|
||||||
_ = s.lifecycle.Close()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err = binary.Write(buf, binary.BigEndian, uint32(portToBind))
|
err = binary.Write(buf, binary.BigEndian, uint32(portToBind))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to write port to buffer:", err)
|
cleanup(fmt.Sprintf("Failed to write port to buffer: %v", err), portToBind, listener, &key)
|
||||||
s.registry.Remove(key)
|
|
||||||
if setErr := portUtil.Default.SetPortStatus(portToBind, false); setErr != nil {
|
|
||||||
log.Printf("Failed to reset port status: %v", setErr)
|
|
||||||
}
|
|
||||||
err = listener.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to close listener: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("TCP forwarding approved on port: %d", portToBind)
|
log.Printf("TCP forwarding approved on port: %d", portToBind)
|
||||||
err = req.Reply(true, buf.Bytes())
|
err = req.Reply(true, buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to reply to request:", err)
|
cleanup(fmt.Sprintf("Failed to reply to request: %v", err), portToBind, listener, &key)
|
||||||
s.registry.Remove(key)
|
|
||||||
if setErr := portUtil.Default.SetPortStatus(portToBind, false); setErr != nil {
|
|
||||||
log.Printf("Failed to reset port status: %v", setErr)
|
|
||||||
}
|
|
||||||
err = listener.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to close listener: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +222,6 @@ func (s *SSHSession) HandleTCPForward(req *ssh.Request, addr string, portToBind
|
|||||||
s.slugManager.Set(key.Id)
|
s.slugManager.Set(key.Id)
|
||||||
s.lifecycle.SetStatus(types.RUNNING)
|
s.lifecycle.SetStatus(types.RUNNING)
|
||||||
go s.forwarder.AcceptTCPConnections()
|
go s.forwarder.AcceptTCPConnections()
|
||||||
s.interaction.Start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSSHString(reader *bytes.Reader) (string, error) {
|
func readSSHString(reader *bytes.Reader) (string, error) {
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ type Controller interface {
|
|||||||
SetWH(w, h int)
|
SetWH(w, h int)
|
||||||
Redraw()
|
Redraw()
|
||||||
SetSessionRegistry(registry SessionRegistry)
|
SetSessionRegistry(registry SessionRegistry)
|
||||||
|
SetMode(m types.Mode)
|
||||||
|
GetMode() types.Mode
|
||||||
|
Send(message string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Forwarder interface {
|
type Forwarder interface {
|
||||||
@@ -54,8 +57,24 @@ type Interaction struct {
|
|||||||
program *tea.Program
|
program *tea.Program
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
mode types.Mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Interaction) SetMode(m types.Mode) {
|
||||||
|
i.mode = m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interaction) GetMode() types.Mode {
|
||||||
|
return i.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interaction) Send(message string) error {
|
||||||
|
if i.channel != nil {
|
||||||
|
_, err := i.channel.Write([]byte(message))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (i *Interaction) SetWH(w, h int) {
|
func (i *Interaction) SetWH(w, h int) {
|
||||||
if i.program != nil {
|
if i.program != nil {
|
||||||
i.program.Send(tea.WindowSizeMsg{
|
i.program.Send(tea.WindowSizeMsg{
|
||||||
@@ -749,6 +768,9 @@ func (m *model) View() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Interaction) Start() {
|
func (i *Interaction) Start() {
|
||||||
|
if i.mode == types.HEADLESS {
|
||||||
|
return
|
||||||
|
}
|
||||||
lipgloss.SetColorProfile(termenv.TrueColor)
|
lipgloss.SetColorProfile(termenv.TrueColor)
|
||||||
|
|
||||||
domain := config.Getenv("DOMAIN", "localhost")
|
domain := config.Getenv("DOMAIN", "localhost")
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"tunnel_pls/session/interaction"
|
"tunnel_pls/session/interaction"
|
||||||
"tunnel_pls/session/lifecycle"
|
"tunnel_pls/session/lifecycle"
|
||||||
"tunnel_pls/session/slug"
|
"tunnel_pls/session/slug"
|
||||||
|
"tunnel_pls/types"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
@@ -87,7 +88,14 @@ func (s *SSHSession) Detail() Detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSHSession) Start() error {
|
func (s *SSHSession) Start() error {
|
||||||
channel := <-s.sshReqChannel
|
var channel ssh.NewChannel
|
||||||
|
var ok bool
|
||||||
|
select {
|
||||||
|
case channel, ok = <-s.sshReqChannel:
|
||||||
|
if !ok {
|
||||||
|
log.Println("Forwarding request channel closed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
ch, reqs, err := channel.Accept()
|
ch, reqs, err := channel.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to accept channel: %v", err)
|
log.Printf("failed to accept channel: %v", err)
|
||||||
@@ -95,23 +103,41 @@ func (s *SSHSession) Start() error {
|
|||||||
}
|
}
|
||||||
go s.HandleGlobalRequest(reqs)
|
go s.HandleGlobalRequest(reqs)
|
||||||
|
|
||||||
|
s.lifecycle.SetChannel(ch)
|
||||||
|
s.interaction.SetChannel(ch)
|
||||||
|
s.interaction.SetMode(types.INTERACTIVE)
|
||||||
|
case <-time.After(500 * time.Millisecond):
|
||||||
|
s.interaction.SetMode(types.HEADLESS)
|
||||||
|
}
|
||||||
|
|
||||||
tcpipReq := s.waitForTCPIPForward()
|
tcpipReq := s.waitForTCPIPForward()
|
||||||
if tcpipReq == nil {
|
if tcpipReq == nil {
|
||||||
_, err := ch.Write([]byte(fmt.Sprintf("Port forwarding request not received. Ensure you ran the correct command with -R flag. Example: ssh %s -p %s -R 80:localhost:3000", config.Getenv("DOMAIN", "localhost"), config.Getenv("PORT", "2200"))))
|
err := s.interaction.Send(fmt.Sprintf("Port forwarding request not received. Ensure you ran the correct command with -R flag. Example: ssh %s -p %s -R 80:localhost:3000", config.Getenv("DOMAIN", "localhost"), config.Getenv("PORT", "2200")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.lifecycle.Close(); err != nil {
|
if err = s.lifecycle.Close(); err != nil {
|
||||||
log.Printf("failed to close session: %v", err)
|
log.Printf("failed to close session: %v", err)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("no forwarding Request")
|
return fmt.Errorf("no forwarding Request")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.lifecycle.SetChannel(ch)
|
if (s.interaction.GetMode() == types.HEADLESS && config.Getenv("MODE", "standalone") == "standalone") && s.lifecycle.GetUser() == "UNAUTHORIZED" {
|
||||||
s.interaction.SetChannel(ch)
|
if err := tcpipReq.Reply(false, nil); err != nil {
|
||||||
|
log.Printf("cannot reply to tcpip req: %s\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.lifecycle.Close(); err != nil {
|
||||||
|
log.Printf("failed to close session: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
s.HandleTCPIPForward(tcpipReq)
|
s.HandleTCPIPForward(tcpipReq)
|
||||||
|
s.interaction.Start()
|
||||||
|
|
||||||
|
s.lifecycle.GetConnection().Wait()
|
||||||
if err := s.lifecycle.Close(); err != nil {
|
if err := s.lifecycle.Close(); err != nil {
|
||||||
log.Printf("failed to close session: %v", err)
|
log.Printf("failed to close session: %v", err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -8,6 +8,13 @@ const (
|
|||||||
SETUP Status = "SETUP"
|
SETUP Status = "SETUP"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Mode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
INTERACTIVE Mode = "INTERACTIVE"
|
||||||
|
HEADLESS Mode = "HEADLESS"
|
||||||
|
)
|
||||||
|
|
||||||
type TunnelType string
|
type TunnelType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
Reference in New Issue
Block a user