1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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 ***************************************************************************/
20 #include "rand_utils.h"
21 #include "log_utils.h"
22 #include "sys_utils.h" //for b64_encode
30 #include "core/context.h" //for context_get_identity_leafs_of_type
31 #include "core/framework.h" //to check for no_rand
34 typedef struct __rand_range {
52 static char *rand_string(int min_length, int max_length);
53 static struct lys_ident *rand_identity(struct lys_ident *type);
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);
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);
67 void rand_init(void) {
70 FILE* urandom = fopen("/dev/urandom", "r");
72 log_error("failed to open /dev/urandom");
75 fread(&seed, sizeof(int), 1, urandom);
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);
88 void rand_init_fixed(unsigned int seed) {
92 log_message(2, "rand_init_fixed() was called and seed was initialized to %u\n", seed);
94 if(RAND_MAX < 65536) {
95 log_error("RAND_MAX is too low: %d", RAND_MAX);
99 char *rand_get_populate_value(const struct lys_type *type) {
104 if(type->der->module) {
107 asprintf(&full_type, "%s:%s", type->der->module->name, type->der->name);
109 log_error("bad malloc");
113 if(strstr(full_type, "ietf-yang-types:date-and-time") != 0) {
114 ret = rand_date_and_time();
116 else if(strstr(full_type, "ietf-inet-types:ipv4-address") != 0) {
117 ret = rand_ipv4_address();
119 else if(strstr(full_type, "ietf-inet-types:ipv6-address") != 0) {
120 ret = rand_ipv6_address();
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();
125 else if(strstr(full_type, "universal-id") != 0) {
139 asprintf(&ret, "true");
143 asprintf(&ret, "false");
149 return rand_get_populate_value(&type->der->type);
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);
159 return rand_get_populate_value(&type->der->type);
163 case LY_TYPE_IDENT: {
164 while(!type->info.ident.ref) {
165 type = &type->der->type;
167 struct lys_ident *ident = rand_identity(type->info.ident.ref[0]);
169 log_error("rand_identity failed");
173 asprintf(&ret, "%s:%s", ident->module->name, ident->name);
177 case LY_TYPE_STRING: {
179 int max_length = 255;
180 char *expression = 0;
181 bool found_length = false;
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) {
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];
202 expression = strdup((char*)(type->info.str.patterns[0].expr + 1));
206 type = &type->der->type;
214 char *ret = rand_regex(expression);
216 log_error("rand_regex failed");
221 while(strlen(ret) < min_length) {
222 char *add = rand_regex(expression);
224 log_error("rand_regex failed");
231 asprintf(&newret, "%s%s", ret, add);
239 log_error("rand_regex failed");
243 if(max_length && (strlen(ret) > max_length)) {
250 return rand_string(min_length, max_length);
261 case LY_TYPE_UINT64: {
262 const char *expr = 0;
265 if(type->info.num.range) {
266 expr = type->info.num.range->expr;
270 type = &type->der->type;
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);
281 else if(type->base == LY_TYPE_UINT16) {
282 asprintf(&ret, "%"PRIu16, (uint16_t)r);
284 else if(type->base == LY_TYPE_UINT32) {
285 asprintf(&ret, "%"PRIu32, (uint32_t)r);
287 else if(type->base == LY_TYPE_UINT64) {
288 asprintf(&ret, "%"PRIu64, (uint64_t)r);
290 else if(type->base == LY_TYPE_INT8) {
291 asprintf(&ret, "%"PRId8, (int8_t)r);
293 else if(type->base == LY_TYPE_INT16) {
294 asprintf(&ret, "%"PRId16, (int16_t)r);
296 else if(type->base == LY_TYPE_INT32) {
297 asprintf(&ret, "%"PRId32, (int32_t)r);
299 else if(type->base == LY_TYPE_INT64) {
300 asprintf(&ret, "%"PRId64, (int64_t)r);
306 case LY_TYPE_DEC64: {
307 const char *expr = 0;
313 if(type->info.dec64.range) {
314 expr = type->info.dec64.range->expr;
318 digits = type->info.dec64.dig;
322 type = &type->der->type;
329 rand_range_t dr = rand_range(expr, LY_TYPE_DEC64);
330 sprintf(fmt, "%%.%df", digits);
332 //19 digits total, including decimal part
333 int intdig = 19 - digits;
334 double max_val = 9.223372036854775807;
336 while(fabs(dr.value.dec) > (pow(10, intdig - 1) * max_val)) {
340 asprintf(&ret, fmt, dr.value.dec);
345 ret = (char*)malloc(1);
347 log_error("malloc failed");
352 for(int i = 0; i < type->info.bits.count; i++) {
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));
358 log_error("malloc failed");
371 case LY_TYPE_BINARY: {
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;
385 type = &type->der->type;
392 uint8_t *data = (uint8_t *)malloc(sizeof(uint8_t) * length);
394 log_error("bad malloc");
398 for(int i = 0; i < length; i++) {
399 data[i] = rand_uint8();
402 ret = b64_encode(data, length);
407 case LY_TYPE_LEAFREF:
410 asprintf(&ret, "{late_resolve_%s}", type->der->name);
411 log_error("needed: %s", ret);
416 case LY_TYPE_UNKNOWN:
418 asprintf(&ret, "{unimplemented_%s}", type->der->name);
419 log_error("can't generate random for: %s", type->der->name);
426 uint8_t rand_uint8(void) {
430 int8_t rand_int8(void) {
431 return (int8_t)rand_uint8();
434 uint16_t rand_uint16(void) {
435 return rand() % 65536;
438 int16_t rand_int16(void) {
439 return (int16_t)rand_uint16();
442 uint32_t rand_uint32(void) {
443 uint32_t x = rand_uint16();
449 int32_t rand_int32(void) {
450 return (int32_t)rand_uint32();
453 uint64_t rand_uint64(void) {
454 uint64_t x = rand_uint32();
460 int64_t rand_int64(void) {
461 return (int64_t)rand_uint64();
464 bool rand_bool(void) {
465 return ((rand() & 0x01) == 1);
468 char *rand_regex(const char *regexp) {
473 static int run_time = 0;
475 char *regexp64 = b64_encode((const unsigned char*)regexp, strlen(regexp));
477 log_error("b64_encode failed");
481 if(framework_arguments.no_rand) {
483 asprintf(&cmd, "regxstring %d '%s'", run_time, regexp64);
486 asprintf(&cmd, "regxstring '%s'", regexp64);
491 log_error("asprintf failed");
495 char last_char = ' ';
496 while(last_char == ' ') {
497 FILE* pipe = popen(cmd, "r");
499 log_error("popen() failed");
504 fgets(buffer, sizeof(buffer), pipe);
507 buffer[strlen(buffer) - 1] = 0; //remove trailing \n
508 last_char = buffer[strlen(buffer) - 1];
511 char *ret = strdup(buffer);
517 char *rand_mac_address(void) {
520 asprintf(&ret, "%02x:%02x:%02x:%02x:%02x:%02x", rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8());
524 static char *rand_string(int min_length, int max_length) {
525 assert(min_length >= 0);
526 assert(min_length <= max_length);
528 char charset[] = "0123456789"
529 "abcdefghijklmnopqrstuvwxyz"
530 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
533 if(min_length == max_length) {
537 if((framework_config.debug_max_string_size) && (framework_config.debug_max_string_size < max_length)) {
538 max_length = framework_config.debug_max_string_size;
541 length = min_length + rand_uint16() % (max_length - min_length);
544 char *ret = (char *)malloc(length + 1);
546 log_error("bad malloc");
550 for(int i = 0; i < length; i++) {
551 ret[i] = charset[(rand_uint8() % (sizeof(charset) - 1))];
557 static struct lys_ident *rand_identity(struct lys_ident *type) {
560 struct lys_ident **found_identities;
561 int total = context_get_identity_leafs_of_type(type, &found_identities);
566 int chosen = rand_uint16() % total;
567 struct lys_ident *ret = found_identities[chosen];
568 free(found_identities);
574 static int64_t rand_range_type_int_min(LY_DATA_TYPE type) {
615 static int64_t rand_range_type_int_max(LY_DATA_TYPE type) {
642 return INT64_MAX; //yes, intended
656 static rand_range_t rand_range(const char *range, const LY_DATA_TYPE type) {
657 char *working_range = 0;
665 char *rrange = (char*)malloc(sizeof(char) * (strlen(range) + 1));
667 log_error("bad malloc");
674 if ((range[i] != ' ') && (range[i] != '\r') && (range[i] != '\n')) {
675 rrange[j] = range[i];
682 //split the range into OR ranges
683 //first count how many different ranges exist
684 int chosen_range = 1;
685 char *search = strchr(rrange, '|');
688 search = strchr(search + 1, '|');
691 //choose a random one
692 chosen_range = rand_uint16() % chosen_range;
693 int current_range = 0;
695 token = strtok(rrange, "|");
697 if (current_range == chosen_range) {
698 working_range = strdup(token);
701 token = strtok(0, "|");
706 //now parse working_range according to type
707 if (type == LY_TYPE_DEC64) {
708 double min = -922337203685477580.8;
709 double max = 922337203685477580.7;
710 bool negative = false;
717 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
718 min = -922337203685477580.8;
719 while (working_range[i] != '.') {
724 if (working_range[i] == '-') {
729 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
731 min += working_range[i] - '0';
736 //working_range[i...] is either '.', ".." or \0
737 if (working_range[i] == '.') {
738 if (working_range[i + 1] != '.') {
741 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
743 min += (working_range[i] - '0') * pow(10, power);
757 if (working_range[i] == 0) {
762 //there's also an upper value
763 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
764 max = 922337203685477580.7;
767 if (working_range[i] == '-') {
772 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
774 max += working_range[i] - '0';
779 //working_range[i...] is either '.', or \0
780 if (working_range[i] == '.') {
783 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
785 max += (working_range[i] - '0') * pow(10, power);
797 ret.value.dec = rand() / 1.0 / RAND_MAX;
798 ret.value.dec = (max - min) * ret.value.dec + min;
803 int64_t min = rand_range_type_int_min(type);
804 int64_t max = rand_range_type_int_max(type);
805 bool negative = false;
812 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
813 min = rand_range_type_int_min(type);
814 while (working_range[i] != '.') {
819 if (working_range[i] == '-') {
824 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
826 min += working_range[i] - '0';
831 //working_range[i...] is either ".." or \0
832 if (working_range[i] == '.') {
841 if (working_range[i] == 0) {
846 //there's also an upper value
847 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
848 max = rand_range_type_int_max(type);
851 if (working_range[i] == '-') {
856 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
858 max += working_range[i] - '0';
871 double ch = rand() / 1.0 / RAND_MAX;
872 ret.value.num = (max - min) * ch + min;
882 static char *rand_date_and_time(void) {
883 time_t t = rand_uint32() / 2;
885 (void)localtime_r(&t, <);
887 char *ret = (char *)malloc(21);
889 log_error("bad malloc");
892 strftime(ret, 21, "%Y-%m-%dT%H:%M:%SZ", <);
896 static char *rand_ipv4_address(void) {
898 uint8_t ip1 = rand_uint8();
899 uint8_t ip2 = rand_uint8();
900 uint8_t ip3 = rand_uint8();
901 uint8_t ip4 = rand_uint8();
903 asprintf(&ret, "%d.%d.%d.%d", ip1, ip2, ip3, ip4);
907 static char *rand_ipv6_address(void) {
910 uint16_t ip1 = rand_uint16();
911 uint16_t ip2 = rand_uint16();
912 uint16_t ip3 = rand_uint16();
913 uint16_t ip4 = rand_uint16();
914 uint16_t ip5 = rand_uint16();
915 uint16_t ip6 = rand_uint16();
916 uint16_t ip7 = rand_uint16();
917 uint16_t ip8 = rand_uint16();
919 asprintf(&ret, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ip1, ip2, ip3, ip4, ip5, ip6, ip7, ip8);
923 static char *rand_uuid(void) {
927 uint32_t v1 = rand_uint32();
928 uint16_t v2 = rand_uint16();
929 uint16_t v3 = rand_uint16();
930 uint16_t v4 = rand_uint16();
931 uint16_t v5 = rand_uint16();
932 uint32_t v6 = rand_uint32();
934 asprintf(&ret, "%08x-%04x-%04x-%04x-%04x%08x", v1, v2, v3, v4, v5, v6);