なぜ「つながらない」のか?ICMP Type 3が語るネットワークの真実
ネットワークエンジニアとして現場に立っていると、「APIが叩けない」「サーバーに疎通しない」という悲鳴のようなアラートに毎日直面します。その際、パケットキャプチャを広げて真っ先に確認するのは、実はステータスコードよりも、この ICMP Type 3 です。
教科書には「宛先到達不能」と一行で書かれていますが、実務においては、このパケットこそが「誰が、どこで、なぜ通信を拒絶したのか」を教えてくれる唯一のヒントです。今日は、RFC 792の仕様を紐解きながら、現場で役立つ ICMP Type 3 の深淵を覗いていきましょう。
—
ICMP Type 3:パケットが発する「遺言」
ICMP Type 3(Destination Unreachable)は、ルーターやホストが「これ以上パケットを先に送れない」と判断したときに生成されます。単なるエラー通知ではなく、送信元に対する「諦めろ」という親切な警告です。
特に注目すべきは Code フィールドです。ここには、パケットがどこで、なぜ挫折したのかという詳細な理由が刻まれています。
現場で頻出する主要な Code 値
- Code 0 (Net Unreachable): ルーティングテーブル上に宛先ネットワークへの経路が存在しない。主にBGPの設定ミスや、ルート広報の失敗で発生します。
- Code 1 (Host Unreachable): ネットワークまでは届いたが、宛先ホストが応答しない。ARP解決に失敗している場合や、スタティックルートのネクストホップが死んでいる時に見かけます。
- Code 3 (Port Unreachable): これがWeb API開発で最も重要です。UDP通信において、宛先ポートで待ち受けているアプリケーションが存在しないことを示します。TCPなら
RSTパケットが返りますが、UDPではこのコードが頼りです。 - Code 4 (Fragmentation Needed): いわゆる「PMTUD (Path MTU Discovery) 失敗」の主犯格です。MTUサイズを超過し、かつ
DF (Don't Fragment)ビットが立っているパケットをルーターが破棄した際に送られてきます。
—
現場でのデバッグ:パケットの挙動を追う
例えば、PythonでUDPソケットを用いたAPI通信を行い、宛先ポートが閉じている場合、OSは即座に ICMP Type 3 Code 3 を受け取り、アプリケーションへ ConnectionRefusedError を伝播させます。
Pythonによる疎通確認サンプル
import socket
# 宛先サーバーとポート
target_host = "192.168.1.100"
target_port = 8080
try:
# UDPソケットを作成
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# パケットを送る(実際には届かない前提)
client.sendto(b"Hello", (target_host, target_port))
# ここでICMPエラーが返ってくると、受信時にエラーが発生する可能性がある
# OS側のスタックがICMPを処理し、ソケットに通知を上げる
data, addr = client.recvfrom(1024)
except ConnectionRefusedError:
# 現場で見るべきはここ!
# OSがICMP Type 3 Code 3 を受け取り、ユーザー空間に伝えた証拠
print("宛先ポートが閉じています (ICMP Type 3 Code 3)")
except Exception as e:
print(f"予期せぬエラー: {e}")
—
Web API運用における注意点:MTUとCode 4
最近のクラウド環境で最も厄介なのは Code 4 です。VPN越しの通信や、トンネリングプロトコル(VXLANなど)を使用している場合、IPパケットがMTUサイズをわずかに超過するだけで、ルーターはパケットを「黙って」捨てることがあります。
もしあなたのWeb APIが「小さなリクエストは通るのに、大きなJSONや画像をPOSTするとタイムアウトする」という挙動を示すなら、それは間違いなく Code 4 を伴うMTU問題です。
Linuxで確認する際のコマンド
tcpdump を使って、実際に ICMP Type 3 が返ってきているかを確認する鉄板コマンドです。
# ICMPプロトコルかつType 3をキャプチャする
# -n で名前解決を抑制、-v でパケットの詳細を表示
sudo tcpdump -ni eth0 icmp and 'icmp[icmptype] == 3' -vv
もし結果に frag needed and DF set と表示されたら、それは送信元クライアントか、経路上のMTU設定を調整しなければならないサインです。iptables や nftables で TCP MSS Clamping を設定するのが、運用の現場では最も手っ取り早い解決策になります。
# iptablesでMTUサイズを強制的に調整する例
# 1400バイト以上のパケットに対し、MSSを調整して強制的にフラグメントを回避させる
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360
—
最後に:ネットワークを「視る」力を養う
ICMP Type 3 は、単なるエラーパケットではありません。それは、ネットワークの裏側で何が起きているかを物語る「メッセンジャー」です。
開発者やインフラエンジニアが「繋がらない」と嘆くとき、そこに何が起きているのか。パケットの深層に潜る勇気を持てば、どんな難解な通信障害も「仕様通りの挙動」として紐解くことができます。
皆さんの現場でも、もし不可解な疎通エラーに出会ったら、まずは ICMP Type 3 の Code を確認してください。そこには、解決への最短ルートが必ず記されています。
コメント