.pcapファイルについてちょっと調べた

パケットキャプチャではおなじみのpcapファイルについて、調べたのでまとめます。

動機

研究室で取り扱っているpcapファイルを管理するためにpcapパーサーを作ろうと思った。
そのためにpcapファイルの構造を調べたが、知りたい情報のある日本語の解説が見つからなかったので調べてまとめた。

pcapファイルの構造

HTTPパケットの入力の概要
上記ページはHitachiのuCosminexus Stream Data Platform - Application Framework システム構築・運用ガイドである。pcapファイルの構造についてはこちらに書かれてたので参考になった。
図を見た方が早いが、

  • Pcapファイル自体のファイルヘッダ(24バイト)
  • キャプチャしたパケット
    • キャプチャしたパケットのヘッダ(16バイト)
    • キャプチャしたパケットのデータ(可変長)

という構造になっているようだ。

Pcapファイル自体のファイルヘッダの構造

Development/LibpcapFileFormat - The Wireshark Wiki
上記のページによると、Pcapファイルのヘッダは下記のようになっているとのこと。

typedef struct pcap_hdr_s {
        guint32 magic_number;   /* magic number */
        guint16 version_major;  /* major version number */
        guint16 version_minor;  /* minor version number */
        gint32  thiszone;       /* GMT to local correction */
        guint32 sigfigs;        /* accuracy of timestamps */
        guint32 snaplen;        /* max length of captured packets, in octets */
        guint32 network;        /* data link type */
} pcap_hdr_t;

それぞれについての説明を見ていくと、

magic_number

ファイルの種類を識別する際に用いる。4バイト。

version_major

ファイルフォーマットのメジャーバージョン(ver:x.yのxの方)。2バイト。

version_minor

ファイルフォーマットのマイナーバージョン(ver:x.yのyの方)。2バイト。

thiszone

パケットヘッダのタイムゾーンGMTとどれだけずれているかの値。一時間のずれは3600になる。4バイト。

sigfigs

キャプチャしたパケットのタイムゾーンの精度?らしい。基本的に値は0になるとのこと。4バイト。

snaplen

"snapshot length"の略で、パケットのキャプチャサイズを制限するために用いるもの?らしい。通常は65535もしくはそれ以上とのこと。4バイト。

network

リンク層の種類。
www.tcpdump.org
上記のサイトに書かれている数値が入るらしい。Ethernetの場合、値は1になる。4バイト。

パケットのヘッダの構造

同じページを参照した。下記のような構造になっているとのこと。

typedef struct pcaprec_hdr_s {
        guint32 ts_sec; / *タイムスタンプ秒* /
        guint32 ts_usec; / *タイムスタンプマイクロ秒* /
        guint32 incl_len; / *ファイルに保存されたパケットのオクテット数* /
        guint32 orig_len; / *パケットの実際の長さ* /
} pcaprec_hdr_t;
ts_sec

パケットがキャプチャされた日時のUNIX時間。GMTに基づいたタイムスタンプではない場合にthiszoneを用いて調整する模様。4バイト。

ts_usec

パケットがキャプチャされた時間のマイクロ秒にあたる部分。4バイト。

incl_len

キャプチャした際に、実際に「保存された」パケットデータのバイト数

orig_len

キャプチャした際に、実際に「観測された」パケットデータのバイト数

パケットのデータの構造

incl_lenの長さで実際のパケットがそのまま現れる。

構造を確認してみる

SampleCaptures - The Wireshark Wiki
上記Wiresharkwikiから"http.pcap"をダウンロードし、Wiresharkバイナリエディタで開いて確認してみた。

f:id:sorenuts:20180607162829p:plain
WireShark上での表示

f:id:sorenuts:20180607162838p:plain
バイナリエディタ上での表示

pcap_hdr_s

magic_number

値は、
0xA1B2C3D4

D4 C3 B2 A1でググると、
File Signature Database:: D4C3B2A1 File Signatures
からwinpcapのキャプチャファイルだとわかります。

version_major,version_minor

それぞれ、
0x0002
0x0004
となっているので、バージョンは2.4だとわかる。
上記に挙げたWiresharkのページでも
"the commonly used format in its current version 2.4. This format version hasn't changed for quite a while (at least since libpcap 0.4 in 1998),"
と書いてあり、1998年からずっとバージョンは2.4の模様。

thiszone

0x0

sigfigs

0x0

snaplen

0xFFFF
10進数に直すと65535なので、通常の値だとわかる。

network

0x0001
Ethernetを示している模様

pcaprec_hdr_t

ts_sec

0x40A34B23
10進数に直すと1084443427である。下記のサイトでUnix時間からJSTに変換したところ、西暦2004年 3月 13日 19時 17分 7秒だとわかる。

f:id:sorenuts:20180607194351p:plain
Wireshark上での時刻の表示
UNIXタイムスタンプ変換ツール
Wiresharkで表示されている時刻と一致していることがわかる。

ts_usec

0x0004BFB8
10進数に直すと311224である。マイクロ秒と一致していることがわかる。

incl_len,orig_len

両方とも0x3Eで、10進数に直すと62
以降の62バイトとWiresharkで表示されているパケット本体が一致していることが確認できた。

結果

pcapの構造はpcap自体の情報を格納するヘッダ(Wiresharkwikiでは"global header"と記載されていた)、個々のパケットの情報を格納するヘッダ("Record(Packet) Header")、パケット本体("Packet Data")から成り立っているとわかった。