ping只是工作在网络层,不涉及到传输层。而traceroute则涉及到了传输层,它用到了udp协议向目的主机发送一个不可达的端口。
traceroute使用icmp和ip的ttl字段实现的。因为路由器是不转发ttl为0的数据包,借助这一点,traceroute向目的主机发送ttl为1的数据包,则到达第一个路由器后ttl减去1,该数据包将被丢弃,同时该路由器发送一个超时的icmp报文给traceroute主机。这个时候traceroute就知道第一个路由器的ip地址啦,根据这个方法,将ttl设置为2,则可以得到第二个路由器的ip地址。traceroute的一个源码实现中,体现了这一点:
int nprobes = 3;
for (ttl = 1; ttl <= max_ttl; ++ttl) {//ttl试探30次
u_long lastaddr = 0; /*用于记录到同一个TTL下到达的上一个中继路由器*/
int got_there = 0;
int unreachable = 0;
Printf("%2d ", ttl);
for (probe = 0; probe < nprobes; ++probe) {//每次探测三次
int cc;
struct timeval t1, t2;
struct timezone tz;
struct ip *ip;
上述程序中,ttl从1变化到30就体现了这一点。
上述过程可以找到目的主机之前的所有路由器,但是不能找到找到目的主机本身。因为上述过程是根据途中路由器发回的icmp报文得到ip的,而目的主机如果接收到了traceroute的探测ip数据包它是不会发出icmp的,因为数据包已经到达了。这种情况traceroute应用另一个策略,通过向目的主机的不存在的端口发送udp报文,强制使得目的主机反馈端口不可达报文,这样traceroute必定可以借助端口不可达报文确定是否达到了目的主机。
因此,traceroute实际上是:
每次发送一个以一个目的端口的udp报文作为ip数据报的数据段的ip分组,如果收到的是超时的icmp报文,则该icmp报文中的源ip地址是到达目的主机的中间一跳的ip地址,如果收到的是端口不可达icmp报文,则该icmp报文的源ip地址是目的地址的ip地址。