@cryptotaxi247 / netdata-1 / commits / 7da20f8a2

UTF8 support for chart ids, names and other metadata (#18684)

* eval without hardcoding what variables look like * allow international characters in journal sources * removed left-over sanitizers from health config * international characters support for chart ids and names * renamed for clarity

Costa Tsaousis committed Oct 4, 2024 at 17:58 UTC 7da20f8a2a1c2289eea3219b3c22f95539f7e96e
10 files changed +211 -602
src/collectors/systemd-journal.plugin/systemd-journal-files.c
+1 -2
@@ -369,8 +369,7 @@ static STRING *string_strdupz_source(const char *s, const char *e, size_t max_le
369 buf[max_len - 1] = '\0';
370
371 for(size_t i = 0; buf[i] ;i++)
372 - if(!isalnum(buf[i]) && buf[i] != '-' && buf[i] != '.' && buf[i] != ':')
373 - buf[i] = '_';
372 + if(!is_netdata_api_valid_character(buf[i])) buf[i] = '_';
373
374 return string_strdupz(buf);
375 }
src/database/rrd.h
-1
@@ -1569,7 +1569,6 @@ void rrddim_store_metric(RRDDIM *rd, usec_t point_end_time_ut, NETDATA_DOUBLE n,
1569 // ----------------------------------------------------------------------------
1570 // Miscellaneous functions
1571
1572 -char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
1572 void reload_host_labels(void);
1573 void rrdhost_set_is_parent_label(void);
1574
src/database/rrdset.c
-15
@@ -597,21 +597,6 @@ void rrdset_acquired_release(RRDSET_ACQUIRED *rsa) {
597 // ----------------------------------------------------------------------------
598 // RRDSET - rename charts
599
600 -char *rrdset_strncpyz_name(char *to, const char *from, size_t length) {
601 - char c, *p = to;
602 -
603 - while (length-- && (c = *from++)) {
604 - if(c != '.' && c != '-' && !isalnum(c))
605 - c = '_';
606 -
607 - *p++ = c;
608 - }
609 -
610 - *p = '\0';
611 -
612 - return to;
613 -}
614 -
600 int rrdset_reset_name(RRDSET *st, const char *name) {
601 if(unlikely(!strcmp(rrdset_name(st), name)))
602 return 1;
src/health/health_config.c
-7
@@ -155,13 +155,6 @@ static inline int health_parse_repeat(
155 return 1;
156 }
157
158 -static inline int isvariableterm(const char s) {
159 - if(isalnum(s) || s == '.' || s == '_')
160 - return 0;
161 -
162 - return 1;
163 -}
164 -
158 static inline int health_parse_db_lookup(size_t line, const char *filename, char *string, struct rrd_alert_config *ac) {
159 if(ac->dimensions) string_freez(ac->dimensions);
160 ac->dimensions = NULL;
src/health/rrdvar.c
-14
@@ -9,20 +9,6 @@ typedef struct rrdvar {
9 // ----------------------------------------------------------------------------
10 // RRDVAR management
11
12 -inline int rrdvar_fix_name(char *variable) {
13 - int fixed = 0;
14 - while(*variable) {
15 - if (!isalnum((uint8_t)*variable) && *variable != '.' && *variable != '_') {
16 - *variable++ = '_';
17 - fixed++;
18 - }
19 - else
20 - variable++;
21 - }
22 -
23 - return fixed;
24 -}
25 -
12 inline STRING *rrdvar_name_to_string(const char *name) {
13 char *variable = strdupz(name);
14 rrdvar_fix_name(variable);
src/health/rrdvar.h
-2
@@ -7,8 +7,6 @@
7
8 #define RRDVAR_MAX_LENGTH 1024
9
10 -int rrdvar_fix_name(char *variable);
11 -
10 #include "database/rrd.h"
11
12 STRING *rrdvar_name_to_string(const char *name);
src/libnetdata/config/dyncfg.c
+2 -2
@@ -211,7 +211,7 @@ bool dyncfg_is_valid_id(const char *id) {
211 return true;
212 }
213
214 -static inline bool is_forbidden_char(char c) {
214 +static inline bool is_forbidden_filename_char(char c) {
215 if(isspace((uint8_t)c) || !isprint((uint8_t)c))
216 return true;
217
@@ -239,7 +239,7 @@ char *dyncfg_escape_id_for_filename(const char *id) {
239 char *dest = escaped;
240
241 while (*src) {
242 - if (is_forbidden_char(*src)) {
242 + if (is_forbidden_filename_char(*src)) {
243 sprintf(dest, "%%%02X", (unsigned char)*src);
244 dest += 3;
245 } else {
src/libnetdata/eval/eval.c
+75 -39
@@ -387,29 +387,63 @@ static inline void skip_spaces(const char **string) {
387 *string = s;
388 }
389
390 -// what character can appear just after an operator keyword
391 -// like NOT AND OR ?
392 -static inline int isoperatorterm_word(const char s) {
393 - if(isspace(s) || s == '(' || s == '$' || s == '!' || s == '-' || s == '+' || isdigit(s) || !s)
394 - return 1;
395 -
396 - return 0;
390 +//static inline int old_isoperatorterm_word(const char s) {
391 +// if (isspace(s) || s == '(' || s == '$' || s == '!' || s == '-' || s == '+' || isdigit(s) || !s)
392 +// return 1;
393 +// return 0;
394 +//}
395 +//
396 +//static inline int old_isoperatorterm_symbol(const char s) {
397 +// if (old_isoperatorterm_word(s) || isalpha(s))
398 +// return 1;
399 +// return 0;
400 +//}
401 +//
402 +//// return 1 if the character should never appear in a variable
403 +//static inline int old_isvariableterm(const char s) {
404 +// if (isalnum(s) || s == '.' || s == '_')
405 +// return 0;
406 +// return 1;
407 +//}
408 +
409 +static inline bool is_operator_first_symbol_or_space(const char s) {
410 + return (
411 + isspace((uint8_t)s) || !s ||
412 + s == '&' || s == '|' || s == '!' || s == '>' || s == '<' ||
413 + s == '=' || s == '+' || s == '-' || s == '*' || s == '/' || s == '?');
414 +}
415 +
416 +// what character can appear just after the operators: NOT, AND, OR
417 +static inline bool is_valid_after_operator_word(const char s) {
418 + bool rc = isspace((uint8_t)s) || s == '(' || s == '$' || s == '!' || s == '-' || s == '+' || isdigit((uint8_t)s) || !s;
419 +// bool old = old_isoperatorterm_word(s);
420 +// if(rc != old) {
421 +// int x = 0;
422 +// x++;
423 +// }
424 + return rc;
425 }
426
427 // what character can appear just after an operator symbol?
400 -static inline int isoperatorterm_symbol(const char s) {
401 - if(isoperatorterm_word(s) || isalpha(s))
402 - return 1;
403 -
404 - return 0;
405 -}
406 -
407 -// return 1 if the character should never appear in a variable
408 -static inline int isvariableterm(const char s) {
409 - if(isalnum(s) || s == '.' || s == '_')
410 - return 0;
411 -
412 - return 1;
428 +static inline bool is_valid_after_operator_symbol(const char s) {
429 + bool rc = is_valid_after_operator_word(s) || is_operator_first_symbol_or_space(s);
430 +// bool old = old_isoperatorterm_symbol(s);
431 +// if(rc != old) {
432 +// int x = 0;
433 +// x++;
434 +// }
435 + return rc;
436 +}
437 +
438 +// return true if the character may appear in a variable name
439 +static inline bool is_valid_variable_character(const char s) {
440 + bool rc = !is_operator_first_symbol_or_space(s) && s != ')' && s != '}';
441 +// bool old = !old_isvariableterm(s);
442 +// if(rc != old) {
443 +// int x = 0;
444 +// x++;
445 +// }
446 + return rc;
447 }
448
449 // ----------------------------------------------------------------------------
@@ -419,13 +453,14 @@ static inline int parse_and(const char **string) {
453 const char *s = *string;
454
455 // AND
422 - if((s[0] == 'A' || s[0] == 'a') && (s[1] == 'N' || s[1] == 'n') && (s[2] == 'D' || s[2] == 'd') && isoperatorterm_word(s[3])) {
456 + if((s[0] == 'A' || s[0] == 'a') && (s[1] == 'N' || s[1] == 'n') && (s[2] == 'D' || s[2] == 'd') &&
457 + is_valid_after_operator_word(s[3])) {
458 *string = &s[4];
459 return 1;
460 }
461
462 // &&
428 - if(s[0] == '&' && s[1] == '&' && isoperatorterm_symbol(s[2])) {
463 + if(s[0] == '&' && s[1] == '&' && is_valid_after_operator_symbol(s[2])) {
464 *string = &s[2];
465 return 1;
466 }
@@ -437,13 +472,13 @@ static inline int parse_or(const char **string) {
472 const char *s = *string;
473
474 // OR
440 - if((s[0] == 'O' || s[0] == 'o') && (s[1] == 'R' || s[1] == 'r') && isoperatorterm_word(s[2])) {
475 + if((s[0] == 'O' || s[0] == 'o') && (s[1] == 'R' || s[1] == 'r') && is_valid_after_operator_word(s[2])) {
476 *string = &s[3];
477 return 1;
478 }
479
480 // ||
446 - if(s[0] == '|' && s[1] == '|' && isoperatorterm_symbol(s[2])) {
481 + if(s[0] == '|' && s[1] == '|' && is_valid_after_operator_symbol(s[2])) {
482 *string = &s[2];
483 return 1;
484 }
@@ -455,7 +490,7 @@ static inline int parse_greater_than_or_equal(const char **string) {
490 const char *s = *string;
491
492 // >=
458 - if(s[0] == '>' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
493 + if(s[0] == '>' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
494 *string = &s[2];
495 return 1;
496 }
@@ -467,7 +502,7 @@ static inline int parse_less_than_or_equal(const char **string) {
502 const char *s = *string;
503
504 // <=
470 - if (s[0] == '<' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
505 + if (s[0] == '<' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
506 *string = &s[2];
507 return 1;
508 }
@@ -479,7 +514,7 @@ static inline int parse_greater(const char **string) {
514 const char *s = *string;
515
516 // >
482 - if(s[0] == '>' && isoperatorterm_symbol(s[1])) {
517 + if(s[0] == '>' && is_valid_after_operator_symbol(s[1])) {
518 *string = &s[1];
519 return 1;
520 }
@@ -491,7 +526,7 @@ static inline int parse_less(const char **string) {
526 const char *s = *string;
527
528 // <
494 - if(s[0] == '<' && isoperatorterm_symbol(s[1])) {
529 + if(s[0] == '<' && is_valid_after_operator_symbol(s[1])) {
530 *string = &s[1];
531 return 1;
532 }
@@ -503,13 +538,13 @@ static inline int parse_equal(const char **string) {
538 const char *s = *string;
539
540 // ==
506 - if(s[0] == '=' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
541 + if(s[0] == '=' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
542 *string = &s[2];
543 return 1;
544 }
545
546 // =
512 - if(s[0] == '=' && isoperatorterm_symbol(s[1])) {
547 + if(s[0] == '=' && is_valid_after_operator_symbol(s[1])) {
548 *string = &s[1];
549 return 1;
550 }
@@ -521,13 +556,13 @@ static inline int parse_not_equal(const char **string) {
556 const char *s = *string;
557
558 // !=
524 - if(s[0] == '!' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
559 + if(s[0] == '!' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
560 *string = &s[2];
561 return 1;
562 }
563
564 // <>
530 - if(s[0] == '<' && s[1] == '>' && isoperatorterm_symbol(s[2])) {
565 + if(s[0] == '<' && s[1] == '>' && is_valid_after_operator_symbol(s[2])) {
566 *string = &s[2];
567 }
568
@@ -538,7 +573,8 @@ static inline int parse_not(const char **string) {
573 const char *s = *string;
574
575 // NOT
541 - if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') && isoperatorterm_word(s[3])) {
576 + if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') &&
577 + is_valid_after_operator_word(s[3])) {
578 *string = &s[3];
579 return 1;
580 }
@@ -555,7 +591,7 @@ static inline int parse_multiply(const char **string) {
591 const char *s = *string;
592
593 // *
558 - if(s[0] == '*' && isoperatorterm_symbol(s[1])) {
594 + if(s[0] == '*' && is_valid_after_operator_symbol(s[1])) {
595 *string = &s[1];
596 return 1;
597 }
@@ -567,7 +603,7 @@ static inline int parse_divide(const char **string) {
603 const char *s = *string;
604
605 // /
570 - if(s[0] == '/' && isoperatorterm_symbol(s[1])) {
606 + if(s[0] == '/' && is_valid_after_operator_symbol(s[1])) {
607 *string = &s[1];
608 return 1;
609 }
@@ -579,7 +615,7 @@ static inline int parse_minus(const char **string) {
615 const char *s = *string;
616
617 // -
582 - if(s[0] == '-' && isoperatorterm_symbol(s[1])) {
618 + if(s[0] == '-' && is_valid_after_operator_symbol(s[1])) {
619 *string = &s[1];
620 return 1;
621 }
@@ -591,7 +627,7 @@ static inline int parse_plus(const char **string) {
627 const char *s = *string;
628
629 // +
594 - if(s[0] == '+' && isoperatorterm_symbol(s[1])) {
630 + if(s[0] == '+' && is_valid_after_operator_symbol(s[1])) {
631 *string = &s[1];
632 return 1;
633 }
@@ -646,7 +682,7 @@ static inline int parse_variable(const char **string, char *buffer, size_t len)
682 else {
683 // $variable_name
684
649 - while (*s && !isvariableterm(*s) && i < len)
685 + while (*s && is_valid_variable_character(*s) && i < len)
686 buffer[i++] = *s++;
687 }
688
@@ -1219,7 +1255,7 @@ void expression_hardcode_variable(EVAL_EXPRESSION *expression, STRING *variable,
1255 }
1256
1257 if (s) {
1222 - if (s == s1 && (isalnum((uint8_t)s[len]) || s[len] == '_')) {
1258 + if (s == s1 && !is_valid_variable_character(s[len])) {
1259 // Move past the variable if it's part of a larger word.
1260 source_ptr = s + len;
1261 continue;
src/libnetdata/sanitizers/chart_id_and_name.c
+126 -520
@@ -2,532 +2,138 @@
2
3 #include "../libnetdata.h"
4
5 -static uint8_t netdata_map_chart_names[256] = {
6 - [0] = '\0', //
7 - [1] = '_', //
8 - [2] = '_', //
9 - [3] = '_', //
10 - [4] = '_', //
11 - [5] = '_', //
12 - [6] = '_', //
13 - [7] = '_', //
14 - [8] = '_', //
15 - [9] = '_', //
16 - [10] = '_', //
17 - [11] = '_', //
18 - [12] = '_', //
19 - [13] = '_', //
20 - [14] = '_', //
21 - [15] = '_', //
22 - [16] = '_', //
23 - [17] = '_', //
24 - [18] = '_', //
25 - [19] = '_', //
26 - [20] = '_', //
27 - [21] = '_', //
28 - [22] = '_', //
29 - [23] = '_', //
30 - [24] = '_', //
31 - [25] = '_', //
32 - [26] = '_', //
33 - [27] = '_', //
34 - [28] = '_', //
35 - [29] = '_', //
36 - [30] = '_', //
37 - [31] = '_', //
38 - [32] = '_', //
39 - [33] = '_', // !
40 - [34] = '_', // "
41 - [35] = '_', // #
42 - [36] = '_', // $
43 - [37] = '_', // %
44 - [38] = '_', // &
45 - [39] = '_', // '
46 - [40] = '_', // (
47 - [41] = '_', // )
48 - [42] = '_', // *
49 - [43] = '_', // +
50 - [44] = '.', // ,
51 - [45] = '-', // -
52 - [46] = '.', // .
53 - [47] = '/', // /
54 - [48] = '0', // 0
55 - [49] = '1', // 1
56 - [50] = '2', // 2
57 - [51] = '3', // 3
58 - [52] = '4', // 4
59 - [53] = '5', // 5
60 - [54] = '6', // 6
61 - [55] = '7', // 7
62 - [56] = '8', // 8
63 - [57] = '9', // 9
64 - [58] = '_', // :
65 - [59] = '_', // ;
66 - [60] = '_', // <
67 - [61] = '_', // =
68 - [62] = '_', // >
69 - [63] = '_', // ?
70 - [64] = '_', // @
71 - [65] = 'a', // A
72 - [66] = 'b', // B
73 - [67] = 'c', // C
74 - [68] = 'd', // D
75 - [69] = 'e', // E
76 - [70] = 'f', // F
77 - [71] = 'g', // G
78 - [72] = 'h', // H
79 - [73] = 'i', // I
80 - [74] = 'j', // J
81 - [75] = 'k', // K
82 - [76] = 'l', // L
83 - [77] = 'm', // M
84 - [78] = 'n', // N
85 - [79] = 'o', // O
86 - [80] = 'p', // P
87 - [81] = 'q', // Q
88 - [82] = 'r', // R
89 - [83] = 's', // S
90 - [84] = 't', // T
91 - [85] = 'u', // U
92 - [86] = 'v', // V
93 - [87] = 'w', // W
94 - [88] = 'x', // X
95 - [89] = 'y', // Y
96 - [90] = 'z', // Z
97 - [91] = '_', // [
98 - [92] = '/', // backslash
99 - [93] = '_', // ]
100 - [94] = '_', // ^
101 - [95] = '_', // _
102 - [96] = '_', // `
103 - [97] = 'a', // a
104 - [98] = 'b', // b
105 - [99] = 'c', // c
106 - [100] = 'd', // d
107 - [101] = 'e', // e
108 - [102] = 'f', // f
109 - [103] = 'g', // g
110 - [104] = 'h', // h
111 - [105] = 'i', // i
112 - [106] = 'j', // j
113 - [107] = 'k', // k
114 - [108] = 'l', // l
115 - [109] = 'm', // m
116 - [110] = 'n', // n
117 - [111] = 'o', // o
118 - [112] = 'p', // p
119 - [113] = 'q', // q
120 - [114] = 'r', // r
121 - [115] = 's', // s
122 - [116] = 't', // t
123 - [117] = 'u', // u
124 - [118] = 'v', // v
125 - [119] = 'w', // w
126 - [120] = 'x', // x
127 - [121] = 'y', // y
128 - [122] = 'z', // z
129 - [123] = '_', // {
130 - [124] = '_', // |
131 - [125] = '_', // }
132 - [126] = '_', // ~
133 - [127] = '_', //
134 - [128] = '_', //
135 - [129] = '_', //
136 - [130] = '_', //
137 - [131] = '_', //
138 - [132] = '_', //
139 - [133] = '_', //
140 - [134] = '_', //
141 - [135] = '_', //
142 - [136] = '_', //
143 - [137] = '_', //
144 - [138] = '_', //
145 - [139] = '_', //
146 - [140] = '_', //
147 - [141] = '_', //
148 - [142] = '_', //
149 - [143] = '_', //
150 - [144] = '_', //
151 - [145] = '_', //
152 - [146] = '_', //
153 - [147] = '_', //
154 - [148] = '_', //
155 - [149] = '_', //
156 - [150] = '_', //
157 - [151] = '_', //
158 - [152] = '_', //
159 - [153] = '_', //
160 - [154] = '_', //
161 - [155] = '_', //
162 - [156] = '_', //
163 - [157] = '_', //
164 - [158] = '_', //
165 - [159] = '_', //
166 - [160] = '_', //
167 - [161] = '_', //
168 - [162] = '_', //
169 - [163] = '_', //
170 - [164] = '_', //
171 - [165] = '_', //
172 - [166] = '_', //
173 - [167] = '_', //
174 - [168] = '_', //
175 - [169] = '_', //
176 - [170] = '_', //
177 - [171] = '_', //
178 - [172] = '_', //
179 - [173] = '_', //
180 - [174] = '_', //
181 - [175] = '_', //
182 - [176] = '_', //
183 - [177] = '_', //
184 - [178] = '_', //
185 - [179] = '_', //
186 - [180] = '_', //
187 - [181] = '_', //
188 - [182] = '_', //
189 - [183] = '_', //
190 - [184] = '_', //
191 - [185] = '_', //
192 - [186] = '_', //
193 - [187] = '_', //
194 - [188] = '_', //
195 - [189] = '_', //
196 - [190] = '_', //
197 - [191] = '_', //
198 - [192] = '_', //
199 - [193] = '_', //
200 - [194] = '_', //
201 - [195] = '_', //
202 - [196] = '_', //
203 - [197] = '_', //
204 - [198] = '_', //
205 - [199] = '_', //
206 - [200] = '_', //
207 - [201] = '_', //
208 - [202] = '_', //
209 - [203] = '_', //
210 - [204] = '_', //
211 - [205] = '_', //
212 - [206] = '_', //
213 - [207] = '_', //
214 - [208] = '_', //
215 - [209] = '_', //
216 - [210] = '_', //
217 - [211] = '_', //
218 - [212] = '_', //
219 - [213] = '_', //
220 - [214] = '_', //
221 - [215] = '_', //
222 - [216] = '_', //
223 - [217] = '_', //
224 - [218] = '_', //
225 - [219] = '_', //
226 - [220] = '_', //
227 - [221] = '_', //
228 - [222] = '_', //
229 - [223] = '_', //
230 - [224] = '_', //
231 - [225] = '_', //
232 - [226] = '_', //
233 - [227] = '_', //
234 - [228] = '_', //
235 - [229] = '_', //
236 - [230] = '_', //
237 - [231] = '_', //
238 - [232] = '_', //
239 - [233] = '_', //
240 - [234] = '_', //
241 - [235] = '_', //
242 - [236] = '_', //
243 - [237] = '_', //
244 - [238] = '_', //
245 - [239] = '_', //
246 - [240] = '_', //
247 - [241] = '_', //
248 - [242] = '_', //
249 - [243] = '_', //
250 - [244] = '_', //
251 - [245] = '_', //
252 - [246] = '_', //
253 - [247] = '_', //
254 - [248] = '_', //
255 - [249] = '_', //
256 - [250] = '_', //
257 - [251] = '_', //
258 - [252] = '_', //
259 - [253] = '_', //
260 - [254] = '_', //
261 - [255] = '_' //
5 +/*
6 + * ! -> simple patterns negation (only when it is the first character)
7 + * " -> needs escaping when parsing
8 + * $ -> can be a shell variable (security in alarm-notify.sh)
9 + * % -> http GET encoded characters
10 + * & -> http GET fields separator
11 + * ' -> needs escaping when parsing
12 + * * -> simple pattern wildcard
13 + * + -> http GET space
14 + * , -> list separator (probably not used today)
15 + * = -> plugins.d protocol separator
16 + * ? -> http GET query string separator
17 + * @ -> hostname separator (on the UI)
18 + * ` -> bash expansion (security in alarm-notify.sh)
19 + * | -> list separator (simple patterns and http GET)
20 + */
21 +
22 +unsigned char chart_names_allowed_chars[256] = {
23 + [0] = '\0', [1] = ' ', [2] = ' ', [3] = ' ', [4] = ' ', [5] = ' ', [6] = ' ', [7] = ' ', [8] = ' ',
24 +
25 + // control characters to be treated as spaces
26 + ['\t'] = ' ', ['\n'] = ' ', ['\v'] = ' ', ['\f'] = ' ', ['\r'] = ' ',
27 +
28 + [14] = ' ', [15] = ' ', [16] = ' ', [17] = ' ', [18] = ' ', [19] = ' ', [20] = ' ', [21] = ' ',
29 + [22] = ' ', [23] = ' ', [24] = ' ', [25] = ' ', [26] = ' ', [27] = ' ', [28] = ' ', [29] = ' ',
30 + [30] = ' ', [31] = ' ',
31 +
32 + // symbols
33 + [' '] = ' ', ['!'] = '!', ['"'] = '_', ['#'] = '#', ['$'] = '_', ['%'] = '_', ['&'] = '_', ['\''] = '_',
34 + ['('] = '(', [')'] = ')', ['*'] = '_', ['+'] = '_', [','] = '.', ['-'] = '-', ['.'] = '.', ['/'] = '/',
35 +
36 + // numbers
37 + ['0'] = '0', ['1'] = '1', ['2'] = '2', ['3'] = '3', ['4'] = '4', ['5'] = '5', ['6'] = '6', ['7'] = '7',
38 + ['8'] = '8', ['9'] = '9',
39 +
40 + // symbols
41 + [':'] = ':', [';'] = ';', ['<'] = '<', ['='] = '_', ['>'] = '>', ['?'] = '_', ['@'] = '_',
42 +
43 + // capitals
44 + ['A'] = 'A', ['B'] = 'B', ['C'] = 'C', ['D'] = 'D', ['E'] = 'E', ['F'] = 'F', ['G'] = 'G', ['H'] = 'H',
45 + ['I'] = 'I', ['J'] = 'J', ['K'] = 'K', ['L'] = 'L', ['M'] = 'M', ['N'] = 'N', ['O'] = 'O', ['P'] = 'P',
46 + ['Q'] = 'Q', ['R'] = 'R', ['S'] = 'S', ['T'] = 'T', ['U'] = 'U', ['V'] = 'V', ['W'] = 'W', ['X'] = 'X',
47 + ['Y'] = 'Y', ['Z'] = 'Z',
48 +
49 + // symbols
50 + ['['] = '[', ['\\'] = '/', [']'] = ']', ['^'] = '_', ['_'] = '_', ['`'] = '_',
51 +
52 + // lower
53 + ['a'] = 'a', ['b'] = 'b', ['c'] = 'c', ['d'] = 'd', ['e'] = 'e', ['f'] = 'f', ['g'] = 'g', ['h'] = 'h',
54 + ['i'] = 'i', ['j'] = 'j', ['k'] = 'k', ['l'] = 'l', ['m'] = 'm', ['n'] = 'n', ['o'] = 'o', ['p'] = 'p',
55 + ['q'] = 'q', ['r'] = 'r', ['s'] = 's', ['t'] = 't', ['u'] = 'u', ['v'] = 'v', ['w'] = 'w', ['x'] = 'x',
56 + ['y'] = 'y', ['z'] = 'z',
57 +
58 + // symbols
59 + ['{'] = '{', ['|'] = '_', ['}'] = '}', ['~'] = '~',
60 +
61 + // rest
62 + [127] = ' ', [128] = ' ', [129] = ' ', [130] = ' ', [131] = ' ', [132] = ' ', [133] = ' ', [134] = ' ',
63 + [135] = ' ', [136] = ' ', [137] = ' ', [138] = ' ', [139] = ' ', [140] = ' ', [141] = ' ', [142] = ' ',
64 + [143] = ' ', [144] = ' ', [145] = ' ', [146] = ' ', [147] = ' ', [148] = ' ', [149] = ' ', [150] = ' ',
65 + [151] = ' ', [152] = ' ', [153] = ' ', [154] = ' ', [155] = ' ', [156] = ' ', [157] = ' ', [158] = ' ',
66 + [159] = ' ', [160] = ' ', [161] = ' ', [162] = ' ', [163] = ' ', [164] = ' ', [165] = ' ', [166] = ' ',
67 + [167] = ' ', [168] = ' ', [169] = ' ', [170] = ' ', [171] = ' ', [172] = ' ', [173] = ' ', [174] = ' ',
68 + [175] = ' ', [176] = ' ', [177] = ' ', [178] = ' ', [179] = ' ', [180] = ' ', [181] = ' ', [182] = ' ',
69 + [183] = ' ', [184] = ' ', [185] = ' ', [186] = ' ', [187] = ' ', [188] = ' ', [189] = ' ', [190] = ' ',
70 + [191] = ' ', [192] = ' ', [193] = ' ', [194] = ' ', [195] = ' ', [196] = ' ', [197] = ' ', [198] = ' ',
71 + [199] = ' ', [200] = ' ', [201] = ' ', [202] = ' ', [203] = ' ', [204] = ' ', [205] = ' ', [206] = ' ',
72 + [207] = ' ', [208] = ' ', [209] = ' ', [210] = ' ', [211] = ' ', [212] = ' ', [213] = ' ', [214] = ' ',
73 + [215] = ' ', [216] = ' ', [217] = ' ', [218] = ' ', [219] = ' ', [220] = ' ', [221] = ' ', [222] = ' ',
74 + [223] = ' ', [224] = ' ', [225] = ' ', [226] = ' ', [227] = ' ', [228] = ' ', [229] = ' ', [230] = ' ',
75 + [231] = ' ', [232] = ' ', [233] = ' ', [234] = ' ', [235] = ' ', [236] = ' ', [237] = ' ', [238] = ' ',
76 + [239] = ' ', [240] = ' ', [241] = ' ', [242] = ' ', [243] = ' ', [244] = ' ', [245] = ' ', [246] = ' ',
77 + [247] = ' ', [248] = ' ', [249] = ' ', [250] = ' ', [251] = ' ', [252] = ' ', [253] = ' ', [254] = ' ',
78 + [255] = ' '
79 };
80
81 +static inline void sanitize_chart_name(char *dst, const char *src, size_t dst_size) {
82 + // text_sanitize deduplicates spaces
83 + text_sanitize((unsigned char *)dst, (const unsigned char *)src, dst_size,
84 + chart_names_allowed_chars, true, "", NULL);
85 +
86 + char *d = dst;
87 +
88 + // do not accept ! as the first character
89 + if(*d == '!') *d = '_';
90 +
91 + // convert remaining spaces to underscores
92 + while(*d) {
93 + if(*d == ' ') *d = '_';
94 + d++;
95 + }
96 +}
97 +
98 // make sure the supplied string
99 // is good for a netdata chart/dimension ID/NAME
100 void netdata_fix_chart_name(char *s) {
267 - while ((*s = netdata_map_chart_names[(uint8_t)*s])) s++;
101 + sanitize_chart_name(s, s, strlen(s) + 1);
102 }
103
270 -static uint8_t netdata_map_chart_ids[256] = {
271 - [0] = '\0', //
272 - [1] = '_', //
273 - [2] = '_', //
274 - [3] = '_', //
275 - [4] = '_', //
276 - [5] = '_', //
277 - [6] = '_', //
278 - [7] = '_', //
279 - [8] = '_', //
280 - [9] = '_', //
281 - [10] = '_', //
282 - [11] = '_', //
283 - [12] = '_', //
284 - [13] = '_', //
285 - [14] = '_', //
286 - [15] = '_', //
287 - [16] = '_', //
288 - [17] = '_', //
289 - [18] = '_', //
290 - [19] = '_', //
291 - [20] = '_', //
292 - [21] = '_', //
293 - [22] = '_', //
294 - [23] = '_', //
295 - [24] = '_', //
296 - [25] = '_', //
297 - [26] = '_', //
298 - [27] = '_', //
299 - [28] = '_', //
300 - [29] = '_', //
301 - [30] = '_', //
302 - [31] = '_', //
303 - [32] = '_', //
304 - [33] = '_', // !
305 - [34] = '_', // "
306 - [35] = '_', // #
307 - [36] = '_', // $
308 - [37] = '_', // %
309 - [38] = '_', // &
310 - [39] = '_', // '
311 - [40] = '_', // (
312 - [41] = '_', // )
313 - [42] = '_', // *
314 - [43] = '_', // +
315 - [44] = '.', // ,
316 - [45] = '-', // -
317 - [46] = '.', // .
318 - [47] = '_', // /
319 - [48] = '0', // 0
320 - [49] = '1', // 1
321 - [50] = '2', // 2
322 - [51] = '3', // 3
323 - [52] = '4', // 4
324 - [53] = '5', // 5
325 - [54] = '6', // 6
326 - [55] = '7', // 7
327 - [56] = '8', // 8
328 - [57] = '9', // 9
329 - [58] = '_', // :
330 - [59] = '_', // ;
331 - [60] = '_', // <
332 - [61] = '_', // =
333 - [62] = '_', // >
334 - [63] = '_', // ?
335 - [64] = '_', // @
336 - [65] = 'a', // A
337 - [66] = 'b', // B
338 - [67] = 'c', // C
339 - [68] = 'd', // D
340 - [69] = 'e', // E
341 - [70] = 'f', // F
342 - [71] = 'g', // G
343 - [72] = 'h', // H
344 - [73] = 'i', // I
345 - [74] = 'j', // J
346 - [75] = 'k', // K
347 - [76] = 'l', // L
348 - [77] = 'm', // M
349 - [78] = 'n', // N
350 - [79] = 'o', // O
351 - [80] = 'p', // P
352 - [81] = 'q', // Q
353 - [82] = 'r', // R
354 - [83] = 's', // S
355 - [84] = 't', // T
356 - [85] = 'u', // U
357 - [86] = 'v', // V
358 - [87] = 'w', // W
359 - [88] = 'x', // X
360 - [89] = 'y', // Y
361 - [90] = 'z', // Z
362 - [91] = '_', // [
363 - [92] = '_', // backslash
364 - [93] = '_', // ]
365 - [94] = '_', // ^
366 - [95] = '_', // _
367 - [96] = '_', // `
368 - [97] = 'a', // a
369 - [98] = 'b', // b
370 - [99] = 'c', // c
371 - [100] = 'd', // d
372 - [101] = 'e', // e
373 - [102] = 'f', // f
374 - [103] = 'g', // g
375 - [104] = 'h', // h
376 - [105] = 'i', // i
377 - [106] = 'j', // j
378 - [107] = 'k', // k
379 - [108] = 'l', // l
380 - [109] = 'm', // m
381 - [110] = 'n', // n
382 - [111] = 'o', // o
383 - [112] = 'p', // p
384 - [113] = 'q', // q
385 - [114] = 'r', // r
386 - [115] = 's', // s
387 - [116] = 't', // t
388 - [117] = 'u', // u
389 - [118] = 'v', // v
390 - [119] = 'w', // w
391 - [120] = 'x', // x
392 - [121] = 'y', // y
393 - [122] = 'z', // z
394 - [123] = '_', // {
395 - [124] = '_', // |
396 - [125] = '_', // }
397 - [126] = '_', // ~
398 - [127] = '_', //
399 - [128] = '_', //
400 - [129] = '_', //
401 - [130] = '_', //
402 - [131] = '_', //
403 - [132] = '_', //
404 - [133] = '_', //
405 - [134] = '_', //
406 - [135] = '_', //
407 - [136] = '_', //
408 - [137] = '_', //
409 - [138] = '_', //
410 - [139] = '_', //
411 - [140] = '_', //
412 - [141] = '_', //
413 - [142] = '_', //
414 - [143] = '_', //
415 - [144] = '_', //
416 - [145] = '_', //
417 - [146] = '_', //
418 - [147] = '_', //
419 - [148] = '_', //
420 - [149] = '_', //
421 - [150] = '_', //
422 - [151] = '_', //
423 - [152] = '_', //
424 - [153] = '_', //
425 - [154] = '_', //
426 - [155] = '_', //
427 - [156] = '_', //
428 - [157] = '_', //
429 - [158] = '_', //
430 - [159] = '_', //
431 - [160] = '_', //
432 - [161] = '_', //
433 - [162] = '_', //
434 - [163] = '_', //
435 - [164] = '_', //
436 - [165] = '_', //
437 - [166] = '_', //
438 - [167] = '_', //
439 - [168] = '_', //
440 - [169] = '_', //
441 - [170] = '_', //
442 - [171] = '_', //
443 - [172] = '_', //
444 - [173] = '_', //
445 - [174] = '_', //
446 - [175] = '_', //
447 - [176] = '_', //
448 - [177] = '_', //
449 - [178] = '_', //
450 - [179] = '_', //
451 - [180] = '_', //
452 - [181] = '_', //
453 - [182] = '_', //
454 - [183] = '_', //
455 - [184] = '_', //
456 - [185] = '_', //
457 - [186] = '_', //
458 - [187] = '_', //
459 - [188] = '_', //
460 - [189] = '_', //
461 - [190] = '_', //
462 - [191] = '_', //
463 - [192] = '_', //
464 - [193] = '_', //
465 - [194] = '_', //
466 - [195] = '_', //
467 - [196] = '_', //
468 - [197] = '_', //
469 - [198] = '_', //
470 - [199] = '_', //
471 - [200] = '_', //
472 - [201] = '_', //
473 - [202] = '_', //
474 - [203] = '_', //
475 - [204] = '_', //
476 - [205] = '_', //
477 - [206] = '_', //
478 - [207] = '_', //
479 - [208] = '_', //
480 - [209] = '_', //
481 - [210] = '_', //
482 - [211] = '_', //
483 - [212] = '_', //
484 - [213] = '_', //
485 - [214] = '_', //
486 - [215] = '_', //
487 - [216] = '_', //
488 - [217] = '_', //
489 - [218] = '_', //
490 - [219] = '_', //
491 - [220] = '_', //
492 - [221] = '_', //
493 - [222] = '_', //
494 - [223] = '_', //
495 - [224] = '_', //
496 - [225] = '_', //
497 - [226] = '_', //
498 - [227] = '_', //
499 - [228] = '_', //
500 - [229] = '_', //
501 - [230] = '_', //
502 - [231] = '_', //
503 - [232] = '_', //
504 - [233] = '_', //
505 - [234] = '_', //
506 - [235] = '_', //
507 - [236] = '_', //
508 - [237] = '_', //
509 - [238] = '_', //
510 - [239] = '_', //
511 - [240] = '_', //
512 - [241] = '_', //
513 - [242] = '_', //
514 - [243] = '_', //
515 - [244] = '_', //
516 - [245] = '_', //
517 - [246] = '_', //
518 - [247] = '_', //
519 - [248] = '_', //
520 - [249] = '_', //
521 - [250] = '_', //
522 - [251] = '_', //
523 - [252] = '_', //
524 - [253] = '_', //
525 - [254] = '_', //
526 - [255] = '_' //
527 -};
528 -
529 -// make sure the supplied string
530 -// is good for a netdata chart/dimension ID/NAME
104 void netdata_fix_chart_id(char *s) {
532 - while ((*s = netdata_map_chart_ids[(uint8_t) *s])) s++;
105 + sanitize_chart_name(s, s, strlen(s) + 1);
106 +// size_t len = strlen(s);
107 +// char buf[len + 1];
108 +//
109 +// text_sanitize((unsigned char *)buf, (const unsigned char *)s, sizeof(buf),
110 +// chart_names_allowed_chars, true, "", NULL);
111 +//
112 +// if(memcmp(s, buf, sizeof(buf)) == 0)
113 +// // they are the same
114 +// return;
115 +//
116 +// // they differ
117 +// XXH128_hash_t hash = XXH3_128bits(s, len);
118 +// ND_UUID *uuid = (ND_UUID *)&hash;
119 +// internal_fatal(sizeof(hash) != sizeof(ND_UUID), "XXH128 and ND_UUID do not have the same size");
120 +// buf[0] = 'x';
121 +// buf[1] = 'x';
122 +// buf[2] = 'h';
123 +// buf[3] = '_';
124 +// uuid_unparse_lower_compact(uuid->uuid, &buf[4]);
125 +}
126 +
127 +char *rrdset_strncpyz_name(char *dst, const char *src, size_t dst_size_minus_1) {
128 + // src starts with "type."
129 + sanitize_chart_name(dst, src, dst_size_minus_1 + 1);
130 + return dst;
131 +}
132 +
133 +bool rrdvar_fix_name(char *variable) {
134 + size_t len = strlen(variable);
135 + char buf[len + 1];
136 + memcpy(buf, variable, sizeof(buf));
137 + sanitize_chart_name(variable, variable, len + 1);
138 + return memcmp(buf, variable, sizeof(buf)) != 0;
139 }
src/libnetdata/sanitizers/chart_id_and_name.h
+7
@@ -7,5 +7,12 @@
7
8 void netdata_fix_chart_id(char *s);
9 void netdata_fix_chart_name(char *s);
10 +char *rrdset_strncpyz_name(char *dst, const char *src, size_t dst_size_minus_1);
11 +bool rrdvar_fix_name(char *variable);
12 +
13 +extern unsigned char chart_names_allowed_chars[256];
14 +static inline bool is_netdata_api_valid_character(char c) {
15 + return (IS_UTF8_BYTE(c) || chart_names_allowed_chars[(unsigned char)c] == (unsigned char)c);
16 +}
17
18 #endif //NETDATA_CHART_ID_AND_NAME_H