tracerouteを考察する
tracerouteは、ある宛先までのネットワーク経路を調べるもの。IPパケットのTTLを1から徐々に増やしていき、ICMPの「Time Exceeded」応答したルーターのIPアドレスをもとに経路を調査する。ルーターを通過すると、TTLがデクリメントされることを利用している。
UDP vs ICMP
背景
Windowsでは「tracert」がそれに相当し、送るパケットとして、ICMPが使われる。Ciscoルーターでは伝統的(?)にUDPが、Linux/Macでは、ICMPもUDPも選ぶことができる(TCPも?)。UDPの場合、ICMPと比べて、Firewallなどでパケットフィルタリングされる可能性が高いので、なぜUDPが使われるのか不思議に思っていた。少々調べてみると、次の記事が見つかった。
-
Why traceroute sends UDP packets and not ICMP ones?
引用すると、
I guess the main motivation was that sending out plain UDP packets requires no special privileges, as sending ICMP packets does (raw sockets or the equivalent). That's why e.g. ping is usually setuid to root, which is a big risk security-wise.
RawソケットをハンドリングするUnix上の権限が関連している、、、との推測。ある程度納得はできるところ。
比較
小生のMacにて、まずは単純に、UDP利用時とICMP利用時のtracerouteとの比較を行った。ターゲットはGoogleのDNSサーバー「8.8.8.8」としている。
UDP
(ドメイン名およびIPアドレスの一部はhidden。)
$ traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 64 hops max, 52 byte packets
1 aterm.me (192.168.10.1) 1.647 ms 1.640 ms 1.592 ms
2 aa.bb.cc.ne.jp (ZZ.146.YYY.74) 4.438 ms 4.274 ms 4.535 ms
3 dd.ee.ff.ne.jp (XX.146.WWW.73) 4.327 ms 4.555 ms 4.353 ms
4 gg.hh.ii.ne.jp (VVV.213.UUU.93) 6.401 ms 6.093 ms 17.918 ms
5 202.213.193.91 (202.213.193.91) 9.083 ms 6.651 ms 5.617 ms
6 * 142.250.160.100 (142.250.160.100) 9.610 ms 10.062 ms
7 * * *
8 dns.google (8.8.8.8) 9.554 ms 5.262 ms 5.041 ms
ICMP
$ traceroute -I 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 64 hops max, 72 byte packets
1 aterm.me (192.168.10.1) 4.123 ms 1.516 ms 1.287 ms
2 aa.bb.cc.ne.jp (ZZ.146.YYY.74) 4.072 ms 4.195 ms 3.987 ms
3 dd.ee.ff.ne.jp (XX.146.WWW.73) 6.707 ms 4.722 ms 4.630 ms
4 gg.hh.ii.ne.jp (VVV.213.UUU.93) 11.479 ms 5.958 ms 6.980 ms
5 202.213.193.91 (202.213.193.91) 9.766 ms 6.826 ms 7.543 ms
6 142.250.160.100 (142.250.160.100) 6.209 ms 22.981 ms 7.530 ms
7 142.251.52.31 (142.251.52.31) 5.221 ms 6.150 ms 333.949 ms
8 142.251.60.193 (142.251.60.193) 8.024 ms 6.078 ms 5.022 ms
9 dns.google (8.8.8.8) 5.187 ms 7.348 ms 5.827 ms
UDPとICMPとの比較
ほぼ同じ時刻に実施しているが、経路が若干異なることがわかる。また、異なる日に実施した場合、同じ経路とはならなかったこともあり。このあたりは、途中経路のルーターの設定(ダイナミックルートなど)に依存するのであろう。
UDPで未応答部分あり
上記UDP結果に、未応答部分がある。
7 * * *
途中経路のFirewallでブロックされたのであろう。UDP利用時のtracerouteは、デフォルト時ポート番号33434から一つずつインクリメントされるらしい。以下、「man traceroute」の説明。
-p port
Protocol specific. For UDP and TCP, sets the base port number used in probes (default
is 33434). traceroute hopes that nothing is listening on UDP ports base to
base+nhops-1 at the destination host (so an ICMP PORT_UNREACHABLE message will be
returned to terminate the route tracing). If something is listening on a port in the
default range, this option can be used to pick an unused port range.
TTLインクリメント時に、ポート番号をインクリメントする理由がよくわからない(おそらく何かあるはず)。デフォルトポート番号を相当数変えてトライしたが(例:「-p 35000」)、IPアドレス「8.8.8.8」へのtraceroute(UDP)にて、未応答部分が必ず存在していた。
IPアドレス「8.8.8.8」はDNSサーバー
DNSサーバー(UDP)である。DNS queryの応答は必ず得られる(はず)。DNSのポート番号である53を指定し続ければ(TTLをインクリメントしつつ)、少なくとも「8.8.8.8」への経路は判明するはず。なので、それをトライすることとした。
Network Packet Generator
tracerouteコマンドでは、ポート番号を常に同一にしてパケットを送ることができない。そこで、何らかの「Network Packet Generator」を使い、IPヘッダを操作することにした。検索すると、GUI上のアプリケーションも多数見つかるが、Python上で利用する
が、とてもハンドリングしやすいと判断。
Scapy
使用例は、同サイトにも、他にも多数見つかる。
ポート番号53固定で、TTLをインクリメント
下記となる(TTLを1から10まで変化させる)。とてもイージー。
>>> ans=sr1(IP(ttl=(1,10), dst="8.8.8.8")/UDP()/DNS(qd=DNSQR(qname="ietf.org")))
Begin emission:
Finished sending 10 packets.
.*.*.*.*..*.*.**.*.*
Received 20 packets, got 10 answers, remaining 0 packets
その時のWiresharkの状況。
期待どおり、未応答は存在しない(成功)。また、「8.8.8.8」までのルートも、tracerouteでUDPやICMPでの結果と異なっているようだ。このあたりは深追いしないこととした。
終わりに
やはり、ICMP利用のtracerouteがベターと感じる。