2009年04月18日

Wiresharkプラグインを作る上でのハマったこと

まだ拡張の余地はあるが、それっぽく動くWiresharkプラグインができた。
だいぶ前にできてはいたが、他の人にも有益と思われる情報をまとめる時間ができたので書いておこう。

かなり汎用的に設計したつもりだが、業務で使っている特殊なプロトコルの仕様のせいで、
一部どうしても汎用的な作りにできなかったので、今回はオープンソース化は見送った。
オープンソース化のメリットはいろいろあるが、それを語るのはまた別の機会に。
また、私が考えたコンセプトは、Wiresharkの他のプロトコル解析プラグインとはちょっと設計思想が異なるので、
文化的にも受け入れられるか疑問が残るし、何をどうやればできるかTrial&Error的に作ったので、
設計も美しくないと言うのも見送った理由。

今回作ったプラグインの解析対象となるプロトコルはクローズドなネットワークだけで使われる特殊なもの。
仕様も度々変わるので、その度にWiresharkプラグインをビルドし直すのもだるいし、
誰もがWiresharkの作りに精通しているわけでもない。

と言うわけで、基本的なコンセプトは、"XML definedable multi-protocol dissector plugin"と言う感じ。
XMLにプロトコルの仕様を書き、Wiresharkプラグイン側でこれを解析してXMLの内容により動作を変えるというもの。
XMLの解析にはlibxml2を使った。Windows用バイナリはこのへんからゲットしてくる。

"dissector"はあまり聞きなれない言葉だが、解剖する人と言う意味。
プロトコルを分析するところからWiresharkプロジェクトではdissectorと呼んでいるのだろう。

Developer's Guide9.2. Adding a basic dissectorに従えば、最も基本的なUDPの1つ上のレイヤのプロトコル解析プラグインはすぐに作ることができる。

しかし、ちょっとまともな作りにしようと思ったら、Developer's Guideには記載がなく、日本語でも英語でもインターネット上にはあまり情報源がないため、既存のdissectorのソースコードを読まないといけない。


1. Wiresharkのリリースに含まれているプラグインをビルドして、それをバイナリリリースされているプラグインディレクトリにコピーしてもエラーダイアログが出て正しく読み込まれない。
これはどういうことか。
Help->about Wiresharkを見ると、バイナリリリースのものは、VC++6.0でビルドされているようだ。
VC++2005EE+PSDKでビルドする場合には何か注意点があるのか?
Windows XPだとエラーダイアログ内にメッセージが出ないので、何が問題かよくわからない。
Windows Vistaで実行すると、msvcr80.dllがないというメッセージが出ていた。
なるほど。CRTをダイナミックリンクにしているのが原因か。
MSVCR80.dllに依存しないようにするを参考にして対処する。

Makefile.namke内のCFLAGSにテキストエディタで直接/MTオプションを書き入れる。
「/MDより/MTが優先されます」というようなWarningがでるが気にすることはない。
それにしても、CRTをスタティックリンクしただけで、22kbyte程度だったdllが、100kbyteを超えたのには驚いた。


2. リリースビルドはどうやるのか
VC++の構成で、Releaseを選択してもなぜかデバッグ情報を吐き出しているようだ。
かといって、Makefile.nmakeの中にデバッグ用とリリース用のターゲットが書かれているわけではなさそうだ。
ふとしたことからスタートメニューにあるPSDKの配下に、Windows XPとか、2000とか、32bit/64bit、Debug/Retail用のコンパイル環境変数を設定したシェルを開くショートカットが用意されていることに気づいた。
なるほど、PSDKの環境変数を変えることで切り替えるのが流儀なのか。
と言うことで、VC++を使ってビルドする場合は、プロジェクトのプロパティページの構成プロパティ->NMakeで、ビルドコマンドラインに渡している

"c:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\SetEnv.Cmd"
と言う文字列を
"c:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\SetEnv.Cmd" /XP32 /RETAIL
などのように変更すればいいということだ。
私の環境では、SetEnv.Cmd内のデフォルトで、/XP32、/DEBUGが指定されたのと同じ動作をするようになっていた。


3. 未知の上位プロトコルに対して、dataという表示をツリーペインに表示させるには
handoff内で、find_dissector("data")を呼んで戻り値のhandleを保存しておき、自分のプロトコルのdisssectを行った後、まだ残りの解析していないパケットデータがあれば、call_dissectorにこのhandleを渡せばよい。
この辺は、epan/dissector/packet-udp.cを読むとわかると思う。


4. 自分で追加したプロトコルのさらに上位のプロトコルを解析するにはどうすればいいか。
たとえば、ether headerのether typeを見て、0x0800だったら、次は、IPのdissectorを呼び、
ip headerのprotocolを見て17だったら、次は、UDPのdissectorを呼び、と言うことを、自前のプロトコルの解析でやるにはどうすればいいかということ。
epan/dissector/packet-eth.c、epan/dissector/packet-ip.c、epan/dissector/packet-udp.cをよく読めばわかるが、ちょっと面倒。
ether typeから上位プロトコルを判別する仕組みは、epan/dissector/packet-ethtype.cにハードコーディングされている。
ipヘッダのプロトコルの解析の仕方は、もっとごちゃごちゃしている。
XMLに定義されたプロトコル仕様からその動作を決めるという要求を満たすには、UDPヘッダやTCPヘッダのポート番号から、上位プロトコルを解析するルーチンへジャンプする仕組みと同様な方法がよい。
例えば、plugins/agentx/packet-agentx.cを見ればわかるが、create_dissector_handleでハンドルを取得し、dissector_add("tcp.port", agentx_tcp_port, agentx_handle)と言う具合に文字列(Wiresharkでは、abbrevと呼んでいて、表示されたパケットをフィルタする時に使う文字列と同じもの)を指定することで上位プロトコルのdissectorを追加したい。
これをやるには、まず、"udp.port"や"tcp.port"という文字列を、abbrevとして登録する必要があり、これをやるには、register_dissector_tableを呼ぶ。
パケットを解析した後、register_dissector_tableの戻り値と共に、dissector_try_portを呼び出せば後は勝手にdissector_addしたdissectorを検索して呼び出してくれる。
この仕組みを使えば、たとえばIPv6のnext headerのように、プロトコル中の特定のデータの値によって、次に来るデータを解析するための型を動的に変えることが可能になる。


5. フラグメントされたパケットをどう扱うか
実は、フラグメント機能は、私はまだ全容を把握していない(ので、実装もできていない)。
基本的な知識は、9.4. How to reassemble split packetsを読む。
UDPやTCPの(というか、実際にはIPフラグメント)フラグメントに対応するには、この手順どおりにやれあばうまくいくだろう。
しかし、独自のプロトコルがフラグメントをサポートする場合はどうすればいいだろうか。
pinfo->fragmented、fragment_add_seq_check、process_reassembled_dataあたりがキーになるようだが、もう少し調査が必要だ。


6. プロトコルの型をXMLに定義する際に、同じ型の繰り返し表現をべたに書いていたのでは大変なので、配列表現に対応した。他のwiresharkプラグインでは特定のプロトコルのみを解析すればいいので、配列のサイズや次元は固定的に扱って(ハードコーディングして)いるようだが、私が作ったプラグインではそうはいかないので、XMLに定義を書けるようにした。多次元配列で、それぞれの次元の配列サイズもXML読み込み時に決定されるが、これをプログラム上でどう扱うかについては、多少工夫が必要だった。基本アイデアは、配列のdimension分のサイズを持つg_arrayの要素に配列のサイズを突っ込んでおいて、後でこれを順次とりだして再帰的に処理を行うということをやっている。XMLの定義を信用して再帰的に処理しているので、セキュリティ的には問題があるが、世間で広く使われるものでもないので、汎用性と実装のしやすさを優先させた。


7. まだ実現できていない機能に可変長対応がある。汎化すると、プロトコル中のある特定のデータ数分、何かのパターンが繰り返されるというデータ解析ロジックをどうやってXMLに定義し、どうやってそれを実装するか。最近、別件で忙しいのであまりWiresharkプラグインには取り組めていない。


他にも、hfとかettとかハマリポイントはあるのだが、それはまた別の機会に。dissector_try_heuristicも何ができるのか気になる。。。
posted by mign0n at 07:35| Comment(0) | TrackBack(0) | ソフトウェア | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/117692243
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。