commit 54cdb80ef7f1972182b57953bf598caa6abc2bd3 Author: root Date: Thu Feb 21 09:37:54 2019 +0800 init diff --git a/ssh.go b/ssh.go new file mode 100644 index 0000000..f8558f9 --- /dev/null +++ b/ssh.go @@ -0,0 +1,286 @@ +package sshd + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "net" + "os" + "path" + "regexp" + "time" + + "github.com/pkg/sftp" + "golang.org/x/crypto/ssh" +) + +var ShellRes, ShellErr string +var ShellExit bool + +type sshd struct { + SSHC *ssh.Session + infile io.Writer + outfile io.Reader + errfile io.Reader + thread bool + counter int +} + +func NewTransferSession(client *ssh.Client) (*ssh.Session, error) { + session, err := client.NewSession() + return session, err +} +func NewSession(client *ssh.Client) (*ssh.Session, error) { + var session *ssh.Session + var err error + // 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 Connect(user, password, host, key string, port int, cipherList []string) (*ssh.Client, error) { + var ( + auth []ssh.AuthMethod + addr string + clientConfig *ssh.ClientConfig + client *ssh.Client + config ssh.Config + err error + ) + // get auth method + auth = make([]ssh.AuthMethod, 0) + if key == "" { + keyboardInteractiveChallenge := func( + user, + instruction string, + questions []string, + echos []bool, + ) (answers []string, err error) { + if len(questions) == 0 { + return []string{}, nil + } + return []string{password}, nil + } + auth = append(auth, ssh.Password(password)) + auth = append(auth, ssh.KeyboardInteractive(keyboardInteractiveChallenge)) + } 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"}, + } + } else { + config = ssh.Config{ + Ciphers: cipherList, + } + } + + clientConfig = &ssh.ClientConfig{ + User: user, + Auth: auth, + Timeout: 10 * 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 + } + + return client, nil +} + +func ScpTransfer(src, dst string, session *ssh.Session) error { + + go func() { + //Buf := make([]byte, 1024) + w, _ := session.StdinPipe() + defer w.Close() + File, err := os.Open(src) + if err != nil { + panic(err) + } + info, _ := File.Stat() + fmt.Fprintln(w, "C0777", info.Size(), info.Name()) + io.Copy(w, File) + fmt.Fprintln(w, "\x00") + }() + if err := session.Run("/usr/bin/scp -qrt " + dst); err != nil { + return err + } + return nil +} + +func CreateSftp(client *ssh.Client) (*sftp.Client, error) { + + sftpClient, err := sftp.NewClient(client) + return sftpClient, err +} + +func FtpTransfer(src, dst string, sftpClient *sftp.Client) error { + srcFile, err := sftpClient.Open(src) + if err != nil { + return err + } + defer srcFile.Close() + + var localFileName = path.Base(src) + dstFile, err := os.Create(path.Join(dst, localFileName)) + if err != nil { + return err + } + defer dstFile.Close() + + if _, err = srcFile.WriteTo(dstFile); err != nil { + return err + } + + return nil +} + +func Command(session *ssh.Session, cmdstr string) (string, error) { + var res bytes.Buffer + session.Stdout = &res + err := session.Run(cmdstr) + if err != nil { + return res.String(), err + } + return res.String(), nil +} + +func SSHPipeShell(session *ssh.Session, cmdstr string) (*sshd, error) { + var err error + lovessh := sshd{} + lovessh.SSHC = session + lovessh.infile, err = lovessh.SSHC.StdinPipe() + if err != nil { + return &lovessh, err + } + lovessh.outfile, err = lovessh.SSHC.StdoutPipe() + if err != nil { + return &lovessh, err + } + lovessh.errfile, err = lovessh.SSHC.StderrPipe() + if err != nil { + return &lovessh, err + } + if err := lovessh.SSHC.Start(cmdstr); err != nil { + return &lovessh, err + } + go func() { + lovessh.SSHC.Wait() + }() + ShellExit = false + lovessh.thread = false + return &lovessh, nil +} + +func SedColor(str string) string { + reg := regexp.MustCompile(`\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]`) + //fmt.Println("regexp:", reg.Match([]byte(str))) + return string(reg.ReplaceAll([]byte(str), []byte(""))) +} + +func (this sshd) GetResult(maxtime int) (string, string, bool) { + var stop bool + reader := bufio.NewReader(this.outfile) + erreader := bufio.NewReader(this.errfile) + if !this.thread { + this.thread = true + go func() { + var line2 string + var stack bool = false + stop = false + for { + if !stack { + go func() { + stack = true + if erreader.Size() > 0 { + line2, _ = erreader.ReadString('\n') + ShellErr += line2 + line2 = "" + } + stack = false + }() + } + line, err2 := reader.ReadString('\n') + if err2 != nil || io.EOF == err2 { + stop = true + break + } + this.counter++ + ShellRes += line + } + }() + } + waittm := 0 + for !stop { + time.Sleep(time.Millisecond * 250) + waittm += 1 + if maxtime >= 0 { + if waittm/4 > maxtime { + restr := SedColor(ShellRes) + ShellRes = "" + errstr := SedColor(ShellErr) + ShellErr = "" + return restr, errstr, false + } + } + } + ShellExit = true + this.thread = false + restr := SedColor(ShellRes) + ShellRes = "" + errstr := SedColor(ShellErr) + ShellErr = "" + return restr, errstr, true +} + +func (this sshd) Exec(cmdstr string, maxtime int) (string, string, bool) { + this.infile.Write([]byte(cmdstr + "\n")) + return this.GetResult(maxtime) +} + +func (this sshd) WriteCmd(cmdstr string) { + this.infile.Write([]byte(cmdstr + "\n")) + return +} + +func (this sshd) IsExit() bool { + return ShellExit +}