【実務・中級編】 TCPベースのtracerouteとファイアウォール透過性の検証 – トラブルシューティング&ネットワーク運用監視実践ガイド

夜中の3時、PagerDutyのけたたましいアラート音で叩き起こされた経験はないだろうか。「特定の外部Web APIへの接続がタイムアウトするようになった。しかし、通常の ping は通る」。

この瞬間、NOCのベテランなら誰もが苦い笑みを浮かべる。犯人は大抵、途中のどこかにそびえ立つお堅いファイアウォールや、気まぐれなステートフル・インスペクションだ。ICMPなんてものは、セキュリティポリシーが厳格な環境では真っ先にドロップされるか、最優先で後回しにされる「お飾り」にすぎない。

経路上のL4(レイヤー4)の現実を暴き出すには、ICMPではなく「本番トラフィックと同じ装いをしたTCPパケット」を放つ必要がある。今回は、標準的な traceroute の限界を突破し、ファイアウォールの裏側を丸裸にするTCPベースのtracerouteと、その実務的な活用法について、現場の泥臭い知見を交えて徹底的に解説しよう。

—

なぜICMPベースのtracerouteでは「見えない壁」に阻まれるのか?

皆さんがよく使う標準的な traceroute(Linuxのiputils版など)は、デフォルトでUDPパケット、あるいはICMPエコーリクエストを使用する。

しかし、現代のクラウドアーキテクチャやエンタープライズネットワークにおいて、これらは全くあてにならない。多くのステートフル・ファイアウォールや次世代FW(NGFW)は、UDPのハイポートあてパケットやICMPを「怪しい通信」とみなして容赦なくドロップする。結果として、ターミナル画面には延々と * * * が並び、途中のホップ数が全く分からないという「ブラックボックス地獄」に陥る。

ここで登場するのが、TCPベースのtracerouteだ。

TCPベースのtracerouteが最強である理由

Web APIやHTTPS通信の本質はTCP(主にポート 443 や 80)である。ファイアウォールやロードバランサー(LB)は、当然ながらこれらのポートを通すように設定されている。

TCPベースのtracerouteは、宛先のWebサーバーの 443 番ポートなどに対して、あえてコネクション確立前の TCP SYN パケットを投げる。このパケットのIPヘッダーにある TTL (Time To Live) を 1、2、3……とインクリメントしながら送信することで、経路上のルーターから返ってくる ICMP Time Exceeded をキャッチし、正確なL4の経路を描き出すのだ。

さらに素晴らしいことに、宛先サーバーに到達した際、もしポートが開いていれば TCP SYN-ACK が、閉じているかファイアウォールで明示的に拒否されていれば TCP RST が返ってくる。これにより、「単にルーターが応答しないのか、それとも本当に宛先まで届いてポートで弾かれているのか」を完璧に切り分けることができる。

—

現場で使える! tcptraceroute と nmap の実践コマンド

Linux環境であれば、tcptraceroute コマンドや、スイスアーミーナイフである nmap を使うのが手っ取り早い。インフラエンジニアなら、踏み台サーバーのツールボックスに必ず入れておくべきコマンドだ。

1. tcptraceroute を使った基本的な経路探索

特定のAPIエンドポイント(例: api.example.com)の 443 番ポートに対して、TCPベースのtracerouteを実行してみよう。

# api.example.comの443番ポート(HTTPS)へTCP SYNパケットを用いたtracerouteを実行
sudo tcptraceroute -n -p 443 api.example.com
  • --n: DNSの逆引きをスキップして高速化する(現場では名前解決のタイムアウトでイライラしたくないので必須)。
  • -p 443: 宛先のポート番号を指定。APIの仕様に合わせて 80 や独自のポート番号(例: 8443)に変更可能。

2. nmap を使った高度なTCP Traceroute

tcptraceroute が入っていない軽量なコンテナ環境や、より詳細なパケット制御を行いたい場合は nmap が重宝する。

# nmapのTCP SYN traceroute機能を利用し、途中のL4デバイスの挙動を暴く
sudo nmap --traceroute -p 443 --send-ip api.example.com

--traceroute オプションをつけるだけで、nmapは通常のポートスキャンと同時に、パケットのTTLを操作した経路探索をバックグラウンドで実行してくれる。ファイアウォールが途中でパケットを食っていないか、どのホップでレイターがレイヤー4のヘッダーを見てブロックしているかが一目瞭然だ。

—

通信フロー(シーケンス)の裏側を覗く

言葉だけではイメージしにくい読者のために、TCPベースのtracerouteがネットワーク上でどのようにパケットをやり取りしているのか、その内部シーケンスを整理しておこう。

[Client (NOC端末)]                    [Router A (TTL=1)]        [Firewall/LB]        [Target API Server]
       |                                     |                        |                        |
       |--- (1) TCP SYN (TTL=1) ------------>|                        |                        |
       |                                     |                        |                        |
       |<-- (2) ICMP Time Exceeded ----------|                        |                        |
       |     (ルーターAがTTL切れを通知)      |                        |                        |
       |                                     |                        |                        |
       |--- (3) TCP SYN (TTL=2) ------------------------------------->|                        |
       |                                     |                        | (ファイアウォール通過)  |
       |<-- (4) ICMP Time Exceeded -----------------------------------|                        |
       |     (FW/LBがTTL切れを通知)          |                        |                        |
       |                                     |                        |                        |
       |--- (5) TCP SYN (TTL=3) -------------------------------------------------------------->|
       |                                     |                        |                        (ポートオープン)
       |<-- (6) TCP SYN-ACK -------------------------------------------------------------------|

1. クライアントは TTL=1 を設定した TCP SYN パケットを送信する。
2. 最初のルーター(Router A)がパケットを受け取り、TTLをデクリメントした結果 0 になったため破棄し、クライアントへ ICMP Time Exceeded を返す。これで1ホップ目が判明する。
3. 次に TTL=2 で送信し、今度は途中のファイアウォールやロードバランサーまで到達させる。
4. 最終的に TTL が十分に大きくなり、ターゲットのWeb APIサーバーまでパケットが到達する。
5. サーバー側が生きていれば TCP SYN-ACK(拒否なら TCP RST)を返すため、「ここまでは完全にL4の疎通が取れている」と確信できる。

—

アプリケーション開発者・インフラ担当者が知るべき実務での活用とトラブルシューティング

この手法がなぜWeb API設計やインフラ運用において強力なのか。それは「アプリケーション層のエラーと、ネットワーク層のエラーを完全に切り分けられるから」だ。

例えば、自社のマイクロサービスから外部の決済APIを叩く際、以下のようなPythonスクリプト(requests や低レイヤーのソケット)や、開発環境からの curl でエラーが出たとしよう。

import socket
import sys

def verify_tcp_route(target_host, target_port):
    print(f"[*] ターゲット {target_host}:{target_port} へのTCP到達性を検証します...")
    
    # ソケットの作成 (IPv4, TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(5.0) # 5秒でタイムアウト
    
    try:
        # 実際にTCP 3wayハンドシェイクを試みる
        s.connect((target_host, target_port))
        print(f"[+] 成功: {target_host}:{target_port} へのTCP接続が確立できました。L4層は健全です。")
    except socket.timeout:
        print("[-] タイムアウトエラー: 途中のファイアウォールでドロップされているか、ルーティングに問題があります。")
    except ConnectionRefusedError:
        print("[!] 接続拒否: ホストには到達しましたが、ポートが閉じているか、サービスが停止しています。")
    except Exception as e:
        print(f"[X] 予期せぬエラーが発生しました: {e}")
    finally:
        s.close()

if __name__ == "__main__":
    # 例として外部APIのエンドポイントを指定
    verify_tcp_route("api.example.com", 443)

このPythonスクリプトや、お馴染みの curl -v https://api.example.com でタイムアウトが発生した際、本稿で紹介したTCPベースのtracerouteを組み合わせることで、次のような切り分けが瞬時に完了する。

  • ケースA:途中のホップ(例: ホップ数 5)でピタッと応答が途絶える
  • $\rightarrow$ 自社側のネットワーク、あるいはプロバイダ、あるいは宛先手前の巨大なセキュリティゲートウェイで特定のトラフィックがフィルタリングされている。ネットワークチームへのエスカレーション材料が揃う。
  • ケースB:最終ホップまで ICMP Time Exceeded が返り、最後に宛先から TCP RST が返ってくる
  • $\rightarrow$ パケットは物理的・論理的に完璧に到達している。原因はネットワークではなく、宛先サーバー側のWAF(Web Application Firewall)がアプリケーション層(HTTPヘッダーやIPレピュテーション)でアクセスをブロックしている。APIキーやホワイトリストの確認が必要。

—

シニアエンジニアからの教訓

ネットワークのトラブルシューティングにおいて、「なんとなく ping を打って通らないからおしまい」というアプローチは、もはやプロの仕事とは言えない。クラウド全盛の時代、ネットワークは複雑なカオスの上に成り立っており、表面的に見えている挙動と内部の実態は異なることが多い。

「どのレイヤーでパケットがどのように扱われているか」を常に意識し、アプリケーションが依存しているL4の文脈(今回の場合はTCPポートとSYNパケット)に合わせた診断ツールを使いこなすこと。これこそが、障害切り戻しの時間を劇的に短縮し、チームからの厚い信頼を勝ち取るための最短ルートである。

さあ、次の夜間障害が起きたときには、ただの ping ではなく、誇りを持って tcptraceroute のコマンドを叩いてほしい。パケットは、いつだって真実を語っているのだから。

コメント

タイトルとURLをコピーしました