Record proxy information when establishing ACLK (#20747)
* Additional logging for ACLK connections when proxy is used Add ACLK proxy info in aclk-state CLI command and api/v1/aclk * Code formatting * Remove unused includes and clean up command pipe logging * Disable socks for now; not working * Remove SOCKS proxy environment check
Stelios Fragkakis committed
Aug 3, 2025 at 21:11 UTC
87db5381490a3d2f3bb2a84a0a4558c6ba6fa7bd
12 files changed
+90
-68
src/aclk/aclk.c
+16
-5
@@ -747,8 +747,14 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
747
748
int ssl_flags = cloud_config_insecure_get() ? MQTT_WSS_SSL_ALLOW_SELF_SIGNED : MQTT_WSS_SSL_CERT_CHECK_FULL;
749
750
- struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT };
751
- aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type);
750
+ struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .proxy_destination = NULL, .type = MQTT_WSS_DIRECT };
751
+ aclk_set_proxy(
752
+ (char **)&proxy_conf.host,
753
+ &proxy_conf.port,
754
+ (char **)&proxy_conf.username,
755
+ (char **)&proxy_conf.password,
756
+ (char **)&proxy_conf.proxy_destination,
757
+ &proxy_conf.type);
758
759
#ifdef ACLK_DISABLE_CHALLENGE
760
int mqtt_rc = mqtt_wss_connect(client, base_url.host, base_url.port, &mqtt_conn_params, ssl_flags, &proxy_conf);
@@ -836,7 +842,7 @@ void aclk_main(void *ptr)
842
worker_register_job_name(WORKER_ACLK_WAITING_TO_CONNECT, "conn wait");
843
844
ACLK_PROXY_TYPE proxy_type;
839
- aclk_get_proxy(&proxy_type);
845
+ aclk_get_proxy(&proxy_type, false);
846
if (proxy_type == PROXY_TYPE_SOCKS5) {
847
netdata_log_error("ACLK: SOCKS5 proxy is not supported by ACLK-NG yet.");
848
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
@@ -1073,7 +1079,8 @@ char *aclk_state(void)
1079
buffer_strcat(wb, "No\n");
1080
else {
1081
const char *cloud_base_url = cloud_config_url_get();
1076
- buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\n", claim_id.str, cloud_base_url ? cloud_base_url : "null");
1082
+ char *aclk_proxy = (char *)aclk_get_proxy(NULL, true);
1083
+ buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\nACLK Proxy: %s\n", claim_id.str, cloud_base_url ? cloud_base_url : "null", aclk_proxy ? aclk_proxy : "none");
1084
}
1085
1086
buffer_sprintf(wb, "Online: %s\nReconnect count: %d\nBanned By Cloud: %s\n", aclk_online() ? "Yes" : "No", aclk_connection_counter > 0 ? (aclk_connection_counter - 1) : 0, aclk_disable_runtime ? "Yes" : "No");
@@ -1200,6 +1207,10 @@ char *aclk_state_json(void)
1207
tmp = cloud_base_url ? json_object_new_string(cloud_base_url) : NULL;
1208
json_object_object_add(msg, "cloud-url", tmp);
1209
1210
+ char *aclk_proxy = (char *)aclk_get_proxy(NULL, true);
1211
+ tmp = aclk_proxy ? json_object_new_string(aclk_proxy) : NULL;
1212
+ json_object_object_add(msg, "aclk_proxy", tmp);
1213
+
1214
tmp = json_object_new_boolean(aclk_online());
1215
json_object_object_add(msg, "online", tmp);
1216
@@ -1288,7 +1299,7 @@ void add_aclk_host_labels(void) {
1299
rrdlabels_add(labels, "_aclk_available", "true", RRDLABEL_SRC_AUTO|RRDLABEL_SRC_ACLK);
1300
ACLK_PROXY_TYPE aclk_proxy;
1301
char *proxy_str;
1291
- aclk_get_proxy(&aclk_proxy);
1302
+ aclk_get_proxy(&aclk_proxy, false);
1303
1304
switch(aclk_proxy) {
1305
case PROXY_TYPE_SOCKS5:
src/aclk/aclk_otp.c
+11
-4
@@ -8,14 +8,21 @@ static https_client_resp_t aclk_https_request(https_req_t *request, https_req_re
8
https_client_resp_t rc;
9
// wrapper for ACLK only which loads ACLK specific proxy settings
10
// then only calls https_request
11
- struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT };
12
- aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type);
11
+ struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .proxy_destination = NULL, .type = MQTT_WSS_DIRECT };
12
+ aclk_set_proxy(
13
+ (char **)&proxy_conf.host,
14
+ &proxy_conf.port,
15
+ (char **)&proxy_conf.username,
16
+ (char **)&proxy_conf.password,
17
+ (char **)&proxy_conf.proxy_destination,
18
+ &proxy_conf.type);
19
20
if (proxy_conf.type == MQTT_WSS_PROXY_HTTP) {
15
- request->proxy_host = (char*)proxy_conf.host; // TODO make it const as well
21
+ request->proxy_host = (char *)proxy_conf.host;
22
request->proxy_port = proxy_conf.port;
23
request->proxy_username = proxy_conf.username;
24
request->proxy_password = proxy_conf.password;
25
+ request->proxy = proxy_conf.proxy_destination;
26
}
27
28
rc = https_request(request, response, fallback_ipv4);
@@ -33,7 +40,7 @@ struct auth_data {
40
41
#define PARSE_ENV_JSON_CHK_TYPE(it, type, name) \
42
if (json_object_get_type(json_object_iter_peek_value(it)) != type) { \
36
- netdata_log_error("ACLK: value of key \"%s\" should be %s", name, #type); \
43
+ netdata_log_error("ACLK: value of key \"%s\" should be %s", name, #type); \
44
goto exit; \
45
}
46
src/aclk/aclk_proxy.c
+19
-43
@@ -1,7 +1,5 @@
1
#include "aclk_proxy.h"
2
3
-#include "database/rrd.h"
4
-
3
#define ACLK_PROXY_ENV "env"
4
#define ACLK_PROXY_CONFIG_VAR "proxy"
5
@@ -44,6 +42,9 @@ ACLK_PROXY_TYPE aclk_verify_proxy(const char *string)
42
// for logging purposes
43
void safe_log_proxy_censor(char *proxy)
44
{
45
+ if (!proxy)
46
+ return;
47
+
48
size_t length = strlen(proxy);
49
char *auth = proxy + length - 1;
50
char *cur;
@@ -75,24 +76,6 @@ static inline void safe_log_proxy_error(char *str, const char *proxy)
76
freez(log);
77
}
78
78
-static inline int check_socks_enviroment(const char **proxy)
79
-{
80
- char *tmp = getenv("socks_proxy");
81
-
82
- if (!tmp || !*tmp)
83
- return 1;
84
-
85
- if (aclk_verify_proxy(tmp) == PROXY_TYPE_SOCKS5) {
86
- *proxy = tmp;
87
- return 0;
88
- }
89
-
90
- safe_log_proxy_error(
91
- "Environment var \"socks_proxy\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:port\".",
92
- tmp);
93
- return 1;
94
-}
95
-
79
static inline int check_http_environment(const char **proxy)
80
{
81
const char *var = "http_proxy";
@@ -130,31 +113,15 @@ const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
113
return proxy;
114
115
if (strcmp(proxy, ACLK_PROXY_ENV) == 0) {
133
- if (check_socks_enviroment(&proxy) == 0) {
134
-#ifdef LWS_WITH_SOCKS5
135
- *type = PROXY_TYPE_SOCKS5;
136
- return proxy;
137
-#else
138
- safe_log_proxy_error("socks_proxy environment variable set to use SOCKS5 proxy "
139
- "but Libwebsockets used doesn't have SOCKS5 support built in. "
140
- "Ignoring and checking for other options.",
141
- proxy);
142
-#endif
143
- }
116
if (check_http_environment(&proxy) == 0)
117
*type = PROXY_TYPE_HTTP;
118
+ else
119
+ proxy = NULL;
120
return proxy;
121
}
122
123
*type = aclk_verify_proxy(proxy);
150
-#ifndef LWS_WITH_SOCKS5
151
- if (*type == PROXY_TYPE_SOCKS5) {
152
- safe_log_proxy_error(
153
- "Config var \"" ACLK_PROXY_CONFIG_VAR
154
- "\" set to use SOCKS5 proxy but Libwebsockets used is built without support for SOCKS proxy. ACLK will be disabled.",
155
- proxy);
156
- }
157
-#endif
124
+
125
if (*type == PROXY_TYPE_UNKNOWN) {
126
*type = PROXY_DISABLED;
127
safe_log_proxy_error(
@@ -169,14 +136,23 @@ const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
136
// helper function to read settings only once (static)
137
// as claiming, challenge/response and ACLK
138
// read the same thing, no need to parse again
172
-const char *aclk_get_proxy(ACLK_PROXY_TYPE *type)
139
+const char *aclk_get_proxy(ACLK_PROXY_TYPE *return_type, bool for_logging)
140
{
141
static const char *proxy = NULL;
142
+ static const char *safe_proxy = NULL;
143
static ACLK_PROXY_TYPE proxy_type = PROXY_NOT_SET;
144
177
- if (proxy_type == PROXY_NOT_SET)
145
+ if (proxy_type == PROXY_NOT_SET) {
146
proxy = aclk_lws_wss_get_proxy_setting(&proxy_type);
147
+ char *log = NULL;
148
+ if (proxy) {
149
+ log = strdupz(proxy);
150
+ safe_log_proxy_censor(log);
151
+ }
152
+ safe_proxy = log;
153
+ }
154
180
- *type = proxy_type;
181
- return proxy;
155
+ if (return_type)
156
+ *return_type = proxy_type;
157
+ return for_logging ? safe_proxy : proxy;
158
}
src/aclk/aclk_proxy.h
+2
-2
@@ -1,7 +1,7 @@
1
#ifndef ACLK_PROXY_H
2
#define ACLK_PROXY_H
3
4
-#include <config.h>
4
+#include "aclk.h"
5
6
#define ACLK_PROXY_PROTO_ADDR_SEPARATOR "://"
7
@@ -16,6 +16,6 @@ typedef enum aclk_proxy_type {
16
ACLK_PROXY_TYPE aclk_verify_proxy(const char *string);
17
const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type);
18
void safe_log_proxy_censor(char *proxy);
19
-const char *aclk_get_proxy(ACLK_PROXY_TYPE *type);
19
+const char *aclk_get_proxy(ACLK_PROXY_TYPE *type, bool for_logging);
20
21
#endif /* ACLK_PROXY_H */
src/aclk/aclk_util.c
+4
-2
@@ -386,10 +386,12 @@ static inline int aclk_parse_userpass_pair(const char *src, const char c, char *
386
}
387
388
#define HTTP_PROXY_PREFIX "http://"
389
-void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type)
389
+void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd,
390
+ char **log_proxy, enum mqtt_wss_proxy_type *type)
391
{
392
ACLK_PROXY_TYPE pt;
392
- const char *ptr = aclk_get_proxy(&pt);
393
+ const char *ptr = aclk_get_proxy(&pt, false);
394
+ *log_proxy = (char *) aclk_get_proxy(&pt, true);
395
char *tmp;
396
397
if (pt != PROXY_TYPE_HTTP)
src/aclk/aclk_util.h
+2
-1
@@ -106,6 +106,7 @@ extern volatile int aclk_conversation_log_counter;
106
unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int mins_ms, unsigned long int min_ms);
107
#define aclk_tbeb_reset(x) aclk_tbeb_delay(1, 0, 0, 0)
108
109
-void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type);
109
+void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd,
110
+ char **log_proxy, enum mqtt_wss_proxy_type *type);
111
112
#endif /* ACLK_UTIL_H */
src/aclk/https_client.c
+22
-4
@@ -664,7 +664,6 @@ static https_client_resp_t handle_http_request(https_req_ctx_t *ctx) {
664
665
buffer_strcat(hdr, HTTP_1_1 HTTP_ENDL);
666
667
- //TODO Headers!
667
buffer_sprintf(hdr, "Host: %s\x0D\x0A", ctx->request->host);
668
buffer_strcat(hdr, "User-Agent: Netdata/rocks newhttpclient\x0D\x0A");
669
@@ -755,9 +754,22 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
754
int ret;
755
char connect_port_str[PORT_STR_MAX_BYTES];
756
758
- const char *connect_host = request->proxy_host ? request->proxy_host : request->host;
759
- int connect_port = request->proxy_host ? request->proxy_port : request->port;
760
- struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
757
+ bool proxy_used = (request->proxy_host != NULL);
758
+
759
+ // assume no proxy
760
+ const char *connect_host;
761
+ int connect_port;
762
+ const char *proxy_used_str = " (no proxy)";
763
+
764
+
765
+ if (unlikely(proxy_used)) {
766
+ connect_host = request->proxy_host;
767
+ connect_port = request->proxy_port;
768
+ proxy_used_str = request->proxy;
769
+ } else {
770
+ connect_host = request->host;
771
+ connect_port = request->port;
772
+ }
773
774
https_req_ctx_t *ctx = callocz(1, sizeof(https_req_ctx_t));
775
ctx->req_start_time = now_realtime_sec();
@@ -771,6 +783,11 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
783
784
snprintfz(connect_port_str, PORT_STR_MAX_BYTES, "%d", connect_port);
785
786
+ nd_log_daemon(NDLP_INFO, "ACLK: Connecting to %s:%d%s%s",
787
+ request->host, request->port,
788
+ proxy_used ? " via proxy " : "", proxy_used_str);
789
+
790
+ struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
791
ctx->sock = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, connect_host, 0, connect_port_str, &timeout, fallback_ipv4);
792
if (ctx->sock < 0) {
793
rc = -ctx->sock;
@@ -887,6 +904,7 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
904
// only exact data without affixed 0x00
905
((char*)response->payload)[response->payload_size] = 0; // mallocz(response->payload_size + 1);
906
}
907
+ errno_clear();
908
netdata_log_info("ACLK: HTTPS \"%s\" request to \"%s\" finished with HTTP code: %d", http_req_type_to_str(ctx->request->request_type), ctx->request->host, response->http_code);
909
910
rc = HTTPS_CLIENT_RESP_OK;
src/aclk/https_client.h
+2
-1
@@ -64,10 +64,11 @@ typedef struct {
64
void *payload;
65
size_t payload_size;
66
67
- char *proxy_host;
67
+ const char *proxy_host;
68
int proxy_port;
69
const char *proxy_username;
70
const char *proxy_password;
71
+ const char *proxy;
72
} https_req_t;
73
74
typedef struct {
src/aclk/mqtt_websockets/mqtt_ng.c
+5
-4
@@ -2063,24 +2063,25 @@ int handle_incoming_traffic(struct mqtt_ng_client *client)
2063
client->connect_msg = NULL;
2064
2065
if (client->client_state != MQTT_STATE_CONNECTING) {
2066
- nd_log(NDLS_DAEMON, NDLP_ERR, "Received unexpected CONNACK");
2066
+ nd_log(NDLS_DAEMON, NDLP_ERR, "ACLK: Received unexpected CONNACK");
2067
client->client_state = MQTT_STATE_ERROR;
2068
return MQTT_NG_CLIENT_PROTOCOL_ERROR;
2069
}
2070
2071
if ((prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_MAX_PKT_SIZE)) != NULL) {
2072
- nd_log(NDLS_DAEMON, NDLP_INFO, "MQTT server limits message size to %" PRIu32, prop->data.uint32);
2072
+ nd_log(NDLS_DAEMON, NDLP_INFO, "ACLK: MQTT server limits message size to %" PRIu32, prop->data.uint32);
2073
client->max_msg_size = prop->data.uint32;
2074
}
2075
2076
if (client->connack_callback)
2077
client->connack_callback(client->user_ctx, client->parser.mqtt_packet.connack.reason_code);
2078
if (!client->parser.mqtt_packet.connack.reason_code) {
2079
- nd_log(NDLS_DAEMON, NDLP_INFO, "MQTT Connection Accepted By Server");
2079
+ nd_log(NDLS_DAEMON, NDLP_INFO, "ACLK: MQTT Connection Accepted By Server");
2080
client->client_state = MQTT_STATE_CONNECTED;
2081
break;
2082
}
2083
- client->client_state = MQTT_STATE_ERROR; return MQTT_NG_CLIENT_SERVER_RETURNED_ERROR;
2083
+ client->client_state = MQTT_STATE_ERROR;
2084
+ return MQTT_NG_CLIENT_SERVER_RETURNED_ERROR;
2085
2086
case MQTT_CPT_PUBACK:
2087
worker_is_busy(WORKER_ACLK_CPT_PUBACK);
src/aclk/mqtt_websockets/mqtt_wss_client.c
+6
-1
@@ -488,6 +488,12 @@ int mqtt_wss_connect(
488
char port_str[16];
489
snprintf(port_str, sizeof(port_str) -1, "%d", client->port);
490
491
+ bool proxy_used = (proxy && proxy->proxy_destination != NULL);
492
+
493
+ nd_log_daemon(NDLP_INFO, "ACLK: Connecting to %s:%d%s%s",
494
+ client->target_host, client->target_port,
495
+ proxy_used ? " via proxy " : " (no proxy)", proxy_used ? proxy->proxy_destination : "");
496
+
497
struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
498
int fd = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, client->host, 0, port_str, &timeout, fallback_ipv4);
499
if (fd < 0) {
@@ -582,7 +588,6 @@ int mqtt_wss_connect(
588
589
client->mqtt_keepalive = (mqtt_params->keep_alive ? mqtt_params->keep_alive : 400);
590
585
- nd_log(NDLS_DAEMON, NDLP_INFO, "Going to connect using internal MQTT 5 implementation");
591
struct mqtt_auth_properties auth;
592
auth.client_id = (char*)mqtt_params->clientid;
593
auth.client_id_free = NULL;
src/aclk/mqtt_websockets/mqtt_wss_client.h
+1
@@ -95,6 +95,7 @@ struct mqtt_wss_proxy {
95
int port;
96
const char *username;
97
const char *password;
98
+ const char *proxy_destination;
99
};
100
101
/* TODO!!! update the description
src/daemon/commands.c
-1
@@ -672,7 +672,6 @@ static void pipe_read_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf
672
if (0 == nread) {
673
netdata_log_info("%s: Zero bytes read by command pipe.", __func__);
674
} else if (UV_EOF == nread) {
675
- netdata_log_info("EOF found in command pipe.");
675
parse_commands(cmd_ctx);
676
} else if (nread < 0) {
677
netdata_log_error("%s: %s", __func__, uv_strerror(nread));