现在的位置: 首页 > 综合 > 正文

traceroute示例程序学习原始套接字

2014年09月05日 ⁄ 综合 ⁄ 共 1626字 ⁄ 字号 评论关闭

    最近学习原始套接字,参考书是《UNIX网络编程》,书中例子有ping和traceroute两个。我觉得traceroute比较全面,所以用了traceroute。在学习过程中,碰到了许多问题,也印证了许多知识,特此记录下。

    traceroute,需要做几件事情:

1、发送UDP消息;其中,ttl从1开始,不断增加;

    注意:设置ttl,setsockopt(sendfd_,IPPROTO_IP,IP_TTL,&ttl,sizeof(int))。我个人感觉,通过实际、有用的操作,更加容易理解、记忆这个函数。

2、接收消息每次发送一个UDP,那么就接收一次

   
接收消息,需要
注意:

1、这里的接收消息是ICMP消息,所以需要用原始套接字来收。

2、接收的ICMP消息有两种,一种是ICMP_TIME_EXCEEDED(ttl过了);一种是ICMP_DEST_UNREACH(UDP消息故意设置成为打开的端口,可以导致端口不可达)——这是到目的的的错误。

3、还有就是:ICMP_DEST_UNREACH,也是接受条件——因为目的地到了,只不过没到端口。

4、原始套接字不仅会接收ICMP消息,那么,其他消息需要过滤之后,再次接收;

5、但是,消息一直不来咋办?那么就需要设置超时(即traceroute中的“*”)。

   
这里说明下:书上,用的是alarm来实现超时的,但是我的系统不知道为什么用不了(具体见:http://bbs.chinaunix.net/thread-4135617-1-1.html)。所以,我通过poll来监控套接字是否可读,并且设置超时时间;也能达到相同效果。

    
另外,关于原始套接字的迷惑跟现在的理解:

1、书上,关于“输入”(即读套接字),有这么一段话:

大部分ICMP包,在内核处理完其中的ICMP消息之后,传递到原始套接字。源自Berkeley版的实现,把不是 回射、时间戳、地址掩码 请求的ICMP传递原始套接字(这三类ICMP消息完全由内核处理)。

    我的理解:源自Berkeley的系统,原始套接字是无法接收“回射、时间戳、地址掩码”的ICMP消息的。

   但是,我们现在做的ping即接收的ICMP的回射消息。我也在linux环境下测试过至少回射消息是可以的。其他环境没测试过。

2、书上说:

在原始套接字的IPv4首部,OpenBSD和Linux系统都是网络字节序;其他的,ip_len和ip_off是主机字节序。这个有人验证过吗?家里自学,可能没有这么全的环境

    我的理解:这两个字段,是跟环境相关的。

3、书上说:

接收到的UDP和TCP分组,不传递到任何套接字。(如果想要读取这些分组,那么只能从链路层获取)

    但是,网上许多人却设置协议为IPPROTO_UDP/IPPROTO_TCP。这让我很费解。我测试了下,的确也收不到UDP/TCP的消息(环境是linux的)。

    我理解下原始套接字接收,是无法收TCP/UDP消息的。但是,在发送的时候,是可以的。而这个时候,协议字段是设置成TCP/UDP的。(这个还没测试过)

   另外,如果在发送消息的时候,自己设置IP头,那么需要setsockopt设置IP_HDRINCL字段。(当然,ip_len/ip_off字段,在设置的时候,也是需要注意的)

4最后说明:traceroute可能无法测试

   
traceroute运行的时候,发现许多时候都是“* * *”,即超时。我网上查了下,这跟路由器相关,可能是路由器过滤了这种类型的ICMP消息。我在路由器的主要(192.168.1.1)上,有个“系统工具”栏,有个tracert,测试了下,是可以运行的(tracert应该是和traceroute类似的一个工具)。我家的路由器是
tp-link

相关测试代码: https://github.com/knull-cn/traceroute-test

抱歉!评论已关闭.