Beispiel #1
0
// 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
}
Beispiel #2
0
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
		}()
	}
}
Beispiel #3
0
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)
			}
		}
	}
}