Hatena::Grouprubyist

Going My Ruby Way このページをアンテナに追加 RSSフィード

Ruby ロゴ (C) Ruby Association LLC

2011年09月17日(土)

SSHサーバを作る(その23) コネクションプロトコル(2)

| 21:44 | SSHサーバを作る(その23) コネクションプロトコル(2) - Going My Ruby Way を含むブックマーク はてなブックマーク - SSHサーバを作る(その23) コネクションプロトコル(2) - Going My Ruby Way SSHサーバを作る(その23) コネクションプロトコル(2) - Going My Ruby Way のブックマークコメント

チャネルリクエストのプロトコル

チャネルリクエストのプロトコルで使用されるメッセージです。

メッセージ番号通常の方向説明
SSH_MSG_CHANNEL_OPEN90C->Sチャネルオープンの要求
SSH_MSG_CHANNEL_OPEN_CONFIRMATION91S->Cチャネルオープンの要求への応答(成功の場合)
SSH_MSG_CHANNEL_OPEN_FAILURE92S->Cチャネルオープンの要求への応答(失敗の場合)
SSH_MSG_CHANNEL_WINDOW_ADJUST93C->S,S->Cウィンドウサイズ調整の通知
SSH_MSG_CHANNEL_DATA94C->S,S->Cデータ転送
SSH_MSG_CHANNEL_EXTENDED_DATA95C->S,S->C拡張データ転送
SSH_MSG_CHANNEL_EOF96C->S,S->CEOFの通知
SSH_MSG_CHANNEL_CLOSE97C->S,S->Cチャネルクローズの通知
SSH_MSG_CHANNEL_REQUEST98C->S,S->Cチャネルリクエスト
SSH_MSG_CHANNEL_SUCCESS99C->S,S->Cチャネルリクエストへの応答(成功の場合)
SSH_MSG_CHANNEL_FAILURE100C->S,S->Cチャネルリクエストへの応答(失敗の場合)

メッセージの方向を記しましたが、これは通常使用される方向です。プロトコル上はチャネルはどちらの方向への要求できます。

メッセージは以下に大別できます。

  • チャネルのオープンとクローズに関するもの
    • CHANNEL_OPEN(90)
    • CHANNEL_OPEN_CONFIRMATION(91)
    • CHANNEL_OPEN_FAILURE(92)
    • CHANNEL_CLOSE(97)
  • チャネルリクエストに関するもの
    • CHANNEL_REQUEST(98)
    • CHANNEL_SUCCESS(99)
    • CHANNEL_FAILURE(100)
  • データ転送に関するもの
    • CHANNEL_WINDOW_ADJUST(93)
    • CHANNEL_DATA(94)
    • CHANNEL_EXTENDED_DATA(95)
    • CHANNEL_EOF(96)

チャネルのオープンとクローズ

  <client>                         <server>
    |  <CHANNEL_OPEN(90)>            |
    |------------------------------->|オープン要求
    |                                |
    | <CHANNEL_OPEN_CONFIRMATION(91)>|
    |<-------------------------------| (※成功の場合)
    |                                |
    |      <CHANNEL_OPEN_FAILURE(92)>|
    |<-------------------------------| (※失敗の場合)
    |                                |
    |................................|
    |                                |
    |  (チャネル間のやりとり...)     |
    |                                |
    |................................|
    |                                |
    |      <CHANNEL_CLOSE(97)>       |クローズ
    |<==============================>|(※送信順不定)

CHANNEL_OPEN のパラメータです。

channel type
チャネルタイプ。"session" など。
sender channel
送信側チャネル番号。(通常はクライアント側の番号)
initial window size
送信側初期ウィンドウサイズ(後述)
maximum packet size
送信側最大パケットサイズ(後述)
以降のパラメータ
チャネルタイプごとに特有。チャネルタイプ "session" の場合はなし。

チャネルをオープンした場合、CHANNEL_OPEN_CONFIRMATION を返信します。

CHANNEL_OPEN_CONFIRMATION のパラメータです。

recipient channel
受信側チャネル番号。(通常はクライアント側の番号)
sender channel
送信側チャネル番号。(通常はサーバ側の番号)
initial window size
送信側初期ウィンドウサイズ(後述)
maximum packet size
送信側最大パケットサイズ(後述)
以降のパラメータ
チャネルタイプごとに特有。チャネルタイプ "session" の場合はなし。

チャネルをオープンしない場合、CHANNEL_OPEN_FAILURE を返信します。

CHANNEL_OPEN_FAILURE のパラメータです。

recipient channel
受信側チャネル番号。(通常はクライアント側の番号)
reason code
理由コード(下記)
description
説明メッセージ
language tag
description の言語タグ(RFC3066参照)

理由コードは以下が RFC 4254 に定義されています。

             Symbolic name                           reason code
             -------------                           -----------
            SSH_OPEN_ADMINISTRATIVELY_PROHIBITED          1
            SSH_OPEN_CONNECT_FAILED                       2
            SSH_OPEN_UNKNOWN_CHANNEL_TYPE                 3
            SSH_OPEN_RESOURCE_SHORTAGE                    4

gmrw-ssh2-server ではチャネルタイプ "session" のみサポートしています。

以後も説明もチャネルタイプ "session" を前提とします。

チャネルリクエスト

オープンされたチャネルに対してチャネルリクエストを送ることができます。

  <client>                         <server>
    |  <CHANNEL_REQUEST(98)>         |
    |------------------------------->|リクエスト
    |................................|............................           
    |                                |※REQUEST の want_reply が true の場合
    |                                |
    |          <CHANNEL_SUCCESS(99)> |
    |<-------------------------------| (※成功の場合)
    |                                |
    |         <CHANNEL_FAILURE(100)> |
    |<-------------------------------| (※失敗の場合)
    |                                |

CHANNEL_REQUEST のパラメータです。

recipient channel
受信側チャネル番号(通常、サーバ側チャネル番号)
request type
リクエストタイプ(次回以降説明)
want_reply
応答の要/不要フラグ
以降のパラメータ
request type ごとに特有(次回以降説明)

CHANNEL_REQUEST の want_reply が true の場合、サーバは応答を返信します。

  • 要求が成功の場合は CHANNEL_SUCCESS を応答
  • 要求が失敗の場合は CHANNEL_FAILURE を応答

CHANNEL_SUCCESS、および CHANNEL_FAILURE のパラメータは以下です。

recipient channel
受信側チャネル番号(通常、クライアント側チャネル番号)

データ転送

チャネルのデータ転送ではウィンドウ制御(バイト単位)が行なわれます。

ウィンドウスペースは送信方向毎に以下のように制御されます。

  • 初期値は initial_window_size (CHANNEL_OPEN または CHANNEL_OPEN_CONFIRMATION のもの)です
  • データ転送(CHANNEL_DATA または CHANNEL_EXTENDED_DATA)で消費されます
  • CHANNEL_WINDOW_ADJUST の受信で増加します。

一度に送信できるデータサイズは、

  • ウィンドウサイズ
  • maximum_packet_size (CHANNEL_OPEN または CHANNEL_OPEN_CONFIRMATION)

のいずれか小さい方です。

ウィンドウスペースが残っていない場合は送信できません。

CHANNEL_DATA
<clientまたはserver>             <相手側>
    |  <CHANNEL_DATA(94)>            |
    |------------------------------->|
    |                                |

相手側へデータを転送します。CHANNEL_DATA のパラメータは以下です。

recipient channel
受信側チャネル番号
data
データ
CHANNEL_EXTENDED_DATA
<clientまたはserver>             <相手側>
    |  <CHANNEL_EXTENDED_DATA(95)>   |
    |------------------------------->|
    |                                |

相手側へ拡張データタイプを使ってデータを転送します。CHANNEL_EXTENDED_DATA のパラメータは以下です。

recipient channel
受信側チャネル番号
data type
拡張データタイプ
data
データ

拡張データタイプは以下の 1種類が RFC 4254 で定義されています。

               Symbolic name                  data_type_code
               -------------                  --------------
             SSH_EXTENDED_DATA_STDERR               1
CHANNEL_WINDOW_ADJUST
<clientまたはserver>             <相手側>
    |  <CHANNEL_WINDOW_ADJUST(93)>   |
    |------------------------------->|
    |                                |

相手から自分側へのウィンドウスペースを増加させます。CHANNEL_WINDOW_ADJUST のパラメタは以下です。

recipient channel
受信側チャネル番号
bytes_to_add
増加するウィンドウサイズ(バイト単位)
CHANNEL_EOF
<clientまたはserver>             <相手側>
    |  <CHANNEL_EOF(96)>             |
    |------------------------------->|
    |                                |

EOF(送信の終了)を通知します。CHANNEL_EOF のパラメタは以下です。

recipient channel
受信側チャネル番号

------

参考。gmrw-ssh2-server でのチャネル関係メッセージの定義です。

module GMRW::SSH2::Message
  def_message :channel_open, [
    [ :byte,    :type             ,90 ],
    [ :string,  :channel_type         ],  # session | x11 | forwarded-tcpip | direct-tcpip
    [ :uint32,  :sender_channel       ],
    [ :uint32,  :initial_window_size  ],
    [ :uint32,  :maximum_packet_size  ],

    [ :string,  :x11_originator_address,      nil, nil, {:channel_type => 'x11'}],
    [ :uint32,  :x11_originator_port,         nil, nil, {:channel_type => 'x11'}],

    [ :string,  :address_that_was_connected,  nil, nil, {:channel_type => 'forwarded-tcpip'}],
    [ :uint32,  :port_that_was_connected,     nil, nil, {:channel_type => 'forwarded-tcpip'}],
    [ :string,  :forward_originator_address,  nil, nil, {:channel_type => 'forwarded-tcpip'}],
    [ :uint32,  :forward_originator_port,     nil, nil, {:channel_type => 'forwarded-tcpip'}],

    [ :string,  :host_to_connect,             nil, nil, {:channel_type => 'direct-tcpip'}],
    [ :uint32,  :port_to_connect,             nil, nil, {:channel_type => 'direct-tcpip'}],
    [ :string,  :direct_originator_address,   nil, nil, {:channel_type => 'direct-tcpip'}],
    [ :uint32,  :direct_originator_port,      nil, nil, {:channel_type => 'direct-tcpip'}],
  ]

  def_message :channel_open_confirmation, [
    [ :byte,    :type                ,91 ],
    [ :uint32,  :recipient_channel       ],
    [ :uint32,  :sender_channel          ],
    [ :uint32,  :initial_window_size     ],
    [ :uint32,  :maximum_packet_size     ],
#   [ :...., :method_specific_field      ],
  ]

  def_message :channel_open_failure, [
    [ :byte,    :type              ,92 ],
    [ :uint32,  :recipient_channel     ],
    [ :uint32,  :reason_code       ,nil, {
                  :ADMINISTRATIVELY_PROHIBITED  =>  1,
                  :CONNECT_FAILED               =>  2,
                  :UNKNOWN_CHANNEL_TYPE         =>  3,
                  :RESOURCE_SHORTAGE            =>  4 }],
    [ :string,  :description           ],
    [ :string,  :language_tag          ],
  ]

  def_message :channel_window_adjust, [
    [ :byte,    :type              ,93 ],
    [ :uint32,  :recipient_channel     ],
    [ :uint32,  :bytes_to_add          ],
  ]

 def_message :channel_data, [
    [ :byte,    :type              ,94 ],
    [ :uint32,  :recipient_channel     ],
    [ :string,  :data                  ],
  ]

  def_message :channel_extended_data, [
    [ :byte,    :type              ,95 ],
    [ :uint32,  :recipient_channel     ],
    [ :uint32,  :data_type             ],
    [ :string,  :data                  ],
  ]

  def_message :channel_eof, [
    [ :byte,    :type              ,96 ],
    [ :uint32,  :recipient_channel     ],
  ]

  def_message :channel_close, [
    [ :byte,    :type              ,97 ],
    [ :uint32,  :recipient_channel     ],
  ]

  def_message :channel_request, [
    [ :byte,    :type              ,98 ],
    [ :uint32,  :recipient_channel     ],
    [ :string,  :request_type          ],
    [ :boolean, :want_reply            ],

    [ :string,  :term_env_var,      nil, nil, {:request_type => 'pty-req'} ],
    [ :uint32,  :term_cols,         nil, nil, {:request_type => 'pty-req'} ],
    [ :uint32,  :term_rows,         nil, nil, {:request_type => 'pty-req'} ],
    [ :uint32,  :term_width,        nil, nil, {:request_type => 'pty-req'} ],
    [ :uint32,  :term_height,       nil, nil, {:request_type => 'pty-req'} ],
    [ :string,  :term_modes,        nil, nil, {:request_type => 'pty-req'} ],

    [ :boolean, :single_connection, nil, nil, {:request_type => 'x11-req'} ],
    [ :string,  :x11_auth_protocol, nil, nil, {:request_type => 'x11-req'} ],
    [ :string,  :x11_auth_cookie,   nil, nil, {:request_type => 'x11-req'} ],
    [ :uint32,  :x11_screen_number, nil, nil, {:request_type => 'x11-req'} ],

    [ :string,  :env_var_name,      nil, nil, {:request_type => 'env'} ],
    [ :string,  :env_var_value,     nil, nil, {:request_type => 'env'} ],

    [ :string,  :command,           nil, nil, {:request_type => 'exec'} ],

    [ :string,  :subsystem,         nil, nil, {:request_type => 'subsystem'} ],

    [ :uint32,  :win_cols,          nil, nil, {:request_type => 'window-change'} ],
    [ :uint32,  :win_rows,          nil, nil, {:request_type => 'window-change'} ],
    [ :uint32,  :win_width,         nil, nil, {:request_type => 'window-change'} ],
    [ :uint32,  :win_height,        nil, nil, {:request_type => 'window-change'} ],

    [ :boolean, :client_can_do,     nil, nil, {:request_type => 'xon-xoff'} ],

    [ :string,  :signal_name,       nil, nil, {:request_type => 'signal'} ],

    [ :uint32,  :exit_status,       nil, nil, {:request_type => 'exit-status'} ],

    [ :string,  :exit_signal,       nil, nil, {:request_type => 'exit-signal'} ],
    [ :boolean, :core_dumped,       nil, nil, {:request_type => 'exit-signal'} ],
    [ :string,  :error_message,     nil, nil, {:request_type => 'exit-signal'} ],
    [ :string,  :language_tag,      nil, nil, {:request_type => 'exit-signal'} ],
  ]

  def_message :channel_success, [
    [ :byte,    :type              ,99 ],
    [ :uint32,  :recipient_channel     ],
  ]

  def_message :channel_failure, [
    [ :byte,    :type              ,100 ],
    [ :uint32,  :recipient_channel      ],
  ]
end