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 if(framework_arguments.no_rand) {
477 asprintf(&cmd, "regxstring %d '%s'", run_time, regexp);
480 asprintf(&cmd, "regxstring '%s'", regexp);
483 FILE* pipe = popen(cmd, "r");
487 log_error("popen() failed");
491 fgets(buffer, sizeof(buffer), pipe);
494 char *ret = strdup(buffer);
495 ret[strlen(ret) - 1] = 0; //remove trailing \n
500 char *rand_mac_address(void) {
503 asprintf(&ret, "%02x:%02x:%02x:%02x:%02x:%02x", rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8());
507 static char *rand_string(int min_length, int max_length) {
508 assert(min_length >= 0);
509 assert(min_length <= max_length);
511 char charset[] = "0123456789"
512 "abcdefghijklmnopqrstuvwxyz"
513 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
516 if(min_length == max_length) {
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;
524 length = min_length + rand_uint16() % (max_length - min_length);
527 char *ret = (char *)malloc(length + 1);
529 log_error("bad malloc");
533 for(int i = 0; i < length; i++) {
534 ret[i] = charset[(rand_uint8() % (sizeof(charset) - 1))];
540 static struct lys_ident *rand_identity(struct lys_ident *type) {
543 struct lys_ident **found_identities;
544 int total = context_get_identity_leafs_of_type(type, &found_identities);
549 int chosen = rand_uint16() % total;
550 struct lys_ident *ret = found_identities[chosen];
551 free(found_identities);
557 static int64_t rand_range_type_int_min(LY_DATA_TYPE type) {
598 static int64_t rand_range_type_int_max(LY_DATA_TYPE type) {
625 return INT64_MAX; //yes, intended
639 static rand_range_t rand_range(const char *range, const LY_DATA_TYPE type) {
640 char *working_range = 0;
648 char *rrange = (char*)malloc(sizeof(char) * (strlen(range) + 1));
650 log_error("bad malloc");
657 if ((range[i] != ' ') && (range[i] != '\r') && (range[i] != '\n')) {
658 rrange[j] = range[i];
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, '|');
671 search = strchr(search + 1, '|');
674 //choose a random one
675 chosen_range = rand_uint16() % chosen_range;
676 int current_range = 0;
678 token = strtok(rrange, "|");
680 if (current_range == chosen_range) {
681 working_range = strdup(token);
684 token = strtok(0, "|");
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;
700 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
701 min = -922337203685477580.8;
702 while (working_range[i] != '.') {
707 if (working_range[i] == '-') {
712 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
714 min += working_range[i] - '0';
719 //working_range[i...] is either '.', ".." or \0
720 if (working_range[i] == '.') {
721 if (working_range[i + 1] != '.') {
724 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
726 min += (working_range[i] - '0') * pow(10, power);
740 if (working_range[i] == 0) {
745 //there's also an upper value
746 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
747 max = 922337203685477580.7;
750 if (working_range[i] == '-') {
755 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
757 max += working_range[i] - '0';
762 //working_range[i...] is either '.', or \0
763 if (working_range[i] == '.') {
766 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
768 max += (working_range[i] - '0') * pow(10, power);
780 ret.value.dec = rand() / 1.0 / RAND_MAX;
781 ret.value.dec = (max - min) * ret.value.dec + min;
786 int64_t min = rand_range_type_int_min(type);
787 int64_t max = rand_range_type_int_max(type);
788 bool negative = false;
795 if ((working_range[i] == 'm') || (working_range[i] == 'M')) {
796 min = rand_range_type_int_min(type);
797 while (working_range[i] != '.') {
802 if (working_range[i] == '-') {
807 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
809 min += working_range[i] - '0';
814 //working_range[i...] is either ".." or \0
815 if (working_range[i] == '.') {
824 if (working_range[i] == 0) {
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);
834 if (working_range[i] == '-') {
839 while ((working_range[i] >= '0') && (working_range[i] <= '9')) {
841 max += working_range[i] - '0';
854 double ch = rand() / 1.0 / RAND_MAX;
855 ret.value.num = (max - min) * ch + min;
865 static char *rand_date_and_time(void) {
866 time_t t = rand_uint32() / 2;
868 (void)localtime_r(&t, <);
870 char *ret = (char *)malloc(21);
872 log_error("bad malloc");
875 strftime(ret, 21, "%Y-%m-%dT%H:%M:%SZ", <);
879 static char *rand_ipv4_address(void) {
881 uint8_t ip1 = rand_uint8();
882 uint8_t ip2 = rand_uint8();
883 uint8_t ip3 = rand_uint8();
884 uint8_t ip4 = rand_uint8();
886 asprintf(&ret, "%d.%d.%d.%d", ip1, ip2, ip3, ip4);
890 static char *rand_ipv6_address(void) {
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();
902 asprintf(&ret, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ip1, ip2, ip3, ip4, ip5, ip6, ip7, ip8);
906 static char *rand_uuid(void) {
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();
917 asprintf(&ret, "%08x-%04x-%04x-%04x-%04x%08x", v1, v2, v3, v4, v5, v6);