You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
6.3 KiB
Go
287 lines
6.3 KiB
Go
6 years ago
|
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
|
||
|
}
|