套接字和ARP(IP邻居)表条目

时间:2014-04-24 14:42:10

标签: linux sockets arp

在CentOS 6.4(内核2.6.32)上,为什么下面的第二个 arping 调用会创建一个新的ARP表项,但第一个不是?网络行为是相同的,我的困惑是,在我看来,系统调用实际上是等同的。我在这里缺少什么系统行为?

#:- arping -s 10.0.2.15 -f 10.0.2.4
ARPING 10.0.2.4 from 10.0.2.15 eth0
Unicast reply from 10.0.2.4 [52:54:00:01:02:03]  0.681ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
#:- ip neigh show | grep -c '^10\.0\.2\.4 '
0                                                   # <--- no new ARP entry

#:- arping -f 10.0.2.4
ARPING 10.0.2.4 from 10.0.2.15 eth0
Unicast reply from 10.0.2.4 [52:54:00:01:02:03]  0.681ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
#:- ip neigh show | grep -c '^10\.0\.2\.4 '
1                                                   # <--- new ARP entry

10.0.2.15是上面eth0的地址。如果你试图自己重现这一点,请注意你的目标根本不在ARP表中 - 例如,它不能处于STALE状态,它必须完全不存在。

现在,如果我 strace 每次调用(并忽略内存位置的差异),相关差异就是:

$:- diff -uN /tmp/arp-no.trace /tmp/arp-yes.trace
--- /tmp/arp-no.trace   2014-04-23 20:17:46.301575314 -0500
+++ /tmp/arp-yes.trace  2014-04-23 20:17:48.790575314 -0500
@@ -1,4 +1,4 @@
-execve("/sbin/arping", ["arping", "-s", "10.0.2.15", "-f", "10.0.2.4"], [/* 19 vars */]) = 0
+execve("/sbin/arping", ["arping", "-f", "10.0.2.4"], [/* 19 vars */]) = 0
 brk(0)                                  = 0xMEMLOCATION
 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xMEMLOCATION
 access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
@@ -37,7 +37,9 @@
 ioctl(3, SIOCGIFFLAGS, {ifr_name="eth0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
 socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
 setsockopt(4, SOL_SOCKET, SO_BINDTODEVICE, "eth0\0", 5) = 0
-bind(4, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("10.0.2.15")}, 16) = 0
+setsockopt(4, SOL_SOCKET, SO_DONTROUTE, [1], 4) = 0
+connect(4, {sa_family=AF_INET, sin_port=htons(1025), sin_addr=inet_addr("10.0.2.4")}, 16) = 0
+getsockname(4, {sa_family=AF_INET, sin_port=htons(38207), sin_addr=inet_addr("10.0.2.15")}, [16]) = 0
 close(4)                                = 0
 bind(3, {sa_family=AF_PACKET, proto=0x806, if2, pkttype=PACKET_HOST, addr(0)={0, }, 40) = 0
 getsockname(3, {sa_family=AF_PACKET, proto=0x806, if2, pkttype=PACKET_HOST, addr(6)={1, 080027538173}, [18]) = 0
 ... and then the sendto/recvfrom happen ...

如果我指定源IP并且未创建ARP条目,则使用创建,绑定和关闭的短期IPPROTO_IP套接字验证源IP地址。在第二种情况下, arping 使用创建的短暂IPPROTO_IP套接字,connect()ed,getsockname()d和关闭来猜测源IP地址。

之后,程序行为(和网络活动)是相同的。然而,系统反应不是,我看到的唯一的重大差异是每个程序的不同但是无害的使用现在关闭的套接字。

1 个答案:

答案 0 :(得分:2)

很奇怪,不是吗? : - )

我很确定它是我在另一个Arping实现(我的)中调查过的相同的内核错误/功能:

https://blog.habets.se/2012/10/Interesting-Arping-bug-report

没有必要剪切和粘贴冗长的解释,但简而言之:如果你查找路由然后发送原始ARP数据包,那么内核会因某种原因嗅探ARP回复并填充ARP表。 / p>

我不知道为什么,或者它是否甚至是预期的行为。但是内核就是这样做的。