1 分間隔に分割した非常に大きな tcpdump ファイルがあります。tshark を使用して、ループ コードを使用して 1 分間のファイルごとに TCP 統計を抽出し、結果を CSV ファイルとして保存して、Excel でさらに分析を実行できます。ここで、すべての 1 分間のファイルについて、1 分間のファイルごとに TCP フローの数をカウントし、そのデータを CSV ファイルに保存できるようにしたいと考えています。ここでの TCP フローは、特定の送信元から特定の宛先に向かうパケットのグループを表します。各フローには、送信元 IP、宛先 IP、A->B からの #pcakets、A->B からの #bytes、B->A からの #packets、B->A からの #bytes、合計パケット、合計バイト、など。そして、1 分間のファイルごとに TCP フローの数を数えたいだけです。これまで読んだことから、それを行うにはディセクタを作成する必要があるようです。始める方法についてのポインタやコードを教えてもらえますか? ありがとう。
2 に答える
Tshark には、必要なすべての情報をダンプするコマンドがあります: tshark -qz conv,tcp -r FILE
. これは、フローごとに 1 行 (およびヘッダーとフッター) を書き込むため、フローをカウントするには、行をカウントしてヘッダー/フッターを差し引くだけです。
解剖者ではなく、タップです。Wireshark のREADME.tappingドキュメントを参照してください。悲しいことに、C の単純な例についてはTShark のユーザーのタップを参照してください。
Lua でタップを作成することもできます。たとえば、Wireshark WikiのLua/Tapsページと、Wireshark ユーザー マニュアルのWireshark セクションの Lua サポートを参照してください。
各パケットの TCP タップに渡される C 構造は次のとおりです。
/* the tcp header structure, passed to tap listeners */
typedef struct tcpheader {
guint32 th_seq;
guint32 th_ack;
gboolean th_have_seglen; /* TRUE if th_seglen is valid */
guint32 th_seglen;
guint32 th_win; /* make it 32 bits so we can handle some scaling */
guint16 th_sport;
guint16 th_dport;
guint8 th_hlen;
guint16 th_flags;
guint32 th_stream; /* this stream index field is included to help differentiate when address/port pairs are reused */
address ip_src;
address ip_dst;
/* This is the absolute maximum we could find in TCP options (RFC2018, section 3) */
#define MAX_TCP_SACK_RANGES 4
guint8 num_sack_ranges;
guint32 sack_left_edge[MAX_TCP_SACK_RANGES];
guint32 sack_right_edge[MAX_TCP_SACK_RANGES];
} tcp_info_t;
したがって、C 言語タップの場合、タップ リスナーの「パケット」ルーチンへの「データ」引数は、そのような構造を指します。
Lua タップの場合、タップ リスナーの「パケット」ルーチンに 3 番目の引数として渡される「tapinfo」テーブルは、「リスナーのタイプに基づく情報のテーブル、または nil.」として記述されます。sack_left_edge
TCP タップの場合、テーブルのエントリには、とを除く、その構造体のすべてのフィールドが含まれますsack_right_edge
。表のキーは構造体のメンバー名です。
フィールドはth_stream
接続を識別します。TCP ディセクタが新しい接続を見つけるたびに、新しい値を割り当てます。コメントが示すように、「このストリーム インデックス フィールドは、アドレス/ポートのペアがいつ再利用されるかを区別するのに役立つ」ため、特定の接続が閉じられ、後の接続が同じエンドポイントを使用しているth_stream
場合でも、2 つの接続は異なる値になります。それらは同じエンドポイントを持っています。
したがって、th_stream
値をキーとして使用するテーブルがあります。このテーブルには、エンドポイント (アドレスとポート) と、各方向のパケット数とバイト数が格納されます。リスナーの「パケット」ルーチンに渡される各パケットについてth_stream
、テーブルで値を検索し、値が見つからない場合は、カウントをゼロから開始して新しいエントリを作成し、それを使用します。新しいエントリ; それ以外の場合は、見つけたエントリを使用します。次に、パケットが A から B に向かうのか、B から A に向かうのかを判断し、適切なパケット数とバイト数を増やします。
また、タイムスタンプも追跡します。最初のパケットでは、そのパケットのタイム スタンプを保存します。パケットごとにタイム スタンプを確認し、保存されているタイム スタンプより 1 分以上遅れている場合は、次のようにします。
- 接続のテーブルから統計をダンプします。
- 接続のテーブルを空にします。
- 以前に保存されたタイムスタンプを置き換えて、新しいパケットのタイムスタンプを保存します。