66 lines
1.5 KiB
Go
66 lines
1.5 KiB
Go
package gateway
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
|
|
"next-terminal/server/log"
|
|
)
|
|
|
|
type Tunnel struct {
|
|
ID string // 唯一标识
|
|
LocalHost string // 本地监听地址
|
|
LocalPort int // 本地端口
|
|
RemoteHost string // 远程连接地址
|
|
RemotePort int // 远程端口
|
|
Gateway *Gateway
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
listener net.Listener
|
|
err error
|
|
}
|
|
|
|
func (r *Tunnel) Open() {
|
|
localAddr := fmt.Sprintf("%s:%d", r.LocalHost, r.LocalPort)
|
|
for {
|
|
select {
|
|
case <-r.ctx.Done():
|
|
_ = r.listener.Close()
|
|
log.Debugf("SSH 隧道 %v 关闭", localAddr)
|
|
return
|
|
default:
|
|
log.Debugf("等待客户端访问 %v", localAddr)
|
|
localConn, err := r.listener.Accept()
|
|
if err != nil {
|
|
log.Debugf("接受连接失败 %v", err.Error())
|
|
continue
|
|
}
|
|
|
|
log.Debugf("客户端 %v 连接至 %v", localConn.RemoteAddr().String(), localAddr)
|
|
remoteAddr := fmt.Sprintf("%s:%d", r.RemoteHost, r.RemotePort)
|
|
log.Debugf("连接远程主机 %v ...", remoteAddr)
|
|
remoteConn, err := r.Gateway.SshClient.Dial("tcp", remoteAddr)
|
|
if err != nil {
|
|
log.Debugf("连接远程主机 %v 失败", remoteAddr)
|
|
r.err = err
|
|
return
|
|
}
|
|
|
|
log.Debugf("连接远程主机 %v 成功", remoteAddr)
|
|
go copyConn(localConn, remoteConn)
|
|
go copyConn(remoteConn, localConn)
|
|
log.Debugf("转发数据 [%v]->[%v]", localAddr, remoteAddr)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r Tunnel) Close() {
|
|
r.cancel()
|
|
}
|
|
|
|
func copyConn(writer, reader net.Conn) {
|
|
_, _ = io.Copy(writer, reader)
|
|
}
|