任何人都能看得懂的网络协议之 ARP

 当当网4.23图书3.9折大促 

对于 ARP 协议,你想知道的,可能包括以下几点:

  • ARP 是啥

  • 为啥需要 ARP

  • ARP 是怎么工作的

  • ARP 报文格式长啥样

  • ARP 安全吗

  • 有哪些命令可以操作 ARP

  • ARP 有哪些内核配置参数

带着这些问题,下面我们就来一一解答。

ARP 是啥

ARP 全称为 Address Resolution Protocol ,即地址解析协议,主要用于根据 IP 地址求出主机所对应的物理地址(或者叫 MAC 地址)。

它还有个孪生兄弟叫 RARP(Reverse ARP),即反向地址解析协议,也就是根据主机 MAC 地址求出对应的 IP 地址,但是这个协议不常用,通常只用在无盘系统中。

ARP 只用于 IPv4,IPv6 使用邻居发现协议( Neighbor Discovery Protocol, NDP) 来代替 ARP 的功能。

为啥需要 ARP

在网络通信中,主机和主机之间的通信需要根据 OSI 模型进行数据包的封装和解封装,这里面不仅需要封装源目的 IP 地址,也需要源目的 MAC 地址,那么 MAC 地址从哪里来呢,一般情况下,上层应用只知道 IP 地址,而并不关心 MAC 地址,所以就需要通过一个协议来获知目的 MAC 地址,完成数据的封装,这个协议就是 ARP 协议该干的活。

ARP 是怎么工作的

在介绍 ARP 如何工作之前,需要知道一个概念 ARP 缓存表 。在每台安装有 TCP/IP 协议的电脑或网络设备里都有一个 ARP 缓存表,表中记录的是 IP 地址和 MAC 地址的映射关系,比如:

任何人都能看得懂的网络协议之 ARP_第1张图片

以上表中的主机 A 向主机 B 发送数据为例,说一下 ARP 的工作流程:

  1. 当发送数据时,主机 A 会在自己的 ARP 缓存表中寻找是否有目标 IP 地址,如果找到,就把对应的目标 MAC 地址封装进帧里进行发送。

  2. 如果没有找到,主机 A 就会向网络中发送一个广播(ARP request),和主机 A 同网段内的所有主机都会收到这个请求,该请求的目标 MAC 地址是"FF.FF.FF.FF.FF.FF",目标 IP 是主机 B 的 IP。

  3. 只有主机 B 会接收这个请求,并且向主机 A 做出回应(ARP response),而其他主机接收到请求之后发现目标 IP 不是自己,就会选择丢弃。主机 B 从请求中获得主机 A 的 MAC 地址和 IP 地址,所以会以单播的方式进行回应,同时更新自己的 ARP 缓存表。

  4. 主机 A 接收到主机 B 的响应之后,也会更新自己的 ARP 缓存,下次再访问主机 B 时,就直接从 ARP 缓存里查找即可。

ARP缓存超时: 既然是缓存表,意味着有时效性。ARP 缓存表采用老化机制,在一段时间内如果表中的某一条目没有使用,就会被删除,这样可以减少缓存表的长度,加快查询速度。

缓存时间,一般是 20 分钟 ,但 RFC 也有规定一些不完整条目是 3 分钟,什么是不完整条目,比如下面这条,对一个不存在的主机执行了一次 ARP 请求,就是一条不完整的条目:

# arp -a
?(10.0.0.99) at  on eth0

ARP 报文格式长啥样

首先看一个以太网帧中,ARP 报文处在一个什么位置。

以下是一个以太网帧的简化图,这里只是为了说明 ARP 报文在整个以太网帧中所处的位置,所以这个以太网帧并不是完整的。

任何人都能看得懂的网络协议之 ARP_第2张图片

我们看到,以太网帧通过一个 2 字节的帧类型来表示它后面的数据负载(payload)部分具体是什么类型的数据,如果帧类型是 16进制的 0x0800,则表示 payload 是 IP 报文,如果是 0x0806,就表示 ARP 报文,包括 ARP 请求报文和应答报文。当然,这里还有其他类型的数据,比如 ARAP,我们就不一一列出了。

下面,继续走进 ARP 报文内部,看看它包含哪些字段:

任何人都能看得懂的网络协议之 ARP_第3张图片

  • 硬件类型:指出硬件地址类型,对于以太网,该值是 1

  • 协议类型:指出网络层协议类型,对于 IPv4,该值是 0x0800

  • 硬件大小和协议大小:分别指出后面的硬件地址和协议地址的大小,对于使用 IPv4 的 ARP 报文,该值分别是 6 和 4

  • Op:指出该报文是 ARP 请求(值为 1)、ARP 应答(2)、RARP 请求(3) 或 RARP 应答(4)

  • 后面的 4 个字段和前面 4 个字段对应,分别表示源目的 MAC 和源目的 IP 地址

我们通过 Wireshark 抓包看看。

ARP 请求报文:

任何人都能看得懂的网络协议之 ARP_第4张图片

ARP 应答报文:

任何人都能看得懂的网络协议之 ARP_第5张图片

可以看到 Op 字段,对于 ARP 请求和应答报文分别为 1 和 2,其他字段大家也可以看看,比较直观。

ARP 安全吗

ARP 提供的功能简单高效,但和所有网络协议一样,它并不是完美的。它的不完美主要体现在它并不安全。

  1. ARP 报文没有任何认证。攻击者可以发送伪造的 ARP 报文(尤其是应答报文),恶意修改网关或网络内其他主机的 ARP 表项,造成报文的转发异常,这就是 ARP 欺骗攻击( ARP spoofing )。

  2. ARP 报文没有状态。它不会去检查自己是否发过请求包,也不知道自己是否发过请求包,也不管应答是否合理,只要收到目标 MAC 是自己的 reply 或者 request 广播包,都会照单全收,写进自己的 ARP 缓存,原有相同的表项就会被替换。如果攻击者利用这一特性,发送大量伪造的 ARP 应答报文,造成主机 ARP 表项溢出,导致无法缓存正常的 ARP 表项,从而影响报文的正常转发,这就是大名鼎鼎的拒绝服务攻击(DDoS)或 ARP 泛洪攻击。

这两种攻击都会导致:

  1. 网络不稳定,引发用户无法上网或者企业断网导致重大生产事故。

  2. 非法获取游戏、网银、文件服务等系统的帐号和口令,给被攻击者造成利益上的重大损失。

解决方案

那么遇到这些攻击,该如何避免呢?

因为攻击者在暗处,我们用户在明处,显然无法知道攻击者的信息,从而加以检测。所以就只能从我们自己身上来避免了。主要要做到两点:

  1. 保证不接收 ARP 欺骗包

  2. 保证接收到 ARP 欺骗包之后不相信,直接丢弃

那么根据这两点,业界也提出了一些方案,比如

动态 ARP 检测方案(DAI)

这种方案一般是在网络设备(比如交换机和路由器)上来做,在攻击数据进入用户主机之前,就将它阻隔。

简单来说,就是交换机或者路由器维护着一个 DAI 表,表中记录这每个接口对应的 IP 和 MAC,比如:port<->mac<->ip。如果当某个接口收到的 ARP 应答包,IP 和 MAC 对应关系和 DAI 表中记录的不一致,那么就可以将这个包丢弃。

一般这种技术都只用在高端的网络设备上,基本都是企业级的产品。

对于我们普通用户,没必要为了防止 ARP 攻击而去买这种设备,那应该怎么办呢?

这就只能在自己的电脑端加以防护了,我们可以:

1)安装 ARP 防火墙 ,很多安全产品都自带这个功能,比如腾讯电脑管家,360安全卫士等,也有专业的 ARP 防火墙,比如金山贝壳,360 ARP 防火墙等。这些防火墙的技术原理,主要是根据网络数据包的特征,自动识别局域网存在的 ARP 扫描和欺骗行为,并做出攻击判断(哪个主机做了攻击,IP 和 MAC 是多少)。

2)自己手动绑定局域网 IP 和 MAC 的映射关系 ,这样即便收到 ARP 欺骗包,由于静态绑定的 ARP 项优先级高于动态学习到的,可以保证不被欺骗。这种方法的缺点也很明显,如果局域网内的主机很多的话,工作量将会很大。

有哪些命令可以操作 ARP

① arp

用法:

# arp (选项)(参数)

-a <主机IP>:显示 arp 缓冲区中的所有条目
-e:以 Linux 的显示风格显示 arp 缓冲区中的条目
-v:显示详细的 arp 缓冲区条目,包括缓冲区条目的统计信息
-i <接口>:显示指定接口的 arp 缓存条目
-s <主机IP>:配置主机的 IP 地址与 MAC 地址的静态映射
-d <主机>:删除 arp 条目
-f <文件>:从文件 /etc/ethers(默认)或者指定文件中记录的 arp 条目配置静态映射

② ip neigh

ip neigh 是和 arp 相同功能但不同用法的另一套命令,全称为 ip neighbour

用法:

# ip neigh help
ip neigh { add | del | change | replace }
         { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]
ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ][ vrf NAME ]

# 其中几个选项的意思解释
- to ADDR: 协议地址,指定主机的 IP 地址
- dev DEV: 指定网口
- lladdr LLADDR: 指定 MAC 地址
- nud STATE: 状态值,有以下几个值:
    - permanent:永久有效
    - noarp:有效,不会验证此条目,但可以在其生命周期到期时将其删除
    - reachable:有效,直到可达性超时到期
    - stale:有效但可疑
    - all:列出所有状态

# 常用操作

1. 列出所有 arp 条目
# ip neigh show

2. 添加 arp 静态条目
# ip neigh add 192.168.10.11 lladdr 00:01:02:03:04:05 dev eth0

3. 删除指定 IP 或者网口的 arp 条目
# ip neigh del 192.168.10.11 dev eth0

4. 刷新 arp 表
# ip neigh flush 192.168.10.11

# 此外还有两个命令,可以更改 arp 条目
# ip neighbour change - 更改
# ip neighbour replace - 添加新的或更改

③ arping

arping 和 ping 相似,主要是通过发送 ARP 请求查看 IP 和 MAC 的映射关系,以及探测 IP 的冲突问题。更多的用法可以参见这篇文章 xxx

④ arpwatch

arpwatch 主要用于监听网络中的 ARP 数据的变化关系并记录,可以将监听到的变化通过 E-mail 发送。

用法:

# arpwatch [-d][-f <记录文件>][-i <接口>][-r <记录文件>]

监听 eth0 的 ARP 信息
# arpwatch -i eth0

将监听到的 ARP 记录存储到文件
# arpwatch -i eth0 -f /var/arpwatch/arp.dat

从指定文件中读取 ARP 记录,而不是从网络中监听
# arpwatch -r /var/arpwatch/arp.dat

ARP 有哪些内核配置参数

从上文我们知道,ARP 是一个无状态协议,就是说它不管自己是否发过请求,也不管应答是否合理,再加上广播的特性,有时候通信上会出现一些匪夷所思的问题,系统会通过以下几个配置参数来规避这些问题。

要说清楚这些参数,我们先上个图:

任何人都能看得懂的网络协议之 ARP_第6张图片

在这样一个局域网的图示中,B 向 A 的 eth0 接口发送 ARP 请求,由于是广播,并且 IP 地址针对的是整个主机,而不是特定的某个接口,所以,A 的两个口 eth0 和 eth1 都会接收请求并发出应答,而 B 则以最后应答的 MAC 地址为准。

这就会带来第一个问题,如果 B 本来想获取 eth0 的 MAC 地址,但却得到 eth1 的,这就会导致后续发送数据的不准确。

解决这个问题可以用两个内核参数,这两个参数都是在 ARP 应答上做文章,让它能够正确应答。

① arp_ignore

定义了对本机 IP 的 ARP 请求时不同的应答模式,它有 8 个整数值:

  • 0:默认值,对本机某个网口的 ARP 请求,所有网口都可以进行 ARP 应答

  • 1:只应答被请求的网口

  • 2:只应答被请求的网口,且请求的 IP 必须在该网口的子网段内

  • 3:不应答该网口的 arp 请求,而只对设置的唯一和连接地址做出回应

  • 4-7:保留未使用

  • 8:不应答所有(本地地址)的 ARP 请求

所以,解决上面的问题,只需要让该网口的 arp_ignore=1即可。

在内核参数中,除了每个网口都有自己的 arp_ignore 配置外,还有两个(一个是默认 default,一个是全局 all),如下。一般,如果网口自身的 arp_ignore 不配置的情况下,使用 default 的配置,如果 all 和网口自身都配置的情况下,使用两者中较大的那一个。

# sysctl -a | grep arp_ignore
net.ipv4.conf.default.arp_ignore=1
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.lo.arp_ignore=1
net.ipv4.conf.eth0.arp_ignore=1
net.ipv4.conf.eth1.arp_ignore=1

关于配置这块,有临时生效和永久生效的配置方式,文末有进一步说明。

② arp_filter

这个参数和 arp_ignore能够达到相同的目的,但 arp_filter会更严格一些,它在选网口应答的时候会按照路由来选。它是一个 bool 值,具体为:

  • 0:默认值,所有网口都可以响应 ARP 请求

  • 1:会根据本机路由表来验证哪个网口应该进行应答,优先选择在路由表前面的网口,也就是会有一个反向路由验证的过程。

同样,他也有以下的参数:

$ sysctl -a | grep arp_filter
net.ipv4.conf.all.arp_filter = 0
net.ipv4.conf.default.arp_filter = 0
net.ipv4.conf.eth0.arp_filter = 0
net.ipv4.conf.eth1.arp_filter = 0
net.ipv4.conf.lo.arp_filter = 0

上面两个参数解决的是 ARP 应答方向上的问题,而下面的 arp_announce 是解决 ARP 请求方向上的问题。它可以控制本机发出的 ARP 请求中的源 IP 地址使用哪个网口的地址。

③ arp_announce

它有以下 3 个整数值:

  • 0:默认值,可以在任意网口上发送 ARP 请求,但是请求的源 IP 地址与当前发送的网口没有关系。也就是说如果源 IP 地址与当前发送网口的地址不同(使用其他网口作为源 IP 地址),使用原本的源 IP 地址。

  • 1:要求尽量避免使用不在当前发送网口子网段内的 IP 地址作为 ARP 请求的源 IP 地址,也就是说系统会遍历所有网口的 IP,然后看哪个网口的 IP 和 ARP 请求包中的源 IP 在同一个网段内,优先选择哪个进行发送,如果都不在,就采用下面级别 2 的方式来选择。

  • 2:1 是看源 IP 地址,这种方式是看目标 IP 地址,选择与目标 IP 地址在同一个网段内的网口 IP 作为 ARP 请求的源 IP 地址,如果还是没找到,则直接选择当前网口的 IP 或者能够接受到 ARP 回应的网口 IP 来发送 ARP 请求,并设源 IP 为发送网口的 IP。

此外,还有两个参数:

④ arp_accept

默认对不在 ARP 表中的 IP 地址发出的 APR 包的处理方式

  • 0:不在 ARP 表中创建对应 IP 地址的表项

  • 1:在 ARP 表中创建对应 IP 地址的表项

⑤ arp_notify

ARP 通知链操作

  • 0:不做任何操作

  • 1:当设备或硬件地址改变时自动产生一个 ARP 请求

附参数配置方法:

Linux内核各种参数的配置,包括以上几个,也包括其他的一些参数,配置上都可以参考以下两种方法:

1、临时生效的配置方法

1)使用 sysctl -w 参数配置

# sysctl -w net.ipv4.conf.default.arp_ignore=1
# sysctl -w net.ipv4.conf.all.arp_ignore=1

2)修改内核参数的映射文件

# echo 1 > /proc/sys/net/ipv4/conf/default/arp_ignore
# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore

2、永久生效的配置方法

在 /etc/sysctl.conf 配置文件中加入如下的配置项:

net.ipv4.conf.default.arp_ignore=1
net.ipv4.conf.all.arp_ignore=1

然后一定记得执行 sysctl -p 使之生效。

总结

本文我们从 ARP 基本概念,到报文结构,再到安全相关的内容,最后到命令、相关内核参数配置上,可以说基本囊括了 ARP 协议的所有内容,大家还有什么内容想交流可以留言指出。


后台回复“加群”,带你进入高手如云交流群

推荐阅读:

3.9折图书限时秒杀!当当网这次要被薅惨了

用好你的网络瑞士军刀netcat

一次Linux系统被攻击的分析过程

Linux下删除大量文件效率对比

130 个相见恨晚的神器网站

分享20个Linux命令小贴士与技巧

一文带你彻底理解文件系统

5G与Wi-Fi6空口技术对

内存泄漏(增长)火焰图

TCP-RST 攻击与防护,看这一篇就够了

探究!一个数据包在网络中的心路历程

牛逼的Linux性能剖析—perf

HTTPS 的 7 次握手以及 9 倍时延

NFV和SDN之间到底有什么关系?

Linux 程序编译过程的来龙去脉

一文搞定 UDP 和 TCP 高频面试题!


喜欢,就给我一个“在看”


10T 技术资源大放送!包括但不限于:云计算、虚拟化、微服务、大数据、网络、Linux、Docker、Kubernetes、Python、Go、C/C++、Shell、PPT 等。在公众号内回复「1024」,即可免费获取!!

你可能感兴趣的:(任何人都能看得懂的网络协议之 ARP)