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