package main import ( "bytes" "fmt" "github.com/gliderlabs/ssh" "github.com/kr/pty" "io" "log" "net/http" "os/exec" ) var ( metrics_num_passwords int ) func main() { log.Println("Starting SSH listener") //// start the ssh server //go func() { // listenErr := ssh.ListenAndServe(":2222", nil, ssh.PasswordAuth(handlePass)) // if listenErr != nil { // log.Fatalln(listenErr.Error()) // } //}() go func() { // star the metrics listener log.Println("Starting HTTP metrics listener") http.HandleFunc("/metrics", metricsHandler) listenErr := http.ListenAndServe(":8080", nil) if listenErr != nil { log.Fatalln(listenErr.Error()) } }() ssh.Handle(handleConnection) log.Fatal(ssh.ListenAndServe(":2222", nil, ssh.PasswordAuth(handlePass))) } 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) commandBuffer := make([]byte, 0) // the current char var char string // read until ENTER is pressed for char != "\x0d"{ // read the char inserted by the user into the buffer _, readErr = s.Read(buf) // trim the char and append it to the commandBuffer char1 := bytes.Trim(buf, "\x00")[0] if char1 == []byte("\x03")[0] { s.Close() return } commandBuffer = append(commandBuffer, char1) // write the char to stdout char = string(bytes.Trim(buf, "\x00")) input := string(bytes.Trim(buf, "\x00")) io.WriteString(s, input) } // prepare the command for execution input := string(bytes.Trim(commandBuffer, "\x00")) // filter out unwanted commands filteredInput := filter(input) // write the string to the commandHandler io.WriteString(p, filteredInput) s.Close() return } }() io.Copy(s, p) s.Close() } func filter(buffer string) string { //if strings.Contains(buffer, "wget") == false { // return "\n" //} //return buffer // all ways 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) }