ネットワークの向こう側にあるサーバーに、思い通りにデータが届かない。そんな「見えない壁」にぶつかったとき、インフラエンジニアが真っ先に手に取る三種の神器といえば、何と言っても ping と traceroute、そして dig ですよね。
特に traceroute は、データがどのルーターを経由して目的地までたどり着いているのかを、まるで地図を広げるかのように可視化してくれる魔法のようなツールです。普段は何気なく使っているこの traceroute ですが、裏側で一体どんなパケットが飛び交っているのか、気になったことはありませんか?
今回は、多くのUnix系OS(LinuxやmacOSなど)の traceroute が採用している「UDPベースの仕組み」と、ちょっぴり変わった「高いポート番号の利用」について、現場の泥臭いエピソードを交えながら、一歩ずつ優しく紐解いていきましょう!
—
郵便配達で例える「traceroute」の基本理念
まず、ネットワークの通信を「手紙の郵送」に例えてみましょう。
ping が「宛先の家が生きていて、ポストに手紙が入るか(返事が返ってくるか)を確認するチャイム」だとしたら、traceroute は「宛先までの間に、どんな経由地のポスト(ルーター)を通ってきたのか」を完全に暴き出す追跡調査です。
普通の郵便なら、中継する郵便局のハンコが手紙の裏にペタペタと押されていきますよね。でも、インターネットの世界では、ルーターが勝手にそんなおせっかいなハンコを押してくれません。
そこで、Unix系の traceroute は、こんな「ちょっとしたイタズラ(巧妙な仕組み)」を使います。
1. 最初は「ご近所(1つ目のルーター)まででいいから、配達員さん、すぐに力尽きて倒れてください!」という有効期限(TTL)付きの手紙を出します。
2. 期限切れになったルーターは、「おっと、この手紙はここまで運べないよ!」と、わざわざ差出人(私たちのPC)に「配達失敗(Time Exceeded)」の小包を送り返してくれます。
3. この小包の送り主を調べることで、「1つ目のルーターのIPアドレス」が判明します。
4. 次は「2つ目のルーターまで!」と有効期限を1つ伸ばして、同じことを繰り返します。
こうして、宛先までのルートをまるで階段を1段ずつ登るように暴いていくわけです。見事な知恵の輪ですよね!
—
なぜ「UDP」で、しかも「高いポート番号(33434〜)」を使うのか?
さて、ここからが今回の本題です。
データを届けるための通信手段には、主に TCP や UDP があります。Web閲覧なら TCP を使うのが王道ですが、なぜ一般的なUnix系の traceroute は、わざわざ UDP のパケットを投げるのでしょうか?
そして、なぜ宛先のポート番号に 33434 や、それ以降の「変に中途半端で高い数字」を指定するのでしょうか?
1. 宛先サーバーに「そんな部屋番号はない!」と言わせるため
ビル(サーバー)に荷物を届けるとき、正確な「部屋番号(ポート番号)」を指定する必要がありますよね。
Webサーバーなら 80 番や 443 番というお馴染みの部屋がありますが、traceroute が目指すのは「ただの経路の調査」であり、宛先のサーバーで特定のアプリを動かしたいわけではありません。
そこで、Unix系の traceroute は、「絶対に誰も使っていなさそうな、めちゃくちゃ高いポート番号(33434番以降)」に向かってUDPパケットを投げつけます。
宛先のサーバーにパケットが届くと、サーバーのOSはこう思います。
*「えっ? 33434番なんて、うちのどのアプリも聞いてない(待ち受けてない)ポートだけど……? よし、送り主に『そんなポート番号の部屋はありません!』ってエラーを返そう!」*
このサーバーから送られてくるエラーメッセージこそが、「ICMP Port Unreachable(ポート到達不能)」です。
traceroute は、このエラーが返ってきた瞬間を見て、こう確信します。「おっ、無事に宛先のサーバーまでパケットが届いたぞ! これで今回の追跡調査は終了だ!」と。
もし、もしも運悪くその高いポート番号を使っている変態的なアプリが宛先サーバーで動いていたとしたら? パケットがスルーされてしまい、うまくゴール判定ができないなんていうトラブル(現場のあるあるです)も起きたりします。歴史的な背景とOSの仕様が絶妙に噛み合った、実に泥臭くて面白い仕組みですね。
—
実際に手を動かしてパケットの挙動を覗いてみよう
百聞は一見にしかず。実際にLinux環境などで traceroute を実行し、その裏側で何が起きているのかをシミュレータ的に確認してみましょう。
例えば、GoogleのパブリックDNS(8.8.8.8)に対して traceroute を実行してみます。
# ネットワーク経路をUDPベースで追跡するコマンド
traceroute 8.8.8.8
実行すると、以下のような出力が画面に流れます。
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 gateway (192.168.1.1) 2.123 ms 1.845 ms 1.712 ms
2 10.0.0.1 (10.0.0.1) 5.432 ms 5.101 ms 4.987 ms
3 ns.provider.net (203.0.113.5) 12.345 ms 11.876 ms 12.111 ms
...
15 dns.google (8.8.8.8) 14.567 ms 14.234 ms 14.456 ms
このとき、パケットキャプチャツールである tcpdump を裏で同時に回しておくと、宛先ポートがしっかりと 33434 から始まっている様子が生々しく観察できます。
# パケットキャプチャで宛先ポートが33434番からインクリメントしている様子を確認する例
sudo tcpdump -nn -i eth0 "udp and portrange 33434-33464"
実行結果のイメージ:
12:34:56.789012 IP 192.168.1.100.54321 > 8.8.8.8.33434: UDP, length 28
12:34:56.791234 IP 192.168.1.1 > 192.168.1.100: ICMP time exceeded in-transit
12:34:57.789012 IP 192.168.1.100.54322 > 8.8.8.8.33435: UDP, length 28
12:34:57.793456 IP 10.0.0.1 > 192.168.1.100: ICMP time exceeded in-transit
見事に、送信するたびに宛先ポート番号が 33434、33435 と1つずつ増えているのが分かりますよね。これは、途中のルーターやファイアウォールが「過去に送ったパケットの返事だ」と誤認してキャッシュを返してしまわないように、プローブ(調査用パケット)ごとに一意な識別子を持たせるための一工夫でもあるのです。
—
現場で役立つ!ファイアウォール(FW)とtracerouteの落とし穴
シニアエンジニアとして現場にいると、若手エンジニアからよくこんな相談を受けます。
*「先輩!自社のサーバーに向けて traceroute を打ったんですけど、途中のルーターまでは綺麗に見えるのに、最後のゴール地点だけ『* * *』になってタイムアウトしちゃうんです! サーバーが落ちてるんでしょうか?」*
この問いに対する答えの多くは、「ファイアウォールがUDPのパケットや、そこから返るICMPエラーを冷たくブロックしているから」です。
セキュリティの観点から、外部からのよく分からない高いポート番号宛てのUDP通信をすべて「破棄(Drop)」するようにファイアウォールが設定されていることは、インフラの現場ではごくごく標準的です。また、宛先サーバー自身が「余計なICMPエラーを返さない(セキュリティ上の理由でICMPをレートリミットまたは無効化している)」こともよくあります。
そのため、
- 「経路の途中が見えない」= そのルーターがTTL切れのICMPを返すのを拒否している
- 「ゴールが見えない」= 宛先サーバーまたは手前のFWがUDP 33434番以降やICMP Port Unreachableをブロックしている
という背景を理解しておくだけで、無駄なパニックを防ぐことができます。もしどうしてもTCPベースで経路を調べたい場合は、現代のOSやツールであれば -T オプション(TCP SYNベースのtraceroute)を使うという選択肢もあることを覚えておくと、いざという時に非常に頼りになりますよ。
—
まとめ
いかがでしたでしょうか?
一見すると難解に見える traceroute の「UDPパケットによる高いポート番号(33434〜)の利用」も、郵便配達の仕組みや、ビル(サーバー)への手紙の投げ入れに置き換えてみると、エンジニアたちの先人たちが編み出した見事な「知恵の結晶」であることが実感できたのではないでしょうか。
日々の運用監視やトラブルシューティングでコマンドを叩くとき、黒い画面の向こう側でパケットたちがどんなドラマを繰り広げているのか、少しでも想像力を膨らませてもらえたら嬉しいです。
それでは、次回のインフラ裏話でお会いしましょう! NOCシニアエンジニアがお届けしました。
コメント