hostnames: convert to utf8 and santitize (#19418)
* hostnames: convert to utf8 and santitize * add windows version of the hostname * fix warnings on windows * fix freebsd * disable iconv on posix systems
Costa Tsaousis committed
Jan 16, 2025 at 19:59 UTC
06c16139f8a57d05d9bd60e65baca6feea6438c4
10 files changed
+199
-21
CMakeLists.txt
+2
@@ -987,6 +987,8 @@ set(LIBNETDATA_FILES
987
src/libnetdata/memory/alignment.h
988
src/libnetdata/os/get_system_pagesize.c
989
src/libnetdata/os/get_system_pagesize.h
990
+ src/libnetdata/os/hostname.c
991
+ src/libnetdata/os/hostname.h
992
)
993
994
set(LIBH2O_FILES
packaging/cmake/config.cmake.h.in
+1
@@ -68,6 +68,7 @@
68
#cmakedefine HAVE_SETENV
69
#cmakedefine HAVE_DLSYM
70
#cmakedefine HAVE_LIBCURL
71
+#cmakedefine HAVE_LIBICONV
72
73
#cmakedefine HAVE_ARC4RANDOM_BUF
74
#cmakedefine HAVE_ARC4RANDOM_UNIFORM
src/daemon/config/netdata-conf-global.c
+2
-18
@@ -40,22 +40,6 @@ skip:
40
return processors;
41
}
42
43
-static int get_hostname(char *buf, size_t buf_size) {
44
- if (netdata_configured_host_prefix && *netdata_configured_host_prefix) {
45
- char filename[FILENAME_MAX + 1];
46
- snprintfz(filename, FILENAME_MAX, "%s/etc/hostname", netdata_configured_host_prefix);
47
-
48
- if (!read_txt_file(filename, buf, buf_size)) {
49
- trim(buf);
50
- return 0;
51
- }
52
- }
53
-
54
- int rc = gethostname(buf, buf_size);
55
- buf[buf_size - 1] = '\0';
56
- return rc;
57
-}
58
-
43
void netdata_conf_glibc_malloc_initialize(size_t wanted_arenas, size_t trim_threshold __maybe_unused) {
44
wanted_arenas = config_get_number(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for plugins", wanted_arenas);
45
if(wanted_arenas < 1 || wanted_arenas > os_get_system_cpus_cached(true)) {
@@ -119,8 +103,8 @@ void netdata_conf_section_global(void) {
103
netdata_configured_host_prefix = config_get(CONFIG_SECTION_GLOBAL, "host access prefix", "");
104
(void) verify_netdata_host_prefix(true);
105
122
- char buf[HOSTNAME_MAX + 1];
123
- if (get_hostname(buf, sizeof(buf)))
106
+ char buf[HOST_NAME_MAX * 4 + 1];
107
+ if (!os_hostname(buf, sizeof(buf), netdata_configured_host_prefix))
108
netdata_log_error("Cannot get machine hostname.");
109
110
netdata_configured_hostname = config_get(CONFIG_SECTION_GLOBAL, "hostname", buf);
src/daemon/pulse/pulse-daemon-memory-system.c
+1
-1
@@ -107,7 +107,7 @@ cleanup:
107
}
108
#endif // HAVE_C_MALLOC_INFO
109
110
-void pulse_daemon_memory_system_do(bool extended) {
110
+void pulse_daemon_memory_system_do(bool extended __maybe_unused) {
111
112
#ifdef HAVE_C_MALLOC_INFO
113
size_t glibc_arenas, glibc_allocated_arenas, glibc_unused_fast, glibc_unused_rest, glibc_allocated_mmap;
src/database/rrdlabels.c
+4
@@ -1577,6 +1577,10 @@ int rrdlabels_unittest_sanitization() {
1577
const unsigned char invalid5[] = "app.clewd修改\xe7\x89_fd_open_limits";
1578
errors += rrdlabels_unittest_sanitize_value((const char *)invalid5, "app.clewd修改e789_fd_open_limits");
1579
1580
+ // invalid UTF8 No 6
1581
+ const unsigned char invalid6[] = "\260\327\312\300\322\242";
1582
+ errors += rrdlabels_unittest_sanitize_value((const char *)invalid6, "d7cac0Ң");
1583
+
1584
return errors;
1585
}
1586
src/libnetdata/common.h
+6
@@ -400,6 +400,12 @@ typedef uint32_t uid_t;
400
401
// --------------------------------------------------------------------------------------------------------------------
402
403
+#ifndef HOST_NAME_MAX
404
+#define HOST_NAME_MAX 256
405
+#endif
406
+
407
+// --------------------------------------------------------------------------------------------------------------------
408
+
409
#if defined(OS_WINDOWS)
410
#include <windows.h>
411
#include <wctype.h>
src/libnetdata/os/hostname.c
new
+161
@@ -0,0 +1,161 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "libnetdata/libnetdata.h"
4
+
5
+#if defined(OS_WINDOWS)
6
+bool os_hostname(char *dst, size_t dst_size, const char *filesystem_root __maybe_unused) {
7
+ WCHAR wbuf[HOST_NAME_MAX * 4 + 1];
8
+ char buf[HOST_NAME_MAX * 4 + 1];
9
+ DWORD size = _countof(wbuf);
10
+ bool success = false;
11
+
12
+ // First try DNS hostname
13
+ if (GetComputerNameExW(ComputerNameDnsHostname, wbuf, &size)) {
14
+ success = true;
15
+ }
16
+ // Then try NetBIOS name
17
+ else {
18
+ size = _countof(wbuf);
19
+ if (GetComputerNameW(wbuf, &size)) {
20
+ success = true;
21
+ }
22
+ }
23
+
24
+ if (success) {
25
+ // Convert UTF-16 to UTF-8
26
+ int utf8_size = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL, NULL);
27
+ if (utf8_size > 0 && utf8_size <= (int)sizeof(buf)) {
28
+ WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, utf8_size, NULL, NULL);
29
+ }
30
+ else {
31
+ success = false;
32
+ }
33
+ }
34
+
35
+ if (!success) {
36
+ // Try getting the machine GUID first
37
+ HKEY hKey;
38
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
39
+ WCHAR guidW[64];
40
+ DWORD guidSize = sizeof(guidW);
41
+ DWORD type = REG_SZ;
42
+
43
+ if (RegQueryValueExW(hKey, L"MachineGuid", NULL, &type, (LPBYTE)guidW, &guidSize) == ERROR_SUCCESS) {
44
+ // Convert GUID to UTF-8
45
+ if (WideCharToMultiByte(CP_UTF8, 0, guidW, -1, buf, sizeof(buf), NULL, NULL) > 0) {
46
+ success = true;
47
+ }
48
+ }
49
+ RegCloseKey(hKey);
50
+ }
51
+
52
+ if (!success) {
53
+ // If machine GUID fails, try getting volume serial number of C: drive
54
+ WCHAR rootPath[] = L"C:\\";
55
+ DWORD serialNumber;
56
+ if (GetVolumeInformationW(rootPath, NULL, 0, &serialNumber, NULL, NULL, NULL, 0)) {
57
+ snprintf(buf, sizeof(buf), "host%08lx", (long unsigned)serialNumber);
58
+ success = true;
59
+ }
60
+ else {
61
+ // Last resort: use process ID
62
+ snprintf(buf, sizeof(buf), "host%lu", (long unsigned)GetCurrentProcessId());
63
+ }
64
+ }
65
+ }
66
+
67
+ char *hostname = trim(buf);
68
+ rrdlabels_sanitize_value(dst, hostname, dst_size);
69
+ return *dst != '\0';
70
+}
71
+#else // !OS_WINDOWS
72
+
73
+#ifdef HAVE_LIBICONV
74
+#include <iconv.h>
75
+
76
+static const char *get_current_locale(void) {
77
+ const char *locale = getenv("LC_ALL"); // LC_ALL overrides all other locale settings
78
+
79
+ if (!locale || !*locale) {
80
+ locale = getenv("LC_CTYPE"); // Check LC_CTYPE for character encoding
81
+
82
+ if (!locale || !*locale)
83
+ locale = getenv("LANG"); // Fallback to LANG
84
+ }
85
+
86
+ return locale;
87
+}
88
+
89
+static const char *get_encoding_from_locale(const char *locale) {
90
+ if(!locale || !*locale)
91
+ return NULL;
92
+
93
+ const char *dot = strchr(locale, '.');
94
+ if (dot)
95
+ return dot + 1;
96
+
97
+ return locale;
98
+}
99
+
100
+// Function to convert from a source encoding to UTF-8
101
+static bool iconv_convert_to_utf8(const char *input, const char *src_encoding, char *output, size_t output_size) {
102
+ iconv_t cd = iconv_open("UTF-8", src_encoding);
103
+ if (cd == (iconv_t)-1) {
104
+ int i = errno;
105
+ return false;
106
+ }
107
+
108
+ char *input_ptr = (char *)input; // iconv() may modify this pointer
109
+ char *output_ptr = output; // iconv() modifies this pointer
110
+ size_t input_len = strlen(input);
111
+ size_t output_len = output_size;
112
+
113
+ // Perform the conversion
114
+ if (iconv(cd, &input_ptr, &input_len, &output_ptr, &output_len) == (size_t)-1) {
115
+ iconv_close(cd);
116
+ return false;
117
+ }
118
+
119
+ // Null-terminate the output string
120
+ *output_ptr = '\0';
121
+
122
+ iconv_close(cd);
123
+ return true;
124
+}
125
+#endif
126
+
127
+bool os_hostname(char *dst, size_t dst_size, const char *filesystem_root) {
128
+ *dst = '\0';
129
+
130
+ char buf[HOST_NAME_MAX * 4 + 1];
131
+ *buf = '\0';
132
+
133
+ if (filesystem_root && *filesystem_root) {
134
+ char filename[FILENAME_MAX + 1];
135
+ snprintfz(filename, FILENAME_MAX, "%s/etc/hostname", netdata_configured_host_prefix);
136
+
137
+ if (read_txt_file(filename, buf, sizeof(buf)))
138
+ *buf = '\0';
139
+ }
140
+
141
+ if(!*buf && gethostname(buf, sizeof(buf)) != 0)
142
+ snprintf(buf, sizeof(buf), "host%ld", gethostid());
143
+
144
+ char *original_hostname = trim(buf);
145
+
146
+#ifdef HAVE_LIBICONV
147
+ const char *locale = get_current_locale();
148
+ if (locale && *locale) {
149
+ char utf8_output[HOST_NAME_MAX * 4 + 1] = "";
150
+ if(iconv_convert_to_utf8(original_hostname, get_encoding_from_locale(locale), utf8_output, sizeof(utf8_output))) {
151
+ rrdlabels_sanitize_value(dst, trim(utf8_output), dst_size);
152
+ return *dst != '\0';
153
+ }
154
+ }
155
+#endif
156
+
157
+ rrdlabels_sanitize_value(dst, original_hostname, dst_size);
158
+ return *dst != '\0';
159
+}
160
+
161
+#endif // !OS_WINDOWS
src/libnetdata/os/hostname.h
new
+21
@@ -0,0 +1,21 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_HOSTNAME_H
4
+#define NETDATA_HOSTNAME_H
5
+
6
+#include "libnetdata/libnetdata.h"
7
+
8
+/**
9
+ * Get system hostname in UTF-8 encoding
10
+ *
11
+ * @param dst Buffer to store the hostname
12
+ * @param dst_size Size of the destination buffer
13
+ * @param filesystem_root Optional root directory (for Unix-like systems, when running in a container)
14
+ * @return true on success, false on failure
15
+ *
16
+ * The function guarantees to return a UTF-8 encoded hostname.
17
+ * On Windows, filesystem_root is ignored.
18
+ */
19
+ bool os_hostname(char *dst, size_t dst_size, const char *filesystem_root);
20
+
21
+#endif //NETDATA_HOSTNAME_H
src/libnetdata/os/os.h
+1
@@ -23,6 +23,7 @@
23
#include "sleep.h"
24
#include "uuid_generate.h"
25
#include "setenv.h"
26
+#include "hostname.h"
27
#include "os-freebsd-wrappers.h"
28
#include "os-macos-wrappers.h"
29
#include "os-windows-wrappers.h"
src/web/api/formatters/rrd2json.h
-2
@@ -18,8 +18,6 @@
18
19
#include "web/server/web_client.h"
20
21
-#define HOSTNAME_MAX 1024
22
-
21
void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
22
23
int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, struct query_target *qt, time_t *latest_timestamp);