ARP是如何工作的

ARP是如何工作的

原文:https://www.slashroot.in/how-does-arp-address-resolution-protocol-work

作者:Sarath Pillai

原文发表日期:2016年10月10日

翻译:tommwq

译文:http://tommwq.tech/blog/?p=358

网络中的两台机器可以相互通信,如果它们知道对方的物理地址。虽然计算机程序使用IP地址来发送和接收消息,但实际的底层通信总是通过物理地址进行的。

我们先来了解一下通信如何通过电线进行。我们尝试ping一台google的公共DNS服务器并捕获网络数据包,看看源地址和目标地址是什么。

tcpdump是一个用于捕获网络数据包并显示其内容的工具。如果你不熟悉tcpdump,我建议你阅读下面的文章,了解tcpdump的基础知识。

阅读:Linux中的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 。 使用参数-host 8.8.8.8只会捕获源或目标为8.8.8.8的数据包(同时因为-n参数,tcpdump输出中显示IP地址,而不是DNS名字)。

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命令的输出非常明显。它显示了从我们的服务器(10.12.2.73)发出的一系列ICMP echo请求,以及随后从google(8.8.8.8)返回的响应。

由于8.8.8.8不在同一个网络中,如果没有网关,我的服务器无法直接访问到。因此ping 8.8.8.8的请求会经过我的网关。网关的地址可以用命令 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。在输出的第一行就清楚地看到。为了访问任意IP地址(用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地址)使用的地方。

随着ping 8.8.8.8继续执行,让我们在另一个会话上再次执行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地址,我们还可以在输出中看到 12:6e:eb:de:b3:ed > 12:6f:56:c0:c4:c1 和 ~12:6f:56:c0:c4:c1 > 12:6e:eb:de:b3:ed ~ 表示的物理地址(MAC地址)。

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:6e:eb:de:b3:ed 呢?我们可以使用命令 arp -n -a 找出它表示什么。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:6e:eb:de:b3:ed 是网关的MAC地址(10.12.2.1)。即使目标IP地址是8.8.8.8,目标mac地址始终是网关服务器。

MAC地址(物理地址)是OSI第二层的部分。IP地址是第三层的部分。第三层的内容封装在第二层中。第二层拥有我们服务器MAC地址和网关的MAC地址。这就是数据包到达网关的方式。网关会覆写第二层(物理层)地址,当它发现目标地是8.8.8.8,它将数据包再次转发到其网关(网关根据路由把数据包转发到下一个网关)。

这就是数据包如何传输并到达其最终目标8.8.8.8的。在到达8.8.8.8的路径中,倒数第二个网络设备将使用ARP协议查询8.8.8.8的MAC地址。,

最终,如果你想到达一个特定的目标IP地址,系统会把这个IP地址转换成等效的MAC地址。因为真正的通讯是用物理地址进行的。ARP(地址解析协议)用于查找与IP地址对应的物理地址。

ARP是如何工作的_第1张图片

上图说明了计算机如何使用ARP协议找出与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地址匹配的机器才会做出响应。

在回复时,目标服务器发送自己的MAC地址。这样10.12.2.73会找到与10.12.2.1对应的MAC地址。以下关于ARP的属于值得注意:

  1. ARP缓存:在找到IP对应的MAC地址后,计算机将其存储在表中以待将来使用。后续所有到这个IP地址的通信都可以使用中的MAC地址。这个表叫做ARP缓存。
  2. ARP缓存超时:添加到ARP缓存中的条目,只在指定的时间内有效。这一术语表明了这个时间段。
  3. ARP请求:我们已经在前面看到了。ARP请求是由计算机发出的广播请求,以找出IP地址对应的MAC地址。
  4. ARP应答:如上图所示,ARP应答这是来自目标主机的响应,包含IP和MAC地址。

1 如何在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

2 如何在Linux下手动添加ARP缓存表项?

Linux下的arp命令有一个选项可以执行这个操作。如:

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

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

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

在Linux中,可以使用ARP命令的-d选项可以从ARP缓存表中删除一个条目。如:

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

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

ip命令可用于此操作。

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

5 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

6 如何一次向arp缓存表添加多个条目?

arp命令支持从文件中加载条目。你可以将文件路径作为参数传递给arp命令。默认使用/etc/ether文件。文件内容如下所示:

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

现在可以将文件的路径作为参数。

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

你可以从这里获取这些文件及其内容的解释:ARP内核模块选项。

你可能感兴趣的:(ARP是如何工作的)