パケットキャプチャのフォーマットである
旧式Pacpと新式PcapNGのフォーマットを
自分の目で調査したのでまとめます。
ちなみに NG は "Next Generation" です。
パケットキャプチャをする際にツールとして、
Wiresharkやtcpdump(WinDump)などを
使う方が多いかと思います。
これらはlibpcapやWinPcap(Npcap)などの
APIから出来ており、Cで実装されています。
libpcapなどを知るにはまずは、
パケットキャプチャ用のファイルフォーマットである
PcapとPcapNGについて理解する必要があります。
この記事の前半部分に Pcapのフォーマット
この記事の後半部分にPcapNGのフォーマット
という構成になっています。
それではまずはPcapからです。
Pcapのフォーマット
Pcapは主に3つで構成されています。
- PCAP Header (24bytes)
- Packet Header (16bytes)
- Raw Packet (Any bytes)
この3つの構造はこのようになっています。

最初にPCAPヘッダーがあって、
それ以降はパケットヘッダーと
実際にのキャプチャデータがそれぞれ
1セットとなって繰り返されます。
PCAPヘッダーとパケットヘッダーは
格納されている情報が異なり、
それぞれ24バイトと16バイトの情報が入ります。
次にそれらを見てみましょう。

まずはPACPヘッダーからです。
細かい内容は次のようになっています。
PCAPヘッダー
pcap.hの中身を覗いてみると、
以下のように定義されています。
(構造体のところだけ抜粋)
1 2 3 4 5 6 7 8 9 |
struct pcap_file_header{ bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; /* gmt to local correction */ bpf_u_int32 sigfigs; /* accuracy of timestamps */ bpf_u_int32 snaplen; /* max length saved portion of each pkt*/ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ }; |
tcpdump magic : 4バイト
ファイルの一番最初に来るものです。
ネットワークにおいてmagicというと、
何かの識別子を意味します。
以下の値が入ります。
ホストマシンのアーキテクチャによって違います。
"A1 B2 C3 D4" (ビッグエンディアンの場合)
"D4 C3 B2 A1" (リトルエンディアンの場合)
ファイルの先頭にこの値が来ることで
「これはPCAPファイルだ!」
ということが分かります。
余談:
magic で他に有名なものにDHCPがあります。
DHCPとBOOTPのフォーマットは、
ほとんど同じなのでmagicによって見分けます。
"63 82 53 63"がパケット中に入ります。
なおDHCPはネットワークエンディアンなので、
実際はビッグエンディアンです。
major version : 2バイト
フォーマットバージョンが入ります。
一般的に言うバージョン○.△の
○の部分がmajor versionに該当します。
minor verion : 2バイト
フォーマットバージョン○.△の
△の部分が入ります。
time zone : 4バイト
基本的には0x00000000が入ります。
sigfigs : 4バイト
タイムスタンプの精度を示します。
基本的には0x00000000が入ります。
snaplen : 4バイト
キャプチャ可能なパケット最大長です。
基本的には0x0000FFFFが入ります。
link type : 4バイト
データリンク層のタイプです。
Ethernetの場合は0x00000001です。
Wi-Fiで使われるIEEE802.11の場合は、
105つまり0x01111001が入ります。
続いてはPacketヘッダーを見てみましょう。
Packetヘッダー
pcap.hの中身を覗いてみると、
以下のように定義されています。
(構造体のところだけ抜粋)
1 2 3 4 5 |
struct pcap_pkthdr{ struct timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ }; |
補足ですがタイムスタンプのところは、
timeval構造体だと上手く動作しないとか。
bpf_u_int32 ts_sec;
bpf_u_int32 ts_usec;
としっかり分けた方がよいとか。
さて、話しを戻しまして・・・
time stamp : 8バイト
8バイトを4バイトづつに分けます。
前4バイトはUNIX時刻形式の値です。
1970年1月1日0時0分0秒から
経過した秒数が入ります。
後ろ4バイトはμ秒を表します。
caplen : 4バイト
ファイルに記録されているパケット長です。
len : 4バイト
実際のパケット長です。
caplenと同じ値が入ることが多いですが、
PCAPヘッダーにある最大長を示す
snaplenよりもキャプチャしたパケットが
大きいと、分割されるので、
上記の2つは違う値を示すことになります。
以上が従来のフォーマットであるPCAPでした。
続いては新しい方のPcapNGフォーマットです。
PcapNGのフォーマット
PCAPよりも機能的になったのがPcapNGです。
キャプチャしたインターフェースの情報など
キャプチャデータ以外にも埋めることが
出来るようになりました。
PCAPは、PCAP Header、Packet Header、
Raw Packet の3種類から構成されていました。
一方、PcapNGでは呼び名が変わり、
"セクション"という単位で構成されています。
.pcapngのファイルを構成するセクションは
1つだけの場合もあれば、複数の場合もあります。
セクションは "ブロック" という単位で
構成されており、各セクションの先頭には、
SHBと呼ばれるセクションヘッダーがいます。
セクションヘッダーの下には、
データに該当する各ブロックが付きます。
1 2 3 4 5 |
|-- 1st Section --|-- 2nd Section --|-- 3rd Section --| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SHB | Data | SHB | Data | SHB | Data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
ブロックにはセクションヘッダー含め、
6種類あり、それぞれ名前が付いています。
- SHB : Section Header Block
- IDB : Interface Description Block
- EPB : Enhanced Packet Block
- SPB : Simple Packet Block
- NRB : Name Resolution Block
- ISB : Interface Statistics Block
PacpNGはこれらのブロックを
組み合わせて一つのファイルにします。
これらのブロックはそれぞれ、
フォーマットが決まっており、
どういう情報を格納する定義されています。
上から3つだけ覚えておけば、
個人的に大丈夫だと思います。
PcapNGは以下のように定義される
ブロック階層にそって構成されます。
1 2 3 4 5 6 7 8 |
Section Header | +- Interface Description | +- Enhanced Packet | +- Simple Packet | +- Interface Statistics | +- Name Resolution |
最初の2つの SHB と IDB は、
1ファイルに最低1つずつ必要で、
SHBはファイルの先頭に必ず来ます。
お察しの通りSHBはmagicを含みます。
それ以外のEPB、SPB、NRB、ISBの4つは
オプションとなっています。
それでは各ブロックについて見てみましょう。
SHB : Section Header Block
フォーマットは次のようになっています。

Block Type :
PcapNGを識別するmagicが入ります。
"0A 0D 0D 0A" によってこのファイルが
PcapNGであることが分かります。
それと同時にこのブロックは、
SHBですよ、ということも意味しています。
このBlock Typeはブロックごとに
決まった値が割り振られており、
それによってどの種のブロックか見分けれます。
ちなみにSHBの magic はシンメトリなので、
リトルもビッグエンディアンも関係なしです。
Block Total Length :
このブロックのサイズが入ります。
SHBの最後にも再び、
Block Total Lengthを詰めます。
Byte-Order Magic :
"1A 2B 3C 4D" が入ります。
リトルエンディアンかビッグエンディアンか
判断するための magic になります。
major version :
Pcapのフォーマットに同じです。
minor version :
Pcapのフォーマットに同じです。
Section Length :
SHBを含めたセクションサイズが入ります。
もしセクションサイズが、
0xFFFFFFFF だった場合は、
セクションサイズ不明記を意味します。
Option :
SHBだけではなく全てのブロックは、
オプションフィールドをもっています。
キャプチャしたパケットを読むのに、
役立つ情報を挿入するためにありますが、
あくまでオプションなので必須ではないです。
全てのブロックに共通して、
オプションフィールド専用の
フォーマットが定義されています。
しかし、もちろん格納する情報は、
ブロックごとで異なります。
記事の最後にオプションフィールドに関する
フォーマットと具体例を記載しました。
PcapNGファイルからSHBだけを抜き取ると、
こんな感じになりました。
Wiresharkでキャプチャしたパケットを
バイナリエディタで開いた画像です。

最初にPcapNGのmagicが来て、
次にブロックサイズの0x000000B4、
そしてByte-order magicを示す
4D 3C 2B 1Aが来ています。
(リトルエンディアンです。)
次は、IDBです。
IDB : Interface Description Block
キャプチャを行ったインタフェースの情報を
格納するためのブロックでPcapNGファイルを
作成するのに必須となっています。
フォーマットは次のようになっています。

Block Type :
IDBは0x00000001が入ります。
Block Total Length :
このブロック(IDB)の全体サイズを入れます。
Link Type :
Pcap同様にキャプチャしたパケットの
データリンク層を示す値が入ります。
例えば、Ethernetなら 1 が、
IEEE802.11なら 105 が入ります。
Reserved :
将来使われる予定で現在は使われていません。
snapLen :
キャプチャ可能な最大バイト数が入ります。
このサイズより大きいパケットは、
別のファイルに分けて保存します。
Option :
省略。
次はEPBです。
EPB : Enhanced Packet Block
キャプチャパケットを保存するために
一番よく使われるブロックです。
フォーマットは次のようになっています。

Block Type :
EHBと認識するために、
このフィールドには 0x00000006 が入ります。
Block Total Length :
SHBに同じです。
Interface ID :
パケットが来たインターフェースを明記します。
もし正しいパケットキャプチャファイルであるならば、
IDBのインターフェースと同じ値が入ります。
Time Stamp (Hign and Low) :
PcapのTime Stampと同じで、
Unix時刻形式に基づいて格納されます。
Captured Len :
Pcapのcaplenに同じです。
Packet Len :
Pcapのlenに同じです。
Packet Data :
パケットキャプチャした生データが入ります。
Option :
省略。
次はSPBです。
SPB : Simple Packet Block
EPBと似ていますが名前から分かる通り、
最小限の情報しか保存しないブロックです。
ここでいう最小限とは、
キャプチャしたデータのことではなく、
EPBにあるインターフェースIDなどの
余分な?情報のことを言います。
フォーマットを見ていただくと分かるのですが、
インターフェースIDがない分、
このブロックからはどのインターフェース(L2層)で
キャプチャしたか分かりません。
したがって、IDB の Link Type で
記されたインターフェースと仮定して
パケットをフォーマット化します。
タイムスタンプもない点も注意です。
感覚的なイメージで言うと、
TCPのEPBに対し、UDPのSPBでしょうか。
フォーマットは次のようになっています。

Block Type :
SPBと認識するために0x0000003が入ります。
あとのフィールドはEPBと同じ意味を持ちます。
EPBと違ってオプションフィールドは持ちません。
次はNRBです。
NRB : Name Resolution Block
NRBはホスト名とアドレスの対応関係を入れます。
基本的にパケットにはアドレスは含まれているが、
ホスト名が含まれておらずDNSによって取得します。
もしPcapNGファイルに、アドレスしか
入っていなかった場合を想定すると、
キャプチャファイルを読んだ人は
ホスト名がないために、
少し不便に思うかもしれません。
そこでをPcapNGファイルを構築する際に、
DNSによって名前を取得し、わざわざ
キャプチャファイルを読む際に、ユーザが
自らDNSしなくても済む仕組みになっています。
つまり時間節約のメリットが得られます。
フォーマットは次のようになっています。

Block Type :
NRBと認識するために、0x00000004が入ります。
その他のフィールドでDNSエントリーにある
アドレスと名前の情報を含めることが出来ます。
また名前解決をしたDNSサーバのIPアドレスも
含めることが出来ます。
最後はISBです。
ISB : Interface Statistics Block
IDBによって記されたインターフェースに関して、
インターフェースのより詳細な情報をセットします。
フォーマットは次のようになっています。

Block Type :
ISBと認識するために0x00000005が入ります。
Block Total LengthやInterface ID、
Time Stampは他のブロックで説明した通りです。
これだけではこのブロックの特徴が分からないので、
このブロックだけはオプションについて触れます。
SHBで述べた通り、オプションフィールドにも
オプションフォーマットがあります。

どのブロックも上記の
オプションフォーマットに従って、
オプションフィールドが埋められます。
ISBのオプションに関しては、
以下の情報が入ります。
Name | Code | Length | Description | |||
---|---|---|---|---|---|---|
isb_starttime | 2 | 8 | キャプチャ開始時刻。 | |||
isb_endtime | 3 | 8 | キャプチャ終了時刻。 | |||
isb_ifrecv | 4 | 8 | インターフェースが受信したパケット数。 | |||
isb_ifdrop | 5 | 8 | 物理資源の不足によって、インターフェースが捨てたパケット数。 | |||
isb_filteraccept | 6 | 8 | フィルターを通過したパケット数。 | |||
isb_osdrop | 7 | 8 | OSが捨てたパケット数。 | |||
isb_usrdeliv | 8 | 8 | ユーザが配送したパケット数。キャプチャ終了時点では、OSバッファにまだパケットが残っている可能性がある |
以上がPcapとPcapNGのフォーマットの違いです。
最後まで読んでいただきありがとうございました。
参考:PcapNG :https://pcapng.com/