こんにちは!今日もデータセンターの冷気とサーバーの排熱に包まれながら、パケットの行方を追い続けているNOC(ネットワークオペレーションセンター)のシニアエンジニアです。
皆さんは、コマンドプロンプトやターミナルで「なんだかネットワークの調子が悪いな」と思ったとき、反射的に打ち込むコマンドは何でしょうか?おそらく、多くの方が ping と答えるでしょう。でも、その次に打つのは……そう、 traceroute (Windowsなら tracert )ですよね。
「目的地まで、どのルーターを通っているか教えてくれる魔法のコマンド」
そんな風に捉えている方も多いかもしれませんが、実はこのコマンド、IPプロトコルが持つ「寿命(TTL)」という仕組みを逆手に取った、非常にトリッキーで賢いハックなんです。今日は、インフラの世界に足を踏み入れたばかりの皆さんに、この「パケットの旅路」の裏側を、郵便配達の仕組みに例えて優しく紐解いていこうと思います。
準備はいいですか?一歩ずつ、一緒に理解していきましょう!
—
1. パケットには「命の期限」がある?
インターネットの世界を飛び交うデータ(パケット)には、実は「命の期限」が設定されています。これが、今回主役となる TTL(Time to Live) です。
直訳すると「生存時間」ですが、実はこれ、時間(秒数)ではなく 「あと何台のルーターを通過できるか」という「通過可能回数」 のことなんです。
なぜこんなものが必要なのでしょうか?
もしネットワークの設定ミスで、パケットがぐるぐると同じ場所を回り続けてしまったら(これをルーティングループと言います)、ネットワークはパケットで溢れかえってパンクしてしまいます。それを防ぐために、「ルーターを一つ通るたびに、この数値を1ずつ減らしていき、0になったらそのパケットを破棄する」というルールが決まっているのです。
2. Tracerouteの裏技:あえて「期限切れ」を起こす
ここで、 traceroute の天才的な仕組みが登場します。
「目的地までの道順を知りたいけれど、ルーターたちはわざわざ『今ここを通ったよ!』なんて報告してくれない……。じゃあ、あえて途中でパケットを死なせて、その死に際の間際に悲鳴を上げてもらおう!」と考えたわけです。
郵便配達に例えると、こんな感じです。
1. 1通目の手紙: 「1軒目の家で爆発する設定(TTL=1)」にして投函します。
2. 結果: 最初の郵便局(ルーター1)に届いた瞬間、寿命が尽きます。郵便局は「あ、この手紙、ここで期限切れになっちゃったよ。ごめんね」という 「通知(ICMP Time Exceeded)」 を差出人のあなたに送り返します。これで、1軒目の住所がわかります。
3. 2通目の手紙: 今度は「2軒目の家で爆発する設定(TTL=2)」にして投函します。
4. 結果: 1軒目の郵便局は「まだ寿命があるな」とスルー(TTLを1に減らす)し、2軒目の郵便局に届いた瞬間に寿命が尽きます。また通知が届き、2軒目の住所がわかります。
これを目的地にたどり着くまで、1ずつ数値を増やしながら繰り返していく。これが traceroute の正体です。
—
3. 実際にコマンドを叩いてみよう!
理屈がわかったところで、実際の挙動を見てみましょう。LinuxやMacでは traceroute、Windowsでは tracert を使います。
ここでは例として、Googleの公開DNS(8.8.8.8)までの経路を追いかけてみます。
# Linux/macOSの場合
# -n オプションをつけると、名前解決をスキップしてIPアドレスだけで表示されるので速いです
traceroute -n 8.8.8.8
# Windowsの場合(コマンドプロンプトやPowerShell)
# tracert 8.8.8.8
実行すると、以下のような結果が返ってきます(※環境によってIPアドレスは異なります)。
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 192.168.1.1 2.456 ms 1.123 ms 0.987 ms # ← 最初のホップ(自宅のルーターなど)
2 10.20.30.1 10.456 ms 11.234 ms 9.876 ms # ← ISP(プロバイダ)の設備
3 172.16.0.5 15.123 ms 14.567 ms 15.890 ms # ← 中継ルーター
4 * * * # ← 反応がないルーター(後述します!)
5 8.8.8.8 20.123 ms 19.567 ms 20.890 ms # ← ゴール!
結果の見方
- 左側の数字(1, 2, 3…): これが「ホップ数(TTLの設定値)」です。
- IPアドレス: その寿命が尽きた場所(ルーター)の住所です。
- ms(ミリ秒): パケットを投げてから返事が来るまでの往復時間です。通常、3回計測して表示されます。
—
4. 現場エンジニアからの豆知識:なぜ * * * が出るの?
結果の4行目に * * * (アスタリスク)が表示されていますよね?これ、故障でしょうか?
いえ、必ずしもそうではありません。これには主に2つの理由があります。
1. セキュリティ設定(ファイアウォール): 「うちのルーターの住所は教えないよ!」「エラー通知なんて送らないよ!」と、管理者がセキュリティのために応答を拒否している場合があります。
2. 優先順位の低下: ルーターの本業は「パケットを転送すること」です。エラー通知を送るのは二の次なので、忙しいルーターは「今は忙しいから返事はしないよ」と無視することがあります。
ですので、 * * * が出ていても、その先のホップ(この例では5番目)にちゃんと届いているなら、通信経路自体には問題がないと判断できるんです。
—
5. Pythonで自分だけのtracerouteを作ってみる(簡易版)
「仕組みはわかったけど、もっと深く知りたい!」という好奇心旺盛な方のために、Pythonを使って「TTLを1ずつ増やして送信する」というロジックをシミュレートするコードを書いてみました。
※実際に動作させるには scapy というライブラリが必要ですが、ここでは「考え方」をコードのコメントで読んでみてください。
# tracerouteの考え方を理解するための擬似コード
# 実際には管理者権限とscapyライブラリが必要です
from scapy.all import IP, ICMP, sr1
def simple_traceroute(target_ip):
print(f"{target_ip} への経路を探索します...")
# TTLを1から最大30まで増やしながらパケットを送る
for ttl in range(1, 31):
# IPヘッダーのTTLフィールドに現在の数値をセット
# ICMPのEcho Request(いわゆるping)を作成
packet = IP(dst=target_ip, ttl=ttl) / ICMP()
# パケットを送信して、返信を待つ(タイムアウトは2秒)
reply = sr1(packet, verbose=0, timeout=2)
if reply is None:
# 返信がない場合(* * * に相当)
print(f"{ttl}: * * *")
elif reply.type == 11:
# type 11 は "Time Exceeded"(寿命切れの通知)
# これが届いたら、そのルーターのIPを表示して次へ
print(f"{ttl}: {reply.src}")
elif reply.type == 0:
# type 0 は "Echo Reply"(目的地に無事到着!)
print(f"{ttl}: {reply.src} [到達!]")
break
# 実行イメージ
# simple_traceroute("8.8.8.8")
おわりに
いかがでしたでしょうか?
普段何気なく使っている traceroute も、その裏側では「パケットの寿命」というルールを利用した、健気で泥臭いやり取りが行われているんです。
「TTLが1減るごとに、ネットワークの階段を一段ずつ降りていく」
そんなイメージを持てるようになると、ネットワークトラブルの際も「あ、ここで止まっているということは、この先のルーターが怪しいな」と、パケットの気持ちになって考えられるようになります。
インフラの世界は一見無機質ですが、こうした仕組みを知ると、少しだけ愛着が湧いてきませんか?これからも一歩ずつ、一緒にパケットの旅を楽しんでいきましょう。
それでは、また次のトラブルシューティング……あ、いや、次の記事でお会いしましょう!応援しています!
コメント