@cryptotaxi247 / netdata-1 / commits / 474d80ef1

Support HTTP proxy Basic auth (#13762)

Timotej S committed Dec 21, 2022 at 08:29 UTC 474d80ef10c8476c210a5018a3f5c6edcf2d899d
6 files changed +125 -37
aclk/aclk.c
+5 -2
@@ -532,7 +532,7 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
532 }
533
534 struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT };
535 - aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type);
535 + aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type);
536
537 struct mqtt_connect_params mqtt_conn_params = {
538 .clientid = "anon",
@@ -630,7 +630,10 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
630 freez((char*)mqtt_conn_params.username);
631 #endif
632
633 - freez((char *)mqtt_conn_params.will_msg);
633 + freez((char*)mqtt_conn_params.will_msg);
634 + freez((char*)proxy_conf.host);
635 + freez((char*)proxy_conf.username);
636 + freez((char*)proxy_conf.password);
637
638 if (!ret) {
639 last_conn_time_mqtt = now_realtime_sec();
aclk/aclk_otp.c
+5 -20
@@ -14,15 +14,19 @@ static int aclk_https_request(https_req_t *request, https_req_response_t *respon
14 // wrapper for ACLK only which loads ACLK specific proxy settings
15 // then only calls https_request
16 struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT };
17 - aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type);
17 + aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type);
18
19 if (proxy_conf.type == MQTT_WSS_PROXY_HTTP) {
20 request->proxy_host = (char*)proxy_conf.host; // TODO make it const as well
21 request->proxy_port = proxy_conf.port;
22 + request->proxy_username = proxy_conf.username;
23 + request->proxy_password = proxy_conf.password;
24 }
25
26 rc = https_request(request, response);
27 freez((char*)proxy_conf.host);
28 + freez((char*)proxy_conf.username);
29 + freez((char*)proxy_conf.password);
30 return rc;
31 }
32
@@ -303,25 +307,6 @@ inline static int base64_decode_helper(unsigned char *out, int *outl, const unsi
307 return 0;
308 }
309
306 -inline static int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
307 -{
308 - int len;
309 - unsigned char *str = out;
310 - EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
311 - EVP_EncodeInit(ctx);
312 - EVP_EncodeUpdate(ctx, str, outl, in, in_len);
313 - str += *outl;
314 - EVP_EncodeFinal(ctx, str, &len);
315 - *outl += len;
316 - // if we ever expect longer output than what OpenSSL would pack into single line
317 - // we would have to skip the endlines, until then we can just cut the string short
318 - str = (unsigned char*)strchr((char*)out, '\n');
319 - if (str)
320 - *str = 0;
321 - EVP_ENCODE_CTX_free(ctx);
322 - return 0;
323 -}
324 -
310 #define OTP_URL_PREFIX "/api/v1/auth/node/"
311 int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **challenge, int *challenge_bytes)
312 {
aclk/aclk_util.c
+88 -14
@@ -346,43 +346,117 @@ unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, un
346 return delay;
347 }
348
349 +static inline int aclk_parse_pair(const char *src, const char c, char **a, char **b)
350 +{
351 + const char *ptr = strchr(src, c);
352 + if (ptr == NULL)
353 + return 1;
354 +
355 +// allow empty string
356 +/* if (!*(ptr+1))
357 + return 1;*/
358 +
359 + *a = callocz(1, ptr - src + 1);
360 + memcpy (*a, src, ptr - src);
361 +
362 + *b = strdupz(ptr+1);
363 +
364 + return 0;
365 +}
366
367 #define HTTP_PROXY_PREFIX "http://"
351 -void aclk_set_proxy(char **ohost, int *port, enum mqtt_wss_proxy_type *type)
368 +void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type)
369 {
370 ACLK_PROXY_TYPE pt;
371 const char *ptr = aclk_get_proxy(&pt);
372 char *tmp;
356 - char *host;
373 +
374 if (pt != PROXY_TYPE_HTTP)
375 return;
376
377 + *uname = NULL;
378 + *pwd = NULL;
379 *port = 0;
380
381 + char *proxy = strdupz(ptr);
382 + ptr = proxy;
383 +
384 if (!strncmp(ptr, HTTP_PROXY_PREFIX, strlen(HTTP_PROXY_PREFIX)))
385 ptr += strlen(HTTP_PROXY_PREFIX);
386
365 - if ((tmp = strchr(ptr, '@')))
366 - ptr = tmp;
387 + if ((tmp = strchr(ptr, '@'))) {
388 + *tmp = 0;
389 + if(aclk_parse_pair(ptr, ':', uname, pwd)) {
390 + error_report("Failed to get username and password for proxy. Will attempt connection without authentication");
391 + }
392 + ptr = tmp+1;
393 + }
394
368 - if ((tmp = strchr(ptr, '/'))) {
369 - host = mallocz((tmp - ptr) + 1);
370 - memcpy(host, ptr, (tmp - ptr));
371 - host[tmp - ptr] = 0;
372 - } else
373 - host = strdupz(ptr);
395 + if (!*ptr) {
396 + freez(proxy);
397 + freez(*uname);
398 + freez(*pwd);
399 + return;
400 + }
401
375 - if ((tmp = strchr(host, ':'))) {
402 + if ((tmp = strchr(ptr, ':'))) {
403 *tmp = 0;
404 tmp++;
378 - *port = atoi(tmp);
405 + if(*tmp)
406 + *port = atoi(tmp);
407 }
408 + *ohost = strdupz(ptr);
409
410 if (*port <= 0 || *port > 65535)
411 *port = 8080;
412
384 - *ohost = host;
385 -
413 if (type)
414 *type = MQTT_WSS_PROXY_HTTP;
415 + else {
416 + freez(*uname);
417 + freez(*pwd);
418 + }
419 +
420 + freez(proxy);
421 +}
422 +
423 +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
424 +static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
425 +{
426 + EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
427 +
428 + if (ctx != NULL) {
429 + memset(ctx, 0, sizeof(*ctx));
430 + }
431 + return ctx;
432 +}
433 +static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
434 +{
435 + OPENSSL_free(ctx);
436 + return;
437 +}
438 +#endif
439 +
440 +int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
441 +{
442 + int len;
443 + unsigned char *str = out;
444 + EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
445 + EVP_EncodeInit(ctx);
446 + EVP_EncodeUpdate(ctx, str, outl, in, in_len);
447 + str += *outl;
448 + EVP_EncodeFinal(ctx, str, &len);
449 + *outl += len;
450 +
451 + str = out;
452 + while(*str) {
453 + if (*str != 0x0D && *str != 0x0A)
454 + *out++ = *str++;
455 + else
456 + str++;
457 + }
458 + *out = 0;
459 +
460 + EVP_ENCODE_CTX_free(ctx);
461 + return 0;
462 }
aclk/aclk_util.h
+3 -1
@@ -107,6 +107,8 @@ extern volatile int aclk_conversation_log_counter;
107 unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, unsigned long int max);
108 #define aclk_tbeb_reset(x) aclk_tbeb_delay(1, 0, 0, 0)
109
110 -void aclk_set_proxy(char **ohost, int *port, enum mqtt_wss_proxy_type *type);
110 +void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type);
111 +
112 +int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len);
113
114 #endif /* ACLK_UTIL_H */
aclk/https_client.c
+22
@@ -6,6 +6,8 @@
6
7 #include "mqtt_websockets/c-rbuf/include/ringbuffer.h"
8
9 +#include "aclk_util.h"
10 +
11 enum http_parse_state {
12 HTTP_PARSE_INITIAL = 0,
13 HTTP_PARSE_HEADERS,
@@ -392,6 +394,24 @@ static int handle_http_request(https_req_ctx_t *ctx) {
394 if (ctx->request->request_type == HTTP_REQ_POST && ctx->request->payload && ctx->request->payload_size) {
395 buffer_sprintf(hdr, "Content-Length: %zu\x0D\x0A", ctx->request->payload_size);
396 }
397 + if (ctx->request->proxy_username) {
398 + size_t creds_plain_len = strlen(ctx->request->proxy_username) + strlen(ctx->request->proxy_password) + 1 /* ':' */;
399 + char *creds_plain = callocz(1, creds_plain_len + 1);
400 + char *ptr = creds_plain;
401 + strcpy(ptr, ctx->request->proxy_username);
402 + ptr += strlen(ctx->request->proxy_username);
403 + *ptr++ = ':';
404 + strcpy(ptr, ctx->request->proxy_password);
405 +
406 + int creds_base64_len = (((4 * creds_plain_len / 3) + 3) & ~3);
407 + // OpenSSL encoder puts newline every 64 output bytes
408 + // we remove those but during encoding we need that space in the buffer
409 + creds_base64_len += (1+(creds_base64_len/64)) * strlen("\n");
410 + char *creds_base64 = callocz(1, creds_base64_len + 1);
411 + base64_encode_helper((unsigned char*)creds_base64, &creds_base64_len, (unsigned char*)creds_plain, creds_plain_len);
412 + buffer_sprintf(hdr, "Proxy-Authorization: Basic %s\x0D\x0A", creds_base64);
413 + freez(creds_plain);
414 + }
415
416 buffer_strcat(hdr, "\x0D\x0A");
417
@@ -491,6 +511,8 @@ int https_request(https_req_t *request, https_req_response_t *response) {
511 req.host = request->host;
512 req.port = request->port;
513 req.url = request->url;
514 + req.proxy_username = request->proxy_username;
515 + req.proxy_password = request->proxy_password;
516 ctx->request = &req;
517 if (handle_http_request(ctx)) {
518 error("Failed to CONNECT with proxy");
aclk/https_client.h
+2
@@ -25,6 +25,8 @@ typedef struct {
25
26 char *proxy_host;
27 int proxy_port;
28 + const char *proxy_username;
29 + const char *proxy_password;
30 } https_req_t;
31
32 typedef struct {