Linux中想获取机器的唯一标识(UUID),只需要在命令行中输入uuid就可以看到类似格式为:xxxxxxxx-xxxx- xxxx-xxxxxxxxxxxxxxxx(8-4-4-16)机器标识,通过该唯一标识生成注册码/序列号。有了设备的唯一编号,我们就可以实现更好的软件的授权机制,还可以利用它来限制客户端软件访问后台服务的权限,从而提高系统的安全性。
使用UUID 的目的
使用 UUID 的主要原因之一是不需要集中权限来管理它们(尽管一种格式使用 IEEE 802 节点标识符,其他格式则不使用)。因此,按需 生成可以完全自动化,并用于各种目的。。。
生成 UUID 的几种算法
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。
1.利用 802 MAC 地址的唯一值来保证唯一性。
2.种使用伪随机数生成器。
3.种使用加密哈希和应用程序提供的文本字符串。
4.当前日期和时间。
因此,根据此处的机制 生成的 UUID 将与所有其他已分配或将要分配的 UUID 不同。
UUID 字符串表示的正式定义
UUID 根据以下算法生成:
time_low 字段设置为以相同的重要性顺序等于时间戳的最低有效 32 位(位 0 到 31)。
time_mid 字段设置为等于时间戳中的第 32 位到第 47 位。
time_hi_and_version 字段的 12 个最低有效位(位 0 到 11)设置为等于时间戳中的位 48 到 59,以相同的重要性顺序。
time_hi_and_version 字段的四个最高有效位(位 12 到 15)设置为与正在创建的 UUID 版本对应的 4 位版本号。
clock_seq_low 字段设置为8 个最低有效位(位 0 到 7)的时钟序列以相同的重要性顺序。
clock_seq_hi_and_reserved 字段的6 个最低有效位(0 到5 位)设置为时钟序列的6 个最高有效位(8 到13 位)。
clock_seq_hi_and_reserved 的两个最高有效位(位6 和7)分别设置为零和一。
将节点字段设置为 48 位 IEEE 地址,其重要性顺序与地址相同。
什么是 machine-id
etc/machine-id 文件包含一个 在安装或首次启动操作系统时生成的、专属于本系统的、独一无二的"machine ID"。 "machine ID"是一个32字符长度的十六进制小写字母字符串,并以换行符结尾。 其本质是一个128位二进制整数的16进制表示。 注意,"machine ID"不能为全零值。
“machine ID"通常在系统安装或首次启动时从一个随机数源生成, 并且之后无论经过多少次开关机,也一直保持不变。 另一方面,对于无状态系统,如果有必要,将在系统启动的早期自动随机生成一个"machine ID”。
每台机器都应该具有一个独一无二的非空"machine ID"。 为了达到这个目标,可以使用多种不同的方法初始化 /etc/machine-id 文件。一般来说, /etc/machine-id 应该 在操作系统安装过程中完成初始化。
linux 的uuid码
linux的uuid码也是有内核提供的,在/proc/sys/kernel/random/uuid这个文件内。其实,random目录,里面还有很多其它文件,都与生成uuid有关系的。
基于当前时间的 UUID
..
int main (int argc, char **argv) {
...
struct timeval tv0;
gettimeofday(&tv0, NULL);
time_t t0 = (time_t)tv0.tv_sec;
struct tm *tm0 = gmtime(&t0);
char buffer[33];
// 00000000-yyyy-mmmm-dddd-hhhhhhnnnnnn
srand((unsigned int)tv0.tv_usec/100);
sprintf(buffer,"%04x%02x%02x%04x%06x%06x%02x%02x%02x",
(int)tm0->tm_year+1900, (int)tm0->tm_mon, (int)tm0->tm_mday, 0,
(int)tv0.tv_sec, (int)tv0.tv_usec, rand()%255, rand()%255, rand()%255);
...
return 0;
}
uuidtime 是一个 Linux 程序,用于生成基于当前时间的 UUID自纪元(1970)以来的秒数和微秒数。当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。
UUID的弊端
如果将一台机器的UUID拷贝到另一台机器,就类似修改Mac地址的方法达到欺骗的目的。
根据型号和 MAC 地址的低 24 位构建序列号
int get_sn(char *iface, int model_id, unsigned int *si)
{
unsigned char mac_address[6];
unsigned char sn[4] = {0};
struct ifreq ifr;
assert(iface);
assert(si);
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
fprintf(stderr, "couldn't create socket\n");
return -1;
};
strcpy(ifr.ifr_name, iface);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
fprintf(stderr, "couldn't ioctl iface: %s\n",
ifr.ifr_name);
return -1;
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
memcpy(sn, &mac_address[3], 3);
*si = sn[2] + 256 * sn[1] + 65536 * sn[0];
*si = *si / 4 - 64;
*si = *si + model_id;
return 0;
}
return -1;
}
总结
UUID 是通用唯一识别码。由 32 位 16 进制数字组成,可以是纯 32 位 16 进制数字,也可以包含连接线(形式为 8-4-4-4-12),更新详细信息请参考RFC4122。
欢迎关注微信公众号【程序猿编码】,需要 UUID完整源码 的添加本人微信号(c17865354792)
参考:RFC 4122