@cryptotaxi247 / netdata-1 / commits / a8e9fcb36

HTTP proxy support + some cleanup (#8418)

* HTTP proxy support + some cleanup * fix unrelated compiler warnings with -Wextra * minor - log proxy setting * run changed code trough .clang-format * fix case when url ends by / * update README

Timo committed Mar 25, 2020 at 09:17 UTC a8e9fcb3630ebdcc92d895a6d8bf3e1c9a588a35
8 files changed +183 -100
aclk/README.md
+16 -1
@@ -7,4 +7,19 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/aclk/README.md
7
8 # Agent-cloud link (ACLK)
9
10 -This is the agent cloud link (ACLK) information file
\ No newline at end of file
10 +
11 +## Configuration Options
12 +
13 +In `netdata.conf`:
14 +
15 +```ini
16 +[agent_cloud_link]
17 + proxy = none
18 +```
19 +
20 +Parameter proxy can take one of the following values:
21 +
22 +- `env` - the default (try to read environment variables `http_proxy` and `socks_proxy`)
23 +- `none` - do not use any proxy (even if system configured otherwise)
24 +- `socks5[h]://[user:pass@]host:ip` - will use specified socks proxy
25 +- `http://[user:pass@]host:ip` - will use specified http proxy
aclk/aclk_common.c
+99 -41
@@ -6,16 +6,31 @@ struct {
6 ACLK_PROXY_TYPE type;
7 const char *url_str;
8 } supported_proxy_types[] = {
9 - { .type = PROXY_TYPE_SOCKS5, .url_str = "socks5" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
9 + { .type = PROXY_TYPE_SOCKS5, .url_str = "socks5" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
10 { .type = PROXY_TYPE_SOCKS5, .url_str = "socks5h" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
11 + { .type = PROXY_TYPE_HTTP, .url_str = "http" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
12 { .type = PROXY_TYPE_UNKNOWN, .url_str = NULL },
13 };
14
15 +const char *aclk_proxy_type_to_s(ACLK_PROXY_TYPE *type)
16 +{
17 + switch (*type) {
18 + case PROXY_DISABLED:
19 + return "disabled";
20 + case PROXY_TYPE_HTTP:
21 + return "HTTP";
22 + case PROXY_TYPE_SOCKS5:
23 + return "SOCKS";
24 + default:
25 + return "Unknown";
26 + }
27 +}
28 +
29 static inline ACLK_PROXY_TYPE aclk_find_proxy(const char *string)
30 {
31 int i = 0;
17 - while( supported_proxy_types[i].url_str ) {
18 - if(!strncmp(supported_proxy_types[i].url_str, string, strlen(supported_proxy_types[i].url_str)))
32 + while (supported_proxy_types[i].url_str) {
33 + if (!strncmp(supported_proxy_types[i].url_str, string, strlen(supported_proxy_types[i].url_str)))
34 return supported_proxy_types[i].type;
35 i++;
36 }
@@ -24,13 +39,13 @@ static inline ACLK_PROXY_TYPE aclk_find_proxy(const char *string)
39
40 ACLK_PROXY_TYPE aclk_verify_proxy(const char *string)
41 {
27 - if(!string)
42 + if (!string)
43 return PROXY_TYPE_UNKNOWN;
44
30 - while(*string == 0x20)
45 + while (*string == 0x20)
46 string++;
47
33 - if(!*string)
48 + if (!*string)
49 return PROXY_TYPE_UNKNOWN;
50
51 return aclk_find_proxy(string);
@@ -38,112 +53,155 @@ ACLK_PROXY_TYPE aclk_verify_proxy(const char *string)
53
54 // helper function to censor user&password
55 // for logging purposes
41 -void safe_log_proxy_censor(char *proxy) {
56 +void safe_log_proxy_censor(char *proxy)
57 +{
58 size_t length = strlen(proxy);
43 - char *auth = proxy+length-1;
59 + char *auth = proxy + length - 1;
60 char *cur;
61
46 - while( (auth >= proxy) && (*auth != '@') )
62 + while ((auth >= proxy) && (*auth != '@'))
63 auth--;
64
65 //if not found or @ is first char do nothing
50 - if(auth<=proxy)
66 + if (auth <= proxy)
67 return;
68
69 cur = strstr(proxy, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
54 - if(!cur)
70 + if (!cur)
71 cur = proxy;
72 else
73 cur += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
74
59 - while(cur < auth) {
60 - *cur='X';
75 + while (cur < auth) {
76 + *cur = 'X';
77 cur++;
78 }
79 }
80
65 -static inline void safe_log_proxy_error(char *str, const char *proxy) {
81 +static inline void safe_log_proxy_error(char *str, const char *proxy)
82 +{
83 char *log = strdupz(proxy);
84 safe_log_proxy_censor(log);
85 error("%s Provided Value:\"%s\"", str, log);
86 freez(log);
87 }
88
72 -static inline int check_socks_enviroment(const char **proxy) {
89 +static inline int check_socks_enviroment(const char **proxy)
90 +{
91 char *tmp = getenv("socks_proxy");
92
75 - if(!tmp)
93 + if (!tmp)
94 + return 1;
95 +
96 + if (aclk_verify_proxy(tmp) == PROXY_TYPE_SOCKS5) {
97 + *proxy = tmp;
98 + return 0;
99 + }
100 +
101 + safe_log_proxy_error(
102 + "Environment var \"socks_proxy\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".",
103 + tmp);
104 + return 1;
105 +}
106 +
107 +static inline int check_http_enviroment(const char **proxy)
108 +{
109 + char *tmp = getenv("http_proxy");
110 +
111 + if (!tmp)
112 return 1;
113
78 - if(aclk_verify_proxy(tmp) == PROXY_TYPE_SOCKS5) {
114 + if (aclk_verify_proxy(tmp) == PROXY_TYPE_HTTP) {
115 *proxy = tmp;
116 return 0;
117 }
118
83 - safe_log_proxy_error("Environment var \"socks_proxy\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".", tmp);
119 + safe_log_proxy_error(
120 + "Environment var \"http_proxy\" defined but of unknown format. Supported syntax: \"http[s]://[user:pass@]host:ip\".",
121 + tmp);
122 return 1;
123 }
124
87 -const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type) {
125 +const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
126 +{
127 const char *proxy = config_get(CONFIG_SECTION_ACLK, ACLK_PROXY_CONFIG_VAR, ACLK_PROXY_ENV);
128 *type = PROXY_DISABLED;
129
91 - if(strcmp(proxy, "none") == 0)
130 + if (strcmp(proxy, "none") == 0)
131 return proxy;
132
94 - if(strcmp(proxy, ACLK_PROXY_ENV) == 0) {
95 - if(check_socks_enviroment(&proxy) == 0)
133 + if (strcmp(proxy, ACLK_PROXY_ENV) == 0) {
134 + if (check_socks_enviroment(&proxy) == 0)
135 *type = PROXY_TYPE_SOCKS5;
136 + else if (check_http_enviroment(&proxy) == 0)
137 + *type = PROXY_TYPE_HTTP;
138 return proxy;
139 }
140
141 *type = aclk_verify_proxy(proxy);
101 - if(*type == PROXY_TYPE_UNKNOWN) {
142 + if (*type == PROXY_TYPE_UNKNOWN) {
143 *type = PROXY_DISABLED;
103 - safe_log_proxy_error("Config var \"" ACLK_PROXY_CONFIG_VAR "\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".", proxy);
144 + safe_log_proxy_error(
145 + "Config var \"" ACLK_PROXY_CONFIG_VAR
146 + "\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".",
147 + proxy);
148 }
149
150 return proxy;
151 }
152
153 +// helper function to read settings only once (static)
154 +// as claiming, challenge/response and ACLK
155 +// read the same thing, no need to parse again
156 +const char *aclk_get_proxy(ACLK_PROXY_TYPE *type)
157 +{
158 + static const char *proxy = NULL;
159 + static ACLK_PROXY_TYPE proxy_type = PROXY_NOT_SET;
160 +
161 + if (proxy_type == PROXY_NOT_SET)
162 + proxy = aclk_lws_wss_get_proxy_setting(&proxy_type);
163 +
164 + *type = proxy_type;
165 + return proxy;
166 +}
167 +
168 int aclk_decode_base_url(char *url, char **aclk_hostname, char **aclk_port)
169 {
111 -int pos = 0;
112 - if (!strncmp("https://", url, 8))
113 - {
170 + int pos = 0;
171 + if (!strncmp("https://", url, 8)) {
172 pos = 8;
115 - }
116 - else if (!strncmp("http://", url, 7))
117 - {
173 + } else if (!strncmp("http://", url, 7)) {
174 error("Cannot connect ACLK over %s -> unencrypted link is not supported", url);
175 return 1;
176 }
121 -int host_end = pos;
122 - while( url[host_end] != 0 && url[host_end] != '/' && url[host_end] != ':' )
177 + int host_end = pos;
178 + while (url[host_end] != 0 && url[host_end] != '/' && url[host_end] != ':')
179 host_end++;
124 - if (url[host_end] == 0)
125 - {
126 - *aclk_hostname = strdupz(url+pos);
180 + if (url[host_end] == 0) {
181 + *aclk_hostname = strdupz(url + pos);
182 *aclk_port = strdupz("443");
183 info("Setting ACLK target host=%s port=%s from %s", *aclk_hostname, *aclk_port, url);
184 return 0;
185 }
131 - if (url[host_end] == ':')
132 - {
186 + if (url[host_end] == ':') {
187 *aclk_hostname = callocz(host_end - pos + 1, 1);
134 - strncpy(*aclk_hostname, url+pos, host_end - pos);
188 + strncpy(*aclk_hostname, url + pos, host_end - pos);
189 int port_end = host_end + 1;
190 while (url[port_end] >= '0' && url[port_end] <= '9')
191 port_end++;
138 - if (port_end - host_end > 6)
139 - {
192 + if (port_end - host_end > 6) {
193 error("Port specified in %s is invalid", url);
194 return 0;
195 }
196 *aclk_port = callocz(port_end - host_end + 1, 1);
144 - for(int i=host_end + 1; i < port_end; i++)
197 + for (int i = host_end + 1; i < port_end; i++)
198 (*aclk_port)[i - host_end - 1] = url[i];
199 }
200 + if (url[host_end] == '/') {
201 + *aclk_port = strdupz("443");
202 + *aclk_hostname = callocz(1, host_end - pos + 1);
203 + strncpy(*aclk_hostname, url+pos, host_end - pos);
204 + }
205 info("Setting ACLK target host=%s port=%s from %s", *aclk_hostname, *aclk_port, url);
206 return 0;
207 }
aclk/aclk_common.h
+3
@@ -11,6 +11,8 @@ typedef enum aclk_proxy_type {
11 PROXY_NOT_SET,
12 } ACLK_PROXY_TYPE;
13
14 +const char *aclk_proxy_type_to_s(ACLK_PROXY_TYPE *type);
15 +
16 #define ACLK_PROXY_PROTO_ADDR_SEPARATOR "://"
17 #define ACLK_PROXY_ENV "env"
18 #define ACLK_PROXY_CONFIG_VAR "proxy"
@@ -19,5 +21,6 @@ ACLK_PROXY_TYPE aclk_verify_proxy(const char *string);
21 const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type);
22 void safe_log_proxy_censor(char *proxy);
23 int aclk_decode_base_url(char *url, char **aclk_hostname, char **aclk_port);
24 +const char *aclk_get_proxy(ACLK_PROXY_TYPE *type);
25
26 #endif //ACLK_COMMON_H
aclk/aclk_lws_https_client.c
+9 -21
@@ -19,6 +19,7 @@ struct simple_hcc_data {
19
20 static int simple_https_client_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
21 {
22 + UNUSED(user);
23 int n;
24 char *ptr;
25 char buffer[SMALL_BUFFER];
@@ -78,7 +79,7 @@ static int simple_https_client_callback(struct lws *wsi, enum lws_callback_reaso
79 debug(D_ACLK, "LWS_CALLBACK_CLIENT_HTTP_WRITEABLE");
80 if(perconn_data && perconn_data->payload) {
81 n = strlen(perconn_data->payload);
81 - if(perconn_data->data_size < LWS_PRE + n + 1) {
82 + if(perconn_data->data_size < (size_t)LWS_PRE + n + 1) {
83 error("Buffer given is not big enough");
84 return 1;
85 }
@@ -133,12 +134,16 @@ static const struct lws_protocols protocols[] = {
134 simple_https_client_callback,
135 0,
136 0,
137 + 0,
138 + 0,
139 + 0
140 },
137 - { NULL, NULL, 0, 0 }
141 + { NULL, NULL, 0, 0, 0, 0, 0 }
142 };
143
144 static void simple_hcc_log_divert(int level, const char *line)
145 {
146 + UNUSED(level);
147 error("Libwebsockets: %s", line);
148 }
149
@@ -159,15 +164,7 @@ int aclk_send_https_request(char *method, char *host, char *port, char *url, cha
164 int n = 0;
165 time_t timestamp;
166
162 - //TODO -> deduplicate (aclk_lws_wss_connect)
163 - static const char *proxy = NULL;
164 - static ACLK_PROXY_TYPE proxy_type = PROXY_NOT_SET;
167 struct lws_vhost *vhost;
166 - char *log;
167 -
168 - if(proxy_type == PROXY_NOT_SET)
169 - proxy = aclk_lws_wss_get_proxy_setting(&proxy_type);
170 -
168
169 memset(&info, 0, sizeof info);
170
@@ -212,17 +209,8 @@ int aclk_send_https_request(char *method, char *host, char *port, char *url, cha
209 if(!vhost)
210 fatal("Could not find the default LWS vhost.");
211
215 - lws_set_socks(vhost, ":");
216 - lws_set_proxy(vhost, ":");
217 -
218 - if(proxy_type == PROXY_TYPE_SOCKS5) {
219 - log = strdupz(proxy);
220 - safe_log_proxy_censor(log);
221 - info("Connecting using SOCKS5 proxy:\"%s\"", log);
222 - freez(log);
223 - if(aclk_wss_set_socks(vhost, proxy))
224 - error("LWS failed to accept socks proxy.");
225 - }
212 + //set up proxy
213 + aclk_wss_set_proxy(vhost);
214
215 lws_client_connect_via_info(&i);
216
aclk/aclk_lws_wss_client.c
+49 -33
@@ -208,42 +208,81 @@ void aclk_lws_wss_client_destroy()
208 #endif
209 }
210
211 -int aclk_wss_set_socks(struct lws_vhost *vhost, const char *socks) {
211 +static int aclk_wss_set_socks(struct lws_vhost *vhost, const char *socks)
212 +{
213 char *proxy = strstr(socks, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
214
214 - if(!proxy)
215 + if (!proxy)
216 return -1;
217
218 proxy += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
219
219 - if(!*proxy)
220 + if (!*proxy)
221 return -1;
222
223 return lws_set_socks(vhost, proxy);
224 }
225
226 +void aclk_wss_set_proxy(struct lws_vhost *vhost)
227 +{
228 + const char *proxy;
229 + ACLK_PROXY_TYPE proxy_type;
230 + char *log;
231 +
232 + proxy = aclk_get_proxy(&proxy_type);
233 +
234 + lws_set_socks(vhost, ":");
235 + lws_set_proxy(vhost, ":");
236 +
237 + if (proxy_type == PROXY_TYPE_UNKNOWN) {
238 + error("Unknown proxy type");
239 + return;
240 + }
241 +
242 + if (proxy_type == PROXY_TYPE_SOCKS5 || proxy_type == PROXY_TYPE_HTTP) {
243 + log = strdupz(proxy);
244 + safe_log_proxy_censor(log);
245 + info("Connecting using %s proxy:\"%s\"", aclk_proxy_type_to_s(&proxy_type), log);
246 + freez(log);
247 + }
248 + if (proxy_type == PROXY_TYPE_SOCKS5) {
249 + if (aclk_wss_set_socks(vhost, proxy))
250 + error("LWS failed to accept socks proxy.");
251 + return;
252 + }
253 + if (proxy_type == PROXY_TYPE_HTTP) {
254 + if (lws_set_proxy(vhost, proxy))
255 + error("LWS failed to accept http proxy.");
256 + return;
257 + }
258 + if (proxy_type != PROXY_DISABLED)
259 + error("Unknown proxy type");
260 +}
261 +
262 // Return code indicates if connection attempt has started async.
263 int aclk_lws_wss_connect(char *host, int port)
264 {
265 struct lws_client_connect_info i;
266 struct lws_vhost *vhost;
230 - static const char *proxy = NULL;
231 - static ACLK_PROXY_TYPE proxy_type = PROXY_NOT_SET;
232 - char *log;
267
268 if (!engine_instance) {
269 return aclk_lws_wss_client_init(host, port);
270 // PROTOCOL_INIT callback will call again.
271 }
272
239 - if(proxy_type == PROXY_NOT_SET)
240 - proxy = aclk_lws_wss_get_proxy_setting(&proxy_type);
241 -
273 if (engine_instance->lws_wsi) {
274 error("Already Connected. Only one connection supported at a time.");
275 return 0;
276 }
277
278 + memset(&i, 0, sizeof(i));
279 + i.context = engine_instance->lws_context;
280 + i.port = engine_instance->port;
281 + i.address = engine_instance->host;
282 + i.path = "/mqtt";
283 + i.host = engine_instance->host;
284 + i.protocol = "mqtt";
285 +
286 // from LWS docu:
287 // If option LWS_SERVER_OPTION_EXPLICIT_VHOSTS is given, no vhost is
288 // created; you're expected to create your own vhosts afterwards using
@@ -253,30 +292,7 @@ int aclk_lws_wss_connect(char *host, int port)
292 if(!vhost)
293 fatal("Could not find the default LWS vhost.");
294
256 - memset(&i, 0, sizeof(i));
257 - i.context = engine_instance->lws_context;
258 - i.port = engine_instance->port;
259 - i.address = engine_instance->host;
260 - i.path = "/mqtt";
261 - i.host = engine_instance->host;
262 - i.protocol = "mqtt";
263 -
264 - switch (proxy_type) {
265 - case PROXY_DISABLED:
266 - lws_set_socks(vhost, ":");
267 - lws_set_proxy(vhost, ":");
268 - break;
269 - case PROXY_TYPE_SOCKS5:
270 - log = strdupz(proxy);
271 - safe_log_proxy_censor(log);
272 - info("Connecting using SOCKS5 proxy:\"%s\"", log);
273 - freez(log);
274 - if(aclk_wss_set_socks(vhost, proxy))
275 - error("LWS failed to accept socks proxy.");
276 - break;
277 - default:
278 - error("The proxy could not be set. Unknown proxy type.");
279 - }
295 + aclk_wss_set_proxy(vhost);
296
297 #ifdef ACLK_SSL_ALLOW_SELF_SIGNED
298 i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
aclk/aclk_lws_wss_client.h
+1 -1
@@ -81,7 +81,7 @@ void aclk_lws_connection_data_received();
81 void aclk_lws_connection_closed();
82 void lws_wss_check_queues(size_t *write_len, size_t *write_len_bytes, size_t *read_len);
83
84 -int aclk_wss_set_socks(struct lws_vhost *vhost, const char *socks);
84 +void aclk_wss_set_proxy(struct lws_vhost *vhost);
85
86 #define FRAGMENT_SIZE 4096
87 #endif
claim/claim.c
+2 -2
@@ -64,9 +64,9 @@ void claim_agent(char *claiming_arguments)
64 ACLK_PROXY_TYPE proxy_type;
65 char proxy_flag[CLAIMING_PROXY_LENGTH] = "-noproxy";
66
67 - proxy_str = aclk_lws_wss_get_proxy_setting(&proxy_type);
67 + proxy_str = aclk_get_proxy(&proxy_type);
68
69 - if(proxy_type == PROXY_TYPE_SOCKS5)
69 + if (proxy_type == PROXY_TYPE_SOCKS5 || proxy_type == PROXY_TYPE_HTTP)
70 snprintf(proxy_flag, CLAIMING_PROXY_LENGTH, "-proxy=\"%s\"", proxy_str);
71
72 snprintfz(command_buffer,
claim/netdata-claim.sh.in
+4 -1
@@ -129,7 +129,7 @@ do
129 -hostname=*) HOSTNAME=${arg:10} ;;
130 -verbose) VERBOSE=1 ;;
131 -insecure) INSECURE=1 ;;
132 - -proxy=socks*) PROXY=${arg:7} ;;
132 + -proxy=*) PROXY=${arg:7} ;;
133 -noproxy) NOPROXY=yes ;;
134 *) echo >&2 "Unknown argument ${arg}"
135 exit 1 ;;
@@ -148,6 +148,7 @@ echo >&2 "Base URL: $URL_BASE"
148 echo >&2 "Id: $ID"
149 echo >&2 "Rooms: $ROOMS"
150 echo >&2 "Hostname: $HOSTNAME"
151 +echo >&2 "Proxy: $PROXY"
152
153 # create the claiming directory for this user
154 if [ ! -d "${CLAIMING_DIR}" ] ; then
@@ -214,6 +215,8 @@ else
215 --body-file=\"${CLAIMING_DIR}/tmpin.txt\""
216 if [ "${NOPROXY}" = "yes" ] ; then
217 URLCOMMAND="${URLCOMMAND} --no-proxy"
218 + elif [ "${PROXY:0:4}" = http ] ; then
219 + URLCOMMAND="export http_proxy=${PROXY}; ${URLCOMMAND}"
220 fi
221 fi
222