Skip to content

Instantly share code, notes, and snippets.

@CypherpunkSamurai
Forked from atotto/ssh.go
Created July 22, 2025 12:06
Show Gist options
  • Save CypherpunkSamurai/4ec4c8fc6ed0e58658ed91a0915c0488 to your computer and use it in GitHub Desktop.
Save CypherpunkSamurai/4ec4c8fc6ed0e58658ed91a0915c0488 to your computer and use it in GitHub Desktop.
golang ssh terminal client
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
)
var (
user = flag.String("l", "", "login_name")
password = flag.String("pass", "", "password")
port = flag.Int("p", 22, "port")
)
func main() {
flag.Parse()
if flag.NArg() == 0 {
flag.Usage()
os.Exit(2)
}
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
ctx, cancel := context.WithCancel(context.Background())
go func() {
if err := run(ctx); err != nil {
log.Print(err)
}
cancel()
}()
select {
case <-sig:
cancel()
case <-ctx.Done():
}
}
func run(ctx context.Context) error {
config := &ssh.ClientConfig{
User: *user,
Auth: []ssh.AuthMethod{
ssh.Password(*password),
},
Timeout: 5 * time.Second,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
hostport := fmt.Sprintf("%s:%d", flag.Arg(0), *port)
conn, err := ssh.Dial("tcp", hostport, config)
if err != nil {
return fmt.Errorf("cannot connect %v: %v", hostport, err)
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
return fmt.Errorf("cannot open new session: %v", err)
}
defer session.Close()
go func() {
<-ctx.Done()
conn.Close()
}()
fd := int(os.Stdin.Fd())
state, err := terminal.MakeRaw(fd)
if err != nil {
return fmt.Errorf("terminal make raw: %s", err)
}
defer terminal.Restore(fd, state)
w, h, err := terminal.GetSize(fd)
if err != nil {
return fmt.Errorf("terminal get size: %s", err)
}
modes := ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
term := os.Getenv("TERM")
if term == "" {
term = "xterm-256color"
}
if err := session.RequestPty(term, h, w, modes); err != nil {
return fmt.Errorf("session xterm: %s", err)
}
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
if err := session.Shell(); err != nil {
return fmt.Errorf("session shell: %s", err)
}
if err := session.Wait(); err != nil {
if e, ok := err.(*ssh.ExitError); ok {
switch e.ExitStatus() {
case 130:
return nil
}
}
return fmt.Errorf("ssh: %s", err)
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment