Traceroute(linux)/tracert(win) 均是用於同一目的的網絡調試工具。它們用於顯示數據包在IP網絡中經過的路由器的IP地址。
原理
這些程序是利用IP數據包的存活時間(TTL)值來實現其功能的。
當一台計算機發送IP數據包時,會為數據包設置存活時間(TTL)值。每當數據包經過一個路由器,其存活時間值就會減 1。當存活時間減到 0 時,路由器將不再轉發數據包,而是發送一個 ICMP TTL 數據包給最初發出數據包的計算機。
Traceroute 程序首先向目標主機發出 TTL 為 1 的數據包,發送數據包的計算機與目標主機之間的路徑中的第一個路由器,在轉發數據包時將數據包的 TTL 減 1,它發現 TTL 被減為了 0,於是向最初發出數據包的計算機發送一個 ICMP TTL 數據包,Traceroute 程序以此獲得了與目標主機之間的路徑上的第一個路由器的IP地址。后面 traceroute 程序依次向目標主機發送 TTL 為 2、3、4 . . . 的數據包,逐個探測出來與目標主機之間的路徑上每一個路由器的 IP 地址。
實現
默認條件下,traceroute 首先發出 TTL = 1 的UDP 數據包,第一個路由器將 TTL 減 1 得 0 后就不再繼續轉發此數據包,而是返回一個 ICMP 超時報文,traceroute 從超時報文中即可提取出數據包所經過的第一個網關的 IP 地址。然后又發送了一個 TTL = 2 的 UDP 數據包,由此可獲得第二個網關的 IP 地址。依次遞增 TTL 便獲得了沿途所有網關的 IP 地址。
注意
並不是所有網關都會如實返回 ICMP 超時報文。處於安全性考慮,大多數防火牆以及啟用了防火牆功能的路由器缺省配置為不返回各種 ICMP 報文,其余路由器或交換機也可能被管理員主動修改配置變為不返回 ICMP 報文。因此 Traceroute 程序不一定能拿到所有的沿途網關地址。所以,當某個 TTL 值的數據包得不到響應時,並不能停止這一追蹤過程,程序仍然會把 TTL 遞增而發出下一個數據包。這個過程將一直持續到數據包發送到目標主機,或者達到默認或用參數指定的追蹤限制(maximum_hops)才結束追蹤。
依據上述原理,利用了 UDP 數據包的 Traceroute 程序在數據包到達真正的目的主機時,就可能因為該主機沒有提供 UDP 服務而簡單將數據包拋棄,並不返回任何信息。為了解決這個問題,Traceroute 故意使用了一個大於 30000 的端口號,因 UDP 協議規定端口號必須小於 30000 ,所以目標主機收到數據包后唯一能做的事就是返回一個 “端口不可達” 的 ICMP 報文,於是主叫方就將端口不可達報文當作跟蹤結束的標志。
UDP 之外的選擇
使用 UDP 的 traceroute,失敗還是比較常見的。這常常是由於,在運營商的路由器上,UDP 與 ICMP 的待遇大不相同。為了利於 troubleshooting,ICMP ECHO Request/Reply 是不會封的,而 UDP 則不同。UDP 常被用來做網絡攻擊,因為 UDP 無需連接,因而沒有任何狀態約束它,比較方便攻擊者偽造源 IP、偽造目的端口發送任意多的 UDP 包,長度自定義。所以運營商為安全考慮,對於 UDP 端口常常采用白名單 ACL,就是只有 ACL 允許的端口才可以通過,沒有明確允許的則統統丟棄。比如允許 DNS/DHCP/SNMP 等。
UNIX/Linux 下的 traceroute 還提供了如下的選項:
$ traceroute --help Usage: traceroute [ -46dFITnreAUDV ] [ -f first_ttl ] [ -g gate,... ] [ -i device ] [ -m max_ttl ] [ -N squeries ] [ -p port ] [ -t tos ] [ -l flow_label ] [ -w waittime ] [ -q nqueries ] [ -s src_addr ] [ -z sendwait ] [ --fwmark=num ] host [ packetlen ] Options: -4 Use IPv4 -6 Use IPv6 -d --debug Enable socket level debugging -F --dont-fragment Do not fragment packets -f first_ttl --first=first_ttl Start from the first_ttl hop (instead from 1) -g gate,... --gateway=gate,... Route packets through the specified gateway (maximum 8 for IPv4 and 127 for IPv6) -I --icmp Use ICMP ECHO for tracerouting -T --tcp Use TCP SYN for tracerouting (default port is 80) -i device --interface=device Specify a network interface to operate with -m max_ttl --max-hops=max_ttl Set the max number of hops (max TTL to be reached). Default is 30 -N squeries --sim-queries=squeries Set the number of probes to be tried simultaneously (default is 16) -n Do not resolve IP addresses to their domain names -p port --port=port Set the destination port to use. It is either initial udp port value for "default" method (incremented by each probe, default is 33434), or initial seq for "icmp" (incremented as well, default from 1), or some constant destination port for other methods (with default of 80 for "tcp", 53 for "udp", etc.) . . . . . . -U --udp Use UDP to particular port for tracerouting (instead of increasing the port per each probe), default port is 53 -UL Use UDPLITE for tracerouting (default dest port is 53) -D --dccp Use DCCP Request for tracerouting (default port is 33434) -P prot --protocol=prot Use raw packet of protocol prot for tracerouting --mtu Discover MTU along the path being traced. Implies `-F -N 1' --help Read this help and exit Arguments: + host The host to traceroute to packetlen The full packet length (default is the length of an IP header plus 40). Can be ignored or increased to a minimal allowed value
除了 UDP 之外,我們還可以用 TCP 或 ICMP 來探測網絡路徑。
Traceroute 使用 TCP 探測網絡路徑的原理是,不斷發出 TTL 逐漸增大的 TCP [SYN] 包,在收到目標主機發回的 TCP [SYN ACK] 或達到默認或設置的追蹤限制(maximum_hops)時結束追蹤。我們用這種方法來探測到 www.qq.com 的網絡路徑。適當修改 Wireshark 的抓包選項,並在命令行中執行:
總結一下,traceroute 主要利用 IP 數據包的 TTL 字段值 + ICMP 來實現,它發送的用於探測網絡路徑的數據包的 IP 之上的協議可以是 UDP、TCP或ICMP。
不同模式下,探測過程中設計的數據包如下:
UDP 模式
UDP 探測數據包(目標端口大於 30000) + 中間網關發回 ICMP TTL 超時數據包 + 目標主機發回 ICMP Destination Unreachable 數據包
TCP 模式
TCP [SYN] 探測數據包(目標端口為 Web 服務的 80) + 中間網關發回 ICMP TTL 超時數據包 + 目標主機發回 TCP [SYN ACK] 數據包
ICMP 模式
ICMP Echo (ping) Request 探測數據包 + 中間網關發回 ICMP TTL 超時數據包 + 目標主機發回 ICMP Echo (ping) reply 數據包