MAC地址格式详解

时间:2024-02-17 17:18:06

MAC地址格式详解

来源 https://www.cnblogs.com/daofaziran/p/12084358.html

 

以太网编址

在数据链路层,数据帧通常依赖于MAC地址来进行数据交换,它如同公网IP地址一样要求具有全球唯一性,这样才可以识别每一台主机。那么MAC地址如何做到这点?它的格式又是什么?

MAC地址,英文全称Medium Access Control,直译为介质访问控制,它通常被固化在每个以太网网卡(NIC,Network Interface Card)。MAC(硬件)地址长48位(6字节),采用十六进制格式,下图说明了48位的MAC地址及其组成部分。

             示例: 00-01-6C-06-A6-29 或 00:01:6C:06:A6:29

组织唯一标识符(OUI)由IEEE(电气和电子工程师协会)分配给厂商,它包含24位。厂商再用剩下的24位(EUI,扩展唯一标识符)为其生产的每个网卡分配一个全球唯一的全局管理地址,一般来说大厂商都会购买多个OUI。

I/G(Individual/Group)位,如果I/G=0,则是某台设备的MAC地址,即单播地址;如果I/G=1,则是多播地址(组播+广播=多播)。

G/L(Global/Local,也称为U/L位,其中U表示Universal)位,如果G/L=0,则是全局管理地址,由IEEE分配;如果G/L=1,则是本地管理地址,是网络管理员为了加强自己对网络管理而指定的地址。

 

对于I/GG/L位的位置,目前有两种说法,或者说两种格式。

对于数据传输来说,数据是按每个字节中一位一位地传输的,一个字节传输完了才到下一个字节。

IEEE 802.3 :以太网介质访问控制协议 (CSMA/CD)及物理层技术规范。
IEEE 802.4 :令牌总线网(Token-Bus)的介质访问控制协议及物理层技术规范。
IEEE 802.5 :令牌环网(Token-Ring)的介质访问控制协议及物理层技术规范。
IEEE 802.6 :城域网介质访问控制协议DQDB (Distributed Queue Dual Bus 分布式队列双总线)及物理层技术规范。

 

 

第一种,每个字节的高位在前,低位在后,I/GG/L分别在字节中的最低位和次低位,最高位先发送,到了对端还是最高位

第二种,每个字节的低位在前,高位在后,I/G位和G/L分别在字节中的最低位和次低位,最低位先发送,到了对端还是最低位

两种看似不一样,但是结果还是一样的,如果还是弄不懂可以再草稿纸上画一画,不难理解。

 

因为以太网线路上按“Big Endian”字节序传送报文(也就是最高字节先传送,关于字节序请参考相关文档),而比特序是”Little Endian”(也就是最低位先传送)。

注意图上的第47bit,这一位表示MAC地址是全球唯一地址还是本地地址,0表示全球唯一地址,1表示本地唯一地址。这一位也叫G/L位。

对于网络设备上固化的MAC地址,因为它唯一标识这个设备,所以只能是单播地址,也就是MAC帧里面的Source地址第48位只能0。

 我们常说有2的48次方个MAC地址可供网络设备使用,这些地址可以多到给地球上每一粒沙子分配一个地址,其实这个数量要打折扣的,因为MAC地址虽然有这么多,但真正用在网卡上并且全球唯一的只有2的46次方个:第48bit一定是0,第47bit一定是0。

这也就引出了一个有意思的现象:随便找一台PC,观察一下它的网卡地址,第1字节的十六进制数一般是4的倍数;查看一下IEEE分配的OUI(http://standards.ieee.org/develop/regauth/oui/oui.txt ),第1字节的十六进制数也一般是4的倍数(早期以太网没有本地地址的概念,所以分配的OUI里面G/L bit也可能是1),这种情况下就不是4的倍数了,但肯定是2的倍数,因为第48位只能是0。

关于组播地址,有这么个误解:MAC地址第1字节必须是0x01才表示组播地址,连TCP/IP详解上也这么说(见中文版12.4.2第一段)。IEEE 802.3里面已经明确说明了只要第48bit是1就表示组播地址,所以无论MAC地址第1字节是0x01、0xC1或者是0x33都表示这个MAC地址是组播地址(以0x33开头的表示IPV6对应的二层组播地址)。之所以有这样的误解,是因为到目前为止,大部分组播MAC地址的第1字节都是0x01。如:

01-80-C2-00-00-00(STP协议使用)

01-80-C2-00-00-01(MAC Control的PAUSE帧使用)

01-80-C2-00-00-02(Slow Protocol: 802.3ah OAM/ LACP 协议都用这个地址,这个地址很有故事,有多少软件处理这个地址会出问题啊!)

01-00-5E-xx-xx-xx(IP组播地址对应的二层组播地址)。

目标MAC是组播MAC地址的以太网帧,只有交换机才会接收,而普通终端设备不会接收

完整的列表见http://standards.ieee.org/develop/regauth/grpmac/public.html

之所以大部分组播地址都以01-80-C2和01-00-5E开头,那是因为使用这些组播地址的协议都是带头大哥IEEE和IANA名下的,它们的OUI分别是00-80-C2和00-00-5E是,变成组播地址就是01-80-C2和01-00-5E了,当然,除了带头大哥霸占的这些组播地址,还有01-00-0C-CC-CC-CC这样的地址,这个地址是Cisco霸占的,Cisco的OUI是00-00-0C。

 

===========

 

主机网卡应该接收的数据帧:
1. 目标MAC是自己的单播帧
2. 广播帧
3. 加入组播对应的组播帧

 

让网卡不检查包的接收方地址,不管是不是自己的包都统统接收下来,这种模式就叫做混杂模式。

linux系统中网卡驱动收到报文后会检查报文的目的mac地址,区分广播,组播,和单播。如果是单播报文,则比较报文的目的mac地址是否和本网卡的mac一样,如果不一样则设置该报文为PACKET_OTHERHOST。在ip_rcv函数中将PACKET_OTHERHOST类型的报文直接丢弃。所以说混杂模式下网卡收到不是自己(仅限于本网卡)mac的报文,只会在链路层处理,不会到网络层。详细分析可以参考文档:https://segmentfault.com/a/1190000021291692

 

ifconfig eth1 promisc ------ 开启混杂模式
ifconfig eth1 -promisc ------ 关闭混杂模式
ifconfig eth1 | grep PROMISC ------ 查看是否开启混杂模式

ip link set eth1 promisc on ------ 开启混杂模式
ip link set eth1 promisc off ------ 关闭混杂模式
ip link show eth1 | grep PROMISC ------ 查看是否开启混杂模式

 

以太网是载波侦听(CSMA/CD)。什么意思。通俗一点讲就是“一个人在点到,大家都在听,点到自己才回答,没有点自己别吭声”。它是一种广播链路,共享信道方式。
        

        2、网络包的过滤特性,过滤分两层,首先是硬件过滤(HW Filter),随后是软件过滤(SW Filter)。上图中主机B,C,D拒绝是指硬件过滤。它过滤判断条件是MAC地址是否匹配,针对的是MAC地址,属于OSI第二层--链路层的处理。 软件过滤判断条件是ip地址是否匹配。属于OSI协议分层里面的第三层过滤。正是因为一些原来不会产生应答而在混杂模式下却会产生应答的差异。提供了检测混杂模式的手段。 
        

       上表是一个很经典的linux下过滤特性统计表格,其中gr bit 是指group bit,组播位。第一个字节的最低位为1的所有地址,例如01-12-0f-00-00-02。当然广播地址 FF:FF:FF:FF:FF:FF 也属于组播的一种。其中最后两行在普通模式下没有应答,而在混杂模式下有应答。所以可以利用最后两行来检测混杂模式。具体检测时候填充的MAC地址如下表。使用红圈两行即可。
        

       最后两行属于多播地址范围(00:00:5e:00:00:00 - 00:00:5e:7f:ff:ff),参照上表,目的地址使用FF:FF:FF:FF:FF:FE或FF:FF:00:00:00:00即可不分windows还是linux,探测出是否开启了混杂模式。

      3、最后一步就是构造测试包,目前linux系统好像没有现成的可以构造目的地址的工具,需要自己写程序或使用第三方工具。可以构造一个arp包或者ip包,设置目的mac地址为上表红圈中地址即可。
        

struct pack 
{
    unsigned char    h_dest[ETH_ALEN];//目标mac地址,填写FF:FF:FF:FF:FF:FE
    unsigned char    h_source[ETH_ALEN];//源mac地址,及发送者本机mac
    unsigned short    h_proto;//以太网包的类型,0x0806 arp或者 0x0800 ip包
    ..... //arp 或 ip 包内容
}

     参考代码比较多,就要就是发包,我这里就不花大篇幅去书写了,也可以参考http://ptool.googlecode.com/svn/trunk/

 

============= End