通常来讲是没有更换 MAC 的必要,但是偶尔被误伤的时候还是很有用的。

起因

手里多了一台服务器,目前部署在 IDC 中心,由于忘记某个服务的端口我遍采取了端口扫描的方式来查看暴露的端口进而判断服务位置,但是我校 IDS 系统比较厉害,不仅仅是没有扫到服务顺带着连我的 IP 到服务器的访问也一并切断了,因此我需要更换 IP 才能重新正常访问该服务器。但是由于一般使用硬件 MAC 因此对于 DHCP 服务器不会为我重新分配新的 IP 地址直到我上一个 IP 过期释放掉。然而释放的这个过程最长可达一年(我上一年度内网 IP 均未发生变更)。因此只能通过更换 MAC 使得 DHCP 服务器认为我是新的接入设备并重新分配可用 IP。

思路

一般来讲我可能会选用 Python 来实现更换 MAC 这个操作,但是受限于路由器本身,使用 Shell 脚本可能是更加经济实惠的选择。

初步思路是从 /dev/urandom 抓取随机数,取 md5sum 获取 16 进制格式然后再切分插入符号。类似如下形式:

1
echo `dd if=/dev/urandom bs=1 count=32 2>/dev/null | md5sum | cut -b 1-12 | sed 's/\(..\)/\1:/g; s/.$//'`
1
2
# result
'21:29:25:69:ec:ad'

但是正如这条 stackoverflow 的讨论串所描述的那样,这样生成的 MAC 地址有概率无法使用,即最直观的感受是要求前两位地址必须为偶数。说白了,由于单播地址限制,首位地址为0x21时相当于映射到多播,但是由于单个硬件设备作为节点连接到网络时其使用单播方法,因此必须限制首位为偶数。即:

如果第一个八位字节的 LSB 为 0,则它是单播地址。如果第一个八位字节的第二个 LSB 是 1,则它是本地生成的 MAC 地址。

对应关系如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
0x0     0000
0x1     0001
0x2     0010
0x3     0011
0x4     0100
0x5     0101
0x6     0110
0x7     0111
0x8     1000
0x9     1001
0xA     1010
0xB     1011
0xC     1100
0xD     1101
0xE     1110
0xF     1111

解决方案

因此最直接且最简单的解决方案就是直接针对不合法的地址,也就是所谓奇数进行替换,比如下面这个例子:

1
echo `dd if=/dev/urandom bs=1 count=32 2>/dev/null | md5sum | cut -b 1-12 | sed 's/\(..\)/\1:/g; s/.$//'|sed 's/^\(.\)[13579bdf]/\10/'`

直接简单粗暴的将不合法的地址全部替换为0。简单省事。不过也存在一个问题,也就是一定程度上减少了随机性。这个时候最佳处理方法大概还是通过awk 来实现。