tcpdump と Wireshark

このページの目次

パケットキャプチャは、特定の観測点および特定の期間中に収集されたパケットを保存したものです。tcpdump は条件に基づく収集やオフライン検査に適しており、Wireshark/TShark はプロトコルフィールドの再構成や時系列分析に適しています。信頼できる結論は、「収集範囲」「プロトコルの事実」「推論の境界」の三者が一致することから導き出されるものであり、単に某行が赤色で強調されているからではありません。

最初に答えるべき質問収集への影響
どの接続が失敗したかクライアント、プロキシのエントリポイント、プロキシの出口では、異なる収集ポイントが必要になる場合があります
TCP か UDP かTCP 443 だけをキャプチャすると、QUIC を見逃す可能性があります
DNS が関与するか宛先 IP のみでフィルタリングすると、その前の名前解決の失敗が見えない場合があります
ハンドシェイクかコンテンツか収集をいつ開始するか、完全な snaplen と復号化素材が必要かどうかを決定します
完全に保存できるかフィルタリングの範囲、バッファリング、ファイルのローテーション、停止条件を決定します

観測位置が証明できる内容を決定する

同じアクセスでも、異なる観測点では異なる接続とパケットの形態が見える クライアント アプリケーション / ソケット プロキシまたは NAT 接続の終了またはアドレスの書き換え バックエンドサービス 別の接続セグメント ホストでのキャプチャは、オフロード前に行われる可能性があります プロキシ後の5タプルは変化する可能性があります インターフェース、ネームスペース、方向、時間基準を最初に記録する パケットが見えないのは、この場所で収集されなかったことを示すだけです。経路の違い、フィルタリング、切り捨て、キャプチャのドロップを除外する必要があります。

Linux ホスト、コンテナネットワークのネームスペース、veth、ブリッジ、物理 NIC、ループバックは、それぞれ異なる視点を提供します。-i any は、現在のネームスペースでキャプチャ可能なインターフェースをカバーしますが、すべてのコンテナに自動的に進入するわけではありません。Linux の any は通常、cooked capture リンクタイプを使用するため、すべてのパケットが標準のイーサネットヘッダーから解析されるとは限りません。

NAT を通過するとアドレスとポートが変更される可能性があります。リバースプロキシを通過すると、通常は別の TCP 接続となっており、同じ tcp.stream や5タプルを使用してバックエンドを見つけることはできません。ファイル間の関連付けには、時間、リクエスト ID、ペイロードの特徴、およびプロキシログを組み合わせる必要があります。各ファイルのストリーム番号は、今回の分析結果におけるインデックスに過ぎません。

両端で同時にキャプチャすると、欠落が発生した位置を絞り込むことができますが、時計が同期されていない場合、タイムスタンプを単純に減算すると、誤った片方向レイテンシが生じます。マイクロ秒またはナノ秒単位の精度のタイムスタンプでも、同等の測定精度が保証されるわけではありません。

キャプチャフィルタと表示フィルタはそれぞれどこで有効になるか

属性キャプチャフィルタ表示フィルタ
一般的な使用箇所tcpdump 式、TShark -fWireshark のフィルターバー、TShark -Y
作用対象収集前のフィルタリング、またはオフライン読み取り時のフィルタリング解析済みの既存パケットのフィールド
例tcp port 443tcp.port == 443
非マッチデータリアルタイム収集時は通常、キャプチャファイルに書き込まれない元のファイルは保持され、条件を変更して再分析可能
能力の限界リンクタイプ、オフセット、コンパイラのサポートに依存ディセクター、再構成、可視な平文に依存

リアルタイム収集では、libpcap はサポートされているプラットフォームでフィルタプログラムをカーネルに渡し、ユーザーモードに渡されるパケットを減らすことができます。オフラインファイルを読み取る際にも同じ式を使用できますが、「すべての BPF フィルタリングが常にカーネルで発生する」わけではありません。トラフィック、マッチング比率、デコードオーバーヘッドが与えられていない場合、固定された桁数で高速であるとは主張できません。tcpdump マニュアルソース

一般的なキャプチャ条件

# 以下はフィルタ式であり、tcpdump に渡す際には引用符で囲まれたパラメータとして扱われます。
# 双方向の宛先を含み、TCP および UDP 443 をカバーします:
tcpdump -nn -r capture.pcap 'host 192.0.2.10 and port 443'

# IPv4 のみで、SYN がセットされ ACK がセットされていない場合;他の協働フラグが同時に存在することを許可:
tcpdump -nn -r capture.pcap 'ip and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'

# 2つの宛先のいずれかであり、かつ TCP 443 である場合:
tcpdump -nn -r capture.pcap '(host 192.0.2.10 or host 192.0.2.20) and tcp port 443'

tcp[tcpflags] == tcp-syn はフラグバイトの厳密な一致であり、他の協働フラグも同時に含んでいる SYN を除外する可能性があります。ビットマスクを使用することで、「SYN があり、ACK がない」を正確に表現できます。生トランスポートヘッダーのオフセット式は、IPv6 拡張ヘッダーなどのシナリオで追加の制限があるため、ここでは明示的に IPv4 を限定しており、全プロトコル共通の接続統計として扱うことはできません。

ポート条件はアプリケーションの識別には等しくありません。443 は異なるプロトコルを運ぶことができ、DNS 暗号化トラフィックがすべて 53 番ポートにあるわけではありません。最初のフラグメント以外の IP フラグメントには、生トランスポート層ポートがないため、狭すぎるポートフィルタリングは再構成の欠片を引き起こす可能性があります。VLAN およびトンネルカプセル化も、オフセットとマッチング範囲に影響を与えます。pcap-filter 構文ソース

表示フィルタを変更しても、キャプチャしなかったパケットは戻ってきますか?

厳密な等値で収集し、その後すべてを表示しても、1つのパケットしか見えません。マスクを使用して再収集すると、2種類の SYN が保存されます。キャプチャドロップダウンボックス自体を変更しても、すでに保存されたファイルは書き換えられないため、新しい収集を明示的に実行する必要があります。

図を準備しています
表示フィルタを変更しても、キャプチャしなかったパケットは戻ってきますか?

表示フィルタは、すでに保存された集合内でのみフィルタリングできます。厳密な SYN 等値は、ECE/CWR も同時にセットしている SYN を見逃すため、事後にすべてを表示しても補完できません。

制御された収集を行い、その後オフラインで分析する

以下は、実際のトラブルシューティング時に環境に応じて調整するコマンドです。NIC 名と宛先アドレスは置き換えてください。ファイルの場所は書き込み可能であることを確認してください。キャプチャインターフェースには通常、適切な権限が必要です。保存されたファイルの読み取りには通常、権限は必要ありません。

# 最大 5000 個のマッチパケットを処理;-c はパケット数を制限し、待ち時間を制限しません。
tcpdump -i eth0 -nn -s 0 -B 4096 -c 5000 \
  -w capture.pcap 'host 192.0.2.10 and port 443'

# 容量に基づいて 5 つのファイルを循環保存;-C 100 の基本単位は 10 進数のメガバイトです。
tcpdump -i eth0 -nn -s 0 -C 100 -W 5 \
  -w trace.pcap 'host 192.0.2.10'

# 読み取り専用、キャプチャを開始しない。
tcpdump -nn -tttt -r capture.pcap

-s 0 は、ツールが定義する最大/デフォルトの snaplen を使用しますが、数学的な無限長ではありません。ファイル内の captured length と original length を確認して、パケットが切り捨てられているかどうかを判断する必要があります。-B の単位は KiB です。-C のローテーションは閾値を少し超える可能性があるため、正確なディスク上限として扱うことはできません。-W と組み合わさると、古いファイルを循環して上書きします。時間ベースの -G とカウントオプションは異なる相互作用を持つため、容量ベースのローテーションロジックをそのままコピーしてはいけません。

終了時に、captured(キャプチャ数)、received by filter(フィルタ通過数)、dropped by kernel(カーネルドロップ数)を記録します。後2つの口径はオペレーティングシステムに依存します。dropped by kernel は、キャプチャメカニズムのバッファドロップを示し、ビジネスネットワークの実際のドロップ数とは異なります。0 と表示されていても、ミラーポート、ドライバ、または他の場所でキャプチャが漏れていないことを保証するものではありません。

大まかなストレージ予算:平均して秒間 20,000 パケット、平均 800 B を保持する場合、古典的な pcap ではレコードごとに 16 B のヘッダーがあり、60秒で約 20,000 × 816 × 60 = 979,200,000 B、つまり 979.2 MB となります。この見積もりにはファイルシステムオーバーヘッドは含まれておらず、pcapng のすべてのブロック構造に直接適用できるものではありません。

まずストリームを特定し、その後再構成と方向を見る

# TCP 会話のサマリー;-q はパケットごとの出力を減らします。
tshark -r capture.pcap -q -z conv,tcp

# 同じキャプチャファイル内のストリーム 3 を選択し、重要なフィールドをエクスポートします。
tshark -r capture.pcap -Y 'tcp.stream == 3' -T fields \
  -e frame.number -e frame.time_relative -e ip.src -e tcp.srcport \
  -e tcp.seq -e tcp.ack -e tcp.len -e tcp.window_size

# 候補となる異常を見つけ、その後、完全なストリームのコンテキストに戻ります。
tshark -r capture.pcap \
  -Y 'tcp.analysis.retransmission || tcp.analysis.zero_window'

IPv6 分析では、ipv6.src などのフィールドも同時に選択する必要があります。ハンドシェイクがない場合、ウィンドウスケーリングなどのネゴシエーション情報は不明である可能性があります。フィールドが空白なのは、そのパケットにそのレイヤーが含まれていないためであり、数値が 0 であるためではありません。TShark マニュアル

ip.addr == A は、どちらの方向のアドレスにも一致します。A に関連するすべてのパケットを除外したい場合は、!(ip.addr == A) を明示的に使用し、多値フィールドで直感的に不等演算のセマンティクスを推測しないようにしてください。表示フィルタは、収集時に失われたバイトを再構築しません。表示フィルタ

HTTP ヘッダーは TCP セグメントにまたがる可能性があり、圧縮または暗号化された後でも、検索可能なテキストになるとは限りません。tcpdump -A | grep Host: は、特定のパケット内の可視な断片しか見つからないため、信頼できる HTTP リクエストパーサーではありません。プロトコル再構成とストリームの追跡を使用し、収集が接続の開始から行われたかどうかを明確にしてください。

「再送」のヒントは、可視なパケットに基づく分析である

シーケンス番号のギャップ:パスのドロップとキャプチャの欠落をまず区別する 送信側 キャプチャポイント 受信側 seq=1001、len=1000 seq=2001、len=1000(この地点ではキャプチャされなかった) ACK=3001 受信側は 3001 まで確認した。中間のキャプチャギャップだけで、送信漏れと断定することはできない これは教育用の仮定です。実際の判断には、完全な双方向ストリーム、重複キャプチャ、シーケンス番号のラップアラウンド、および分析設定の確認が必要です。
ヒントまたは現象まず何と解釈するか継続的な確認
Previous segment not captured現在可視のシーケンス番号の前にギャップがあるキャプチャの中途開始、キャプチャ漏れ、またはフィルタリングが狭すぎた
Retransmission / Out-of-order可視のシーケンス番号と既存のストリーム状態の間に重複または順序入れ替えの関係がある双方向 ACK、タイムスタンプ、重複キャプチャ、および分析設定
ZeroWindowこのパケットの送信者が受信ウィンドウをゼロとして通知しているこの側のアプリケーションの読み取りと受信バッファの状態
Bad checksum現在のサンプリングバイトの計算結果が一致しない、または検証条件が不十分送信側のオフロード、切り捨て、およびキャプチャ位置
通常の MTU より大きい「パケット」ホストがより大きな処理単位を観測したTSO/GSO/GRO/LRO が関与しているかどうか

Wireshark の TCP 分析は、キャプチャパケットの順序と可視な履歴に依存しており、その分類には曖昧さがある可能性があります。各ヒントを、相手側の TCP 実装が直接報告した事実として扱うことはできません。TCP 分析

送信側でのキャプチャは、NIC によるチェックサム補完やセグメンテーションの前で行われる可能性があります。受信側では、集約されたデータを観測する場合があります。この場合、誤ったチェックサムや「大きなパケット」が必ずしも回線上に現れるわけではありません。実際の回線上の形態を確認するには、受信側または外部の観測点と比較する必要があります。オフロードを無効にするとパフォーマンスと動作が変化するため、ヒントを見つけた後のデフォルトの最初のステップとして行うべきではありません。Wireshark オフロード

TLS 復号化には、正しいセッションシークレットが必要であり、変数名を1つ記入するだけでは不十分です

SSLKEYLOGFILE は、一部のクライアントおよび TLS ライブラリがサポートするキーログインターフェースであり、オペレーティングシステムがすべてのプログラムに秘密の出力を強制する汎用スイッチではありません。プログラムは実際にサポートしており、起動時に設定を読み取り、キャプチャセッションと一致するログを生成する必要があります。

Wireshark の TLS プロトコル設定でログファイルを指定するか、オフラインで使用します:

tshark -r capture.pcap -o tls.keylog_file:session.keys -Y http

復号化されたプロトコルが必ずしも HTTP/1 であるとは限りません。HTTP/2 などは、対応するフィルタが必要です。サーバー証明書プライベートキーのみでは、前方秘匿性を持つ ECDHE セッションや通常の TLS 1.3 セッションを復号できません。歴史的な RSA キー交換のプライベートキーによる復号には、厳格な適用条件があります。ハンドシェイク、レコード、またはログの欠如も、再構成と復号化を妨げます。Wireshark TLS

キーログと対応するキャプチャを組み合わせると、そのセッションの内容が露出するため、含まれるセッションデータに応じてアクセスと保持範囲を管理する必要があります。復号化された可視内容は、アプリケーションが独自のエンドツーエンド暗号化を持っているかどうかにも依存します。

フィルタセマンティクスのオフライン検証:SYN が2つと ACK が1つ

以下は、インストール済みの tcpdump を使用して、一時的な Ethernet/IPv4/TCP pcap を生成し、読み取りおよびフィルタリングするものです。インターフェースに接続せず、パケットを送信しません。3つのパケットは、SYN、SYN+ECE+CWR、ACK です。SYN と厳密に一致するのは1つのみですが、マスク条件は2つに一致する必要があります。

import ipaddress
import struct
import subprocess
import tempfile
from pathlib import Path

def checksum(data):
    if len(data) % 2: data += b'\0'
    total = sum(struct.unpack('>' + 'H' * (len(data) // 2), data))
    while total >> 16: total = (total & 0xffff) + (total >> 16)
    return (~total) & 0xffff

src = ipaddress.ip_address('192.0.2.1').packed
dst = ipaddress.ip_address('192.0.2.10').packed
packets = []
for flags in [0x02, 0xc2, 0x10]:
    tcp = struct.pack('>HHIIBBHHH', 40000, 443, 1000, 0, 0x50, flags, 65535, 0, 0)
    pseudo = src + dst + struct.pack('>BBH', 0, 6, len(tcp))
    tcp = tcp[:16] + struct.pack('>H', checksum(pseudo + tcp)) + tcp[18:]
    ip = struct.pack('>BBHHHBBH4s4s', 0x45, 0, 40, 1, 0, 64, 6, 0, src, dst)
    ip = ip[:10] + struct.pack('>H', checksum(ip)) + ip[12:]
    ethernet = bytes.fromhex('0200000000020200000000010800')
    packets.append(ethernet + ip + tcp)

with tempfile.TemporaryDirectory() as folder:
    path = Path(folder) / 'flags.pcap'
    output = struct.pack('<IHHIIII', 0xa1b2c3d4, 2, 4, 0, 0, 65535, 1)
    for i, packet in enumerate(packets):
        output += struct.pack('<IIII', 1700000000 + i, 0, len(packet), len(packet))
        output += packet
    filters = [
        ('ip and tcp[tcpflags] == tcp-syn', 1),
        ('ip and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn', 2),
        ('tcp port 443', 3),
    ]
    for expression, expected in filters:
        result = subprocess.run(['tcpdump', '-nn', '-r', str(path), expression],
                                text=True, capture_output=True, check=True)
        assert len(result.stdout.strip().splitlines()) == expected
print('オフライン pcap:厳密な SYN 1個、マスク SYN 2個、443 合計 3個')

これは、キャプチャ式とパケットエンコーディングのマッチングを検証するものであり、パフォーマンステストではなく、完全な TCP セッションをシミュレートしたものではありません。実際のトラブルシューティングでは、元のファイル、収集コマンド、ツールバージョン、収集カウント、および重要なフレーム番号を一緒に記録し、結論を検証可能にする必要があります。