28222e698e0f33a010260a5c7e707ca3e8891db5
[sim/o1-interface.git] / ntsimulator / ntsim-ng / utils / rand_utils.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "rand_utils.h"
21 #include "log_utils.h"
22 #include "sys_utils.h"  //for b64_encode
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <time.h>
26 #include <inttypes.h>
27 #include <assert.h>
28 #include <math.h>
29
30 #include "core/context.h"       //for context_get_identity_leafs_of_type
31 #include "core/framework.h"     //to check for no_rand
32
33 //private definitions
34 typedef struct __rand_range {
35     union {
36         int64_t num;
37         double dec;
38     } value;
39
40     union {
41         int64_t num;
42         double dec;
43     } min;
44
45     union {
46         int64_t num;
47         double dec;
48     } max;
49 } rand_range_t;
50
51 //private functions
52 static char *rand_string(int min_length, int max_length);
53 static struct lys_ident *rand_identity(struct lys_ident *type);
54
55 //random based on ranges
56 static int64_t rand_range_type_int_min(LY_DATA_TYPE type);
57 static int64_t rand_range_type_int_max(LY_DATA_TYPE type);
58 static rand_range_t rand_range(const char *range, const LY_DATA_TYPE type);
59
60 //for the following functions, the result should be freed by the user
61 static char *rand_date_and_time(void);
62 static char *rand_ipv4_address(void);
63 static char *rand_ipv6_address(void);
64 static char *rand_uuid(void);
65
66
67 void rand_init(void) {
68     unsigned int seed;
69
70     FILE* urandom = fopen("/dev/urandom", "r");
71     if(urandom == 0) {
72         log_error("failed to open /dev/urandom");
73     }
74     else {
75         fread(&seed, sizeof(int), 1, urandom);
76         fclose(urandom);
77     }
78
79     srand(seed);
80     srandom(seed);
81
82     log_message(2, "rand_init() was called and seed was initialized to %u\n", seed);
83     if(RAND_MAX < 65536) {
84         log_error("RAND_MAX is too low: %d", RAND_MAX);
85     }
86 }
87
88 void rand_init_fixed(unsigned int seed) {
89     srand(seed);
90     srandom(seed);
91
92     log_message(2, "rand_init_fixed() was called and seed was initialized to %u\n", seed);
93
94     if(RAND_MAX < 65536) {
95         log_error("RAND_MAX is too low: %d", RAND_MAX);
96     }
97 }
98
99 char *rand_get_populate_value(const struct lys_type *type) {
100     assert(type);
101
102     char *ret = 0;
103
104     if(type->der->module) {
105         char *full_type = 0;
106         
107         asprintf(&full_type, "%s:%s", type->der->module->name, type->der->name);
108         if(full_type == 0) {
109             log_error("bad malloc");
110             return 0;
111         }
112
113         if(strstr(full_type, "ietf-yang-types:date-and-time") != 0) {
114             ret = rand_date_and_time();
115         }
116         else if(strstr(full_type, "ietf-inet-types:ipv4-address") != 0) {
117             ret = rand_ipv4_address();
118         }
119         else if(strstr(full_type, "ietf-inet-types:ipv6-address") != 0) {
120             ret = rand_ipv6_address();
121         }
122         else if((strstr(full_type, "ietf-yang-types:mac-address") != 0) || (strstr(full_type, "ietf-yang-types:phys-address") != 0)) {
123             ret = rand_mac_address();
124         }
125         else if(strstr(full_type, "universal-id") != 0) {
126             ret = rand_uuid();
127         }
128         
129         free(full_type);
130         if(ret) {
131             return ret;
132         }
133     }
134
135     switch(type->base) {
136         case LY_TYPE_EMPTY:
137         case LY_TYPE_BOOL:
138             if(rand_bool()) {
139                 asprintf(&ret, "true");
140                 return ret;
141             }
142             else {
143                 asprintf(&ret, "false");
144                 return ret;
145             }
146             break;
147
148         case LY_TYPE_DER:
149             return rand_get_populate_value(&type->der->type);
150             break;
151
152         case LY_TYPE_ENUM:
153             if(type->info.enums.count) {
154                 int i = rand_uint16() % type->info.enums.count; 
155                 asprintf(&ret, "%s", type->info.enums.enm[i].name);
156                 return ret;
157             }
158             else {
159                 return rand_get_populate_value(&type->der->type);
160             }
161             break;
162
163         case LY_TYPE_IDENT: {
164             while(!type->info.ident.ref) {
165                 type = &type->der->type;
166             }
167             struct lys_ident *ident = rand_identity(type->info.ident.ref[0]);
168             if(ident == 0) {
169                 log_error("rand_identity failed");
170                 return 0;
171             }
172
173             asprintf(&ret, "%s:%s", ident->module->name, ident->name);
174             return ret;    
175         } break;
176
177         case LY_TYPE_STRING: {
178             int min_length = 1;
179             int max_length = 255;
180             char *expression = 0;
181             bool found_length = false;
182
183             do {
184                 if(type->info.str.length && !found_length) {
185                     rand_range_t vals = rand_range(type->info.str.length->expr, LY_TYPE_UINT8);
186                     min_length = vals.min.num;
187                     max_length = vals.max.num;
188                     if(min_length == 0) {
189                         min_length = 1;
190                     }
191
192                     found_length = true;
193                 }
194
195                 if(type->info.str.pat_count) {
196                     //checkAL aici de fapt trebuie sa facem AND si NOT intre toate expresiile, in functie de modifier
197                     // int modifier = type->info.str.patterns[i].expr[0];
198                     if(expression) {
199                         free(expression);
200                         expression = 0;
201                     }
202                     expression = strdup((char*)(type->info.str.patterns[0].expr + 1));
203                 }
204
205                 if(type->der) {
206                     type = &type->der->type;
207                 }
208                 else {
209                     break;
210                 }
211             } while(1);
212
213             if(expression) {
214                 char *ret = rand_regex(expression);
215                 if(ret == 0) {
216                     log_error("rand_regex failed");
217                     free(expression);
218                     return 0;
219                 }
220
221                 while(strlen(ret) < min_length) {
222                     char *add = rand_regex(expression);
223                     if(add == 0) {
224                         log_error("rand_regex failed");
225                         free(expression);
226                         free(ret);
227                         return 0;
228                     }
229
230                     char *newret = 0;
231                     asprintf(&newret, "%s%s", ret, add);
232                     free(add);
233                     free(ret);
234                     ret = newret;
235                 }
236                 free(expression);
237
238                 if(ret == 0) {
239                     log_error("rand_regex failed");
240                     return 0;
241                 }
242
243                 if(max_length && (strlen(ret) > max_length)) {
244                     ret[max_length] = 0;
245                 }
246
247                 return ret;
248             }
249             else {
250                 return rand_string(min_length, max_length);
251             }
252         } break;
253
254         case LY_TYPE_INT8:
255         case LY_TYPE_UINT8:
256         case LY_TYPE_INT16:
257         case LY_TYPE_UINT16:
258         case LY_TYPE_INT32:
259         case LY_TYPE_UINT32:
260         case LY_TYPE_INT64:
261         case LY_TYPE_UINT64: {
262             const char *expr = 0;
263             
264             do {
265                 if(type->info.num.range) {
266                     expr = type->info.num.range->expr;
267                 }    
268
269                 if(type->der) {
270                     type = &type->der->type;
271                 }
272                 else {
273                     break;
274                 }
275             } while(1);
276
277             int64_t r = rand_range(expr, type->base).value.num;
278             if(type->base == LY_TYPE_UINT8) {
279                 asprintf(&ret, "%"PRIu8, (uint8_t)r);
280             }
281             else if(type->base == LY_TYPE_UINT16) {
282                 asprintf(&ret, "%"PRIu16, (uint16_t)r);
283             }
284             else if(type->base == LY_TYPE_UINT32) {
285                 asprintf(&ret, "%"PRIu32, (uint32_t)r);
286             }
287             else if(type->base == LY_TYPE_UINT64) {
288                 asprintf(&ret, "%"PRIu64, (uint64_t)r);
289             }
290             else if(type->base == LY_TYPE_INT8) {
291                 asprintf(&ret, "%"PRId8, (int8_t)r);
292             }
293             else if(type->base == LY_TYPE_INT16) {
294                 asprintf(&ret, "%"PRId16, (int16_t)r);
295             }
296             else if(type->base == LY_TYPE_INT32) {
297                 asprintf(&ret, "%"PRId32, (int32_t)r);
298             }
299             else if(type->base == LY_TYPE_INT64) {
300                 asprintf(&ret, "%"PRId64, (int64_t)r);
301             }
302
303             return ret;
304         } break;
305
306         case LY_TYPE_DEC64: {
307             const char *expr = 0;
308             int digits = -1;
309             char fmt[10];
310             char *ret = 0;
311             
312             do {
313                 if(type->info.dec64.range) {
314                     expr = type->info.dec64.range->expr;
315                 }
316
317                 if(digits == -1) {
318                     digits = type->info.dec64.dig;
319                 }
320
321                 if(type->der) {
322                     type = &type->der->type;
323                 }
324                 else {
325                     break;
326                 }
327             } while(1);
328
329             rand_range_t dr = rand_range(expr, LY_TYPE_DEC64);
330             sprintf(fmt, "%%.%df", digits);
331
332             //19 digits total, including decimal part
333             int intdig = 19 - digits;
334             double max_val = 9.223372036854775807;
335
336             while(fabs(dr.value.dec) > (pow(10, intdig - 1) * max_val)) {
337                 dr.value.dec /= 10;
338             }
339
340             asprintf(&ret, fmt, dr.value.dec);
341             return ret;
342         } break;
343
344         case LY_TYPE_BITS:
345             ret = (char*)malloc(1);
346             if(ret == 0) {
347                 log_error("malloc failed");
348                 return 0;
349             }
350             ret[0] = 0;
351
352             for(int i = 0; i < type->info.bits.count; i++) {
353                 if(rand_bool()) {
354                     const char *val = type->info.bits.bit[i].name;
355                     bool first = (ret == 0);
356                     ret = (char*)realloc(ret, sizeof(char) * (strlen(ret) + 1 + strlen(val) + 1));
357                     if(ret == 0) {
358                         log_error("malloc failed");
359                         return 0;
360                     }
361
362                     if(!first) {
363                         strcat(ret, " ");
364                     }
365                     strcat(ret, val);
366                 }
367             }
368             return ret;
369             break;
370
371         case LY_TYPE_BINARY: {
372             int length = 1;
373             char *ret = 0;
374
375             do {
376                 if(type->info.binary.length) {
377                     rand_range_t vals = rand_range(type->info.binary.length->expr, LY_TYPE_UINT16);
378                     length = vals.min.num;
379                     if(length == 0) {
380                         length = 1;
381                     }
382                 }
383
384                 if(type->der) {
385                     type = &type->der->type;
386                 }
387                 else {
388                     break;
389                 }
390             } while(1);
391
392             uint8_t *data = (uint8_t *)malloc(sizeof(uint8_t) * length);
393             if(!data) {
394                 log_error("bad malloc");
395                 return 0;
396             }
397
398             for(int i = 0; i < length; i++) {
399                 data[i] = rand_uint8();
400             }
401
402             ret = b64_encode(data, length);
403             free(data);
404             return ret;
405         } break;
406
407         case LY_TYPE_LEAFREF:
408         case LY_TYPE_UNION:
409         case LY_TYPE_INST:
410             asprintf(&ret, "{late_resolve_%s}", type->der->name);
411             log_error("needed: %s", ret);
412             assert(0);
413             return ret;
414             break;
415
416         case LY_TYPE_UNKNOWN:
417         default:
418             asprintf(&ret, "{unimplemented_%s}", type->der->name);
419             log_error("can't generate random for: %s", type->der->name);
420             assert(0);
421             return ret;
422             break;
423     }
424 }
425
426 uint8_t rand_uint8(void) {
427     return rand() % 256;
428 }
429
430 int8_t rand_int8(void) {
431     return (int8_t)rand_uint8();
432 }
433
434 uint16_t rand_uint16(void) {
435     return rand() % 65536;
436 }
437
438 int16_t rand_int16(void) {
439     return (int16_t)rand_uint16();
440 }
441
442 uint32_t rand_uint32(void) {
443     uint32_t x = rand_uint16();
444     x <<= 16;
445     x += rand_uint16();
446     return x;
447 }
448
449 int32_t rand_int32(void) {
450     return (int32_t)rand_uint32();
451 }
452
453 uint64_t rand_uint64(void) {
454     uint64_t x = rand_uint32();
455     x <<= 32;
456     x += rand_uint32();
457     return x;
458 }
459
460 int64_t rand_int64(void) {
461     return (int64_t)rand_uint64();
462 }
463
464 bool rand_bool(void) {
465     return ((rand() & 0x01) == 1);
466 }
467
468 char *rand_regex(const char *regexp) {
469     assert(regexp);
470
471     char buffer[8192];
472     char *cmd = 0;
473     static int run_time = 0;
474
475     if(framework_arguments.no_rand) {
476         run_time++;
477         asprintf(&cmd, "regxstring %d '%s'", run_time, regexp);
478     }
479     else {
480         asprintf(&cmd, "regxstring '%s'", regexp);
481     }
482
483     FILE* pipe = popen(cmd, "r");
484     free(cmd);
485
486     if (!pipe) {
487         log_error("popen() failed");
488         return 0;
489     }
490
491     fgets(buffer, sizeof(buffer), pipe);
492     pclose(pipe);
493     
494     char *ret = strdup(buffer);
495     ret[strlen(ret) - 1] = 0;   //remove trailing \n
496
497     return ret;
498 }
499
500 char *rand_mac_address(void) {
501     char *ret = 0;
502
503     asprintf(&ret, "%02x:%02x:%02x:%02x:%02x:%02x", rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8());
504     return ret;
505 }
506
507 static char *rand_string(int min_length, int max_length) {
508     assert(min_length >= 0);
509     assert(min_length <= max_length);
510
511     char charset[] = "0123456789"
512                      "abcdefghijklmnopqrstuvwxyz"
513                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
514
515     int length = 1;
516     if(min_length == max_length) {
517         length = min_length;
518     }
519     else {
520         if((framework_config.debug_max_string_size) && (framework_config.debug_max_string_size < max_length)) {
521             max_length = framework_config.debug_max_string_size;
522         }
523
524         length = min_length + rand_uint16() % (max_length - min_length);
525     }
526
527     char *ret = (char *)malloc(length + 1);
528     if(!ret) {
529         log_error("bad malloc");
530         return 0;
531     }
532
533     for(int i = 0; i < length; i++) {
534         ret[i] = charset[(rand_uint8() % (sizeof(charset) - 1))];
535     }
536     ret[length] = 0;
537     return ret;
538 }
539
540 static struct lys_ident *rand_identity(struct lys_ident *type) {
541     assert(type);
542
543     struct lys_ident **found_identities;
544     int total = context_get_identity_leafs_of_type(type, &found_identities);
545     if(total == 0) {
546         return 0;
547     }
548
549     int chosen = rand_uint16() % total;
550     struct lys_ident *ret = found_identities[chosen];
551     free(found_identities);
552
553     return ret;
554 }
555
556
557 static int64_t rand_range_type_int_min(LY_DATA_TYPE type) {
558     switch (type) {
559         case LY_TYPE_UINT8:
560             return 0;
561             break;
562
563         case LY_TYPE_INT8:
564             return INT8_MIN;
565             break;
566
567         case LY_TYPE_UINT16:
568             return 0;
569             break;
570
571         case LY_TYPE_INT16:
572             return INT16_MIN;
573             break;
574
575         case LY_TYPE_UINT32:
576             return 0;
577             break;
578
579         case LY_TYPE_INT32:
580             return INT32_MIN;
581             break;
582
583         case LY_TYPE_UINT64:
584             return 0;
585             break;
586
587         case LY_TYPE_INT64:
588             return INT64_MIN;
589             break;
590
591         default:
592             return 0;
593             assert(0);
594             break;
595     }
596 }
597
598 static int64_t rand_range_type_int_max(LY_DATA_TYPE type) {
599     switch (type) {
600         case LY_TYPE_UINT8:
601             return UINT8_MAX;
602             break;
603
604         case LY_TYPE_INT8:
605             return INT8_MAX;
606             break;
607
608         case LY_TYPE_UINT16:
609             return UINT16_MAX;
610             break;
611
612         case LY_TYPE_INT16:
613             return INT16_MAX;
614             break;
615
616         case LY_TYPE_UINT32:
617             return UINT32_MAX;
618             break;
619
620         case LY_TYPE_INT32:
621             return INT32_MAX;
622             break;
623
624         case LY_TYPE_UINT64:
625             return INT64_MAX;   //yes, intended
626             break;
627
628         case LY_TYPE_INT64:
629             return INT64_MAX;
630             break;
631
632         default:
633             return 0;
634             assert(0);
635             break;
636     }
637 }
638
639 static rand_range_t rand_range(const char *range, const LY_DATA_TYPE type) {
640     char *working_range = 0;
641     rand_range_t ret;
642     ret.value.num = 0;
643     ret.min.num = 0;
644     ret.max.num = 0;
645
646     if (range) {
647         //remove spaces
648         char *rrange = (char*)malloc(sizeof(char) * (strlen(range) + 1));
649         if (!rrange) {
650             log_error("bad malloc");
651             return ret;
652         }
653
654         int i = 0;
655         int j = 0;
656         while (range[i]) {
657             if ((range[i] != ' ') && (range[i] != '\r') && (range[i] != '\n')) {
658                 rrange[j] = range[i];
659                 j++;
660             }
661             i++;
662         }
663         rrange[j] = 0;
664  
665         //split the range into OR ranges
666         //first count how many different ranges exist
667         int chosen_range = 1;
668         char *search = strchr(rrange, '|');
669         while (search) {
670             chosen_range++;
671             search = strchr(search + 1, '|');
672         }
673
674         //choose a random one
675         chosen_range = rand_uint16() % chosen_range;
676         int current_range = 0;
677         char *token;
678         token = strtok(rrange, "|");
679         while (token) {
680             if (current_range == chosen_range) {
681                 working_range = strdup(token);
682             }
683             current_range++;
684             token = strtok(0, "|");
685         }
686         free(rrange);
687     }
688
689     //now parse working_range according to type
690     if (type == LY_TYPE_DEC64) {
691         double min = -922337203685477580.8;
692         double max = 922337203685477580.7;
693         bool negative = false;
694
695         if (working_range) {
696             min = 0;
697             max = 0;
698
699             int i = 0;
700             if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
701                 min = -922337203685477580.8;
702                 while (working_range[i] != '.') {
703                     i++;
704                 }
705             }
706             else {
707                 if (working_range[i] == '-') {
708                     negative = true;
709                     i++;
710                 }
711
712                 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
713                     min *= 10;
714                     min += working_range[i] - '0';
715                     i++;
716                 }
717             }
718
719             //working_range[i...] is either '.', ".." or \0
720             if (working_range[i] == '.') {
721                 if (working_range[i + 1] != '.') {
722                     i++;
723                     int power = 0;
724                     while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
725                         power--;
726                         min += (working_range[i] - '0') * pow(10, power);
727                         i++;
728                     }
729                 }
730                 else {
731                     i += 2;    //skip ".."
732                 }
733             }
734
735             if (negative) {
736                 min *= -1;
737                 negative = false;
738             }
739             
740             if (working_range[i] == 0) {
741                 //single value
742                 max = min;
743             }
744             else {
745                 //there's also an upper value
746                 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
747                     max = 922337203685477580.7;
748                 }
749                 else {
750                     if (working_range[i] == '-') {
751                         negative = true;
752                         i++;
753                     }
754
755                     while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
756                         max *= 10;
757                         max += working_range[i] - '0';
758                         i++;
759                     }
760                 }
761
762                 //working_range[i...] is either '.', or \0
763                 if (working_range[i] == '.') {
764                     i++;
765                     int power = 0;
766                     while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
767                         power--;
768                         max += (working_range[i] - '0') * pow(10, power);
769                         i++;
770                     }
771                 }
772
773                 if (negative) {
774                     max *= -1;
775                     negative = false;
776                 }
777             }
778         }
779
780         ret.value.dec = rand() / 1.0 / RAND_MAX;
781         ret.value.dec = (max - min) * ret.value.dec + min;
782         ret.min.dec = min;
783         ret.max.dec = max;
784     }
785     else {
786         int64_t min = rand_range_type_int_min(type);
787         int64_t max = rand_range_type_int_max(type);
788         bool negative = false;
789
790         if (working_range) {
791             min = 0;
792             max = 0;
793
794             int i = 0;
795             if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
796                 min = rand_range_type_int_min(type);
797                 while (working_range[i] != '.') {
798                     i++;
799                 }
800             }
801             else {
802                 if (working_range[i] == '-') {
803                     negative = true;
804                     i++;
805                 }
806
807                 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
808                     min *= 10;
809                     min += working_range[i] - '0';
810                     i++;
811                 }
812             }
813
814             //working_range[i...] is either ".." or \0
815             if (working_range[i] == '.') {
816                 i += 2;    //skip ".."
817             }
818
819             if (negative) {
820                 min *= -1;
821                 negative = false;
822             }
823
824             if (working_range[i] == 0) {
825                 //single value
826                 max = min;
827             }
828             else {
829                 //there's also an upper value
830                 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
831                     max = rand_range_type_int_max(type);
832                 }
833                 else {
834                     if (working_range[i] == '-') {
835                         negative = true;
836                         i++;
837                     }
838
839                     while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
840                         max *= 10;
841                         max += working_range[i] - '0';
842                         i++;
843                     }
844                 }
845
846                 if (negative) {
847                     max *= -1;
848                     negative = false;
849                 }
850
851             }
852         }
853
854         double ch = rand() / 1.0 / RAND_MAX;
855         ret.value.num = (max - min) * ch + min;
856         ret.min.num = min;
857         ret.max.num = max;
858     }
859
860     free(working_range);
861
862     return ret;
863 }
864
865 static char *rand_date_and_time(void) {
866     time_t t = rand_uint32() / 2;
867     struct tm lt;
868     (void)localtime_r(&t, &lt);
869
870     char *ret = (char *)malloc(21);
871     if(!ret) {
872         log_error("bad malloc");
873         return 0;
874     }
875     strftime(ret, 21, "%Y-%m-%dT%H:%M:%SZ", &lt);
876     return ret;
877 }
878
879 static char *rand_ipv4_address(void) {
880     char *ret = 0;
881     uint8_t ip1 = rand_uint8();
882     uint8_t ip2 = rand_uint8();
883     uint8_t ip3 = rand_uint8();
884     uint8_t ip4 = rand_uint8();
885
886     asprintf(&ret, "%d.%d.%d.%d", ip1, ip2, ip3, ip4);
887     return ret;
888 }
889
890 static char *rand_ipv6_address(void) {
891     char *ret = 0;
892
893     uint16_t ip1 = rand_uint16();
894     uint16_t ip2 = rand_uint16();
895     uint16_t ip3 = rand_uint16();
896     uint16_t ip4 = rand_uint16();
897     uint16_t ip5 = rand_uint16();
898     uint16_t ip6 = rand_uint16();
899     uint16_t ip7 = rand_uint16();
900     uint16_t ip8 = rand_uint16();
901
902     asprintf(&ret, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ip1, ip2, ip3, ip4, ip5, ip6, ip7, ip8);
903     return ret;
904 }
905
906 static char *rand_uuid(void) {
907     char *ret = 0;
908
909     //8-4-4-4-12
910     uint32_t v1 = rand_uint32();
911     uint16_t v2 = rand_uint16();
912     uint16_t v3 = rand_uint16();
913     uint16_t v4 = rand_uint16();
914     uint16_t v5 = rand_uint16();
915     uint32_t v6 = rand_uint32();
916
917     asprintf(&ret, "%08x-%04x-%04x-%04x-%04x%08x", v1, v2, v3, v4, v5, v6);
918
919     return ret;
920 }