第10回 IPパケットの構造とIPフラグメンテーション基礎から学ぶWindowsネットワーク(2/3 ページ)

» 2003年04月04日 00時00分 公開

 前回の説明では、各ルータやコンピュータからIPパケット(IP層でやり取りされるパケット)が送受信される過程を簡単に説明したが、そこでやり取りされるIPパケットの詳細構造は実際には次のようになっている。

IPパケットの詳細構造
IPパケットの構造は、IPヘッダ部分と、IPパケットによって運ばれるデータ部分(図中の赤の部分)の大きく2つに分けられる。そしてIPヘッダはさらに固定長の部分(図中の青色と緑色の部分。先頭の20bytes)と、オプション部分(図中の黄色の部分。最小0byte)の2つで構成される。図中の小さい1目盛りは1bit幅であり、ここでは32bitずつに区切って表現している。IPパケットの詳細については「RFC791―INTERNET PROTOCOL」を参照のこと。

 一見すると何やら複雑そうに見えるかもしれないが、あまり難しく考える必要はない。すでに何度も述べているように、ネットワーク・プロトコルは階層的に構築されており、IP層よりも下にはイーサネットxDSL、無線LAN、光ファイバなど、物理的なネットワーク媒体の層が存在し、IP層よりも上位には、TCPやUDPといった、アプリケーション・プログラムから直接利用できるネットワーク・プロトコルが用意されている。IP層の目的は、上位プロトコル(TCP/IPの場合は、TCPもしくはUDPプロトコル)から渡されたデータを、IPアドレスに基づいて、最終的なあて先として指定されたコンピュータにまで届けることである。そのため、このIPパケットの先頭部分(IPヘッダの部分)には、パケットの送信元のIPアドレスとあて先のIPアドレス、そして上位層から渡されたデータや上位のプロトコル・タイプ、そしてIPルーティング作業を実行するために必要な情報などが入っているだけなのである。

 IPパケットを受け取ったコンピュータは、まずこのIPヘッダの部分を見て、自分のIPアドレスあてのパケットかどうかを調査する。自分のIPアドレスあてであれば、それは最終目的のコンピュータに到達したということなので、次にIPパケットの中からデータ部分を取り出して、上位の(TCPやUDPの)プロトコル処理部へと引き渡す。だがそのIPパケットが自分あてでなければ、(ルータの場合は)さらにルーティング・テーブルを参照して別のコンピュータやルータへとIPパケットを再送することになる。このような動作をIPルーティングと呼ぶ。IPヘッダの中には、このIPルーティングを行うために必要な情報がすべて格納されており、上位プロトコルのデータ(TCPやUDP層のヘッダ情報)や、下位プロトコルのデータ(物理層のヘッダ情報)を参照する必要がないように設計されている。

 IPパケットの構造は、IPヘッダ部分と、IPパケットによって運ばれるデータ部分(図中の赤色の部分)の大きく2つに分けられる。そしてIPヘッダはさらに固定長の部分(先頭の20bytes)と、オプション部分(図中の黄色の部分。最小0byte)の2つから成り立っている。IPパケットで送るデータが何もない場合でも(実際には上位のデータがまったくないということはないが)、IPヘッダ部分だけは必要になるので、(理論的な)IPパケットの最小サイズは20bytesということになる。

 さて、それではヘッダ中の各フィールドについて詳しく見ていこう。フィールド名の後ろに併記した4bitなどの数字は、そのフィールドに割り当てられているbit幅を表している(ここでは8bitを1byteとする)

「バージョン」フィールド:4bit幅

 バージョン・フィールドはIPプロトコルのバージョンを表現するために使われる。この連載で扱うTCP/IPは、IPv4をベースにしているので、このフィールドの値は常に4(2進数表現では0100)となっている。次世代のTCP/IPプロトコルであるIPv6ではこのフィールドが6(2進数では0110)となるので、同じネットワーク媒体上にIPv4とIPv6のパケットが混在していても混乱しないし、区別することができる。

「ヘッダ長」フィールド:4bit幅

 ヘッダ長フィールドはIPヘッダ部分(固定長部分+オプション部分)のサイズを表すためのフィールドである。4bit幅しかないので、0から15までしか表現できないが、ヘッダの長さは32bit(4bytes)単位(つまりヘッダ部分は常に4bytesの倍数)で数えるので、実際の最大長は15×4=60bytesまで表すことが可能となる。なお、IPヘッダの固定長部分が常に20bytesあるので、このフィールドの最小値は5(20÷4)であり、最大値は15となる。

「サービス・タイプ(TOS)」フィールド:8bit幅

 サービス・タイプ・フィールドは、IPパケットの優先度などを表すTOS(Type Of Service)を指定するために使われる。例えば、ある特定の値が指定された場合には、そのほかのパケットよりも優先してルーティング処理などを行う、といった設定ができるとされている。だが現在使われている実際のTCP/IPネットワークでは、このフィールドによるTOS指定はほとんど使用されておらず、意味を持っていないことが多い。

「データグラム長」フィールド:16bit幅

  ヘッダ長フィールドが「IPヘッダ部分のサイズ」を4bytes単位で数えたものであるのに対し、データグラム長フィールドはIPパケット全体のサイズをbyte単位で数えたものである。データグラム長フィールドは、「IPパケット全体(IPヘッダ部分とデータ部分の合計)」の長さを表しているという違いもある。

 このフィールドの幅は16bitなので、IPパケットのサイズの最大長、つまり1つのIPパケットで送信可能なデータ(+ヘッダ部)のサイズは64Kbytes(65,535bytes)までとなる。IPヘッダ部分のサイズは最低でも20bytesあるので、このフィールドの最小値は「20+データ部分の長さ(bytes)」となる。

 なおIPパケットがフラグメント化(後述)されている場合は、このフィールドは、元のIPパケット全体のサイズではなく、このIPフラグメントだけのサイズを表す。

「ID」フィールド:16bit幅

 IDフィールドは、IPフラグメンテーションにおいて利用される、IPパケットを識別するための数値である。IPフラグメンテーションについては後述するが、簡単にいうと、IPパケットをいくつかに分割して小さくしてから送信するという機能である。IPパケットの最大サイズは64Kbytesであるが、このサイズのデータを1回で送信することのできるネットワーク媒体は(ほとんど)ない。そのため、送信可能なサイズにまでIPパケットを小さく分割してから送信を行う。そして、最終的なあて先のコンピュータ上で分割されて届いたIPパケット合成し、もとのサイズのIPパケットに再構成する。これにより、物理的なネットワーク媒体によらず、IPパケットを送受信することが可能となる。

 各コンピュータは、IPパケットを送信するたびにランダムな16bitの数値をこのIDフィールドに設定する。このIDの数値そのものには意味がなく、毎回異なるIDがセットされてからIPパケットが送信されるということだけが重要である。同じIPパケットに属するフラグメント化(分割)されたパケットは、すべて同じIDを共有するので、後で1つのIPパケットに再構成する場合の目印となる。

「フラグ」フィールド:3bit幅

 フラグ・フィールドもフラグメンテーションにおいて利用される、特別なフラグ情報である。3bit分あるが、使われているのは以下の2bit分だけである。

■MF(More Fragment)ビット
 1bitは、フラグメントがさらに続くかどうかを表す。1つのIPパケットを複数に分割した場合、最後部のパケットではこのMFビットを0にし、そのほかのパケットではMFビットを1にする。このビットが1ならば、フラグメント化されたIPパケットがさらに後ろに続くという意味になる。

■DF(Don't Fragment)ビット
 もう1bitは、IPパケットを分断してはいけない、という指示を与えるために利用される。ルータは必要ならばIPパケットのフラグメント化を行うが、このDFビットが1にセットされていると、それはフラグメント化を行ってはいけないという指示になる。IPパケットのフラグメント化とその逆操作(フラグメント化されたIPパケットからの再構成)を行うには、少なからず複雑な操作が必要になる。性能の低いコンピュータや、フラグメンテーション・アルゴリズムを組み込むのが困難な組み込み機器などでは、このDFビットを使うことで、フラグメンテーション処理を使わずにTCP/IP通信を実現することが可能になる。例えばシステム起動時に実行されるネットワーク・ブート(ネットワーク上からプログラムをロードして起動するようなシステム)のプログラムでは、サイズなどの制約からあまり複雑なコードを組み込むことができない。このような場合には、このDFフラグをセットし、なおかつ通信をUDPだけに限定するなどにより、TCP/IPの機能をすべて実装しなくてもネットワークを利用できるようにしている。

「フラグメント・オフセット」フィールド:16bit幅

 フラグメント・オフセット・フィールドは、フラグメント化されたIPパケットにおいて、フラグメントのどの部分がIPパケット中に含まれているかを示すためのオフセット数値フィールドである。IPパケットのサイズは64Kbytesあるが、上位3bitがフラグ・フィールドのために利用されているので、全部で13bit分の幅しかない。しかしフラグメントは常に8bytes単位で行われるので、この値を8倍してオフセットの数値とする。これならば13bitでも64Kbytesの範囲を表すことができる。詳細については後述する。

「TTL」フィールド:8bit幅

 IPパケットの「寿命」を表すための数値フィールドが、TTLフィールドである。IPパケットを送信するコンピュータは、このフィールドに適当な数値をセットしておき、その決められた寿命の間しかIPパケットが生存できないようにする。この詳細についても後述する。

「プロトコル番号」フィールド:8bit幅

 プロトコル番号フィールドは、上位に当たるトランスポート層のネットワーク・プロトコルの種類を表す番号を格納するフィールドである。TCP/IPプロトコルで利用される具体的なプロトコル番号の例としては、次のようなものがある。これらの値は、いわゆる「protocolファイル」(Windows 2000/XPならば%windir%\system32\drivers\protocolファイル)に書き込まれている。

※これはWindows XPに含まれているprocotolファイルからの抜粋

# <protocol name>  <assigned number>  [aliases...]   [#<comment>]
ip       0     IP       # Internet protocol
icmp     1     ICMP     # Internet control message protocol
ggp      3     GGP      # Gateway-gateway protocol
tcp      6     TCP      # Transmission control protocol
egp      8     EGP      # Exterior gateway protocol
pup      12    PUP      # PARC universal packet protocol
udp      17    UDP      # User datagram protocol
hmp      20    HMP      # Host monitoring protocol
xns-idp  22    XNS-IDP  # Xerox NS IDP
rdp      27    RDP      # "reliable datagram" protocol
rvd      66    RVD      # MIT remote virtual disk

 このなかでは、1番のICMP、6番のTCP、17番のUDP、そしてここにはないが47番のGRE(PPTPプロトコルで利用される)などが、実際によく使われているプロトコルである。

「ヘッダ・チェックサム」フィールド:16bit幅

 これはヘッダ部分(固定部分+オプション部分)のチェックサム(整合性を検査するためのデータ)を表すフィールドである。データ部分をチェックサムの対象としていないのは、IPパケットがフラグメント化された場合には、すべてのデータ部分が揃わないので、チェックサムを計算することができなくなるからである。IPヘッダの部分はすべてのIPパケットに含まれているので、IPプロトコルではこの部分だけを対象としてチェックサムを計算する。データ部分の内容が正しいかどうかは、上位のプロトコル(UDPやTCP)が独自にチェックサムなどの技法を使って検査することになっている。だが実際には下位のネットワーク媒体(および上位プロトコル)でもさまざまな方法でエラー検査が行われているので、IPプロトコルでエラーを検出しなくても問題は発生する確率は非常に少ない。

 このチェックサム計算では「1の補数演算」という特別なアルゴリズムが利用される。通常のコンピュータでは「2の補数演算」によるチェックサムがよく使われるが、IPやTCP、UDPでは、計算が高速で、かつ十分な信頼性が確保できる「1の補数演算」が利用される。チェックサム・フィールドは2bytesであるが、1の補数のチェックサムを計算する場合は、途中の計算は4bytesや8bytesずつでもかまない。そのため、計算を高速化できるという特徴がある。計算方法そのものは単純である。単に固定幅でデータを足し込んで、最上位からあふれた1bit(桁上がり)を、最下位bitへ足せばよい(例:0xffff+0xffff=0x1fffeとなるので、0xfffeに1を加えて0xffffが結果となる)。詳細については「RFC1071―Computing the Internet Checksum」を参照していただきたい。

「送信元IPアドレス」フィールド:32bit幅

 これは送信元のコンピュータのIPアドレスを表すためのフィールドである。あて先のIPアドレスさえ分かれば目的のコンピュータにまで届くので、このフィールドはIPプロトコル的にはその必要性は高くない(ルーティング処理などで経路を最適化するために使用することがある)。だが通信の相手先のコンピュータでは、送信元のコンピュータのIPアドレスが分からないと、パケット(データ)を送り返すことができないので、この送信元IPアドレスは絶対必要であるといえる。

「あて先IPアドレス」フィールド:32bit幅

 これはIPパケットの送信先コンピュータのIPアドレスを表す。ルーティング処理では、このあて先IPアドレスを元にしてルーティング処理が行われ、目的のコンピュータへとIPパケットが届けられる。

「オプション」フィールド:32bit単位で可変長

 IPパケットの送信に伴い、さまざまな付加的な機能を実現するために利用される。通常はオプション部分は利用されることはないが、IPパケットの通過のログ(時間の記録)やルーティングなどで利用されることがある。オプションの詳しい内容についてはここでは触れないが、例えばルーティングの経路を強制的に指定したり、パケットが通過したルート(ルータのIPアドレス)を記録させたりすることができる。

 オプション部分は通常は使用されないので、IPヘッダ部分のサイズは20bytesである。だがオプションが利用される場合は、4bytes(32bit)単位で可変であり、最大で40bytes(固定部分とあわせると最大で60bytes)にまで拡大することがある。

「データ」フィールド:可変長

 「データ」フィールドは、IPパケットとして運ばれるデータ(ペイロード)が含まれる場所であり、通常はTCPやUDP、ICMPなどのパケットがここに含まれることになる。TCPなら最小でも20bytes、UDPやICMPなら最小で8bytesのヘッダが使われるので(+さらにユーザー・データが含まれる)、IPヘッダ中における「データ」フィールドのサイズは最小でも8とかそれ以上の値になるであろう。

ネットワーク・バイト・オーダー(エンディアン)

 以上でヘッダ部分の各フィールドの説明は終わりであるが、ここでネットワーク・バイト・オーダー(network byte order)について触れておこう。

 ネットワークを通じてパケットを送信する場合、その内部にはバイナリのデータが含まれるのが普通である。例えば先にあげたIPヘッダ中にも、IPアドレスやデータ長、フラグメント・オフセットなど、さまざまなバイナリのデータ・フィールドが含まれている。これらのバイナリ・データをネットワークを使って送信する場合、その「バイト・オーダー(byte order)」をどのようにするかということはあらかじめ決めておかなければ、正しくデータをやり取りすることはできない。

 バイト・オーダー(日本語に訳すなら「バイトの順番」というところか)とは、2bytes以上のバイナリの数値データを、1byteずつに分割して送信する場合に、どのような順番で送るかという取り決めである。例えば「192.168.0.1」というIPアドレスを考えてみる。これを16進数で表現すると「0xc0.0xa8.0x00.0x01」となり、4bytesの1つの数値で表現すると「0xc0a80001」という数値になる。

 この数値をIPヘッダ中の「あて先IPアドレス」フィールドに埋め込んで送信したいが、実際のネットワーク媒体では、データは1byteずつしか送信することができない。とすると、この4bytesのデータを1byteずつに分割して送信しなければならない。このときにどのように分割して、そのような順番でバイト・データを送信するかということを決めるのが「ネットワーク・バイト・オーダー」である。TCP/IPでは、「ビッグ・エンディアン」方式でバイト・データを送信することになっている(x86プロセッサなどでは、メモリ上では「リトル・エンディアン」を採用している)。そのため、「0xc0a80001」という数値は、「0xc0」「0xa8」「0x00」「0x01」という順番で相手先へ送られ、相手側ではこれらのデータを集めて元の「0xc0a80001」という数値を取得することになる。もしバイト・オーダーが送信側と受信側で異なっていると、「0x0100a8c0」という数値になってしまい、これではまったく意味をなさなくなってしまう。そのため、プロトコルではネットワーク・バイト・オーダーを決めておくことが大切である。

IPパケットの例

 それでは実際にIPパケットの例を見てみよう。以下はWindows XP Professionalにおいて、DNSサーバへのクエリを行った場合のパケットのキャプチャ例である(Windows Serverに付属のネットワーク・モニタでキャプチャしている)。

 この場合のネットワークの階層は、最上位がDNSの問い合わせプロトコルであり、これはUDPプロトコルを使用している。UDPはIPパケットを使って送信されており、最終的にはイーサネットのフレームとしてネットワーク・ケーブル上に送信されている。

DNS問い合わせパケットのキャプチャ・解析例
 (1)注目しているパケット。キャプチャした時間や送受信MACアドレス、最上位のプロトコルなどが表示されている。
 (2)最下位にあるイーサネット・フレームの情報。
 (3)IPプロトコル。今回はこの部分に注目する。IPプロトコルを選択すると、下の16進ダンプ表示画面において、IPプロトコルに相当する部分((6))が反転表示される。
 (4)UDPプロトコル。UDPのヘッダ・サイズは8bytes。
 (5)DNSの問い合わせプロトコル。
 (6)パケットの内容をバイナリ・ダンプ表示させたところ。反転している部分がIPヘッダ(20bytes)。

 一番下に16進ダンプ形式で表示されているのが実際のネットワーク上を流れているパケットの例である。中段はそのプロトコルを分かりやすくツリー状に表示したものである。ちょうど「IP」プロトコルの部分を選択しているので、一番下の16進ダンプ表示でも、IPプロトコルのヘッダに相当する部分(20bytes)が反転表示されている。20bytesしかないので、順に取り出して解説しておこう。データの並びはネットワーク・バイト・オーダーなので、2bytesや4bytesのバイナリ・データはそのまま左から右へと読めばよい。

フィールド 値(16進数) 意味
バージョンとヘッダ長 45 プロトコル番号は4なのでIPv4を表している。ヘッダ・サイズ長は5なので、ヘッダの実際のサイズは5×4=20bytes
TOS 00 TOSフィールドはすべて0(未使用)
データグラム長 00 3F データグラム長はIPヘッダとデータ部(UDP+DNS)のサイズを表す。この場合は0x3f(63)bytes。ヘッダを除くと、IPのデータ部分は43bytesとなる
ID A0 59 IPパケットの識別用のID(0xa059)
フラグメント 00 00 フラグメントしていないのですべて0
TTL 80 IPパケットの生存時間。初期値は0x80(128)
プロトコル番号 11 プロトコル番号0x11(17)番はUDPを表す
チェックサム 18 67 IPヘッダ部分のチェックサム
送信元 C0 A8 00 67 送信元IPアドレスは192.168.0.103
あて先 C0 A8 00 36 あて先IPアドレスは192.168.0.54

 先のネットワーク・モニタの中段に表示されているプロトコルのツリー状表示は、この表の内容と合致していることが分かるだろう。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。