深入理解iputils网络工具-第4篇 tracepath:路由追踪程序
2012-08-19 21:19
405 查看
4.1 引言
tracepath和更为强大和更为广泛使用的程序traceroute一样,可以让我们看到IP数据报从一台主机传到另一台主机所经过的路由。tracepath的作者是Alexey Kuznetsov。
4.2 tracepath程序的使用
lixi@lixi-desktop:~$ tracepath 210.45.74.25/8888 1: lixi-desktop.local (210.45.74.25) 0.123ms pmtu 16436 1: lixi-desktop.local (210.45.74.25) 0.054ms reached 1: lixi-desktop.local (210.45.74.25) 0.045ms reached Resume: pmtu 16436 hops 1 back 64
210.45.74.25是本地主机的IP地址,8888是选择的测试端口。
可以发现在本机进行了三次测试,为什么有三次测试,在下面的内容中有分析。
lixi@lixi-desktop:~$ tracepath 210.45.74.25/8888 1: lixi-desktop.local (210.45.74.25) 0.122ms pmtu 16436 1?: reply received 8) 1: lixi-desktop.local (210.45.74.25) 0.048ms reached Resume: pmtu 16436 hops 1 back 64
编写简单的UDP服务程序,对8888端口的UDP请求进行服务(程序见<./test/udpserv.c>)。在运行这个服务程序之后,得到的测试结果如上。
在第二轮时程序接受到了UDP的回复程序,所以输出了一个'?'表示疑问。
lixi@lixi-desktop:~$ tracepath 210.45.74.25/44444 1: lixi-desktop.local (210.45.74.25) 0.131ms pmtu 16436 1: lixi-desktop.local (210.45.74.25) 0.054ms reached 1: lixi-desktop.local (210.45.74.25) 0.046ms reached Resume: pmtu 16436 hops 1 back 64
在运行对8888端口进行服务的UDP服务程序时,如果tracepath采用其他端口就不会产生上例中的情况了。
lixi@lixi-desktop:~$ tracepath www.ustc.edu.cn 1: lixi-desktop.local (210.45.74.25) 0.198ms pmtu 1500 1: 210.45.74.1 (210.45.74.1) 0.777ms 1: 210.45.74.1 (210.45.74.1) 0.775ms 2: 202.38.96.33 (202.38.96.33) 1.068ms 3: 202.38.64.9 (202.38.64.9) 1.012ms reached Resume: pmtu 1500 hops 3 back 253
对比此例和上例,可以发现PMTU发生了变化,由16436变成了1500。
lixi@lixi-desktop:~$ tracepath www.ustc.edu.cn -l 1500 1: 210.45.74.1 (210.45.74.1) 0.828ms 2: 202.38.96.33 (202.38.96.33) 0.988ms 3: 202.38.64.9 (202.38.64.9) 1.140ms reached Resume: pmtu 1500 hops 3 back 253
我们将MTU手动设置为1500,程序就不会默认将MTU设置为一个很大的数,然后找出PMTU了。
tracepath程序的选项解释如下:
-n
与ping命令的-n选项差不多。
只有数字形式的输出,不查找DNS主机以节省时间,不查寻主机名,仅仅给出ip地址值。
只要设置了F_NUMERIC,就不用调用gethostbyaddr来查询DNS主机名了。
用gethostbyaddr的由查询目的主机的IP地址。
-l
设置初始的包的大小。如果不设置则,则报文的大小为65535
4.3 tracepath程序的流程图
tracepath程序的流程图如下:4.4 tracepath重要函数的分析
int main(int argc, char **argv);接受用户的选项,设置发送MTU或者设置是否不要验证主机名等标识。取得一个UDP类型的套接字,并设置好这个套接字的选项。,从1开始递增,直至31,设置套接字的IP_TTL选项为不同的值,调用probe_ttl()函数,直到probe_ttl()函数告知找到目的主机或者出现严重的错误为止。
int probe_ttl(int fd, int ttl);
循环执行十次如下操作,直到正确发送报文跳出循环,或者recverr()返回0:
调用sendto()函数尝试发送UDP报文到目的地址,如果发送出现错误则调用recverr()函数处理接受到的ICMP差错报文。如果正确发送报文,则跳出循环。
如果循环过程中:recverr()函数返回0,则本函数返回0;如果recverr()函数返回大于0的数,则重新进行如上循环。
如果循环超过十次,则表明因为某种原因,无法发送UDP报文,程序返回0。
如果正确发送了UDP报文,则尝试使用recv()函数接受UDP报文的回复。正常情况下不会有UDP的回复,如果果真接受到了回复,则打印‘?’号表示吃惊,返回0。如果正如所预见到的,没有接到回复,则调用recverr()函数处理可能接受到的ICMP差错报文,返回recverr()返回的数值。
总结本函数的返回值意义如下:
返回0表示找到主机或者有严重的错误。
返回负数-1,表示没有接受到ICMP差错报文回复。
返回正数是当前MTU,表示接受并处理了一些错误,但是还没有找到目的主机。
int recverr(int fd, int ttl);
函数将progress初始化为-1,然后不断循环执行如下操作,直到循环中函数返回:调用recvmsg()函数接受错误报文,并处理错误,如果没有错误返回progress。在错误队列中查找对应错误(SOL_IP级别IP_RECVERR类型),progress设置为MTU的值,并处理错误。如果错误队列的错误不是对应错误,返回0。
并处理错误的几种情况如下:
如果是MTU太大(EMSGSIZE),则修改MTU的变量值,继续循环。
如果是UDP端口不可达错误(ECONNREFUSED),则UDP报文已经在规定TTL内传送到了目的主机。这种情况返回0。
如果是EHOSTUNREACH错误且出错原因是接受到了ICMP差错报文,这个ICMP差错报文如果类型为11,代码为0,则表示因为在传输期间TTL等于0所以出错(参看ICMP报文类型)。这就说明UDP还没有到达目的主机TTL就变成了0,需要进一步递加TTL进行试探。
如果是其他的错误,对于不严重的错误继续循环,否则返回0。
总结本函数的返回值意义如下:
返回0表示找到主机或者有严重的错误。
返回的数如果大于0,其值是当前的MTU,表示接受并处理了一个或几个错误。
返回负数-1,表示没有发现任何错误,也就是没有进展(progress)。
4.5 tracepath全局变量的分析
struct hhistory his[64];用来存放历史上发出的UDP报文的ttl设置值和发送时间。
当发送UDP报文时,将报文的端口号设置为base_port + hisptr,在his[hisptr]元素中,存储该UDP报文的ttl设置值和发送时间。
当接受到一个UDP的回复报文(“端口不可达”错误ICMP报文)时,通过ICMP报文的端口号,就可以知道该UDP报文对应的ttl设置值和发送时间存储在his数组的哪个元素里了。
his数组大小有限,只有64个元素。不过已经能够保证即使hisptr回绕也不会出错了。
int hisptr;
用来指向his数组的元素。
当发送UDP报文时,hisptr递加,将发出的UDP报文的ttl设置值和发送时间存储在his[hisptr]元素中。
由于his数组大小为64,故此hisptr每次加到63,下一次就会回绕到0。
struct sockaddr_in target;
要查询的目的主机的地址。
包括地址种类(IPv4)、IP地址、端口号等信息。
端口号会被设置为基础端口号加上hisptr。
__u16 base_port;
基础端口号
可以在设定目的主机时连带设定,否则程序默认是44444端口。
基础端口号加上hisptr就是UDP报文的发送端口号。
设置这么大的端口号,是为了使得目的主机的任何一个应用程序都不可能使用该端口,而产生一个“端口不可达”错误。
这个值很大,目的就是让UDP出现“端口不可达”错误。
const int overhead = 28;
在UDP数据部分之前的头部大小。
IP首部为20,UDP首部为8,故此总共为28字节。
这个数是个常量。
int mtu = 65535;
可以通过-l选项设置,如果设置的值不大于传输路径的MTU。
如果不设置默认值是65535,这个默认值肯定会超过传输路径的MTU,当超过了路径的MTU时,程序会受到错误消息,并根据这个错误消息所带的MTU值,更新MTU值。这样就tracepath能找出路径的MTU了。
int hops_to = -1;
从本地主机到目的主机的跳数。
如果目的主机不可达,则hops_to一直维持-1,最后就不会输出hops_to。
当程序接受到目的主机发出的“拒绝服务”ICMP错误报文时,就说明探测到了目的主机。hops_to取为此时的recverr()函数局部变量sndhops的值。
sndhops有两种方式取得,一种是取得发送时存储在his数组中的ttl值(前面已经谈到如何通过错误报文的IP端口得到存储地址),另一种是取得当前探测阶段发送的UDP报文的ttl的值。
如果不出意外,第一种方式能比较可靠地取得;但是由于某种原因,前一种方式出问题后,就用后一种方式作为代替。
int hops_from = -1;
从目的主机到本地主机的剩余TTL值。
如果目的主机不可达,则hops_from一直维持-1,最后就不会输出。
hops_from从目的主机发送给本地主机的IP报文头取得TTL字段值即可。
int no_resolve = 0;
标识是否不要验证主机名。
可以通过-n选项设置为1。
如果设置为0,就调用gethostbyaddr的由查询目的主机的IP地址,否则就不用,以节省时间。
本文章欢迎转载,请保留原始博客链接http://blog.csdn.net/fsdev/article
相关文章推荐
- 深入理解iputils网络工具-第8篇 rdisk:路由表更新程序
- 深入理解iputils网络工具-第6篇 rarpd:逆地址解析程序
- 深入理解iputils网络工具-第2篇 ping:通路检测程序
- 深入理解iputils网络工具-第5篇 arping:地址解析程序
- 深入理解iputils网络工具-第5篇 arping:地址解析程序
- 深入理解iputils网络工具-第3篇 clockdiff:时间比对程序
- 深入理解iputils网络工具-第7篇 tftpd:简单文本传输
- 深入理解iputils网络工具-第1篇 简介
- 深入理解.NET程序的原理 谈一谈破解.NET软件的工具和方法
- 深入理解.NET程序的原理 谈一谈破解.NET软件的工具和方法
- 网络诊断工具之—路由追踪tracert命令
- 深入理解.NET程序的原理 谈一谈破解.NET软件的工具和方法
- 深入理解openstack网络架构(3)-----路由
- 深入理解openstack网络架构(3)-----路由
- 深入理解Linux网络技术内幕——IPv4 概念
- 深入理解计算机系统阅读笔记-优化程序性能
- 深入理解JVM(七)——性能监控工具
- 深入理解计算机系统——第03章——程序的机器级表示
- 深入理解Linux网络技术内幕——L4层协议与Raw IP的处理
- 神经网络深入(连载10)一个demo程序