1 |
|
|
/* $OpenBSD: uuid.c,v 1.5 2016/08/27 01:42:37 guenther Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2002, Stockholms Universitet |
4 |
|
|
* (Stockholm University, Stockholm Sweden) |
5 |
|
|
* All rights reserved. |
6 |
|
|
* |
7 |
|
|
* Redistribution and use in source and binary forms, with or without |
8 |
|
|
* modification, are permitted provided that the following conditions |
9 |
|
|
* are met: |
10 |
|
|
* |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* |
14 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
|
* documentation and/or other materials provided with the distribution. |
17 |
|
|
* |
18 |
|
|
* 3. Neither the name of the university nor the names of its contributors |
19 |
|
|
* may be used to endorse or promote products derived from this software |
20 |
|
|
* without specific prior written permission. |
21 |
|
|
* |
22 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
23 |
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
26 |
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
33 |
|
|
*/ |
34 |
|
|
|
35 |
|
|
/* |
36 |
|
|
* NCS/DCE/AFS/GUID generator |
37 |
|
|
* |
38 |
|
|
* for more information about DCE UUID, see |
39 |
|
|
* <http://www.opengroup.org/onlinepubs/9629399/apdxa.htm> |
40 |
|
|
* |
41 |
|
|
* Note, the Microsoft GUID is a DCE UUID, but it seems like they |
42 |
|
|
* folded in the seq num with the node part. That would explain how |
43 |
|
|
* the reserved field have a bit pattern 110 when reserved is a 2 bit |
44 |
|
|
* field. |
45 |
|
|
* |
46 |
|
|
* XXX should hash the node address for privacy issues |
47 |
|
|
*/ |
48 |
|
|
|
49 |
|
|
#include <sys/types.h> |
50 |
|
|
#include <sys/socket.h> |
51 |
|
|
#include <sys/time.h> |
52 |
|
|
#include <netinet/in.h> |
53 |
|
|
#include <net/if.h> |
54 |
|
|
#include <net/if_types.h> |
55 |
|
|
#include <net/if_dl.h> |
56 |
|
|
#include <sys/file.h> |
57 |
|
|
|
58 |
|
|
#include <fcntl.h> |
59 |
|
|
#include <ifaddrs.h> |
60 |
|
|
#include <stdio.h> |
61 |
|
|
#include <stdlib.h> |
62 |
|
|
#include <string.h> |
63 |
|
|
#include <unistd.h> |
64 |
|
|
|
65 |
|
|
#include "uuid.h" |
66 |
|
|
|
67 |
|
|
static uint32_t seq_num; |
68 |
|
|
static struct timeval last_time; |
69 |
|
|
static int32_t counter; |
70 |
|
|
static char nodeaddr[6]; |
71 |
|
|
|
72 |
|
|
enum { UUID_NODE_MULTICAST = 0x80 }; |
73 |
|
|
|
74 |
|
|
static int |
75 |
|
|
time_cmp(struct timeval *tv1, struct timeval *tv2) |
76 |
|
|
{ |
77 |
|
|
if (tv1->tv_sec > tv2->tv_sec) |
78 |
|
|
return -1; |
79 |
|
|
if (tv1->tv_sec < tv2->tv_sec) |
80 |
|
|
return 1; |
81 |
|
|
if (tv1->tv_usec > tv2->tv_usec) |
82 |
|
|
return -1; |
83 |
|
|
if (tv1->tv_usec < tv2->tv_usec) |
84 |
|
|
return 1; |
85 |
|
|
return 0; |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
static void |
89 |
|
|
get_node_addr(char *addr) |
90 |
|
|
{ |
91 |
|
|
struct ifaddrs *ifa, *ifa0; |
92 |
|
|
int found_mac = 0; |
93 |
|
|
|
94 |
|
|
if (getifaddrs(&ifa0) != 0) |
95 |
|
|
ifa0 = NULL; |
96 |
|
|
|
97 |
|
|
for (ifa = ifa0; ifa != NULL && !found_mac; ifa = ifa->ifa_next) { |
98 |
|
|
if (ifa->ifa_addr == NULL) |
99 |
|
|
continue; |
100 |
|
|
|
101 |
|
|
#if IFF_LOOPBACK |
102 |
|
|
if (ifa->ifa_flags & IFF_LOOPBACK) |
103 |
|
|
continue; |
104 |
|
|
#endif |
105 |
|
|
|
106 |
|
|
switch (ifa->ifa_addr->sa_family) { |
107 |
|
|
#ifdef AF_LINK |
108 |
|
|
case AF_LINK: { |
109 |
|
|
struct sockaddr_dl *dl = (struct sockaddr_dl *)ifa->ifa_addr; |
110 |
|
|
|
111 |
|
|
switch (dl->sdl_type) { |
112 |
|
|
case IFT_ETHER: |
113 |
|
|
case IFT_FDDI: |
114 |
|
|
if (dl->sdl_alen == 6) { |
115 |
|
|
memcpy(addr, LLADDR(dl), 6); |
116 |
|
|
found_mac = 1; |
117 |
|
|
} |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
} |
121 |
|
|
#endif |
122 |
|
|
default: |
123 |
|
|
break; |
124 |
|
|
} |
125 |
|
|
} |
126 |
|
|
|
127 |
|
|
if (ifa0 != NULL) |
128 |
|
|
freeifaddrs(ifa0); |
129 |
|
|
|
130 |
|
|
if (!found_mac) { |
131 |
|
|
/* |
132 |
|
|
* Set the multicast bit to make sure we won't collide with an |
133 |
|
|
* allocated (mac) address. |
134 |
|
|
*/ |
135 |
|
|
arc4random_buf(addr, 6); |
136 |
|
|
addr[0] |= UUID_NODE_MULTICAST; |
137 |
|
|
} |
138 |
|
|
return; |
139 |
|
|
} |
140 |
|
|
|
141 |
|
|
/* |
142 |
|
|
* Creates a new UUID. |
143 |
|
|
*/ |
144 |
|
|
|
145 |
|
|
void |
146 |
|
|
uuid_create(afsUUID *uuid) |
147 |
|
|
{ |
148 |
|
|
static int uuid_inited = 0; |
149 |
|
|
struct timeval tv; |
150 |
|
|
int ret, got_time; |
151 |
|
|
uint64_t dce_time; |
152 |
|
|
|
153 |
|
|
if (uuid_inited == 0) { |
154 |
|
|
gettimeofday(&last_time, NULL); |
155 |
|
|
seq_num = arc4random(); |
156 |
|
|
get_node_addr(nodeaddr); |
157 |
|
|
uuid_inited = 1; |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
gettimeofday(&tv, NULL); |
161 |
|
|
|
162 |
|
|
got_time = 0; |
163 |
|
|
|
164 |
|
|
do { |
165 |
|
|
ret = time_cmp(&tv, &last_time); |
166 |
|
|
if (ret < 0) { |
167 |
|
|
/* Time went backward, just inc seq_num and be done. |
168 |
|
|
* seq_num is 6 + 8 bit field it the uuid, so let it wrap |
169 |
|
|
* around. don't let it be zero. |
170 |
|
|
*/ |
171 |
|
|
seq_num = (seq_num + 1) & 0x3fff ; |
172 |
|
|
if (seq_num == 0) |
173 |
|
|
seq_num++; |
174 |
|
|
got_time = 1; |
175 |
|
|
counter = 0; |
176 |
|
|
last_time = tv; |
177 |
|
|
} else if (ret > 0) { |
178 |
|
|
/* time went forward, reset counter and be happy */ |
179 |
|
|
last_time = tv; |
180 |
|
|
counter = 0; |
181 |
|
|
got_time = 1; |
182 |
|
|
} else { |
183 |
|
|
#define UUID_MAX_HZ (1) /* make this bigger fix you have larger tickrate */ |
184 |
|
|
#define MULTIPLIER_100_NANO_SEC 10 |
185 |
|
|
if (++counter < UUID_MAX_HZ * MULTIPLIER_100_NANO_SEC) |
186 |
|
|
got_time = 1; |
187 |
|
|
} |
188 |
|
|
} while(!got_time); |
189 |
|
|
|
190 |
|
|
/* |
191 |
|
|
* now shift time to dce_time, epoch 00:00:00:00, 15 October 1582 |
192 |
|
|
* dce time ends year ~3400, so start to worry now |
193 |
|
|
*/ |
194 |
|
|
|
195 |
|
|
dce_time = tv.tv_usec * MULTIPLIER_100_NANO_SEC + counter; |
196 |
|
|
dce_time += ((uint64_t)tv.tv_sec) * 10000000; |
197 |
|
|
dce_time += (((uint64_t)0x01b21dd2) << 32) + 0x13814000; |
198 |
|
|
|
199 |
|
|
uuid->time_low = dce_time & 0xffffffff; |
200 |
|
|
uuid->time_mid = 0xffff & (dce_time >> 32); |
201 |
|
|
uuid->time_hi_and_version = 0x0fff & (dce_time >> 48); |
202 |
|
|
|
203 |
|
|
uuid->time_hi_and_version |= (1 << 12); |
204 |
|
|
|
205 |
|
|
uuid->clock_seq_low = seq_num & 0xff; |
206 |
|
|
uuid->clock_seq_hi_and_reserved = (seq_num >> 8) & 0x3f; |
207 |
|
|
uuid->clock_seq_hi_and_reserved |= 0x80; /* dce variant */ |
208 |
|
|
|
209 |
|
|
memcpy(uuid->node, nodeaddr, 6); |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
/* |
213 |
|
|
* Converts a UUID from binary representation to a string representation. |
214 |
|
|
*/ |
215 |
|
|
|
216 |
|
|
void |
217 |
|
|
uuid_to_string(const afsUUID *uuid, char *str, size_t strsz) |
218 |
|
|
{ |
219 |
|
|
snprintf(str, strsz, |
220 |
|
|
"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", |
221 |
|
|
uuid->time_low, |
222 |
|
|
uuid->time_mid, |
223 |
|
|
uuid->time_hi_and_version, |
224 |
|
|
(unsigned char)uuid->clock_seq_hi_and_reserved, |
225 |
|
|
(unsigned char)uuid->clock_seq_low, |
226 |
|
|
(unsigned char)uuid->node[0], |
227 |
|
|
(unsigned char)uuid->node[1], |
228 |
|
|
(unsigned char)uuid->node[2], |
229 |
|
|
(unsigned char)uuid->node[3], |
230 |
|
|
(unsigned char)uuid->node[4], |
231 |
|
|
(unsigned char)uuid->node[5]); |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
|
235 |
|
|
#ifdef TEST |
236 |
|
|
int |
237 |
|
|
main(int argc, char **argv) |
238 |
|
|
{ |
239 |
|
|
char str[1000]; |
240 |
|
|
afsUUID u1, u2; |
241 |
|
|
|
242 |
|
|
uuid_create(&u1); |
243 |
|
|
|
244 |
|
|
uuid_to_string(&u1, str, sizeof(str)); |
245 |
|
|
|
246 |
|
|
printf("u: %s\n", str); |
247 |
|
|
|
248 |
|
|
if (uuid_from_string(str, &u2)) { |
249 |
|
|
printf("failed to parse\n"); |
250 |
|
|
return 0; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
if (bcmp(&u1, &u2, sizeof(u1)) != 0) |
254 |
|
|
printf("u1 != u2\n"); |
255 |
|
|
|
256 |
|
|
return 0; |
257 |
|
|
} |
258 |
|
|
#endif |