OpenTSDB and TLS (#9068)
Brings TLS to OpenTSDB connector and InfluxDB
thiagoftsm committed
May 26, 2020 at 17:05 UTC
6b091fafd9c3b0197325b3ef751dbdb317048e2b
6 files changed
+171
-3
exporting/exporting_engine.h
+2
@@ -25,6 +25,7 @@ typedef enum exporting_options {
25
26
EXPORTING_OPTION_SEND_CONFIGURED_LABELS = (1 << 3),
27
EXPORTING_OPTION_SEND_AUTOMATIC_LABELS = (1 << 4),
28
+ EXPORTING_OPTION_USE_TLS = (1 << 5),
29
30
EXPORTING_OPTION_SEND_NAMES = (1 << 16)
31
} EXPORTING_OPTIONS;
@@ -252,6 +253,7 @@ static inline void disable_instance(struct instance *instance)
253
}
254
255
#include "exporting/prometheus/prometheus.h"
256
+#include "exporting/opentsdb/opentsdb.h"
257
#if ENABLE_PROMETHEUS_REMOTE_WRITE
258
#include "exporting/prometheus/remote_write/remote_write.h"
259
#endif
exporting/opentsdb/opentsdb.c
+10
@@ -59,6 +59,16 @@ int init_opentsdb_http_instance(struct instance *instance)
59
instance->config.connector_specific_config = (void *)connector_specific_config;
60
connector_specific_config->default_port = 4242;
61
62
+#ifdef ENABLE_HTTPS
63
+ struct opentsdb_specific_data *connector_specific_data = callocz(1, sizeof(struct opentsdb_specific_data));
64
+ connector_specific_data->flags = NETDATA_SSL_START;
65
+ connector_specific_data->conn = NULL;
66
+ if (instance->config.options & EXPORTING_OPTION_USE_TLS) {
67
+ security_start_ssl(NETDATA_SSL_CONTEXT_OPENTSDB);
68
+ }
69
+ instance->connector_specific_data = connector_specific_data;
70
+#endif
71
+
72
instance->start_batch_formatting = NULL;
73
instance->start_host_formatting = format_host_labels_opentsdb_http;
74
instance->start_chart_formatting = NULL;
exporting/opentsdb/opentsdb.h
+7
@@ -18,4 +18,11 @@ int format_dimension_stored_opentsdb_telnet(struct instance *instance, RRDDIM *r
18
int format_dimension_collected_opentsdb_http(struct instance *instance, RRDDIM *rd);
19
int format_dimension_stored_opentsdb_http(struct instance *instance, RRDDIM *rd);
20
21
+#ifdef ENABLE_HTTPS
22
+struct opentsdb_specific_data {
23
+ SSL *conn; //SSL connection
24
+ int flags; //The flags for SSL connection
25
+};
26
+#endif
27
+
28
#endif //NETDATA_EXPORTING_OPENTSDB_H
exporting/read_config.c
+6
@@ -430,6 +430,12 @@ struct engine *read_exporting_config()
430
431
tmp_instance->config.destination = strdupz(exporter_get(instance_name, "destination", default_destination));
432
433
+#ifdef ENABLE_HTTPS
434
+ if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_HTTP && !strncmp(tmp_ci_list->local_ci.connector_name, "opentsdb:https", 14)) {
435
+ tmp_instance->config.options |= EXPORTING_OPTION_USE_TLS;
436
+ }
437
+#endif
438
+
439
#ifdef NETDATA_INTERNAL_CHECKS
440
info(
441
" Dest=[%s], upd=[%d], buffer=[%d] timeout=[%ld] options=[%u]",
exporting/send_data.c
+129
-1
@@ -45,6 +45,13 @@ void simple_connector_receive_response(int *sock, struct instance *instance)
45
response = buffer_create(1);
46
47
struct stats *stats = &instance->stats;
48
+#ifdef ENABLE_HTTPS
49
+ uint32_t options = (uint32_t)instance->config.options;
50
+ struct opentsdb_specific_data *connector_specific_data = instance->connector_specific_data;
51
+
52
+ if (options & EXPORTING_OPTION_USE_TLS)
53
+ ERR_clear_error();
54
+#endif
55
56
errno = 0;
57
@@ -53,7 +60,41 @@ void simple_connector_receive_response(int *sock, struct instance *instance)
60
buffer_need_bytes(response, 4096);
61
62
ssize_t r;
63
+#ifdef ENABLE_HTTPS
64
+ if (options & EXPORTING_OPTION_USE_TLS &&
65
+ connector_specific_data->conn &&
66
+ connector_specific_data->flags == NETDATA_SSL_HANDSHAKE_COMPLETE) {
67
+ r = (ssize_t)SSL_read(connector_specific_data->conn,
68
+ &response->buffer[response->len],
69
+ (int) (response->size - response->len));
70
+
71
+ if (likely(r > 0)) {
72
+ // we received some data
73
+ response->len += r;
74
+ stats->received_bytes += r;
75
+ stats->receptions++;
76
+ continue;
77
+ } else {
78
+ int sslerrno = SSL_get_error(connector_specific_data->conn, (int) r);
79
+ u_long sslerr = ERR_get_error();
80
+ char buf[256];
81
+ switch (sslerrno) {
82
+ case SSL_ERROR_WANT_READ:
83
+ case SSL_ERROR_WANT_WRITE:
84
+ goto endloop;
85
+ default:
86
+ ERR_error_string_n(sslerr, buf, sizeof(buf));
87
+ error("SSL error (%s)",
88
+ ERR_error_string((long)SSL_get_error(connector_specific_data->conn, (int)r), NULL));
89
+ goto endloop;
90
+ }
91
+ }
92
+ } else {
93
+ r = recv(*sock, &response->buffer[response->len], response->size - response->len, MSG_DONTWAIT);
94
+ }
95
+#else
96
r = recv(*sock, &response->buffer[response->len], response->size - response->len, MSG_DONTWAIT);
97
+#endif
98
if (likely(r > 0)) {
99
// we received some data
100
response->len += r;
@@ -69,10 +110,14 @@ void simple_connector_receive_response(int *sock, struct instance *instance)
110
error("EXPORTING: cannot receive data from '%s'.", instance->config.destination);
111
}
112
}
113
+
114
#ifdef UNIT_TESTING
115
break;
116
#endif
117
}
118
+#ifdef ENABLE_HTTPS
119
+endloop:
120
+#endif
121
122
// if we received data, process them
123
if (buffer_strlen(response))
@@ -96,6 +141,14 @@ void simple_connector_send_buffer(int *sock, int *failures, struct instance *ins
141
flags += MSG_NOSIGNAL;
142
#endif
143
144
+#ifdef ENABLE_HTTPS
145
+ uint32_t options = (uint32_t)instance->config.options;
146
+ struct opentsdb_specific_data *connector_specific_data = instance->connector_specific_data;
147
+
148
+ if (options & EXPORTING_OPTION_USE_TLS)
149
+ ERR_clear_error();
150
+#endif
151
+
152
struct stats *stats = &instance->stats;
153
154
int ret = 0;
@@ -104,8 +157,19 @@ void simple_connector_send_buffer(int *sock, int *failures, struct instance *ins
157
158
ssize_t written = -1;
159
107
- if (!ret)
160
+ if (!ret) {
161
+#ifdef ENABLE_HTTPS
162
+ if (options & EXPORTING_OPTION_USE_TLS &&
163
+ connector_specific_data->conn &&
164
+ connector_specific_data->flags == NETDATA_SSL_HANDSHAKE_COMPLETE) {
165
+ written = (ssize_t)SSL_write(connector_specific_data->conn, buffer_tostring(buffer), len);
166
+ } else {
167
+ written = send(*sock, buffer_tostring(buffer), len, flags);
168
+ }
169
+#else
170
written = send(*sock, buffer_tostring(buffer), len, flags);
171
+#endif
172
+ }
173
174
if(written != -1 && (size_t)written == len) {
175
// we sent the data successfully
@@ -167,6 +231,13 @@ void simple_connector_worker(void *instance_p)
231
{
232
struct instance *instance = (struct instance*)instance_p;
233
234
+#ifdef ENABLE_HTTPS
235
+ uint32_t options = (uint32_t)instance->config.options;
236
+ struct opentsdb_specific_data *connector_specific_data = instance->connector_specific_data;
237
+
238
+ if (options & EXPORTING_OPTION_USE_TLS)
239
+ ERR_clear_error();
240
+#endif
241
struct simple_connector_config *connector_specific_config = instance->config.connector_specific_config;
242
struct stats *stats = &instance->stats;
243
@@ -208,6 +279,56 @@ void simple_connector_worker(void *instance_p)
279
&reconnects,
280
NULL,
281
0);
282
+#ifdef ENABLE_HTTPS
283
+ if(sock != -1) {
284
+ if (netdata_opentsdb_ctx) {
285
+ if ( sock_delnonblock(sock) < 0 )
286
+ error("Exporting cannot remove the non-blocking flag from socket %d", sock);
287
+
288
+ if (connector_specific_data->conn == NULL) {
289
+ connector_specific_data->conn = SSL_new(netdata_opentsdb_ctx);
290
+ if (connector_specific_data->conn == NULL) {
291
+ error("Failed to allocate SSL structure to socket %d.", sock);
292
+ connector_specific_data->flags = NETDATA_SSL_NO_HANDSHAKE;
293
+ }
294
+ } else {
295
+ SSL_clear(connector_specific_data->conn);
296
+ }
297
+
298
+ if (connector_specific_data->conn) {
299
+ if (SSL_set_fd(connector_specific_data->conn, sock) != 1) {
300
+ error("Failed to set the socket to the SSL on socket fd %d.", sock);
301
+ connector_specific_data->flags = NETDATA_SSL_NO_HANDSHAKE;
302
+ } else {
303
+ connector_specific_data->flags = NETDATA_SSL_HANDSHAKE_COMPLETE;
304
+ SSL_set_connect_state(connector_specific_data->conn);
305
+ int err = SSL_connect(connector_specific_data->conn);
306
+ if (err != 1) {
307
+ err = SSL_get_error(connector_specific_data->conn, err);
308
+ error("SSL cannot connect with the server: %s ",
309
+ ERR_error_string((long)SSL_get_error(connector_specific_data->conn, err), NULL));
310
+ connector_specific_data->flags = NETDATA_SSL_NO_HANDSHAKE;
311
+ } else {
312
+ info("Exporting established a SSL connection.");
313
+
314
+ struct timeval tv;
315
+ tv.tv_sec = timeout.tv_sec /4;
316
+ tv.tv_usec = 0;
317
+
318
+ if (!tv.tv_sec)
319
+ tv.tv_sec = 2;
320
+
321
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)))
322
+ error("Cannot set timeout to socket %d, this can block communication", sock);
323
+
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ }
330
+#endif
331
+
332
stats->reconnects += reconnects;
333
}
334
@@ -265,5 +386,12 @@ void simple_connector_worker(void *instance_p)
386
clean_prometheus_remote_write(instance);
387
#endif
388
389
+#ifdef ENABLE_HTTPS
390
+ if (options & EXPORTING_OPTION_USE_TLS) {
391
+ SSL_free(connector_specific_data->conn);
392
+ freez(instance->connector_specific_data);
393
+ }
394
+#endif
395
+
396
simple_connector_cleanup(instance);
397
}
libnetdata/socket/security.c
+17
-2
@@ -66,12 +66,16 @@ int tls_select_version(const char *lversion) {
66
return TLS1_1_VERSION;
67
else if (!strcmp(lversion, "1.2"))
68
return TLS1_2_VERSION;
69
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_111
69
+#if defined(TLS1_3_VERSION)
70
else if (!strcmp(lversion, "1.3"))
71
return TLS1_3_VERSION;
72
#endif
73
74
+#if defined(TLS_MAX_VERSION)
75
return TLS_MAX_VERSION;
76
+#else
77
+ return TLS1_2_VERSION;
78
+#endif
79
}
80
#endif
81
@@ -120,7 +124,18 @@ SSL_CTX * security_initialize_openssl_client() {
124
ctx = SSL_CTX_new(TLS_client_method());
125
#endif
126
if(ctx) {
123
- security_openssl_common_options(ctx, 1);
127
+#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
128
+ SSL_CTX_set_options (ctx,SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION);
129
+#else
130
+ SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
131
+# if defined(TLS_MAX_VERSION)
132
+ SSL_CTX_set_max_proto_version(ctx, TLS_MAX_VERSION);
133
+# elif defined(TLS1_3_VERSION)
134
+ SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
135
+# elif defined(TLS1_2_VERSION)
136
+ SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
137
+# endif
138
+#endif
139
}
140
141
return ctx;