ICMPブラックホールのトラブルシューティング:トンネルネットワークにおけるPMTUDの修正

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

接続を阻む静かな刺客:ICMPブラックホール

以前、私はある支店のトラブルシューティングに丸一日を費やしたことがあります。そこでは社内チャットにはアクセスできるものの、ドキュメントポータルが開けないという問題が起きていました。画面は読み込み中のまま動きません。これはファイアウォールのブロックやDNSの失敗ではなく、Path MTU Discovery (PMTUD)の機能不全によって引き起こされる典型的なICMPブラックホールでした。

GRE、IPsec、VXLANなどのトンネル内にトラフィックをカプセル化すると、各パケットに余分なヘッダーが付加されます. 標準的なEthernetフレームのMTU(最大転送単位)は1500バイトです。

もしIPsecトンネルが60バイトのオーバーヘッドを加える場合、元のパケットは1440バイトを超えてはいけません。ルーターがトンネルに対して大きすぎるパケットを受信し、かつ「Don’t Fragment」(DF) ビットがセットされている場合、そのパケットを破棄する必要があります。通常、ルーターはICMPの「Destination Unreachable – Fragmentation Needed(宛先到達不能 – 断片化が必要)」メッセージを送信元に返し、パケットサイズを小さくするよう伝えます。

ICMPブラックホールは、セキュリティポリシーや誤設定されたファイアウォールがその特定のICMPメッセージを破棄したときに発生します。送信元のサーバーにはその通知が届きません。サーバーはサイズ超過のパケットを再送し続け、最終的に接続はタイムアウトします。これが、64バイトのpingは完璧に通るのに、1400バイトのWebレスポンスが毎回失敗する理由です。

診断ツールのセットアップ

この問題を解決するには、パケットレベルで何が起きているかを明らかにするツールが必要です。ほとんどのLinuxディストリビューションにはこれらが含まれていますが、診断用のマシンで最新の状態であることを確認してください。

UbuntuやDebianシステムでは、iputils-pingtcpdumpmtrをインストールします。これらはパケットがどこで消失しているかを追跡するために不可欠です。

# ネットワークツールの更新とインストール
sudo apt update
sudo apt install iputils-ping tcpdump mtr-tiny -y

RHEL、CentOS、Fedoraユーザーの場合は、以下を実行します。

sudo dnf install iputils tcpdump mtr -y

私はこれらのツールを本番環境で使用し、数百ものリモートサイトの接続問題を解決してきました。これらを準備しておくことで、推測ではなく計測に基づいた対応が可能になります。

設定:MTUとMSSのミスマッチを修正する

この問題は2つの方法で解決できます。インターフェースのMTUを手動で下げる方法と、現代のネットワークでより堅牢な選択肢であるTCP MSSクランプを使用する方法です。

方法1:手動によるMTU調整

エンドユーザーのデバイスや特定のトンネルインターフェースを管理している場合は、MTUを直接下げることができます。標準的なGREトンネルの場合、MTUを1476(1500バイトから24バイトのGREヘッダーを引いた値)に設定すると、通常は競合が解消されます。

# 特定のインターフェースのMTUを下げる
sudo ip link set dev eth0 mtu 1400

手動での変更はスケールさせるのが困難です。500台のノートPCがある場合、一台ずつ設定したくはないでしょう。そのため、多くのエンジニアはMSSクランプを好みます。

方法2:TCP MSSクランプ(プロフェッショナルな修正)

最初のSYN/ACKハンドシェイク中に、双方がこの値に合意します。ルーターでMSSを「クランプ(固定)」することで、最初の1バイト目から両方のエンドポイントに小さなパケットを使用させることができます。

iptablesを使用している Linuxゲートウェイでは、トンネルを通過するすべてのトラフィックに対してMSSを自動的に調整するために、以下のルールを適用します。

# MSSを自動的にPMTUにクランプする
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu

オーバーヘッドが予測しにくいIPsecトンネルの場合、1360バイトという固定値を推奨します。これにより、さまざまな暗号化ヘッダーのための安全マージンが確保されます。

# IPsecの安全性のために特定のMSS値を設定する
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1360

もしnftablesを使用している場合は、以下の構文を使用します。

# MSSクランプのnftables版
nft add rule ip filter forward tcp flags syn tcp option maxseg size set 1360

検証:修正が機能していることを証明する

設定を適用した後、大きなパケットが実際にパスを通過することを確認します。最も効果的な方法は、Don’t Fragmentビットを有効にした「スイープping」です。

Pingによるテスト

断片化を禁止するpingテストを実行します。1472バイト(ヘッダーを含めると1500バイト)から始めて、徐々に下げていきます。

# -M do: Don't Fragmentビットをセット
# -s: パケットのデータサイズ
ping -M do -s 1472 1.1.1.1

もし「Frag needed and DF set」というエラーが表示された場合、MTUはまだ高すぎます。pingが成功するまで -s の値を下げてください。もしリクエストが単にタイムアウトする場合、ICMPエラーメッセージが依然として上流のどこかでブロックされています。

tcpdumpによる監視

tcpdumpを使用して、TCPハンドシェイクをリアルタイムで監視します。ゲートウェイがSYNパケット内のMSS値を正常に書き換えているかを確認します。

# MSS値を確認するためにSYNパケットをキャプチャする
sudo tcpdump -i any -n "tcp[tcpflags] & (tcp-syn) != 0"

出力の options [mss XXXX] フィールドを確認してください。ルールが機能していれば、デフォルトの1460ではなく、1360(または選択した値)が表示されます。

最後に

長期的な安定性を確保するために、ファイアウォールのICMPポリシーを確認してください。常に ICMP Type 3, Code 4 を許可する必要があります。これがないと、PMTUDは設計上機能しません。MSSクランプと1350〜1380バイト程度の保守的な制限を組み合わせることで、VPNやSD-WAN環境を悩ませがちな謎の接続断を排除することができます。

Share: