C++でパケット解析する PacketMachine というライブラリの1.0.0をリリースしました,というのを紹介する記事です.
なおこの手の話ではお約束ですが,ネットワークキャプチャはあくまで自分の管理権限がある箇所のみで実施してください。不用意なネットワークキャプチャは法に触れる可能性もありますのでご注意ください。
何をするライブラリなのか
研究やネットワーク通信解析などのツール開発をする際,パケットキャプチャの部分をお手軽・かつ性能を出せるように書けるといいなと思ったのがモチベーションです.例えばTCPの通信を eth0
からキャプチャしてIPアドレスやポート番号を表示する,というのは以下のように書くことができます.
# include <iostream>
# include <packetmachine.hpp>
int main(int argc, char* argv[]) {
pm::Machine m;
m.on("TCP", [](const pm::Property& p) {
std::cout << "TCP: " <<
p["IPv4.src"] << ":" << p["TCP.src_port"] << " > " <<
p["IPv4.dst"] << ":" << p["TCP.dst_port"] << std::endl;
});
m.add_pcapdev("eth0");
m.loop();
return 0;
}
pm::Machine
の on()
というメソッドで引っ掛けたいイベント (対応イベント一覧) とコールバックを指定し,pm::Property
からパケット解析で得られたパラメータ (対応パラメータ一覧) を取り出して利用できます.
他にも,例えばDNSの問い合わせクエリから .google.
という文字を含むものを探す場合には以下のように書くことができます.
# include<iostream>
# include<packetmachine.hpp>
int main(int argc, char* argv[]) {
int google_count = 0;
auto m = pm::Machine();
m.add_pcapfile("eth0");
m.on("DNS", [&](const pm::Property& p) {
const auto& vals = p.value("DNS.question");
if (!vals.is_null()) {
for (size_t idx = 0; idx < vals.size(); idx++) {
const auto& v = vals.get(idx);
auto s = v.find("name").repr();
if (s.find(".google.") != std::string::npos) {
google_count++;
}
}
}
});
std::cout << google_count << std::endl;
m.loop();
return 0;
}
何ができないのか
- PacketMachineはパケットの分析部分を高速化するツールであり,キャプチャを高速化するものではありません.現状はバックエンドにlibpcapを使っており,netmapやDPDKのようにIOフレームワークを提供するものではありません.
- PacketMachineはパケットの読み取りに特化しており,パケットの編集や新しいパケット作成はできません.
どのぐらい高速なのか
詳しくはベンチマークのページに結果を書いていますが,一部抜粋します.
三種類のデータセットを使って,同じくC++で書かれたパケット分析ライブラリlibtins,Goで書かれたGoPacketと性能を比較しています.
このグラフはTCPポート80番のパケットがいくつあったかを数え上げるタスクの性能を比較しています.ここでの性能とは秒間あたりのパケット処理数(Packet Per Second, pps) であり,縦軸がこれにあたります.ppsは高いほど多くのパケットを処理できることを意味します.
データセットに含まれるパケットの種類などにも影響しますが,PacketMachineは概ね2Mppsを超える性能をだしています.WIDE projectのMAWIの計測ページから計算すると昨今のパケット平均長は約660バイトであるため,2Mpps処理できるとなると約10Gbpsの性能がでると言えます.(実際に net-2009-11-17-10:32.pcap
のデータセットを使った処理では13Gbpsほどの性能がでています)
念のため注意していただきたいのは,この結果はあくまでライブラリとしての一側面でしかないということです.例えばlibtinsはパケットの加工などの機能も備えているし,GoPacketではGoで書いたほうが親和性の高いプロジェクトもあるでしょう.そういった諸々を踏まえて検討する際の参考にしてほしい,というのがこの結果を出した狙いです.
今後
とりあえず公開はしてみましたが,一人で黙々とやっていたプロジェクトなのでまだ機能的にはいろいろ足りないところがありますし(特にTCPセッションのセグメント再構築まわりが怪しい)継続して機能拡張していこうと考えています.もしご意見・ご要望があれば可能な範囲で取り入れさせていただきたいと思いますので,お気軽にお知らせください.