Go实现ssh执行远端命令及远程终端

什么是ssh?

SSH是一种网络协议,用于计算机之间的加密登录.

如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露.

互联网通信早期都是明文通信,一旦被截获,内容就暴露无疑. 1995年,芬兰学者Tatu Ylonen设计了SSH协议,将登录信息全部加密,成为互联网安全的一个基本解决方案,迅速在全世界获得推广, 目前已经成为Linux系统的标准配置.

Go实现ssh执行远端命令

package main

import (
	"fmt"
	"golang.org/x/crypto/ssh"
	"log"
	"time"
)

func main(){
	sshHost := ""
	sshUser := "root"
	sshPassword := ""
	sshType := "password"
	sshPort := 22


	//创建sshp登陆配置
	config := &ssh.ClientConfig{
		Timeout:         time.Second,//ssh 连接time out 时间一秒钟, 如果ssh验证错误 会在一秒内返回
		User:            sshUser,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(), //这个可以, 但是不够安全
		//HostKeyCallback: hostKeyCallBackFunc(h.Host),
	}
	if sshType == "password" {
		config.Auth = []ssh.AuthMethod{ssh.Password(sshPassword)}
	}



	//dial 获取ssh client
	addr := fmt.Sprintf("%s:%d", sshHost, sshPort)
	sshClient, err := ssh.Dial("tcp", addr, config)
	if err != nil {
		log.Fatal("创建ssh client 失败",err)
	}
	defer sshClient.Close()


	//创建ssh-session
	session, err := sshClient.NewSession()
	if err != nil {
		log.Fatal("创建ssh session 失败",err)
	}
	defer session.Close()
	//执行远程命令
	combo,err := session.CombinedOutput("whoami; cd /; ls -al;echo https://github.com/libragen/felix")
	if err != nil {
		log.Fatal("远程执行cmd 失败",err)
	}
	log.Println("命令输出:",string(combo))

}

Go实现一个远程终端

package main

import (
	"fmt"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
	"io"
	"log"
	"net"
	"os"
	"time"
)

type Cli struct {
	IP string
	Username string
	Password string
	Port int
	client *ssh.Client
	LastResult string
}

func New(ip string, username string, password string, port ...int) *Cli  {
	cli := new(Cli)
	cli.IP = ip
	cli.Username = username
	cli.Password = password
	switch  {
	case len(port) <= 0:
		cli.Port = 22
	case len(port) > 0:
		cli.Port = port[0]
	}
	return cli
}

func (c *Cli) connect() error  {
	config := ssh.ClientConfig{
		User: c.Username,
		Auth: []ssh.AuthMethod{ssh.Password(c.Password)},
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		},
		Timeout: 10 * time.Second,
	}
	addr := fmt.Sprintf("%s:%d", c.IP,c.Port)
	sshClient, err := ssh.Dial("tcp",addr,&config)
	if err != nil {
		return err
	}
	c.client = sshClient
	return nil
}

func (c *Cli) RunTerminal(stdout, stderr io.Writer) error  {
	if c.client == nil {
		if err := c.connect(); err != nil {
			return err
		}
	}
	session, err := c.client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()

	fd := int(os.Stdin.Fd())
	oldState,err := terminal.MakeRaw(fd)
	if err != nil {
		panic(err)
	}
	defer terminal.Restore(fd,oldState)

	session.Stdout = stdout
	session.Stderr = stderr
	session.Stdin = os.Stdin

	termWidth, termHeight, err := terminal.GetSize(fd)
	if err != nil {
		panic(err)
	}

	modes := ssh.TerminalModes{
		ssh.ECHO: 1,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}
	if err := session.RequestPty("xterm-256color", termHeight,termWidth,modes); err != nil {
		return err
	}
	session.Shell()
	session.Wait()
	return nil
}

func main()  {
	cli := New("IP","用户名","密码",22)
	err := cli.RunTerminal( os.Stdout, os.Stdin)
	if err != nil {
		log.Fatal(err)
	}
}

1

posted @ 2020-12-20 13:54  常见-youmen  阅读(6315)  评论(1编辑  收藏  举报