pcapをパースする(その3・IP/ICMP編)
これまで以下の記事でEthernetフレームやARPのパケットをpcapファイルからパースするために必要なフォーマットについて解説していきました.
pcapをパースする(その2・ARP編) - ポン酢ブログ(β)
pcapをパースする(その1・ヘッダ編) - ポン酢ブログ(β)
引き続き,IPやICMPをパースしてみたいと思います.
IPパケット
IPパケットはRFC 791で策定されています.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
今回のパースは,Golangの準標準パッケージであるnetを使ってみる練習がてら,パースをそれに任せてみました.
実際にパースをする場合は,Parseを呼び,そこに[]byteでパケットを入れてあげれば大丈夫です.
気づきとしては,socket.NativeEndianには動作するOSのbinary.ByteOrderが入っており,それを使って処理していました.
実装はこちらになっていて,パースしたあとにその後ろの[]byteを返すようになっています.
ICMPパケット
IPパケットまでパースできたので,関連するICMPパケットについてもパースしていきたいと思います.ICMPはRFC 792で策定されています.普段pingコマンド等で馴染みのある人もいるのではないでしょうか.
ICMPのメッセージには多くの種類があり,こちらが参考になります.
今回のパースも,Golangの準標準パッケージであるnetを使ってみる練習がてら,パースをそれに任せてみました.実際にパースと言っても,structに値をマッピングしていく形になります.パッケージでの実装を参考にしながら使っていきますが,internalでメッセージのタイプが隠れていたため,仕方なく同じものを自分て定義しそれを使っています.
実際の実装部分です.
自作のものとつなげていく
自作しているpcapのパーサーでは,Packetインターフェースを作り,それを満たすように各データを格納しています.そして,実際にに読み込んでいる部分はこちらになります.
実際にファイルを読み込ませてみると,パースできていることがわかります.

実はこの他にも追加した機能があるのですが,それはまた別の機会に説明します.