summaryrefslogtreecommitdiffstats
path: root/web/server
diff options
context:
space:
mode:
Diffstat (limited to 'web/server')
-rw-r--r--web/server/README.md71
-rw-r--r--web/server/static/static-threaded.c68
-rw-r--r--web/server/web_client.c182
-rw-r--r--web/server/web_client.h4
-rw-r--r--web/server/web_client_cache.c38
-rw-r--r--web/server/web_server.c2
6 files changed, 341 insertions, 24 deletions
diff --git a/web/server/README.md b/web/server/README.md
index 7d74c181e..df29f331f 100644
--- a/web/server/README.md
+++ b/web/server/README.md
@@ -33,15 +33,15 @@ The ports to bind are controlled via `[web].bind to`, like this:
```
[web]
default port = 19999
- 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
+ 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
```
Using the above, netdata will bind to:
-- 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.
+- 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.
- IPv4 10.1.1.1 at port 19998. The management API and netdata.conf will be accessible on this port.
- 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.
-- All IPv6 IPs at port 19996. Only metric streaming requests from other netdata agents will be accepted on this port.
+- 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).
- 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.
- 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.
- Unix domain socket `/tmp/netdata.sock`. All requests are serviceable on this socket.
@@ -57,6 +57,65 @@ The API requests are serviced as follows:
- `badges` gives access only to the badges API calls.
- `management` gives access only to the management API calls.
+### Enabling TLS support
+
+
+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.
+Inbound unix socket connections are unaffected, regardless of the SSL settings.
+To enable SSL, provide the path to your certificate and private key in the `[web]` section of `netdata.conf`:
+
+```
+[web]
+ ssl key = /etc/netdata/ssl/key.pem
+ ssl certificate = /etc/netdata/ssl/cert.pem
+```
+
+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.
+
+For a master/slave connection, only the master needs these settings.
+
+For test purposes, you can generate self-signed certificates with the following command:
+
+```
+$ openssl req -newkey rsa:2048 -nodes -sha512 -x509 -days 365 -keyout key.pem -out cert.pem
+```
+
+TIP: If you use 4096 bits for the key and the certificate, netdata will need more CPU to process the whole communication.
+rsa4096 can be until 4 times slower than rsa2048, so we recommend using 2048 bits. You can verify the difference by running
+
+```
+$ openssl speed rsa2048 rsa4096
+```
+
+#### SSL enforcement
+
+When the certificates are defined and unless any other options are provided, a Netdata server will:
+- Redirect all incoming HTTP web server requests to HTTPS. Applies to the dashboard, the API, netdata.conf and badges.
+- Allow incoming slave connections to use both unencrypted and encrypted communications for streaming.
+
+To change this behavior, you need to modify the `bind to` setting in the `[web]` section of `netdata.conf`.
+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.
+
+SSL setting | HTTP requests | HTTPS requests | Unencrypted Streams | Encrypted Streams
+:------:|:-----:|:-----:|:-----:|:--------
+none | Redirected to HTTPS | Accepted | Accepted | Accepted
+`force` | Redirected to HTTPS | Accepted | Denied | Accepted
+`optional` | Accepted | Accepted | Accepted | Accepted
+
+Example:
+
+```
+[web]
+ bind to = *=dashboard|registry|badges|management|streaming|netdata.conf^SSL=force
+```
+
+For information how to configure the slaves to use TLS, check [securing the communication](../../streaming#securing-the-communication) in the streaming documentation.
+You will find there additional details on the expected behavior for client and server nodes, when their respective SSL options are enabled.
+
+#### SSL error
+
+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.
+
### Access lists
Netdata supports access lists in `netdata.conf`:
@@ -96,10 +155,10 @@ setting | default | info
:------:|:-------:|:----
ses max window | `15` | See [single exponential smoothing](../api/queries/des/)
des max window | `15` | See [double exponential smoothing](../api/queries/des/)
-listen backlog | `4096` | The port backlog. Check `man 2 listen`.
-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`.
+listen backlog | `4096` | The port backlog. Check `man 2 listen`.
+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`.
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.
-disconnect idle clients after seconds | `60` | The time in seconds to disconnect web clients after being totally idle.
+disconnect idle clients after seconds | `60` | The time in seconds to disconnect web clients after being totally idle.
timeout for first request | `60` | How long to wait for a client to send a request before closing the socket. Prevents slow request attacks.
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)
respect do not track policy | `no` | If set to `yes`, will respect the client's browser preferences on storing cookies.
diff --git a/web/server/static/static-threaded.c b/web/server/static/static-threaded.c
index 1945b8a3e..5dda27000 100644
--- a/web/server/static/static-threaded.c
+++ b/web/server/static/static-threaded.c
@@ -152,10 +152,67 @@ static void *web_server_add_callback(POLLINFO *pi, short int *events, void *data
struct web_client *w = web_client_create_on_fd(pi->fd, pi->client_ip, pi->client_port, pi->port_acl);
w->pollinfo_slot = pi->slot;
- if(unlikely(pi->socktype == AF_UNIX))
+ if ( !strncmp(pi->client_port,"UNIX",4)){
web_client_set_unix(w);
- else
+ } else {
web_client_set_tcp(w);
+ }
+
+#ifdef ENABLE_HTTPS
+ if ((!web_client_check_unix(w)) && ( netdata_srv_ctx )) {
+ if( sock_delnonblock(w->ifd) < 0 ){
+ error("Web server cannot remove the non-blocking flag from socket %d",w->ifd);
+ }
+
+ //Read the first 7 bytes from the message, but the message
+ //is not removed from the queue, because we are using MSG_PEEK
+ char test[8];
+ if ( recv(w->ifd,test, 7,MSG_PEEK) == 7 ) {
+ test[7] = 0x00;
+ }
+ else {
+ //Case I do not have success to read 7 bytes,
+ //this means that the mensage was not completely read, so
+ //I cannot identify it yet.
+ sock_setnonblock(w->ifd);
+ return w;
+ }
+
+ //The next two ifs are not together because I am reusing SSL structure
+ if (!w->ssl.conn)
+ {
+ w->ssl.conn = SSL_new(netdata_srv_ctx);
+ if ( w->ssl.conn ) {
+ SSL_set_accept_state(w->ssl.conn);
+ } else {
+ error("Failed to create SSL context on socket fd %d.", w->ifd);
+ if (test[0] < 0x18){
+ WEB_CLIENT_IS_DEAD(w);
+ sock_setnonblock(w->ifd);
+ return w;
+ }
+ }
+ }
+
+ if (w->ssl.conn) {
+ if (SSL_set_fd(w->ssl.conn, w->ifd) != 1) {
+ error("Failed to set the socket to the SSL on socket fd %d.", w->ifd);
+ //The client is not set dead, because I received a normal HTTP request
+ //instead a Client Hello(HTTPS).
+ if ( test[0] < 0x18 ){
+ WEB_CLIENT_IS_DEAD(w);
+ }
+ }
+ else{
+ w->ssl.flags = security_process_accept(w->ssl.conn, (int)test[0]);
+ }
+ }
+
+ sock_setnonblock(w->ifd);
+ } else{
+ w->ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
+ }
+#endif
debug(D_WEB_CLIENT, "%llu: ADDED CLIENT FD %d", w->id, pi->fd);
return w;
@@ -189,6 +246,8 @@ static int web_server_rcv_callback(POLLINFO *pi, short int *events) {
struct web_client *w = (struct web_client *)pi->data;
int fd = pi->fd;
+ //BRING IT TO HERE
+
if(unlikely(web_client_receive(w) < 0))
return -1;
@@ -398,6 +457,9 @@ void *socket_listen_main_static_threaded(void *ptr) {
if(!api_sockets.opened)
fatal("LISTENER: no listen sockets available.");
+#ifdef ENABLE_HTTPS
+ security_start_ssl(NETDATA_SSL_CONTEXT_SERVER);
+#endif
// 6 threads is the optimal value
// since 6 are the parallel connections browsers will do
// so, if the machine has more CPUs, avoid using resources unnecessarily
@@ -412,7 +474,7 @@ void *socket_listen_main_static_threaded(void *ptr) {
if(static_threaded_workers_count < 1) static_threaded_workers_count = 1;
- size_t max_sockets = (size_t)config_get_number(CONFIG_SECTION_WEB, "web server max sockets", (long long int)(rlimit_nofile.rlim_cur / 2));
+ size_t max_sockets = (size_t)config_get_number(CONFIG_SECTION_WEB, "web server max sockets", (long long int)(rlimit_nofile.rlim_cur / 4));
static_workers_private_data = callocz((size_t)static_threaded_workers_count, sizeof(struct web_server_static_threaded_worker));
diff --git a/web/server/web_client.c b/web/server/web_client.c
index 3dc6ec82b..bd275f5e5 100644
--- a/web/server/web_client.c
+++ b/web/server/web_client.c
@@ -143,7 +143,9 @@ void web_client_request_done(struct web_client *w) {
debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) {
- if (w->ifd != -1) close(w->ifd);
+ if (w->ifd != -1){
+ close(w->ifd);
+ }
}
w->ifd = w->ofd;
@@ -688,6 +690,9 @@ const char *web_response_code_to_string(int code) {
case 200:
return "OK";
+ case 301:
+ return "Moved Permanently";
+
case 307:
return "Temporary Redirect";
@@ -724,15 +729,21 @@ const char *web_response_code_to_string(int code) {
}
static inline char *http_header_parse(struct web_client *w, char *s, int parse_useragent) {
- static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0, hash_donottrack = 0, hash_useragent = 0, hash_authorization = 0;
+ static uint32_t hash_origin = 0, hash_connection = 0, hash_donottrack = 0, hash_useragent = 0, hash_authorization = 0, hash_host = 0;
+#ifdef NETDATA_WITH_ZLIB
+ static uint32_t hash_accept_encoding = 0;
+#endif
if(unlikely(!hash_origin)) {
hash_origin = simple_uhash("Origin");
hash_connection = simple_uhash("Connection");
+#ifdef NETDATA_WITH_ZLIB
hash_accept_encoding = simple_uhash("Accept-Encoding");
+#endif
hash_donottrack = simple_uhash("DNT");
hash_useragent = simple_uhash("User-Agent");
hash_authorization = simple_uhash("X-Auth-Token");
+ hash_host = simple_uhash("Host");
}
char *e = s;
@@ -780,6 +791,9 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
} else if(hash == hash_authorization&& !strcasecmp(s, "X-Auth-Token")) {
w->auth_bearer_token = strdupz(v);
}
+ else if(hash == hash_host && !strcasecmp(s, "Host")){
+ strncpyz(w->host, v, (ve - v));
+ }
#ifdef NETDATA_WITH_ZLIB
else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
if(web_enable_gzip) {
@@ -807,7 +821,12 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
typedef enum {
HTTP_VALIDATION_OK,
HTTP_VALIDATION_NOT_SUPPORTED,
+#ifdef ENABLE_HTTPS
+ HTTP_VALIDATION_INCOMPLETE,
+ HTTP_VALIDATION_REDIRECT
+#else
HTTP_VALIDATION_INCOMPLETE
+#endif
} HTTP_VALIDATION;
static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
@@ -847,6 +866,35 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
w->mode = WEB_CLIENT_MODE_OPTIONS;
}
else if(!strncmp(s, "STREAM ", 7)) {
+#ifdef ENABLE_HTTPS
+ if ( (w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)){
+ w->header_parse_tries = 0;
+ w->header_parse_last_size = 0;
+ web_client_disable_wait_receive(w);
+ char hostname[256];
+ char *copyme = strstr(s,"hostname=");
+ if ( copyme ){
+ copyme += 9;
+ char *end = strchr(copyme,'&');
+ if(end){
+ size_t length = end - copyme;
+ memcpy(hostname,copyme,length);
+ hostname[length] = 0X00;
+ }
+ else{
+ memcpy(hostname,"not available",13);
+ hostname[13] = 0x00;
+ }
+ }
+ else{
+ memcpy(hostname,"not available",13);
+ hostname[13] = 0x00;
+ }
+ error("The server is configured to always use encrypt connection, please enable the SSL on slave with hostname '%s'.",hostname);
+ return HTTP_VALIDATION_NOT_SUPPORTED;
+ }
+#endif
+
encoded_url = s = &s[7];
w->mode = WEB_CLIENT_MODE_STREAM;
}
@@ -899,6 +947,16 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
// copy the URL - we are going to overwrite parts of it
// TODO -- ideally we we should avoid copying buffers around
strncpyz(w->last_url, w->decoded_url, NETDATA_WEB_REQUEST_URL_SIZE);
+#ifdef ENABLE_HTTPS
+ if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
+ 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)) ) {
+ w->header_parse_tries = 0;
+ w->header_parse_last_size = 0;
+ web_client_disable_wait_receive(w);
+ return HTTP_VALIDATION_REDIRECT;
+ }
+ }
+#endif
w->header_parse_tries = 0;
w->header_parse_last_size = 0;
@@ -918,6 +976,26 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
return HTTP_VALIDATION_INCOMPLETE;
}
+static inline ssize_t web_client_send_data(struct web_client *w,const void *buf,size_t len, int flags)
+{
+ ssize_t bytes;
+#ifdef ENABLE_HTTPS
+ if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
+ if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
+ bytes = SSL_write(w->ssl.conn,buf, len) ;
+ } else {
+ bytes = send(w->ofd,buf, len , flags);
+ }
+ } else {
+ bytes = send(w->ofd,buf, len , flags);
+ }
+#else
+ bytes = send(w->ofd, buf, len, flags);
+#endif
+
+ return bytes;
+}
+
static inline void web_client_send_http_header(struct web_client *w) {
if(unlikely(w->response.code != 200))
buffer_no_cacheable(w->response.data);
@@ -948,6 +1026,23 @@ static inline void web_client_send_http_header(struct web_client *w) {
strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", tm);
}
+ char headerbegin[8328];
+ if (w->response.code == 301) {
+ memcpy(headerbegin,"\r\nLocation: https://",20);
+ size_t headerlength = strlen(w->host);
+ memcpy(&headerbegin[20],w->host,headerlength);
+ headerlength += 20;
+ size_t tmp = strlen(w->last_url);
+ memcpy(&headerbegin[headerlength],w->last_url,tmp);
+ headerlength += tmp;
+ memcpy(&headerbegin[headerlength],"\r\n",2);
+ headerlength += 2;
+ headerbegin[headerlength] = 0x00;
+ }else {
+ memcpy(headerbegin,"\r\n",2);
+ headerbegin[2]=0x00;
+ }
+
buffer_sprintf(w->response.header_output,
"HTTP/1.1 %d %s\r\n"
"Connection: %s\r\n"
@@ -955,13 +1050,14 @@ static inline void web_client_send_http_header(struct web_client *w) {
"Access-Control-Allow-Origin: %s\r\n"
"Access-Control-Allow-Credentials: true\r\n"
"Content-Type: %s\r\n"
- "Date: %s\r\n"
+ "Date: %s%s"
, w->response.code, code_msg
, web_client_has_keepalive(w)?"keep-alive":"close"
, VERSION
, w->origin
, content_type_string
, date
+ , headerbegin
);
if(unlikely(web_x_frame_options))
@@ -1046,6 +1142,37 @@ static inline void web_client_send_http_header(struct web_client *w) {
size_t count = 0;
ssize_t bytes;
+#ifdef ENABLE_HTTPS
+ if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
+ if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
+ while((bytes = SSL_write(w->ssl.conn, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output))) < 0) {
+ count++;
+ if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
+ error("Cannot send HTTP headers to web client.");
+ break;
+ }
+ }
+ } else {
+ while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
+ count++;
+
+ if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
+ error("Cannot send HTTP headers to web client.");
+ break;
+ }
+ }
+ }
+ } else {
+ while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
+ count++;
+
+ if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
+ error("Cannot send HTTP headers to web client.");
+ break;
+ }
+ }
+ }
+#else
while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
count++;
@@ -1054,6 +1181,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
break;
}
}
+#endif
if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
if(bytes > 0)
@@ -1303,7 +1431,16 @@ void web_client_process_request(struct web_client *w) {
return;
}
break;
-
+#ifdef ENABLE_HTTPS
+ case HTTP_VALIDATION_REDIRECT:
+ {
+ buffer_flush(w->response.data);
+ w->response.data->contenttype = CT_TEXT_HTML;
+ 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>");
+ w->response.code = 301;
+ break;
+ }
+#endif
case HTTP_VALIDATION_NOT_SUPPORTED:
debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
@@ -1373,9 +1510,11 @@ ssize_t web_client_send_chunk_header(struct web_client *w, size_t len)
{
debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len);
char buf[24];
- sprintf(buf, "%zX\r\n", len);
-
- ssize_t bytes = send(w->ofd, buf, strlen(buf), 0);
+ ssize_t bytes;
+ bytes = (ssize_t)sprintf(buf, "%zX\r\n", len);
+ buf[bytes] = 0x00;
+
+ bytes = web_client_send_data(w,buf,strlen(buf),0);
if(bytes > 0) {
debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes);
w->stats_sent_bytes += bytes;
@@ -1397,7 +1536,8 @@ ssize_t web_client_send_chunk_close(struct web_client *w)
{
//debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
- ssize_t bytes = send(w->ofd, "\r\n", 2, 0);
+ ssize_t bytes;
+ bytes = web_client_send_data(w,"\r\n",2,0);
if(bytes > 0) {
debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
w->stats_sent_bytes += bytes;
@@ -1419,7 +1559,8 @@ ssize_t web_client_send_chunk_finalize(struct web_client *w)
{
//debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
- ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, 0);
+ ssize_t bytes;
+ bytes = web_client_send_data(w,"\r\n0\r\n\r\n",7,0);
if(bytes > 0) {
debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
w->stats_sent_bytes += bytes;
@@ -1533,7 +1674,7 @@ ssize_t web_client_send_deflate(struct web_client *w)
debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t);
- len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
+ len = web_client_send_data(w,&w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
if(len > 0) {
w->stats_sent_bytes += len;
w->response.zsent += len;
@@ -1589,7 +1730,7 @@ ssize_t web_client_send(struct web_client *w) {
return 0;
}
- bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
+ bytes = web_client_send_data(w,&w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
if(likely(bytes > 0)) {
w->stats_sent_bytes += bytes;
w->response.sent += bytes;
@@ -1664,11 +1805,26 @@ ssize_t web_client_receive(struct web_client *w)
if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
return web_client_read_file(w);
+ ssize_t bytes;
+ ssize_t left = w->response.data->size - w->response.data->len;
+
// do we have any space for more data?
buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_RECEIVE_SIZE);
- ssize_t left = w->response.data->size - w->response.data->len;
- ssize_t bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
+#ifdef ENABLE_HTTPS
+ if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
+ if ( ( w->ssl.conn ) && (!w->ssl.flags)) {
+ bytes = SSL_read(w->ssl.conn, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
+ }else {
+ bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
+ }
+ }
+ else{
+ bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
+ }
+#else
+ bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
+#endif
if(likely(bytes > 0)) {
w->stats_received_bytes += bytes;
diff --git a/web/server/web_client.h b/web/server/web_client.h
index 4263e252a..0a57e8d8e 100644
--- a/web/server/web_client.h
+++ b/web/server/web_client.h
@@ -129,6 +129,7 @@ struct web_client {
char decoded_url[NETDATA_WEB_REQUEST_URL_SIZE + 1]; // we decode the URL in this buffer
char last_url[NETDATA_WEB_REQUEST_URL_SIZE+1]; // we keep a copy of the decoded URL here
+ char host[256];
struct timeval tv_in, tv_ready;
@@ -153,6 +154,9 @@ struct web_client {
// STATIC-THREADED WEB SERVER MEMBERS
size_t pollinfo_slot; // POLLINFO slot of the web client
size_t pollinfo_filecopy_slot; // POLLINFO slot of the file read
+#ifdef ENABLE_HTTPS
+ struct netdata_ssl ssl;
+#endif
};
extern uid_t web_files_uid(void);
diff --git a/web/server/web_client_cache.c b/web/server/web_client_cache.c
index ab470560e..763e7e96a 100644
--- a/web/server/web_client_cache.c
+++ b/web/server/web_client_cache.c
@@ -6,6 +6,18 @@
// ----------------------------------------------------------------------------
// allocate and free web_clients
+#ifdef ENABLE_HTTPS
+
+static void web_client_reuse_ssl(struct web_client *w) {
+ if (netdata_srv_ctx) {
+ if (w->ssl.conn) {
+ SSL_clear(w->ssl.conn);
+ }
+ }
+}
+#endif
+
+
static void web_client_zero(struct web_client *w) {
// zero everything about it - but keep the buffers
@@ -35,6 +47,14 @@ static void web_client_free(struct web_client *w) {
buffer_free(w->response.header);
buffer_free(w->response.data);
freez(w->user_agent);
+#ifdef ENABLE_HTTPS
+ if ((!web_client_check_unix(w)) && ( netdata_srv_ctx )) {
+ if (w->ssl.conn) {
+ SSL_free(w->ssl.conn);
+ w->ssl.conn = NULL;
+ }
+ }
+#endif
freez(w);
}
@@ -159,12 +179,25 @@ struct web_client *web_client_get_from_cache_or_allocate() {
if(w->prev) w->prev->next = w->next;
if(w->next) w->next->prev = w->prev;
web_clients_cache.avail_count--;
+#ifdef ENABLE_HTTPS
+ web_client_reuse_ssl(w);
+ SSL *ssl = w->ssl.conn;
+#endif
web_client_zero(w);
web_clients_cache.reused++;
+#ifdef ENABLE_HTTPS
+ w->ssl.conn = ssl;
+ w->ssl.flags = NETDATA_SSL_START;
+ debug(D_WEB_CLIENT_ACCESS,"Reusing SSL structure with (w->ssl = NULL, w->accepted = %d)",w->ssl.flags);
+#endif
}
else {
// allocate it
w = web_client_alloc();
+#ifdef ENABLE_HTTPS
+ w->ssl.flags = NETDATA_SSL_START;
+ debug(D_WEB_CLIENT_ACCESS,"Starting SSL structure with (w->ssl = NULL, w->accepted = %d)",w->ssl.flags);
+#endif
web_clients_cache.allocated++;
}
@@ -205,6 +238,11 @@ void web_client_release(struct web_client *w) {
if (w->ifd != -1) close(w->ifd);
if (w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
w->ifd = w->ofd = -1;
+#ifdef ENABLE_HTTPS
+ web_client_reuse_ssl(w);
+ w->ssl.flags = NETDATA_SSL_START;
+#endif
+
}
// unlink it from the used
diff --git a/web/server/web_server.c b/web/server/web_server.c
index 11f7edf8a..9e51c81fe 100644
--- a/web/server/web_server.c
+++ b/web/server/web_server.c
@@ -138,5 +138,3 @@ void web_client_initialize_connection(struct web_client *w) {
web_client_cache_verify(0);
}
-
-