ARP(地址解析协议)如何工作?

时间:2020-03-21 11:44:04  来源:igfitidea点击:

如果网络中的两台计算机知道彼此的物理地址,则它们只能相互通信。
尽管计算机程序使用IP地址发送和接收消息,但实际的基础通信始终在物理地址上进行。

首先,让我们了解一下如何通过网络进行通信。
让我们尝试通过计算机对Google的公用dns服务器执行ping操作,并尝试捕获网络数据包并查看源地址和目标地址。

tcpdump是用于捕获网络数据包并查看详细信息的工具。

root@ip-10-12-2-73:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=39 time=9.16 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=39 time=9.28 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=39 time=9.31 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=39 time=9.32 ms

现在,在上述ping操作正常的同时,让我们尝试使用同一服务器上的另一个Shell会话捕获网络数据包。
用于捕获网络数据包的命令是tcpdump -n host 8.8.8.8

-n主机8.8.8.8仅捕获源或者目标为8.8.8.8的数据包(而且,它将在输出中显示IP地址而不是dns名称。
这是由于-n参数所致)。

root@ip-10-12-2-73:~# tcpdump -n host 8.8.8.8
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
21:39:41.531390 IP 10.12.2.73 > 8.8.8.8: ICMP echo request, id 16331, seq 1, length 64
21:39:41.540342 IP 8.8.8.8 > 10.12.2.73: ICMP echo reply, id 16331, seq 1, length 64
21:39:42.531815 IP 10.12.2.73 > 8.8.8.8: ICMP echo request, id 16331, seq 2, length 64
21:39:42.540840 IP 8.8.8.8 > 10.12.2.73: ICMP echo reply, id 16331, seq 2, length 64

tcpdump命令的输出非常简单。
它显示了一系列从服务器发出的ICMP回显请求(由10.12.2.73指示),以及从google返回的后续答复(由8.8.8.8指示)。

由于8.8.8.8不在同一个网络中,因此如果没有网关,我的服务器将无法直接到达那里。
因此,我对8.8.8.8的ping请求应该通过我的网关。
网关地址可以使用命令route -n找到

root@ip-10-12-2-73:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.12.2.1       0.0.0.0         UG    0      0        0 eth0
10.12.2.0       0.0.0.0         255.255.255.0   U     0      0        0 eth0

我们的网关是10.12.2.1.
上面输出中的第一行清楚地表明了这一点。
为了到达任何地方(以0.0.0.0表示),数据包应通过10.12.2.1的网关地址流动。

因此,即使我们需要达到8.8.8.8,也需要通过10.12.2.1(因为它是我们的网关)。
但是,为什么tcpdump输出未显示10.12.2.1(网关)的任何痕迹?

Tcpdump显示源地址为10.12.2.73,目标地址为8.8.8.8.
由于8.8.8.8不属于我们的本地网络,因此我们将不得不通过10.12.2.1的网关地址。
所以目标地址应该是10.12.2.1,对吧?
否则我们的数据包将如何到达网关?

我们的ping正常运行。
因此,它肯定会使用网关达到8.8.8.8(因为没有其他出路)。
但是其中是数据包中的网关地址。
该数据包显示的目标地址为8.8.8.8.
但是,它如何到达网关?

这正是物理地址(MAC地址)介入的地方。

随着对8.8.8.8的ping操作的进行,让我们在另一个会话上再次执行tcpdump(这次使用添加选项-e。

root@ip-10-12-2-73:~# tcpdump -e -n host 8.8.8.8
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
21:47:56.820194 12:6e:eb:de:b3:ed > 12:6f:56:c0:c4:c1, ethertype IPv4 (0x0800), length 98: 10.12.2.73 > 8.8.8.8: ICMP echo request, id 16347, seq 1, length 64
21:47:56.829102 12:6f:56:c0:c4:c1 > 12:6e:eb:de:b3:ed, ethertype IPv4 (0x0800), length 98: 8.8.8.8 > 10.12.2.73: ICMP echo reply, id 16347, seq 1, length 64
21:47:57.821516 12:6e:eb:de:b3:ed > 12:6f:56:c0:c4:c1, ethertype IPv4 (0x0800), length 98: 10.12.2.73 > 8.8.8.8: ICMP echo request, id 16347, seq 2, length 64
21:47:57.830386 12:6f:56:c0:c4:c1 > 12:6e:eb:de:b3:ed, ethertype IPv4 (0x0800), length 98: 8.8.8.8 > 10.12.2.73: ICMP echo reply, id 16347, seq 2, length 64

这次与ip地址一起,我们还可以在输出中看到物理地址(mac地址)。
由12:6e:eb:de:b3:ed> 12:6f:56:c0:c4:c1和12:6f:56:c0:c4:c1> 12:6e:eb:de:b3:ed表示。

root@ip-10-12-2-73:~# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 12:6e:eb:de:b3:ed  
          inet addr:10.12.2.73  Bcast:10.12.2.255  Mask:255.255.255.0
          inet6 addr: fe80::106e:ebff:fede:b3ed/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:1200693 errors:0 dropped:0 overruns:0 frame:0
          TX packets:945763 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2452613050 (2.4 GB)  TX bytes:447161879 (447.1 MB)

从上面的ifconfig命令输出中,我们可以确认12:6e:eb:de:b3:ed是我们服务器的mac地址(在ifconfig输出中由HWaddr 12:6e:eb:de:b3:ed指示)。

但是12:6f:56:c0:c4:c1是什么?
我们可以使用一个名为arp -n -a的命令来找出12:6f:56:c0:c4:c1是什么。
ARP代表地址解析协议。
它完成将IP地址转换为MAC地址的工作。
因此,arp -n -a将显示我们的服务器知道的所有mac地址及其等效的IP地址。
我们将很快进入arp及其工作。

root@ip-10-12-2-73:~# arp -n -a
? (10.12.2.40) at 12:f7:fd:48:aa:79 [ether] on eth0
? (172.17.0.2) at 02:42:ac:11:00:02 [ether] on docker0
? (10.12.2.43) at 12:48:08:aa:a5:bb [ether] on eth0
? (10.12.2.8) at 12:ab:ed:67:34:79 [ether] on eth0
? (10.12.2.94) at 12:47:87:c2:60:8d [ether] on eth0
? (10.12.2.1) at 12:6f:56:c0:c4:c1 [ether] on eth0

瞧! 12:6f:56:c0:c4:c1是我们网关的mac地址(10.12.2.1)。
因此,基本上,即使目标IP地址是8.8.8.8,目标mac地址也始终是网关服务器的地址。

MAC地址(物理地址)是第2层的一部分。
IP地址是第3层的一部分(源地址:)。
第3层的内容封装在第2层内部。
第2层将具有服务器的源mac地址和网关的目标mac地址。
这是数据包到达网关的方式。
网关将物理层2剥离,并且一旦找到目的地8.8.8.8,它将再次将该数据包转发到其网关(即:我们的网关会根据路由将数据包转发到下一个网关)。

这就是数据包如何传播并到达其最终目的地8.8.8.8的方式。
在到达8.8.8.8的路径中,倒数第二个网络设备将使用ARP协议知道8.8.8.8的mac地址。

底线是...如果我们想到达特定的目标IP地址,系统将将该IP地址转换为等效的mac地址。
因为真正的通信是使用物理地址进行的。
ARP(地址解析协议)用于查找与IP地址关联的物理地址。

上图所示说明了计算机如何使用“地址解析协议”找出与IP地址关联的mac地址。
上图中显示的“第一个请求”描述了一个“来自10.12.2.73的ARP请求”,以找出10.12.2.1的MAC地址。

该ARP请求是广播请求。
这就是为什么此请求中的目标MAC地址设置为00:00:00:00:00(广播mac地址)的原因。
当此网络中所有计算机所连接到的网络设备收到这样的请求,其目的地址为00:00:00:00:00时,它将把该请求转发到该网络中的所有计算机(这就是广播方式。
将其发送给所有相关人员)。

尽管网络中的每台计算机都会收到该请求。
IP地址为10.12.2.1的计算机将进行响应。
验证目标IP地址后,网络中的其他所有人都将丢弃此请求。
只有IP地址与ARP请求中的目标IP地址匹配的计算机才会回复。

在回复时,它将发送自己的mac地址。
通过这种方式10.12.2.73找出与10.12.2.1关联的mac地址。
以下关于ARP的术语值得注意...

  • ARP高速缓存:找到与IP关联的MAC地址后,计算机会将其存储在表格中以备将来参考。与该IP地址的所有后续通信都可以使用此表中的mac地址。该表也称为ARP缓存。
  • ARP缓存超时:添加到ARP表中以供将来参考的条目将在指定的时间内有效。这表示该时间。
  • ARP请求:我们已经在上面看到了。它是由计算机发送的广播请求,以查找与IP地址关联的mac。
  • ARP响应:如上图所示,这是来自目标主机的响应,包含IP和MAC。

如何在Linux中查看ARP缓存表?

几乎所有的Linux发行版都带有一个称为arp的命令行实用程序。
我们可以使用它来查看arp表条目(如下所示)。

root@ip-10-12-2-73:~# arp -n -a
? (10.12.2.40) at 12:f7:fd:48:aa:79 [ether] on eth0
? (10.12.2.43) at 12:48:08:aa:a5:bb [ether] on eth0
? (10.12.2.8) at 12:ab:ed:67:34:79 [ether] on eth0
? (10.12.2.94) at 12:47:87:c2:60:8d [ether] on eth0
? (10.12.2.1) at 12:6f:56:c0:c4:c1 [ether] on eth0

我们也可以使用以下命令查看arp表。

root@ip-10-12-2-73:~# arp -n -e
Address                  HWtype  HWaddress           Flags Mask            Iface
10.12.2.40               ether   12:f7:fd:48:aa:79   C                     eth0
10.12.2.43               ether   12:48:08:aa:a5:bb   C                     eth0
10.12.2.8                ether   12:ab:ed:67:34:79   C                     eth0
10.12.2.94               ether   12:47:87:c2:60:8d   C                     eth0
10.12.2.1                ether   12:6f:56:c0:c4:c1   C                     eth0

如何在Linux中的ARP缓存表中手动添加条目?

arp命令具有在Linux中执行此操作的选项。
见下文。

root@ip-10-12-2-73:~# arp  -s  10.12.67.43  12:48:08:bb:a5:bb

确保上述命令中的IP地址是有效的。

如何在Linux中从ARP缓存表中手动删除条目?

我们可以在Linux中使用arp命令的-d选项从ARP缓存表中删除条目(如下所示)。

root@ip-10-12-2-73:~# arp  -d  10.12.67.43

如何在Linux中从ARP缓存表中删除所有条目?

标准ip命令可用于此目的。

root@ip-10-12-2-73:~# ip neigh flush all

ARP条目存储在系统中的什么位置?

它在内存中。
因此,我们可以从/proc文件系统访问它。
见下文..

root@ip-10-12-2-73:~# cat /proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
10.12.2.40       0x1         0x2         12:f7:fd:48:aa:79     *        eth0
10.12.2.43       0x1         0x2         12:48:08:aa:a5:bb     *        eth0
10.12.2.8        0x1         0x2         12:ab:ed:67:34:79     *        eth0
10.12.2.94       0x1         0x2         12:47:87:c2:60:8d     *        eth0
10.12.2.1        0x1         0x2         12:6f:56:c0:c4:c1     *        eth0

如何一次将多个条目添加到arp缓存表?

arp实用程序支持从文件中获取条目。
我们可以将文件路径作为参数传递给arp命令。
缺省情况下,使用/etc/ethers文件。
文件内容应如下所示。

12:f7:fd:48:aa:79 10.12.2.40
12:48:08:aa:a5:bb 10.12.2.43

现在,我们可以将文件的路径指定为argumet。

root@ip-10-12-2-73:~# arp -f /etc/ethers

linux内核ARP模块支持许多微调选项。
其中大多数是使用/proc内的文件修改的。
我们可以在/proc/sys/net/ipv4/neigh/default中找到与ARP相关的内核文件。

root@ip-10-12-2-73:/proc/sys/net/ipv4/neigh/default# ls
anycast_delay           gc_interval    locktime       retrans_time_ms
app_solicit             gc_stale_time  mcast_solicit  ucast_solicit
base_reachable_time     gc_thresh1     proxy_delay    unres_qlen
base_reachable_time_ms  gc_thresh2     proxy_qlen     unres_qlen_bytes
delay_first_probe_time  gc_thresh3     retrans_time