@cryptotaxi247 / netdata-1 / commits / 4abf0eb9e

add streaming access lists and fix unix domain sockets access lists; now 127.0.0.1, ::1 and unix domain sockets are matched with localhost; fixes #2636

Costa Tsaousis (ktsaou) committed Sep 19, 2017 at 22:53 UTC 4abf0eb9ee37d76de2405b1c286e15757a8d5a0f
6 files changed +86 -33
conf.d/stream.conf
+25 -10
@@ -21,13 +21,13 @@
21 #
22 # If many are given, the first available will get the metrics.
23 #
24 - # PROTOCOL = tcp or udp (only tcp is supported by masters)
25 - # HOST = an IPv4, IPv6 IP, or a hostname.
24 + # PROTOCOL = tcp, udp, or unix (only tcp and unix are supported by masters)
25 + # HOST = an IPv4, IPv6 IP, or a hostname, or a unix domain socket path.
26 # IPv6 IPs should be given with brackets [ip:address]
27 - # INTERFACE = the network interface to use
27 + # INTERFACE = the network interface to use (only for IPv6)
28 # PORT = the port number or service name (/etc/services)
29 #
30 - # This communication is not HTTP (cannot be proxied by web proxies).
30 + # This communication is not HTTP (it cannot be proxied by web proxies).
31 destination =
32
33 # The API_KEY to use (as the sender)
@@ -56,26 +56,34 @@
56 # -----------------------------------------------------------------------------
57 # 2. ON MASTER NETDATA - THE ONE THAT WILL BE RECEIVING METRICS
58
59 -# You can have one API key per slave, or the same API key for all slaves.
59 +# You can have one API key per slave,
60 +# or the same API key for all slaves.
61 #
62 # netdata searches for options in this order:
63 #
63 -# a) [MACHINE_GUID] section (settings for each machine)
64 -# b) [API_KEY] section (settings for the API key)
65 -# c) master netdata settings (netdata.conf)
64 +# a) master netdata settings (netdata.conf)
65 +# b) [API_KEY] section (below, settings for the API key)
66 +# c) [MACHINE_GUID] section (below, settings for each machine)
67 #
68 # You can combine the above (the more specific setting will be used).
69
70 # API key authentication
70 -# If the key is not listed here, it will not be able to connect.
71 +# If the key is not listed here, it will not be able to push metrics.
72
73 +# [API_KEY] is [YOUR-API-KEY], i.e [11111111-2222-3333-4444-555555555555]
74 [API_KEY]
73 - # Default settings for the API key
75 + # Default settings for this API key
76
77 # You can disable the API key, by setting this to: no
78 # The default (for unknown API keys) is: no
79 enabled = no
80
81 + # A list of simple patterns matching the IPs of the servers that
82 + # will be pushing metrics using this API key.
83 + # The metrics are received via the API port, so the same IPs
84 + # should also be matched at netdata.conf [web].allow connections from
85 + allow from = *
86 +
87 # The default history in entries, for all hosts using this API key.
88 # You can also set it per host below.
89 # If you don't set it here, the history size of the central netdata
@@ -132,6 +140,13 @@
140 # Use only the API key for security.
141 enabled = no
142
143 + # A list of simple patterns matching the IPs of the servers that
144 + # will be pushing metrics using this MACHINE GUID.
145 + # The metrics are received via the API port, so the same IPs
146 + # should also be matched at netdata.conf [web].allow connections from
147 + # and at stream.conf [API_KEY].allow from
148 + allow from = *
149 +
150 # The number of entries in the database
151 history = 3600
152
src/main.c
+2 -2
@@ -83,11 +83,11 @@ void web_server_config_options(void) {
83 web_x_frame_options = config_get(CONFIG_SECTION_WEB, "x-frame-options response header", "");
84 if(!*web_x_frame_options) web_x_frame_options = NULL;
85
86 - web_allow_connections_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow connections from", "127.* ::1 *"), SIMPLE_PATTERN_EXACT);
86 + web_allow_connections_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow connections from", "localhost *"), SIMPLE_PATTERN_EXACT);
87 web_allow_badges_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow badges from", "*"), SIMPLE_PATTERN_EXACT);
88 web_allow_registry_from = simple_pattern_create(config_get(CONFIG_SECTION_REGISTRY, "allow from", "*"), SIMPLE_PATTERN_EXACT);
89 web_allow_streaming_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow streaming from", "*"), SIMPLE_PATTERN_EXACT);
90 - web_allow_netdataconf_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow netdata.conf from", "::1 fd* 127.* 10.* 192.168.* 172.16.* 172.17.* 172.18.* 172.19.* 172.20.* 172.21.* 172.22.* 172.23.* 172.24.* 172.25.* 172.26.* 172.27.* 172.28.* 172.29.* 172.30.* 172.31.*"), SIMPLE_PATTERN_EXACT);
90 + web_allow_netdataconf_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow netdata.conf from", "localhost fd* 10.* 192.168.* 172.16.* 172.17.* 172.18.* 172.19.* 172.20.* 172.21.* 172.22.* 172.23.* 172.24.* 172.25.* 172.26.* 172.27.* 172.28.* 172.29.* 172.30.* 172.31.*"), SIMPLE_PATTERN_EXACT);
91
92 #ifdef NETDATA_WITH_ZLIB
93 web_enable_gzip = config_get_boolean(CONFIG_SECTION_WEB, "enable gzip compression", web_enable_gzip);
src/rrdpush.c
+41 -21
@@ -781,6 +781,14 @@ static void rrdpush_sender_thread_spawn(RRDHOST *host) {
781 rrdhost_unlock(host);
782 }
783
784 +int rrdpush_receiver_permission_denied(struct web_client *w) {
785 + // we always respond with the same message and error code
786 + // to prevent an attacker from gaining info about the error
787 + buffer_flush(w->response.data);
788 + buffer_sprintf(w->response.data, "You are not permitted to access this. Check the logs for more info.");
789 + return 401;
790 +}
791 +
792 int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url) {
793 (void)host;
794
@@ -819,57 +827,69 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url
827 if(!key || !*key) {
828 log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO KEY");
829 error("STREAM [receive from [%s]:%s]: request without an API key. Forbidding access.", w->client_ip, w->client_port);
822 - buffer_flush(w->response.data);
823 - buffer_sprintf(w->response.data, "You need an API key for this request.");
824 - return 401;
830 + return rrdpush_receiver_permission_denied(w);
831 }
832
833 if(!hostname || !*hostname) {
834 log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO HOSTNAME");
835 error("STREAM [receive from [%s]:%s]: request without a hostname. Forbidding access.", w->client_ip, w->client_port);
830 - buffer_flush(w->response.data);
831 - buffer_sprintf(w->response.data, "You need to send a hostname too.");
832 - return 400;
836 + return rrdpush_receiver_permission_denied(w);
837 }
838
839 if(!machine_guid || !*machine_guid) {
840 log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO MACHINE GUID");
841 error("STREAM [receive from [%s]:%s]: request without a machine GUID. Forbidding access.", w->client_ip, w->client_port);
838 - buffer_flush(w->response.data);
839 - buffer_sprintf(w->response.data, "You need to send a machine GUID too.");
840 - return 400;
842 + return rrdpush_receiver_permission_denied(w);
843 }
844
845 if(regenerate_guid(key, buf) == -1) {
846 log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - INVALID KEY");
847 error("STREAM [receive from [%s]:%s]: API key '%s' is not valid GUID (use the command uuidgen to generate one). Forbidding access.", w->client_ip, w->client_port, key);
846 - buffer_flush(w->response.data);
847 - buffer_sprintf(w->response.data, "Your API key is invalid.");
848 - return 401;
848 + return rrdpush_receiver_permission_denied(w);
849 }
850
851 if(regenerate_guid(machine_guid, buf) == -1) {
852 log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - INVALID MACHINE GUID");
853 error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not GUID. Forbidding access.", w->client_ip, w->client_port, machine_guid);
854 - buffer_flush(w->response.data);
855 - buffer_sprintf(w->response.data, "Your machine GUID is invalid.");
856 - return 404;
854 + return rrdpush_receiver_permission_denied(w);
855 }
856
857 if(!appconfig_get_boolean(&stream_config, key, "enabled", 0)) {
858 log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - KEY NOT ENABLED");
859 error("STREAM [receive from [%s]:%s]: API key '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, key);
862 - buffer_flush(w->response.data);
863 - buffer_sprintf(w->response.data, "Your API key is not permitted access.");
864 - return 401;
860 + return rrdpush_receiver_permission_denied(w);
861 + }
862 +
863 + {
864 + SIMPLE_PATTERN *key_allow_from = simple_pattern_create(appconfig_get(&stream_config, key, "allow from", "*"), SIMPLE_PATTERN_EXACT);
865 + if(key_allow_from) {
866 + if(!simple_pattern_matches(key_allow_from, w->client_ip)) {
867 + simple_pattern_free(key_allow_from);
868 + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname) ? hostname : "-", "ACCESS DENIED - KEY NOT ALLOWED FROM THIS IP");
869 + error("STREAM [receive from [%s]:%s]: API key '%s' is not permitted from this IP. Forbidding access.", w->client_ip, w->client_port, key);
870 + return rrdpush_receiver_permission_denied(w);
871 + }
872 + simple_pattern_free(key_allow_from);
873 + }
874 }
875
876 if(!appconfig_get_boolean(&stream_config, machine_guid, "enabled", 1)) {
877 log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - MACHINE GUID NOT ENABLED");
878 error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid);
870 - buffer_flush(w->response.data);
871 - buffer_sprintf(w->response.data, "Your machine guide is not permitted access.");
872 - return 404;
879 + return rrdpush_receiver_permission_denied(w);
880 + }
881 +
882 + {
883 + SIMPLE_PATTERN *machine_allow_from = simple_pattern_create(appconfig_get(&stream_config, machine_guid, "allow from", "*"), SIMPLE_PATTERN_EXACT);
884 + if(machine_allow_from) {
885 + if(!simple_pattern_matches(machine_allow_from, w->client_ip)) {
886 + simple_pattern_free(machine_allow_from);
887 + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (hostname && *hostname) ? hostname : "-", "ACCESS DENIED - MACHINE GUID NOT ALLOWED FROM THIS IP");
888 + error("STREAM [receive from [%s]:%s]: Machine GUID '%s' is not permitted from this IP. Forbidding access.", w->client_ip, w->client_port, machine_guid);
889 + return rrdpush_receiver_permission_denied(w);
890 + }
891 + simple_pattern_free(machine_allow_from);
892 + }
893 }
894
895 struct rrdpush_thread *rpt = mallocz(sizeof(struct rrdpush_thread));
src/socket.c
+12
@@ -873,6 +873,13 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien
873 client_port[portsize - 1] = '\0';
874
875 switch (((struct sockaddr *)&sadr)->sa_family) {
876 + case AF_UNIX:
877 + debug(D_LISTENER, "New UNIX domain web client from %s on socket %d.", client_ip, fd);
878 + // set the port - certain versions of libc return garbage on unix sockets
879 + strncpy(client_port, "UNIX", portsize);
880 + client_port[portsize - 1] = '\0';
881 + break;
882 +
883 case AF_INET:
884 debug(D_LISTENER, "New IPv4 web client from %s port %s on socket %d.", client_ip, client_port, fd);
885 break;
@@ -892,6 +899,11 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien
899 }
900
901 if(access_list) {
902 + if(!strcmp(client_ip, "127.0.0.1") || !strcmp(client_ip, "::1")) {
903 + strncpy(client_ip, "localhost", ipsize);
904 + client_ip[ipsize - 1] = '\0';
905 + }
906 +
907 if(unlikely(!simple_pattern_matches(access_list, client_ip))) {
908 errno = 0;
909 debug(D_LISTENER, "Permission denied for client '%s', port '%s'", client_ip, client_port);
src/web_client.h
+1
@@ -77,6 +77,7 @@ typedef enum web_client_flags {
77
78 #define web_client_set_tcp(w) web_client_flag_set(w, WEB_CLIENT_FLAG_TCP_CLIENT)
79 #define web_client_set_unix(w) web_client_flag_set(w, WEB_CLIENT_FLAG_UNIX_CLIENT)
80 +#define web_client_check_unix(w) web_client_flag_check(w, WEB_CLIENT_FLAG_UNIX_CLIENT)
81
82 #define web_client_is_corkable(w) web_client_flag_check(w, WEB_CLIENT_FLAG_TCP_CLIENT)
83
src/web_server.c
+5
@@ -168,6 +168,11 @@ void *socket_listen_main_multi_threaded(void *ptr) {
168 continue;
169 }
170
171 + if(api_sockets.fds_families[i] == AF_UNIX)
172 + web_client_set_unix(w);
173 + else
174 + web_client_set_tcp(w);
175 +
176 if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
177 error("%llu: failed to create new thread for web client.", w->id);
178 WEB_CLIENT_IS_OBSOLETE(w);