フレッツ回線 + IPv6 環境で SSH できない


自宅のネット環境を IPv6 対応したら SSH や Git でインターネットに接続できなくなって困った話。

現象

「フレッツ回線」「IPv6(※)」「SSH」でインターネットに出ようとした際に、「client_loop: send disconnect: Broken pipe」というエラーが出て接続できない。

※ DS-Lite による IPv4 over IPv6 を設定していたので、実際は IPv4 での接続でもこの問題が発生した。

原因

フレッツ網は IPv6 DSCP 値によってパケットを drop してしまうらしく、それによって SSH のパケットが届かなかったため。

DSCP

DSCP は IP パケットに含まれる 6bit の値で、パケットの優先度を制御する目的で使われる。

QoS - DSCP(Differentiated Services Code Point)とは

OpenSSH と DSCP

OpenSSH では IPQoS というオプションで SSH パケットの DSCP 値を設定できる。

ssh_config(5) - Linux manual page

設定しなかった場合、対話型セッションでは af21 非対話型セッションでは cs1IPQoS のデフォルト値として利用される。(OpenSSH 7.8 以降)

OpenSSH 7.8 Changelog

フレッツ回線と DSCP

フレッツ回線の仕様では、IPv6 パケットの DSCP 値によってパケットが drop されてしまう。

VPN 越しの Cisco WLC で WPA2 の SSID に associate できない時の罠 - diary.sorah

具体的にどの DSCP 値だと drop されるのか詳しくはわからないが、少なくとも af21 は drop される模様。

対処方法

IPv6 通信をする端末ごとに対応する方法と、ルータで対応する方法がある。

端末ごとに対応

SSH の設定ファイルを以下のように書き換えた。

~/.ssh/config
Host *
  IPQoS cs1

IPQoS に値をひとつだけ設定した場合は、対話型セッションと非対話型セッションの両方で設定した値が利用される。

なお、 cs1 以外にも 0x00none でも drop されない模様。

このあたり何を指定するのがベストなのかはわからないが、cs1 はデフォルト値にも設定されているから大丈夫やろ、という感じで決めてしまった・・・。

ルータで対応

すべての端末で設定をするのは大変な場合は、ルータでパケットの DSCP 値を書き換えてしまうという方法もある。

ググったところ EdgeRouter でやっている人がいた。
EdgeRouter X のファイアウォールでフレッツ光 の IPv6 から SSH が繫がらない問題を解決する – ちとくのホームページ