Last active
January 30, 2023 01:56
-
-
Save blacknon/a90b01dee1e86f430a8f979c9b6022ec to your computer and use it in GitHub Desktop.
goで多段proxy経由でsshでシェルに接続する検証・サンプルコード
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"net" | |
"os" | |
"os/signal" | |
"syscall" | |
"golang.org/x/crypto/ssh" | |
"golang.org/x/crypto/ssh/terminal" | |
) | |
// @note: | |
// proxy1 ... プロキシサーバ(1個目) | |
// proxy2 ... プロキシサーバ(2個目) | |
// target ... プロキシサーバ経由でログインするサーバ | |
func main() { | |
// proxy1の情報 | |
proxy1Host := "proxy1.host.local" | |
proxy1Port := "22" | |
proxy1User := "user" | |
proxy1Pass := "password" | |
// proxy2の情報 | |
proxy2Host := "proxy2.host.local" | |
proxy2Port := "22" | |
proxy2User := "user" | |
proxy2Pass := "password" | |
// targetの情報 | |
targetHost := "target.host.local" | |
targetPort := "22" | |
targetUser := "user" | |
targetPass := "password" | |
// sshClientConfigの作成(proxy1) | |
proxy1SshConfig := &ssh.ClientConfig{ | |
User: proxy1User, | |
Auth: []ssh.AuthMethod{ssh.Password(proxy1Pass)}, | |
HostKeyCallback: ssh.InsecureIgnoreHostKey(), | |
} | |
// sshClientConfigの作成(proxy2) | |
proxy2SshConfig := &ssh.ClientConfig{ | |
User: proxy2User, | |
Auth: []ssh.AuthMethod{ssh.Password(proxy2Pass)}, | |
HostKeyCallback: ssh.InsecureIgnoreHostKey(), | |
} | |
// sshClientConfigの作成(target) | |
targetSshConfig := &ssh.ClientConfig{ | |
User: targetUser, | |
Auth: []ssh.AuthMethod{ssh.Password(targetPass)}, | |
HostKeyCallback: ssh.InsecureIgnoreHostKey(), | |
} | |
// Proxy1へのsshClientの作成 | |
proxy1Client, err := ssh.Dial("tcp", net.JoinHostPort(proxy1Host, proxy1Port), proxy1SshConfig) | |
if err != nil { | |
fmt.Println(err) | |
} | |
// Proxy1経由でのProxy2への接続を実施 | |
proxy1Conn, err := proxy1Client.Dial("tcp", net.JoinHostPort(proxy2Host, proxy2Port)) | |
if err != nil { | |
fmt.Println(err) | |
} | |
// Proxy2へのsshClientを作成 | |
pConnect, pChans, pReqs, err := ssh.NewClientConn(proxy1Conn, net.JoinHostPort(proxy2Host, proxy2Port), proxy2SshConfig) | |
if err != nil { | |
fmt.Println(err) | |
} | |
proxy2Client := ssh.NewClient(pConnect, pChans, pReqs) | |
// Proxy2経由でのtargetへの接続を実施 | |
proxy2Conn, err := proxy2Client.Dial("tcp", net.JoinHostPort(targetHost, targetPort)) | |
if err != nil { | |
fmt.Println(err) | |
} | |
// TargetへのsshClientを作成 | |
p2Connect, p2Chans, p2Reqs, err := ssh.NewClientConn(proxy2Conn, net.JoinHostPort(targetHost, targetPort), targetSshConfig) | |
if err != nil { | |
fmt.Println(err) | |
} | |
client := ssh.NewClient(p2Connect, p2Chans, p2Reqs) | |
// ----------------------------------- | |
// ↓以降はプロキシの処理とは無関係なコード | |
// ----------------------------------- | |
// 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) | |
} | |
// sessionの標準入出力の処理 | |
session.Stdout = os.Stdout | |
session.Stderr = os.Stderr | |
session.Stdin = os.Stdin | |
// ssh接続先でShellの起動 | |
err = session.Shell() | |
if err != nil { | |
fmt.Println(err) | |
} | |
// ターミナルサイズの変更検知・処理 | |
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