Yang's Blog

for anything.

ARP 广播拿到错误 MAC 地址

线上服务器有时候会无缘无故发生 Zabbix Server 误报机器 Zabbix Agent 不存活的情况,而且发生的非常没有规律。但是过一段之后之后自然就好了。服务也没有各种异常发生。机器这段时间也并没有做过任何改动,甚至都没有登陆过。

报警的机器一般都是有2块网卡的,eth0 接的内网IP,eth1 接公网IP。网络配置如下:

eth0: 10.211.55.2

eth1: 220.0.0.2

防火墙基本配置如下:

iptables -A INPUT -i eth0 -j ACCEPT
iptables -A INPUT -i eth1 -t tcp --dport 80 -j ACCEPT
iptables -A INPUT -m state —state  RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -j DROP

防火墙配置主要是让内网全部放行,公网只放行80端口和已建立连接的请求。

在又一次误报的时候,我尝试登到 Zabbix Server 尝试 telnet 机器的10080端口,发现竟然超时了!但是在其他机器上 telnet 却没有超时。查看 arp 记录。发现在 zabbix 的 arp 表是这样的:

root@zabbix:~# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.211.55.2              ether   00:1c:42:d3:a6:de   C                     eth0

但是在其他机器上的 arp 表却是这样的:

root@host:~# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.211.55.2              ether   00:1c:42:00:00:08   C                     eth0

zabbix 的机器竟然拿到错误的 MAC 地址了!

登陆到 10.211.55.6,查看其 IP:

root@bug:~# ifconfig
eth0        Link encap:Ethernet  HWaddr 00:1c:42:00:00:08
            inet addr:10.211.55.6  Bcast:10.211.55.255  Mask:255.255.255.0
            ...
eth1        Link encap:Ethernet  HWaddr 00:1c:42:d3:a6:de
            inet addr:220.0.0.2  Bcast:220.0.0.255  Mask:255.255.255.0
            ...

发现 zabbix 的服务期在找 10.211.55.6 这台机器的时候拿到了220.0.0.2的 MAC 地址。可是为什么呢,使用 tcpdump 抓包:

arp who-has 10.211.55.2 tell 10.211.55.1
arp reply 10.211.55.2 is-at 00:1c:42:d3:a6:de

是 arp 回应的时候就拿到了一个错误的 MAC 地址。

但是因为这个 MAC 地址对应的 eth1 网口只开放了80端口,其他端口都是 DROP 掉得。这就解释了为什么无法telnet通10080端口了。

可是为什么会这样呢。通过查看文档,发现 ARP 的定义是这样的:

arp_filter - BOOLEAN
    1 - Allows you to have multiple network interfaces on the same
    subnet, and have the ARPs for each interface be answered
    based on whether or not the kernel would route a packet from
    the ARP'd IP out that interface (therefore you must use source
    based routing for this to work). In other words it allows control
    of which cards (usually 1) will respond to an arp request.

    0 - (default) The kernel can respond to arp requests with addresses
    from other interfaces. This may seem wrong but it usually makes
    sense, because it increases the chance of successful communication.
    IP addresses are owned by the complete host on Linux, not by
    particular interfaces. Only for more complex setups like load-
    balancing, does this behaviour cause problems.

    arp_filter for the interface will be enabled if at least one of
    conf/{all,interface}/arp_filter is set to TRUE,
    it will be disabled otherwise

原文在这里

大概翻译过来就是:当有一个 ARP 广播请求一个 MAC 地址时,本机会查看自己是否拥有这个 IP,只要本机任何端口拥有该IP,就会随机返回一个网口的 MAC 地址。

具体解释就是: 机器不管你的请求通过哪个网卡进来,反正请求能进到这台机器,就行了。

处理方法有两种:

  • 按照文档的介绍,将 /proc/sys/net/ipv4/conf/all/arp_filter 设为 1 即可。

  • 将防火墙设置为以 IP 段划分,不以网口划分。具体如下:

    iptables -A INPUT -s 10.211.55.0/24 -j ACCEPT
    iptables -A INPUT -t tcp --dport 80 -j ACCEPT
    iptables -A INPUT -m state —state  RELATED,ESTABLISHED -j ACCEPT
    iptables -A INPUT -j DROP