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 {