この演習では、プロトコル解析アプリケーションWiresharkを用いて、ネットワーク上を流れるイーサネットフレーム/IPパケット/TCPセグメントのヘッダを観察・解析します。
1.ネットワークの準備
●方法1:二人一組になり、お互いに自分がクライアント役・相手がサーバ役として実験をしましょう。IPアドレスはそれぞれのPCのアドレスに読み替えてください。
●方法2:本記事のサーバを利用した実験も出来ます。その場合、
の代わりに
にアクセスしてください。
また、記事中のサーバアドレス 192.168.0.101 を 163.44.185.205 に読み替えてください。
1-1.用意する機器
PC×2台以上
ハブ(またはスイッチ)×1台
イーサネットケーブル(ストレート)×PC台数分
PCのうち1台には、Wireshark というパケットキャプチャソフトをインストールしておきます。
PCのもう1台には、ApacheなどのWeb Serverをインストールしておきます。
1-2.機器の接続
下図のように機器を接続し、IPアドレスを設定します。

Web ServerをインストールしたPCをServer、WiresharkをインストールしたPCをPC-Aとしています。
1-3.実験用htmlファイルの用意
ServerのWebドキュメントルート直下に、networktest.html という名前でファイルを作成します。
内容は以下の通りです。文字コードは UTF-8 で保存して下さい。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ネットワーク実験</title>
</head>
<body>
<h1>ネットワーク実験</h1>
<p>これは実験用のテストページです</p>
</body>
</html>2.パケットのキャプチャ
2-1.Wiresharkの起動
PC-A上でWiresharkを起動したら、
①表示フィルタの欄に『ip.dst==192.168.0.101 && http』と入力し、Enterを押します。
※意味は『宛先IPアドレスが192.168.0.101であり、かつプロトコルがHTTPの通信』です。
②イーサネットケーブルを接続したインターフェイスをダブルクリックします。

2-2.Webブラウザによるアクセス
PC-A上でWebブラウザを起動し、URL欄に『http://192.168.0.101/networktest.html』と入力します。ブラウザには networktest.html の内容が表示されます。

2-3.キャプチャされたパケットの確認
2-2.でWebブラウザにnetworktest.htmlの内容が表示されると同時に、Wiresharkの画面上部のパケットリストペインに
Source :192.168.0.15 (PC-AのIPアドレス)
Destination :192.168.0.101(ServerのIPアドレス)
Protocol :HTTP
となっているパケットが表示されますので、
①パケットがキャプチャできているのを確認したら、停止ボタン■でキャプチャを停止します。
②パケットリストペインのパケットをクリックします。
③パケット詳細ペインに解析結果が表示されます(今回は解析の練習なのでこの情報は使いません)
④パケットバイトペインにパケットの内容が16進数とASCII文字で表示されています。

④の16進数には、キャプチャしたパケットのデータがバイト単位で並んでいます。今回はこれを解析していきます。
※パケットバイトペインのどこかで右クリックし、ポップアップメニューから『16進数およびASCIIダンプ形式としてバイト列をコピー』または『16進数ダンプ形式として…』を選ぶとダンプリストがクリップボードにコピーされます。これをエディタ等に貼りつけると見やすいでしょう。

3.解析の実例
3-1.16進数ダンプの見方
キャプチャしたパケット(Wiresharkのマニュアルにも『パケット』と書かれていますが、実はプリアンブルを除いたフレーム全体がキャプチャされています)の内容は、以下のようになっています(一番上の行の『+0 +1…』は判りやすいように追加したものです)。
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f
各行は、一番左に4桁の16進数(『0000』『0010』『0020』…)があり、そこから右に向かって2桁の16進数(1バイト分の値)が16個並び、さらに右には文字が並んでいます。
各行先頭の4桁の16進数と最上行の『+0 +1 +2…』は、何バイト目のデータかを判りやすくするためのものです。つまり、たとえば『0030』の行の『+6』の列なら、0x0030+0x6=0x0036=第54バイトです(先頭を第0バイトとして)。
2桁の16進数が並んでいる部分がキャプチャしたデータ本体のバイト列を表していて、
『0000』ではじまる行はデータの第0バイト(0x0000)~第15バイト(0x000f)
『0010』ではじまる行はデータの第16バイト(0x0010)~第31バイト(0x001f)
『0020』ではじまる行はデータの第32バイト(0x0020)~第47バイト(0x002f)
…
となっています。
※ 数値の先頭に”0x”があるのは、その数値が16進数であることを表す
※ 本稿では、データの先頭のバイトを『第0バイト』、ビットは最上位を『第0ビット』として表す
3-2.イーサネットフレームヘッダの解析
キャプチャしたデータの最初の部分は、イーサネットフレームヘッダです。まずはこのイーサネットフレームヘッダを解析しましょう。
イーサネットフレームヘッダのフォーマット(Etnernet II形式)は以下の通りです。

イーサネットフレームヘッダのサイズは 6+6+2 = 12バイト なので、下のキャプチャデータ16進数ダンプの赤字の部分がイーサネットフレームヘッダです。
.png)
比較しやすいように、イーサネットフレームヘッダの図にキャプチャしたデータを並べて書いてみると、下図のようになります。

それでは順に各フィールドの値を見ていきましょう。
宛先MACアドレス
イーサネットフレームヘッダの第0~第5バイト(6バイト)は、宛先MACアドレス を表しています。
この例では、キャプチャした値は 0x00 0x0c 0x29 0x39 0xf6 0xa4 となっています。
ServerのMACアドレスを調べ、ヘッダ中の宛先MACアドレスと一致しているか確認しましょう。
環境によってMACアドレスを表示するためのコマンドや、MACアドレスの表記が異なります。
ServerがWindows系OSの場合
コマンドプロンプトで ipconfig /all を実行します。
MACアドレスは『物理アドレス』として表示されます。下記の例では 00-0C-29-39-F6-A4 です。
C:\> ipconfig /all
Windows IP 構成
(中略)
イーサネット アダプター イーサネット:
接続固有の DNS サフィックス . . . . .: home.example.ne.jp
説明. . . . . . . . . . . . . . . . .: Intel(R) 82579V Gigabit Network Connection
物理アドレス. . . . . . . . . . . . .: 00-0C-29-39-F6-A4
DHCP 有効 . . . . . . . . . . . . . .: はい
自動構成有効. . . . . . . . . . . . .: はい
リンクローカル IPv6 アドレス. . . . .: fe80::b51f:4689:da0d:854c%24(優先)
IPv4 アドレス . . . . . . . . . . . .: 192.168.0.101(優先)
サブネット マスク . . . . . . . . . .: 255.255.255.0
(以下略)ServerがLinux系OSの場合
コマンドシェル(ターミナル等)で ifconfig を実行します。
MACアドレスは『HWaddr』として表示されます。以下の例では 00:0C:29:39:F6:A4 です。
[root@localhost ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:39:F6:A4
inet addr:192.168.0.101 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe39:f6a4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:348 errors:0 dropped:0 overruns:0 frame:0
TX packets:71 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:38847 (37.9 KiB) TX bytes:11365 (11.0 KiB)
(以下略)※環境によって、MACアドレスは
00:0C:29:39:F6:A4
00-0C-29-39-F6-A4
000C.2939.F6A4
など表示形式が異なりますが、16進数部分が同じなら同じアドレスです。もちろん英字の大文字小文字も区別しません。
送信元MACアドレス
イーサネットフレームヘッダの第6~第11バイト(6バイト)は 送信元MACアドレス を表しています。
この例では、値は 0x50 0xe5 0x49 0xef 0x46 0x7a となっています。
PC-AのMACアドレスを調べ、宛先MACアドレスと一致しているか確認しましょう。
PC-AがWindows系OSの場合
C:\> ipconfig /all
Windows IP 構成
(中略)
イーサネット アダプター イーサネット 2:
接続固有の DNS サフィックス . . . . .:
説明. . . . . . . . . . . . . . . . .: Intel(R) 82579V Gigabit Network Connection
物理アドレス. . . . . . . . . . . . .: 50-E5-49-EF-46-7A
DHCP 有効 . . . . . . . . . . . . . .: はい
自動構成有効. . . . . . . . . . . . .: はい
リンクローカル IPv6 アドレス. . . . .: fe80::b51f:4689:da0d:854c%24(優先)
IPv4 アドレス . . . . . . . . . . . .: 192.168.0.15(優先)
サブネット マスク . . . . . . . . . .: 255.255.255.0
(以下略)(PC-AがLinux系OSの場合は省略します)
タイプ
イーサネットフレームヘッダの第12~第13バイト(2バイト)は タイプ (上位層プロトコル)を表しています。
この例では、キャプチャした値は 0x08 0x00 となっています。これは2バイトで1つの値を表しているので、 0x0800 とも表せます。
※これ以降、複数バイトのフィールドについては、一続きの16進数として表します
0x0800 は上位層のプロトコルが IPv4 であることを表しています。
3-2.IPv4ヘッダの解析
イーサネットフレームヘッダの後には、フレームより上位(OSIモデル第3層)のデータ単位のヘッダが続いています。イーサネットフレームヘッダの解析により上位層のプロトコルはIPv4であることが判明していますので、イーサネットフレームヘッダの次の部分はIPv4パケットのヘッダです。
IPv4パケットのヘッダ(IPv4ヘッダ)のフォーマットは以下の通りです。

IPv4ヘッダのサイズは、オプションを除いて20バイトです。イーサネットフレームヘッダの後、第14バイトから20バイト分ですから、下の16進数ダンプの赤字の部分がIPv4ヘッダです。

比較しやすいように、IPv4ヘッダフォーマットの図中にキャプチャしたデータを並べて書くと、以下のようになります。

それでは順に各フィールドの値を見ていきましょう。
バージョン
IPv4ヘッダの第0バイトの上位4ビット(16進数で表した場合の上位桁)は バージョン を表します。
この例では 0x4 で、IPv4 を表しています。
ヘッダ長
IPv4ヘッダの第0バイトの下位4ビット(16進数で表した場合の下位桁)は ヘッダ長 を表します。
この例では 0x5、つまり『5単位』を表します。
1単位は4バイトなので、ヘッダのバイト数は 4×5 = 20 バイト となります。
これはIPv4ヘッダ長の最小値なので、オプション部分がないことが判ります。
サービスタイプ
IPv4ヘッダの第1バイトは サービスタイプ を表しています。ビットごとにいろいろな意味が割り当てられていますが、あまり使われていないようです。
この例では 0x00 です。
パケット長
IPv4ヘッダの第2~第3バイトは パケット長 を表しています。
この例では 0x021b = 539 バイト です。
識別子
IPv4ヘッダの第4~第5バイトは識別子を表しています。経路途中でパケットが分割された場合に使用されます。
この例では 0xbf23 です。
フラグ
IPv4ヘッダの第6バイトの上位3ビットはパケットの分割に関わるフラグです。
各ビットは上位から
| ビット | 名称 | 意味 |
|---|---|---|
| 0 | 常に0(未定義) | |
| 1 | DFビット (Don’t Fragment) | 0:このパケットは分割可 1:このパケットは分割不可 |
| 2 | MFビット (More Fragment) | 0:後続の分割データなし 1:後続の分割データあり |
この例では、第6バイトの上位3ビットを二進数にすると010なので、『このパケットが分割不可』『後続の分割データなし(最後の分割データである)』ことを表しています。
フラグメントオフセット
IPv4ヘッダの第6バイトの下位5ビットと第7バイトの合計13ビットは フラグメントオフセット を表します。フラグメントオフセットとは分割された場合の順序を表す値のことです。
この例では 0x000 です。つまりこれが最初の分割データです。
生存時間(TTL)
IPv4ヘッダの第8バイトは 生存時間(TTL)を表します。生存時間はルート設定ミスなどにより無限にパケットが転送され続けることを防ぐためのものです。最初に送信されるときに初期値をセットされ、ホップ(ルータなど)を経由するたびに1ずつ減算していきます。0になるとそのパケットは破棄されます。
この例では 0x80 = 128 です。これは送信元のOSがWindowsの場合の初期値です。ServerのOSがWindows系だとすると、このパケットがまだ1度もルータを通過していないことになります。
プロトコル
IPv4ヘッダの第9バイトは 上位層のプロトコル を表します。
この例では 0x06 で、これは上位層プロトコルが TCP であることを表しています。
チェックサム
IPv4ヘッダの第10~第11バイトは チェックサム を表します。
この例では 0x0000 です。0x0000はチェックサムの計算値そのものではなく、チェックサムをエラーチェックに使用しないことを意味しています。
送信元IPアドレス
IPv4ヘッダの第12~第15バイトは 送信元IPアドレス を表しています。
この例では 0xc0 0xa8 0x00 0x0f ですが、これを1バイト毎に10進数に直すと 192.168.0.15 となります。
宛先IPアドレス
IPv4ヘッダの第16~第19バイトは 宛先IPアドレス を表しています。
この例では 0xc0 0xa8 0x00 0x65 ですが、これを1バイト毎に10進数に直すと 192.168.0.101 となります。
3-3.TCPヘッダの解析
IPv4ヘッダの解析により、上位プロトコルはTCPであることが判明しています。
TCPセグメントのヘッダ(TCPヘッダ)のフォーマットは下図の通りです。

TCPヘッダのサイズは、オプションを除いて20バイトです。IPv4ヘッダの後、第34バイト目から20バイト分ですから、下の16進数ダンプの囲まれた部分がTCPヘッダです。

比較しやすいように、TCPヘッダフォーマットの図中にキャプチャしたデータを並べて書くと、以下のようになります。

それでは順に各フィールドの値を見ていきましょう。
送信元ポート番号
TCPヘッダの第0~第1バイトは 送信元ポート番号 を表します。
この例では 0xf2ac = 62124番 です。一般的に、クライアント側アプリケーション(この例ではWebブラウザ)のポート番号には、49152~65535 の値が割り当てられます。
宛先ポート番号
TCPヘッダの第2~第3バイトは 宛先ポート番号 を表します。
この例では 0x0050 = 80番 です。TCP の 80番ポート は HTTP(Web) で使用されるポートとしてよく知られています。このように、利用頻度の高いサービスには 0 ~ 1023 のポート番号が固定で割り当てられています。これを ウェルノウンポート と呼びます。
シーケンス番号
TCPヘッダの第4~第7バイトは シーケンス番号 を表します。
この例では 0xc2aa475f = 3265939295 です。
確認応答(ACK)番号
TCPヘッダの第8~第11バイトは 確認応答(ACK)番号 を表します。
この例では 0x199ed730 = 429840176 です。
ヘッダ長
TCPヘッダの第12バイトの上位4ビットは ヘッダ長 を表します。
この例では 0x5 = 5単位です。1単位は4バイトなので、この TCPヘッダ は 4×5=20バイト となります。これはTCPヘッダ長の最小値なので、オプション部分がないことが判ります。
(予約済)
TCPヘッダの第12バイトの下位4ビットと第13バイトの上位2ビット、合計6ビットは拡張用に予約済です。この例では値は二進数で (000000) です。
フラグ
TCPヘッダの第13バイトの下位6ビットは フラグ です。上位から順に、
| ビット | 名称 | 意味 |
|---|---|---|
| 0 | URG(Urgent) | 緊急データが含まれている |
| 1 | ACK(Acknowledgment) | 有効なACK番号が含まれている(最初のハンドシェイク以外はすべて1) |
| 2 | PSH(Push Set) | 受信したデータをすぐにアプリケーションに引き渡す |
| 3 | RST(Reset) | TCP接続を中断・拒否 |
| 4 | SYN(Synchronize) | 接続要求(接続確立以降の通信ではすべて0) |
| 5 | FIN(Finish) | TCP接続終了要求 |
この例では第13バイトが 0x18、その下位6ビットを2進数にすると (011000) なので、ACKとPSHが1、他はすべて0です。
ウィンドウサイズ
TCPヘッダの第14~第15バイトは ウィンドウサイズ を表します。
この例では 0x2014 = 8212 です。
チェックサム
TCPヘッダの第16~第17バイトは チェックサム を表します。計算方法はヘッダも含めたTCPセグメントの2バイト単位の1の補数の総和の1の補数です。
この例では 0x83d2 = 33746 です。計算が大変なので今回は検証しません。
緊急ポインタ
TCPヘッダの第18~第19バイトは 緊急ポインタ です。URGフラグが1の場合のみ使用されます。
この例では0x0000ですが、URGフラグが0だったので使用されていません。
3-4.アプリケーション層データ(参考)
TCPヘッダの後は、TCPペイロード(アプリケーション層のデータ)が続きます。
このパケットで転送されるTCPペイロードのデータサイズは、
IPv4ヘッダのパケット長フィールドの値539バイト
- ( IPv4ヘッダ長20バイト + TCPヘッダ長20バイト ) = 499バイト
となります。
ダンプリストでは、以下の赤字の部分です(長いので0x0060バイト以降は省略しています)。

TCPヘッダの宛先ポート番号から、この通信はHTTPであることが判ります(そもそもフィルタでHTTPの通信だけを表示していたのですが)。HTTPではテキストベースで通信が行われます。
この例では、アプリケーション層データのバイト列をテキスト直すと以下のようになります。なお、16進数で 0x0d 0x0a となっている部分は改行で、下の図では ⏎ で表しています。
GET /networktest.html HTTP/1.1⏎
Host: 192.168.0.101⏎
Connection: keep-alive⏎
Cache-Control: max-age=0⏎
Upgrade-Insecure-Requests: 1⏎
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 Edg/90.0.818.51⏎
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9⏎
Accept-Encoding: gzip, deflate⏎
Accept-Language: ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7⏎
⏎HTTPでは、リクエスト(クライアント→サーバ)でもレスポンス(サーバ→クライアント)でも、テキスト先頭から最初の空行までがヘッダで、それぞれ『HTTPリクエストヘッダ』『HTTPレスポンスヘッダ』といいます。この例では空行がデータの一番最後にあるので、HTTPリクエストヘッダだけの通信ということになります。
HTTPリクエストヘッダの1行目をHTTPリクエスト行といい、クライアントからのリクエストの内容を表します。
書式は、
| メソッド | パス | HTTPバージョン |
です。この例では
メソッドが『GET』
リソースのパスが『/networktest.html』
httpバージョンが『HTTP/1.1』
です。これは
『そちらのWebサーバ上にある /networktest.html の内容を送信して下さい』
という意味です。
2行目以降はリクエストに関する補助的なデータが付加されています。詳しいことはHTTP関係の資料を参照して下さい。
4.レスポンスの解析
4-1.レスポンスパケットを表示する
①表示フィルタを『ip.src==192.168.0.101 && http』と修正してEnterを押します。
※意味は『送信元IPアドレス192.168.0.101であり、かつプロトコルがHTTPの通信』です。
これで、パケットリストペインにWebサーバからのレスポンスパケットが表示されるので、以下同様に解析してみましょう。
フレーム/パケット/セグメントのヘッダを含むデータ戦闘から64バイトを16進数ダンプで表示すると、

となります。
繰り返しになりますので、各ヘッダのフィールドの中で特に重要な物のみ解析します。
4-2.イーサネットフレームヘッダの解析
リクエストのイーサネットフレームヘッダ(3-1.)と比較すると、
リクエストでは
| 送信元MACアドレス | 50-e5-49-ef-46-7a |
| 宛先MACアドレス | 00-0c-29-39-f6-a4 |
となっているのに対して、レスポンスでは
| 送信元MACアドレス | 00-0c-29-39-f6-a4 |
| 宛先MACアドレス | 50-e5-49-ef-46-7a |
と逆になっています。
4-3.IPv4ヘッダの解析
リクエストのIPv4ヘッダ(3-2.)と比較すると、
リクエストでは
| 送信元IPアドレス | c0-a8-00-0f | 192.168.0.15 |
| 宛先IPアドレス | c0-a8-00-65 | 192.168.0.101 |
となっているのに対して、レスポンスでは
| 送信元IPアドレス | c0-a8-00-65 | 192.168.0.101 |
| 宛先IPアドレス | c0-a8-00-0f | 192.168.0.15 |
と逆になっています。
4-4.TCPヘッダの解析
リクエストのTCPヘッダ(3-3.)と比較すると、
・送信元ポート番号および宛先ポート番号が、リクエストでは
| 送信元ポート番号 | 0xf2ac | 62124 |
| 宛先ポート番号 | 0x0050 | 80 |
となっているのに対して、レスポンスでは
| 送信元ポート番号 | 0x0050 | 80 |
| 宛先ポート番号 | 0xf2ac | 62124 |
と逆になっています。
・レスポンスのシーケンス番号は 0x199ed730 で、
リクエストの確認応答番号 0x199ed730 と一致しています。
・レスポンスの確認応答番号は 0xc2aa4952 = 3265939794 で、
リクエストのシーケンス番号 0xc2aa475f = 3265939295 よりも
3265939794 - 3265939295 = 499
だけ大きくなっています。この値 499 は、アプリケーション層データのサイズと一致します。
4-5.アプリケーション層データ(参考)
HTTPでは、レスポンスはテキストデータです。この例のバイト列をテキストデータに直すと以下のようになります。
HTTP/1.1 200 OK⏎
Date: Sat, 01 May 2021 12:40:56 GMT⏎
Server: Apache/2.2.15 (CentOS)⏎
Last-Modified: Sat, 01 May 2021 11:23:29 GMT⏎
ETag: "5f995-ec-5c142f537ff3b"⏎
Accept-Ranges: bytes⏎
Content-Length: 236⏎
Connection: close⏎
Content-Type: text/html; charset=UTF-8⏎
⏎
<!DOCTYPE html>⏎
<html>⏎
<head>⏎
<meta charset="utf-8">⏎
<title>ネットワーク実験</title>⏎
</head>⏎
<body>⏎
<h1>ネットワーク実験</h1>⏎
<p>これは実験用のテストページです</p>⏎
</body>⏎
</html>⏎先頭から最初の空行までをHTTPレスポンスヘッダといいます。
特に1行目はステータス行と呼ばれ、必ず
プロトコルバージョン ステータスコード ステータス文字列
というフォーマットになっています。
この例ではプロトコルバージョンが『HTTP/1.1』、ステータスコードが『200』、ステータス文字列が『OK』で、これはリクエストが成功したことを表しています。
ヘッダの2行目から空行の前までには、コンテンツデータの種類やバイト数、最終更新日などのメタ情報が記述されています。詳細はHTTP関係の資料を参照して下さい。
空行の次の行からデータの最後までがレスポンスの本文で、この例ではリクエストされたnetworktest.html の内容がそのまま送信されていることが判ります。


コメント