@cryptotaxi247 / netdata-1 / commits / b6088e08a

SSL implementation for Netdata (#5956)

* SSL implementation for Netdata * Upload of fixes asked by @paulkatsoulakis and @cakrit * Fix local computer * Adding openssl to webserver * fixing.. * HTTPS almost there * Codacity * HTTPS day 3 * HTTPS without Bio step 1 * HTTPS without Bio step 2 * HTTPS without Bio step 3 * HTTPS without Bio step 4 * HTTPS without Bio step 5 * HTTPS without Bio step 6 * HTTPS without Bio step 7 * HTTPS without Bio step 8 * HTTPS without Bio step 9 * HTTPS without Bio step 10 * SSL on streaming 1 * Daily pull * HTTPS without Bio step 11 * HTTPS without Bio step 12 * HTTPS without Bio step 13 * HTTPS without Bio step 14 * SSL_Interception change documentation * HTTPS without Bio step 15 * HTTPS without Bio step 16 * SSL_Interception fix codacity * SSL_Interception fix doc * SSL_Interception comments * SSL_Interception fixing problems! * SSL_Interception killing bugs * SSL_Interception changing parameter * SSL_Implementation documentation and script * SSL_Implementation multiple fixes * SSL_Implementation installer and cipher * SSL_Implementation Redirect 301 * SSL_Implementation webserver doc and install-or-update.sh * SSL_Implementation error 00000001:lib(0):func(0):reason(1) * SSL_Implementation web server doc * SSL_Implementation SEGFAULT on Fedora * SSL_Implementation fix ^SSL=force|optional * SSL_Implementation Redirect and Ciphers * SSL_Implementation race condition 1 * SSL_Implementation Fix Location * SSL_Implementation Fix Location 2 * SSL_Implementation Fix stream * SSL_Implementation Fix stream 2 * SSL_Implementation Fix stream 3 * SSL_Implementation last problems! * SSL_Implementation adjusts to commit! * SSL_Implementation documentation permission! * SSL_Implementation documentation permission 2! * SSL_Implementation documentation permission 3!

thiagoftsm committed May 31, 2019 at 14:27 UTC b6088e08a7dcf40c89dc859f85be11b2f9883a23
24 files changed +888 -37
.gitignore
+3
@@ -171,3 +171,6 @@ docs/generator/build
171 docs/generator/mkdocs.yml
172
173 .environment.sh
174 +
175 +#CLion files
176 +netdata.cbp
CMakeLists.txt
+2 -1
@@ -284,7 +284,8 @@ set(LIBNETDATA_FILES
284 libnetdata/threads/threads.h
285 libnetdata/url/url.c
286 libnetdata/url/url.h
287 - )
287 + libnetdata/socket/security.c
288 + libnetdata/socket/security.h)
289
290 add_library(libnetdata OBJECT ${LIBNETDATA_FILES})
291
Makefile.am
+3
@@ -154,6 +154,8 @@ LIBNETDATA_FILES = \
154 libnetdata/simple_pattern/simple_pattern.h \
155 libnetdata/socket/socket.c \
156 libnetdata/socket/socket.h \
157 + libnetdata/socket/security.c \
158 + libnetdata/socket/security.h \
159 libnetdata/statistical/statistical.c \
160 libnetdata/statistical/statistical.h \
161 libnetdata/storage_number/storage_number.c \
@@ -496,6 +498,7 @@ endif
498 NETDATA_COMMON_LIBS = \
499 $(OPTIONAL_MATH_LIBS) \
500 $(OPTIONAL_ZLIB_LIBS) \
501 + $(OPTIONAL_SSL_LIBS) \
502 $(OPTIONAL_UUID_LIBS) \
503 $(OPTIONAL_UV_LIBS) \
504 $(OPTIONAL_LZ4_LIBS) \
configure.ac
+17 -3
@@ -131,6 +131,12 @@ AC_ARG_ENABLE(
131 ,
132 [enable_lto="detect"]
133 )
134 +AC_ARG_ENABLE(
135 + [https],
136 + [AS_HELP_STRING([--enable-https], [Enable SSL support @<:@default autodetect@:>@])],
137 + ,
138 + [enable_https="detect"]
139 +)
140 AC_ARG_ENABLE(
141 [dbengine],
142 [AS_HELP_STRING([--disable-dbengine], [disable netdata dbengine @<:@default autodetect@:>@])],
@@ -138,7 +144,6 @@ AC_ARG_ENABLE(
144 [enable_dbengine="detect"]
145 )
146
141 -
147 # -----------------------------------------------------------------------------
148 # netdata required checks
149
@@ -338,7 +343,7 @@ OPTIONAL_SSL_CFLAGS="${SSL_CFLAGS}"
343 OPTIONAL_SSL_LIBS="${SSL_LIBS}"
344
345 # -----------------------------------------------------------------------------
341 -# DB engine
346 +# DB engine and HTTPS
347 test "${enable_dbengine}" = "yes" -a -z "${UV_LIBS}" && \
348 AC_MSG_ERROR([libuv required but not found. Try installing 'libuv1-dev' or 'libuv-devel'.])
349
@@ -348,7 +353,7 @@ test "${enable_dbengine}" = "yes" -a -z "${LZ4_LIBS}" && \
353 test "${enable_dbengine}" = "yes" -a -z "${JUDY_LIBS}" && \
354 AC_MSG_ERROR([libJudy required but not found. Try installing 'libjudy-dev' or 'Judy-devel'.])
355
351 -test "${enable_dbengine}" = "yes" -a -z "${SSL_LIBS}" && \
356 +test "${enable_dbengine}" = "yes" -o "${enable_https}" = "yes" -a -z "${SSL_LIBS}" && \
357 AC_MSG_ERROR([OpenSSL required but not found. Try installing 'libssl-dev' or 'openssl-devel'.])
358
359 AC_MSG_CHECKING([if netdata dbengine should be used])
@@ -361,6 +366,15 @@ fi
366 AC_MSG_RESULT([${enable_dbengine}])
367 AM_CONDITIONAL([ENABLE_DBENGINE], [test "${enable_dbengine}" = "yes"])
368
369 +AC_MSG_CHECKING([if netdata https should be used])
370 +if test "${enable_https}" != "no" -a "${SSL_LIBS}"; then
371 + enable_https="yes"
372 + AC_DEFINE([ENABLE_HTTPS], [1], [netdata HTTPS usability])
373 +else
374 + enable_https="no"
375 +fi
376 +AC_MSG_RESULT([${enable_https}])
377 +AM_CONDITIONAL([ENABLE_HTTPS], [test "${enable_https}" = "yes"])
378
379 # -----------------------------------------------------------------------------
380 # compiler options
daemon/main.c
+26 -2
@@ -49,6 +49,10 @@ void netdata_cleanup_and_exit(int ret) {
49 error("EXIT: cannot unlink pidfile '%s'.", pidfile);
50 }
51
52 +#ifdef ENABLE_HTTPS
53 + security_clean_openssl();
54 +#endif
55 +
56 info("EXIT: all done - netdata is now exiting - bye bye...");
57 exit(ret);
58 }
@@ -345,7 +349,20 @@ static const char *verify_required_directory(const char *dir) {
349 return dir;
350 }
351
348 -void log_init(void) {
352 +#ifdef ENABLE_HTTPS
353 +static void security_init(){
354 + char filename[FILENAME_MAX + 1];
355 + snprintfz(filename, FILENAME_MAX, "%s/ssl/key.pem",netdata_configured_user_config_dir);
356 + security_key = config_get(CONFIG_SECTION_WEB, "ssl key", filename);
357 +
358 + snprintfz(filename, FILENAME_MAX, "%s/ssl/cert.pem",netdata_configured_user_config_dir);
359 + security_cert = config_get(CONFIG_SECTION_WEB, "ssl certificate", filename);
360 +
361 + security_openssl_library();
362 +}
363 +#endif
364 +
365 +static void log_init(void) {
366 char filename[FILENAME_MAX + 1];
367 snprintfz(filename, FILENAME_MAX, "%s/debug.log", netdata_configured_log_dir);
368 stdout_filename = config_get(CONFIG_SECTION_GLOBAL, "debug log", filename);
@@ -420,8 +437,9 @@ static void get_netdata_configured_variables() {
437 // get the hostname
438
439 char buf[HOSTNAME_MAX + 1];
423 - if(gethostname(buf, HOSTNAME_MAX) == -1)
440 + if(gethostname(buf, HOSTNAME_MAX) == -1){
441 error("Cannot get machine hostname.");
442 + }
443
444 netdata_configured_hostname = config_get(CONFIG_SECTION_GLOBAL, "hostname", buf);
445 debug(D_OPTIONS, "hostname set to '%s'", netdata_configured_hostname);
@@ -1080,6 +1098,12 @@ int main(int argc, char **argv) {
1098 log_init();
1099 error_log_limit_unlimited();
1100
1101 + // --------------------------------------------------------------------
1102 + // get the certificate and start security
1103 +#ifdef ENABLE_HTTPS
1104 + security_init();
1105 +#endif
1106 +
1107 // --------------------------------------------------------------------
1108 // setup process signals
1109
database/rrd.h
+4
@@ -723,6 +723,10 @@ struct rrdhost {
723 struct rrdengine_instance *rrdeng_ctx; // DB engine instance for this host
724 #endif
725
726 +#ifdef ENABLE_HTTPS
727 + struct netdata_ssl ssl; //Structure used to encrypt the connection
728 +#endif
729 +
730 struct rrdhost *next;
731 };
732 extern RRDHOST *localhost;
database/rrdhost.c
+4
@@ -147,6 +147,10 @@ RRDHOST *rrdhost_create(const char *hostname,
147 host->rrdpush_sender_pipe[0] = -1;
148 host->rrdpush_sender_pipe[1] = -1;
149 host->rrdpush_sender_socket = -1;
150 +#ifdef ENABLE_HTTPS
151 + host->ssl.conn = NULL;
152 + host->ssl.flags = NETDATA_SSL_START;
153 +#endif
154
155 netdata_mutex_init(&host->rrdpush_sender_buffer_mutex);
156 netdata_rwlock_init(&host->rrdhost_rwlock);
docs/Running-behind-nginx.md
+14
@@ -117,6 +117,19 @@ Using the above, you access Netdata on the backend servers, like this:
117 - `http://nginx.server/netdata/server1/` to reach `backend-server1`
118 - `http://nginx.server/netdata/server2/` to reach `backend-server2`
119
120 +### Using TLS communication
121 +
122 +In case the Netdata web server has been [configured to use TLS](../web/server/#enabling-tls-support),
123 +you must also encrypt the communication between Nginx and Netdata.
124 +
125 +To enable encryption, first [enable SSL on nginx](http://nginx.org/en/docs/http/configuring_https_servers.html) and then put the following in the location section of the Nginx configuration:
126 +
127 +```
128 +proxy_set_header X-Forwarded-Proto https;
129 +proxy_pass https://localhost:19999;
130 +```
131 +
132 +If nginx is not configured as described here, you will probably receive the error `SSL_ERROR_RX_RECORD_TOO_LONG`.
133
134 ### Enable authentication
135
@@ -201,4 +214,5 @@ If you get an 502 Bad Gateway error you might check your nginx error log:
214
215 If you see something like the above, chances are high that SELinux prevents nginx from connecting to the backend server. To fix that, just use this policy: `setsebool -P httpd_can_network_connect true`.
216
217 +
218 [![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Fdocs%2FRunning-behind-nginx&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)]()
libnetdata/libnetdata.h
+1
@@ -298,6 +298,7 @@ extern char *netdata_configured_host_prefix;
298 #include "clocks/clocks.h"
299 #include "popen/popen.h"
300 #include "simple_pattern/simple_pattern.h"
301 +#include "socket/security.h"
302 #include "socket/socket.h"
303 #include "config/appconfig.h"
304 #include "log/log.h"
libnetdata/socket/security.c new
+215
@@ -0,0 +1,215 @@
1 +#include "../libnetdata.h"
2 +
3 +SSL_CTX *netdata_cli_ctx=NULL;
4 +SSL_CTX *netdata_srv_ctx=NULL;
5 +const char *security_key=NULL;
6 +const char *security_cert=NULL;
7 +int netdata_use_ssl_on_stream = NETDATA_SSL_OPTIONAL;
8 +int netdata_use_ssl_on_http = NETDATA_SSL_FORCE; //We force SSL due safety reasons
9 +int netdata_validate_server = NETDATA_SSL_VALID_CERTIFICATE;
10 +
11 +static void security_info_callback(const SSL *ssl, int where, int ret) {
12 + (void)ssl;
13 + if ( where & SSL_CB_ALERT ) {
14 + debug(D_WEB_CLIENT,"SSL INFO CALLBACK %s %s",SSL_alert_type_string( ret ),SSL_alert_desc_string_long(ret));
15 + }
16 +}
17 +
18 +void security_openssl_library()
19 +{
20 +#if OPENSSL_VERSION_NUMBER < 0x10100000L
21 +# if (SSLEAY_VERSION_NUMBER >= 0x0907000L)
22 + OPENSSL_config(NULL);
23 +# endif
24 +
25 +# if OPENSSL_API_COMPAT < 0x10100000L
26 + SSL_load_error_strings();
27 +# endif
28 +
29 + SSL_library_init();
30 +#else
31 + if ( OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG,NULL) != 1 ){
32 + error("SSL library cannot be initialized.");
33 + }
34 +#endif
35 +}
36 +
37 +void security_openssl_common_options(SSL_CTX *ctx){
38 +#if OPENSSL_VERSION_NUMBER >= 0x10100000L
39 + static char *ciphers = {"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"};
40 +#endif
41 +#if OPENSSL_VERSION_NUMBER < 0x10100000L
42 + SSL_CTX_set_options (ctx,SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION);
43 +#else
44 + SSL_CTX_set_min_proto_version(ctx,TLS1_2_VERSION);
45 + //We are avoiding the TLS v1.3 for while, because Google Chrome
46 + //is giving the message net::ERR_SSL_VERSION_INTERFERENCE with it.
47 + SSL_CTX_set_max_proto_version(ctx,TLS1_2_VERSION);
48 +#endif
49 + SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
50 +
51 +#if OPENSSL_VERSION_NUMBER >= 0x10100000L
52 + if (!SSL_CTX_set_cipher_list(ctx,ciphers) ){
53 + error("SSL error. cannot set the cipher list");
54 + }
55 +#endif
56 +
57 +
58 +}
59 +
60 +static SSL_CTX * security_initialize_openssl_client() {
61 + SSL_CTX *ctx;
62 +#if OPENSSL_VERSION_NUMBER < 0x10100000L
63 + ctx = SSL_CTX_new(SSLv23_client_method());
64 +#else
65 + ctx = SSL_CTX_new(TLS_client_method());
66 +#endif
67 + security_openssl_common_options(ctx);
68 +
69 + return ctx;
70 +}
71 +
72 +static SSL_CTX * security_initialize_openssl_server(){
73 + SSL_CTX *ctx;
74 + char lerror[512];
75 + static int netdata_id_context = 1;
76 +
77 + //TO DO: Confirm the necessity to check return for other OPENSSL function
78 +#if OPENSSL_VERSION_NUMBER < 0x10100000L
79 + ctx = SSL_CTX_new(SSLv23_server_method());
80 + if ( !ctx ) {
81 + error("Cannot create a new SSL context, netdata won't encrypt communication");
82 + return NULL;
83 + }
84 +
85 + SSL_CTX_use_certificate_file(ctx, security_cert, SSL_FILETYPE_PEM);
86 +#else
87 + ctx = SSL_CTX_new(TLS_server_method());
88 + if ( !ctx ){
89 + error("Cannot create a new SSL context, netdata won't encrypt communication");
90 + return NULL;
91 + }
92 +
93 + SSL_CTX_use_certificate_chain_file(ctx, security_cert );
94 +#endif
95 + security_openssl_common_options(ctx);
96 +
97 + SSL_CTX_use_PrivateKey_file(ctx,security_key,SSL_FILETYPE_PEM);
98 +
99 + if ( !SSL_CTX_check_private_key(ctx) ){
100 + ERR_error_string_n(ERR_get_error(),lerror,sizeof(lerror));
101 + error("SSL cannot check the private key: %s",lerror);
102 + SSL_CTX_free(ctx);
103 + return NULL;
104 + }
105 +
106 + SSL_CTX_set_session_id_context(ctx,(void*)&netdata_id_context,(unsigned int)sizeof(netdata_id_context));
107 + SSL_CTX_set_info_callback(ctx,security_info_callback);
108 +
109 +#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
110 + SSL_CTX_set_verify_depth(ctx,1);
111 +#endif
112 + debug(D_WEB_CLIENT,"SSL GLOBAL CONTEXT STARTED\n");
113 +
114 + return ctx;
115 +}
116 +
117 +void security_start_ssl(int type){
118 + if ( !type){
119 + struct stat statbuf;
120 + if ( (stat(security_key,&statbuf)) || (stat(security_cert,&statbuf)) ){
121 + info("To use encryption it is necessary to set \"ssl certificate\" and \"ssl key\" in [web] !\n");
122 + return;
123 + }
124 +
125 + netdata_srv_ctx = security_initialize_openssl_server();
126 + }
127 + else {
128 + netdata_cli_ctx = security_initialize_openssl_client();
129 + }
130 +}
131 +
132 +void security_clean_openssl(){
133 + if ( netdata_srv_ctx )
134 + {
135 + SSL_CTX_free(netdata_srv_ctx);
136 + }
137 +
138 + if ( netdata_cli_ctx )
139 + {
140 + SSL_CTX_free(netdata_cli_ctx);
141 + }
142 +
143 +#if OPENSSL_VERSION_NUMBER < 0x10100000L
144 + ERR_free_strings();
145 +#endif
146 +}
147 +
148 +int security_process_accept(SSL *ssl,int msg) {
149 + int sock = SSL_get_fd(ssl);
150 + int test;
151 + if (msg > 0x17)
152 + {
153 + return NETDATA_SSL_NO_HANDSHAKE;
154 + }
155 +
156 + ERR_clear_error();
157 + if ((test = SSL_accept(ssl)) <= 0) {
158 + int sslerrno = SSL_get_error(ssl, test);
159 + switch(sslerrno) {
160 + case SSL_ERROR_WANT_READ:
161 + {
162 + error("SSL handshake did not finish and it wanna read on socket %d!",sock);
163 + return NETDATA_SSL_WANT_READ;
164 + }
165 + case SSL_ERROR_WANT_WRITE:
166 + {
167 + error("SSL handshake did not finish and it wanna read on socket %d!",sock);
168 + return NETDATA_SSL_WANT_WRITE;
169 + }
170 + case SSL_ERROR_NONE:
171 + case SSL_ERROR_SSL:
172 + case SSL_ERROR_SYSCALL:
173 + default:
174 + {
175 + u_long err;
176 + char buf[256];
177 + int counter = 0;
178 + while ((err = ERR_get_error()) != 0){
179 + ERR_error_string_n(err, buf, sizeof(buf));
180 + info("%d SSL Handshake error (%s) on socket %d ",counter++,ERR_error_string((long)SSL_get_error(ssl,test),NULL),sock);
181 + }
182 + return NETDATA_SSL_NO_HANDSHAKE;
183 + }
184 + }
185 + }
186 +
187 + if ( SSL_is_init_finished(ssl) )
188 + {
189 + debug(D_WEB_CLIENT_ACCESS,"SSL Handshake finished %s errno %d on socket fd %d",ERR_error_string((long)SSL_get_error(ssl,test),NULL),errno,sock);
190 + }
191 +
192 + return 0;
193 +}
194 +
195 +int security_test_certificate(SSL *ssl){
196 + X509* cert = SSL_get_peer_certificate(ssl);
197 + int ret;
198 + long status;
199 + if (!cert){
200 + return -1;
201 + }
202 +
203 + status = SSL_get_verify_result(ssl);
204 + if((X509_V_OK != status))
205 + {
206 + char error[512];
207 + ERR_error_string_n(ERR_get_error(),error,sizeof(error));
208 + error("SSL RFC4158 check: We have a invalid certificate, the tests result with %ld and message %s",status,error);
209 + ret = -1;
210 + }
211 + else {
212 + ret = 0;
213 + }
214 + return ret;
215 +}
\ No newline at end of file
libnetdata/socket/security.h new
+38
@@ -0,0 +1,38 @@
1 +#ifndef NETDATA_SECURITY_H
2 +# define NETDATA_SECURITY_H
3 +
4 +# include <openssl/ssl.h>
5 +# include <openssl/err.h>
6 +# if (SSLEAY_VERSION_NUMBER >= 0x0907000L) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
7 +# include <openssl/conf.h>
8 +# endif
9 +
10 +#define NETDATA_SSL_HANDSHAKE_COMPLETE 0 //All the steps were successful
11 +#define NETDATA_SSL_START 1 //Starting handshake, conn variable is NULL
12 +#define NETDATA_SSL_WANT_READ 2 //The connection wanna read from socket
13 +#define NETDATA_SSL_WANT_WRITE 4 //The connection wanna write on socket
14 +#define NETDATA_SSL_NO_HANDSHAKE 8 //Continue without encrypt connection.
15 +#define NETDATA_SSL_OPTIONAL 16 //Flag to define the HTTP request
16 +#define NETDATA_SSL_FORCE 32 //We only accepts HTTPS request
17 +#define NETDATA_SSL_INVALID_CERTIFICATE 64 //Accepts invalid certificate
18 +#define NETDATA_SSL_VALID_CERTIFICATE 128 //Accepts invalid certificate
19 +struct netdata_ssl{
20 + SSL *conn; //SSL connection
21 + int flags;
22 +};
23 +
24 +extern SSL_CTX *netdata_cli_ctx;
25 +extern SSL_CTX *netdata_srv_ctx;
26 +extern const char *security_key;
27 +extern const char *security_cert;
28 +extern int netdata_use_ssl_on_stream;
29 +extern int netdata_use_ssl_on_http;
30 +extern int netdata_validate_server;
31 +
32 +void security_openssl_library();
33 +void security_clean_openssl();
34 +void security_start_ssl(int type);
35 +int security_process_accept(SSL *ssl,int msg);
36 +int security_test_certificate(SSL *ssl);
37 +
38 +#endif //NETDATA_SECURITY_H
libnetdata/socket/socket.c
+50 -1
@@ -301,14 +301,37 @@ void listen_sockets_close(LISTEN_SOCKETS *sockets) {
301 sockets->failed = 0;
302 }
303
304 +WEB_CLIENT_ACL socket_ssl_acl(char *ssl){
305 + if (!strcmp(ssl,"optional")){
306 + netdata_use_ssl_on_http = NETDATA_SSL_OPTIONAL;
307 + return WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING;
308 + }
309 + else if (!strcmp(ssl,"force")){
310 + netdata_use_ssl_on_stream = NETDATA_SSL_FORCE;
311 + return WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING;
312 + }
313 +
314 + return WEB_CLIENT_ACL_NONE;
315 +}
316 +
317 WEB_CLIENT_ACL read_acl(char *st) {
318 + char *ssl = strchr(st,'^');
319 + if (ssl){
320 + ssl++;
321 + if ( !strncmp("SSL=",ssl,4)){
322 + ssl += 4;
323 + }
324 + socket_ssl_acl(ssl);
325 + }
326 +
327 if (!strcmp(st,"dashboard")) return WEB_CLIENT_ACL_DASHBOARD;
328 if (!strcmp(st,"registry")) return WEB_CLIENT_ACL_REGISTRY;
329 if (!strcmp(st,"badges")) return WEB_CLIENT_ACL_BADGE;
330 if (!strcmp(st,"management")) return WEB_CLIENT_ACL_MGMT;
331 if (!strcmp(st,"streaming")) return WEB_CLIENT_ACL_STREAMING;
332 if (!strcmp(st,"netdata.conf")) return WEB_CLIENT_ACL_NETDATACONF;
311 - return WEB_CLIENT_ACL_NONE;
333 +
334 + return socket_ssl_acl(st);
335 }
336
337 static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition, uint16_t default_port, int listen_backlog) {
@@ -824,7 +847,12 @@ int connect_to_one_of(const char *destination, int default_port, struct timeval
847 // --------------------------------------------------------------------------------------------------------------------
848 // helpers to send/receive data in one call, in blocking mode, with a timeout
849
850 +#ifdef ENABLE_HTTPS
851 +ssize_t recv_timeout(struct netdata_ssl *ssl,int sockfd, void *buf, size_t len, int flags, int timeout) {
852 +#else
853 ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
854 +#endif
855 +
856 for(;;) {
857 struct pollfd fd = {
858 .fd = sockfd,
@@ -852,10 +880,22 @@ ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout)
880 if(fd.events & POLLIN) break;
881 }
882
883 +#ifdef ENABLE_HTTPS
884 + if (ssl->conn){
885 + if (!ssl->flags){
886 + return SSL_read(ssl->conn,buf,len);
887 + }
888 + }
889 +#endif
890 return recv(sockfd, buf, len, flags);
891 }
892
893 +#ifdef ENABLE_HTTPS
894 +ssize_t send_timeout(struct netdata_ssl *ssl,int sockfd, void *buf, size_t len, int flags, int timeout) {
895 +#else
896 ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
897 +#endif
898 +
899 for(;;) {
900 struct pollfd fd = {
901 .fd = sockfd,
@@ -883,6 +923,13 @@ ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout)
923 if(fd.events & POLLOUT) break;
924 }
925
926 +#ifdef ENABLE_HTTPS
927 + if(ssl->conn){
928 + if (!ssl->flags){
929 + return SSL_write(ssl->conn, buf, len);
930 + }
931 + }
932 +#endif
933 return send(sockfd, buf, len, flags);
934 }
935
@@ -1291,6 +1338,8 @@ static void poll_events_process(POLLJOB *p, POLLINFO *pi, struct pollfd *pf, sho
1338 do {
1339 char client_ip[NI_MAXHOST + 1];
1340 char client_port[NI_MAXSERV + 1];
1341 + client_ip[0] = 0x00;
1342 + client_port[0] = 0x00;
1343
1344 debug(D_POLLFD, "POLLFD: LISTENER: calling accept4() slot %zu (fd %d)", i, fd);
1345 nfd = accept_socket(fd, SOCK_NONBLOCK, client_ip, NI_MAXHOST + 1, client_port, NI_MAXSERV + 1, p->access_list);
libnetdata/socket/socket.h
+6
@@ -3,6 +3,7 @@
3 #ifndef NETDATA_SOCKET_H
4 #define NETDATA_SOCKET_H
5
6 +#include <openssl/ossl_typ.h>
7 #include "../libnetdata.h"
8
9 #ifndef MAX_LISTEN_FDS
@@ -51,8 +52,13 @@ extern void listen_sockets_close(LISTEN_SOCKETS *sockets);
52 extern int connect_to_this(const char *definition, int default_port, struct timeval *timeout);
53 extern int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size);
54
55 +#ifdef ENABLE_HTTPS
56 +extern ssize_t recv_timeout(struct netdata_ssl *ssl,int sockfd, void *buf, size_t len, int flags, int timeout);
57 +extern ssize_t send_timeout(struct netdata_ssl *ssl,int sockfd, void *buf, size_t len, int flags, int timeout);
58 +#else
59 extern ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
60 extern ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
61 +#endif
62
63 extern int sock_setnonblock(int fd);
64 extern int sock_delnonblock(int fd);
netdata-installer.sh
+1 -1
@@ -635,7 +635,7 @@ fi
635
636 # --- conf dir ----
637
638 -for x in "python.d" "charts.d" "node.d" "health.d" "statsd.d" "go.d" "custom-plugins.d"; do
638 +for x in "python.d" "charts.d" "node.d" "health.d" "statsd.d" "go.d" "custom-plugins.d" "ssl"; do
639 if [ ! -d "${NETDATA_USER_CONFIG_DIR}/${x}" ]; then
640 echo >&2 "Creating directory '${NETDATA_USER_CONFIG_DIR}/${x}'"
641 run mkdir -p "${NETDATA_USER_CONFIG_DIR}/${x}" || exit 1
packaging/makeself/install-or-update.sh
+1 -1
@@ -175,7 +175,7 @@ fi
175
176 progress "create user config directories"
177
178 -for x in "python.d" "charts.d" "node.d" "health.d" "statsd.d" "custom-plugins.d"
178 +for x in "python.d" "charts.d" "node.d" "health.d" "statsd.d" "custom-plugins.d" "ssl"
179 do
180 if [ ! -d "etc/netdata/${x}" ]
181 then
streaming/README.md
+38 -1
@@ -123,7 +123,7 @@ a `proxy`).
123 ```
124 [stream]
125 enabled = yes | no
126 - destination = IP:PORT ...
126 + destination = IP:PORT[:SSL] ...
127 api key = XXXXXXXXXXX
128 ```
129
@@ -136,6 +136,8 @@ headless proxy|`none`|not `none`|`yes`|only for `data source = as collected`|not
136 proxy with db|not `none`|not `none`|`yes`|possible|possible|yes
137 central netdata|not `none`|not `none`|`no`|possible|possible|yes
138
139 +For the options to encrypt the data stream between the slave and the master, refer to [securing the communication](#securing-the-communication)
140 +
141 ##### options for the receiving node
142
143 `stream.conf` looks like this:
@@ -209,6 +211,41 @@ The receiving end (`proxy` or `master`) logs entries like these:
211
212 For netdata v1.9+, streaming can also be monitored via `access.log`.
213
214 +### Securing the communication
215 +
216 +Netdata does not activate TLS encryption by default. To encrypt the connection, you first need to [enable TLS support](../web/server/#enabling-tls-support) on the master. With encryption enabled on the receiving side, we need to instruct the slave to use SSL as well. On the slave's `stream.conf`, configure the destination as follows:
217 +
218 +```
219 +[stream]
220 + destination = host:port:SSL
221 +```
222 +
223 +The word SSL appended to the end of the destination tells the slave that the connection must be encrypted.
224 +
225 +#### Certificate verification
226 +
227 +When SSL is enabled on the slave, the default behavior will be do not connect with the master unless the server's certificate can be verified via the default chain. In case you want to avoid this check, add to the slave's `stream.conf` the following:
228 +
229 +```
230 +[stream]
231 + ssl skip certificate verification = yes
232 +```
233 +
234 +#### Expected behaviors
235 +
236 +With the introduction of SSL, the master-slave communication behaves as shown in the table below, depending on the following configurations:
237 +- Master TLS (Yes/No): Whether the `[web]` section in `netdata.conf` has `ssl key` and `ssl certificate`.
238 +- Master port SSL (-/force/optional): Depends on whether the `[web]` section `bind to` contains a `^SSL=force` or `^SSL=optional` directive on the port(s) used for streaming.
239 +- Slave TLS (Yes/No): Whether the destination in the slave's `stream.conf` has `:SSL` at the end.
240 +- Slave SSL Verification (yes/no): Value of the slave's `stream.conf` `ssl skip certificate verification` parameter (default is no).
241 +
242 + Master TLS enabled | Master port SSL | Slave TLS | Slave SSL Ver. | Behavior
243 +:------:|:-----:|:-----:|:-----:|:--------
244 +No | - | No | no | Legacy behavior. The master-slave stream is unencrypted.
245 +Yes | force | No | no | The master rejects the slave connection.
246 +Yes | -/optional | No | no | The master-slave stream is unencrypted (expected situation for legacy slaves and newer masters)
247 +Yes | -/force/optional | Yes | no | The master-slave stream is encrypted, provided that the master has a valid SSL certificate. Otherwise, the slave refuses to connect.
248 +Yes | -/force/optional | Yes | yes | The master-slave stream is encrypted.
249
250 ## Viewing remote host dashboards, using mirrored databases
251
streaming/rrdpush.c
+116 -2
@@ -79,6 +79,25 @@ int rrdpush_init() {
79 default_rrdpush_enabled = 0;
80 }
81
82 +#ifdef ENABLE_HTTPS
83 + if (netdata_use_ssl_on_stream == NETDATA_SSL_OPTIONAL) {
84 + if (default_rrdpush_destination){
85 + char *test = strstr(default_rrdpush_destination,":SSL");
86 + if(test){
87 + *test = 0X00;
88 + netdata_use_ssl_on_stream = NETDATA_SSL_FORCE;
89 + }
90 + }
91 + }
92 + char *invalid_certificate = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "ssl skip certificate verification", "no");
93 + if ( !strcmp(invalid_certificate,"yes")){
94 + if (netdata_validate_server == NETDATA_SSL_VALID_CERTIFICATE){
95 + info("The Netdata is configured to accept invalid certificate.");
96 + netdata_validate_server = NETDATA_SSL_INVALID_CERTIFICATE;
97 + }
98 + }
99 +#endif
100 +
101 return default_rrdpush_enabled;
102 }
103
@@ -414,6 +433,7 @@ static inline void rrdpush_sender_thread_close_socket(RRDHOST *host) {
433 }
434 }
435
436 +//called from client side
437 static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_port, int timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) {
438 struct timeval tv = {
439 .tv_sec = timeout,
@@ -442,9 +462,38 @@ static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_po
462
463 info("STREAM %s [send to %s]: initializing communication...", host->hostname, connected_to);
464
465 +#ifdef ENABLE_HTTPS
466 + if( netdata_cli_ctx ){
467 + host->ssl.flags = NETDATA_SSL_START;
468 + if (!host->ssl.conn){
469 + host->ssl.conn = SSL_new(netdata_cli_ctx);
470 + if(!host->ssl.conn){
471 + error("Failed to allocate SSL structure.");
472 + host->ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
473 + }
474 + }
475 + else{
476 + SSL_clear(host->ssl.conn);
477 + }
478 +
479 + if (host->ssl.conn)
480 + {
481 + if (SSL_set_fd(host->ssl.conn, host->rrdpush_sender_socket) != 1) {
482 + error("Failed to set the socket to the SSL on socket fd %d.", host->rrdpush_sender_socket);
483 + host->ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
484 + } else{
485 + host->ssl.flags = NETDATA_SSL_HANDSHAKE_COMPLETE;
486 + }
487 + }
488 + }
489 + else {
490 + host->ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
491 + }
492 +#endif
493 +
494 #define HTTP_HEADER_SIZE 8192
495 char http[HTTP_HEADER_SIZE + 1];
447 - snprintfz(http, HTTP_HEADER_SIZE,
496 + int eol = snprintfz(http, HTTP_HEADER_SIZE,
497 "STREAM key=%s&hostname=%s&registry_hostname=%s&machine_guid=%s&update_every=%d&os=%s&timezone=%s&tags=%s"
498 "&NETDATA_SYSTEM_OS_NAME=%s"
499 "&NETDATA_SYSTEM_OS_ID=%s"
@@ -486,8 +535,39 @@ static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_po
535 , host->program_name
536 , host->program_version
537 );
489 -
538 + http[eol] = 0x00;
539 +
540 +#ifdef ENABLE_HTTPS
541 + if (!host->ssl.flags) {
542 + ERR_clear_error();
543 + SSL_set_connect_state(host->ssl.conn);
544 + int err = SSL_connect(host->ssl.conn);
545 + if (err != 1){
546 + err = SSL_get_error(host->ssl.conn, err);
547 + error("SSL cannot connect with the server: %s ",ERR_error_string((long)SSL_get_error(host->ssl.conn,err),NULL));
548 + if (netdata_use_ssl_on_stream == NETDATA_SSL_FORCE) {
549 + rrdpush_sender_thread_close_socket(host);
550 + return 0;
551 + }else {
552 + host->ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
553 + }
554 + }
555 + else {
556 + if (netdata_use_ssl_on_stream == NETDATA_SSL_FORCE) {
557 + if (netdata_validate_server == NETDATA_SSL_VALID_CERTIFICATE) {
558 + if ( security_test_certificate(host->ssl.conn)) {
559 + error("Closing the stream connection, because the server SSL certificate is not valid.");
560 + rrdpush_sender_thread_close_socket(host);
561 + return 0;
562 + }
563 + }
564 + }
565 + }
566 + }
567 + if(send_timeout(&host->ssl,host->rrdpush_sender_socket, http, strlen(http), 0, timeout) == -1) {
568 +#else
569 if(send_timeout(host->rrdpush_sender_socket, http, strlen(http), 0, timeout) == -1) {
570 +#endif
571 error("STREAM %s [send to %s]: failed to send HTTP header to remote netdata.", host->hostname, connected_to);
572 rrdpush_sender_thread_close_socket(host);
573 return 0;
@@ -495,7 +575,11 @@ static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_po
575
576 info("STREAM %s [send to %s]: waiting response from remote netdata...", host->hostname, connected_to);
577
578 +#ifdef ENABLE_HTTPS
579 + if(recv_timeout(&host->ssl,host->rrdpush_sender_socket, http, HTTP_HEADER_SIZE, 0, timeout) == -1) {
580 +#else
581 if(recv_timeout(host->rrdpush_sender_socket, http, HTTP_HEADER_SIZE, 0, timeout) == -1) {
582 +#endif
583 error("STREAM %s [send to %s]: remote netdata does not respond.", host->hostname, connected_to);
584 rrdpush_sender_thread_close_socket(host);
585 return 0;
@@ -565,6 +649,12 @@ void *rrdpush_sender_thread(void *ptr) {
649 return NULL;
650 }
651
652 +#ifdef ENABLE_HTTPS
653 + if (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE ){
654 + security_start_ssl(1);
655 + }
656 +#endif
657 +
658 info("STREAM %s [send]: thread created (task id %d)", host->hostname, gettid());
659
660 int timeout = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "timeout seconds", 60);
@@ -852,6 +942,9 @@ static int rrdpush_receive(int fd
942 , int update_every
943 , char *client_ip
944 , char *client_port
945 +#ifdef ENABLE_HTTPS
946 + , struct netdata_ssl *ssl
947 +#endif
948 ) {
949 RRDHOST *host;
950 int history = default_rrd_history_entries;
@@ -965,7 +1058,11 @@ static int rrdpush_receive(int fd
1058 snprintfz(cd.cmd, PLUGINSD_CMD_MAX, "%s:%s", client_ip, client_port);
1059
1060 info("STREAM %s [receive from [%s]:%s]: initializing communication...", host->hostname, client_ip, client_port);
1061 +#ifdef ENABLE_HTTPS
1062 + if(send_timeout(ssl,fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
1063 +#else
1064 if(send_timeout(fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
1065 +#endif
1066 log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "FAILED - CANNOT REPLY");
1067 error("STREAM %s [receive from [%s]:%s]: cannot send ready command.", host->hostname, client_ip, client_port);
1068 close(fd);
@@ -1058,6 +1155,9 @@ struct rrdpush_thread {
1155 char *program_version;
1156 struct rrdhost_system_info *system_info;
1157 int update_every;
1158 +#ifdef ENABLE_HTTPS
1159 + struct netdata_ssl ssl;
1160 +#endif
1161 };
1162
1163 static void rrdpush_receiver_thread_cleanup(void *ptr) {
@@ -1079,7 +1179,13 @@ static void rrdpush_receiver_thread_cleanup(void *ptr) {
1179 freez(rpt->client_port);
1180 freez(rpt->program_name);
1181 freez(rpt->program_version);
1182 +#ifdef ENABLE_HTTPS
1183 + if(rpt->ssl.conn){
1184 + SSL_free(rpt->ssl.conn);
1185 + }
1186 +#endif
1187 freez(rpt);
1188 +
1189 }
1190 }
1191
@@ -1104,6 +1210,7 @@ static void *rrdpush_receiver_thread(void *ptr) {
1210 , rpt->update_every
1211 , rpt->client_ip
1212 , rpt->client_port
1213 + , &rpt->ssl
1214 );
1215
1216 netdata_thread_cleanup_pop(1);
@@ -1294,6 +1401,13 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url
1401 rpt->client_port = strdupz(w->client_port);
1402 rpt->update_every = update_every;
1403 rpt->system_info = system_info;
1404 +#ifdef ENABLE_HTTPS
1405 + rpt->ssl.conn = w->ssl.conn;
1406 + rpt->ssl.flags = w->ssl.flags;
1407 +
1408 + w->ssl.conn = NULL;
1409 + w->ssl.flags = NETDATA_SSL_START;
1410 +#endif
1411
1412 if(w->user_agent && w->user_agent[0]) {
1413 char *t = strchr(w->user_agent, '/');
streaming/stream.conf
+12 -1
@@ -17,7 +17,7 @@
17 # Where is the receiving netdata?
18 # A space separated list of:
19 #
20 - # [PROTOCOL:]HOST[%INTERFACE][:PORT]
20 + # [PROTOCOL:]HOST[%INTERFACE][:PORT][:SSL]
21 #
22 # If many are given, the first available will get the metrics.
23 #
@@ -26,10 +26,21 @@
26 # IPv6 IPs should be given with brackets [ip:address]
27 # INTERFACE = the network interface to use (only for IPv6)
28 # PORT = the port number or service name (/etc/services)
29 + # SSL = when this word appear at the end of the destination string
30 + # the Netdata will do encrypt connection with the master.
31 #
32 # This communication is not HTTP (it cannot be proxied by web proxies).
33 destination =
34
35 + # Skip Certificate verification?
36 + #
37 + # The netdata slave is configurated to avoid invalid SSL/TLS certificate,
38 + # so certificates that are self-signed or expired will stop the streaming.
39 + # Case the server certificate is not valid, you can enable the use of
40 + # 'bad' certificates setting the next option as 'yes'.
41 + #
42 + #ssl skip certificate verification = yes
43 +
44 # The API_KEY to use (as the sender)
45 api key =
46
web/server/README.md
+65 -6
@@ -33,15 +33,15 @@ The ports to bind are controlled via `[web].bind to`, like this:
33 ```
34 [web]
35 default port = 19999
36 - bind to = 127.0.0.1=dashboard 10.1.1.1:19998=management|netdata.conf hostname:19997=badges [::]:19996=streaming localhost:19995=registry *:http=dashboard unix:/tmp/netdata.sock
36 + bind to = 127.0.0.1=dashboard^SSL=optional 10.1.1.1:19998=management|netdata.conf hostname:19997=badges [::]:19996=streaming^SSL=force localhost:19995=registry *:http=dashboard unix:/tmp/netdata.sock
37 ```
38
39 Using the above, netdata will bind to:
40
41 -- IPv4 127.0.0.1 at port 19999 (port was used from `default port`). Only the UI (dashboard) and the read API will be accessible on this port.
41 +- IPv4 127.0.0.1 at port 19999 (port was used from `default port`). Only the UI (dashboard) and the read API will be accessible on this port. Both HTTP and HTTPS requests will be accepted.
42 - IPv4 10.1.1.1 at port 19998. The management API and netdata.conf will be accessible on this port.
43 - All the IPs `hostname` resolves to (both IPv4 and IPv6 depending on the resolved IPs) at port 19997. Only badges will be accessible on this port.
44 -- All IPv6 IPs at port 19996. Only metric streaming requests from other netdata agents will be accepted on this port.
44 +- All IPv6 IPs at port 19996. Only metric streaming requests from other netdata agents will be accepted on this port. Only encrypted streams will be allowed (i.e. slaves also need to be [configured for TLS](../../streaming).
45 - All the IPs `localhost` resolves to (both IPv4 and IPv6 depending the resolved IPs) at port 19996. This port will only accept registry API requests.
46 - All IPv4 and IPv6 IPs at port `http` as set in `/etc/services`. Only the UI (dashboard) and the read API will be accessible on this port.
47 - Unix domain socket `/tmp/netdata.sock`. All requests are serviceable on this socket.
@@ -57,6 +57,65 @@ The API requests are serviced as follows:
57 - `badges` gives access only to the badges API calls.
58 - `management` gives access only to the management API calls.
59
60 +### Enabling TLS support
61 +
62 +
63 +Netdata since version 1.16 supports encrypted HTTP connections to the web server and encryption of the data stream between a slave and a master.
64 +Inbound unix socket connections are unaffected, regardless of the SSL settings.
65 +To enable SSL, provide the path to your certificate and private key in the `[web]` section of `netdata.conf`:
66 +
67 +```
68 +[web]
69 + ssl key = /etc/netdata/ssl/key.pem
70 + ssl certificate = /etc/netdata/ssl/cert.pem
71 +```
72 +
73 +Both files must be readable by the netdata user. If any of the two files does not exist or is unreadable, Netdata falls back to HTTP.
74 +
75 +For a master/slave connection, only the master needs these settings.
76 +
77 +For test purposes, you can generate self-signed certificates with the following command:
78 +
79 +```
80 +$ openssl req -newkey rsa:2048 -nodes -sha512 -x509 -days 365 -keyout key.pem -out cert.pem
81 +```
82 +
83 +TIP: If you use 4096 bits for the key and the certificate, netdata will need more CPU to process the whole communication.
84 +rsa4096 can be until 4 times slower than rsa2048, so we recommend using 2048 bits. You can verify the difference by running
85 +
86 +```
87 +$ openssl speed rsa2048 rsa4096
88 +```
89 +
90 +#### SSL enforcement
91 +
92 +When the certificates are defined and unless any other options are provided, a Netdata server will:
93 +- Redirect all incoming HTTP web server requests to HTTPS. Applies to the dashboard, the API, netdata.conf and badges.
94 +- Allow incoming slave connections to use both unencrypted and encrypted communications for streaming.
95 +
96 +To change this behavior, you need to modify the `bind to` setting in the `[web]` section of `netdata.conf`.
97 +At the end of each port definition, you can append `^SSL=force` or `^SSL=optional`. What happens with these settings differs, depending on whether the port is used for HTTP/S requests, or for streaming.
98 +
99 +SSL setting | HTTP requests | HTTPS requests | Unencrypted Streams | Encrypted Streams
100 +:------:|:-----:|:-----:|:-----:|:--------
101 +none | Redirected to HTTPS | Accepted | Accepted | Accepted
102 +`force` | Redirected to HTTPS | Accepted | Denied | Accepted
103 +`optional` | Accepted | Accepted | Accepted | Accepted
104 +
105 +Example:
106 +
107 +```
108 +[web]
109 + bind to = *=dashboard|registry|badges|management|streaming|netdata.conf^SSL=force
110 +```
111 +
112 +For information how to configure the slaves to use TLS, check [securing the communication](../../streaming#securing-the-communication) in the streaming documentation.
113 +You will find there additional details on the expected behavior for client and server nodes, when their respective SSL options are enabled.
114 +
115 +#### SSL error
116 +
117 +It is possible that when you start to use the Netdata with SSL some erros will be register in the logs, this happens due possible incompatibilities between the browser options related to SSL like Ciphers and TLS/SSL version and the Netdata internal configuration. The most common error would be `error:00000006:lib(0):func(0):EVP lib`. In a near future the Netdata will allow our users to change the internal configuration to avoid errors like this, but until there we are setting the most common and safety options to the communication.
118 +
119 ### Access lists
120
121 Netdata supports access lists in `netdata.conf`:
@@ -96,10 +155,10 @@ setting | default | info
155 :------:|:-------:|:----
156 ses max window | `15` | See [single exponential smoothing](../api/queries/des/)
157 des max window | `15` | See [double exponential smoothing](../api/queries/des/)
99 -listen backlog | `4096` | The port backlog. Check `man 2 listen`.
100 -web files owner | `netdata` | The user that owns the web static files. Netdata will refuse to serve a file that is not owned by this user, even if it has read access to that file. If the user given is not found, netdata will only serve files owned by user given in `run as user`.
158 +listen backlog | `4096` | The port backlog. Check `man 2 listen`.
159 +web files owner | `netdata` | The user that owns the web static files. Netdata will refuse to serve a file that is not owned by this user, even if it has read access to that file. If the user given is not found, netdata will only serve files owned by user given in `run as user`.
160 web files group | `netdata` | If this is set, Netdata will check if the file is owned by this group and refuse to serve the file if it's not.
102 -disconnect idle clients after seconds | `60` | The time in seconds to disconnect web clients after being totally idle.
161 +disconnect idle clients after seconds | `60` | The time in seconds to disconnect web clients after being totally idle.
162 timeout for first request | `60` | How long to wait for a client to send a request before closing the socket. Prevents slow request attacks.
163 accept a streaming request every seconds | `0` | Can be used to set a limit on how often a master Netdata server will accept streaming requests from the slaves in a [streaming and replication setup](../../streaming)
164 respect do not track policy | `no` | If set to `yes`, will respect the client's browser preferences on storing cookies.
web/server/static/static-threaded.c
+64 -2
@@ -152,10 +152,67 @@ static void *web_server_add_callback(POLLINFO *pi, short int *events, void *data
152 struct web_client *w = web_client_create_on_fd(pi->fd, pi->client_ip, pi->client_port, pi->port_acl);
153 w->pollinfo_slot = pi->slot;
154
155 - if(unlikely(pi->socktype == AF_UNIX))
155 + if ( !strncmp(pi->client_port,"UNIX",4)){
156 web_client_set_unix(w);
157 - else
157 + } else {
158 web_client_set_tcp(w);
159 + }
160 +
161 +#ifdef ENABLE_HTTPS
162 + if ((!web_client_check_unix(w)) && ( netdata_srv_ctx )) {
163 + if( sock_delnonblock(w->ifd) < 0 ){
164 + error("Web server cannot remove the non-blocking flag from socket %d",w->ifd);
165 + }
166 +
167 + //Read the first 7 bytes from the message, but the message
168 + //is not removed from the queue, because we are using MSG_PEEK
169 + char test[8];
170 + if ( recv(w->ifd,test, 7,MSG_PEEK) == 7 ) {
171 + test[7] = 0x00;
172 + }
173 + else {
174 + //Case I do not have success to read 7 bytes,
175 + //this means that the mensage was not completely read, so
176 + //I cannot identify it yet.
177 + sock_setnonblock(w->ifd);
178 + return w;
179 + }
180 +
181 + //The next two ifs are not together because I am reusing SSL structure
182 + if (!w->ssl.conn)
183 + {
184 + w->ssl.conn = SSL_new(netdata_srv_ctx);
185 + if ( w->ssl.conn ) {
186 + SSL_set_accept_state(w->ssl.conn);
187 + } else {
188 + error("Failed to create SSL context on socket fd %d.", w->ifd);
189 + if (test[0] < 0x18){
190 + WEB_CLIENT_IS_DEAD(w);
191 + sock_setnonblock(w->ifd);
192 + return w;
193 + }
194 + }
195 + }
196 +
197 + if (w->ssl.conn) {
198 + if (SSL_set_fd(w->ssl.conn, w->ifd) != 1) {
199 + error("Failed to set the socket to the SSL on socket fd %d.", w->ifd);
200 + //The client is not set dead, because I received a normal HTTP request
201 + //instead a Client Hello(HTTPS).
202 + if ( test[0] < 0x18 ){
203 + WEB_CLIENT_IS_DEAD(w);
204 + }
205 + }
206 + else{
207 + w->ssl.flags = security_process_accept(w->ssl.conn, (int)test[0]);
208 + }
209 + }
210 +
211 + sock_setnonblock(w->ifd);
212 + } else{
213 + w->ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
214 + }
215 +#endif
216
217 debug(D_WEB_CLIENT, "%llu: ADDED CLIENT FD %d", w->id, pi->fd);
218 return w;
@@ -189,6 +246,8 @@ static int web_server_rcv_callback(POLLINFO *pi, short int *events) {
246 struct web_client *w = (struct web_client *)pi->data;
247 int fd = pi->fd;
248
249 + //BRING IT TO HERE
250 +
251 if(unlikely(web_client_receive(w) < 0))
252 return -1;
253
@@ -398,6 +457,9 @@ void *socket_listen_main_static_threaded(void *ptr) {
457 if(!api_sockets.opened)
458 fatal("LISTENER: no listen sockets available.");
459
460 +#ifdef ENABLE_HTTPS
461 + security_start_ssl(0);
462 +#endif
463 // 6 threads is the optimal value
464 // since 6 are the parallel connections browsers will do
465 // so, if the machine has more CPUs, avoid using resources unnecessarily
web/server/web_client.c
+166 -14
@@ -143,7 +143,9 @@ void web_client_request_done(struct web_client *w) {
143 debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
144
145 if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) {
146 - if (w->ifd != -1) close(w->ifd);
146 + if (w->ifd != -1){
147 + close(w->ifd);
148 + }
149 }
150
151 w->ifd = w->ofd;
@@ -688,6 +690,9 @@ const char *web_response_code_to_string(int code) {
690 case 200:
691 return "OK";
692
693 + case 301:
694 + return "Moved Permanently";
695 +
696 case 307:
697 return "Temporary Redirect";
698
@@ -724,15 +729,21 @@ const char *web_response_code_to_string(int code) {
729 }
730
731 static inline char *http_header_parse(struct web_client *w, char *s, int parse_useragent) {
727 - static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0, hash_donottrack = 0, hash_useragent = 0, hash_authorization = 0;
732 + static uint32_t hash_origin = 0, hash_connection = 0, hash_donottrack = 0, hash_useragent = 0, hash_authorization = 0, hash_host = 0;
733 +#ifdef NETDATA_WITH_ZLIB
734 + static uint32_t hash_accept_encoding = 0;
735 +#endif
736
737 if(unlikely(!hash_origin)) {
738 hash_origin = simple_uhash("Origin");
739 hash_connection = simple_uhash("Connection");
740 +#ifdef NETDATA_WITH_ZLIB
741 hash_accept_encoding = simple_uhash("Accept-Encoding");
742 +#endif
743 hash_donottrack = simple_uhash("DNT");
744 hash_useragent = simple_uhash("User-Agent");
745 hash_authorization = simple_uhash("X-Auth-Token");
746 + hash_host = simple_uhash("Host");
747 }
748
749 char *e = s;
@@ -780,6 +791,9 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
791 } else if(hash == hash_authorization&& !strcasecmp(s, "X-Auth-Token")) {
792 w->auth_bearer_token = strdupz(v);
793 }
794 + else if(hash == hash_host && !strcasecmp(s, "Host")){
795 + strncpyz(w->host, v, (ve - v));
796 + }
797 #ifdef NETDATA_WITH_ZLIB
798 else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
799 if(web_enable_gzip) {
@@ -807,7 +821,8 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
821 typedef enum {
822 HTTP_VALIDATION_OK,
823 HTTP_VALIDATION_NOT_SUPPORTED,
810 - HTTP_VALIDATION_INCOMPLETE
824 + HTTP_VALIDATION_INCOMPLETE,
825 + HTTP_VALIDATION_REDIRECT
826 } HTTP_VALIDATION;
827
828 static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
@@ -847,6 +862,35 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
862 w->mode = WEB_CLIENT_MODE_OPTIONS;
863 }
864 else if(!strncmp(s, "STREAM ", 7)) {
865 +#ifdef ENABLE_HTTPS
866 + if ( (w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)){
867 + w->header_parse_tries = 0;
868 + w->header_parse_last_size = 0;
869 + web_client_disable_wait_receive(w);
870 + char hostname[256];
871 + char *copyme = strstr(s,"hostname=");
872 + if ( copyme ){
873 + copyme += 9;
874 + char *end = strchr(copyme,'&');
875 + if(end){
876 + size_t length = end - copyme;
877 + memcpy(hostname,copyme,length);
878 + hostname[length] = 0X00;
879 + }
880 + else{
881 + memcpy(hostname,"not available",13);
882 + hostname[13] = 0x00;
883 + }
884 + }
885 + else{
886 + memcpy(hostname,"not available",13);
887 + hostname[13] = 0x00;
888 + }
889 + error("The server is configured to always use encrypt connection, please enable the SSL on slave with hostname '%s'.",hostname);
890 + return HTTP_VALIDATION_NOT_SUPPORTED;
891 + }
892 +#endif
893 +
894 encoded_url = s = &s[7];
895 w->mode = WEB_CLIENT_MODE_STREAM;
896 }
@@ -899,6 +943,16 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
943 // copy the URL - we are going to overwrite parts of it
944 // TODO -- ideally we we should avoid copying buffers around
945 strncpyz(w->last_url, w->decoded_url, NETDATA_WEB_REQUEST_URL_SIZE);
946 +#ifdef ENABLE_HTTPS
947 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
948 + if ((w->ssl.conn) && ((w->ssl.flags & NETDATA_SSL_NO_HANDSHAKE) && (netdata_use_ssl_on_http & NETDATA_SSL_FORCE) && (w->mode != WEB_CLIENT_MODE_STREAM)) ) {
949 + w->header_parse_tries = 0;
950 + w->header_parse_last_size = 0;
951 + web_client_disable_wait_receive(w);
952 + return HTTP_VALIDATION_REDIRECT;
953 + }
954 + }
955 +#endif
956
957 w->header_parse_tries = 0;
958 w->header_parse_last_size = 0;
@@ -918,6 +972,26 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
972 return HTTP_VALIDATION_INCOMPLETE;
973 }
974
975 +static inline ssize_t web_client_send_data(struct web_client *w,const void *buf,size_t len, int flags)
976 +{
977 + ssize_t bytes;
978 +#ifdef ENABLE_HTTPS
979 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
980 + if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
981 + bytes = SSL_write(w->ssl.conn,buf, len) ;
982 + } else {
983 + bytes = send(w->ofd,buf, len , flags);
984 + }
985 + } else {
986 + bytes = send(w->ofd,buf, len , flags);
987 + }
988 +#else
989 + bytes = send(w->ofd, buf, len, flags);
990 +#endif
991 +
992 + return bytes;
993 +}
994 +
995 static inline void web_client_send_http_header(struct web_client *w) {
996 if(unlikely(w->response.code != 200))
997 buffer_no_cacheable(w->response.data);
@@ -948,6 +1022,23 @@ static inline void web_client_send_http_header(struct web_client *w) {
1022 strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", tm);
1023 }
1024
1025 + char headerbegin[8328];
1026 + if (w->response.code == 301) {
1027 + memcpy(headerbegin,"\r\nLocation: https://",20);
1028 + size_t headerlength = strlen(w->host);
1029 + memcpy(&headerbegin[20],w->host,headerlength);
1030 + headerlength += 20;
1031 + size_t tmp = strlen(w->last_url);
1032 + memcpy(&headerbegin[headerlength],w->last_url,tmp);
1033 + headerlength += tmp;
1034 + memcpy(&headerbegin[headerlength],"\r\n",2);
1035 + headerlength += 2;
1036 + headerbegin[headerlength] = 0x00;
1037 + }else {
1038 + memcpy(headerbegin,"\r\n",2);
1039 + headerbegin[2]=0x00;
1040 + }
1041 +
1042 buffer_sprintf(w->response.header_output,
1043 "HTTP/1.1 %d %s\r\n"
1044 "Connection: %s\r\n"
@@ -955,13 +1046,14 @@ static inline void web_client_send_http_header(struct web_client *w) {
1046 "Access-Control-Allow-Origin: %s\r\n"
1047 "Access-Control-Allow-Credentials: true\r\n"
1048 "Content-Type: %s\r\n"
958 - "Date: %s\r\n"
1049 + "Date: %s%s"
1050 , w->response.code, code_msg
1051 , web_client_has_keepalive(w)?"keep-alive":"close"
1052 , VERSION
1053 , w->origin
1054 , content_type_string
1055 , date
1056 + , headerbegin
1057 );
1058
1059 if(unlikely(web_x_frame_options))
@@ -1046,6 +1138,37 @@ static inline void web_client_send_http_header(struct web_client *w) {
1138
1139 size_t count = 0;
1140 ssize_t bytes;
1141 +#ifdef ENABLE_HTTPS
1142 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1143 + if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
1144 + while((bytes = SSL_write(w->ssl.conn, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output))) < 0) {
1145 + count++;
1146 + if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
1147 + error("Cannot send HTTP headers to web client.");
1148 + break;
1149 + }
1150 + }
1151 + } else {
1152 + while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
1153 + count++;
1154 +
1155 + if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
1156 + error("Cannot send HTTP headers to web client.");
1157 + break;
1158 + }
1159 + }
1160 + }
1161 + } else {
1162 + while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
1163 + count++;
1164 +
1165 + if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
1166 + error("Cannot send HTTP headers to web client.");
1167 + break;
1168 + }
1169 + }
1170 + }
1171 +#else
1172 while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
1173 count++;
1174
@@ -1054,6 +1177,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
1177 break;
1178 }
1179 }
1180 +#endif
1181
1182 if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
1183 if(bytes > 0)
@@ -1303,7 +1427,16 @@ void web_client_process_request(struct web_client *w) {
1427 return;
1428 }
1429 break;
1306 -
1430 +#ifdef ENABLE_HTTPS
1431 + case HTTP_VALIDATION_REDIRECT:
1432 + {
1433 + buffer_flush(w->response.data);
1434 + w->response.data->contenttype = CT_TEXT_HTML;
1435 + buffer_strcat(w->response.data, "<!DOCTYPE html><!-- SPDX-License-Identifier: GPL-3.0-or-later --><html><body onload=\"window.location.href ='https://'+ window.location.hostname + ':' + window.location.port + window.location.pathname\">Redirecting to safety connection, case your browser does not support redirection, please click <a onclick=\"window.location.href ='https://'+ window.location.hostname + ':' + window.location.port + window.location.pathname\">here</a>.</body></html>");
1436 + w->response.code = 301;
1437 + break;
1438 + }
1439 +#endif
1440 case HTTP_VALIDATION_NOT_SUPPORTED:
1441 debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
1442
@@ -1373,9 +1506,11 @@ ssize_t web_client_send_chunk_header(struct web_client *w, size_t len)
1506 {
1507 debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len);
1508 char buf[24];
1376 - sprintf(buf, "%zX\r\n", len);
1377 -
1378 - ssize_t bytes = send(w->ofd, buf, strlen(buf), 0);
1509 + ssize_t bytes;
1510 + bytes = (ssize_t)sprintf(buf, "%zX\r\n", len);
1511 + buf[bytes] = 0x00;
1512 +
1513 + bytes = web_client_send_data(w,buf,strlen(buf),0);
1514 if(bytes > 0) {
1515 debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes);
1516 w->stats_sent_bytes += bytes;
@@ -1397,7 +1532,8 @@ ssize_t web_client_send_chunk_close(struct web_client *w)
1532 {
1533 //debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
1534
1400 - ssize_t bytes = send(w->ofd, "\r\n", 2, 0);
1535 + ssize_t bytes;
1536 + bytes = web_client_send_data(w,"\r\n",2,0);
1537 if(bytes > 0) {
1538 debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
1539 w->stats_sent_bytes += bytes;
@@ -1419,7 +1555,8 @@ ssize_t web_client_send_chunk_finalize(struct web_client *w)
1555 {
1556 //debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
1557
1422 - ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, 0);
1558 + ssize_t bytes;
1559 + bytes = web_client_send_data(w,"\r\n0\r\n\r\n",7,0);
1560 if(bytes > 0) {
1561 debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
1562 w->stats_sent_bytes += bytes;
@@ -1533,7 +1670,7 @@ ssize_t web_client_send_deflate(struct web_client *w)
1670
1671 debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t);
1672
1536 - len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
1673 + len = web_client_send_data(w,&w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
1674 if(len > 0) {
1675 w->stats_sent_bytes += len;
1676 w->response.zsent += len;
@@ -1589,7 +1726,7 @@ ssize_t web_client_send(struct web_client *w) {
1726 return 0;
1727 }
1728
1592 - bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
1729 + bytes = web_client_send_data(w,&w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
1730 if(likely(bytes > 0)) {
1731 w->stats_sent_bytes += bytes;
1732 w->response.sent += bytes;
@@ -1664,11 +1801,26 @@ ssize_t web_client_receive(struct web_client *w)
1801 if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
1802 return web_client_read_file(w);
1803
1804 + ssize_t bytes;
1805 + ssize_t left = w->response.data->size - w->response.data->len;
1806 +
1807 // do we have any space for more data?
1808 buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_RECEIVE_SIZE);
1809
1670 - ssize_t left = w->response.data->size - w->response.data->len;
1671 - ssize_t bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
1810 +#ifdef ENABLE_HTTPS
1811 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1812 + if ( ( w->ssl.conn ) && (!w->ssl.flags)) {
1813 + bytes = SSL_read(w->ssl.conn, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
1814 + }else {
1815 + bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
1816 + }
1817 + }
1818 + else{
1819 + bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
1820 + }
1821 +#else
1822 + bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
1823 +#endif
1824
1825 if(likely(bytes > 0)) {
1826 w->stats_received_bytes += bytes;
web/server/web_client.h
+4
@@ -129,6 +129,7 @@ struct web_client {
129
130 char decoded_url[NETDATA_WEB_REQUEST_URL_SIZE + 1]; // we decode the URL in this buffer
131 char last_url[NETDATA_WEB_REQUEST_URL_SIZE+1]; // we keep a copy of the decoded URL here
132 + char host[256];
133
134 struct timeval tv_in, tv_ready;
135
@@ -153,6 +154,9 @@ struct web_client {
154 // STATIC-THREADED WEB SERVER MEMBERS
155 size_t pollinfo_slot; // POLLINFO slot of the web client
156 size_t pollinfo_filecopy_slot; // POLLINFO slot of the file read
157 +#ifdef ENABLE_HTTPS
158 + struct netdata_ssl ssl;
159 +#endif
160 };
161
162 extern uid_t web_files_uid(void);
web/server/web_client_cache.c
+38
@@ -6,6 +6,18 @@
6 // ----------------------------------------------------------------------------
7 // allocate and free web_clients
8
9 +#ifdef ENABLE_HTTPS
10 +
11 +static void web_client_reuse_ssl(struct web_client *w) {
12 + if (netdata_srv_ctx) {
13 + if (w->ssl.conn) {
14 + SSL_clear(w->ssl.conn);
15 + }
16 + }
17 +}
18 +#endif
19 +
20 +
21 static void web_client_zero(struct web_client *w) {
22 // zero everything about it - but keep the buffers
23
@@ -35,6 +47,14 @@ static void web_client_free(struct web_client *w) {
47 buffer_free(w->response.header);
48 buffer_free(w->response.data);
49 freez(w->user_agent);
50 +#ifdef ENABLE_HTTPS
51 + if ((!web_client_check_unix(w)) && ( netdata_srv_ctx )) {
52 + if (w->ssl.conn) {
53 + SSL_free(w->ssl.conn);
54 + w->ssl.conn = NULL;
55 + }
56 + }
57 +#endif
58 freez(w);
59 }
60
@@ -159,12 +179,25 @@ struct web_client *web_client_get_from_cache_or_allocate() {
179 if(w->prev) w->prev->next = w->next;
180 if(w->next) w->next->prev = w->prev;
181 web_clients_cache.avail_count--;
182 +#ifdef ENABLE_HTTPS
183 + web_client_reuse_ssl(w);
184 + SSL *ssl = w->ssl.conn;
185 +#endif
186 web_client_zero(w);
187 web_clients_cache.reused++;
188 +#ifdef ENABLE_HTTPS
189 + w->ssl.conn = ssl;
190 + w->ssl.flags = NETDATA_SSL_START;
191 + debug(D_WEB_CLIENT_ACCESS,"Reusing SSL structure with (w->ssl = NULL, w->accepted = %d)",w->ssl.flags);
192 +#endif
193 }
194 else {
195 // allocate it
196 w = web_client_alloc();
197 +#ifdef ENABLE_HTTPS
198 + w->ssl.flags = NETDATA_SSL_START;
199 + debug(D_WEB_CLIENT_ACCESS,"Starting SSL structure with (w->ssl = NULL, w->accepted = %d)",w->ssl.flags);
200 +#endif
201 web_clients_cache.allocated++;
202 }
203
@@ -205,6 +238,11 @@ void web_client_release(struct web_client *w) {
238 if (w->ifd != -1) close(w->ifd);
239 if (w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
240 w->ifd = w->ofd = -1;
241 +#ifdef ENABLE_HTTPS
242 + web_client_reuse_ssl(w);
243 + w->ssl.flags = NETDATA_SSL_START;
244 +#endif
245 +
246 }
247
248 // unlink it from the used
web/server/web_server.c
-2
@@ -138,5 +138,3 @@ void web_client_initialize_connection(struct web_client *w) {
138
139 web_client_cache_verify(0);
140 }
141 -
142 -