Ticket #41886

SSH2 ダイナミックポートフォワーディングを使うと落ちる

Eröffnet am: 2021-03-31 00:39 Letztes Update: 2022-12-22 00:55

Auswertung:
Verantwortlicher:
Typ:
Status:
Geschlossen
Komponente:
Meilenstein:
Priorität:
5 - Mittel
Schweregrad:
5 - Mittel
Lösung:
Gefixt
Datei:
Keine
Vote
Score: 0
No votes
0.0% (0/0)
0.0% (0/0)

Details

4-stable, trunk ともに現象の再現を確認。4.x, 5.x 両方で対応が必要

4.104 (r7771) から発生

fwd.c

static void read_local_connection(PTInstVar pvar, int channel_num) の

		// recvの一時停止中ならば、何もせずに戻る。
		if (SSHv2(pvar)) {
			Channel_t* c = ssh2_local_channel_lookup(channel_num); /// c が NULL になっている。
			if (c->bufchain_recv_suspended) {

問題についての言及を観測した地点

再現手順

  • TTSSH でダイナミックポートフォワーディングを有効にする(例:port 1080)
  • Firefox の設定でプロキシを設定する(例:「設定」-「一般」-「ネットワーク設定」「手動でプロキシを設定」「SOCKS 127.0.0.1:1080」
  • 同時接続しそうな、画像の多いウェブサイトにアクセスする

Ticket-Verlauf (3/13 Historien)

2021-03-31 00:39 Aktualisiert von: nmaya
  • New Ticket "SSH2 ダイナミックポートフォワーディングを使うと落ちる" created
2021-05-09 14:31 Aktualisiert von: nmaya
Kommentar

r7771 から発生

2021-05-20 20:53 Aktualisiert von: youlab
2021-06-25 13:04 Aktualisiert von: nmaya
  • Details Updated
2022-02-11 21:53 Aktualisiert von: nmaya
  • Details Updated
2022-04-04 01:24 Aktualisiert von: nmaya
  • Details Updated
2022-08-19 12:22 Aktualisiert von: nmaya
  • Details Updated
2022-08-22 23:12 Aktualisiert von: nmaya
Kommentar

ポート転送がどう動いているのか調べました。

-L の場合の動作

  • accept_local_connection() が呼ばれると ssh2_channel_new() が呼ばれ、channels 側に pvar->fwd_state.channels の番号が保存される
  • pvar->fwd_state.channels の番号をもとに ssh.c の channels から Channel_t channel を見つけ、受信を一時停止しているか確認する
  • データを受信して、SSH サーバに送信する

-D の場合の動作

  • accept_local_connection() が呼ばれても ssh2_channel_new() が呼ばれないので、channels 側に pvar->fwd_state.channels の番号が保存されない
  • pvar->fwd_state.channels の番号から channels を見つけられない→ここで落ちる

おそらく問題がある動作

  • ダイナミックポートフォワーディングでは CHANNEL_OPEN を後回しにしているが、まだ開いていないチャンネルに「受信一時停止」を確認しにいくので落ちる
    • 一つ目の接続は繋がり、二つ目の接続から落ちる。一周遅れで問題が起きている感じで、一つ目で繋がるのはおそらく次項の理由による
  • ssh2_local_channel_lookup() は「いま使われているかどうかを」見ていないため、channel_num で探して channels[0](shellで使用中)の次の channels[1](used=0, local_num=0)が見つかって返してしまう
    • この動きをしているせいで、-D の場合に一つ目の接続が繋がってしまっている

データの変遷

  • 起動時
    • channels[0].used ... 0
    • channels[0].local_num ... 0
    • channels[0].bufchain_recv_suspended ... 0
    • channels[1].used ... 0
    • channels[1].local_num ... 0
    • channels[1].bufchain_recv_suspended ... 0
    • channels[2].used ... 0
    • channels[2].local_num ... 0
    • channels[2].bufchain_recv_suspended ... 0
  • SSH 接続
    • channels[0].used ... 0 -> 1
    • channels[0].local_num ... 0 -> -1 // シェルのときは -1 にしている
  • SOCKS 1接続目
    • local_num==0 の channels[1] が見つかる(used == 0)
    • channels[1].bufchain_recv_suspended 0 なので進む
    • チャンネルをオープン
      • channels[1].used ... 0 -> 1
      • channels[1].local_num ... 0 -> 0
    • チャンネルをオープンしたあとの、この socket での受信
      • local_num==0 の channels[1] が見つかるので、チェックして送信できる
  • SOCKS 2接続目
    • local_num==1 のチャンネルは channels の中にないので見つからない

呼び出しを追いかけたメモ

Channel_t channels ... ssh.c にあるほう・SSH2 のやつ
pvar->fwd_state.channels ... SSH1 からあるやつ・転送専用?
pvar->fwd_state.requests


1. SSH 接続
ssh2_channel_new(-1)
  channels[0]
    self_id: 0
    local_num: -1
    type: SHELL


2. 転送ポート listen
request = pvar->fwd_state.requests + request_num
request->listening_sockets
  socket()
  bind()
  WSAAsyncSelect()
  listen()


3-1. FWD_LOCAL_TO_REMOTE
accept_wnd_proc() ... WM_SOCK_ACCEPT
  request_num = find_request_num((SOCKET)wParam)
  listening_socket_num = find_listening_socket_num(request_num, (SOCKET)wParam)
  accept_local_connection(request_num, listening_socket_num)
    channel_num = alloc_channel(request_num) ... channel_num は pvar->fwd_state.channels のほう
      pvar->fwd_state.channels に追加
    SSH_open_channel(channel_num)
      ssh2_channel_new(local_channel_num)
        channels[found]->local_num = local_channel_num ... 空きチャネルを見つけて使う

accept_wnd_proc() ... FD_READ
  channel_num = find_channel_num((SOCKET) wParam)
  read_local_connection(channel_num)
     /* r7771 追加 */
     c = ssh2_local_channel_lookup(channel_num)
     c が受信にストップをかけているか確認する
     /* r7771 追加ここまで */
  recv()
  SSH_channel_send(channel_num)

3-2. FWD_LOCAL_DYNAMIC
accept_wnd_proc() ... WM_SOCK_ACCEPT
  request_num = find_request_num((SOCKET)wParam)
  listening_socket_num = find_listening_socket_num(request_num, (SOCKET)wParam)
  accept_local_connection(request_num, listening_socket_num)
    channel_num = alloc_channel(request_num) ... channel_num は pvar->fwd_state.channels のほう
      pvar->fwd_state.channels に追加
    // SSH_open_channel() を呼ばない

accept_wnd_proc() ... FD_READ
  channel_num = find_channel_num((SOCKET) wParam)
  read_local_connection(channel_num)
     /* r7771 追加 */
    c = ssh2_local_channel_lookup(channel_num) // channel_num が保存されていないので見つけられない
    c が受信ストップ中か確認する
     /* r7771 追加ここまで */
    recv()
    SSH_channel_send(channel_num)
    channel->filter(channel->filter_closure)
      SOCKS_filter(closure) ... FWD_FILTER_FROM_CLIENT
        parse_client_request(closure)
          parse_socks5_init_request(closure)
            SSH_open_channel(closure->channel_num)
              ssh2_channel_new(local_channel_num)
                channels[found]->local_num = local_channel_num ... 空きチャネルを見つけて使う
(Edited, 2022-08-23 12:07 Aktualisiert von: nmaya)
2022-12-15 08:21 Aktualisiert von: nmaya
  • Details Updated
2022-12-18 21:28 Aktualisiert von: None
Kommentar

修正をいれました。trunk/r10411, 4-stable/r10412 です。

手もとではうまく動いています。

2022-12-20 00:35 Aktualisiert von: zmatsuo
  • Verantwortlicher Update from youlab to zmatsuo
  • Lösung Update from Keine to Gefixt
2022-12-21 01:14 Aktualisiert von: nmaya
Kommentar

修正ありがとうございます。

ソースは追えていませんが、trunk/4-stable どちらもうまく動いているようです。

2022-12-22 00:55 Aktualisiert von: zmatsuo
  • Status Update from Offen to Geschlossen
Kommentar

ありがとうございます。

履歴を入れました。r10418, r10419 です。

クローズします。

Dateianhangliste

Keine Anhänge

Bearbeiten

You are not logged in. I you are not logged in, your comment will be treated as an anonymous post. » Anmelden