原文链接:https://draveness.me/whys-the-design-non-unique-mac-address/ MAC地址(Media access control address)是分配给==网络接口控制器==(Network interface controller, NIC)的唯一标识符,++它会在网络段中充当网络地址使用,所有具有网卡的主机都有单独的 MAC 地址,该地址总共包含 48 位,占 6 字节的空间++,可以表示 281,474,976,710,656 个网络设备,一个正常的 MAC 地址如下所示的格式表示,每个字节都会使用两位 16 进制的数字:

6e:77:0f:b8:8b:6b

因为MAC地址需要保证唯一,所以I==EEE会根据设备的制造商分配地址段,48位MAC地址的前24位是设备制造商的标识符,也就是组织唯一标识符(Organizationally Unique Identifier,OUI),后面的24位是序列号==;如果每个设备制造商都能保证在同一个命名空间中的全部MAC地址唯一,那么全世界所有的MAC地址就可以保证唯一。 image.png MAC地址可以使用两种不同的格式表示,分别是48位的EUI-48和64位的EUI-64,本文会使用EUI-48格式的MAC地址,EUI-64主要用于IPv6协议,我们在这篇文章就不展开讨论了。在通常情况下,MAC地址会使用24位表示组织序列号,但是因为很多组织不会生产这么多的设备,所以在实际操作中会划分出三种不同大小的地址块:

image.png 图 2 - MA-L, MA-M, MA-S ==MA-L(MAC Address Block Large)==:包含 24 位组织标识符和 24 位地址; ==MA-M(MAC Address Block Medium)== - 包含 28 位组织标识符和 20 位地址; ==MA-S(MAC Address Block Small)== - 包含 36 位组织标识符和 12 位地址; 这三种不同大小的地址块价格也完全不同,MA-L 的注册价格为 2995 美金,而 MA-S 的注册价格为 755 美金,感兴趣并且有需要的读者可以在IEEE的官方购买[^5],在理想情况下,所有的地址加起来价值大概在 52 万亿美金左右,==果然定义和掌握了标准就可以躺着等别人注册来赚钱==。 这种由机构分发MAC地址段并由设备商保证地址唯一的方式就是为了保证全世界所有硬件的网络地址唯一,但是在实际操作中,全球唯一是无法保证的而且我们也并不需要地址的全球唯一,这主要因为以下两个原因:

  • 在不同操作系统上,我们都可以通过软件直接修改网卡的 MAC 地址;
  • 只需要保证一个局域网内的 MAC 地址不重复,网络就可以正常工作;

修改MAC地址

无论是在 Linux 上还是在 macOS 上,修改网络设备的 MAC 地址都是非常简单的。在 Linux 操作系统中我们可以使用命令 ifconfig 修改设备上的 MAC 地址:

$ ifconfig eth0 | grep ether
        ether 6e:77:0f:b8:8b:6b  txqueuelen 1000  (Ethernet)
$ ifconfig eth0 down
$ ifconfig eth0 hw ether 6e:77:0f:b8:8b:6a
$ ifconfig eth0 up
$ ifconfig eth0 | grep ether
        ether 6e:77:0f:b8:8b:6a  txqueuelen 1000  (Ethernet)

只要我们使用上述的命令就可以轻松地修改当前网卡的MAC地址,不过建议不要在远程的Linux机器上使用,最好在本地的Linux上测试相关的命令,在修改测试完成之后也最好使用命令将 MAC 地址改回去;在 macOS 上修改 MAC 地址也可以使用 ifconfig 命令,使用的方式与 Linux 几乎完全相同。 因为 MAC 地址是与硬件绑定的,所以这种修改MAC地址的方式其实都是临时的,一旦操作系统重启,这些变更就会被系统撤销,想要让类似的变更永久生效需要在系统重启时执行相应的命令或者修改对应的网卡配置文件。

局域网通信

所有的计算机和终端设备都需要通过==网络适配器==连接到局域网中,每一个适配器都有唯一的链路层地址,也被叫做 LAN地址或者MAC 地址,MAC地址被设计成了扁平结构,它们不会随着所处网络的不同而发生改变。

当设备的网络适配器想要向其他的适配器发送数据帧时,它会将目的适配器的MAC地址插入到如下所示的以太网帧中,每个以太网帧都与IP数据报类似,包含源地址和目标地址,只是以太网帧中的地址是MAC地址,而IP数据报中的地址是IP 地址: image.png 图 3 - 以太网帧 局域网中的数据传输不是通过网络层的IP地址进行路由和转发的,然而IP地址一般都是发送数据主机知道的唯一信息,想要在局域网中发送数据,还是需要知道它们的MAC地址。当我们的设备想要向其他的设备发送数据时,它会先通过 ==ARP(Address Resolution Protocol,地址解析协议)== 在局域网中获取目的IP地址对应的MAC地址:

源主机会向当前局域网中发送==ARP请求==,目标的MAC地址是==FF-FF-FF-FF-FF-FF==,这表示当前请求是一个广播请求,局域网内的所有设备都会收到该请求; 接收到ARP请求的主机都会检查目的IP和自己的IP地址是否一致; 如果IP地址不一致,主机会忽略当前的ARP请求; 如果IP地址一致,主机会直接向源主机发送ARP响应; 源主机在接收到ARP的响应之后,会更新本地的缓存表并继续向目的主机发送数据; image.png 图 4 - 地址解析协议 在局域网中我们一般会使用==集线器(Hub)或者交换机(Switch)来==连接不同的网络设备。因为在集线器连接的局域网中,所有的数据帧都会被广播给局域网内的全部主机,所以使用相同的MAC地址一般也不会出现太多的问题;但是交换机会学习局域网中不同设备的MAC地址并将数据帧转发给特定主机,所以如果局域网是由交换机构成的,就会影响网络的通信。 image.png 图 5 - 集线器和交换机 假设局域网中的具有两台MAC地址完全相同的网络设备A和B,即 6e:77:0f:b8:8b:6b,当设备A想要向设备B发送以太网帧时会遇到如下所示的情况:

  • 设备A在构造的以太网帧中将源地址和目的地址都设置为6e:77:0f:b8:8b:6b并向交换机发送数据;
  • 交换机接收到了设备 A 发送的数据帧后,会从数据帧的源地址学习到设备A的MAC地址并将6e:77:0f:b8:8b:6b -> A 这条记录插入本地缓存中;
  • 交换机发现收到数据帧的目的地址会指向了网络设备A,所以它会将该数据转发回A; 因为++交换机的MAC地址学习策略,所以我们不能在同一个局域网中使用相同的MAC地址,但是因为MAC地址是链路层网络中的概念,跨局域网的网络传输需要通过网络层的IP协议,所以在不同的局域网中使用相同的MAC地址就不存在类似的问题了。++

总结 MAC 地址是链路层网络中的重要概念,在局域网中会通过 MAC 地址转发以太网数据帧,全球唯一的 MAC 地址是非常理想的情况,然而在实际的网络场景中,我们不需要保证如此强的限制:

  • MAC地址可以通过软件进行修改,而第三方的山寨厂商不会在IEEE中申请独立的MAC地址段,它们也可能会盗用其他厂商申请的MAC地址;
  • 保证MAC地址在局域网中唯一就不会造成网络问题,不同局域网中的MAC地址可以相同; 上述的结论不是说全球唯一的MAC地址没有意义,与此相反,我们应该尽可能保证MAC地址的唯一,这样在组建局域网时才不需要手动确认所有设备的MAC地址,减少网络工程师的工作量。到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:

MAC 地址和 IP 地址之间有什么样的关系? 为什么我们有了 MAC 地址还需要 IP 地址?