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) Run() { localAddr := fmt.Sprintf("%s:%d", r.LocalHost, r.LocalPort) log.Debugf("等待客户端访问 [%v] ...", localAddr) localConn, err := r.listener.Accept() if err != nil { r.err = err return } 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) go func() { <-r.ctx.Done() _ = r.listener.Close() _ = localConn.Close() _ = remoteConn.Close() log.Debugf("SSH隧道 [%v]-[%v] 已关闭", localAddr, remoteAddr) }() } func (r Tunnel) Close() { r.cancel() } func copyConn(writer, reader net.Conn) { _, _ = io.Copy(writer, reader) }