- PublicKey">type PublicKey
- AuthMethod">type AuthMethod
- ClientConfig">type ClientConfig
- Client">type Client
- Session">type Session
- Signal">type Signal
- 例子:
- 交互式执行
- 注意:
import “golang.org/x/crypto/ssh”
文档 https://godoc.org/golang.org/x/crypto/ssh
type PublicKey
type PublicKey interface {// Type returns the key's type, e.g. "ssh-rsa".Type() string// Marshal returns the serialized key data in SSH wire format,// with the name prefix. To unmarshal the returned data, use// the ParsePublicKey function.Marshal() []byte// Verify that sig is a signature on the given data using this// key. This function will hash the data appropriately first.Verify(data []byte, sig *Signature) error}
func NewPublicKey(key interface{}) (PublicKey, error)
type AuthMethod
func Password(secret string) AuthMethod 使用密码
func PublicKeys(signers …Signer) AuthMethod 使用密钥
var hostKey ssh.PublicKeykey, err := ioutil.ReadFile("/home/user/.ssh/id_rsa")if err != nil {log.Fatalf("unable to read private key: %v", err)}// Create the Signer for this private key.signer, err := ssh.ParsePrivateKey(key)if err != nil {log.Fatalf("unable to parse private key: %v", err)}config := &ssh.ClientConfig{User: "user",Auth: []ssh.AuthMethod{// Use the PublicKeys method for remote authentication.ssh.PublicKeys(signer),},HostKeyCallback: ssh.FixedHostKey(hostKey),}// Connect to the remote server and perform the SSH handshake.client, err := ssh.Dial("tcp", "host.com:22", config)if err != nil {log.Fatalf("unable to connect: %v", err)}defer client.Close()
type ClientConfig
type ClientConfig struct {ConfigUser stringAuth []AuthMethodHostKeyCallback HostKeyCallbackBannerCallback BannerCallbackClientVersion stringHostKeyAlgorithms []stringTimeout time.Duration}
type Client
func Dial(network, addr string, config ClientConfig) (Client, error)
func (c Client) NewSession() (Session, error)
type Session
一个会话只接受一个run、start或Shell调用。
type Session struct {Stdin io.ReaderStdout io.WriterStderr io.Writer// contains filtered or unexported fields}
func (s Session) Close() error
func (s Session) CombinedOutput(cmd string) ([]byte, error) 返回标准输出和标准错误,以0的状态退出错误为nil
本机命令错误才算错误,远程错误属于标准输出res:scp -p 22 root@1.1.1.1 cat11 /home/test.txt || 1.1.1.1机器上cat11不是一个命令,CombinedOutput认为他是标准输出res:scp11 -p 22 root@1.1.1.1 cat /home/test.txt || scp11 命令在本机不存在,这样才是标准错误
func (s Session) Output(cmd string) ([]byte, error) 返回标准输出,以0的状态退出,则返回的错误为nil
func (s Session) Run(cmd string) error
- 一个session应只能调用一次,stdin、stdout和stderr没有问题,且以0的状态退出,则返回的错误为nil
func (s Session) Setenv(name, value string) error 设置一个环境变量,该变量将用于Shell或Run执行的任何命令func (s Session) Signal(sig Signal) error 将给定的信号发送给远程进程
func (s Session) Start(cmd string) error 在远程主机上运行cmd
func (s Session) StderrPipe() (io.Reader, error) 错误信息,与标准输出信息一直
func (s Session) StdinPipe() (io.WriteCloser, error) 输入信息
func (s Session) StdoutPipe() (io.Reader, error) 输出信息,与标准错误信息一直
func (s *Session) Wait() error Start+Wait = run
type Signal
type Signal stringconst (SIGABRT Signal = "ABRT"SIGALRM Signal = "ALRM"SIGFPE Signal = "FPE"SIGHUP Signal = "HUP"SIGILL Signal = "ILL"SIGINT Signal = "INT"SIGKILL Signal = "KILL"SIGPIPE Signal = "PIPE"SIGQUIT Signal = "QUIT"SIGSEGV Signal = "SEGV"SIGTERM Signal = "TERM"SIGUSR1 Signal = "USR1"SIGUSR2 Signal = "USR2")
例子:
package mainimport ("fmt""golang.org/x/crypto/ssh""log""net""time")func connect(user, password, host string, port int) (*ssh.Session, error) {var (auth []ssh.AuthMethodaddr stringclientConfig *ssh.ClientConfigclient *ssh.Clientsession *ssh.Sessionerr error)// get auth methodauth = make([]ssh.AuthMethod, 0)auth = append(auth, ssh.Password(password))clientConfig = &ssh.ClientConfig{User: user,Auth: auth,Timeout: 30 * time.Second,HostKeyCallback:func(hostname string, remote net.Addr, key ssh.PublicKey) error {return nil},}// connet to sshaddr = fmt.Sprintf("%s:%d", host, port)if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {return nil, err}// create sessionif session, err = client.NewSession(); err != nil {return nil, err}return session, nil}func main() {session, err := connect("root", "*****", "*.*.*.*", 22)if err != nil {log.Fatal("error:",err)}defer session.Close()res,err := session.CombinedOutput("cd /home/jw && ./shell01.sh")if err != nil {log.Fatal("error:",err)}res_str := fmt.Sprintf("%s",res)fmt.Println(res_str)}
交互式执行
package mainimport ("bytes""fmt""golang.org/x/crypto/ssh""log""sync")type MyReader struct {channel chan string}func newReader() *MyReader {reader := new(MyReader)reader.channel = make(chan string)return reader}func (r *MyReader) Read(p []byte) (n int, err error) {var cmd stringcmd = <-r.channelcmdB := []byte(cmd + "\n")for i, v := range cmdB {p[i] = v}n = len(cmdB)return n, err}type MyWriter struct {channel chan string}func newWriter() *MyWriter {writer := new(MyWriter)writer.channel = make(chan string)return writer}func (w *MyWriter) Write(p []byte) (n int, err error) {res := string(p)//fmt.Println(res)w.channel <- resreturn len(p), err}func main() {// 建立SSH客户端连接client, err := ssh.Dial("tcp", "47.107.180.221:22", &ssh.ClientConfig{User: "public",Auth: []ssh.AuthMethod{ssh.Password("public")},HostKeyCallback: ssh.InsecureIgnoreHostKey(),})if err != nil {log.Fatalf("SSH dial error: %s", err.Error())}// 建立新会话session, err := client.NewSession()defer session.Close()if err != nil {log.Fatalf("new session error: %s", err.Error())}writer := newWriter()reader := newReader()session.Stdout = writer // 会话输出session.Stderr = writer // 会话错误session.Stdin = reader // 会话输入go func() {for {output, ok := <-writer.channelif !ok {break}if strings.Contains(output, "-bash:") {err = errors.New(output)}fmt.Println(output)}}()s := "cd /home;ll -a \n exit \n"go func() {//f := bufio.NewReader(os.Stdin) //读取输入的内容f := bytes.NewBufferString(s)for {input, err := f.ReadString('\n') //定义一行输入的内容分隔符。if err != nil {break}reader.channel <- input}}()ExecuteTerminal(session)}// 这里是一个阻塞会话,没遇到exit这里不会退出func ExecuteTerminal(session *ssh.Session) {var err errormodes := ssh.TerminalModes{ssh.ECHO: 0, // 禁用回显(0禁用,1启动)ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaudssh.TTY_OP_OSPEED: 14400, //output speed = 14.4kbaud}if err = session.RequestPty("linux", 32, 160, modes); err != nil {log.Fatalf("request pty error: %s", err.Error())}if err = session.Shell(); err != nil {log.Fatalf("start shell error: %s", err.Error())}if err = session.Wait(); err != nil {log.Fatalf("return error: %s", err.Error())}}
注意:
- cat 一个不存在的文件会报错
- ls -la 查看隐藏文件,不能用ll -a,会报错
- ls -l | grep -w xxx ,如果xxx不存在,会报错
不是所有的linux命令用ssh去执行与本机执行的结果是一样的
例如:
ssh远程执行

本机执行
