【テクニカル・上級編】 IPヘッダー:フラグメントオフセットとMore Fragmentsフラグの挙動 – ネットワーク基礎とWebセキュリティ実践ガイド

パケット解剖学:IPフラグメントの深層と、フラグメントオフセット・MFフラグが奏でる再構築の美学

ネットワークの現場に身を置く者なら、誰もが一度は「MTUの壁」に阻まれたパケットの悲劇を目撃したことがあるはずだ。現代のインターネットはEthernetの標準である1,500バイトのMTU(Maximum Transmission Unit)をベースに構築されているが、IP(Internet Protocol)層は、それよりも遥かに巨大なペイロードを受け入れる設計になっている。

ルーターのインターフェースが支えきれないほどの巨体をまとったパケットが飛び込んできたとき、IP層は自らの手でその肉体を切り刻み、宛先へと送り出す。これがIPフラグメンテーションだ。

しかし、この「パケットの切断と縫合」の裏側では、レイヤー3のプリミティブなメカニズムが黙々と、しかし極めて精密な計算を繰り返している。今回は、IPヘッダーにおける More Fragments (MF) フラグと フラグメントオフセット (Fragment Offset) がどのように連係し、バラバラになったパケットの欠片を元の姿へと完璧に復元しているのか。その内部挙動を、Linuxカーネルの視点とセキュリティ、そしてパフォーマンスの観点から徹底的に解剖していこう。

—

1. IPフラグメンテーションの物理的・論理的背景

データリンク層のMTUを超えたIPパケットに直面したルーターやホストは、パケットを分割(フラグメント化)せざるを得ない。ここで重要なのは、IPはコネクションレス型のベストエフォートプロトコルであり、トランスポート層(TCPやUDP)がどのようにデータをやり取りしているかなど、知ったことではないという点だ。

IP層にとって重要なのは、「与えられたIPデータグラムを、指定されたMTU以下のサイズに分割し、それぞれに有効なIPヘッダーを付与して送り出すこと」のみである。

分割された各パケット(フラグメント)は、それぞれ独立したIPパケットとしてルーティングされる。つまり、元のパケットの順序がそのまま保たれて宛先に届く保証はどこにもない。あるフラグメントは高速なバックボーンをかすめ取り、別のフラグメントは輻輳したルーターのキューで数ミリ秒足踏みをするかもしれない。

この無秩序なパケットの奔流から、宛先ホストのIPスタックは元のデータグラムを寸分違わず再構築しなければならない。その鍵を握るのが、IPヘッダーの「Flags」フィールドと「Fragment Offset」フィールドなのだ。

—

2. フラグメントオフセットとMFフラグの数学的挙動

IPv4ヘッダーの中央部に位置する16ビットの「Flags(3ビット)」と「Fragment Offset(13ビット)」は、パケット再構築のパズルを解くための羅針盤だ。

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|     Fragment Offset     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

この構造の中で、運命の分かれ道となるのが以下の2つの要素である。

  • MF (More Fragments) フラグ: 3ビットあるFlagsのうちの2ビット目(値としては 0x01)。これが 1 であれば「後ろにまだ続きのフラグメントが存在する」ことを意味し、0 であれば「これがこのパケットの最後のフラグメントである」ことを示す。
  • フラグメントオフセット (13ビット): 元のデータグラムの先頭から数えて、このフラグメントのペイロードがどの位置(何バイト目)に相当するかを示す。ただし、単位は「バイト」ではなく 「8オクテット(8バイト)単位」 である点に注意が必要だ。

オフセット計算のリアルな実例

仮に、IPヘ20バイトを含む、総サイズ 4,000 バイトのIPデータグラム(ペイロード 3,980 バイト)が存在するとしよう。これを、MTU 1,500 バイトのネットワーク(IPヘッダー20バイトを引くと、ペイロードの最大値は 1,480 バイト)に送り出すケースを考える。

1. 第1フラグメント:

  • ペイロードサイズ: 1,480 バイト(8の倍数である 185 ブロック)
  • MFフラグ: 1 (まだ後ろに続く)
  • フラグメントオフセット: 0 (先頭)

2. 第2フラグメント:

  • ペイロードサイズ: 1,480 バイト(185ブロック)
  • MFフラグ: 1 (まだ後ろに続く)
  • フラグメントオフセット: 1480 / 8 = 185

3. 第3フラグメント(最後):

  • 残りのペイロードサイズ: 3980 - (1480 * 2) = 1,020 バイト
  • ※ 1,020 は8で割り切れないため、通常は最後のフラグメント以外は8の倍数に丸められるが、概念として最後のチャンクは残りすべてを内包する。
  • MFフラグ: 0 (これが最後)
  • フラグメントオフセット: (1480 + 1480) / 8 = 370

宛先のLinuxカーネルなどのIPスタックは、受信したフラグメントの Identification フィールドでグループ化し、Fragment Offset を見てメモリ上の正しい位置にペイロードをコピペしていく。そして、最後に MF = 0 のフラグメントを受け取った瞬間、「データグラムの全体像が揃った」と判断し、上位層(TCP/UDP)へと引き渡すのだ。

—

3. ゼロトラストとセキュリティ:フラグメントが孕む暗黒の罠

ネットワークスペシャリストやセキュリティエンジニアがIPフラグメントに鋭い眼光を向けざるを得ない理由は、歴史的にこの「再構築のロジック」が数々の悪名高い攻撃の温床になってきたからだ。

1. ティアードロップ攻撃 (Teardrop Attack)

フラグメントオフセットの値を意図的に重ね合わせる(オーバーラップさせる)ことで、OSの再構築処理をバグらせ、システムをクラッシュさせる古典的なDDoS手法。現代のOSはこの手の重複に対して厳格なバリデーションを持っているが、組み込み機器やレガシーなファイアウォールでは依然として脅威になり得る。

2. IDS/IPSおよびWAFのバイパス

ステートフルインスペクションを行わない安直なパケットフィルタは、フラグメント化されたパケットの先頭(オフセット 0 のパケット)にしかTCPヘッダーが含まれないという仕様の隙をつかれる。
攻撃者は、悪意あるHTTPリクエストやシェルコードを第2、第3のフラグメントに分散させて送り込むことで、先頭パケットだけを検査するセキュリティアプライアンスの目を眩まし、内部ネットワークへ侵入を果たす。

現代の防御策:Linuxカーネルチューニングとパケット検査

こうしたリスクに対抗するため、エンタープライズの境界防御や高負荷サーバーでは、IPフラグメントのハンドリングを厳しく統制する必要がある。例えば、Linux環境(sysctl)では、不審なフラグメント再構築やメモリ枯渇を防ぐために以下のパラメータをチューニングすることが定石となっている。

# /etc/sysctl.d/99-security-fragments.conf
# IPフラグメントの再構築に割り当てるメモリの最大値(バイト単位)
net.ipv4.ipfrag_high_thresh = 4194304

# 再構築メモリがこの閾値を下回るようにカーネルが古いフラグメントを破棄し始める値
net.ipv4.ipfrag_low_thresh = 3145728

# フラグメントパケットが再構築のためにメモリ上で生存できるタイムアウト秒数(デフォルトは30秒だが、DDoS耐性を上げるために短縮することも)
net.ipv4.ipfrag_time = 15

また、ゼロトラストアーキテクチャの観点からは、そもそもファイアウォールや次世代FW(NGFW)において「非初回のフラグメント(Fragment Offset > 0)単体をドロップする」、あるいは「可能な限りPath MTU Discovery (PMTUD) を強制し、アプリケーション層でフラグメントそのものを発生させない」設計が極めて重要になる。

—

4. パフォーマンスとトランスポート層の最適化:フラグメントの回避

ネットワークの底流でフラグメントが発生することは、パケット処理のオーバーヘッド増大を意味する。ルーターにとっては CPU 負荷の上昇であり、エンドホストにとってはメモリバッファの占有と再構築待ちによる遅延(Latency)の増大に直結する。

特に、HTTPS/TLSハンドショイクにおいて大量の証明書チェーンや鍵交換パラメータがやり取りされる際、パケットサイズがMTUを超過してフラグメント化すると、RTT(Round Trip Time)の増大やパケットロス時のスループット急落を引き起こす。

パスMTUディスカバリー (PMTUD) とMSSクランピング

これを防ぐための黄金律が、Path MTU Discovery (PMTUD) の徹底と、ルーター/ファイアウォールにおける TCP MSS (Maximum Segment Size) クランピング である。

特にPPPoE環境やトンネリング(IPsec, VXLAN, GREなど)を多用する現代のエンタープライズNWでは、カプセル化によって実際の外側MTUが縮小するため、内側のパケットが意図せずフラグメント化の危機に晒される。

以下は、Linuxルーター環境(nftablesまたはiptables)でTCP MSSを適切に強制(クランプ)し、無駄なフラグメントの発生を根絶する設定例だ。

# iptablesを用いたTCP MSSクランピングの設定例
# 外部インターフェースのMTUが1400の場合、MSSを (1400 - IPヘッダー20 - TCPヘッダー20 =) 1360 に制限する
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360
# nftables (現代のLinux標準パケットフィルタ) でのMSSクランピング設定
table inet filter {
    chain forward {
        type filter hook forward priority 0; policy drop;
        
        # TCPのSYNパケットを検出し、Path MTUに合わせてMSSを自動調整(クランプ)する
        tcp flags & (syn | rst) == syn tcp option maxseg size set rt mtu
    }
}

この設定により、TCPのネゴシエーション段階(3ウェイハンドシェイク)で、クライアントとサーバーは「このパスではこれ以上大きなセグメントを流してはいけない」という合意をあらかじめ形成し、IP層でのフラグメント発生を未然に防ぐことができるのだ。

—

5. まとめ:パケットの細部に宿るプロトコルの美学

IPヘッダーのたった13ビットの Fragment Offset と1ビットの MFフラグ。それは、インターネットという巨大で混沌としたパケットの海において、秩序を保つための極めてエレガントな数理的アプローチである。

しかし、セキュリティの最前線や極限の低遅延を求められるインフラの現場においては、この「親切な自動分割・再構築機能」が、時としてセキュリティホールやパフォーマンスの足枷に変貌する。

真のネットワークスペシャリストやテックリードであれば、コマンドを叩いて表面上の疎通を確認するだけでなく、Wiresharkのキャプチャ画面の向こう側にあるフラグメントの断片を脳内で組み立て、カーネルがメモリ上でどのようにバッファを消費し、ルーターがどのヘッダー書き換えを行っているのかをありありと想像できなければならない。

パケットの挙動に無関心なインフラに、真のゼロトラストと高パフォーマンスは宿らない。日々の運用のなかで、フラグメントの存在を意識し、それをコントロールし続けることこそが、強靭で美しいネットワークを作り上げる唯一の道なのだ。

コメント

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