Skip to content

Instantly share code, notes, and snippets.

@blacknon
Last active January 30, 2023 01:53
Show Gist options
  • Save blacknon/038541ca650eab28bd32e98592193bf0 to your computer and use it in GitHub Desktop.
Save blacknon/038541ca650eab28bd32e98592193bf0 to your computer and use it in GitHub Desktop.
goでsshでシェルに接続して、ターミナルログ(タイムスタンプ付き)も記録する検証・サンプルコード
package main
import (
"bytes"
"fmt"
"io"
"os"
"os/signal"
"syscall"
"time"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
)
func main() {
host := "target.host.local"
port := "22"
user := "user"
pass := "password"
// Create sshClientConfig
sshConfig := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.Password(pass),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
// SSH connect.
client, err := ssh.Dial("tcp", host+":"+port, sshConfig)
// Create Session
session, err := client.NewSession()
defer session.Close()
// キー入力を接続先が認識できる形式に変換する(ここがキモ)
fd := int(os.Stdin.Fd())
state, err := terminal.MakeRaw(fd)
if err != nil {
fmt.Println(err)
}
defer terminal.Restore(fd, state)
// ターミナルサイズの取得
w, h, err := terminal.GetSize(fd)
if err != nil {
fmt.Println(err)
}
modes := ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
err = session.RequestPty("xterm", h, w, modes)
if err != nil {
fmt.Println(err)
}
log := new(bytes.Buffer)
session.Stdout = io.MultiWriter(os.Stdout, log)
session.Stderr = io.MultiWriter(os.Stderr, log)
session.Stdin = os.Stdin
err = session.Shell()
if err != nil {
fmt.Println(err)
}
// log write(with timestamp)
go func() {
file, _ := os.OpenFile("./ssh_term_with_log.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
preLine := []byte{}
for {
if log.Len() > 0 {
line, err := log.ReadBytes('\n')
if err == io.EOF {
preLine = append(preLine, line...)
continue
} else if err != nil {
fmt.Println(err)
} else {
timestamp := time.Now().Format("2006/01/02 15:04:05 ")
fmt.Fprintf(file, timestamp+string(preLine)+string(line))
preLine = []byte{}
}
}
}
file.Close()
}()
// ターミナルサイズの変更検知・処理
signal_chan := make(chan os.Signal, 1)
signal.Notify(signal_chan, syscall.SIGWINCH)
go func() {
for {
s := <-signal_chan
switch s {
case syscall.SIGWINCH:
fd := int(os.Stdout.Fd())
w, h, _ = terminal.GetSize(fd)
session.WindowChange(h, w)
}
}
}()
err = session.Wait()
if err != nil {
fmt.Println(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment