Tracerouteの仕組みについて解説してるページは数あれど、障害箇所特定のノウハウはあまり見かけないので、今回は「Tracerouteは有用だけど、これを知らないと結果が読めないぞ」という話を。
いちおう仕組みの解説#
Tracerouteにはそれ専用のプロトコルがあるわけではく、IPのパケット転送制限の仕様をうまく応用することで実現する。IPヘッダにはTTL(Time To Live、IPv6では hop-limit)フィールドがある。この本来の役割は誤ったルーティングによるパケットループを防ぐことで、ルータは転送するパケットの TTLフィールドの値をデクリメントし、0の場合は転送せず送信元に対して ICMP - Time Exceeded (期限切れ)を返す。つまりIPパケットは送信時にTTLフィールドに設定した値と同じ数のルータを経由できる。TTLの初期値は環境によって異なるが、64とか128とか、通信相手に到達するために適当な値が設定されている。
これを逆手に取って、 TTLを1からインクリメントしながらパケットを送信すれば、送信経路上のルータたちから ICMP - Time Exceeded が返ってくる。そのICMPパケットの送信元IPアドレスを見れば送信経路上のルータがわかるという仕組み。
知るべきこと1: プローブ・パケットの使い分け#
送信するプローブ・パケット(調査パケット)は、UDPパケット、TCP SYN パケット、ICMP - Echo Request パケットが使われる。
UDP | TCP SYN パケット#
よいところ#
ルータが port-based routing をしている場合、 その経路で通信するサービスのポートを送信パケットに設定すれば、実際の送信経路がわかる。ただし、Tracerouteの実装によっては試行回数ごとにポート番号をインクリメントするので、特定ポートをプローブしたいときは試行回数を1回にする。
わるいところ#
経路上のファイヤウォールでパケットが暗黙に破棄されることが多々あり、一見して障害と区別がつかない。
また、TracerouteはUDPパケットが宛先にパケットが到達したとき、 ICMP - Port Unreachable パケットが返ることを期待しているが、プローブ・パケットの宛先ポートが実際に使用されていると ICMP - Port Unreachable パケットが返らないので、結果は宛先に到達していないように見える。(TCPの場合、リッスンされていなければ RST、リッスンされていれば SYN ACK が返ってくるので、宛先に到達したことが判別できる。)
ICMP - Echo Request パケット#
よいところ#
pingコマンドと同じプロトコルなので、 ファイヤウォールで遮断されていることが比較的少ない。
宛先まで到達できれば、 ICMP - Echo Reply が返ってくる
わるいところ#
ルータが port-based routing をしている場合、ICMP - Echo Request と実際に調査したいパケットの経路が異なることがある。
Tracerouteでは問題ないのに、アプリケーションの UDP | TCP パケットが届かないという現象が起こりうる。
ICMPパケットに対するICMPパケットは返さないルータがまれにある。(ICMPパケットの無限ピンポンを防ぐため、ICMPエラーパケットを対するICMPパケットを返さない決まりだが、ICMP - Echo Request に対しては ICMP - Time Exceeded を返す実装がほとんど。)
知るべきこと2: 受信経路の障害はわからない#
パケットの送信経路と受信経路が同じとは全く限らない。むしろ違うものと思ったほうがよい。Tracerouteから見て受信経路で起きている障害は、その箇所を特定できない。 Tracerouteの結果の見かけ上の障害箇所は、実は問題がなく、当該箇所からパケットが返る経路上で発生している障害の可能性がある。障害でなくとも、経路途中のルータから先がTracerouteできなくなる現象は受信経路でICMPパケットが捨てられている可能性もある。もし受信経路が知りたいときは対向からTracerouteするしか思いつかないが、その対向と通信できないからTracerouteしている場合が多く、もはやなすすべなし。