SSH 简介

https://godoc.org/golang.org/x/crypto/ssh

SSH 客户端

工作流程

  • Linux SSH Work Flow:

    • execute: ssh root@host:ip
    • input: pwd
    • hosted remote shell: execute command
  • 同理,通过 Golang 的 SSH 包提供的函数也要实现上述流程:

    • Input command by keyboard
    • Obtain user’s input from os.Stdin
    • Establish a ssh connect
    • Send data|cmd by ssh

获取标准输入

关键代码:os & bufio 包

1
2
reader := bufio.NewReader(os.Stdin)
str, _ := reader.ReadString("\n")

建立SSH连接

关键代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func (s *SSH) connect() (*ssh.Session, error) {
	var (
		auth         []ssh.AuthMethod
		addr         string
		clientConfig *ssh.ClientConfig
		client       *ssh.Client
		session      *ssh.Session
		err          error
	)

	// get auth method
	auth = make([]ssh.AuthMethod, 0)
	auth = append(auth, ssh.Password(s.Password))
	clientConfig = &ssh.ClientConfig{User: s.Username, Auth: auth, Timeout: 30 * time.Second}

	// connect to ssh
	addr = fmt.Sprintf("%s:%s", s.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
	}
	return session, nil
}

发送数据

有好几种方式可实现数据发送或命令执行

  • 调用Run()方法

    • session.Run(cmd)
  • Hosted Shell(托管远程Shell),关键代码:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    // execute command
    session.Stdout = os.Stdout
    session.Stderr = os.Stderr
    session.Stdin = os.Stdin
        
    // set up terminal modes
    modes := ssh.TerminalModels {
        ssh.ECHO: 0,            // enable echoing
        ssh.OP_ISPEED: 14400,   // input speed = 14.4kbaud
        ssh.OP_OSPEED: 14400,   // output speed = 14.4kbaud
    }
    
    // request pseudo terminal(伪终端)
    if err := session.RequestPty("xterm-256color", 25, 80, modes); err != nil {
        fmt.Println(err.Error())
        return
    }
    
    // hosted shell
    session.Shell()
    session.Wait()

    远程执行命令

    连接

    • 认证方式:

    • By Password: 提供Host, Username, Password

    • By sshkey:

    • 连接成功后会获取到该连接的 session

    • Session实现了如下常用方法

    • (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error

    • (s *Session) Start(cmd string) error

    • (s *Session) Run(cmd string) error

    • (s *Session) Shell() error

    • (s *Session) start() error

    • (s *Session) Wait() error

    执行

    • 连接成功后调用 session.Run() 即可在远程主机执行命令
    1
    
    session.Run("ls /; ls /home/")
    • 注:此时命令虽然正常执行了,但没有 正常|异常 结果输出,因为没有将session的 stdout, stderr 绑定到系统的 stdout, stderr上

获取结果

  • 执行如下代码即可获取输出信息

    1
    2
    
    session.Stdout = os.Stdout
    session.Stderr = os.Stder

    交互式命令

    上述方式虽然可以在远程主机执行命令,但无法完成交互式命令,比如执行top,vim等。 如果要支持交互式命令就要当前的terminal接管远程的PTY

    需要将最后的两行代码进行替换:

    old:

    1
    2
    3
    
    // hosted shell
    session.Shell()
    session.Wait()

new:

1
session.Run("vim /etc/mongod.conf")

Click here to check out the repo

See Also

Thanks to the authors 🙂