プログラミング

パケットキャプチャツールのつくり方 〜IPヘッダー解析〜

このページはこんな方におすすめです
  • 自分でパケットキャプチャツールを作ってみたい
  • パケットの構造に興味がある
  • ネットワークの知識を深めたい

「パケットキャプチャツールをつくる」と聞くと難しそうな印象を持ってしまうかもしれませんが、そんなことはありません。

はじめは高機能なものは全然必要なくて最初は単純なもので大丈夫です。簡単なものであれば受信したパケットの中身を解析してヘッダーの内容を表示するくらいのものがC言語100行くらいで書けます。

対象とするOS

  • macOS
  • Linux
  • BSD

対象はUnix系OSですが、Windowsでも基本部分は変わらないと思います。なお、C言語の勉強が目的ではないのでC言語についての解説はしません。

パケットキャプチャツールのつくり方

パケット受信処理方法の違い

macOSとBSDは/dev/bpfというデバイスファイルを開いて読むことでパケットを受信することができます。それに対してLinuxはsocket(2)を使います。

パケットの受信は低レベルな処理なので、どうしてもOSによって差異が生じてしまいます。そこでOSの差異を吸収する仕組みとして生み出されたものがlibpcapです。

libpcapは元々tcpdmpのために作られたライブラリです。

libpcapを使う事によりOSに関係なく統一したコードを書くことができるようになります。今回はこのlibpcapを使ってLinuxとmacOS、BSDで動く共通コードを書くことにします。

libpcapが導入されていない場合は別途インストールする必要があります。わたしの手元のCentOSは未導入でしたので以下のようにしてインストールをおこないました。

# yum -y install libpcap-devel

Ubuntu/Debianでは以下のようにインストールします。

$ sudo apt install libpcap-dev

パケットキャプチャの流れ

パケットキャプチャは以下の流れでおこないます。

  1. デバイス(ソケット)を開く
  2. ループでひたすらパケットを受信する
  3. 受信したパケットをIPヘッダーの構造体にマッピングする
  4. IPヘッダーのプロトコルタイプを調べて、TCPならTCPヘッダー、UDPならUDPヘッダーという感じで構造体にマッピングする
  5. 各ヘッダー値を画面に出力する

ポインタが解っていれば問題なく書けると思います。古い本ですが、わたしは「Cプログラミング専門課程」を読んで一発でポインタを理解しました。超オススメの良書です。

Cプログラミング専門課程

Cプログラミング専門課程

藤原 博文
発売日: 1994/12/01
Amazonの情報を掲載しています

パケットを扱うときの注意点

パケットキャプチャのコードを書くにあたって、ひとつだけ注意する点があります。それはバイトオーダーです。バイトーオーダーは「リトルエンディアン」と「ビッグエンディアン」があります。

バイトオーダーはデータをどのような順でメモリに格納するのか、というものです。たとえば0x12345678という4バイトのデータをメモリに格納する場合を想定すると以下のようになります。

ビッグエンディアン ⇒ 12 34 56 78
リトルエンディアン ⇒ 78 56 34 12

このようにビッグエンディアンとリトルエンディアンはメモリへのデータ格納順が逆です。そのためバイトオーダーが異なると同じデータを受信しても値がまったく異なる結果となります。

そのためネットワークの世界では「ネットワークバイトオーダー」でデータを送信するという決まりがあります

ネットワークバイトオーダーに対してローカルのバイトオーダーを「ホストバイトオーダー」といいます。

IPヘッダーやTCPヘッダーなど、2バイト以上の値は必ずバイトオーダーの変換が必要になるので注意してください。

このバイトオーダーの差異を吸収するのがhtons、htonl、htonll、ntohs、ntohl、ntohllです。

ローカルホストのバイトオーダーをネットワークバイトオーダーへ変換するときはhtonXを使い、ネットワークバイトオーダーをローカルホストのバイトオーダーへ変換するときはntohXを使います。

Xの部分は変換するデータのサイズに合わせます。2バイトのデータはshortなので「s」、4バイトのデータはlongなので「l」、8バイトのデータはlong longなので「ll」となります。この後に出てくるサンプルコードを見れば、どういうことか解ると思います。

  • 送信時はネットワークバイトオーダーに変換
  • 受信時はホストバイトオーダーに変換

パケットを受信する方法

デバイスを開く

pcapでデバイスを指定して開くには、以下のようにします。

今回はサンプルとして ICMPパケットのみ受信するようにフィルターの設定をします。ここで設定しているフィルターの文字列は、普段tcpdumpを使用するときに指定するフィルターの文字列と同じです。

ループでひたすらパケットを受信する

libpcapでパケットを受信する方法はいくつかあるのですが、今回は単純なpcap_next()を使用します。

受信したパケットをIPヘッダーの構造体にマッピングする

受信したパケットからIPヘッダーの値へアクセスするには以下のようにしてIPヘッダーの構造体にマッピングします。

各ヘッダー値を画面に出力する

IPヘッダーの構造体にマッピングできたら、あとは値を取得して画面へ表示するだけです。先述したとおりntohXでホストバイトオーダーに変換します。IPヘッダーの場合は基本的に2バイトの値がメインなのでntohsを使うことになると思います。

サンプルコードと実行例

サンプルコード

サンプルコードはGitHubからもダウンロードできます。

コンパイルするには以下のようにします。libpcapとリンクするために”-l pcap”が必要であることに注意してください。

$ cc packet_cape_icmp.c -lpcap

コンパイルは一般ユーザーで構いませんが実行はルート権限でおこないます。手元のmacOSでは以下のようにして実行しました。

コンパイルしたプログラムを実行後、ICMP通信を受信するとIPヘッダーの値を表示します。

まとめ

パケット解析のコツは /usr/include/netinet 以下にあるip.hやtcp.hなどを読むことです。これが読めれば、受信したデータを構造体にマッピングして値を表示するだけです。

ネットワークプログラミングに興味があれば「UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI・ソケットとXTI」を読むことをおすすめします。著者、翻訳者共に世界最高レベルのハッカーが書いた名著です。

UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI

UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI

W.リチャード スティーヴンス
発売日: 1999/07/01
Amazonの情報を掲載しています

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA


日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)