ネットワークで送信可能なパケットの最大サイズをMTUという。IPパケットのサイズがMTUサイズを超えるとパケットの分割処理が行われる(IPフラグメンテーション)。pingの-fオプションを使うとIPパケットのDF bitがセットされ、IPフラグメンテーションが禁止される。データ・サイズを変えながらping -fを実行すると、ネットワークのMTUサイズを調査できる。
対象OS:Windows 2000/Windows XP/Windows Server 2003
ネットワークで通信を行う場合、(通常は)一度に送信可能なデータ(パケット)のサイズには上限がある。例えば、TCP/IPプロトコルで利用されているIPプロトコルでは、1つのIPパケットでは最大64Kbytesまでしか送信できない(IPv4の場合)。
しかし、このような大きなサイズのIPデータを1つのパケットで送信することのできる物理ネットワーク媒体はない。例えばイーサネット(および相互互換性を持つ無線LANなど)では、1パケット(1フレーム)のサイズは最大1500bytesだし、FDDI(光ファイバ)では4352bytesというのが普通である。
このように、一度に送信することができるデータのサイズを「MTU(Maximum Transmission Unit)」といい、ネットワークのプロトコルや媒体ごとに固有の値がある。
MTUサイズよりも大きなサイズのIPパケットを送信しようとすると、MTUサイズに収まるように、IPパケットをいくつかに分割して送信しなければならない。これを「IPフラグメンテーション(IP fragmentation)」といい、MTUサイズに合わせてIP送信時やルータ経由時に自動的に行われる。
そして、分割されたそれぞれのパケット(「フラグメント」という)は、最終的な受信先で合成されて元のIPパケットに復元される。このようにして、MTUサイズの違いによらず、ネットワーク上でIPパケットは送受信されている。
IPフラグメンテーション機能があるため、(アプリケーションは)MTUサイズを意識せずに送信することができるし、MTUサイズが異なるネットワーク・メディアを経由しても、パケットが最終目的地まで正しく届けられることになる。
だが、IPフラグメンテーションが起こると、フラグメント化(分割)と再構成(結合)のためにオーバーヘッドが生じるという問題がある。
フラグメント化されたパケットは、最終的なあて先(IPパケットのあて先IPアドレスのコンピュータ)で再構成が行われるが、この作業はすべてのフラグメント・パケットがそろうまで実行することができない(すべてがそろわない限り、上位プロトコルへは渡されない)。そのため、フラグメンテーションが発生しないように、MTUサイズに収まるようなパケットだけを送信する方がパフォーマンスが向上する。
また、こちらの方がより問題であるが、フラグメンテーションが発生すると、場合によっては通信できなくなる場合がある。ファイアウォールによっては、フラグメント化されたパケットは受け取らないように設定されていることがあるからだ。
IPフラグメンテーションはTCP/IPにおける基本的な機能であるが、意味のない大きなIPパケットを送信してDoS攻撃に使われることがある。またフラグメント化したパケットのうちの一部分(最後の部分)だけを送信して、受信側に再構成用の準備をさせ、システム・リソースを無駄に消費させるといった攻撃にも使われることがある。このような事情があるため、フラグメント化したパケットの受信を拒否するようにしている場合がある。
このようなファイアウォールが使われていると、正常な通信までもが拒否されることになる。すべてのインターネット上のサイトがこのような運用をしているわけではないが、実際にこうしているところは少なからず存在する。そのため、相手によってはWebサーバにつながらない、メールが送れない、というトラブルが発生することがある。
この問題を避けるため、可能ならばIPパケットのサイズをMTUサイズ以下になるように調整するのがよい。TCP/IPの規格では、MTUの最小サイズは576bytesと決められているが、イーサネットやPPPoEなどではより大きなサイズが使われている。上で述べたとおり、フラグメンテーションを起こさずに送信できる、可能な限り大きなパケットを使うのが望ましい。
本TIPSでは、pingコマンドを使って、MTUサイズを調査する方法について解説する。調査したMTUサイズに基づいて、TCP/IPプロトコルを調整する方法については右上の関連記事を参照していただきたい。
pingコマンドは、ICMP Echoパケットの送受信を行うためのプログラムである。ICMPプロトコルはIPプロトコルの上に実装されており、ICMP Echoでデータを送信すると、そのままICMP Echo Replyで送り返してくるだけの単純な機能を持っている。もしMTUサイズを超えるような大きなパケットをpingのデータとして送信すると、途中でフラグメント化されて相手に届くことになる。
IPヘッダのサイズはデフォルトでは20bytes、ICMPのヘッダは8bytesなので、イーサネット(MTU=1500bytes)では、最大で1472bytesのデータ・サイズまでならフラグメント化せずに送信することができる。もしpingで1473bytes以上のデータを指定すると、IPヘッダ/ICMPヘッダと合わせて1501bytes以上となり、フラグメント化しなければ送信することはできない。
pingコマンドのオプションとして「-f」を指定すると、IPフラグメントをしてはいけないという指定になる。具体的には、-fオプションを指定するとIPヘッダ中のDF(Don't Fragment)bitがオンになる。DF bitがオンのパケットは、フラグメント化が禁止され、フラグメント化してから(あて先へ)ルーティングする代わりに、送信元に対してエラーを返すことになっている。
ネットワークのMTUサイズを調査するには、pingのデータ・サイズを変えながら、-fオプションを付けたpingコマンドを実行すればよい。
データ・サイズが小さいうちはMTUサイズに収まるので、pingのパケットは正しく相手先まで届くし、戻ってもくるだろう。だがMTUサイズに収まらないサイズになると、IPフラグメント化ができないので、ルータからエラーが返ってくる。
これにより、MTUサイズを調査することができる。例えば、以下はイーサネットだけで構成されたLAN上で調査した場合の例である(「-n 1」オプションは、1回だけpingするという指定)。
C:\>ping -f -l 1472 -n 1 10.20.1.11 ……サイズ=1472bytesで実行
Pinging 10.20.1.11 with 1472 bytes of data:
Reply from 10.20.1.11: bytes=1472 time=1ms TTL=127 ……応答あり
Ping statistics for 10.20.1.11:
Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 1ms, Maximum = 1ms, Average = 1ms
C:\>ping -f -l 1473 -n 1 10.20.1.11 ……サイズ=1473bytes
Pinging 10.20.1.11 with 1473 bytes of data:
Packet needs to be fragmented but DF set. ……エラー応答
Ping statistics for 10.20.1.11:
Packets: Sent = 1, Received = 0, Lost = 1 (100% loss),
C:\>
2つ目のpingでは、1473bytesのデータ長でpingを実行しようとしたが、「Packet needs to be fragmented but DF set.(パケットはフラグメント化する必要があるが、DF bitがセットされているのでできなかった)」というエラー・メッセージが表示されている(これは、実際にはパケットの送信前に、ローカル・コンピュータ自身で表示している)。
1472bytesのデータまでは正しく送受信できていることから、このネットワークのMTUサイズは、「1472(データ・サイズ)+8(ICMPヘッダ)+20(IPヘッダ)=1500bytes」より、イーサネットのMTUサイズ(1500bytes)と一致していることが分かる。
以上はローカルのイーサネットの例であったが、例えばPPPoE(xDSLや光ファイバ・インターネット回線などで使われているプロトコル)などが使われていると、それらのプロトコルの分だけ、MTUサイズが制限されることになる。以下は、あるADSL回線サービスとPPPoEを使ったインターネット・アクセス回線における例である。
C:\>ping -f -l 1438 -n 1 61.XX.XX.XX ……サイズ=1438bytesで実行
Pinging 61.XX.XX.XX with 1438 bytes of data:
Reply from 61.XX.XX.XX: bytes=1438 time=36ms TTL=54 ……応答あり
Ping statistics for 61.XX.XX.XX:
Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 36ms, Maximum = 36ms, Average = 36ms
C:\>ping -f -l 1439 -n 1 61.XX.XX.XX ……サイズ=1439bytesで実行
Pinging 61.XX.XX.XX with 1439 bytes of data:
Packet needs to be fragmented but DF set. ……エラー応答
Ping statistics for 61.XX.XX.XX:
Packets: Sent = 1, Received = 0, Lost = 1 (100% loss),
この例では、1438bytesまではpingが通ることから、MTUサイズは「1438+8+20=1466bytes」であることが分かる。イーサネットのMTUサイズと比べると34bytes少ないが、これがPPPoEなどのヘッダ・サイズの分である。NTTのFLET'Sなどではもう少し大きく、46bytes(MTUサイズ=1454bytes)となっている。
なお、途中にMTUサイズが異なるネットワーク・メディアが複数存在していると、経路中で最も小さいMTUサイズが得られることになる。特定のルータ(に接続されているネットワーク・メディア)までのMTUサイズを調査したければ、pingのあて先をそのルータに設定して実行する必要がある。どのルータを経由しているかを調べるには、tracert.exeやpathping.exeコマンドなどを使えばよい。
以上は、DFフラグ付きのIPパケットに対して、途中のルータやあて先コンピュータがエラーを返している場合の例であったが、ファイアウォールの設定によっては、エラーを返さずに、単にパケットを捨てている場合もある。DoS攻撃のようなものに対していちいちエラーを返していると、余計な問題を引き起こす可能性があるからだ(送信元IPアドレスが詐称されていれば、そのIPアドレスに対してエラー・メッセージが送られてしまうため)。
このような場合は、pingの応答は「Packet needs to be fragmented but DF set.」ではなく、単に「Request timed out.(応答がない)」となる。
■この記事と関連性の高い別の記事
Copyright© Digital Advantage Corp. All Rights Reserved.