「なぜPingは通るのにアプリは繋がらない?」──TCP Tracerouteで魔境のネットワークを暴く
現場で働いていると、一度はこんな事態に遭遇するはずだ。「監視ツールは正常と言っているのに、特定のWeb APIだけがタイムアウトする」。Pingを打てば応答はある。だが、肝心のサービスポートが死んでいるのか、それとも途中のファイアウォール(FW)がL7レベルで遮断しているのか。標準的な traceroute(UDP)や ping(ICMP)だけでは、今の「セキュリティがガチガチに固められた境界」を突破して真実を突き止めることはできない。
今日は、百戦錬磨のインフラエンジニアが最後に行き着く、TCP SYN Traceroute を用いた泥臭い経路診断術を伝授しよう。
—
1. なぜ標準のtracerouteでは「見えない壁」があるのか
標準的な traceroute は、デフォルトでUDPパケット(Linux系)やICMP Echo Request(Windows系)を使用する。しかし、現代のデータセンターやクラウド環境において、これらは「真っ先にドロップされる対象」だ。
- UDP traceroute: 宛先ポートが(たまたま)開いていない限り、途中のルーターはICMP Time Exceededを返すが、FWがUDPのインバウンドを全遮断していれば、ただ「* * *」と表示されるだけの虚無が待っている。
- ICMP ping: 多くのFWはセキュリティポリシーとして「外部からのPing応答」を無効化している。
ここで真の味方となるのが、TCP SYN Traceroute だ。
—
2. TCP SYN Tracerouteのロジック:パケットの「擬態」
TCP SYN Tracerouteは、宛先ポート(例えば 80 や 443)に向けて、あたかも正規のコネクションを確立しようとするかのように SYN パケットを送りつける。
1. TTLの仕掛け: 各ホップ(ルーター)に対して、TTL(Time To Live)を 1 から順にインクリメントしながらパケットを投げる。
2. 中間ノードの反応: TTL が尽きたノードは、ICMP Time Exceededを返してくる。
3. 最終目的地: 宛先に到達すると、ターゲットサーバーは「接続していいよ」と SYN/ACK を返してくる(またはポートが閉じているなら RST を返す)。
この「正規の通信に見える」という性質が、FWのフィルタリングをすり抜ける最大の武器になるのだ。
—
3. 実践:最強のツール tcptraceroute を使いこなす
Linux環境であれば、tcptraceroute をインストールしておくのが鉄板だ。
# Ubuntu/Debian系の場合
sudo apt install tcptraceroute
# 実行例:Webサーバーの443番ポートに向けて経路を追跡
# -n: 名前解決をせずIPで表示(DNS待ちのロスを防ぐ)
# -p 443: TCP 443番ポートを指定
# -q 3: 各ホップで3回送信(パケットロス確認のため)
sudo tcptraceroute -n -p 443 192.168.1.100 80
もし tcptraceroute が入っていない環境でも、traceroute コマンド自体が -T オプション(TCPモード)をサポートしていることが多い。
# 標準のtracerouteコマンドでTCPモードを使用
traceroute -T -p 443 192.168.1.100
—
4. プログラミングで「自作」する経路監視
APIの疎通が断続的に途切れるような嫌な障害の場合、定期的に経路を記録しておくスクリプトがあると便利だ。Pythonの scapy を使えば、生のTCPパケットを自由に操作できる。
from scapy.all import *
# 宛先ターゲット
target = "192.168.1.100"
dest_port = 443
# TTLを1から順に増やす
for i in range(1, 20):
# TCP SYNパケットを作成
pkt = IP(dst=target, ttl=i) / TCP(dport=dest_port, flags="S")
# 送信して応答を待つ
reply = sr1(pkt, timeout=2, verbose=0)
if reply is None:
print(f"{i}: * (Timeout)")
elif reply.type == 11: # ICMP Time Exceeded
print(f"{i}: {reply.src} (Route node)")
elif reply.haslayer(TCP): # 宛先に到達
print(f"{i}: {reply.src} (Target reached!)")
break
—
5. 現場のシニアからの警告:注意すべき「罠」
この手法は強力だが、注意点が一つだけある。「DoS攻撃と誤認される」リスクだ。
特に、SYN パケットを短時間に大量に投げるようなスクリプトを走らせると、相手側のIDS(侵入検知システム)が「SYN Flood攻撃だ!」と判断し、あなたの送信元IPを自動的にブラックリストへ放り込んでしまうことがある。
- Tips: 調査を行う際は、必ず
-q 1(試行回数を1回)にするか、送信間隔(--waitやsleep)を十分に空けること。特に本番環境のクリティカルなサーバーに対して行う場合は、監視担当者に一声かけるのがプロの流儀だ。
—
まとめ:ネットワークの深淵を覗くために
「パケットは嘘をつかない」。これは私が新人の頃、師匠に教わった言葉だ。CLI画面に表示される * * * の羅列に絶望するのではなく、どのレイヤーで、どのポートで、どのようなフラグが弾かれているのかを論理的に分解すれば、必ずボトルネックは特定できる。
次にAPIが繋がらない時は、慌ててログを見る前に tcptraceroute を叩いてみてほしい。君の目の前にある「見えない壁」の正体が、きっと姿を現すはずだ。
コメント