【実務・中級編】 VPN接続時におけるMTU(Maximum Transmission Unit)とMSS調整の仕組み – ゼロトラスト&エンタープライズセキュリティ実践ガイド

「なぜVPN越しだとAPIがタイムアウトするのか?」――MTU/MSS調整の泥沼を脱出する技術

ネットワークエンジニアとして現場を歩いていると、若手から「VPNを通すと特定のWeb APIだけがレスポンスを返さない」「pingは通るのにcurlだと固まる」という相談を受けることがよくあります。

画面越しにパケットキャプチャを見せてもらうと、そこには決まって「断片化(Fragment)」の山か、あるいはブラックホール化したパケットの成れの果てが転がっています。今回は、VPN構築において避けては通れない「MTU(Maximum Transmission Unit)」と「MSS(Maximum Segment Size)」の深淵について、現場の知見を交えて解説しましょう。

—

1. なぜ「VPN」でパケットは溢れ出すのか

VPN(IPsecやSSL-VPN)の正体は、元のパケットを別のパケットの中に「包み込む(カプセル化)」技術です。

例えば、MTU 1500バイトのイーサネットフレームで運ばれてきたIPパケットが、IPsecトンネルに入るとどうなるか。IPsecのヘッダーやESP(Encapsulating Security Payload)のオーバーヘッドが加わることで、全体のサイズは1500バイトを優に超えてしまいます。

ここでルーターは二択を迫られます。
1. 断片化(Fragmentation): 巨大なパケットを2つに割る。
2. 破棄(Drop): 「DF(Don’t Fragment)」ビットが立っていれば、ルーターは「無理だ」と判断してパケットを捨てる。

最新のWeb APIやHTTPS通信において、TCPパケットにはほぼ間違いなく DF ビットがセットされています。これが、「VPN越しだと通信が止まる」最大の原因です。

—

2. MSS Clamping:現場を救う特効薬

断片化を物理的に防ぐために、我々が現場で採用するのは「MSS Clamping」という手法です。

TCPの3ウェイ・ハンドシェイク(SYNパケット)の時点で、両端のホストに「俺はこれ以上のサイズのデータは一度に受け取れないから、このサイズ以下にしてくれ」と交渉させる仕組みです。

設定例:CiscoルーターでのMSS Clamping

VPNトンネルインターフェース(Tunnel0)にて、以下の設定を投入するのが定石です。

! インターフェース設定モードにて
interface Tunnel0
 ! IPsecオーバーヘッドを考慮し、通常は1360〜1400バイト程度に設定
 ! 1500 - 40 (IP/TCP) - 60 (IPsec/ESP) ≒ 1400 と計算する
 ip tcp adjust-mss 1360

この一行を入れるだけで、VPNを通過するTCP通信は、ルーターがSYNパケット内のMSS値を強制的に書き換えてくれます。これにより、ホスト側が自発的に小さなパケットを生成するようになり、断片化によるパケットロスが嘘のように消え去ります。

—

3. 実務で遭遇する「見えないパケットサイズ」の壁

APIの開発現場では、クライアント側の curl や Fetch API を使った検証中にこの問題にぶつかることがあります。以下のコマンドで、パケットサイズを意識したテストを行う習慣をつけましょう。

手順:パケットサイズを指定して疎通確認を行う

Linux環境であれば、ping コマンドで DF ビットを立てつつ、サイズを指定して送信できます。

# -M do: DFビットをセットする
# -s 1472: ペイロードサイズを1472にする(IPヘッダー20+ICMP8=1500)
# VPN越しにこれが通らない場合、MTU調整が必須です
ping -M do -s 1472 <ターゲットサーバーのIP>

もし、ping のサイズを少しずつ減らして 1400 くらいで通るようになったら、その差分がVPNのオーバーヘッドの正体です。

PythonによるAPIリクエスト時の注意

アプリケーション層で大きなJSONを投げたり、TLSハンドシェイクで証明書チェーンが大きくなったりすると、APIリクエスト自体が断片化のトリガーになることがあります。

import requests

# タイムアウトが頻発する場合、コネクションプールやヘッダーサイズを疑う
# MTU問題が疑われる環境では、あえて一度に送るデータ量を抑える設計も考慮する
try:
    response = requests.post(
        "https://api.example.com/data",
        json={"big_payload": "..." * 1000},
        timeout=5
    )
except requests.exceptions.Timeout:
    # 現場のTips: ここで「通信エラー」だけでなくMTU問題を疑い、
    # tcpdumpでパケットを確認するフローを標準化すること
    print("MTU問題の可能性あり:パケットキャプチャを確認せよ")

—

4. 最後に:エンジニアへのアドバイス

ネットワークは「魔術」ではありません。パケットは常に物理法則(MTUサイズ)に従って動いています。

  • まずはキャプチャ: tcpdump -ni any host <IP> -w capture.pcap で、通信がどこで止まっているかを見る。
  • DFビットを確認: Wireshark で IP Flags: 0x02 (Don't fragment) が立っているパケットが、VPNの入り口で再送を繰り返していないかを確認する。
  • 設計段階で考慮: Web API設計において、巨大なリクエストボディを扱う場合は、VPN経由のクライアントの存在を考慮し、チャンク分けやページネーションを徹底する。

「VPNで遅い・つながらない」と言われたら、まずはMTUとMSSのバランスシートを頭の中で描いてみてください。これだけで、トラブルシューティングのスピードは劇的に向上します。

技術は現場で磨かれます。明日からの運用で、ぜひこの視点を活かしてみてください。

コメント

タイトルとURLをコピーしました