
Fedora LinuxでTLS接続だけがタイムアウトする事象をPMTU Blackholeの観点から解決した
はじめに
Fedora Linux環境で、AWS STSやKiro CLIの認証エンドポイントへのTLS接続だけがタイムアウトする事象が発生しました。TCP接続自体は成功し、通常サイズのICMP echoも正常に返ってきます。しかし、TLSハンドシェイクだけが無応答になるという症状です。
結論から言うと、これは証明書やTLSライブラリの問題ではなく、下位のネットワーク層で発生していたPMTU Blackhole(Path MTU Discoveryの機能不全)が原因でした。net.ipv4.tcp_mtu_probing を有効化することで即座に解消しています。以下、切り分け手順を記録します。
環境
- OS:Fedora Linux Asahi Remix 44(Server Edition、
aarch64) - カーネル:
7.0.13-400.asahi.fc44.aarch64+16k - CPU:Apple M1
- 発生タイミング:Fedora 43→44への
dnf system-upgrade実施後(数日間は無症状、その後突然発生) - 症状:AWSのHTTPSエンドポイントへの接続がタイムアウト。Kiro CLIの認証・初期化も失敗
アップグレード直後の数日間は無症状だったことから、アップグレード自体が直接の引き金ではなく、その後の経路上の状態変化(ICMPドロップの発生)が引き金だったと考えられます。ただしこれは状況証拠であり、確定的な証明ではありません。
PMTU Blackholeとは
Path MTU Discovery(PMTUD)は、通信経路上で許容される最大パケットサイズ(Path MTU)を検出する仕組みです。IPv4では送信側がIPパケットにDF(Don't Fragment)ビットを立てて送信します。経路上のルーターがパケットサイズ超過を検知すると、送信元にICMPメッセージを返します。IPv4ではICMP "Fragmentation Needed"(Destination Unreachable, Type 3 Code 4)を返します(RFC 1191)。IPv6ではICMPv6 "Packet Too Big" メッセージを返します。送信側はこのICMPメッセージを受け取ってパケットサイズを縮小します。
PMTU Blackholeとは、この経路上のICMPメッセージが何らかの理由でドロップされ、送信側にパケットサイズ超過が通知されない状態を指します。ドロップの理由としては、ファイアウォール、セキュリティ機器、ISPのフィルタリング等が挙げられます。結果として送信側は大きなパケットを送り続けるものの応答が返らず、接続がタイムアウトします。
調査内容
症状の再現確認
curl -v でAWSエンドポイントへのHTTPS接続を試みると、TLSハンドシェイクの段階でハングしました。
$ curl -v https://sts.ap-northeast-1.amazonaws.com/
* Trying xxx.xxx.xxx.xxx:443...
* Connected to sts.ap-northeast-1.amazonaws.com (xxx.xxx.xxx.xxx) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
* CApath: none
TCP接続(Connected to ...)は成功していますが、Client Hello送信後にサーバーからの応答(Server Hello)が一切返ってこないまま、最終的にタイムアウトしました。
TCP到達性の確認
TCP接続自体に問題がないことを確認しました。
$ echo > /dev/tcp/sts.ap-northeast-1.amazonaws.com/443
$
エラーなく即座に返りました。TCPの3ウェイハンドシェイクは正常に完了しています。
ICMP到達性の確認
ping でICMP echoの到達性を確認しました。
$ ping -M do -s 1472 sts.ap-northeast-1.amazonaws.com
PING sts.ap-northeast-1.amazonaws.com (xxx.xxx.xxx.xxx) 1472(1500) bytes of data.
ping: local error: message too long, mtu=1460
-M do(DFビット強制)で 1472 バイトのICMPペイロード(IP/ICMPヘッダ28バイトを含めると1500バイト相当、MTU 1460を超えるサイズ)を送信した場合、"message too long, mtu=1460" という応答が得られました。ただし、これは経路上のルーターから返ってきたICMPパケットではなく、Linuxカーネルが送信前にローカルの既知のMTU情報に基づいて送信を拒否したローカルエラー(local error)です。少なくともローカルには1460というMTU情報が存在していたことが分かりますが、経路上でICMPが正常に機能しているかどうかはこの結果だけでは判断できません。
TLS Client Hello(DF付き、約1.5KB)の送信時も、対応するICMP応答が返らずタイムアウトしていました。ML-KEM等でClient Helloのデータサイズが増加すると、TCPセグメント化後のIPパケットが経路MTUを超えやすくなります。経路上のICMP到達性を直接確認する手段がなかったため、ping の結果だけで「ICMPは通っているから経路の問題ではない」と判断してしまうと、誤った除外につながりかねません。
ローカルファイアウォール設定の確認
ローカルのfirewalld / nftablesがICMPをブロックしている可能性を確認しました。
$ sudo nft list ruleset | grep -i icmp
meta l4proto icmp accept
meta l4proto ipv6-icmp accept
ICMPは明示的に許可されていました。ct state related ルールも正しく設定されており、ローカルのファイアウォールは原因ではないと判断しました。
tcp_mtu_probing の確認と変更
ここまでの切り分けで、TCP接続は成功するがTLSハンドシェイク(大きなパケットの送信)で停止するという状況から、PMTU Blackholeを疑いました。
$ sysctl net.ipv4.tcp_mtu_probing
net.ipv4.tcp_mtu_probing = 0
値は 0(無効)でした。この設定の意味は以下のとおりです(kernel.org ip-sysctl.txtより)。
| 値 | 動作 |
|---|---|
| 0 | 無効(デフォルト)。PMTUDは従来のICMPベースのみ |
| 1 | 通常はICMPベースのPMTUDで動作し、ICMP Black Holeを検知した場合にPLPMTUDを有効化 |
| 2 | 常に有効。tcp_base_mss を初期MSSとして使用 |
tcp_mtu_probing を有効にすると、LinuxカーネルはICMPだけに依存せず、TCPレイヤーで段階的にパケットサイズを増やしながら経路のMTUを探索します。これはRFC 4821「Packetization Layer Path MTU Discovery(PLPMTUD)」(RFC 4821)の考え方に基づく手法です。
値を 2 に変更しました。
$ sudo sysctl -w net.ipv4.tcp_mtu_probing=2
net.ipv4.tcp_mtu_probing = 2
効果の確認
変更直後に同じエンドポイントへ接続を試みたところ、即座に成功しました。
$ curl -v -o /dev/null -w "time_total: %{time_total}s\n" https://sts.ap-northeast-1.amazonaws.com/
* Trying xxx.xxx.xxx.xxx:443...
* Connected to sts.ap-northeast-1.amazonaws.com (xxx.xxx.xxx.xxx) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / x25519 / RSASSA-PSS
...
time_total: 0.523s
タイムアウトしていた接続が0.5秒台で完了しました。
恒久化
再起動後も設定を維持するため、sysctl.dに設定ファイルを作成しました。
$ sudo tee /etc/sysctl.d/99-tcp-mtu-probing.conf <<'EOF'
# PMTU Blackhole回避: ICMPに依存せずTCPレイヤーでMTUを探索する
net.ipv4.tcp_mtu_probing = 2
EOF
$ sudo sysctl --system
副次的な調査: ML-KEM(ポスト量子鍵交換)の影響
TLS 1.3のポスト量子鍵交換(ML-KEM / Kyber)は、Client Helloのサイズを肥大化させます。
実際の通信を確認したところ、ML-KEMなしの場合、Client Helloは約777バイトですが、ML-KEM付きの場合は約1587バイトまで増加します。これにより、TCPセグメント化後のパケットが経路MTU(今回の場合1460バイト)を超えやすくなり、PMTU Blackholeを顕在化させる要因の1つになります。
当初はML-KEM付きClient HelloがAWSエンドポイント側で拒否されている可能性を疑いました。しかし事後検証の結果、今回検証したAWSエンドポイントでは、ML-KEM付きハンドシェイクが正常に処理されることを確認しました。直接の原因ではありませんでしたが、Client Helloの肥大化がPMTU Blackholeを顕在化させやすくする誘因だったと考えられます。
注意事項・Tips
curl -v でPMTU Blackholeを疑うシグナル
curl -v の出力で以下のパターンが見られた場合、PMTU Blackholeを疑う価値があります。
- TCP接続(
Connected to ...)は成功する TLS handshake, Client hello (1):の OUT 方向のログが出た後、IN 方向のログが一切出ない- 最終的にタイムアウトで終了する
TLSライブラリや証明書の問題では、通常何らかのエラーメッセージ(alert、verify failed 等)が返ります。完全な無応答は、パケットが経路上でドロップされている可能性を示唆します。
tcp_mtu_probing の値の使い分け
| 値 | ユースケース | トレードオフ |
|---|---|---|
| 0 | 経路上のICMPが正しく機能している環境 | PMTU Blackhole発生時に対処が難しい |
| 1 | 通常はICMPベースのPMTUDを使い、Black Hole検知時のみPLPMTUDに移行したい場合 | 検知まで数十秒のタイムアウトが発生する可能性あり |
| 2 | ICMP Blackholeが頻発する環境、TCP MTU probingを常に有効化したい場合 | 初回接続時に小さいMSSから開始するため、若干のレイテンシ増加の可能性あり |
今回は 2 を選択しました。ISPや経路上の機器構成が変わるたびに再発しうる問題であり、検知を待つ 1 よりも恒常的に有効化する 2 の方が適切と判断しました。
経路上のICMPドロップに注意
ローカルのfirewalld / nftablesでICMPを許可していても、経路上でICMP "Fragmentation Needed" がドロップされていれば同じ症状が発生します。経路上とは、ISPのルーター、セキュリティアプライアンス等を指します。ローカル設定だけで「ICMPは通している」と判断するのは不十分です。
TLSで顕在化しやすい理由
TCPの3ウェイハンドシェイク(SYN / SYN-ACK / ACK)は数十バイトの小さなパケットであり、一般的なMTU制限に引っかかりません。一方、TLS Client Helloは暗号スイートの一覧や拡張フィールドを含むため1.5KB前後になりやすく、経路上のMTU制限に到達しやすい構造です。さらにML-KEM等のポスト量子鍵交換が有効な場合、ClientHelloのサイズは一層増大します。
このため、「TCP接続は成功するのにTLSだけ失敗する」という一見不可解な症状が生じます。
まとめ
TLSハンドシェイクだけがタイムアウトし、TCP接続や通常サイズのICMP echoは正常という症状では、TLSライブラリや証明書の問題だけでなく、PMTU Blackholeも切り分け対象になります。明確なTLS alertや証明書検証エラーが出ている場合は、まず証明書設定、TLSバージョン、暗号スイート、SNIなどを確認します。一方、Client Hello送信後に応答がないままタイムアウトする場合は、PMTU Blackholeを疑うシグナルになります。
今回の環境では、net.ipv4.tcp_mtu_probing を 0 から 2 に変更した直後に接続が成功しました。tcp_mtu_probing を有効化すると、ICMPだけに依存せずTCPレイヤーでMTU探索を行えるため、経路上のICMPドロップによる影響を受けにくくなります。
1 はICMP Black Hole検知後にTCP MTU probingへ移行する設定で、初回接続時にタイムアウトが残ることがあります。2 はTCP MTU probingを常時有効化し、tcp_base_mss を初期MSSとして使用します。今回は検知待ちを避けるため、2 を選択しました。
設定は net.ipv4.tcp_mtu_probing = 2 を /etc/sysctl.d/ 配下の設定ファイルに追加することで恒久化できます。同種の事象では、curl -v の停止位置と sysctl net.ipv4.tcp_mtu_probing の値を確認すると、切り分けの手がかりになります。







