98-traceroute 程序

traceroute 程序可以让我们看到 IP 数据报从一台主机传到另一台主机所经过的路由,该程序最早由 Van Jacobson 实现。

当然我们不可能原汁原味的模仿一遍 traceroute 程序,在这里,我们只需要把最关键的功能实现出来就算完成任务。

1. 牛刀小试

本文使用的程序工具托管在 gitos 上:http://git.oschina.net/ivan_allen/unp

1.1 仿真环境测试

这里使用 GNS3 软件来模拟实验,该工程们于路径unp/protocol/gns3/demo01下。拓扑图如图 1 所示。


这里写图片描述
图1 仿真环境拓扑图

  • 在 PC1 上执行 traceroute,跟踪 PC1 到 PC3 的路径


这里写图片描述
图2 PC1 到 PC3 的路径

  • 在 PC3 上执行 traceroute,跟踪 PC3 到 PC1 的路径


这里写图片描述
图3 PC3 到 PC1 的路径

1.2 真实网络测试

  • 程序路径

如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本节程序所使用的程序路径是 unp/program/icmp/traceroute.

  • 运行结果


这里写图片描述
图4 查看到 192.168.165.1 这台路由器的路径

上面的 tracert 是我们自己写的程序,下面的 traceroute 是系统自带的程序。可以看到,分别经过了 4 跳就到达了目的地。图 5 是该网络拓扑图。


这里写图片描述
图5 网络拓扑示意图

2. 程序设计

2.1 traceroute 程序的执行过程

  • 发送一份 TLL 字段为 1 的 IP 数据报给目的主机。处理这份数据报的第一个路由器将 TTL 值减 1,并丢弃该数据报,并发回一份超时 ICMP 报文(type=11, code=0),这样就得到了该路径的第一个路由器地址。
  • 发送一份 TLL 官僚为 2 的 IP 数据报给目的主机,处理这份数据报的第一个路由器将 TLL 值减 1,并转发给第二个路由器;第二个路由器将 TLL 值减 1,并丢弃数据报,并发回一份超时 ICMP 报文。
  • ……

在 traceroute 中,它实际发送一份 UDP 数据报给目的主机,但它选一个不可能的值作为 UDP 端口,目的主机任何一个应用程序都不可能使用这个端口。

最后,当该数据报到达目的主机时,会产生一个端口不可达的 ICMP 差错报文(见上一篇文章),traceroute 程序要做的就是区分接收到的 icmp 报文是超时还是端口不可达,以此判断什么时候应该结束。

2.2 伪代码

完整代码请参考 unp/program/icmp/traceroute

// 默认 30 跳 int done = 0; for (ttl = 1:30 && !done) {   for (i = 0; i < 3; ++i) {     // 重复发 3 次     // 1. 发送 UDP 报文给目标主机     // 2. 接收 ICMP 报文     // 3.     if (// 没有收到 icmp 报文) {       printf(" *");     }     else if (icmp->type == 11 && icmp->code == 0) {       // 超时报文       // 打印发送者(src) ip 地址以及 rtt      }     else if (icmp->type == 3 && icmp->code == 3) {       // 端口不可达报文       // 已经到达目标主机,打印 ip 地址以及 rtt       done = 1; // 可以提前结束           }   } }

3. 实验

tracert 程序接收命令行参数 -m hops,用 m 来指定最大跳数。来看一下跟踪到主机 mars 的路径:


这里写图片描述
图6 运行结果

出现 * 号是因为有些中间路由器不产生 ICMP 超时报文(该功能被关闭)。

下面是使用自带的 traceroute 命令得出的结果:


这里写图片描述
图7 自带命令运行结果

4. 总结

  • 掌握 traceroute 程序的原理
  • 编写 traceroute 程序

说明:本文转自blog.csdn.net,用于学习交流分享,仅代表原文作者观点。如有疑问,请联系我们删除~