TCP MSSネゴシエーションの深層:MTUの罠、パケット断片化、そしてゼロトラスト時代のエッジ最適化
ネットワークの現場において、アプリケーション層の華やかなAPI設計や、セキュアなTLSハンドシェイクの裏側で、静かに、しかし確実にシステム全体のパフォーマンスと信頼性を左右している黒衣が存在する。それが、L3のMTU(Maximum Transmission Unit)とL4のTCP MSS(Maximum Segment Size)の関係性だ。
「なぜか特定の大容量ファイルをアップロードすると途中で固まる」「クラウド間のVPNトンネルを通した途端にレイテンシが跳ね上がる、あるいはパケットがドロップする」。こうした泥臭いトラブルシューティングの現場に直面したとき、多くのエンジニアが頭を抱えることになる。その根本原因の多くは、MSSのミスマッチとPath MTU Discovery(PMTUD)の失敗にある。
今回は、TCPのSYNパケットが飛び交うコネクション確立の瞬間から、Linuxカーネル内部でのパケット処理、そして現代のクラウドネイティブ環境やゼロトラストアーキテクチャにおける最適化プラクティスまで、パケットの挙動を解剖しながら徹底的に掘り下げていこう。
—
1. MTUとMSSの基礎方程式:なぜ「IPヘッダーとTCPヘッダーの分」を引くのか?
まず、用語の定義と物理的な制約を整理しておこう。
- MTU (Maximum Transmission Unit): データリンク層(L2)が一度に送信できる最大パケットサイズ。一般的なイーサネットであれば
1500バイトだ。 - MSS (Maximum Segment Size): トランスポート層(L4)のTCPが、フラグメンテーションを起こさずに1つのセグメントに格納できるペイロード(TCPデータ)の最大サイズ。
この2者の間には、以下の厳密な引き算の関係が成り立つ。
$$\text{MSS} = \text{MTU} – (\text{IPヘッダーサイズ} + \text{TCPヘッダーサイズ})$$
IPv4の標準ヘッダーは 20 バイト、TCPの標準ヘッダーも 20 バイトであるため、標準的なイーサネット(MTU 1500 バイト)におけるデフォルトのMSSは以下のようになる。
$$1500 – (20 + 20) = 1460 \text{ バイト}$$
もしここにIPv4のオプションやTCPオプション(タイムスタンプやSACKなど、通常は 12 バイト程度)が加われば、TCPヘッダーは長くなり、実効的なMSSはさらに小さくなる。この計算を怠り、L3の境界でパケットサイズがMTUを超過すると、何が起きるだろうか?
—
2. SYNパケットによるMSSネゴシエーションのメカニズム
TCPのコネクション確立(3ウェイハンドシェイク)の際、クライアントとサーバーは互いに自分が受信可能な最大セグメントサイズを MSSオプショナルフィールド を用いて通知し合う。
Client Server
| ----- [SYN, MSS=1460] ------------------------------> |
| <---- [SYN-ACK, MSS=1440] --------------------------- |
| ----- [ACK] ----------------------------------------> |
ここで重要なのは、TCPのMSSネゴシエーションは「両者で同じ値に統一する」のではなく、「お互いが宣言した値の小さい方を採用する」という点だ。
クライアントが 1460 を主張しても、経路上のどこかにルーターやVPNトンネル(IPsecやVXLANなど、追加のオーバーヘッドが発生する仕組み)が存在し、サーバー側が 1440 のMSSを持つインターフェースで受けていれば、以降のセグメントサイズは小さい方の 1440 に制限される。
しかし、この美しく機能するはずのネゴシエーションは、現代の複雑なネットワークトポロジにおいて容易に破綻する。それが「Path MTU Discoveryの機能不全」だ。
—
3. Path MTU Discovery(PMTUD)の暗闘とパケット断片化の恐怖
IPv4では、ルーターがMTUを超えるパケットを受信した場合、2つの挙動のいずれかを選択する。
1. パケットを断片化(Fragmentation)して転送する。
2. IPヘッダーの DF (Don't Fragment) フラグが立っている場合、パケットを破棄し、送信元へ ICMP Destination Unreachable (Fragmentation Needed) メッセージを返送する。
現代のインターネットおよびセキュアなエンタープライズネットワークでは、パフォーマンスとセキュリティ上の理由から、パケットの断片化は悪とみなされる。断片化はルーターのCPU負荷を高め、万が一フラグメントの一部がドロップした際に全パケットの再送を強いるためだ。そのため、現代のOSはデフォルトで DF フラグを立ててパケットを送信する。
ここでPMTUDの出番となる。送信元は DF=1 でパケットを送り、途中のルーターからICMPが返ってくることで「この経路の最小MTU(Path MTU)はいくつか」を学習し、それに合わせてMSSを動的に縮小する。
PMTUDが完全に崩壊するシナリオ(ICMPブラックホール)
セキュリティの観点から、ファイアウォールやWAF、クラウドのセキュリティグループにおいて、ICMPパケット(特にタイプ3、コード4の「Fragmentation Needed」)をすべて一律でドロップするポリシーが適用されているケースが後を絶たない。
この状態(ICMPブラックホール)に陥ると、以下のような悲劇的な挙動が発生する。
1. クライアントは MTU=1500(MSS=1460)でパケットを送信する。
2. 途中の経路に MTU=1400 のホップが存在するが、DF=1 のため通過できない。
3. ルーターはICMPを返す。
4. しかし、ファイアウォールがICMPをドロップするため、送信元には何も届かない。
5. 送信元はタイムアウトまで待ち続け、コネクションがハングアップする、あるいは極端にスループットが低下する。
—
4. 現場で使える対策:MSS ClampingとLinuxカーネルチューニング
こうしたネットワークの不条理からシステムを守るため、インフラエンジニアは適切な多層防御とカーネルチューニングを施す必要がある。
境界ルーター・ファイアウォールでの「MSS Clamping」
もっとも確実なアプローチの一つが、ネットワークの境界(ルーターやVPNゲートウェイ)でTCPのSYNパケットを監視し、通過するMSSの値を強制的に書き換える「MSS Clamping」だ。
例えば、CiscoルーターやLinuxベースのルーター(iptables/nftables)では、以下のように設定してトンネルのオーバーヘッド分(例: PPPoEなら - 8、IPsecなら - 72 など)をあらかじめ差し引く。
# iptablesを使用して、FORWARDチェインを通るTCP SYNパケットのMSSを強制的に1360にクランプする例
sudo iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360
これにより、内側のクライアントがどのような設定であれ、経路上の物理制約に合わせた安全なMSSへと強制的に補正される。
LinuxカーネルにおけるMSSとPMTUDのチューニング
アプリケーションサーバーやコンテナホストとして稼働するLinuxのカーネルパラメータ(sysctl)も、堅牢なネットワーク運用において見逃せないポイントだ。
以下の設定を /etc/sysctl.d/99-networking.conf などに記述し、パケット処理の最適化を図る。
# パスMTUディスカバリーを有効化(通常はデフォルトで有効)
net.ipv4.ip_no_pmtu_disc = 0
# 万が一ICMPブラックホールに遭遇した場合のフォールバックとして、
# 閉塞したルートに対して自動的にMSSを小さくする機能(TcpMtuProbe)を有効化
net.ipv4.tcp_mtu_probing = 1
# TCP送受信バッファの自動チューニング範囲(動的にスループットを最大化)
# min, default, max (バイト単位)
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
特に net.ipv4.tcp_mtu_probing = 1 は、ICMPがドロップする環境において、パケットロスを検知した際にカーネルが自発的に小さいMSSでプローブパケットを送り、経路の限界MTUを自力で見つけ出す極めて強力な機能である。
—
5. ゼロトラスト・クラウドネイティブ時代におけるハンドシェイクの最適化
今日のエンタープライズは、単一の社内ネットワークから、SaaS、パブリッククラウド、そしてゼロトラストネットワークアクセス(ZTNA)が複雑に入り組む境界のない世界へと移行している。
ここで改めて意識すべきなのが、トランスポート層(TCP/MSS)とトランスポートセキュリティ層(TLSハンドシェイク)のインタラクションだ。
TLS 1.3とTCPセグメントの衝突
TLS 1.3ではハンドシェイクが1-RTTに短縮され、初期のクライアントHelloメッセージの中に鍵交換パラメータが詰め込まれる。この結果、初期のTLS Client Helloメッセージは非常に大きなペイロードを持つことになり、しばしば単一のTCPセグメントに収まりきらずに分割(あるいはパケット断片化のリスクに直面)する。
もしMSSが適切にネゴシエーションされておらず、途中のプロキシやロードバランサー、クラウドのNATゲートウェイでパケットがフラグメント化されると、TLSハンドシェイクのレイテンシが劇的に悪化するだけでなく、WAFやIDS/IPSがパケットの断片を正しく再構築できずにセキュリティバイパスや誤検知を引き起こす温床となる。
ゼロトラストエッジ(CASB / Secure Web Gateway)における配慮
リモートワーカーがZTNAクライアントを経由して社内リソースやSaaSにアクセスする際、パケットは一度セキュリティエッジ(クラウドプロキシ)で終端され、再度カプセル化されて転送される。
この多重カプセル化(VXLAN over IPsecなど)環境下では、元のMTU 1500 のままではオーバーヘッドにより必ずパケットがオーバーフローする。
- モダンなZTNAクライアントは、仮想ネットワークインターフェース(TUN/TAP)のMTUをあらかじめ
1360や1400といった小さめの値に設定し、生成されるTCPセグメントのMSSを最初から強制的に抑え込む設計になっている。 - もしインフラ側やクライアント側の設定でこれが正しく連動していない場合、エンドツーエンドの通信で謎のパケットドロップに悩まされることになる。
—
結びにかえて:パケットの声を聞け
ネットワークスペシャリストやアーキテクトにとって、トラブルシューティングの極意は「パケットの声を聞くこと」に尽きる。Wiresharkや tcpdump を立ち上げ、SYNパケットのオプションフィールドに刻まれたMSSの数値を見つめる。そして、その値が経路上のルーターやトンネルの物理的制約、さらにはファイアウォールのポリシーと整合しているかを脳内で計算する。
# 現場での確認用:インタフェースのMTUと、キャプチャによるMSSの確認
ip link show
sudo tcpdump -nnvvv -i eth0 'tcp[tcpflags] & (tcp-syn) != 0'
クラウドやコンテナ、ゼロトラストといった抽象化のレイヤーがどれほど厚くなろうとも、その下層でデータを運んでいるのは依然としてIPとTCPの泥臭いパケットの群れに他ならない。MSSとMTUの本質を理解し、適切にチューニングされたインフラストラクチャこそが、セキュアで高スループットなモダンエンタープライズの土台となるのだ。
コメント