Skip to content

Instantly share code, notes, and snippets.

@iamralch
Last active April 16, 2023 03:09
Show Gist options
  • Star 78 You must be signed in to star a gist
  • Fork 32 You must be signed in to fork a gist
  • Save iamralch/b7f56afc966a6b6ac2fc to your computer and use it in GitHub Desktop.
Save iamralch/b7f56afc966a6b6ac2fc to your computer and use it in GitHub Desktop.
SSH client in GO
package main
import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"strings"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
type SSHCommand struct {
Path string
Env []string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
}
type SSHClient struct {
Config *ssh.ClientConfig
Host string
Port int
}
func (client *SSHClient) RunCommand(cmd *SSHCommand) error {
var (
session *ssh.Session
err error
)
if session, err = client.newSession(); err != nil {
return err
}
defer session.Close()
if err = client.prepareCommand(session, cmd); err != nil {
return err
}
err = session.Run(cmd.Path)
return err
}
func (client *SSHClient) prepareCommand(session *ssh.Session, cmd *SSHCommand) error {
for _, env := range cmd.Env {
variable := strings.Split(env, "=")
if len(variable) != 2 {
continue
}
if err := session.Setenv(variable[0], variable[1]); err != nil {
return err
}
}
if cmd.Stdin != nil {
stdin, err := session.StdinPipe()
if err != nil {
return fmt.Errorf("Unable to setup stdin for session: %v", err)
}
go io.Copy(stdin, cmd.Stdin)
}
if cmd.Stdout != nil {
stdout, err := session.StdoutPipe()
if err != nil {
return fmt.Errorf("Unable to setup stdout for session: %v", err)
}
go io.Copy(cmd.Stdout, stdout)
}
if cmd.Stderr != nil {
stderr, err := session.StderrPipe()
if err != nil {
return fmt.Errorf("Unable to setup stderr for session: %v", err)
}
go io.Copy(cmd.Stderr, stderr)
}
return nil
}
func (client *SSHClient) newSession() (*ssh.Session, error) {
connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Host, client.Port), client.Config)
if err != nil {
return nil, fmt.Errorf("Failed to dial: %s", err)
}
session, err := connection.NewSession()
if err != nil {
return nil, fmt.Errorf("Failed to create session: %s", 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 {
session.Close()
return nil, fmt.Errorf("request for pseudo terminal failed: %s", err)
}
return session, nil
}
func PublicKeyFile(file string) ssh.AuthMethod {
buffer, err := ioutil.ReadFile(file)
if err != nil {
return nil
}
key, err := ssh.ParsePrivateKey(buffer)
if err != nil {
return nil
}
return ssh.PublicKeys(key)
}
func SSHAgent() ssh.AuthMethod {
if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
}
return nil
}
func main() {
// ssh.Password("your_password")
sshConfig := &ssh.ClientConfig{
User: "jsmith",
Auth: []ssh.AuthMethod{
SSHAgent(),
},
}
client := &SSHClient{
Config: sshConfig,
Host: "example.com",
Port: 22,
}
cmd := &SSHCommand{
Path: "ls -l $LC_DIR",
Env: []string{"LC_DIR=/"},
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
fmt.Printf("Running command: %s\n", cmd.Path)
if err := client.RunCommand(cmd); err != nil {
fmt.Fprintf(os.Stderr, "command run error: %s\n", err)
os.Exit(1)
}
}
@nullne
Copy link

nullne commented Sep 21, 2015

hi why i get this error message :
set command run error: ssh: setenv failed

@DeadNumbers
Copy link

Any socks proxy connect to remote ssh server example? Thanks.

@ymgyt
Copy link

ymgyt commented Oct 12, 2017

if you got set command run error: ssh: setenv failed
check remote server /etc/ssh/sshd_config
AcceptEnv line

@mylesw42
Copy link

You'll need to set, at a minimum: HostKeyCallback: ssh.InsecureIgnoreHostKey() in the ssh.ClientConfig{} struct now, or you'll get this error message: ssh: must specify HostKeyCallback

golang/go#19767

@shlao
Copy link

shlao commented Apr 29, 2019

@mylesw42 thanks

@melbahja
Copy link

I created a simple ssh client package you can check it here:
https://github.com/melbahja/goph

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment