読者です 読者をやめる 読者になる 読者になる

行列屋さんの作業ログ

行列まわりで色々やってたエンジニアの作業メモ&国内外旅行記ブログ

パケットデータ(pcap)をRで読み込む話

R プログラミング

tcpdumpで取得したパケットのキャプチャデータをRに読み込ませる話。

遊びでパケットキャプチャしてみたけど結果が見難い。じゃあいつも使ってるRで読ませてみましょうと考えた。wiresharkや、そのCUI版であるTsharkを使えばキャプチャデータをcsvに変換出来て楽だけど、Rだけでなんとかしてみる。データ読み込みのお勉強。

つかうキャプチャデータは,tcpdumpで得られたもの.tcpdumpに何のオプションを付けるかによって得られるデータが変わるけど,今回はIPアドレスの名前解決や,パケットの中身の取得は行わず,純粋にプロトコルやIP,ポート番号だけを記録したものを使う...というか,今回扱いたいデータがそうして取得されたものだった.

Rで読み込ませる前に,catでデータの中身を表示させてみた....が文字化け.文字コードを変更しつつvimで開いてもダメ.そもそもテキストで保存されてないのか.
じゃあとおもって

tcpdump -r packet_data.pcap > encoded.txt


と打つと,無事encoded.txtに人間が見て分かる形式で表示された.

あとは人間で読める形式に変換してからRを起動してデータを読みこませれば良いわけだけど,シェルでtcpdump打って変換してからRを起動して...とやるのは面倒.
全部Rで完結させるために,R内からshellコマンドを実行することにする.

今回使うのは,Rのsystemコマンド.

system('ls')
system('pwd')

みたいに使うと,シェルコマンドをRから実行してくれる.実行結果はRのコンソール上に吐かれるので,オプションのinternをTRUEにして,文字列としてR内で持たせてあげる.

まとめるとこんなかんじ

pcap.path <- <pcapデータへのフルパス>
data <- system(paste0('tcpdump -nn -r 'pcap.path),intern=T)

これでtcpdumpの出力が,オブジェクトdataに文字列として保存される.
nnオプションはIPの名前解決をしないオプション.付けないと勝手にドメインに書き換えられるから必須.
追記
(オプション-nnttqが、色々無駄なの消えて一番楽ということに後で気付いた.
またプロトコルを指定したい場合はオプションを色々弄ると楽になる.)

data
[1] "09:00:37.1691342 IP 100.100.123.123.52 > 123.123.123.123.22: UDP, length 0"
....


あとは文字列処理のお話.
strsplitで空白とカンマで分割してやる.

strsplit(data,split=' |,')
#strsplit(data,split=' |,|:|>|\\.') #コロンやピリオドでも分割するならこっち.時刻やIPが分かれすぎるけど
#追記の-nnttqオプションでやるならこっちが便利(僕の場合)


結果はリスト.unlistしたいところだけど,パケットごとに分割後の長さが異なるのでやめておく.「時刻」とか「送信元」とか,必要な情報をリストからいちいち取り出してゆく

Time <- sapply(data,'[[',1) #時刻だけ取り出し
Source <- sapply(data,'[[',3) #送信元だけ取り出し(IPとポートは後で分けよう)
Dest <- sapply(data,'[[',5) #宛先だけ取り出し(IPとポートは後で分けよう,末尾のコロンも後で消そう)
Protocol <- sapply(data,'[[',6) #TCPかUDPかそれ以外か


とりあえず,僕が必要なのはこれだけ.パケットフラグとかも必要なら,もう少し面倒な処理が必要だったかも.
あとはTime,Source,Dest,Protocolをdata.frameにまとめれば解析に必要なデータは得られたことになる.(IPとポート分ける処理とかは書いてないけど)
追記
(icmpが来るとポート番号が無いので変なことになるのに気付いた。僕の場合はtcpだけ取れれば良いから、tcpdumpの時点でフィルタリングしてしまう)

さっそくプロットとかしてみよう