| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "sanitizers-labels.h" |
| 4 | |
| 5 | /* |
| 6 | * All labels follow these rules: |
| 7 | * |
| 8 | * Character Symbol Names Values |
| 9 | * UTF-8 characters UTF-8 -> _ yes |
| 10 | * Lower case letter [a-z] yes yes |
| 11 | * Upper case letter [A-Z] yes yes |
| 12 | * Digit [0-9] yes yes |
| 13 | * Underscore _ yes yes |
| 14 | * Minus - yes yes |
| 15 | * Plus + -> _ yes |
| 16 | * Colon : -> _ yes |
| 17 | * Semicolon ; -> _ -> : |
| 18 | * Equal = -> _ -> : |
| 19 | * Period . yes yes |
| 20 | * Comma , -> . -> . |
| 21 | * Slash / yes yes |
| 22 | * Backslash \ -> / -> / |
| 23 | * At @ -> _ yes |
| 24 | * Space -> _ yes |
| 25 | * Opening parenthesis ( -> _ yes |
| 26 | * Closing parenthesis ) -> _ yes |
| 27 | * anything else -> _ -> space |
| 28 | * |
| 29 | * The above rules should allow users to set in tags (indicative): |
| 30 | * |
| 31 | * 1. hostnames and domain names as-is |
| 32 | * 2. email addresses as-is |
| 33 | * 3. floating point numbers, converted to always use a dot as the decimal point |
| 34 | * |
| 35 | * Leading and trailing spaces and control characters are removed from both label |
| 36 | * names and values. |
| 37 | * |
| 38 | * Multiple spaces inside the label name or the value are removed (only 1 is retained). |
| 39 | * In names spaces are also converted to underscores. |
| 40 | * |
| 41 | * Names that are only underscores are rejected (they do not enter the dictionary). |
| 42 | * |
| 43 | * The above rules do not require any conversion to be included in JSON strings. |
| 44 | * |
| 45 | * Label names and values are truncated to LABELS_MAX_LENGTH (200) characters. |
| 46 | * |
| 47 | * When parsing, label key and value are separated by the first colon (:) found. |
| 48 | * So label:value1:value2 is parsed as key = "label", value = "value1:value2" |
| 49 | * |
| 50 | * This means a label key cannot contain a colon (:) - it is converted to |
| 51 | * underscore if it does. |
| 52 | * |
| 53 | */ |
| 54 | |
| 55 | static unsigned char prometheus_label_names_char_map[256]; |
| 56 | static unsigned char label_names_char_map[256]; |
| 57 | static unsigned char label_values_char_map[256] = { |
| 58 | [0] = '\0', [1] = ' ', [2] = ' ', [3] = ' ', [4] = ' ', [5] = ' ', [6] = ' ', [7] = ' ', [8] = ' ', |
| 59 | |
| 60 | // control characters to be treated as spaces |
| 61 | ['\t'] = ' ', ['\n'] = ' ', ['\v'] = ' ', ['\f'] = ' ', ['\r'] = ' ', |
| 62 | |
| 63 | [14] = ' ', [15] = ' ', [16] = ' ', [17] = ' ', [18] = ' ', [19] = ' ', [20] = ' ', [21] = ' ', |
| 64 | [22] = ' ', [23] = ' ', [24] = ' ', [25] = ' ', [26] = ' ', [27] = ' ', [28] = ' ', [29] = ' ', |
| 65 | [30] = ' ', [31] = ' ', |
| 66 | |
| 67 | // symbols |
| 68 | [' '] = ' ', ['!'] = '_', ['"'] = '_', ['#'] = '_', ['$'] = '_', ['%'] = '_', ['&'] = '_', ['\''] = '_', |
| 69 | ['('] = '(', [')'] = ')', ['*'] = '_', ['+'] = '+', [','] = '.', ['-'] = '-', ['.'] = '.', ['/'] = '/', |
| 70 | |
| 71 | // numbers |
| 72 | ['0'] = '0', ['1'] = '1', ['2'] = '2', ['3'] = '3', ['4'] = '4', ['5'] = '5', ['6'] = '6', ['7'] = '7', |
| 73 | ['8'] = '8', ['9'] = '9', |
| 74 | |
| 75 | // symbols |
| 76 | [':'] = ':', [';'] = ':', ['<'] = '_', ['='] = ':', ['>'] = '_', ['?'] = '_', ['@'] = '@', |
| 77 | |
| 78 | // capitals |
| 79 | ['A'] = 'A', ['B'] = 'B', ['C'] = 'C', ['D'] = 'D', ['E'] = 'E', ['F'] = 'F', ['G'] = 'G', ['H'] = 'H', |
| 80 | ['I'] = 'I', ['J'] = 'J', ['K'] = 'K', ['L'] = 'L', ['M'] = 'M', ['N'] = 'N', ['O'] = 'O', ['P'] = 'P', |
| 81 | ['Q'] = 'Q', ['R'] = 'R', ['S'] = 'S', ['T'] = 'T', ['U'] = 'U', ['V'] = 'V', ['W'] = 'W', ['X'] = 'X', |
| 82 | ['Y'] = 'Y', ['Z'] = 'Z', |
| 83 | |
| 84 | // symbols |
| 85 | ['['] = '[', ['\\'] = '/', [']'] = ']', ['^'] = '_', ['_'] = '_', ['`'] = '_', |
| 86 | |
| 87 | // lower |
| 88 | ['a'] = 'a', ['b'] = 'b', ['c'] = 'c', ['d'] = 'd', ['e'] = 'e', ['f'] = 'f', ['g'] = 'g', ['h'] = 'h', |
| 89 | ['i'] = 'i', ['j'] = 'j', ['k'] = 'k', ['l'] = 'l', ['m'] = 'm', ['n'] = 'n', ['o'] = 'o', ['p'] = 'p', |
| 90 | ['q'] = 'q', ['r'] = 'r', ['s'] = 's', ['t'] = 't', ['u'] = 'u', ['v'] = 'v', ['w'] = 'w', ['x'] = 'x', |
| 91 | ['y'] = 'y', ['z'] = 'z', |
| 92 | |
| 93 | // symbols |
| 94 | ['{'] = '_', ['|'] = '_', ['}'] = '_', ['~'] = '_', |
| 95 | |
| 96 | // rest |
| 97 | [127] = ' ', [128] = ' ', [129] = ' ', [130] = ' ', [131] = ' ', [132] = ' ', [133] = ' ', [134] = ' ', |
| 98 | [135] = ' ', [136] = ' ', [137] = ' ', [138] = ' ', [139] = ' ', [140] = ' ', [141] = ' ', [142] = ' ', |
| 99 | [143] = ' ', [144] = ' ', [145] = ' ', [146] = ' ', [147] = ' ', [148] = ' ', [149] = ' ', [150] = ' ', |
| 100 | [151] = ' ', [152] = ' ', [153] = ' ', [154] = ' ', [155] = ' ', [156] = ' ', [157] = ' ', [158] = ' ', |
| 101 | [159] = ' ', [160] = ' ', [161] = ' ', [162] = ' ', [163] = ' ', [164] = ' ', [165] = ' ', [166] = ' ', |
| 102 | [167] = ' ', [168] = ' ', [169] = ' ', [170] = ' ', [171] = ' ', [172] = ' ', [173] = ' ', [174] = ' ', |
| 103 | [175] = ' ', [176] = ' ', [177] = ' ', [178] = ' ', [179] = ' ', [180] = ' ', [181] = ' ', [182] = ' ', |
| 104 | [183] = ' ', [184] = ' ', [185] = ' ', [186] = ' ', [187] = ' ', [188] = ' ', [189] = ' ', [190] = ' ', |
| 105 | [191] = ' ', [192] = ' ', [193] = ' ', [194] = ' ', [195] = ' ', [196] = ' ', [197] = ' ', [198] = ' ', |
| 106 | [199] = ' ', [200] = ' ', [201] = ' ', [202] = ' ', [203] = ' ', [204] = ' ', [205] = ' ', [206] = ' ', |
| 107 | [207] = ' ', [208] = ' ', [209] = ' ', [210] = ' ', [211] = ' ', [212] = ' ', [213] = ' ', [214] = ' ', |
| 108 | [215] = ' ', [216] = ' ', [217] = ' ', [218] = ' ', [219] = ' ', [220] = ' ', [221] = ' ', [222] = ' ', |
| 109 | [223] = ' ', [224] = ' ', [225] = ' ', [226] = ' ', [227] = ' ', [228] = ' ', [229] = ' ', [230] = ' ', |
| 110 | [231] = ' ', [232] = ' ', [233] = ' ', [234] = ' ', [235] = ' ', [236] = ' ', [237] = ' ', [238] = ' ', |
| 111 | [239] = ' ', [240] = ' ', [241] = ' ', [242] = ' ', [243] = ' ', [244] = ' ', [245] = ' ', [246] = ' ', |
| 112 | [247] = ' ', [248] = ' ', [249] = ' ', [250] = ' ', [251] = ' ', [252] = ' ', [253] = ' ', [254] = ' ', |
| 113 | [255] = ' ' |
| 114 | }; |
| 115 | |
| 116 | __attribute__((constructor)) void initialize_labels_keys_char_map(void) { |
| 117 | // copy the values char map to the names char map |
| 118 | size_t i; |
| 119 | for(i = 0; i < 256 ;i++) |
| 120 | label_names_char_map[i] = label_values_char_map[i]; |
| 121 | |
| 122 | // apply overrides to the label names map |
| 123 | label_names_char_map['='] = '_'; |
| 124 | label_names_char_map[':'] = '_'; |
| 125 | label_names_char_map['+'] = '_'; |
| 126 | label_names_char_map[';'] = '_'; |
| 127 | label_names_char_map['@'] = '_'; |
| 128 | label_names_char_map['('] = '_'; |
| 129 | label_names_char_map[')'] = '_'; |
| 130 | label_names_char_map['\\'] = '/'; |
| 131 | |
| 132 | // prometheus label names |
| 133 | for(i = 0; i < 256 ;i++) prometheus_label_names_char_map[i] = '_'; |
| 134 | for(int s = 'A' ; s <= 'Z' ; s++) prometheus_label_names_char_map[s] = s; |
| 135 | for(int s = 'a' ; s <= 'z' ; s++) prometheus_label_names_char_map[s] = s; |
| 136 | for(int s = '0' ; s <= '9' ; s++) prometheus_label_names_char_map[s] = s; |
| 137 | prometheus_label_names_char_map[0] = '\0'; |
| 138 | prometheus_label_names_char_map[':'] = ':'; |
| 139 | prometheus_label_names_char_map['_'] = '_'; |
| 140 | } |
| 141 | |
| 142 | size_t rrdlabels_sanitize_name(char *dst, const char *src, size_t dst_size) { |
| 143 | size_t rc = text_sanitize((unsigned char *)dst, (const unsigned char *)src, dst_size, label_names_char_map, 0, "", NULL); |
| 144 | |
| 145 | for(size_t i = 0; i < rc ; i++) |
| 146 | if(dst[i] == ' ') dst[i] = '_'; |
| 147 | |
| 148 | return rc; |
| 149 | } |
| 150 | |
| 151 | size_t rrdlabels_sanitize_value(char *dst, const char *src, size_t dst_size) { |
| 152 | return text_sanitize((unsigned char *)dst, (const unsigned char *)src, dst_size, label_values_char_map, 1, "[none]", NULL); |
| 153 | } |
| 154 | |
| 155 | size_t prometheus_rrdlabels_sanitize_name(char *dst, const char *src, size_t dst_size) { |
| 156 | return text_sanitize((unsigned char *)dst, (const unsigned char *)src, dst_size, prometheus_label_names_char_map, 0, "", NULL); |
| 157 | } |