前言
从我面试的经验来看,网易这个公司是很会深究的一个公司,会努力在一个点上将面试者问倒的公司,所以对于网易游戏的面经我不会倾向于简单的罗列问题,而是对他们提出的问题从原理上进行深度的理解。正因为被他们问的很深,所以对于问的问题我有很深的印象,前面的两篇博客分别是关于python的特性,关于python的部门还没有完,后续还会再写一些面试题目的,今天要说的是一个网络程序——traceroute,面试官当时让我讲述traceroute的原理,这个在之前我知道他使用ICMP结合TTL来实现的,实现也是相当巧妙,今天的博文参考TCP/IP详解卷一,来彻底的搞清楚这个程序。
正文
在Windows下,相同的功能的实现命令为:tracert,首先至关的感受下traceroute命令的效果。我执行了两次tracerout百度的命令,结果如下:
根据上面的执行结果包括对于程序的名字traceroute相信没有接触过这个命令的人也可以大体猜出来这个命令的作用——路由跟踪,即确定IP数据包访问目标所经过的路径,当然这些路径指的是路由器。对于执行结果的每一行来说,比如3 2ms 1ms 1ms 10.6.17.1表示从本机出发的第三跳路由器地址为10.6.17.1,中间的三列时间显示了RTT,即数据包到达此跳路由或主机再返回你的主机所需要的时间,单位是毫秒,为什么是三列呢?因为traceroute发送了三个独立的数据包,统计出了每个RTT,而国内很多博客在这里存在误区,认为三列分别代表最小,平均和最大时间,有的时间栏没有具体的数字,只是一个星号,这个可能有多种多样的原因,比如路由器禁止了ICMP数据包,traceroute程序本身就被用来发现网络故障,如果从某跳开始所有的时间都成了星号,即超时,则网络故障很有可能就出现在了这一跳。从上面两次执行结果可以看到,traceroute命令执行的结果不是完全相同的,这个也是很容易理解的,毕竟网络是动态时时变化的。
Traceroute程序使用ICMP报文和IP首部中的TTL字段,TTL由发送端初始化,当路由器接收到一份IP数据包,如果TTL字段是0或者1,路由器将该数据包丢弃,并给源主机发一个ICMP“超时”信息。按照这个基本的相应过程,可以猜想traceroute程序的完整过程,首先它发送一份TTL字段为1的IP数据报给目的主机,处理这个数据报的第一个路由器将TTL值减1,然后丢弃该数据报,并给源主机发送一个ICMP报文,这个报文包含了路由器的IP地址,这样就得到了第一个路由器的地址,然后,traceroute发送一个TTL为2的数据报来得到第二个路由器的IP地址,继续这个过程,直至这个数据报到达目的主机。按照这个原理我们也可以很好的解释了上面tracert www.baidu.com的结果了,即所有显示的13跳是从我到百度119.75.218.70这个服务器所经过的所有路由器的信息,而且由于网络是动态变化的,路径也可能会发生变化,所以如果追踪同样的目的IP,发现不同的路径当属于正常情况。
这里必须加一条分割线,因为这个知识我相信很多人在很早之前就知道了,但是面试官的面试重点显然不在上面的知识点,如果你回答了上述过程,面试官肯定会接着问一个问题:目的主机在接收到TTL值为1的IP数据报是不会丢失的吧,这样也不会产生一个超时的ICMP数据报文了,那么程序如何判断是否已经到达目的主机了呢?
在Linux下,traceroute程序发送一个UDP数据报给目的主机,但它选择一个不可能的值作为UDP端口号(大于30000),使目的主机的任何一个应用程序都不可能使用该端口,因此,当该数据报达到目的主机的时候,目的主机会产生一个“端口不可达”错误的ICMP报文,这样,traceroute程序要做的就是区分接收到的ICMP报文是超时还是端口不可达,从而来区分是路由器还是目的主机。
下面进行实验验证,仍然用上面的例子,用wireshark抓取数据报来验证。由于主机上有大量的数据报文,所以我们根据本地IP地址和百度服务器的IP地址进行数据报过滤,按照我的例子过滤条件应该为:ip.src192.168.99.200&&ip.dst119.75.218.70,首先整体看一个过滤之后的报文总体情况,如下图:
其中浅色背景的表示本机构造的ICMP数据报文,深色的表示超时ICMP报文,如果细心的人就会发现:所发送的数据报的数量要大于路径上的路由器的数量,这个上文也提到过,每一跳都会发送三个报文,同时相应报文的数量少于构造报文数量,因为有些路由器禁止相应ICMP数据报,只提供转发功能,所有本地发出的构造ICMP数据报源IP都是本地,目的IP都是百度的IP地址,所有相应的超时ICMP数据报的目的IP都是本地,源IP地址分为为路由器的IP地址,首先来看一个本机构造的ICMP数据报文:
在这个报文中,可以注意他的TTL的值为1,同时他填充的负载为0,相同的报文会发送3次,接着再看这个报文的响应报文:
在这个响应报文中应该注意的点我都用红色方框圈出来了。
关于最后确定是否达到目的主机则和具体的操作系统有关系,在Windows下,我猜测他可以通过正确的回应ICMP数据报得出已经到达目的主机,而在Linux下面,则是通过上文所说的原理实现的,附图如下:
总结
关于traceroute的内容,如果在进行深究,还有很多很多,比如他可以通过ICMP,TCP实现,在Windows下面达到目的主机之后会停止发送traceroute数据报,但是在Linux下,会持续发送30个TTL不同的数据报,每个发送三个报文,在达到目的主机之前可以发送ICMP,TCP等,但是在达到之后,开始发送UDP数据报,目的端口从大于30000的某个值开始,没发送一个数据报则加一,这个从上面的截图也可以看出。
好公司在面试的时候都会揪住一个点问的很深很深,所以在自己的领域,将基础知识一定要掌握的十分好。