@cryptotaxi247 / netdata-1 / commits / b829cb3ae

Aclk proxy connect log (#21789)

* Improve ACLK logging if proxy is used - Enhance logging if proxy is used (with or without credentials) * - Replace inline proxy display formatting with `aclk_proxy_get_display` helper function. - Simplify and unify proxy display construction in ACLK logging. - Adjust key name in JSON payload from `aclk-proxy` to `aclk_proxy`. * Refactor proxy display construction with new `aclk_proxy_get_full_display` helper function. * Fix incorrect proxy username extraction by replacing `strchr` with `strrchr` in `aclk_proxy_get_display`.

Stelios Fragkakis committed Feb 24, 2026 at 12:44 UTC b829cb3ae2bd2ff88609a990cdce7732de85fb94
7 files changed +157 -20
src/aclk/aclk.c
+11 -5
@@ -1096,11 +1096,14 @@ char *aclk_state(void)
1096 buffer_strcat(wb, "No\n");
1097 else {
1098 const char *cloud_base_url = cloud_config_url_get();
1099 - char *aclk_proxy = (char *)aclk_get_proxy(NULL, true);
1099 +
1100 + char proxy_display[512];
1101 + aclk_proxy_get_full_display(proxy_display, sizeof(proxy_display));
1102 +
1103 usec_t latency = __atomic_load_n(&publish_latency, __ATOMIC_RELAXED);
1104 char latency_str[64];
1105 duration_snprintf(latency_str, sizeof(latency_str), (int64_t) latency, "us", true);
1103 - buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\nACLK Proxy: %s\nPublish Latency: %s\n", claim_id.str, cloud_base_url ? cloud_base_url : "null", aclk_proxy ? aclk_proxy : "none", latency_str);
1106 + buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\nACLK Proxy: %s\nPublish Latency: %s\n", claim_id.str, cloud_base_url ? cloud_base_url : "null", proxy_display, latency_str);
1107 }
1108
1109 bool aclk_is_online = aclk_online();
@@ -1244,9 +1247,12 @@ char *aclk_state_json(void)
1247 tmp = cloud_base_url ? json_object_new_string(cloud_base_url) : NULL;
1248 json_object_object_add(msg, "cloud-url", tmp);
1249
1247 - char *aclk_proxy = (char *)aclk_get_proxy(NULL, true);
1248 - tmp = aclk_proxy ? json_object_new_string(aclk_proxy) : NULL;
1249 - json_object_object_add(msg, "aclk_proxy", tmp);
1250 + {
1251 + char proxy_display[512];
1252 + aclk_proxy_get_full_display(proxy_display, sizeof(proxy_display));
1253 + tmp = json_object_new_string(proxy_display);
1254 + json_object_object_add(msg, "aclk_proxy", tmp);
1255 + }
1256
1257 usec_t latency = __atomic_load_n(&publish_latency, __ATOMIC_RELAXED);
1258 tmp =json_object_new_int64((int64_t) latency);
src/aclk/aclk_proxy.c
+76 -2
@@ -76,6 +76,19 @@ static inline void safe_log_proxy_error(char *str, const char *proxy)
76 freez(log);
77 }
78
79 +// helper to extract "http://host:port" from a proxy URL, skipping credentials
80 +void aclk_proxy_get_display(char *buf, size_t buflen, const char *proxy, ACLK_PROXY_TYPE type)
81 +{
82 + const char *at = strrchr(proxy, '@');
83 + const char *host_start = at ? at + 1 : proxy;
84 + const char *sep = strstr(proxy, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
85 + if (!at && sep)
86 + host_start = sep + strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
87 + snprintfz(buf, buflen, "%s%s", aclk_proxy_type_to_url(type), host_start);
88 +}
89 +
90 +static const char *proxy_source = NULL;
91 +
92 static inline int check_http_environment(const char **proxy)
93 {
94 const char *var = "http_proxy";
@@ -90,6 +103,15 @@ static inline int check_http_environment(const char **proxy)
103
104 if (aclk_verify_proxy(tmp) == PROXY_TYPE_HTTP) {
105 *proxy = tmp;
106 + char display[512];
107 + aclk_proxy_get_display(display, sizeof(display), tmp, PROXY_TYPE_HTTP);
108 + char source_buf[256];
109 + snprintfz(source_buf, sizeof(source_buf), "environment variable '%s'", var);
110 + freez((void *)proxy_source);
111 + proxy_source = strdupz(source_buf);
112 + nd_log(NDLS_DAEMON, NDLP_INFO,
113 + "ACLK: using HTTP proxy %s (%s, from %s)",
114 + display, strchr(tmp, '@') ? "with credentials" : "without credentials", proxy_source);
115 return 0;
116 }
117
@@ -109,14 +131,28 @@ const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
131
132 *type = PROXY_DISABLED;
133
112 - if (!proxy || !*proxy || strcmp(proxy, "none") == 0)
134 + if (!proxy || !*proxy || strcmp(proxy, "none") == 0) {
135 + nd_log(NDLS_DAEMON, NDLP_INFO,
136 + "ACLK: proxy is %s, will connect directly without proxy.",
137 + (!proxy || !*proxy) ? "not configured" : "set to 'none'");
138 + freez((void *)proxy_source);
139 + proxy_source = NULL;
140 return proxy;
141 + }
142
143 if (strcmp(proxy, ACLK_PROXY_ENV) == 0) {
144 if (check_http_environment(&proxy) == 0)
145 *type = PROXY_TYPE_HTTP;
118 - else
146 + else {
147 + if (cloud_config_proxy_is_explicitly_set())
148 + nd_log(NDLS_DAEMON, NDLP_WARNING,
149 + "ACLK: proxy is explicitly set to 'env' but neither 'http_proxy' nor 'https_proxy'"
150 + " environment variables are set. Will connect directly without proxy.");
151 +
152 + freez((void *)proxy_source);
153 + proxy_source = NULL;
154 proxy = NULL;
155 + }
156 return proxy;
157 }
158
@@ -128,6 +164,21 @@ const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
164 "Config var \"" ACLK_PROXY_CONFIG_VAR
165 "\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".",
166 proxy);
167 + freez((void *)proxy_source);
168 + proxy_source = NULL;
169 + }
170 + else {
171 + const char *src = cloud_config_proxy_source_get();
172 + freez((void *)proxy_source);
173 + proxy_source = src ? strdupz(src) : NULL;
174 + char display[512];
175 + aclk_proxy_get_display(display, sizeof(display), proxy, *type);
176 + nd_log(NDLS_DAEMON, NDLP_INFO,
177 + "ACLK: using %s proxy %s (%s, from %s)",
178 + *type == PROXY_TYPE_HTTP ? "HTTP" : "SOCKS5",
179 + display,
180 + strchr(proxy, '@') ? "with credentials" : "without credentials",
181 + proxy_source);
182 }
183
184 return proxy;
@@ -156,3 +207,26 @@ const char *aclk_get_proxy(ACLK_PROXY_TYPE *return_type, bool for_logging)
207 *return_type = proxy_type;
208 return for_logging ? safe_proxy : proxy;
209 }
210 +
211 +const char *aclk_get_proxy_source(void) {
212 + return proxy_source;
213 +}
214 +
215 +void aclk_proxy_get_full_display(char *buf, size_t buflen) {
216 + ACLK_PROXY_TYPE proxy_type;
217 + const char *proxy_str = aclk_get_proxy(&proxy_type, false);
218 +
219 + if (proxy_type == PROXY_DISABLED || proxy_type == PROXY_NOT_SET || !proxy_str) {
220 + snprintfz(buf, buflen, "none");
221 + return;
222 + }
223 +
224 + char host_display[256];
225 + aclk_proxy_get_display(host_display, sizeof(host_display), proxy_str, proxy_type);
226 +
227 + const char *source = aclk_get_proxy_source();
228 + snprintfz(buf, buflen, "%s (%s, from %s)",
229 + host_display,
230 + strchr(proxy_str, '@') ? "with credentials" : "without credentials",
231 + source ? source : "unknown");
232 +}
src/aclk/aclk_proxy.h
+11
@@ -17,5 +17,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, bool for_logging);
20 +const char *aclk_get_proxy_source(void);
21 +void aclk_proxy_get_display(char *buf, size_t buflen, const char *proxy, ACLK_PROXY_TYPE type);
22 +void aclk_proxy_get_full_display(char *buf, size_t buflen);
23 +
24 +static inline const char *aclk_proxy_type_to_url(ACLK_PROXY_TYPE type) {
25 + switch (type) {
26 + case PROXY_TYPE_HTTP: return "http://";
27 + case PROXY_TYPE_SOCKS5: return "socks5://";
28 + default: return "";
29 + }
30 +}
31
32 #endif /* ACLK_PROXY_H */
src/aclk/https_client.c
+30 -8
@@ -763,16 +763,28 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
763
764 bool proxy_used = (request->proxy_host != NULL);
765
766 + // extract protocol prefix from proxy URL for logging
767 + const char *proxy_proto = "";
768 + char proto_buf[16];
769 + if (proxy_used && request->proxy) {
770 + const char *sep = strstr(request->proxy, "://");
771 + if (sep) {
772 + size_t len = (size_t)(sep - request->proxy) + 3;
773 + if (len < sizeof(proto_buf)) {
774 + memcpy(proto_buf, request->proxy, len);
775 + proto_buf[len] = '\0';
776 + proxy_proto = proto_buf;
777 + }
778 + }
779 + }
780 +
781 // assume no proxy
782 const char *connect_host;
783 int connect_port;
769 - const char *proxy_used_str = " (no proxy)";
770 -
784
785 if (unlikely(proxy_used)) {
786 connect_host = request->proxy_host;
787 connect_port = request->proxy_port;
775 - proxy_used_str = request->proxy;
788 } else {
789 connect_host = request->host;
790 connect_port = request->port;
@@ -790,9 +802,14 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
802
803 snprintfz(connect_port_str, PORT_STR_MAX_BYTES, "%d", connect_port);
804
793 - nd_log_daemon(NDLP_INFO, "ACLK: Connecting to %s:%d%s%s",
794 - request->host, request->port,
795 - proxy_used ? " via proxy " : "", proxy_used_str);
805 + if (proxy_used)
806 + nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d via proxy %s%s:%d%s",
807 + request->host, request->port,
808 + proxy_proto, request->proxy_host, request->proxy_port,
809 + request->proxy_username ? " (with credentials)" : " (without credentials)");
810 + else
811 + nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d (no proxy)",
812 + request->host, request->port);
813
814 struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
815 ctx->sock = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, connect_host, 0, connect_port_str, &timeout, fallback_ipv4);
@@ -823,13 +840,18 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
840 ctx->request = &req;
841 rc = handle_http_request(ctx);
842 if (rc != HTTPS_CLIENT_RESP_OK) {
826 - netdata_log_error("ACLK: failed to CONNECT with proxy");
843 + netdata_log_error("ACLK: failed to CONNECT via proxy %s%s:%d to %s:%d",
844 + proxy_proto, request->proxy_host, request->proxy_port,
845 + request->host, request->port);
846 http_parse_ctx_destroy(&ctx->parse_ctx);
847 goto exit_sock;
848 }
849 if (ctx->parse_ctx.http_code != 200) {
850 rc = HTTPS_CLIENT_RESP_PROXY_NOT_200;
832 - netdata_log_error("ACLK: proxy didn't return 200 OK (got %d)", ctx->parse_ctx.http_code);
851 + netdata_log_error("ACLK: proxy %s%s:%d returned HTTP %d (expected 200) for CONNECT to %s:%d",
852 + proxy_proto, request->proxy_host, request->proxy_port,
853 + ctx->parse_ctx.http_code,
854 + request->host, request->port);
855 http_parse_ctx_destroy(&ctx->parse_ctx);
856 goto exit_sock;
857 }
src/aclk/mqtt_websockets/mqtt_wss_client.c
+10 -5
@@ -479,11 +479,16 @@ int mqtt_wss_connect(
479 char port_str[16];
480 snprintf(port_str, sizeof(port_str) -1, "%d", client->port);
481
482 - bool proxy_used = (proxy && proxy->proxy_destination != NULL);
483 -
484 - nd_log_daemon(NDLP_INFO, "ACLK: Connecting to %s:%d%s%s",
485 - client->target_host, client->target_port,
486 - proxy_used ? " via proxy " : " (no proxy)", proxy_used ? proxy->proxy_destination : "");
482 + if (proxy && proxy->type != MQTT_WSS_DIRECT) {
483 + const char *proxy_proto = (proxy->type == MQTT_WSS_PROXY_HTTP) ? "http://" : "socks5://";
484 + nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d via proxy %s%s:%d%s",
485 + client->target_host, client->target_port,
486 + proxy_proto, client->host, client->port,
487 + client->proxy_uname ? " (with credentials)" : " (without credentials)");
488 + }
489 + else
490 + nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d (no proxy)",
491 + client->target_host, client->target_port);
492
493 struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
494 int fd = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, client->host, 0, port_str, &timeout, fallback_ipv4);
src/claim/claim.h
+2
@@ -30,6 +30,8 @@ CLOUD_STATUS claim_reload_and_wait_online(void);
30 const char *cloud_config_url_get(void);
31 void cloud_config_url_set(const char *url);
32 const char *cloud_config_proxy_get(void);
33 +const char *cloud_config_proxy_source_get(void);
34 +bool cloud_config_proxy_is_explicitly_set(void);
35 bool cloud_config_insecure_get(void);
36
37 #endif //NETDATA_CLAIM_H
src/claim/cloud-conf.c
+17
@@ -16,6 +16,9 @@ void cloud_config_url_set(const char *url) {
16 inicfg_set(&cloud_config, CONFIG_SECTION_GLOBAL, "url", url);
17 }
18
19 +static const char *cloud_config_proxy_source = NULL;
20 +static bool cloud_config_proxy_explicitly_set = false;
21 +
22 const char *cloud_config_proxy_get(void) {
23 // load cloud.conf or internal default
24 const char *proxy = inicfg_get(&cloud_config, CONFIG_SECTION_GLOBAL, "proxy", "env");
@@ -28,15 +31,26 @@ const char *cloud_config_proxy_get(void) {
31
32 // update cloud.conf
33 proxy = inicfg_set(&cloud_config, CONFIG_SECTION_GLOBAL, "proxy", proxy);
34 + cloud_config_proxy_source = "netdata.conf [cloud]";
35 + cloud_config_proxy_explicitly_set = true;
36 }
37 else {
38 // set in netdata.conf the proxy of cloud.conf
39 inicfg_set(&netdata_config, CONFIG_SECTION_CLOUD, "proxy", proxy);
40 + cloud_config_proxy_source = "cloud.conf";
41 }
42
43 return proxy;
44 }
45
46 +const char *cloud_config_proxy_source_get(void) {
47 + return cloud_config_proxy_source;
48 +}
49 +
50 +bool cloud_config_proxy_is_explicitly_set(void) {
51 + return cloud_config_proxy_explicitly_set;
52 +}
53 +
54 bool cloud_config_insecure_get(void) {
55 // load it from cloud.conf or use internal default
56 return inicfg_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "insecure", CONFIG_BOOLEAN_NO);
@@ -70,6 +84,9 @@ void cloud_conf_load(int silent) {
84 CONFIG_SECTION_GLOBAL, "cloud base url",
85 CONFIG_SECTION_GLOBAL, "url");
86
87 + // check if proxy was explicitly set in cloud.conf before defaults overwrite it
88 + cloud_config_proxy_explicitly_set = inicfg_exists(&cloud_config, CONFIG_SECTION_GLOBAL, "proxy");
89 +
90 cloud_conf_load_defaults();
91 }
92