package main
import (
"flag"
"fmt"
"golang.org/x/crypto/ssh"
"io"
"log"
"strings"
"time"
)
func readBuffForString(whattoexpect string, sshOut io.Reader, buffRead chan<- string) {
buf := make([]byte, 1000)
waitingString := ""
for {
n, err := sshOut.Read(buf) //this reads the ssh terminal
if err != nil && err != io.EOF{
fmt.Println(err)
break
}
if err == io.EOF || n == 0 {
break
}
fmt.Println(string(buf[:n]))
waitingString += string(buf[:n])
}
//n, err := sshOut.Read(buf) //this reads the ssh terminal
//waitingString := ""
//if err == nil {
// waitingString = string(buf[:n])
//}
//for (err == nil) && (!strings.Contains(waitingString, whattoexpect)) {
// n, err = sshOut.Read(buf)
// waitingString += string(buf[:n])
// //fmt.Println(waitingString) //uncommenting this might help you debug if you are coming into errors with timeouts when correct details entered
//}
buffRead <- waitingString
}
func readBuff(whattoexpect string, sshOut io.Reader, timeoutSeconds int) string {
ch := make(chan string)
go func(whattoexpect string, sshOut io.Reader) {
buffRead := make(chan string)
go readBuffForString(whattoexpect, sshOut, buffRead)
select {
case ret := <-buffRead:
ch <- ret
case <-time.After(time.Duration(timeoutSeconds) * time.Second):
handleError(fmt.Errorf("%d", timeoutSeconds), true, "Waiting for \""+whattoexpect+"\" took longer than %s seconds, perhaps you've entered incorrect details?")
}
}(whattoexpect, sshOut)
return <-ch
}
func writeBuff(command string, sshIn io.WriteCloser) (int, error) {
returnCode, err := sshIn.Write([]byte(command + "\r"))
return returnCode, err
}
func handleError(e error, fatal bool, customMessage ...string) {
var errorMessage string
if e != nil {
if len(customMessage) > 0 {
errorMessage = strings.Join(customMessage, " ")
} else {
errorMessage = "%s"
}
if fatal == true {
log.Fatalf(errorMessage, e)
} else {
log.Print(errorMessage, e)
}
}
}
func main() {
flag.Parse()
sshConfig := &ssh.ClientConfig{
User: "admin",
Auth: []ssh.AuthMethod{
ssh.Password("r00ttest"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
modes := ssh.TerminalModes{
ssh.ECHO: 0, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
connection, err := ssh.Dial("tcp", "172.16.240.189:22", sshConfig)
if err != nil {
log.Fatalf("Failed to dial: %s", err)
}
session, err := connection.NewSession()
handleError(err, true, "Failed to create session: %s")
sshOut, err := session.StdoutPipe()
handleError(err, true, "Unable to setup stdin for session: %v")
sshIn, err := session.StdinPipe()
handleError(err, true, "Unable to setup stdout for session: %v")
//sshErr, err := session.StderrPipe()
//handleError(err, true, "Unable to setup stderr for session: %v")
if err := session.RequestPty("xterm", 0, 200, modes); err != nil {
session.Close()
handleError(err, true, "request for pseudo terminal failed: %s")
}
if err := session.Shell(); err != nil {
session.Close()
handleError(err, true, "request for shell failed: %s")
}
fmt.Print(readBuff(">", sshOut, 2))
if _, err := writeBuff("configure", sshIn); err != nil {
handleError(err, true, "Failed to run: %s")
}
fmt.Println(readBuff("#", sshOut, 2))
if _, err := writeBuff("set system host-name fuckme", sshIn); err != nil {
handleError(err, true, "Failed to run: %s")
}
fmt.Println(readBuff("#", sshOut, 2))
//fmt.Print(readBuff("", sshErr, 2))
if _, err := writeBuff("commit", sshIn); err != nil {
handleError(err, true, "Failed to run: %s")
}
fmt.Println(readBuff("#", sshOut, 20))
if _, err := writeBuff("show system", sshIn); err != nil {
handleError(err, true, "Failed to run: %s")
}
fmt.Println(readBuff("[edit]", sshOut, 20))
session.Close()
}
in the func readBuffForString, how to get the buffer end like io.EOF ?
the commented code is not a elegant way to do that
strings.Contains(waitingString, whattoexpect)