【実務・中級編】 tracerouteのポート番号制御とファイアウォールによるブロックの検知 – トラブルシューティング&ネットワーク運用監視実践ガイド

深夜3時、データセンターの冷気が肌を刺すNOCルーム。突然、監視モニターが赤く染まった。
「おい、プライベートクラウドとオンプレミスを繋ぐバックボーンの疎通が落ちたぞ。APIのレイテンシも跳ね上がってる」

こういう修羅場で、若いエンジニアが最初にやることといえば ping を連打することだ。しかし、百戦錬磨のインフラエンジニアなら知っている。ping(ICMP Echo)が通らないからといって、ネットワークが完全に死んでいるとは限らない。現代の硬いセキュリティに守られたネットワークでは、ICMPは行儀よく無視されるのがデフォルトなのだから。

では、パケットがどのルーターを通過し、どのファイアウォールの壁で阻まれているのかを正確に暴くにはどうすればいいか?
そう、tracerouteのポート番号制御だ。

今回は、パケットの挙動の裏側にあるRFCの仕様から、ファイアウォール(FW)に阻まれたときのリアルな応答、そして実務で即座に使えるデバッグ手法まで、現場の泥臭い知見を交えて徹底的に解説しよう。

—

1. なぜ ping だけでは不十分なのか? traceroute の基本とUDPの罠

まずは基本のおさらいだ。traceroute は、IPパケットのヘッダーに含まれる TTL (Time To Live) の値を1ずつ増やしながら送信し、経由するルーター(ホップ)から送り返されてくる ICMP Time Exceeded (有効期限切れ)のメッセージをキャッチして経路を可視化する。

だが、標準の traceroute(多くのUNIX系OSの実装)は、宛先に対してUDPパケットの33434番ポート以降を叩き込む。
ここにインフラ運用の落とし穴がある。

現代のWeb API設計やクラウドインフラでは、セキュリティポリシー(NACLやセキュリティグループ、次世代ファイアウォールなど)によって、不要なUDPポート(特に高番ポート)は容赦なくドロップ(破棄)またはリジェクト(拒否)される。
つまり、宛先サーバーが生きていて、Webサービスの TCP/443 は正常に動いていたとしても、標準の traceroute が使う UDP/33434 が途中のFWでブロックされていれば、画面には星印(*)が並び、「まるで経路全体がブラックホールに飲み込まれたかのような」誤った絶望を見ることになるのだ。

—

2. ネットワークの裏側:パケットの往来とRFCが定める挙動

パケットがどのようにルーターを駆け抜け、どこで遮断されるのか。そのシーケンスを頭に叩き込んでおこう。

[Client / 筆者]                       [L3 Router]                    [Firewall / 宛先NW]
    |                                      |                                  |
    |--- (1) UDP (TTL=1, Dst:33434) ------->|                                  |
    |<-- (2) ICMP Time Exceeded -----------| (TTL切れを通知)                   |
    |                                      |                                  |
    |--- (3) UDP (TTL=2, Dst:33434) ----------------------------------------->|
    |                                      |                                  | (ここでFWがUDP/33434をドロップ)
    |--- (4) [タイムアウト: 返答なし(*)] ------------------------------------->|

ここで重要なのは、宛先に到達した際の挙動だ。
もしパケットが無事にファイウォールを抜け、宛先ホストのOSまで届いた場合、OSは「そんな高番UDPポートで待ち受けてるプロセスはないよ!」と返すため、ICMP Destination Unreachable (ポート到達不能、コード3: Port Unreachable)を返送する。これが traceroute の「ゴール到達」の合図となる。

しかし、途中のファイアウォールでブロックされている場合は話が違う。
設定によって挙動が分かれる。

1. ドロップ(Drop / Silent Drop): パケットを完全に闇に葬り去る。traceroute 側からは何の音沙汰もなく、タイムアウト(*)になり続ける。
2. リジェクト(Reject / Prohibited): ICMP Administratively Prohibited などの拒否パケットをわざわざ送り返してくる。

この違いを見極めることが、障害切り分けの第一歩だ。

—

3. 実務で必須! traceroute のポート・プロトコル制御テクニック

「標準のUDPがダメなら、どうするのか?」
答えは簡単だ。実際に自分が通信させたいアプリケーションが使っているプロトコルとポート番号に traceroute を偽装(擬似)させるのだ。

Web APIやHTTPS通信の経路を調べたいなら、当然 TCP の 443 番ポートを指定してパケットを飛ばすべきである。

Linux環境での traceroute (tcptraceroute)

Linuxの標準的な traceroute コマンドでTCPパケットを飛ばすには、-T オプションや専用のコマンドを使用する。

# TCPの443番ポート(HTTPS)を指定してトレースを実行する
# -T: TCPモードを使用
# -p 443: 宛先ポートを443に固定
# -n: DNS逆引きをスキップして高速化(現場の基本)
sudo traceroute -T -p 443 -n api.example.com

このコマンドを打ったとき、途中のホップまではIPアドレスが返ってくるのに、ある特定のホップから先がすべて * になる場合、そのホップに鎮座するファイアウォールが TCP/443 を弾いている(あるいは traceroute が使うSYNパケットを嫌っている)と即座に特定できる。

macOS環境での traceroute

macOSのデフォルト traceroute はオプションが少し異なるが、TCPモードをサポートしている。

# macOSでTCPパケット(ポート80)を使ってトレース
traceroute -I -p 80 example.com
# ※ -I は ICMP ECHO を使うオプション。これもうまくファイウォールをバイパスする定番手法。

—

4. コードとCLIで検証する:Pythonによるカスタムパケット診断

「コマンドラインだけじゃ物足りない、アプリケーション層から特定のポートの挙動をプログラムで検証したい」という実務的なシチュエーションのために、Pythonを使った簡単なソケット接続テストのスクリプトを紹介しよう。

ネットワークエンジニアであっても、Pythonなどのスクリプトでレイヤー4の疎通をサクッと確認できるスキルは、現代のクラウドインフラ運用の現場では強力な武器になる。

import socket
import sys

def check_port_reachability(host, port, timeout=3.0):
    """
    指定されたホストとポートに対してTCPコネクションを試み、
    ファイアウォールによるブロックやタイムアウトを検知する関数
    """
    print(f"[*] 診断開始: {host}:{port} へのTCP接続テスト...")
    
    # IPv4 / TCPソケットの作成
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    
    try:
        # 3wayハンドシェイクの試行
        s.connect((host, port))
        print(f"[+] 成功: {host}:{port} への接続に成功しました。ポートはオープンです。")
    except socket.timeout:
        print(f"[-] 警告: 接続がタイムアウトしました。途中のファイアウォールでドロップされている可能性があります。")
    except ConnectionRefusedError:
        print(f"[!] 応答あり: 接続は拒否されましたが、パケットは宛先(またはFW)まで到達しています(Port Unreachable)。")
    except Exception as e:
        print(f"[X] エラー発生: {e}")
    finally:
        s.close()

if __name__ == "__main__":
    # テスト対象のホストとポート(例: 外部APIサーバーのHTTPSポート)
    target_host = "api.example.com"
    target_port = 443
    
    check_port_reachability(target_host, target_port)

このスクリプトを実行した際、ConnectionRefusedError(接続拒否)が返ってくるということは、ファイアウォールはパケットを通したが、宛先サーバー側でプロセスが動いていないことを意味する。
逆に、socket.timeout(タイムアウト)で数秒間止まった挙句に失敗する場合は、途中のファイアウォールがパケットを黙ってドロップ(黑塗り)している可能性が極めて高い。この違いをコードの例外処理から読み取れるようになると、障害切り分けのスピードが圧倒的に変わる。

—

5. シニアからの現場の教訓:パケットは嘘をつかない

障害対応の現場で最も恐ろしいのは、「なんとなく動かないから、全部のファイアウォールのルールを緩めよう」という、思考停止した安易な変更だ。それをやるとセキュリティ事故の温床になる。

今回解説したように、

  • 標準の traceroute(UDP 33434)はセキュリティ機器の格好の標的になり、容易にドロップされること。
  • 調査したいトラフィックのプロトコル(TCP 443など)に合わせたポート制御(tcptraceroute や -T オプション)を使い分けるべきこと。
  • タイムアウト(*)と、明確なICMP拒否メッセージ、そしてアプリ層でのエラー(Connection Refused)を論理的に切り分けること。

これらを体系的に理解していれば、どんなに複雑なマルチクラウド環境や厳重な社内NWのトラブルであっても、パケットの足跡をたどることで真の原因箇所をピンポイントで炙り出すことができる。

さあ、コーヒーを飲み干したら、次のアラートに備えよう。ネットワークの向こう側で、パケットたちが君の解析を待っている。

コメント

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