package funcs import ( "bytes" "fmt" "io/ioutil" "net" "strconv" "strings" "time" "github.com/shanghai-edu/multissh/g" "golang.org/x/crypto/ssh" ) func connect(user, password, host, key string, port int, cipherList []string) (*ssh.Session, error) { var ( auth []ssh.AuthMethod addr string clientConfig *ssh.ClientConfig client *ssh.Client config ssh.Config session *ssh.Session err error ) // get auth method auth = make([]ssh.AuthMethod, 0) if key == "" { auth = append(auth, ssh.Password(password)) } else { pemBytes, err := ioutil.ReadFile(key) if err != nil { return nil, err } var signer ssh.Signer if password == "" { signer, err = ssh.ParsePrivateKey(pemBytes) } else { signer, err = ssh.ParsePrivateKeyWithPassphrase(pemBytes, []byte(password)) } if err != nil { return nil, err } auth = append(auth, ssh.PublicKeys(signer)) } if len(cipherList) == 0 { config = ssh.Config{ Ciphers: []string{"aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "aes192-cbc", "aes256-cbc"}, KeyExchanges: []string{"diffie-hellman-group-exchange-sha1", "diffie-hellman-group1-sha1", "diffie-hellman-group-exchange-sha256"}, } } else { config = ssh.Config{ Ciphers: cipherList, } } clientConfig = &ssh.ClientConfig{ User: user, Auth: auth, Timeout: 30 * time.Second, Config: config, HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, } // connet to ssh addr = fmt.Sprintf("%s:%d", host, port) if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil { return nil, err } // create session if session, err = client.NewSession(); err != nil { return nil, err } 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 } if err := session.RequestPty("xterm", 80, 40, modes); err != nil { return nil, err } return session, nil } func Dossh(username, password, host, key string, cmdlist []string, port, timeout int, cipherList []string, linuxMode bool, ch chan g.SSHResult) { chSSH := make(chan g.SSHResult) if linuxMode { go dossh_run(username, password, host, key, cmdlist, port, cipherList, chSSH) } else { go dossh_session(username, password, host, key, cmdlist, port, cipherList, chSSH) } var res g.SSHResult select { case <-time.After(time.Duration(timeout) * time.Second): res.Host = host res.Success = false res.Result = ("SSH run timeout:" + strconv.Itoa(timeout) + " second.") ch <- res case res = <-chSSH: ch <- res } return } func dossh_session(username, password, host, key string, cmdlist []string, port int, cipherList []string, ch chan g.SSHResult) { session, err := connect(username, password, host, key, port, cipherList) var sshResult g.SSHResult sshResult.Host = host if err != nil { sshResult.Success = false sshResult.Result = fmt.Sprintf("<%s>", err.Error()) ch <- sshResult return } defer session.Close() cmdlist = append(cmdlist, "exit") stdinBuf, _ := session.StdinPipe() var outbt, errbt bytes.Buffer session.Stdout = &outbt session.Stderr = &errbt err = session.Shell() if err != nil { sshResult.Success = false sshResult.Result = fmt.Sprintf("<%s>", err.Error()) ch <- sshResult return } for _, c := range cmdlist { c = c + "\n" stdinBuf.Write([]byte(c)) } session.Wait() if errbt.String() != "" { sshResult.Success = false sshResult.Result = errbt.String() ch <- sshResult } else { sshResult.Success = true sshResult.Result = outbt.String() ch <- sshResult } return } func dossh_run(username, password, host, key string, cmdlist []string, port int, cipherList []string, ch chan g.SSHResult) { session, err := connect(username, password, host, key, port, cipherList) var sshResult g.SSHResult sshResult.Host = host if err != nil { sshResult.Success = false sshResult.Result = fmt.Sprintf("<%s>", err.Error()) ch <- sshResult return } defer session.Close() cmdlist = append(cmdlist, "exit") newcmd := strings.Join(cmdlist, "&&") var outbt, errbt bytes.Buffer session.Stdout = &outbt session.Stderr = &errbt err = session.Run(newcmd) if err != nil { sshResult.Success = false sshResult.Result = fmt.Sprintf("<%s>", err.Error()) ch <- sshResult return } if errbt.String() != "" { sshResult.Success = false sshResult.Result = errbt.String() ch <- sshResult } else { sshResult.Success = true sshResult.Result = outbt.String() ch <- sshResult } return }