LinuxでtsharkによるDeep pcap解析:プロトコルのフィルタリング、フィールド抽出、トラフィック統計の生成

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

tcpdumpやWiresharkで取得したpcapファイルがある。その中から何かを調べたい。リモートサーバーにSSH接続中だったり、CIパイプラインの中で作業しているなら、WiresharkのGUIは使えない。tsharkがそのギャップを埋めてくれる — WiresharkのフルDissectionエンジンに対応したCLIフロントエンドだ。フィールド抽出の構文を覚えてしまえば、生のパケットキャプチャがシェルから直接クエリできる構造化データに変わる。

本番環境のインシデント調査でこれを使ったことがある — 複数ノードのキャプチャを同時にパースし、100MBを超えるファイルも処理した。文句ひとつ言わずこなしてくれる。

アプローチ比較:tshark vs tcpdump vs スクリプト解析

既存のpcapファイルを解析する場合、現実的な選択肢は3つある:

オプション1:tcpdumpで読み直す

tcpdump -r file.pcapでpcapを再生するのは軽量でどこでも使える。ただし、tcpdumpの出力はプロトコル認識が限定的なライン指向のテキストだ — ざっと確認するには向いているが、特定フィールドの抽出やプロトコル別バイト数の計算には向かない。

オプション2:Pythonで生バイトをパースする(scapy / dpkt)

scapyならPythonで完全なコントロールが得られる。パケットを1つずつ繰り返し処理して、好きな統計を構築できる。ただし欠点は深刻だ:セットアップのオーバーヘッド、50MBを超えるファイルでの処理速度の低下、そしてWiresharkがすでに正しく処理しているプロトコルパーシング(自分では気づかないエッジケースを含む)を再実装する羽目になる。

オプション3:フィールド抽出を使ったtshark

tsharkはWiresharkと一緒に提供され、3000以上のプロトコルをすぐに理解できる。Displayフィルタ(WiresharkのGUIと同じ構文)でフィルタリングし、名前付きフィールドをタブ区切りの列として抽出し、出力をawk、sort、またはPythonにパイプできる。pcapファイルから具体的な答えへの最短ルートだ。

メリットとデメリット

tsharkの強み

  • WiresharkのフルDissectionエンジン — TLSハンドシェイク、HTTP/2、DNS over TCPなど、正確なプロトコルパーシング
  • Displayフィルタの構文は表現豊かでドキュメントも充実している
  • フィールド名は安定していて予測しやすい(ip.srctcp.dstporthttp.request.uri
  • 組み込みの統計コマンド(-zフラグ)で外部処理を完全にスキップできる
  • ライブインターフェースと既存のpcapファイルの両方に同じフラグで動作する

tsharkの弱点

  • バイナリフットプリントが大きい — WiresharkはQtと多数のDissectorライブラリを引き込む
  • 会話テーブルの構築時に非常に大きなキャプチャでメモリ消費が増加する
  • -z統計フラグはメジャーバージョン間で構文が一貫していない
  • 最小限のサーバーイメージにはデフォルトでインストールされていない

代わりにtcpdumpを選ぶタイミング

キャプチャをざっと確認したり、パケットがホストに届いたかを確認するだけなら、tcpdumpの方が入力が速くて常に使える。「DNSクエリでNXDOMAINが返った件数は?」や「最もバイト数を送信したIPは?」といった具体的な質問があるときにtsharkを使おう。

推奨セットアップ

解析マシンにtsharkをインストールする — キャプチャノードには不要で、pcapファイルをコピーするだけでいい:

# Debian / Ubuntu
sudo apt install tshark -y

# RHEL / Rocky / AlmaLinux
sudo dnf install wireshark-cli -y

# Arch
sudo pacman -S wireshark-cli

Debianのインストーラーは、rootではないユーザーがパケットをキャプチャできるかどうかを尋ねてくる。「はい」を選んで、自分をグループに追加しよう:

sudo usermod -aG wireshark $USER
newgrp wireshark

バージョンを確認しよう — フィールド名はメジャーリリース間で変わることがある:

tshark --version | head -1

実装ガイド

ステップ1:pcapファイルをすばやく検査する

フィルタリングの前に、まずざっと確認しよう:

# パケット総数を数える
tshark -r capture.pcap 2>/dev/null | wc -l

# プロトコルサマリー付きで最初の20パケットを表示する
tshark -r capture.pcap -c 20

2>/dev/nullはスクリプトを汚すインターフェース/バージョンバナーを抑制する。パイプで使うすべてのtsharkコマンドに追加しよう。

ステップ2:Displayフィルタでプロトコルをフィルタリングする

DisplayフィルタはWiresharkのGUIフィルタバーと同じ構文を使う。tcpdumpのBPF構文との重要な違い:Displayフィルタは生バイトではなく、デコードされたプロトコルフィールドに対して動作する。つまり、特定のオフセットでバイトをマッチさせようとする代わりにdns.flags.rcodeでフィルタリングできる。

# DNS通信のみ
tshark -r capture.pcap -Y 'dns' 2>/dev/null

# HTTPリクエスト(レスポンスは除く)
tshark -r capture.pcap -Y 'http.request' 2>/dev/null

# TCP RSTパケット — 接続拒否の検出に役立つ
tshark -r capture.pcap -Y 'tcp.flags.reset == 1' 2>/dev/null

# NXDOMAINを返したDNSクエリ
tshark -r capture.pcap -Y 'dns.flags.rcode == 3' 2>/dev/null

# 2つの特定ホスト間のトラフィック
tshark -r capture.pcap -Y 'ip.addr == 10.0.1.5 and ip.addr == 10.0.1.1' 2>/dev/null

ステップ3:特定フィールドを列として抽出する

-T fieldsフラグと-e fieldnameを組み合わせると、awk、sort、またはPythonですぐに使えるタブ区切り出力が得られる。手動パーシングは不要 — デコードされたプロトコルデータからの列抽出だけだ。

# すべてのTCPパケットの送信元IP、宛先IP、宛先ポートを抽出する
tshark -r capture.pcap -Y 'tcp' -T fields \
  -e ip.src \
  -e ip.dst \
  -e tcp.dstport \
  2>/dev/null

# DNSクエリ名とレスポンスコードを抽出する
tshark -r capture.pcap -Y 'dns' -T fields \
  -e dns.qry.name \
  -e dns.flags.rcode \
  2>/dev/null

# すべてのHTTPリクエストのメソッド、ホスト、URIを抽出する
tshark -r capture.pcap -Y 'http.request' -T fields \
  -e http.request.method \
  -e http.host \
  -e http.request.uri \
  2>/dev/null

正確なフィールド名がわからない?Wiresharkでパケット詳細ペインのフィールドにカーソルを合わせると、下部のステータスバーに名前が表示される。またはフィールドレジストリから直接検索することもできる:

tshark -G fields 2>/dev/null | grep -i 'user.agent'

ステップ4:-zでトラフィック統計を構築する

-zフラグはtsharkの組み込み統計モジュールを呼び出す。フィールド出力を外部ツールにパイプするより速い — すべてが1回のパスで実行されるからだ — 中間出力なし、余分なシェルプロセスもなし。

# プロトコル階層 — プロトコル別のパーセンテージ内訳
tshark -r capture.pcap -z io,phs -q 2>/dev/null

# IPごとのトップトーカー(転送バイト数)
tshark -r capture.pcap -z conv,ip -q 2>/dev/null | sort -k 6 -rn | head -20

# DNSクエリ/レスポンスのサマリー
tshark -r capture.pcap -z dns,tree -q 2>/dev/null

# HTTPリクエストメソッドとレスポンスコード
tshark -r capture.pcap -z http,tree -q 2>/dev/null

# TCP接続サマリー(ペアごとのSYN/FIN/RST数)
tshark -r capture.pcap -z conv,tcp -q 2>/dev/null

-qフラグはパケットごとの出力を抑制し、統計テーブルだけを表示する。

ステップ5:カスタム統計のためにフィールド抽出とUnixツールを組み合わせる

組み込みの統計がすべての質問をカバーするわけではない。カスタムの答えが必要な場合、フィールド出力を標準のUnixツールにパイプしよう:

# ドメインごとのDNSクエリ数を頻度順でカウントする
tshark -r capture.pcap -Y 'dns.flags.response == 0' -T fields \
  -e dns.qry.name 2>/dev/null \
  | sort | uniq -c | sort -rn | head -20

# 接続先の上位ポートを探す
tshark -r capture.pcap -Y 'tcp.flags.syn == 1 and tcp.flags.ack == 0' \
  -T fields -e tcp.dstport 2>/dev/null \
  | sort | uniq -c | sort -rn

# すべてのHTTP User-Agent文字列を抽出する(ボット検出に役立つ)
tshark -r capture.pcap -Y 'http.user_agent' -T fields \
  -e http.user_agent 2>/dev/null \
  | sort -u

ステップ6:フィルタリングしたパケットを新しいpcapにエクスポートする

500MBのファイルを移動させずに同僚と共有したり、別のツールに渡したりするために、キャプチャの一部だけが必要な場合もある:

# DNS通信のみを新しいファイルに保存する
tshark -r capture.pcap -Y 'dns' -w dns_only.pcap 2>/dev/null

# 特定ホストへ/からのトラフィックを保存する
tshark -r capture.pcap -Y 'ip.addr == 192.168.1.100' -w host_traffic.pcap 2>/dev/null

実用的なスクリプト:pcapクイックサマリー

インシデントのトリアージ用に用意しているシェルスクリプトを紹介する。pcapファイルを渡すと、10秒以内に全体像を把握できる:

#!/bin/bash
# 使い方:./pcap-summary.sh capture.pcap
FILE="${1:-capture.pcap}"

echo "=== パケット数 ==="
tshark -r "$FILE" 2>/dev/null | wc -l

echo "=== プロトコル内訳 ==="
tshark -r "$FILE" -z io,phs -q 2>/dev/null

echo "=== 上位10トーカー ==="
tshark -r "$FILE" -z conv,ip -q 2>/dev/null \
  | tail -n +8 | sort -k6 -rn | head -10

echo "=== DNS失敗(NXDOMAIN) ==="
tshark -r "$FILE" -Y 'dns.flags.rcode == 3' -T fields \
  -e dns.qry.name 2>/dev/null | sort | uniq -c | sort -rn

echo "=== TCP RSTの送信元 ==="
tshark -r "$FILE" -Y 'tcp.flags.reset == 1' -T fields \
  -e ip.src -e tcp.srcport 2>/dev/null | sort | uniq -c | sort -rn | head -10

高スループットのサービスでは、pcapファイルはあっという間にギガバイト単位に膨れ上がる。最も効果的な2つのことがある:Displayフィルタをできるだけ絞り込む(絞り込むほど、tsharkの走査量が減る)、そして常に-z-qをセットで使う。-qなしでは、統計テーブルと並んでパケットごとの出力がターミナルに溢れてしまう。

注意すべきこと

  • 複数値フィールド:1つのパケットに複数の質問が含まれている場合、dns.qry.nameに対して複数の値が返されることがある。tsharkはデフォルトでカンマで区切る — 1行に1つの値が必要な場合は-E separator=\nを使おう。
  • 暗号化通信:セッションキーファイルを提供すれば、tsharkはTLSを復号できる:-o tls.keylog_file:/path/to/sslkeylog.log。このファイルを生成するには、ブラウザやアプリケーションでSSLKEYLOGFILEを設定しよう。
  • 大容量ファイル:1GBを超えるキャプチャは、まずeditcap -c 100000 big.pcap split/out.pcapで分割してから、各チャンクを並行処理しよう。
Share: