为什么ARP请求非本地地址?

时间:2015-07-14 10:43:42

标签: linux tcp-ip arp

我有一个带有2个NIC的Linux虚拟服务器。

eth0 <IP1>
eth1 <IP2>

arp_filter已开启且rp_filter设为2(宽松模式) 策略路由配置如下:

table T1
default via <GW> dev eth0 src <IP1>
127.0.0.0/8 dev lo
<LAN> dev eth0 src <IP1>

table T2
default via <GW> dev eth1 src <IP2>
127.0.0.0/8 dev lo
<LAN> dev eth1 src <IP2>

ip rule add from <IP1> table T1
ip rule add from <IP2> table T2

之后,我可以ping从外部<IP1><IP2>绑定两个浮点数。但是ping -I eth1 <some_domain>不起作用。 tcpdump表示当我从eth1 ping到外部时,Linux会直接询问MAC外部地址,这是不正确的,因为它们不在同一个LAN中。

以下是tcpdump数据:

root@rm-2:~# tcpdump -i eth1 arp
tcpdump: verbose output suppressed, use -v or -vv for full protocol     decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535     bytes
17:53:08.696191 ARP, Request who-has 172.30.250.119 tell 172.30.248.2, length 46
17:53:08.728482 ARP, Request who-has 172.30.251.144 tell 172.30.251.138, length 46
17:53:09.447252 ARP, Request who-has 61.135.169.125 tell 172.30.251.43, length 28
17:53:09.551514 ARP, Request who-has 172.30.250.127 tell 172.30.248.2, length 46
17:53:09.698076 ARP, Request who-has 172.30.250.119 tell 172.30.248.2, length 46
17:53:09.859046 ARP, Request who-has 172.30.248.246 tell 172.30.248.245, length 46
17:53:10.446009 ARP, Request who-has 61.135.169.125 tell 172.30.251.43, length 28
17:53:10.477104 ARP, Request who-has 172.30.250.128 tell 172.30.248.2, length 46

如你所见,61.135.169.125是一个外国地址,这是一个错误还是什么?

修改
route:// 172.30.248.1的输出是GW

Destination     Gateway         Genmask         Flags Metric Ref    Use      Iface  
default         172.30.248.1    0.0.0.0         UG    0      0        0      eth0

1 个答案:

答案 0 :(得分:4)

答案:

除了ip rule add oif ...之外,您还需要添加输出接口规则(ip rule add from ...),因为ping绑定到接口,而不是IP。

示例:

ip rule add from <IP1> table T1
ip rule add oif <eth0> table T1
ip rule add from <IP2> table T2
ip rule add oif <eth1> table T2

说明:

您问题中的ping示例是使用接口作为源(ping -I eth1 <some domain>),它没有任何匹配的策略路由。因此ping的行为与没有为接口定义的路由完全相同。

测试/证明的示例(无策略路由启动):

使用我的手机USB系留作为替代路线,我有以下基本配置。

Linux desktop:
$ ip addr show usb0
...
inet 192.168.42.1/32 ...
..

Android phone:
$ ip addr show rndis0
...
inet 192.168.42.129/24 ...
...

因为桌面usb0接口被分配了一个/ 32地址,如果我尝试ping 192.168.42.129 -I 192.168.42.1,它将失败,因为没有为该地址定义路由,并且它不在usb0的广播域内< EM>地址。但是,使用ping 192.168.42.129 -I usb0 - 我告诉ping使用接口本身,并且没有匹配接口的路由(因此,没有广播域的概念),所以它会盲目地触发任何不属于自己的IP的ARP请求。

让我们尝试使用接口(无路由)进行ping操作。这将导致ARP请求发生,即使它不在同一个广播域中:

desktop$ ping 192.168.42.129 -I usb0
phone# tcpdump -i rndis0 -n icmp or arp
ARP, Request who-has 192.168.42.129 tell 192.168.42.1, length 28
ARP, Reply 192.168.42.129 is-at 3e:04:37:23:05:0e, length 28
IP 192.168.42.1 > 192.168.42.129: ICMP echo request, id 24641, seq 1, length 64
IP 192.168.42.129 > 192.168.42.1: ICMP echo reply, id 24641, seq 1, length 64

使用接口的源IP(无路由),它不会发出ARP请求,因为源不在广播域中:

desktop$ ping 192.168.42.129 -I 192.168.42.1
phone# tcpdump -i rndis0 -n icmp or arp
... nothing comes over the wire, as expected ...

现在,如果我通过接口向主机添加路由,ping知道它可以为192.168.42.129地址发出ARP请求:

desktop$ ip route add 192.168.42.129/32 dev usb0
desktop$ ping 192.168.42.129 -I 192.168.42.1
phone# tcpdump -i rndis0 -n icmp or arp
ARP, Request who-has 192.168.42.129 tell 192.168.42.1, length 28
ARP, Reply 192.168.42.129 is-at 3e:04:37:23:05:0e, length 28
IP 192.168.42.1 > 192.168.42.129: ICMP echo request, id 24667, seq 1, length 64
IP 192.168.42.129 > 192.168.42.1: ICMP echo reply, id 24667, seq 1, length 64

因此,当我尝试在网络外ping某些内容时,同样的概念也适用;如果我使用接口作为源ping 8.8.8.8,它将盲目地使ARP请求没有任何匹配的路由:

desktop$ ping 8.8.8.8 -I usb0
phone# tcpdump -i rndis0 -n icmp or arp
ARP, Request who-has 8.8.8.8 tell 192.168.42.1, length 28

使用接口地址时,路由表中缺少任何类型的下一跳路由将导致其失败并且不发出ARP请求:

desktop$ ping 8.8.8.8 -I 192.168.42.1
phone# tcpdump -i rndis0 -n icmp or arp
... nothing ...

因此,我们为192.168.42.1地址添加策略路由(使用&#34;来自...&#34;的ip规则),使用192.168.42.129作为下一跳默认值,方式与问题相同例如:

desktop$ sudo ip rule add from 192.168.42.1 lookup T1
desktop$ sudo ip route add default via 192.168.42.129 dev usb0 table T1
desktop$ ping 8.8.8.8 -I 192.168.42.1
PING 8.8.8.8 (8.8.8.8) from 192.168.42.1 : 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=59 time=28.6 ms
...
phone# tcpdump -i rndis0 -n icmp or arp
IP 192.168.42.1 > 8.8.8.8: ICMP echo request, id 24969, seq 1, length 64
IP 8.8.8.8 > 192.168.42.1: ICMP echo reply, id 24969, seq 1, length 64

它有效,因为我们使用地址,它正确匹配ip规则。

现在我们使用界面

再次尝试ping
desktop$ ping 8.8.8.8 -I usb0
PING 8.8.8.8 (8.8.8.8) from 192.168.42.1 usb0: 56(84) bytes of data.
^C
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
...
phone# tcpdump -i rndis0 -n icmp or arp
ARP, Request who-has 8.8.8.8 tell 192.168.42.1, length 28

失败了;下一跳没有接口路由,因此它将再次发出ARP请求,永远不会得到回复。因此,我们需要为接口添加ip规则,以便将192.168.42.129用作下一跳:

desktop$ sudo ip rule add oif usb0 lookup T1
desktop$ ping 8.8.8.8 -I usb0
PING 8.8.8.8 (8.8.8.8) from 192.168.42.1 usb0: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=59 time=10.7 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 10.791/10.791/10.791/0.000 ms
...
phone# tcpdump -i rndis0 -n icmp or arp
IP 192.168.42.1 > 8.8.8.8: ICMP echo request, id 24979, seq 1, length 64
IP 8.8.8.8 > 192.168.42.1: ICMP echo reply, id 24979, seq 1, length 64

我认为通常,缺少接口路由不会对正常的非接口绑定传出连接的实现产生负面影响。大多数(并非所有)应用程序都绑定到地址以用于出站TCP / UDP连接,并且仅绑定到接口以用于传入连接(侦听)。 ping实用程序是一种特殊情况。

为了证明这一点,如果我从路由策略中删除接口规则,我仍然可以在指定bind 地址时使用正常的出站套接字。在下面的示例中,我使用telnet和netcat,在两种情况下指定绑定地址(-b 192.168.42.1)并且它正确匹配T1表,因此使用网关。

# remove the interface route, keep the address route
desktop$ sudo ip rule del from all oif usb0 lookup T1
desktop$ nc -zv 8.8.8.8 443 -s 192.168.42.1
google-public-dns-a.google.com [8.8.8.8] 443 (https) open

phone# tcpdump -i rndis0 -n host 8.8.8.8
IP 192.168.42.1.40785 > 8.8.8.8.443: Flags [S], seq 1678217252, win 29200, options [mss 1460,sackOK,TS val 20223895 ecr 0,nop,wscale 6], length 0
IP 8.8.8.8.443 > 192.168.42.1.40785: Flags [S.], seq 86178051, ack 1678217253, win 28400, options [mss 1432,sackOK,TS val 1937335284 ecr 20223895,nop,wscale 8], length 0
....
desktop$ telnet 8.8.8.8 53 -b 192.168.42.1
...
phone# tcpdump -i rndis0 -n host 8.8.8.8
IP 192.168.42.1.57109 > 8.8.8.8.53: Flags [.], ack 1, win 457, options [nop,nop,TS val 20288983 ecr 4154032957], length 0
IP 8.8.8.8.53 > 192.168.42.1.57109: Flags [F.], seq 1, ack 1, win 111, options [nop,nop,TS val 4154033968 ecr 20288983], length 0

我在测试策略路由实现时遇到了同样的问题,我花了很多时间来理解为什么我的界面ping没有得到答复。希望这可以解决它。