在Fedora 20上写了一个简单的ping程序,创建原始套接字后没有设置任何选项,ping其他主机(NetBSD-1.0)的时候运行正常:
[root@sea network]# ./ping 192.168.1.114 PING 192.168.1.114: send packet(icmp): 08 00 cc 95 0d 4c 00 00 a5 a5 .....L.... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 .... recv packet(ip): 45 00 00 54 35 04 40 00 ff 01 E..T5.@... c2 7c c0 a8 01 72 c0 a8 01 65 .|...r...e 00 00 d4 95 0d 4c 00 00 a5 a5 .....L.... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 .... 64 bytes from 192.168.1.114: seq=0, ttl=255 [root@sea network]#
但是ping本机的IP地址的时候却有问题了:
[root@sea network]# ./ping 192.168.1.101 PING 192.168.1.101: send packet(icmp): 08 00 11 95 c8 4c 00 00 a5 a5 .....L.... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 .... recv packet(ip): 45 00 00 54 a8 c8 40 00 40 01 E..T..@.@. 0d c6 c0 a8 01 65 c0 a8 01 65 .....e...e 08 00 11 95 c8 4c 00 00 a5 a5 .....L.... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 .... error, the type of reply packet is not icmp echoreply! [root@sea network]#
返回的ICMP报文和发送出去的是一样的!!
用 tcpdump 命令查看网卡接口的数据包,发现没有任何数据输出。觉得这不太可能,忽然想到本机的IP地址是不是发送到环回接口上啦?验证发现果然如此:
[root@sea network]# tcpdump -i lo -X icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes 12:06:30.336304 IP sea > sea: ICMP echo request, id 16974, seq 0, length 64 0x0000: 4500 0054 a8d0 4000 4001 0dbe c0a8 0165 E..T..@.@......e 0x0010: c0a8 0165 0800 9793 424e 0000 a5a5 a5a5 ...e....BN...... 0x0020: a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 ................ 0x0030: a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 ................ 0x0040: a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 ................ 0x0050: a5a5 a5a5 .... 12:06:30.336327 IP sea > sea: ICMP echo reply, id 16974, seq 0, length 64 0x0000: 4500 0054 a8d1 0000 4001 4dbd c0a8 0165 E..T....@.M....e 0x0010: c0a8 0165 0000 9f93 424e 0000 a5a5 a5a5 ...e....BN...... 0x0020: a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 ................ 0x0030: a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 ................ 0x0040: a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 a5a5 ................ 0x0050: a5a5 a5a5 ....
从 tcpdump 的输出来看,lo接口的返回并没有什么问题,但是为什么程序中的 recvfrom 函数会收到和 sendto 一样的数据呢?
Fedora 20自带的 ping 程序又是没有这个问题的,于是下载了 ping 的源码,看看自带的程序是不是做了什么特殊的处理。经过一番调试,最后确认是下面的代码起了作用:
if (1) { struct icmp_filter filt; filt.data = ~((1<<ICMP_SOURCE_QUENCH)| (1<<ICMP_DEST_UNREACH)| (1<<ICMP_TIME_EXCEEDED)| (1<<ICMP_PARAMETERPROB)| (1<<ICMP_REDIRECT)| (1<<ICMP_ECHOREPLY)); if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) perror("WARNING: setsockopt(ICMP_FILTER)"); }
过滤掉了 ICMP_ECHO 类型的报文?在我自己的程序中加上类似的代码:
filt.data = ~((1<<ICMP_ECHOREPLY)); if (setsockopt(sockfd, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) { perror("WARNING: setsockopt(ICMP_FILTER)"); }
重新编译后,运行就正确了:
[root@sea network]# ./ping 192.168.1.101 PING 192.168.1.101: send packet(icmp): 08 00 37 92 a2 4f 00 00 a5 a5 ..7..O.... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 .... recv packet(ip): 45 00 00 54 a8 d3 00 00 40 01 E..T....@. 4d bb c0 a8 01 65 c0 a8 01 65 M....e...e 00 00 3f 92 a2 4f 00 00 a5 a5 ..?..O.... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 .......... a5 a5 a5 a5 .... 64 bytes from 192.168.1.101: seq=0, ttl=64 [root@sea network]#
在NetBSD-1.0上,不设置任何的套接字选项,直接ping本机的IP地址是没有这个问题的。
在Slackware-14.1上测试,也有Fedora-20的问题,看来Linux系统的实现都是这样的。是bug?还是实现特性?
Fedora-20上ping本机IP地址时的问题,布布扣,bubuko.com
原文:http://www.cnblogs.com/StupidTortoise/p/3789322.html