package ssh import ( "fmt" "io" "net" gossh "golang.org/x/crypto/ssh" ) // direct-tcpip data struct as specified in RFC4254, Section 7.2 type forwardData struct { DestinationHost string DestinationPort uint32 OriginatorHost string OriginatorPort uint32 } func directTcpipHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx *sshContext) { d := forwardData{} if err := gossh.Unmarshal(newChan.ExtraData(), &d); err != nil { newChan.Reject(gossh.ConnectionFailed, "error parsing forward data: "+err.Error()) return } if srv.LocalPortForwardingCallback == nil || !srv.LocalPortForwardingCallback(ctx, d.DestinationHost, d.DestinationPort) { newChan.Reject(gossh.Prohibited, "port forwarding is disabled") return } dest := fmt.Sprintf("%s:%d", d.DestinationHost, d.DestinationPort) var dialer net.Dialer dconn, err := dialer.DialContext(ctx, "tcp", dest) if err != nil { newChan.Reject(gossh.ConnectionFailed, err.Error()) return } ch, reqs, err := newChan.Accept() if err != nil { dconn.Close() return } go gossh.DiscardRequests(reqs) go func() { defer ch.Close() defer dconn.Close() io.Copy(ch, dconn) }() go func() { defer ch.Close() defer dconn.Close() io.Copy(dconn, ch) }() }