@cryptotaxi247 / netdata-1 / commits / 10090b556

Support SOCKS5 in ACLK Challenge/Response and rewrite with LWS (#8404)

* wip * add alpn * beggining of cleanup * move common code * add SOCKS5 support * check HTTP response code * add timeout * separate https_client into own files * fix some mem leaks from master + avoid string copying and alloc/free * fix some PR unrelated warnings

Timo committed Mar 15, 2020 at 20:35 UTC 10090b556b07463a0ca2412fc4be8b470d115e31
10 files changed +383 -183
CMakeLists.txt
+2
@@ -616,6 +616,8 @@ set(ACLK_PLUGIN_FILES
616 aclk/agent_cloud_link.h
617 aclk/aclk_lws_wss_client.c
618 aclk/aclk_lws_wss_client.h
619 + aclk/aclk_lws_https_client.c
620 + aclk/aclk_lws_https_client.h
621 aclk/mqtt.c
622 aclk/mqtt.h
623 )
Makefile.am
+2
@@ -481,6 +481,8 @@ ACLK_PLUGIN_FILES = \
481 aclk/mqtt.h \
482 aclk/aclk_lws_wss_client.c \
483 aclk/aclk_lws_wss_client.h \
484 + aclk/aclk_lws_https_client.c \
485 + aclk/aclk_lws_https_client.h \
486 $(NULL)
487
488 EXPORTING_ENGINE_FILES = \
aclk/aclk_common.c
+72
@@ -1,5 +1,7 @@
1 #include "aclk_common.h"
2
3 +#include "../daemon/common.h"
4 +
5 struct {
6 ACLK_PROXY_TYPE type;
7 const char *url_str;
@@ -33,3 +35,73 @@ ACLK_PROXY_TYPE aclk_verify_proxy(const char *string)
35
36 return aclk_find_proxy(string);
37 }
38 +
39 +// helper function to censor user&password
40 +// for logging purposes
41 +void safe_log_proxy_censor(char *proxy) {
42 + size_t length = strlen(proxy);
43 + char *auth = proxy+length-1;
44 + char *cur;
45 +
46 + while( (auth >= proxy) && (*auth != '@') )
47 + auth--;
48 +
49 + //if not found or @ is first char do nothing
50 + if(auth<=proxy)
51 + return;
52 +
53 + cur = strstr(proxy, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
54 + if(!cur)
55 + cur = proxy;
56 + else
57 + cur += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
58 +
59 + while(cur < auth) {
60 + *cur='X';
61 + cur++;
62 + }
63 +}
64 +
65 +static inline void safe_log_proxy_error(char *str, const char *proxy) {
66 + char *log = strdupz(proxy);
67 + safe_log_proxy_censor(log);
68 + error("%s Provided Value:\"%s\"", str, log);
69 + freez(log);
70 +}
71 +
72 +static inline int check_socks_enviroment(const char **proxy) {
73 + char *tmp = getenv("socks_proxy");
74 +
75 + if(!tmp)
76 + return 1;
77 +
78 + if(aclk_verify_proxy(tmp) == PROXY_TYPE_SOCKS5) {
79 + *proxy = tmp;
80 + return 0;
81 + }
82 +
83 + safe_log_proxy_error("Environment var \"socks_proxy\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".", tmp);
84 + return 1;
85 +}
86 +
87 +const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type) {
88 + const char *proxy = config_get(CONFIG_SECTION_ACLK, ACLK_PROXY_CONFIG_VAR, ACLK_PROXY_ENV);
89 + *type = PROXY_DISABLED;
90 +
91 + if(strcmp(proxy, "none") == 0)
92 + return proxy;
93 +
94 + if(strcmp(proxy, ACLK_PROXY_ENV) == 0) {
95 + if(check_socks_enviroment(&proxy) == 0)
96 + *type = PROXY_TYPE_SOCKS5;
97 + return proxy;
98 + }
99 +
100 + *type = aclk_verify_proxy(proxy);
101 + if(*type == PROXY_TYPE_UNKNOWN) {
102 + *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);
104 + }
105 +
106 + return proxy;
107 +}
aclk/aclk_common.h
+3
@@ -16,5 +16,8 @@ typedef enum aclk_proxy_type {
16 #define ACLK_PROXY_CONFIG_VAR "proxy"
17
18 ACLK_PROXY_TYPE aclk_verify_proxy(const char *string);
19 +const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type);
20 +void safe_log_proxy_censor(char *proxy);
21 +int aclk_decode_base_url(char *url, char **aclk_hostname, char **aclk_port);
22
23 #endif //ACLK_COMMON_H
aclk/aclk_lws_https_client.c new
+246
@@ -0,0 +1,246 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#define ACLK_LWS_HTTPS_CLIENT_INTERNAL
4 +#include "aclk_lws_https_client.h"
5 +
6 +#include "aclk_common.h"
7 +
8 +#include "aclk_lws_wss_client.h"
9 +
10 +#define SMALL_BUFFER 16
11 +
12 +struct simple_hcc_data {
13 + char *data;
14 + size_t data_size;
15 + char *payload;
16 + int response_code;
17 + int done;
18 +};
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 + int n;
23 + char *ptr;
24 + char buffer[SMALL_BUFFER];
25 + struct simple_hcc_data *perconn_data = lws_get_opaque_user_data(wsi);
26 +
27 + switch (reason) {
28 + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
29 + debug(D_ACLK, "LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ");
30 + return 0;
31 + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
32 + debug(D_ACLK, "LWS_CALLBACK_RECEIVE_CLIENT_HTTP");
33 + if(!perconn_data) {
34 + error("Missing Per Connect Data");
35 + return -1;
36 + }
37 + ptr = perconn_data->data;
38 + n = perconn_data->data_size;
39 + if (lws_http_client_read(wsi, &ptr, &n) < 0)
40 + return -1;
41 + return 0;
42 + case LWS_CALLBACK_WSI_DESTROY:
43 + debug(D_ACLK, "LWS_CALLBACK_WSI_DESTROY");
44 + if(perconn_data)
45 + perconn_data->done = 1;
46 + return 0;
47 + case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
48 + debug(D_ACLK, "LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP");
49 + if(perconn_data)
50 + perconn_data->response_code = lws_http_client_http_response(wsi);
51 + return 0;
52 + case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
53 + debug(D_ACLK, "LWS_CALLBACK_CLOSED_CLIENT_HTTP");
54 + return 0;
55 + case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
56 + debug(D_ACLK, "LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS");
57 + return 0;
58 + case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
59 + debug(D_ACLK, "LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER");
60 + if(perconn_data && perconn_data->payload) {
61 + unsigned char **p = (unsigned char **)in, *end = (*p) + len;
62 + snprintfz(buffer, SMALL_BUFFER, "%zu", strlen(perconn_data->payload));
63 + if (lws_add_http_header_by_token(wsi,
64 + WSI_TOKEN_HTTP_CONTENT_LENGTH,
65 + (unsigned char *)buffer, strlen(buffer), p, end))
66 + return -1;
67 + if (lws_add_http_header_by_token(wsi,
68 + WSI_TOKEN_HTTP_CONTENT_TYPE,
69 + (unsigned char *)ACLK_CONTENT_TYPE_JSON,
70 + strlen(ACLK_CONTENT_TYPE_JSON), p, end))
71 + return -1;
72 + lws_client_http_body_pending(wsi, 1);
73 + lws_callback_on_writable(wsi);
74 + }
75 + return 0;
76 + case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
77 + debug(D_ACLK, "LWS_CALLBACK_CLIENT_HTTP_WRITEABLE");
78 + if(perconn_data && perconn_data->payload) {
79 + n = strlen(perconn_data->payload);
80 + if(perconn_data->data_size < LWS_PRE + n + 1) {
81 + error("Buffer given is not big enough");
82 + return 1;
83 + }
84 +
85 + memcpy(&perconn_data->data[LWS_PRE], perconn_data->payload, n);
86 + if(n != lws_write(wsi, (unsigned char*)&perconn_data->data[LWS_PRE], n, LWS_WRITE_HTTP)) {
87 + error("lws_write error");
88 + perconn_data->data[0] = 0;
89 + return 1;
90 + }
91 + lws_client_http_body_pending(wsi, 0);
92 + // clean for subsequent reply read
93 + perconn_data->data[0] = 0;
94 + }
95 + return 0;
96 + case LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL:
97 + debug(D_ACLK, "LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL");
98 + return 0;
99 + case LWS_CALLBACK_WSI_CREATE:
100 + debug(D_ACLK, "LWS_CALLBACK_WSI_CREATE");
101 + return 0;
102 + case LWS_CALLBACK_PROTOCOL_INIT:
103 + debug(D_ACLK, "LWS_CALLBACK_PROTOCOL_INIT");
104 + return 0;
105 + case LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL:
106 + debug(D_ACLK, "LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL");
107 + return 0;
108 + case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
109 + debug(D_ACLK, "LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED");
110 + return 0;
111 + case LWS_CALLBACK_GET_THREAD_ID:
112 + debug(D_ACLK, "LWS_CALLBACK_GET_THREAD_ID");
113 + return 0;
114 + case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
115 + debug(D_ACLK, "LWS_CALLBACK_EVENT_WAIT_CANCELLED");
116 + return 0;
117 + case LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION:
118 + debug(D_ACLK, "LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION");
119 + return 0;
120 + case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
121 + debug(D_ACLK, "LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH");
122 + return 0;
123 + default:
124 + debug(D_ACLK, "Unknown callback %d", (int)reason);
125 + return 0;
126 + }
127 +}
128 +
129 +static const struct lws_protocols protocols[] = {
130 + {
131 + "http",
132 + simple_https_client_callback,
133 + 0,
134 + 0,
135 + },
136 + { NULL, NULL, 0, 0 }
137 +};
138 +
139 +static void simple_hcc_log_divert(int level, const char *line)
140 +{
141 + error("Libwebsockets: %s", line);
142 +}
143 +
144 +int aclk_send_https_request(char *method, char *host, char *port, char *url, char *b, size_t b_size, char *payload)
145 +{
146 + info("%s %s", __func__, method);
147 +
148 + struct lws_context_creation_info info;
149 + struct lws_client_connect_info i;
150 + struct lws_context *context;
151 +
152 + struct simple_hcc_data *data = callocz(1, sizeof(struct simple_hcc_data));
153 + data->data = b;
154 + data->data[0] = 0;
155 + data->data_size = b_size;
156 + data->payload = payload;
157 +
158 + int n = 0;
159 + time_t timestamp;
160 +
161 + //TODO -> deduplicate (aclk_lws_wss_connect)
162 + static const char *proxy = NULL;
163 + static ACLK_PROXY_TYPE proxy_type = PROXY_NOT_SET;
164 + struct lws_vhost *vhost;
165 + char *log;
166 +
167 + if(proxy_type == PROXY_NOT_SET)
168 + proxy = aclk_lws_wss_get_proxy_setting(&proxy_type);
169 +
170 +
171 + memset(&info, 0, sizeof info);
172 +
173 + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
174 + info.port = CONTEXT_PORT_NO_LISTEN;
175 + info.protocols = protocols;
176 +
177 +
178 + context = lws_create_context(&info);
179 + if (!context) {
180 + error("Error creating LWS context");
181 + return 1;
182 + }
183 +
184 + lws_set_log_level(LLL_ERR | LLL_WARN, simple_hcc_log_divert);
185 +
186 + lws_service(context, 0);
187 +
188 + memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
189 + i.context = context;
190 +
191 +#ifdef ACLK_SSL_ALLOW_SELF_SIGNED
192 + i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
193 + info("Disabling SSL certificate checks");
194 +#else
195 + i.ssl_connection = LCCSCF_USE_SSL;
196 +#endif
197 +
198 + i.port = atoi(port);
199 + i.address = host;
200 + i.path = url;
201 +
202 + i.host = i.address;
203 + i.origin = i.address;
204 + i.method = method;
205 + i.opaque_user_data = data;
206 + i.alpn = "http/1.1";
207 +
208 + i.protocol = protocols[0].name;
209 +
210 + vhost = lws_get_vhost_by_name(context, "default");
211 + if(!vhost)
212 + fatal("Could not find the default LWS vhost.");
213 +
214 + lws_set_socks(vhost, ":");
215 + lws_set_proxy(vhost, ":");
216 +
217 + if(proxy_type == PROXY_TYPE_SOCKS5) {
218 + log = strdupz(proxy);
219 + safe_log_proxy_censor(log);
220 + info("Connecting using SOCKS5 proxy:\"%s\"", log);
221 + freez(log);
222 + if(aclk_wss_set_socks(vhost, proxy))
223 + error("LWS failed to accept socks proxy.");
224 + }
225 +
226 + lws_client_connect_via_info(&i);
227 +
228 + // libwebsockets handle connection timeouts already
229 + // this adds additional safety in case of bug in LWS
230 + timestamp = now_monotonic_sec();
231 + while( n >= 0 && !data->done && !netdata_exit) {
232 + n = lws_service(context, 0);
233 + if( now_monotonic_sec() - timestamp > SEND_HTTPS_REQUEST_TIMEOUT ) {
234 + data->data[0] = 0;
235 + data->done = 1;
236 + error("Servicing LWS took too long.");
237 + }
238 + }
239 +
240 + lws_context_destroy(context);
241 +
242 + n = data->response_code;
243 +
244 + freez(data);
245 + return (n < 200 || n >= 300);
246 +}
aclk/aclk_lws_https_client.h new
+18
@@ -0,0 +1,18 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_LWS_HTTPS_CLIENT_H
4 +#define NETDATA_LWS_HTTPS_CLIENT_H
5 +
6 +#include "../daemon/common.h"
7 +#include "libnetdata/libnetdata.h"
8 +
9 +#define DATAMAXLEN 1024*16
10 +
11 +#ifdef ACLK_LWS_HTTPS_CLIENT_INTERNAL
12 +#define ACLK_CONTENT_TYPE_JSON "application/json"
13 +#define SEND_HTTPS_REQUEST_TIMEOUT 30
14 +#endif
15 +
16 +int aclk_send_https_request(char *method, char *host, char *port, char *url, char *b, size_t b_size, char *payload);
17 +
18 +#endif /* NETDATA_LWS_HTTPS_CLIENT_H */
aclk/aclk_lws_wss_client.c
+12 -81
@@ -1,3 +1,5 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 #include "aclk_lws_wss_client.h"
4
5 #include "libnetdata/libnetdata.h"
@@ -188,7 +190,7 @@ failure_cleanup_2:
190 return 1;
191 }
192
191 -void aclk_lws_wss_client_destroy(struct aclk_lws_wss_engine_instance *engine_instance)
193 +void aclk_lws_wss_client_destroy()
194 {
195 if (engine_instance == NULL)
196 return;
@@ -204,89 +206,18 @@ void aclk_lws_wss_client_destroy(struct aclk_lws_wss_engine_instance *engine_ins
206 #endif
207 }
208
207 -static int _aclk_wss_set_socks(struct lws_vhost *vhost, const char *socks)
208 -{
209 - char *proxy = strstr(socks, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
210 -
211 - if(!proxy)
212 - return -1;
213 -
214 - proxy += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
215 -
216 - if(!*proxy)
217 - return -1;
218 -
219 - return lws_set_socks(vhost, proxy);
220 -}
221 -
222 -// helper function to censor user&password
223 -// for logging purposes
224 -static void safe_log_proxy_censor(char *proxy) {
225 - size_t length = strlen(proxy);
226 - char *auth = proxy+length-1;
227 - char *cur;
209 +int aclk_wss_set_socks(struct lws_vhost *vhost, const char *socks) {
210 + char *proxy = strstr(socks, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
211
229 - while( (auth >= proxy) && (*auth != '@') )
230 - auth--;
212 + if(!proxy)
213 + return -1;
214
232 - //if not found or @ is first char do nothing
233 - if(auth<=proxy)
234 - return;
235 -
236 - cur = strstr(proxy, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
237 - if(!cur)
238 - cur = proxy;
239 - else
240 - cur += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
241 -
242 - while(cur < auth) {
243 - *cur='X';
244 - cur++;
245 - }
246 -}
247 -
248 -static inline void safe_log_proxy_error(char *str, const char *proxy) {
249 - char *log = strdupz(proxy);
250 - safe_log_proxy_censor(log);
251 - error("%s Provided Value:\"%s\"", str, log);
252 - freez(log);
253 -}
215 + proxy += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
216
255 -static inline int check_socks_enviroment(const char **proxy) {
256 - char *tmp = getenv("socks_proxy");
257 -
258 - if(!tmp)
259 - return 1;
260 -
261 - if(aclk_verify_proxy(tmp) == PROXY_TYPE_SOCKS5) {
262 - *proxy = tmp;
263 - return 0;
264 - }
265 -
266 - safe_log_proxy_error("Environment var \"socks_proxy\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".", tmp);
267 - return 1;
268 -}
269 -
270 -static const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type) {
271 - const char *proxy = config_get(CONFIG_SECTION_ACLK, ACLK_PROXY_CONFIG_VAR, ACLK_PROXY_ENV);
272 - *type = PROXY_DISABLED;
273 -
274 - if(strcmp(proxy, "none") == 0)
275 - return proxy;
276 -
277 - if(strcmp(proxy, ACLK_PROXY_ENV) == 0) {
278 - if(check_socks_enviroment(&proxy) == 0)
279 - *type = PROXY_TYPE_SOCKS5;
280 - return proxy;
281 - }
282 -
283 - *type = aclk_verify_proxy(proxy);
284 - if(*type == PROXY_TYPE_UNKNOWN) {
285 - *type = PROXY_DISABLED;
286 - safe_log_proxy_error("Config var \"" ACLK_PROXY_CONFIG_VAR "\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".", proxy);
287 - }
217 + if(!*proxy)
218 + return -1;
219
289 - return proxy;
220 + return lws_set_socks(vhost, proxy);
221 }
222
223 // Return code indicates if connection attempt has started async.
@@ -338,7 +269,7 @@ int aclk_lws_wss_connect(char *host, int port)
269 safe_log_proxy_censor(log);
270 info("Connecting using SOCKS5 proxy:\"%s\"", log);
271 freez(log);
341 - if(_aclk_wss_set_socks(vhost, proxy))
272 + if(aclk_wss_set_socks(vhost, proxy))
273 error("LWS failed to accept socks proxy.");
274 break;
275 default:
aclk/aclk_lws_wss_client.h
+4
@@ -1,3 +1,5 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 #ifndef ACLK_LWS_WSS_CLIENT_H
4 #define ACLK_LWS_WSS_CLIENT_H
5
@@ -79,5 +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);
85 +
86 #define FRAGMENT_SIZE 4096
87 #endif
aclk/agent_cloud_link.c
+23 -101
@@ -2,6 +2,7 @@
2
3 #include "libnetdata/libnetdata.h"
4 #include "agent_cloud_link.h"
5 +#include "aclk_lws_https_client.h"
6
7 // State-machine for the on-connect metadata transmission.
8 // TODO: The AGENT_STATE should be centralized as it would be useful to control error-logging during the initial
@@ -176,7 +177,6 @@ static int create_private_key()
177 char err[512];
178 ERR_error_string_n(ERR_get_error(), err, sizeof(err));
179 error("Claimed agent cannot establish ACLK - cannot create private key: %s", err);
179 - freez(err);
180
181 biofailed:
182 freez(private_key);
@@ -946,75 +946,6 @@ static void aclk_main_cleanup(void *ptr)
946 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
947 }
948
949 -int send_https_request(char *method, char *host, char *port, char *url, BUFFER *b, char *payload)
950 -{
951 - struct timeval timeout = { .tv_sec = 30, .tv_usec = 0 };
952 - int rc=1;
953 -
954 - size_t payload_len = 0;
955 - if (payload != NULL)
956 - payload_len = strlen(payload);
957 -
958 - buffer_flush(b);
959 - buffer_sprintf(
960 - b,
961 - "%s %s HTTP/1.1\r\nHost: %s\r\nAccept: plain/text\r\nContent-length: %zu\r\nAccept-Language: en-us\r\n"
962 - "User-Agent: Netdata/rocks\r\n\r\n",
963 - method, url, host, payload_len);
964 - if (payload != NULL)
965 - buffer_strcat(b, payload);
966 - debug(D_ACLK, "Sending HTTPS req (%zu bytes): '%s'", b->len, buffer_tostring(b));
967 - int sock = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, host, 0, port, &timeout);
968 -
969 - if (unlikely(sock == -1)) {
970 - error("Handshake failed");
971 - return 1;
972 - }
973 -
974 - SSL_CTX *ctx = security_initialize_openssl_client();
975 - if (ctx==NULL) {
976 - error("Cannot allocate SSL context");
977 - goto exit_sock;
978 - }
979 - // Certificate chain: not updating the stores - do we need private CA roots?
980 - // Calls to SSL_CTX_load_verify_locations would go here.
981 - SSL *ssl = SSL_new(ctx);
982 - if (ssl==NULL) {
983 - error("Cannot allocate SSL");
984 - goto exit_CTX;
985 - }
986 - SSL_set_fd(ssl, sock);
987 - int err = SSL_connect(ssl);
988 - if (err!=1) {
989 - error("SSL_connect() failed with err=%d", err);
990 - goto exit_SSL;
991 - }
992 - err = SSL_write(ssl, b->buffer, b->len);
993 - if (err <= 0)
994 - {
995 - error("SSL_write() failed with err=%d", err);
996 - goto exit_SSL;
997 - }
998 - buffer_flush(b);
999 - int bytes_read = SSL_read(ssl, b->buffer, b->size);
1000 - if (bytes_read >= 0) {
1001 - debug(D_ACLK, "Received %d bytes in response", bytes_read);
1002 - b->len = bytes_read;
1003 - }
1004 - else {
1005 - error("No response available - SSL_read()=%d", bytes_read);
1006 - }
1007 - SSL_shutdown(ssl);
1008 - rc = 0;
1009 -exit_SSL:
1010 - SSL_free(ssl);
1011 -exit_CTX:
1012 - SSL_CTX_free(ctx);
1013 -exit_sock:
1014 - close(sock);
1015 - return rc;
1016 -}
1017 -
949 struct dictionary_singleton {
950 char *key;
951 char *result;
@@ -1242,6 +1173,7 @@ int host_end = pos;
1173
1174 void aclk_get_challenge(char *aclk_hostname, char *aclk_port)
1175 {
1176 + char *data_buffer = mallocz(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
1177 debug(D_ACLK, "Performing challenge-response sequence");
1178 if (aclk_password != NULL)
1179 {
@@ -1249,44 +1181,36 @@ void aclk_get_challenge(char *aclk_hostname, char *aclk_port)
1181 aclk_password = NULL;
1182 }
1183 // curl http://cloud-iam-agent-service:8080/api/v1/auth/node/00000000-0000-0000-0000-000000000000/challenge
1252 - BUFFER *b = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
1184 // TODO - target host?
1185 char *agent_id = is_agent_claimed();
1186 if (agent_id == NULL)
1187 {
1188 error("Agent was not claimed - cannot perform challenge/response");
1258 - return;
1189 + goto CLEANUP;
1190 }
1191 char url[1024];
1192 sprintf(url, "/api/v1/auth/node/%s/challenge", agent_id);
1193 info("Retrieving challenge from cloud: %s %s %s", aclk_hostname, aclk_port, url);
1263 - if(send_https_request("GET", aclk_hostname, aclk_port, url, b, NULL))
1194 + if(aclk_send_https_request("GET", aclk_hostname, aclk_port, url, data_buffer, NETDATA_WEB_RESPONSE_INITIAL_SIZE, NULL))
1195 {
1196 error("Challenge failed");
1266 - return;
1197 + goto CLEANUP;
1198 }
1199 struct dictionary_singleton challenge = { .key = "challenge", .result = NULL };
1269 - // Force null-termination?
1270 - char *payload = NULL;
1271 - payload = extract_payload(b);
1272 - if (payload==NULL) {
1273 - error("Could not find payload in http response #1 (the challenge):\n%s", b->buffer);
1274 - return;
1275 - }
1276 - debug(D_ACLK, "Challenge response from cloud: %s", payload);
1277 - if (json_parse(payload, &challenge, json_extract_singleton) != JSON_OK)
1200 +
1201 + debug(D_ACLK, "Challenge response from cloud: %s", data_buffer);
1202 + if ( json_parse(data_buffer, &challenge, json_extract_singleton) != JSON_OK)
1203 {
1204 freez(challenge.result);
1280 - error("Could not parse the json response with the challenge: %s", payload);
1281 - return;
1205 + error("Could not parse the json response with the challenge: %s", data_buffer);
1206 + goto CLEANUP;
1207 }
1208 if (challenge.result == NULL ) {
1284 - error("Could not retrieve challenge from auth response: %s", payload);
1285 - return;
1209 + error("Could not retrieve challenge from auth response: %s", data_buffer);
1210 + goto CLEANUP;
1211 }
1212
1213
1289 -
1214 size_t challenge_len = strlen(challenge.result);
1215 unsigned char decoded[512];
1216 size_t decoded_len = base64_decode((unsigned char*)challenge.result, challenge_len, decoded, sizeof(decoded));
@@ -1304,29 +1228,25 @@ void aclk_get_challenge(char *aclk_hostname, char *aclk_port)
1228 debug(D_ACLK, "Password phase: %s",response_json);
1229 // TODO - host
1230 sprintf(url, "/api/v1/auth/node/%s/password", agent_id);
1307 - if(send_https_request("POST", aclk_hostname, aclk_port, url, b, response_json))
1231 + if(aclk_send_https_request("POST", aclk_hostname, aclk_port, url, data_buffer, NETDATA_WEB_RESPONSE_INITIAL_SIZE, response_json))
1232 {
1233 error("Challenge-response failed");
1310 - return;
1311 - }
1312 - payload = extract_payload(b);
1313 - if (payload==NULL) {
1314 - error("Could not find payload in http response #2 (the password):\n%s", b->buffer);
1315 - return;
1234 + goto CLEANUP;
1235 }
1317 - debug(D_ACLK, "Password response from cloud: %s", payload);
1236 +
1237 + debug(D_ACLK, "Password response from cloud: %s", data_buffer);
1238
1239 struct dictionary_singleton password = { .key = "password", .result = NULL };
1320 - if (json_parse(payload, &password, json_extract_singleton) != JSON_OK)
1240 + if ( json_parse(data_buffer, &password, json_extract_singleton) != JSON_OK)
1241 {
1242 freez(password.result);
1323 - error("Could not parse the json response with the password: %s", payload);
1324 - return;
1243 + error("Could not parse the json response with the password: %s", data_buffer);
1244 + goto CLEANUP;
1245 }
1246
1247 if (password.result == NULL ) {
1248 error("Could not retrieve password from auth response");
1329 - return;
1249 + goto CLEANUP;
1250 }
1251 if (aclk_password != NULL )
1252 freez(aclk_password);
@@ -1334,7 +1254,9 @@ void aclk_get_challenge(char *aclk_hostname, char *aclk_port)
1254 aclk_username = strdupz(agent_id);
1255 aclk_password = password.result;
1256
1337 - buffer_free(b);
1257 +CLEANUP:
1258 + freez(data_buffer);
1259 + return;
1260 }
1261
1262 static void aclk_try_to_connect(char *hostname, char *port, int port_num)
aclk/mqtt.c
+1 -1
@@ -284,7 +284,7 @@ int _link_send_message(char *topic, unsigned char *message, int *mid)
284 if (unlikely(rc != MOSQ_ERR_SUCCESS))
285 return rc;
286
287 - int msg_len = strlen(message);
287 + int msg_len = strlen((char*)message);
288 error("Sending MQTT len=%d starts %02x %02x %02x", msg_len, message[0], message[1], message[2]);
289 rc = mosquitto_publish(mosq, mid, topic, msg_len, message, ACLK_QOS, 0);
290