package main import ( "bytes" "fmt" "github.com/gliderlabs/ssh" "github.com/kr/pty" "io" "log" "net/http" "os/exec" "flag" ) var ( metrics_num_passwords int ) func handleConnection(s ssh.Session) { cmd := exec.Command("bash") p, _ := pty.Start(cmd) go func() { var readErr error for readErr == nil { // create two buffers, one for storing the char input (buf) // and the other for storing complete commands (commandBuffer) buf := make([]byte, 1024) var command []byte for string(bytes.Trim(buf, "\x00")) != "\x0d" { _, readErr = s.Read(buf) input := string(bytes.Trim(buf, "\x00")) io.WriteString(s, input) if len(string(bytes.Trim(buf, "\x00"))) > 0 { command = append(command, bytes.Trim(buf, "\x00")[0]) } } var commandString string for _, char := range command { commandString += string(char) } log.Printf("Command: %s", commandString) s.Close() return } }() io.Copy(s, p) s.Close() } func filter(buffer string) string { // allways return a newline -> track what is input log.Printf("%s", buffer) return "\n" } func handlePass(ctx ssh.Context, pass string) bool { metrics_num_passwords++ log.Printf("%s@%s: '%s'", ctx.User(), ctx.RemoteAddr().String(), pass) return true } // Handle HTTP /metrics requests func metricsHandler(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "num_passwords %d\n", metrics_num_passwords) } func main() { log.Println("Starting SSH listener") var port string flag.StringVar(&port, "port", "2222", "port used to host the service") flag.Parse() log.Printf("port: %s", port) go func() { // star the metrics listener log.Println("Starting HTTP metrics listener") http.HandleFunc("/metrics", metricsHandler) listenErr := http.ListenAndServe(":8081", nil) if listenErr != nil { log.Fatalln(listenErr.Error()) } }() ssh.Handle(handleConnection) log.Fatal(ssh.ListenAndServe(fmt.Sprintf(":%s", port), nil, ssh.PasswordAuth(handlePass))) }