深夜3時、ピッチリと冷えたデータセンターの片隅で、あるいは自宅のデスクでディスプレイの青白い光に照らされながら、あなたは「なぜこのパケットはルーターの向こうへ抜けないんだ…」と頭を抱えていないだろうか。
ネットワークエンジニアやWebインフラの構築・運用を担う者にとって、パケットの道筋を追う traceroute は、いわば暗闇の中を照らすヘッドライトのようなものだ。しかし、このヘッドライト、実はOSやツールの実装によって照らし方が全く違うということをご存知だろうか。
「Windowsからだと通るのに、なぜかLinuxコンテナ(AlpineやUbuntu)からだと途中で星マーク(*)のタイムアウトになる」
「ファイアウォール(FW)やロードバランサー(LB)の設定を変えていないのに、監視サーバーの切り替えだけで疎通診断の結果が変わった」
こうした現場の怪奇現象の裏には、大抵の場合、「ICMP版」と「UDP版」の traceroute が持つ仕様と、ステートフルなファイアウォールの挙動のギャップが隠されている。
今回は、数々の修羅場をくぐってきたNOCのシニアエンジニアである私から、この traceroute の深淵なる世界を紐解こう。実務で即座に役立つパケットの挙動、OSごとの違い、そしてデバッグの勘所を叩き込んでいく。
—
1. なぜ「道筋を追う」必要があるのか?:TTLとICMP Time Exceededの基本
まずは基本のおさらいだ。traceroute(Windowsでは tracert)が、どうやって宛先までのルーターのホップ(中継機器)を暴き出しているのか。そのメカニズムは、IPパケットのヘッダーに含まれる TTL(Time To Live / ホップリミット) というカウンターの仕組みを利用している。
1. TTL=1のパケットを送る: 最初の中継ルーターに届いた時点でTTLが「0」になり、ルーターはパケットを破棄する。同時に、送信元へ「おい、TTLが切れたぞ」というエラーメッセージ、すなわち ICMP Time Exceeded (Type 11, Code 0) を送り返す。これで1ホップ目のルーターのIPアドレスが判明する。
2. TTLを1つずつ増やす: 次は TTL=2 でパケットを送り、2ホップ目のルーターから ICMP Time Exceeded をもらう。これを宛先に届くまで繰り返す。
3. 宛先に到達する: 宛先にパケットが届くと、今度は「そんな高ポートは開いてねえよ」あるいは「届いたぜ」という別の応答が返り、一連の旅が完了する。
この「TTL切れの通知を拾う」という基本原則は共通だが、「中身のパケットをどう作るか」において、OSやツールごとに大きな分岐点が存在する。
—
2. 最大の罠:ICMP版 vs UDP版 の決定的な違い
ここが本日のハイライトだ。traceroute の実装は、主に以下の2つの流派に分かれている。
- UDP版(UNIX / Linux標準の
tracerouteコマンド) - ICMP版(Windowsの
tracertコマンド、およびLinuxのtraceroute -I)
この違いが、ネットワーク上のセキュリティ機器(ファイアウォールやセキュリティグループ)を通過できるかどうかの運命を分ける。
① UNIX / Linux系(デフォルト)の「UDP版」の挙動
Linuxの標準的な traceroute は、宛先に対して「UDPデータグラム」を送信する。このとき、宛先ポート番号は通常 33434 から始まり、ホップが進むごとにインクリメントされる(33434, 33435, 33436…)。これは、通常のアプリケーションが使わないであろう「使われていなさそうな高いポート番号(High Port)」をあえて狙っている。
- 途中のルーターの挙動: TTL切れを起こしたルーターは、送信元へ
ICMP Time Exceededを返す(これはどのプロトコルでも共通)。 - 宛先ホストに到達した時の挙動: 宛先サーバーにUDPパケットが届くと、サーバー側で「そんな高ポートで待ち受けてるプロセスはないよ」と判断し、ICMP Destination Unreachable (Port Unreachable, Type 3, Code 3) を送り返す。送信元はこのエラーを受け取ると、「あ、宛先に着いたんだな」と理解してプローブを終了する。
② Windows系(および -I オプション)の「ICMP版」の挙動
一方、Windowsの tracert や、Linuxで -I(または icmp)オプションを指定した場合は、UDPではなく「ICMP Echo Request(いわゆるpingのパケット)」をそのまま使用する。
- 途中のルーターの挙動: TTL切れを起こすと、通常通り
ICMP Time Exceededを返す。 - 宛先ホストに到達した時の挙動: 宛先サーバーにICMP Echo Requestが届くと、サーバーは通常のpingに応答するように ICMP Echo Reply を返す。これで送信元は宛先到達を検知する。
—
3. なぜこれでトラブルが起きるのか?(通信フローとFWの壁)
実務で最もハマるのが、「社内やクラウドのファイアウォール(Security Group / ACL)が、UDPの高ポートをブロックしている」というケースだ。
[Linux Client (UDP 33434+)]
│
▼ (TTL=1)
[Router A] ──(ICMP Time Exceeded)──> [Client] (1ホップ目成功)
│
▼ (TTL=2)
[Firewall / Security Group]
│
├─× (UDP 33434-33534 をブロック!) ──> パケット消滅(星マーク * が並ぶ)
│
[Destination Server]
Linuxのデフォルト(UDP版)で traceroute を実行すると、宛先へ向けてUDPの33434番以降のポートを叩く。もし途中のファイアウォールや宛先サーバーの手前で「外から来るよく分からない高ポート宛てのUDP」をセキュリティポリシーでドロップ(破棄)していると、パケットはそこで遮断される。結果として、宛先まで生きているはずなのに、途中からずっと * * * が続き、経路調査が失敗するという現象が起きる。
しかし、ここで -I オプションをつけてICMP版に切り替えてみるとどうだろうか。
# LinuxでICMP版(Windowsのtracertと同じ挙動)を実行する
$ traceroute -I example.com
ファイアウォールが通常の ping(ICMP Echo)を許可していれば、UDP版では通らなかった経路が、何事もなかったかのように綺麗に最後まで表示される。
「ネットワーク経路の障害なのか、単にファイアウォールがUDPの高ポートを塞いでいるだけなのか」――この切り分けができないと、夜間障害の切り分けで無駄な数時間を溶かすことになりかねない。
—
4. 実務で役立つ!ツールの使い分けとコマンド実践
インフラエンジニアやSREとして現場に立つなら、OSや環境によるツールの違いを頭に叩き込み、必要に応じてプロトコルやポートを意図的にコントロールできるようにしておくべきだ。
各種OS・ツールの比較表
| 環境 / ツール | デフォルトのプロトコル | 到達確認のトリガー | 特徴・注意点 |
| :— | :— | :— | :— |
| Windows (tracert) | ICMP | ICMP Echo Request | FWでpingが通れば経路が見えやすい。 |
| Linux (traceroute) | UDP | UDP (Port 33434〜) | セキュリティ機器にブロックされやすい。 |
| macOS (traceroute) | UDP (またはICMP指定可) | UDP | Linux版とほぼ同等。-I でICMPに変更可能。 |
| tcptraceroute | TCP | TCP SYN (Port 80/443等) | Web系エンジニアの強い味方。HTTP/HTTPSの経路を完全に模倣できる。 |
実務で使えるデバッグコマンド集
A. Linuxで確実に経路を追いたい時(ICMPモード)
UDPが弾かれている疑いがある場合は、まず -I を試す。これだけで「ただのFWの仕様」だったことが即座に判明する。
# ICMP Echoをベースにしたtracerouteの実行
$ traceroute -I 192.168.100.1
B. Webサービス(HTTP/HTTPS)の向こう側を正確に測りたい時 (tcptraceroute)
「Webサーバーへのルーティングや、途中のロードバランサーの挙動を見たい」というときは、UDPやICMPではなく、実際のWebトラフィックと同じTCPパケットを使った tcptraceroute(または traceroute -T)を使うのが最も実務的だ。
# Linux標準のtracerouteでTCP SYNパケットを使う(ポート443を指定)
$ traceroute -T -p 443 api.example.com
このコマンドの素晴らしいところは、「実際にクライアントがAPIサーバーへHTTPSリクエストを送る際のパケットと全く同じ経路(TCPポート443)」をシミュレートできる点にある。特定のロードバランサーが特定のTCPポートに対してのみ異なるルーティングをしている場合でも、この方法なら正確に追跡できる。
—
5. 自動化スクリプトでの落とし穴:PythonやNode.jsでのネットワーク診断
インフラの監視システムや、自作のWeb API診断ツールなどで「プログラムからネットワーク経路を調べたい」という要件に直面することもあるだろう。ここで、Pythonの subprocess や外部ライブラリを使って実装する際の注意点を述べておきたい。
サーバーサイドで動作するプログラム(例えばDockerコンテナ上のPythonなど)から traceroute を実行する場合、その実行環境のOSがLinuxである以上、デフォルトではUDP版が走る。
もし監視対象のサーバーやクラウド環境がUDP高ポートを厳しく制限している場合、プログラムからの定期実行がすべてタイムアウト(あるいは不正確な結果)になる。そのため、プログラム内から呼び出す際も、環境に応じたオプションのチューニングが必要だ。
以下に、Pythonで安全に traceroute をラップし、結果をハンドリングする実用的なコードスニペットを示す。
import subprocess
import sys
def run_traceroute(target_host, use_icmp=True):
"""
指定されたホストに対してtracerouteを実行し、結果を返す関数
:param target_host: 宛先ホスト名またはIPアドレス
:param use_icmp: Trueの場合はICMP版(-I)、Falseの場合はデフォルト(UDP)
"""
# 基本コマンドの組み立て
cmd = ["traceroute"]
if use_icmp:
# ファイアウォール透過性を考慮してICMPモードを追加
cmd.append("-I")
cmd.append(target_host)
print(f"[*] 診断実行中: {' '.join(cmd)}")
try:
# サブプロセスとして実行し、標準出力とエラーをキャプチャ
result = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
timeout=30 # タイムアウトは30秒に設定
)
if result.returncode != 0:
print(f"[!] 警告: コマンドが異常終了しました:\n{result.stderr}", file=sys.stderr)
return result.stdout
except subprocess.TimeoutExpired:
print("[!] エラー: tracerouteの実行がタイムアウトしました。", file=sys.stderr)
return None
except FileNotFoundError:
print("[!] エラー: tracerouteコマンドが見つかりません。インストールを確認してください。", file=sys.stderr)
return None
if __name__ == "__main__":
# 使用例:CloudflareのパブリックDNSに対してICMPモードで実行
target = "1.1.1.1"
output = run_traceroute(target, use_icmp=True)
if output:
print("\n--- 診断結果 ---")
print(output)
このスクリプトをWeb APIのバックエンドやヘルスチェックツールに組み込む際は、ユーザーからの入力値(target_host)に対するバリデーション(インジェクション対策)を忘れないこと。ネットワークツールの実行はセキュリティ上のリスクになりやすいため、厳格な正規表現等でIPアドレスやホスト名の形式を検証することが鉄則だ。
—
6. まとめ:シニアエンジニアからのメッセージ
パケットの挙動は嘘をつかない。しかし、私たちが使っている「ツール」や「OSのデフォルト実装」が、良かれと思って隠している仕様や、セキュリティ機器による「検閲」によって、見えている景色が歪められることは多々ある。
- 「UDP版」と「ICMP版」の根本的な違いを理解しているか?
- 途中のファイアウォールがどのポートをブロックしているか想像できているか?
- Web APIの通信を追うために、TCPベースのプローブ(
tcptraceroute)を使いこなせているか?
これらを意識するだけで、ネットワーク障害に直面したときの初動のスピードは劇的に変わる。「なぜ繋がらないのか」ではなく、「どのプロトコルのどのパケットが、どのポリシーで弾かれているのか」というレイヤーで物事を捉えられるようになると、インフラエンジニアとしての視野は一段と広がるはずだ。
さあ、ログとパケットを味方につけて、次のトラブルも鮮やかに解決してやろう。
コメント