Linux生成UUID的算法方式(序列号C/C++代码实现)

Linux中想获取机器的唯一标识(UUID),只需要在命令行中输入uuid就可以看到类似格式为:xxxxxxxx-xxxx- xxxx-xxxxxxxxxxxxxxxx(8-4-4-16)机器标识,通过该唯一标识生成注册码/序列号。有了设备的唯一编号,我们就可以实现更好的软件的授权机制,还可以利用它来限制客户端软件访问后台服务的权限,从而提高系统的安全性。

使用UUID 的目的

Linux生成UUID的算法方式(序列号C/C++代码实现)_第1张图片
使用 UUID 的主要原因之一是不需要集中权限来管理它们(尽管一种格式使用 IEEE 802 节点标识符,其他格式则不使用)。因此,按需 生成可以完全自动化,并用于各种目的。。。

生成 UUID 的几种算法

UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。

1.利用 802 MAC 地址的唯一值来保证唯一性。
2.种使用伪随机数生成器。
3.种使用加密哈希和应用程序提供的文本字符串。
4.当前日期和时间。

因此,根据此处的机制 生成的 UUID 将与所有其他已分配或将要分配的 UUID 不同。

UUID 字符串表示的正式定义
UUID 根据以下算法生成:

Linux生成UUID的算法方式(序列号C/C++代码实现)_第2张图片Linux生成UUID的算法方式(序列号C/C++代码实现)_第3张图片

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

Linux生成UUID的算法方式(序列号C/C++代码实现)_第4张图片
man 手册译文是这样讲的:

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的弊端

Linux生成UUID的算法方式(序列号C/C++代码实现)_第5张图片
如果将一台机器的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

你可能感兴趣的:(C/C++,linux,c语言,c++,uuid,序列号)