読者です 読者をやめる 読者になる 読者になる

tracerouteのベストプラクティス

ファイヤウォールの設定が厳しいネットワークや、ロードバランサーが動作するネットワーク、使用するパケットのプロトコルによる違い、等を考えて最も経路発見しやすい方法を考える。

ファイヤウォールの設定が厳しいネットワーク

ファイヤウォールの設定が厳しい場合、pingすらインターネット上のサーバに通らないことがある。tracerouteも同様で、デフォルトの設定では通らないことが多いが、ファイヤウォールが必ずといっていいほど通しているポートを使えば良い。TCPではHTTPの80番ポート、UDPではDNSの53番ポート、が最も良く知られたポートの内の一つだろう。実際、tracerouteのデフォルト設定ではデフォルトゲートウェイまでしか経路発見できないが、UDPの53番ポートを使うとかなり先まで経路発見できることがある。

ロードバランサーが動作するネットワーク

ECMPによってロードバランスしているネットワーク(インターネット)では、パケットを投げる度に経路が変わってしまう。ただし、ロードバランスには大きく二つの方式があって、インターフェースをフローで振り分けるか、パケットで振り分けるか、の違いがある。フローは5 tuples (IP/Port Dest/Src Protocol) によってインターフェースを振り分ける方式で、IP/UDP/TCPのヘッダで決まる5 tuplesを固定すれば、ロードバランスによる経路の違いは出ないので安定した経路発見が行えるはずだ。

ただし5 tuplesを固定するために、tracerouteがどのように経路発見を行っているのかを確認しておく必要がある。Linux版のtracerouteコマンドはデフォルトはUDPパケットによる経路発見を行う。つまり、UDPパケットのIPヘッダのTTLを一つずつ増やしていくやり方だ。また、受け取ったTime ExceededのICMPパケットが、どのUDPパケットに対応するのかを判断できる必要がある。大きく遅延したパケットを受信したり、他のアプリケーションが送信したパケットに対するTime Exceededパケットと区別する必要があるし、Linuxのtracerouteのデフォルト動作は以下の通り同時に複数のパケットを投げる。

       -N squeries, --sim-queries=squeries
              Specifies the number of probe packets sent out simultaneously.
              Sending several probes concurrently can  speed  up  traceroute
              considerably. The default value is 16.
              Note that some routers and hosts can use ICMP rate throttling.
              In such a situation specifying too large number  can  lead  to
              loss of some responses.

Time ExceededのICMPパケットはそのデータ部に、元のパケットのIPヘッダとペイロードの最初の8バイトを含めるので、元のUDPパケットのヘッダに存在するポート番号を識別できるため、tracerouteはこれを生かしてUDPの宛先ポート番号を一つずつ増やしながらUDPパケットを生成する。

http://pages.cs.wisc.edu/~agember/cs640/s15/assign3/images/image00.png

Internet Control Message Protocol - Wikipedia

ここで、フローベースのロードバランスに対応しようとすると問題があることが分かる。5 tuplesが変わってしまうとロードバランスの影響を受けるからだ。これに対応したのが Paris Traceroute で、UDPパケットヘッダの宛先ポート番号ではなくチェックサムを使って対応を取る。まるでビットコインのように、UDPパケットのペイロードを用いて任意のチェックサムの値を作り出す。UDPパケットヘッダのチェックサムは最初の8バイトに含まれるので、これもTime ExceededのICMPパケットに含まれる。単純にUDPパケットのペイロードにシーケンス番号を書けないのもこれが理由だ。

http://paris-traceroute.net/images/traceroute_load_balancers.gif

Paris Traceroute

ただ、tracerouteにもこれと同等と思われるオプションが実装されているため、UDPパケットを使いつつ宛先や送信元のポート番号を任意の値に固定できる。例えば、-Uオプションで宛先ポート番号を53に固定する。これは、DNSで使われるポート番号であり、最も通りやすい(経路途中でファイヤウォールにフィルタで破棄される可能性が少ない)ポートの一つだ。また--sport=オプションで、送信元ポートを固定することもできる。

両者の違いはChecksumの使い方にあるようだ。tracerouteのパケットをtcpdump -vvで見てみると[bad udp cksum]と表示されるのが分かる。宛先ポートや送信元ポートを変更してもChecksumの値を変えておらず固定値にしているようだ。一方、paris-tracerouteの方は[udp sum ok]と表示されるため、ヘッダに併せてChecksumを正確に作り直していることが分かる。これが、tracerouteの動作の結果としてどう影響するかは分からないが、全く同じ挙動ではないという点は気をつけておいた方がいいだろう。また、paris-tracerouteは完全に全ての経路を把握してから標準出力に出力するので、複数経路を何らかのアルゴリズムで適当な経路を選択しているのかもしれない*1

なお、Windows版のtracertはICMPパケットを使った経路発見を行う。LinuxのtracerouteでもICMPやTCPを扱えるが、これも細かい仕様は両者で異なると思われるので、同じICMPパケットでも発見できる経路に違いが出るかもしれない。

また、-Aで各ホップの所属するAS番号を取得することができるので活用した方が良い。これは内部でwhoisを使っており*2whoisはポート45番*3を用いてwhoisサーバとやり取りするので、イントラネットがポート45番をフィルタしていると使うことができず、AS番号の部分が[!!]という表示になってしまう。

使用するパケットのプロトコルによる違い

上記でほとんど説明したが、総括するとtracerouteにはICMP/UDP/TCPの違いがあって、ネットワークによってはそれぞれで結果が異なることが予想できるのでいくつか試してみるべきだろう。あと、最後にpingで宛先とのRTTを確認して、どの程度まで経路発見が出来たのかを把握しておくのが良い。

実際にやってみた結果を考慮する*4と以下のようになった。ネットワークによって結果は変わってくるので、これが唯一の解答にはならないとは思う。

  • ファイヤウォールが厳しい場合はWell-Knownなポートを使ってみる
  • ロードバランスによる影響を抑えたい場合は宛先と送信元のポートを固定する
  • ウェブサーバに対してTCP80番を使うとCDNの影響により2〜3ホップで届いてしまうことがある(実際に知りたい経路ではない可能性がある)
  • 宛先ポートと送信元ポートを固定すると結果が悪くなる場合もあったため、デフォルト設定も含めていくつかのオプションを試すべき

*1:そのあたりは論文参照のこと https://paris-traceroute.net/images/e2emon2007.pdf

*2:実際にwhoisコマンドをインストールする必要は無かった

*3:straceで見た限りUDP/TCP両方を使っているようだ

*4:実際に発見した経路は出さないことにする