はじめに
wiresharkで対応していないプロトコルなんて滅多に無いので、利用シーンは限られるんだろうけど。
wireshark: http://www.wireshark.org/ 言わずと知れたパケット解析ソフトウェア。
- dissector : 解析部分のこと。デコード、パース等言い方は何でもいいよ。
- Lua : スクリプト言語的なの。wiresharkにはLua用APIがあるので連携できるの。
以下レッツ、コーディングなので興味ある人だけどーぞ。
準備
特にコレといって無いですね。
動作環境は Windows XP/Vista/7 と wireshark 1.6/1.8 辺りを想定してます。くらいかな。
Luaスクリプト動作のための設定
Wireshark 1.6以降では、今のところLuaサポートはデフォルトで有効なので、そこは割愛。
任意で作成したLuaスクリプトをwiresharkに読み込ませる方法はいくつかあるけど、代表的なのはこういうの。
Windowsの場合
- .luaファイルを
%WIRESHARK%/plugins/<version>
か%APPDATA%/Wireshark/plugins
に置く。
Windowsの場合は、WireSharkのバージョンアップ過程でwiresharkを一旦アンインストールしたりすると消えちゃったりするので、ちょっと面倒です。
Unix/Linuxの場合
- Commentout the
disable_lua=true
in/etc/wireshark/init.lua
(Windowsの場合はこれデフォルトで有効だと思う) - .luaファイルを
/usr/share/wireshark/plugins
か/usr/local/share/wireshark/plugins
か$HOME/.wireshark/plugins
に置く。
デコード対象のプロトコル
ここはひとつ現実に存在するwiresharkでは対応していないプロトコルの方が達成感があるかなー、と思うので、FreeBSDのpingコマンドを対象にしてみる。
一般に、wiresharkでpingをキャプチャした時のデコード結果は、次の図のようになると思うわけだ。
ただ、FreeBSDのpingはペイロードにテストデータだけでなく、先頭8byteにタイムスタンプが埋め込まれている。
これをこんな感じで出力出来るようにしてみる。
コードを書く
本来であれば、プロトコルの理解から入るべきなのだが、wiresharkでデコードするプロトコルを拡張したいとか言ってる人に、
「ICMP Echo requestのペイロード先頭4byteが[sec]、その次の4byteに[usec]が入ってる」
と説明するのに、図も何も要らないんじゃないかと思うんだ。
という訳で fbsdping.lua
というファイルを作って、コードを書く。
ちなみに、windowsの場合、このスクリプトの文字コードをUTF-8にすると1行目からエラーが出るので、日本語のコメントなんぞ書こうものならShift-JISにせざるを得ないという苦痛を味わうことを付け加えておく。
|
|
中途半端に説明する
- ProtoオブジェクトとProtoFieldオブジェクトを作る。
- ProtoFieldをProtoオブジェクトに紐付ける
- 必要なデータを拾ってくる。
- Wiresharkから貰えるdissectorメソッドの引数であるところのtreeにaddしていく。
- その関数をフックするように最後に登録する。
というのがおおよその流れ。
Proto, ProtoFieldオブジェクトを作る。
第1引数がフィルタ名、第2引数が説明文という理解。
|
|
第1引数がフィルタ名、第2引数が説明文という理解。
|
|
- Proto : http://www.wireshark.org/docs/wsug_html_chunked/lua_module_Proto.html#lua_class_Proto
- ProtoField : http://www.wireshark.org/docs/wsug_html_chunked/lua_module_Proto.html#lua_class_ProtoField
ProtoFieldをProtoに関連付け
え、こんだけですけど…。
|
|
必要なデータを拾ってくる。
デコード前のデータbufferに入っている(bufferというのはこちらが勝手に決めた名前だが)。
実際に値を取得する時は、範囲を指定し、型を決めて使う。
|
|
これは、利用するときの形態によって変わってくるので一概には言えないものの、tostring()で囲って文字列にしてもいい。
こう書いてもいいのだけど、Fieldを選択した時にHexの該当部分がカラーリングされて欲しいので、分けて書いたほうが何かと便利だろう。
|
|
既にデコード済みデータを拾う場合は、フィルタで引っ掛けた場所のオブジェクトが貰えるので、valueで値にアクセス。
|
|
value以外にも、いくつかパラメータがあるよ。
ツリーに追加
プロトコルを追加する時は、第3引数のtreeにProtoオブジェクトを直接addする。
|
|
フィールドを追加する時は、Protoオブジェクトを追加した時に突っ込んだ方にaddする。
|
|
ちなみに、bit表現のツリー追加について端折り気味に書くと、
元々のバイト表現
|
|
True/Falseでフィルタ出来るように、値と文字の関連付け
|
|
ProtoFieldの登録。1Byteの場合は、uint8を選択。16進数表現を使うか、表示フォーマットの指定、どのbitを指すのかを指定する。
|
|
flag自体はバイトで拾って、そのまま渡す。
flag_F_B = ProtoField.uint8
の部分で base.HEX, VALS_BOOL, 0x80
を指定してるので、勝手に解釈してくれる。
|
|
次のプロトコルが決まってる時
以降のプロトコルデコードをwiresharkにお返しする事ができる。今回はdata。
|
|
Dissector.get
すると、指定した解析用処理ブロックを拾ってこれるので、自分でcallデータ位置をずらして呼び出す。
こんな感じで無理矢理次のデコード方式を決めることも出来るので、スーパー意味分かんないカプセル化を解除することも出来るよ。
|
|
フック関数の登録
全部のデコードが終わった後に指定した関数が走るように登録。
|
|
この場合、取得できるバッファは先頭0byte目から全てなので、必要な部分を読み込めるようにポインタ移動処理が待っている。
今回は、こんな風にずらした。
|
|
一般的には、ポート番号を引っ掛けて登録することの方が多いと思う。
その場合は、公式サンプルのように DissectorTable.get
して add
します。
http://wiki.wireshark.org/Lua/Dissectors
この場合は、取得できるバッファは下位プロトコルから渡されたデータグラムになるので、ポインタ移動は不要である。