// Make new terminal from a session channel func NewTerminal(conn *ssh.ServerConn, ch ssh.NewChannel) (*Terminal, error) { if ch.ChannelType() != "session" { return nil, errors.New("terminal requires session channel") } channel, requests, err := ch.Accept() if err != nil { return nil, err } term := Terminal{ *terminal.NewTerminal(channel, "Connecting..."), sshConn{conn}, channel, } go term.listen(requests) go func() { // FIXME: Is this necessary? conn.Wait() channel.Close() }() return &term, nil }
func handleRegs(reqs <-chan *ssh.Request, sshConn *ssh.ServerConn) { defer sshConn.Close() for req := range reqs { if req.Type == "keepalive" && req.WantReply { req.Reply(true, nil) continue } var payload tcpipforwardPayload if err := ssh.Unmarshal(req.Payload, &payload); err != nil { fmt.Println("ERROR", err) continue } addr := fmt.Sprintf("%s:%d", payload.Addr, payload.Port) ln, err := net.Listen("tcp", addr) if err != nil { fmt.Println("Unable to listen on address: ", addr) req.Reply(false, nil) continue } defer ln.Close() reply := (payload.Port == 0) && req.WantReply if !reply { req.Reply(true, nil) } else { req.Reply(false, nil) } go func() { fmt.Println("Listening on address: ", ln.Addr().String()) quit := make(chan bool) go func() { go func() { t := time.NewTicker(30 * time.Second) defer t.Stop() for { <-t.C _, _, err := sshConn.SendRequest("keepalive", true, nil) if err != nil { fmt.Println("closed", sshConn) sshConn.Close() return } } }() for { select { case <-quit: return default: conn, err := ln.Accept() if err != nil { continue } go func(conn net.Conn) { p := forwardedTCPPayload{} var err error var portnum int p.Addr = payload.Addr p.Port = payload.Port p.OriginAddr, portnum, err = getHostPortFromAddr(conn.RemoteAddr()) if err != nil { conn.Close() return } p.OriginPort = uint32(portnum) ch, reqs, err := sshConn.OpenChannel("forwarded-tcpip", ssh.Marshal(p)) if err != nil { conn.Close() log.Println("Open forwarded Channel: ", err.Error()) return } go ssh.DiscardRequests(reqs) go func(ch ssh.Channel, conn net.Conn) { close := func() { ch.Close() conn.Close() } go copyConnections(conn, ch, close) }(ch, conn) }(conn) } } }() sshConn.Wait() fmt.Println("Stop forwarding/listening on ", ln.Addr()) quit <- true }() } }
func (server *registrarSSHServer) handleConn(logger lager.Logger, conn *ssh.ServerConn, chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request) { defer conn.Close() forwardedTCPIPs := make(chan forwardedTCPIP, 1) go server.handleForwardRequests(logger, conn, reqs, forwardedTCPIPs) var processes []ifrit.Process // ensure processes get cleaned up defer func() { cleanupLog := logger.Session("cleanup") for _, p := range processes { cleanupLog.Debug("interrupting") p.Signal(os.Interrupt) } for _, p := range processes { err := <-p.Wait() if err != nil { cleanupLog.Error("process-exited-with-failure", err) } else { cleanupLog.Debug("process-exited-successfully") } } }() for newChannel := range chans { if newChannel.ChannelType() != "session" { logger.Info("rejecting-unknown-channel-type", lager.Data{ "type": newChannel.ChannelType(), }) newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") continue } channel, requests, err := newChannel.Accept() if err != nil { logger.Error("failed-to-accept-channel", err) return } defer channel.Close() for req := range requests { logger.Info("channel-request", lager.Data{ "type": req.Type, }) if req.Type != "exec" { logger.Info("rejecting") req.Reply(false, nil) continue } var request execRequest err = ssh.Unmarshal(req.Payload, &request) if err != nil { logger.Error("malformed-exec-request", err) req.Reply(false, nil) return } switch request.Command { case "register-worker": logger := logger.Session("register-worker") req.Reply(true, nil) process, err := server.continuouslyRegisterWorkerDirectly(logger, channel) if err != nil { logger.Error("failed-to-register", err) return } processes = append(processes, process) err = conn.Wait() logger.Error("connection-closed", err) case "forward-worker": logger := logger.Session("forward-worker") var forwarded forwardedTCPIP select { case forwarded = <-forwardedTCPIPs: logger.Info("forwarded-tcpip", lager.Data{ "bound-port": forwarded.boundPort, }) processes = append(processes, forwarded.process) process, err := server.continuouslyRegisterForwardedWorker(logger, channel, forwarded.boundPort) if err != nil { logger.Error("failed-to-register", err) return } processes = append(processes, process) err = conn.Wait() logger.Error("connection-closed", err) case <-time.After(10 * time.Second): // todo better? logger.Info("never-forwarded-tcpip") } default: logger.Info("invalid-command", lager.Data{ "command": request.Command, }) req.Reply(false, nil) } } } }