1 /* $OpenBSD: uuid.c,v 1.6 2018/04/26 12:42:51 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 57 #include <fcntl.h> 58 #include <ifaddrs.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #include "uuid.h" 65 66 static uint32_t seq_num; 67 static struct timeval last_time; 68 static int32_t counter; 69 static char nodeaddr[6]; 70 71 enum { UUID_NODE_MULTICAST = 0x80 }; 72 73 static int 74 time_cmp(struct timeval *tv1, struct timeval *tv2) 75 { 76 if (tv1->tv_sec > tv2->tv_sec) 77 return -1; 78 if (tv1->tv_sec < tv2->tv_sec) 79 return 1; 80 if (tv1->tv_usec > tv2->tv_usec) 81 return -1; 82 if (tv1->tv_usec < tv2->tv_usec) 83 return 1; 84 return 0; 85 } 86 87 static void 88 get_node_addr(char *addr) 89 { 90 struct ifaddrs *ifa, *ifa0; 91 int found_mac = 0; 92 93 if (getifaddrs(&ifa0) != 0) 94 ifa0 = NULL; 95 96 for (ifa = ifa0; ifa != NULL && !found_mac; ifa = ifa->ifa_next) { 97 if (ifa->ifa_addr == NULL) 98 continue; 99 100 #if IFF_LOOPBACK 101 if (ifa->ifa_flags & IFF_LOOPBACK) 102 continue; 103 #endif 104 105 switch (ifa->ifa_addr->sa_family) { 106 #ifdef AF_LINK 107 case AF_LINK: { 108 struct sockaddr_dl *dl = (struct sockaddr_dl *)ifa->ifa_addr; 109 110 switch (dl->sdl_type) { 111 case IFT_ETHER: 112 case IFT_FDDI: 113 if (dl->sdl_alen == 6) { 114 memcpy(addr, LLADDR(dl), 6); 115 found_mac = 1; 116 } 117 } 118 119 } 120 #endif 121 default: 122 break; 123 } 124 } 125 126 if (ifa0 != NULL) 127 freeifaddrs(ifa0); 128 129 if (!found_mac) { 130 /* 131 * Set the multicast bit to make sure we won't collide with an 132 * allocated (mac) address. 133 */ 134 arc4random_buf(addr, 6); 135 addr[0] |= UUID_NODE_MULTICAST; 136 } 137 return; 138 } 139 140 /* 141 * Creates a new UUID. 142 */ 143 144 void 145 uuid_create(afsUUID *uuid) 146 { 147 static int uuid_inited = 0; 148 struct timeval tv; 149 int ret, got_time; 150 uint64_t dce_time; 151 152 if (uuid_inited == 0) { 153 gettimeofday(&last_time, NULL); 154 seq_num = arc4random(); 155 get_node_addr(nodeaddr); 156 uuid_inited = 1; 157 } 158 159 gettimeofday(&tv, NULL); 160 161 got_time = 0; 162 163 do { 164 ret = time_cmp(&tv, &last_time); 165 if (ret < 0) { 166 /* Time went backward, just inc seq_num and be done. 167 * seq_num is 6 + 8 bit field it the uuid, so let it wrap 168 * around. don't let it be zero. 169 */ 170 seq_num = (seq_num + 1) & 0x3fff ; 171 if (seq_num == 0) 172 seq_num++; 173 got_time = 1; 174 counter = 0; 175 last_time = tv; 176 } else if (ret > 0) { 177 /* time went forward, reset counter and be happy */ 178 last_time = tv; 179 counter = 0; 180 got_time = 1; 181 } else { 182 #define UUID_MAX_HZ (1) /* make this bigger fix you have larger tickrate */ 183 #define MULTIPLIER_100_NANO_SEC 10 184 if (++counter < UUID_MAX_HZ * MULTIPLIER_100_NANO_SEC) 185 got_time = 1; 186 } 187 } while(!got_time); 188 189 /* 190 * now shift time to dce_time, epoch 00:00:00:00, 15 October 1582 191 * dce time ends year ~3400, so start to worry now 192 */ 193 194 dce_time = tv.tv_usec * MULTIPLIER_100_NANO_SEC + counter; 195 dce_time += ((uint64_t)tv.tv_sec) * 10000000; 196 dce_time += (((uint64_t)0x01b21dd2) << 32) + 0x13814000; 197 198 uuid->time_low = dce_time & 0xffffffff; 199 uuid->time_mid = 0xffff & (dce_time >> 32); 200 uuid->time_hi_and_version = 0x0fff & (dce_time >> 48); 201 202 uuid->time_hi_and_version |= (1 << 12); 203 204 uuid->clock_seq_low = seq_num & 0xff; 205 uuid->clock_seq_hi_and_reserved = (seq_num >> 8) & 0x3f; 206 uuid->clock_seq_hi_and_reserved |= 0x80; /* dce variant */ 207 208 memcpy(uuid->node, nodeaddr, 6); 209 } 210 211 /* 212 * Converts a UUID from binary representation to a string representation. 213 */ 214 215 void 216 uuid_to_string(const afsUUID *uuid, char *str, size_t strsz) 217 { 218 snprintf(str, strsz, 219 "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 220 uuid->time_low, 221 uuid->time_mid, 222 uuid->time_hi_and_version, 223 (unsigned char)uuid->clock_seq_hi_and_reserved, 224 (unsigned char)uuid->clock_seq_low, 225 (unsigned char)uuid->node[0], 226 (unsigned char)uuid->node[1], 227 (unsigned char)uuid->node[2], 228 (unsigned char)uuid->node[3], 229 (unsigned char)uuid->node[4], 230 (unsigned char)uuid->node[5]); 231 } 232 233 234 #ifdef TEST 235 int 236 main(int argc, char **argv) 237 { 238 char str[1000]; 239 afsUUID u1, u2; 240 241 uuid_create(&u1); 242 243 uuid_to_string(&u1, str, sizeof(str)); 244 245 printf("u: %s\n", str); 246 247 if (uuid_from_string(str, &u2)) { 248 printf("failed to parse\n"); 249 return 0; 250 } 251 252 if (bcmp(&u1, &u2, sizeof(u1)) != 0) 253 printf("u1 != u2\n"); 254 255 return 0; 256 } 257 #endif 258