ssh login

とある行列で隣に来たおじいさんが、不思議な帽子を被っていたので、何処に売ってましたって聞いてみたよ。ユニクロにも、しまむらにも無いようなやつだったからね。

おじいさんの答えが、思いがけない事だったのでびっくり。西アフリカに旅行に行った時、面白いやつがあったんで、10帽まとめて土産にしたとか。5000円とか言ってた。高いんだか安いんだか?

原色に染めた毛を複数組み合わせた、頭にちょこっと載せるやつ。これから寒くなるので、毛が寂しい人にはうってつけかも。

なんでもそのおじいさんは、世界各国70ケ国ぐらいに行ったとか。どこが一番良かったですって聞いたら、イグアスの滝って即答された。

南米?北米?そのあたりだよね。いってQでよく出てきてたな。現地で滝が見える所まで行くのが大変だったとか。崖っぷちの細い道をひやひやしながら行くとの事。そうなのか、絶景にたどり着くには、多大な努力が必要になるんだな。

他の国はどうって聞いたら、ヨーロッパなんてつなんない。何処へ行ってもキリスト教の寺院しかないからね。同感します。最初は、もの珍しさも手伝って感激するけど、そのうちに飽きてしまって、何処へ行っても一緒ってなっちゃう。

ヨーロッパで良かったのは、ミュンヘンのビール祭り(オクトバー・フェスト)ぐらいかな。ああ、今年はもう終わって しまったか。日比谷あたりで、遅れてやらないかね。

そんな折、『バックパッカーズ読本』なんていう、楽しい本をみて、心だけでも若くなっている。そのうちに、うずうずし始めて、海外へ飛び出して行ったりして。T/Cが日本ではすでに買えないなんて知らなかった。現地通貨の入手は、国際キャッシュカードを使って、ATMから引き出すのが一般的とか。要替わりしたものだ。

ssh login

前回やってたloginの調査で、sshへ行きついた。それはいいんだけど、ソースを鑑賞するには、ちと荷が重い。もっと、すっきりさっぱりなものが無いかと探してみた。そして、放浪の末に見つけたのが下記。

Golangでターミナル接続できるsshクライアントコマンドを作成する(制御キー対応)

上手い具合に、手ごろなサイズの実例だ。ここで使われているpkgの解説は、下記にあった。

golang.org/x/crypto/ssh

golang.org/x/crypto/ssh/terminal

どうも、golangの正式リリースに入れるにはユーザー数が少なくて躊躇しそうだけど、有れば 泣いて喜ぶ人が居るでしょうってものを集積してるみたい。

githubは、個人任せで、ちょいと信用ならんって趣か。golangは、pkgをgitなりで取ってくるって現代風な作りになってるけど、オイラー好きなのは、tar玉でのリリース。これが一番無難だと思ってる。

だって、昔PHPだかで事件が有ったよね。個人がアップしてるあるパーツを取り下げた。それに依存してるモジュールが軒並み動かなくなった。提供場所はgithubのみ。他でバックアップしてる所は無かった。便利さに隠れた罠ですな。

FreeBSDのportsは、tar玉を勿論正式な公開場所から落として来るのだけど、そこがアクセス出来なくなっていても、バックアップサイトを渡り歩いて、なんとかダウンロードしてくれる。これもそれも、取り回しが楽な、tar玉だからこそ出来る芸当。

んでもって、ウブで試してみた。無事にパッケージが出来たよ。

sakae@usvr:~$ tree go/pkg/
go/pkg/
└── linux_amd64
    └── golang.org
        └── x
            └── crypto
                ├── ssh
                │   └── terminal.a
                └── ssh.a

そして、サンプルスクリプトに、ちょいと追加。

    // ターミナルサイズの取得
    w, h, err := terminal.GetSize(fd)
    if err != nil {
        fmt.Println(err)
    }
fmt.Printf("%d   %d\n", w, h)

そして、OpenBSDに乗り入れてみた。

sakae@usvr:~/go/src/sterm$ go run sterm.go
80   37
       Last login: Sat Sep 29 14:02:52 2018 from xxx.xxx.xxx.xxx
OpenBSD 6.3 (GENERIC.MP) #11: Thu Sep 20 16:05:37 CEST 2018

Welcome to OpenBSD: The proactively secure Unix-like operating system.
ob6$ stty -a
speed 14400 baud; 37 rows; 80 columns;
  :

端末サイズは、接続前とOpenBSDのそれと同一になってるけど、これは接続時に貰ったものではない。OpenBSD側でlogin時に設定したもの。ターミナルのスピードだけは、継承されてた。

気を良くしたオイラーは、Windows側のgolangでバイナリーを作ってみようとした。 Windowsでgitですか。以前やった事があるけど、gitのために色々な付属品が付いてきて気持ち悪い。どうせなら、WSL側にgitを入れて、wsl git と言うラッパーを書けばいいじゃん。

この方法は失敗に終わった。go get した時、gitHubからエラーが返ってきちゃうんだ。ちゃんとOSを確認して、それ様にフォーマットを整えているんですかね。cloneした時のPATHがWindows式だった。それに対して、unix用が動いているんで、フォーマットが違うって文句垂れたんでしょうね。

諦めて、うぶ側のものを、そっくりそのまま持って行ったら、pkgはlinux_amd64式なのに、普通に動いちゃったぞ。こんな事ってあるんだなあ。OSを越えて動いてる。

ちゃんとOpenBSDにもlogin出来た。但し、Windows側で検出した画面サイズが、w,h共に0だった。これって、Windowsの馬鹿窓では、サイズ情報が提供されていないって事かな?

それから、エスケープシーケンスが理解出来ないようで、emacsとかを使うと、化け文字(正確には、エスケープ制御文字列)の嵐になったぞ。土台のWindows窓では、せいぜい色を付ける ぐらいなんですかね。

Windows 10のbashを試す! (2/2)に、画面の色付けの事が解説されてたけど、これってxtermと共通なのかな?Windowsの事だから、変な独自色を出してたりしてね。秋の大改造で変わったりして。

go/src/golang.org/x/crypto/ssh/terminal$ emacs terminal.go

var vt100EscapeCodes = EscapeCodes{
        Black:   []byte{keyEscape, '[', '3', '0', 'm'},
        Red:     []byte{keyEscape, '[', '3', '1', 'm'},
        Green:   []byte{keyEscape, '[', '3', '2', 'm'},
        Yellow:  []byte{keyEscape, '[', '3', '3', 'm'},
        Blue:    []byte{keyEscape, '[', '3', '4', 'm'},
        Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
        Cyan:    []byte{keyEscape, '[', '3', '6', 'm'},
        White:   []byte{keyEscape, '[', '3', '7', 'm'},

        Reset: []byte{keyEscape, '[', '0', 'm'},
}

一番目立つ所に陳列されてた。他のやつは、関数の中に分散されてた。vt100とxtermはこのあたりに互換性が有るのだろうか? 余り深入りしてもしょうがない。

今日の所は、大筋が理解出来たので良しとしよう。

test

サンプルと言うかテスト版が用意されてた。

sakae@usvr:~/go/src/golang.org/x/crypto/ssh$ find . -name '*test*' | grep -v /test
./benchmark_test.go
./knownhosts/knownhosts_test.go
./cipher_test.go
./client_test.go
./certs_test.go
./session_test.go
./mempipe_test.go
./messages_test.go
./client_auth_test.go
./example_test.go
./mux_test.go
./transport_test.go
./keys_test.go
./agent/client_test.go
./agent/example_test.go
./agent/server_test.go
./agent/keyring_test.go
./kex_test.go
./buffer_test.go
./tcpip_test.go
./terminal/terminal_test.go
./handshake_test.go

色々な目的のテストが羅列されているけど、総合的に動きを見るなら、example_test.goの中を 漁るがよかろう。例えば、その中にあるExampleDial()ってやつ。 コメントがしっかり入っているのに、スニペットになる。

クライアントとして、ssh接続し、サーバー側でwhoamiってのを実行して、結果を持ち帰る例。 要約すると、

        client, err := ssh.Dial("tcp", "yourserver.com:22", config)
        session, err := client.NewSession()
	
        // Once a Session is created, you can execute a single command on
        // the remote side using the Run method.
        var b bytes.Buffer
        session.Stdout = &b
        session.Run("/usr/bin/whoami")
        fmt.Println(b.String())

ターミナルに特化したものだと、terminal_test.goが参考になるな。とか言いつつ、これらを 上手に組み合わせて、ちゃんと使えるものに仕立てた、方は凄いな。尊敬しますだ。

コネクションを張るメソッドがDialって名前、どこかでお目にかかったぞ。思い出すはplan9だ。goの主要設計者がplan9挙がりを思えば、当たり前の所業。

そして、cryptoと並置されて、sysが来てるんだけど、

sakae@usvr:~/go/src/golang.org/x$ tree sys -d
sys
├── cpu
├── plan9
├── unix
│   └── linux
└── windows
    ├── registry
    └── svc
        ├── debug
        ├── eventlog
        ├── example
        └── mgr

何故か、plan9なんてのも顔を出している。やっぱり故郷は忘れられないのかな。

参考に、session.goを見てたら

// POSIX signals as listed in RFC 4254 Section 6.10.
// POSIX terminal mode flags as listed in RFC 4254 Section 8.

RFC 4254のオンパレードでした。これに則っていれば、ちゃんと接続出来ますとな。今度、どんな事が書いてあるか、お取り寄せしてみるか。

golang with dlv

golangにもdebuggerが欲しい。以前やったな、進歩が無いなと思いながらも入れてしまった。

Golangのデバッガdelveの使い方

軽くリナで動く事を確認の後、gitが動かないWindowsに移植。てか、srcの下にあるgithub.com以下のものを一式、Windowsに持っていくだけ。持って行くに先立ち、配下にあるゴミが入っている、.git を消しておく。今回は、ゴミが20Mあった。それを除くソースが16M。ゴミは、過去に遡るとか、更新をする積りがなければ、本当に不要なゴミだ。リサイクルすら出来ない。 これだから、gitは嫌いさ。

sakae@usvr:~$ cd go/src/sterm/
sakae@usvr:~/go/src/sterm$ dlv debug
Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x5ca07b for main.main() ./sterm.go:11
(dlv) c
> main.main() ./sterm.go:11 (hits goroutine(1):1 total:1) (PC: 0x5ca07b)
     6:
     7:     "golang.org/x/crypto/ssh"
     8:     "golang.org/x/crypto/ssh/terminal"
     9: )
    10:
=>  11: func main() {

こんな具合に始めればよい。コマンド体系がgdbに似ているんだけど、微妙に違う所が有って、ちょいとむかつく。でも、Windows上でも動くから良しとするか。

でも、32Bitのマシンでは、サポートしていない。もう古い石は退役してくださいって言う、無言の圧力かな。時代の流れだわな。

RFC 4254

上で出て来た RFC 4254って何かと思って、資料を取り寄せてみた。

sakae@fb:/tmp % rfc -o 4254 >RFC4254
Abstract

   Secure Shell (SSH) is a protocol for secure remote login and other
   secure network services over an insecure network.

   This document describes the SSH Connection Protocol.  It provides
   interactive login sessions, remote execution of commands, forwarded
   TCP/IP connections, and forwarded X11 connections.  All of these
   channels are multiplexed into a single encrypted tunnel.

   The SSH Connection Protocol has been designed to run on top of the
   SSH transport layer and user authentication protocols.

普段お世話になるsshの接続規約か。login, remote exec, forwared TCP/IPって、これ無しでは、生きていけない程大事な規約だ。

ちゃんねるなんて概念があるんで、一度チャネルを確保しちゃえば、色々なセッションを同時に張れるって事か。

他に関連したRFCが無いか、rfcのindexを検索してみる。

sakae@fb:/tmp % rfc -k ssh
4250 The Secure Shell (SSH) Protocol Assigned Numbers. S. Lehtinen, C.
     Lonvick, Ed.. January 2006. (Format: TXT=44010 bytes) (Updated by
     RFC8268) (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC4250)
4251 The Secure Shell (SSH) Protocol Architecture. T. Ylonen, C. Lonvick,
     Ed.. January 2006. (Format: TXT=71750 bytes) (Updated by RFC8308)
     (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC4251)
4252 The Secure Shell (SSH) Authentication Protocol. T. Ylonen, C.
     Lonvick, Ed.. January 2006. (Format: TXT=34268 bytes) (Updated by
     RFC8308, RFC8332) (Status: PROPOSED STANDARD) (DOI:
     10.17487/RFC4252)
4253 The Secure Shell (SSH) Transport Layer Protocol. T. Ylonen, C.
     Lonvick, Ed.. January 2006. (Format: TXT=68263 bytes) (Updated by
     RFC6668, RFC8268, RFC8308, RFC8332) (Status: PROPOSED STANDARD)
     (DOI: 10.17487/RFC4253)
 :

一連のssh関係が2006年あたりに提案されたんだな。

セキュア シェル (SSH) 認証プロトコル(rfc4252)

セキュア シェル (SSH) トランスポート層プロトコル(rfc4253)

セキュアシェル(SSH)接続プロトコル(rfc4254)

ssh login log

折角なので、ssh loginした時のログを取ってみる。実行したのは、うぶなサーバー版

sakae@usvr:/tmp$ ssh -vv localhost
OpenSSH_7.6p1 Ubuntu-4, OpenSSL 1.0.2n  7 Dec 2017
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: resolving "localhost" port 22
debug2: ssh_connect_direct: needpriv 0
debug1: Connecting to localhost [::1] port 22.
debug1: Connection established.
debug1: key_load_public: No such file or directory
debug1: identity file /home/sakae/.ssh/id_rsa type -1
 :
debug1: Local version string SSH-2.0-OpenSSH_7.6p1 Ubuntu-4
debug1: Remote protocol version 2.0, remote software version OpenSSH_7.6p1 Ubuntu-4
debug1: match: OpenSSH_7.6p1 Ubuntu-4 pat OpenSSH* compat 0x04000000
debug2: fd 3 setting O_NONBLOCK
debug1: Authenticating to localhost:22 as 'sakae'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug2: local client KEXINIT proposal
 :
debug1: Next authentication method: password
sakae@localhost's password:
debug2: we sent a password packet, wait for reply
debug1: Authentication succeeded (password).
Authenticated to localhost ([::1]:22).
 :
debug1: channel 0: new [client-session]
debug2: channel 0: send open
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
 :
debug2: channel_input_status_confirm: type 99 id 0
debug2: shell request accepted on channel 0
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-34-generic x86_64)

 * Documentation:  https://help.ubuntu.com
   <LOGIN MESSAGES>
sakae@usvr:~$ exit
logout
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0
debug2: channel 0: rcvd eow
debug2: channel 0: close_read

実行時に -vを付けると、やり取りが出て来る。最初に身元を晒すやり取りが有るんだな。続いて認証関係、暗号関係。

パスワード関係の入力が終わってから、チャンネル番号0を使って、shellを起動。目出度くログイン環境って運びか。

裏で、色々やってる事が分かりましたよ。

SSHのプロトコルについてまとめてみた

sshd by golang

SSHサーバー(最低限の認証機能付き)をつくる

Golangで軽量なSSHサーバを実装する

Other ssh client

Windows からも ssh でリモートコマンド実行したい、それ golang で出来るよ