对于ARP协议, 我本来是不了解的,只是解决了两个ARP相关的P2的Bug后,也就懂了。本文将从原理的角度对ARP做一个透析。
1. 什么是ARP?
ARP(Address Resolution Protocol),也就是地址解析协议。解析什么地址?将IP地址解析为以太网MAC地址(i.e. 物理地址)的协议。在以太网当中 , 网络设备是通过物理地址表示的 , 这个物理地址就是48位的以太网地址。 简言之,ARP 协议是用来将 32 位的IP地址解析为48 位的以太网地址的协议。
2. 为什么需要ARP协议?
在局域网中,当主机或其他网络设备有数据要发送给另一个主机或设备时,它必须知道对方的网络层地址(也就是IP地址)。但是,仅仅知道IP地址是不够的,因为IP数据报文必须封装成帧(frame)才能通过物理网络发送,因此发送站还必须有接收站的物理地址,所以需要一个从IP地址到物理地址的映射。于是,ARP协议应运而生。
3. ARP报文格式
ARP是一个独立的三层协议,所以ARP报文在向数据链路层传输时不需要经过IP协议的封装,而是直接生成自己的报文,其中包括ARP报头,到数据链路层后再由对应的数据链路层协议(如以太网协议)进行封装。 ARP报文分为ARP请求和ARP应答报文两种,其报文格式定义如下:
一个典型的ARP请求包看起来是这个样儿滴,
在Linux源代码中,ARP报头是这么定义的,
/* http://src.illumos.org/source/xref/linux-master/include/uapi/linux/if_arp.h#139 */ 139 /* 140 * This structure defines an ethernet arp header. 141 */ 142 143 struct arphdr { 144 __be16 ar_hrd; /* format of hardware address */ 145 __be16 ar_pro; /* format of protocol address */ 146 unsigned char ar_hln; /* length of hardware address */ 147 unsigned char ar_pln; /* length of protocol address */ 148 __be16 ar_op; /* ARP opcode (command) */ 149 150 #if 0 151 /* 152 * Ethernet looks like this : This bit is variable sized however... 153 */ 154 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ 155 unsigned char ar_sip[4]; /* sender IP address */ 156 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ 157 unsigned char ar_tip[4]; /* target IP address */ 158 #endif 159 160 };
下面对arp header的各个字段做一个说明:
- Hardware type (硬件类型): 占2个字节,表示ARP报文可以在哪种类型的网络上传输,当值为1时表示为以太网。
- Protocol type (上层协议类型): 占2个字节,表示硬件地址要映射的上层协议地址类型, 当上层协议为IP时其值为0x0800。
- Hardware address length(硬件地址长度): 占1个字节,标识MAC地址长度,以字节为单位,此处为6。
- Protocol address length(上层协议地址长度): 占1个字节,标识IP地址长度时,以字节为单位,此处为4。
- Operation code(操作类型): 占2个字节,指定本次ARP报文的类型。1-ARP请求,2-ARP应答。
- Sender hardware address(发送方硬件地址): 占6个字节,表示发送方设备的硬件地址。
- Sender protocol address(发送方上层协议地址): 占4个字节,表示发送方设备的上层协议地址,对以太网来说就是发送方设备的IP地址。
- Target hardware address(接收方硬件地址): 占6个字节,表示接收方设备的硬件地址。注意: 在请求报文中该字段值全为0, 即00-00-00-00-00-00,表示任意地址,因为现在还不知道目标的MAC地址。
- Target protocol address(接收方上层协议地址): 占4个字节,表示接收方设备的上层协议地址,对以太网来说就是接收方设备的IP地址。
ARP报文并不是直接在网络层发送的,它还是需要向下传输到数据链路层,所以当ARP报文传输到数据链路层后,需要再次进行封装。以以太网为例,ARP报文传输到以太网数据链路层后会形成ARP帧。一个典型的以太网帧看起来是这样子滴,
以太网帧头中包含了三个字段,说明如下:
- Destination address(目标MAC地址): 占6个字节,如果是ARP请求帧,因为它是一个广播帧,所以要填上广播MAC地址 -- FF-FF-FF-FF-FF-FF,其目标是网络上的所有主机。
- Source address (源MAC地址): 占6个字节,发送ARP帧的节点的MAC地址。
- Type (类型): 占2个字节,用来标识帧封装的上层协议,因为本帧的数据部分是ARP报文,所以直接用ARP的协议号0x0806表示即可。
4. ARP地址解析原理
无论是主机还是交换机,都有一个用来缓存同一网络设备IP地址和MAC地址的ARP映射表,用于数据帧的转发。设备通过ARP解析到目标MAC地址后,将会在自己的ARP映射表中增加IP地址到MAC地址的映射表项,以用于后续到同一目的地数据帧的转发。 ARP表项分为动态ARP表项和静态ARP表项,这里不做详细介绍,只简单介绍一下动态ARP表项。 动态ARP表项由ARP协议通过ARP报文自动生成和维护,可以被老化,可以被新的ARP报文更新,也可以被静态ARP表项所覆盖。当到达老化时间或接口关闭时会删除相应的动态ARP表项。
为了讲述ARP地址解析原理,先上个图,该图来源于Book 《COMPUTER NETWORKS》(FIFTH EDITION) Page 468。
4.1 同一网段中两个主机的ARP地址解析 (Host 1 <---> Host 2)
Host # | IP | MAC |
Host 1 | IP1: 192.32.65.7 | E1: B8:AE:ED:BF:EE:B6 |
Host 2 | IP2: 192.32.65.5 | E2: C0:7C:D1:3D:17:19 |
- 101 - Host 1 首先查看它自己的ARP表(一个IP地址与MAC地址的映射表),确定其中是否包含Host 2的IP地址和对应的MAC地址。如果找到了对应的MAC地址E2, 则Host 1直接利用ARP表中找到的MAC地址E2对IP数据包进行帧封装,并将数据包发送给Host 2;
- 102 - 如果Host 1在ARP表中找不到对应的MAC地址E2, 则先缓存该数据报文,按后以广播方式(目标MAC地址为广播MAC地址 - FF:FF:FF:FF:FF:FF, 在同一个网段里的任何节点都能收到)发送一个ARP请求报文。 在这个ARP请求报文中,发送端(源)IP地址为IP1(192.32.65.7), 发送端(源)MAC地址为E1(B8:AE:ED:BF:EE:B6), 目的IP地址为IP2(192.32.65.5), 目的MAC地址为00:00:00:00:00:00(因为还不知道目的MAC地址是啥)。 因为ARP请求报文是以广播的方式发送,所以该网段上的所有主机都可以接收到该请求包,但只有其IP地址与目的IP地址一致的Host 2才会对该请求进行处理。那些IP地址与目的IP地址不一致的Host会把该ARP请求包直接drop掉;
- 103 - Host 2将ARP请求报文中的发送端(即Host 1)的IP地址(192.32.65.7)和MAC地址(B8:AE:ED:BF:EE:B6)存入自己的ARP表中,然后以单播的方式向Host 1发送一个ARP响应报文,该响应报文中就包含了它的MAC地址E2(C0:7C:D1:3D:17:19), 也就是原来在请求报文要请求的目的MAC地址;
- 104 - Host 1在收到来自Host 2的ARP响应报文后,将Host 2的MAC地址E2(C0:7C:D1:3D:17:19)加入到自己的ARP表中以用于后续报文的转发,同时将原来缓存的IP数据包再次修改(在"目的MAC地址"字段填上Host 2的MAC地址E2(C0:7C:D1:3D:17:19))后发送出去。
P.S. 下面给出一张来自Mellanox的培训材料截图,以帮助更好地理解以太网的ARP原理
4.2 不同网段的两个主机的ARP地址解析
Node # | IP | MAC |
Host 1 | IP1: 192.32.65.7 | E1: B8:AE:ED:BF:EE:B6 |
Gateway |
193.32.65.1/192.168.63.1 |
E3/E4: |
Host 4 | IP4: 192.32.63.8 | E6: 6C:92:BF:1B:54:07 |
- 201 - 如果Host 1不知道网关的MAC地址(也就是在Host 1的ARP表中没有网关对应的MAC地址表项),则Host 1现在本网段(192.32.65.0/24)中发出一个ARP请求广播包,ARP请求报文中的目的IP地址为网关的IP地址(192.168.65.1),代表其目的就是想获得网关的MAC地址。如果Host 1已经知道网关的地址,则略过此步;
- 202 - 网关收到ARP广播包后同样会给Host 1发送一个ARP应答包。当Host 1从收到的ARP报文中获得网关的MAC地址后,在Host 1向Host 4发送的原报文的目的MAC地址字段填上网关的MAC地址后发给网关;
- 203 - 如果网关的ARP表中已经有Host 4对应的MAC地址,则网关直接将来自Host 1的报文中的目的MAC地址字段替换为Host 4的MAC地址后转发给Host 4;
- 204 - 如果网关的ARP表中还没有Host 4对应的MAC地址,则网关会再次向Host 4所在的网段发送ARP广播请求,此时目的IP地址为Host 4的IP地址。当网关收到来自Host 4的应答报文后,从中获取到Host 4的MAC地址,就把由Host 1发来的报文重新在目的MAC地址字段替换为Host 4的MAC地址后发送给Host 4。
5. ARP诊断工具
- arp(8) - manipulate the system ARP cache
- arping(8) - send ARP REQUEST to a neighbour host
e.g.
$ arp -a localhost (192.168.1.1) at 0c:72:2c:c0:02:c8 [ether] on eth0 $ ping 192.168.1.103 PING 192.168.1.103 (192.168.1.103) 56(84) bytes of data. 64 bytes from 192.168.1.103: icmp_seq=1 ttl=64 time=2431 ms 64 bytes from 192.168.1.103: icmp_seq=2 ttl=64 time=1424 ms 64 bytes from 192.168.1.103: icmp_seq=3 ttl=64 time=417 ms 64 bytes from 192.168.1.103: icmp_seq=4 ttl=64 time=2.84 ms ^C --- 192.168.1.103 ping statistics --- 5 packets transmitted, 4 received, 20% packet loss, time 4015ms rtt min/avg/max/mdev = 2.842/1069.057/2431.390/941.354 ms, pipe 3 $ arp -a localhost (192.168.1.103) at 1c:77:f6:71:cc:fc [ether] on eth0 localhost (192.168.1.1) at 0c:72:2c:c0:02:c8 [ether] on eth0 $ arping -I eth0 -s 192.168.1.102 192.168.1.103 ARPING 192.168.1.103 from 192.168.1.102 eth0 Unicast reply from 192.168.1.103 [1C:77:F6:71:CC:FC] 63.293ms Unicast reply from 192.168.1.103 [1C:77:F6:71:CC:FC] 292.082ms Unicast reply from 192.168.1.103 [1C:77:F6:71:CC:FC] 519.626ms ^CSent 4 probes (2 broadcast(s)) Received 3 response(s)
参考资料:
- https://en.wikipedia.org/wiki/Address_Resolution_Protocol
- http://www.eventhelix.com/RealtimeMantra/Networking/Arp.pdf
- http://www.cs.virginia.edu/~cs458/slides/module06-arpV2.pdf
- https://tools.ietf.org/html/rfc826