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

前回はパケットキャプチャでIPヘッダーの表示を行いました。今回は、UDPヘッダーの解析と表示をおこないます。UDPヘッダーは単純な構造のため、UDPヘッダーの解析ができればTCPやICMPでも同様に対応できるはずです。

UDPヘッダーの構造については次の記事を参照してください。

参考記事:TCP/IPヘッダ構造

ヘッダーファイル取り扱いについての注意

各OS向け専用にコードを記述する場合はまったく問題にならないのですが、Mac OS X、BSDとLinuxで共通のコードを記述する場合は対策をしないとUDPヘッダーの構造体定義が異なるためコンパイルエラーになります。幸いにも、LinuxにはBSD形式の構造体が用意されていて「__FAVOR_BSD」を定義することで使用することができるようになります。

具体的にどうするのかというと、以下のようにnetinet/udp.hをincludeする前に__FAVOR_BSDを定義します。

UDPヘッダーのマッピング方法

この方法はTCPやICMPでも同様の方法です。パケットの中でUDPヘッダーの先頭へアクセスするためには、IPヘッダーのサイズを知る必要があります。既にご存じの通り、IPヘッダーは可変長です。そこで、IPヘッダーのip_hlフィールドを使用します。このフィールドはIPヘッダーのサイズを4オクテット単位で表しているため、ip_hlの値を4倍することによってIPヘッダーのサイズを知ることができます。

今回のサンプルコードでは、以下のようにしてUDPヘッダーが格納されているメモリアドレスを計算しています。

このようにip_hlを左へ2ビットシフトした値をポインタipに加算しています。

上位プロトコルの判定

IPヘッダーの上位プロトコルについては、IPヘッダーのip_pフィールドを調べることによって知ることができます。どのような値が定義されているのかについては、ヘッダーファイルのnetinet/in.hを見てください。

サンプルコードでは、以下のようにしてプロトコルによる処理の振り分けをおこなっています(まだUDPしか処理していません)。

UDPヘッダー値を表示する

UDPヘッダーの表示はIPヘッダーと変わりません。バイトオーダーに注意して、各フィールドの値を表示するだけです。サンプルコードでは、以下のようにしています。

サンプルコードのコンパイルと実行

上記のファイルをudp-cap.cという名前で保存しました。コンパイルするには以下のようにします。libpcapとリンクするために”-l pcap”が必要であることに注意してください。

今回のサンプルコードはパケットフィルターを引数で指定できるようにしているので、実行時に「udp and port 53」を引数として渡すことで、DNSパケットのみ受信しています。

まとめ

UDPヘッダーはとても単純なため、UDPヘッダーを表示させられるようになれば、TCPやICMPも簡単に対応できますから、興味のある方は是非UDPヘッダーを自在に表示できるようになってください。

ネットワークプログラミングのオススメ本は、やはりバイブルのこの本で決まりです。