master
root 5 years ago
commit 54cdb80ef7

286
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
}
Loading…
Cancel
Save