目次
「アプリのログには何も出ていないのに、外部APIの呼び出しだけが時々タイムアウトする」「curlは通るのに、アプリからだと接続できない」。こうした問題は、アプリケーションのログをいくら眺めても原因にたどり着けないことが多いものです。ログに残るのは「アプリが何をしようとしたか」までで、「ネットワーク上で実際に何が起きたか」は記録されていないからです。
この記事では、Linuxサーバー上でパケットを直接観察するtcpdumpと、そのキャプチャをGUIで解析するWiresharkの使い方を解説します。基本的なフィルタの書き方、pcapファイルの保存と読み込み、TLS通信で見えるもの・見えないものを押さえたうえで、「接続はできるが応答がない」「再送が多い」「DNSが失敗する」という3つの典型的なトラブルをパケットから切り分ける手順を身につけられます。なお、ip・ss・curl・pingといった基本コマンドはLinuxネットワークコマンド入門で解説していますので、そちらを前提とします。
パケットキャプチャで何がわかるのか
ログとパケットの決定的な違い
パケットキャプチャとは、NIC(ネットワークインターフェース)を通過するデータをそのまま記録することです。アプリのログが「意図」の記録だとすれば、パケットは「事実」の記録です。SYNを送ったのか、相手からSYN-ACKが返ってきたのか、RST(強制切断)を受けたのか、あるいは何も返ってこなかったのか。この違いは、原因が自サーバー側か、経路上のファイアウォールか、相手サーバー側かを切り分ける決め手になります。
TCPの接続確立や状態遷移の仕組み自体はTCPの3ウェイハンドシェイクとTIME_WAITで扱っていますので、本記事では「その挙動を実際に目で確認する」ことに集中します。
tcpdumpとWiresharkの役割分担
実務では、2つのツールを次のように使い分けるのが一般的です。
| ツール | 動作環境 | 得意なこと |
|---|---|---|
| tcpdump | サーバー上のCLI | 本番サーバーでの取得、フィルタして保存、軽量 |
| Wireshark | 手元のPC(GUI) | pcapの詳細解析、ストリーム追跡、統計、プロトコル解釈 |
| tshark | CLI(Wireshark同梱) | サーバー上でWireshark相当の解析をテキストで行う |
「サーバーではtcpdumpでpcapに保存し、手元にダウンロードしてWiresharkで開く」という流れが基本形です。
tcpdumpの基本フィルタと保存方法
まず動かしてみる
tcpdumpはroot権限(またはCAP_NET_RAW)が必要です。インターフェースは-iで指定し、anyとするとすべてのインターフェースを対象にできます。-nを付けると名前解決を行わないため、表示が速くなりDNSクエリを余計に発生させずに済みます。
# インターフェース一覧を確認
sudo tcpdump -D
# 443番ポートの通信を、名前解決なしで10パケットだけ表示
sudo tcpdump -i any -n port 443 -c 10
# 特定ホストとの通信だけを見る
sudo tcpdump -i eth0 -n host 203.0.113.10
# 複数条件の組み合わせ(and / or / not)
sudo tcpdump -i eth0 -n 'host 203.0.113.10 and (port 80 or port 443)'
sudo tcpdump -i eth0 -n 'not port 22'
フィルタ構文はBPF(Berkeley Packet Filter)と呼ばれ、host・net・port・src・dstをand・or・notでつなぎます。SSH越しに作業しているときはnot port 22を入れないと自分のSSH通信で画面が埋まるので、最初に覚えておきたい書き方です。
TCPフラグで絞り込む
SYNだけ、RSTだけ、といった抽出ができると、「接続を試みた回数」や「切断された瞬間」だけを一覧できます。
# SYNのみ(接続開始の試み)を抽出
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'
# RST(強制切断)を抽出
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & tcp-rst != 0'
# SYN-ACK(サーバーからの応答)を抽出
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)'
pcapに保存してWiresharkに渡す
画面で流し見するより、ファイルに保存して後から解析するほうが確実です。-wでpcap形式に保存し、-s 0でパケット全体を記録します(古いバージョンではデフォルトが先頭96バイトに切り詰められるため、明示しておくと安全です)。長時間取得する場合は-C(ファイルサイズ上限、MB単位)と-W(ローテーション数)でディスクを圧迫しないようにします。
# 保存(Ctrl+Cで停止)
sudo tcpdump -i eth0 -n -s 0 -w /tmp/capture.pcap 'host 203.0.113.10 and port 443'
# 100MBごとにローテーションし、最大5ファイルまで保持
sudo tcpdump -i eth0 -n -s 0 -C 100 -W 5 -w /tmp/rotate.pcap port 5432
# 保存したファイルをtcpdump自身で読む
sudo tcpdump -n -r /tmp/capture.pcap | head
# 手元PCへダウンロード
scp user@server:/tmp/capture.pcap ./
ダウンロードしたファイルはWiresharkで「ファイルを開く」だけで読み込めます。
Wiresharkでの解析手順
最初に見るべき3つの機能
数千行のパケットを上から読む必要はありません。次の3つの機能で必要な箇所にすぐたどり着けます。
- 表示フィルタ:画面上部のフィルタ欄にWireshark独自の構文を入力します。tcpdumpのBPFとは別物なので注意してください。例:
ip.addr == 203.0.113.10 && tcp.port == 443、tcp.flags.reset == 1、dns.flags.rcode != 0 - Follow TCP Stream:パケットを右クリックして「追跡」→「TCPストリーム」を選ぶと、その接続だけを会話形式で表示できます。HTTPなら平文のリクエストとレスポンスがそのまま読めます。
- Expert Information(分析→エキスパート情報):再送、重複ACK、ウィンドウサイズゼロなど、Wiresharkが自動検出した異常を一覧できます。「何かおかしいが、どこを見ればいいかわからない」ときに最初に開く画面です。
覚えておくと便利な表示フィルタ
# 再送だけを表示
tcp.analysis.retransmission
# 3ウェイハンドシェイクが完了していない接続(SYNに対する応答がない)
tcp.flags.syn == 1 && tcp.flags.ack == 0
# 遅いHTTPレスポンス(応答まで2秒以上)
http.time > 2
# TLSのハンドシェイク(ClientHello / ServerHello)だけ
tls.handshake.type == 1 || tls.handshake.type == 2
TLS通信で見えるもの・見えないもの
暗号化されていても得られる情報は多い
現在のWeb通信はほぼHTTPSなので、「暗号化されているならキャプチャしても意味がないのでは」と思われがちです。しかし実際には、TLSでも次の情報は平文のまま観察できます。
- TCPレベルの挙動すべて(接続確立、再送、RST、ウィンドウサイズ)
- ClientHelloに含まれるSNI(接続先ホスト名)とクライアントが提示するTLSバージョン・暗号スイート
- ServerHelloで選ばれたTLSバージョンと暗号スイート、サーバー証明書(TLS 1.2まで。1.3では証明書も暗号化されます)
つまり「TLSハンドシェイクは完了しているのに、その後の応答が遅い」なのか、「そもそもハンドシェイクで失敗している」なのかは、復号しなくても判別できます。証明書エラーやプロトコル不一致は、ServerHelloの直後にAlertレコードが飛んでくるので、そこで気づけます。
中身を見たいときの選択肢
HTTPのボディまで確認したい場合は、暗号化される前の場所で取得するのが現実的です。Nginxでリバースプロキシを組んでいるなら、NginxとアプリサーバーのあいだはHTTPであることが多いので、そこでport 3000などをキャプチャすれば平文で読めます。この構成の考え方はリバースプロキシの解説記事を参照してください。開発環境であれば、環境変数SSLKEYLOGFILEにファイルパスを指定してブラウザやcurlを起動し、Wiresharkの設定(Protocols→TLS→(Pre)-Master-Secret log filename)で読み込ませると、TLSを復号して表示できます。
実例で学ぶトラブルの切り分け
事例1:接続はできるが応答がない
症状:アプリから外部APIを呼ぶと、エラーにならないまま30秒後にタイムアウトする。curlで叩いても同じ。
調査:tcpdump -n host <APIのIP> and port 443で観察すると、SYN→SYN-ACK→ACKの3ウェイハンドシェイクは完了し、ClientHelloも送信されているが、ServerHelloが返ってこない。数秒おきにClientHelloの再送だけが続いている。
原因:経路上のファイアウォールがTCP接続そのものは通すが、一定サイズ以上のパケットを落としていた(MTU/フラグメント関連の問題)。ハンドシェイクの小さなパケットは通るのに、証明書を含む大きなServerHelloが届かないというパターンです。
対処:ping -M do -s 1400 <IP>でMTUの上限を確認し、インターフェースのMTUを下げるかMSSクランプを設定して解消。SYNに対してSYN-ACKすら返らない場合は、逆に「相手側かファイアウォールで完全にブロックされている」と判断できます。
事例2:再送が多く、転送が極端に遅い
症状:ファイルアップロードが数MBで異常に遅い。小さなAPI呼び出しは問題ない。
調査:Wiresharkのtcp.analysis.retransmissionでフィルタすると、大量の再送と重複ACKが検出される。Expert Informationにも「TCP Retransmission」「TCP Dup ACK」が並んでいる。
原因:経路上でパケットロスが起きており、TCPが輻輳制御でウィンドウを縮小して速度が落ちていた。同一区間をmtrで確認すると特定ホップでロスが観測された。
対処:クラウド側のNICドライバの既知の問題だったため、インスタンスタイプの変更で解消しました。
事例3:名前解決が失敗する
症状:特定のホスト名だけ、たまにgetaddrinfo ENOTFOUNDで失敗する。
調査:tcpdump -n port 53でDNSクエリを観察すると、AレコードとAAAAレコードを同時に問い合わせており、AAAA側の応答だけが返ってこないケースがあった。
原因:社内のDNSフォワーダーがAAAAクエリを正しく処理せず、タイムアウト扱いになっていた。DNSの解決の流れはDNSの仕組みの解説にありますが、「クエリを送ったのか」「応答が返ったのか」「応答がエラー(NXDOMAIN/SERVFAIL)だったのか」はパケットを見れば一目でわかります。Wiresharkならdns.flags.rcode != 0でエラー応答だけを抽出できます。
対処:/etc/resolv.confの参照先を正しいリゾルバに変更。並行して、アプリ側の名前解決結果のキャッシュ設定を見直しました。
本番で使うときの注意点
負荷とセキュリティへの配慮
tcpdumpはカーネルからパケットをコピーするため、フィルタなしで高トラフィックのサーバーに掛けるとCPUとディスクを消費します。必ずhostやportで絞り、-cや-C/-Wで上限を設けてください。pcapには認証トークンや個人情報が含まれる可能性があるので、保存先の権限とダウンロード後の削除までを決めてから取得するのが実務上のマナーです。コンテナ内の通信を見たい場合は、ホスト側で-i anyを指定すればコンテナの通信も観察できます。
まとめ
パケットキャプチャは「ログに出ないトラブル」に対する最後の切り札です。tcpdumpは-i・-n・host・port・-wの5つを覚えれば実務で使い始められ、Wiresharkは表示フィルタ・Follow TCP Stream・Expert Informationの3機能で大半の解析がこなせます。TLSであってもハンドシェイクの成否やタイミング、再送の有無は観察できるので、「どの層で止まっているか」の切り分けには十分です。まずは開発環境で自分のアプリの通信を1度キャプチャしてみて、正常時のパケットの流れを頭に入れておくと、異常時との差分がすぐ見えるようになります。
ネットワーク層の切り分けからインフラ全体の見直しまで、自社だけでは手が回らない場合は、Harmonic Societyのシステム開発・インフラ支援にご相談ください。
Harmonic Society
この記事の内容、自社の業務でも活かせそうですか?
ローカルLLM・AI・クラウドなどの技術導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK。まずは30分の無料相談から。売り込みはしません。
関連記事
Related / 9 articles
Notes & Insights
- プログラミング
DDoS攻撃の仕組みと対策入門|レイヤー別の防御とCDN・クラウドの活用
DDoS攻撃をボリューム型・プロトコル型・アプリ層に分けて仕組みを解説し、自前サーバーで防げない理由、CloudflareやAWS Shieldの標準防御、オリジンIPの隠し方、レートリミットとBot対策、攻撃を受けたときの初動、費用が跳ね上がるDenial of Walletへの備えまでわかります。
- プログラミング
WAFとは?仕組み・導入パターン・誤検知対策|Webアプリを攻撃から守る実践ガイド
WAFがファイアウォールやIDSと何が違うのか、シグネチャとマネージドルールの仕組み、Cloudflare WAF・AWS WAF・ModSecurityの比較、フォーム送信がブロックされる誤検知の調査と例外設定、ログ監視、WAFが代替できないことまで実践的に解説します。
- プログラミング
セキュリティヘッダー入門|CSP・HSTS・X-Frame-Optionsの設定と効果を実践解説
CSP・HSTS・X-Frame-Options・X-Content-Type-Optionsなど主要セキュリティヘッダーが防ぐ攻撃と、CSPのReport-Onlyからの段階導入、nonce/hash、HSTS preloadの不可逆リスク、Nginx・Next.js・Astroでの設定例、確認方法を解説します。
- プログラミング
クラウドの通信費(Egress)入門|データ転送量課金の仕組みと転送コストを抑える設計
クラウドの「受信無料・送信有料」の原則、AZ間・リージョン間・インターネット向けの単価差、NATゲートウェイ処理料の罠、CDNで転送量を減らす方法、バックアップやログ転送の見落とし、請求書で転送料を特定する手順を解説。想定外の請求を防げます。
- プログラミング
秘密情報をGitに入れない仕組み|.gitignore・git-secrets・履歴から漏れた鍵の削除
APIキーや.envをGitにコミットしてしまう典型経路と、.gitignore・.env.exampleの運用、pre-commitでのgitleaks検知、GitHub secret scanningの活用、漏れた鍵の無効化と履歴書き換え(git filter-repo)の手順を解説。仕組みで再発を防げます。
- プログラミング
開発・ステージング・本番環境の分離設計|環境差分をなくす構成とアクセス制御
開発・ステージング・本番それぞれの目的と、構成をコードで揃える方法、環境別の設定注入、本番データを使わないテストデータ戦略、ステージングの保護(Basic認証・IP制限・noindex)、コストを抑える運用までを解説。環境差分による本番障害を防げます。
- プログラミング
ngrok・Cloudflare Tunnelでローカルを公開|Webhook開発とデモ環境の作り方
NAT内のローカル環境にStripeやLINEのWebhookを届けるトンネリングの仕組みを解説。ngrok・Cloudflare Tunnel・localtunnelの比較、固定ドメインと認証、リクエスト検査、公開時のセキュリティ、自宅サーバー公開への応用までわかります。
- プログラミング
ローカル開発環境のHTTPS化|mkcert・hostsファイル・自己署名証明書の正しい使い方
ローカル開発をHTTPS前提にすべき理由(Secure Cookie・Service Worker・OAuth)と、mkcertでローカルCAを作りhostsで独自ドメインを割り当ててVite・Next.js・Dockerで使う手順を解説。証明書警告を無視する癖の危険も理解できます。
- プログラミング
localhost・0.0.0.0・127.0.0.1の違い|ポートとUnixソケットを理解して「つながらない」を解決
localhost・127.0.0.1・0.0.0.0の意味の違い、Dockerで外から接続できない原因、host.docker.internal、ポート競合の調べ方、Unixソケットの利点と権限、1024未満ポートの制約を解説。「つながらない」を仕組みから解決できます。
Harmonic Society
「読んで終わり」にせず、自社の業務で試してみませんか?
AI・ローカルLLM・クラウドの導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK・売り込みなし。
無料・30分・オンラインOK|1営業日以内に返信します