master
c 232 lines 7.27 KB
Raw
1 #include "aclk_proxy.h"
2
3 #define ACLK_PROXY_ENV "env"
4 #define ACLK_PROXY_CONFIG_VAR "proxy"
5
6 struct {
7 ACLK_PROXY_TYPE type;
8 const char *url_str;
9 } supported_proxy_types[] = {
10 { .type = PROXY_TYPE_SOCKS5, .url_str = "socks5" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
11 { .type = PROXY_TYPE_SOCKS5H, .url_str = "socks5h" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
12 { .type = PROXY_TYPE_HTTP, .url_str = "http" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
13 { .type = PROXY_TYPE_UNKNOWN, .url_str = NULL },
14 };
15
16 static inline ACLK_PROXY_TYPE aclk_find_proxy(const char *string)
17 {
18 int i = 0;
19 while (supported_proxy_types[i].url_str) {
20 if (!strncmp(supported_proxy_types[i].url_str, string, strlen(supported_proxy_types[i].url_str)))
21 return supported_proxy_types[i].type;
22 i++;
23 }
24 return PROXY_TYPE_UNKNOWN;
25 }
26
27 ACLK_PROXY_TYPE aclk_verify_proxy(const char *string)
28 {
29 if (!string)
30 return PROXY_TYPE_UNKNOWN;
31
32 while (*string == 0x20)
33 string++;
34
35 if (!*string)
36 return PROXY_TYPE_UNKNOWN;
37
38 return aclk_find_proxy(string);
39 }
40
41 // helper function to censor user&password
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;
51
52 while ((auth >= proxy) && (*auth != '@'))
53 auth--;
54
55 //if not found or @ is first char do nothing
56 if (auth <= proxy)
57 return;
58
59 cur = strstr(proxy, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
60 if (!cur)
61 cur = proxy;
62 else
63 cur += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
64
65 while (cur < auth) {
66 *cur = 'X';
67 cur++;
68 }
69 }
70
71 static inline void safe_log_proxy_error(char *str, const char *proxy)
72 {
73 char *log = strdupz(proxy);
74 safe_log_proxy_censor(log);
75 netdata_log_error("%s Provided Value:\"%s\"", str, log);
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_environment_proxy(const char **proxy, ACLK_PROXY_TYPE *type)
93 {
94 const char *var = "http_proxy";
95 char *tmp = getenv(var);
96
97 if (!tmp || !*tmp) {
98 var = "https_proxy";
99 tmp = getenv(var);
100 if (!tmp || !*tmp)
101 return 1;
102 }
103
104 *type = aclk_verify_proxy(tmp);
105 if (*type == PROXY_TYPE_HTTP || *type == PROXY_TYPE_SOCKS5 || *type == PROXY_TYPE_SOCKS5H) {
106 *proxy = tmp;
107 char display[512];
108 aclk_proxy_get_display(display, sizeof(display), tmp, *type);
109 char source_buf[256];
110 snprintfz(source_buf, sizeof(source_buf), "environment variable '%s'", var);
111 freez((void *)proxy_source);
112 proxy_source = strdupz(source_buf);
113 nd_log(NDLS_DAEMON, NDLP_INFO,
114 "ACLK: using %s proxy %s (%s, from %s)",
115 *type == PROXY_TYPE_HTTP ? "HTTP" : (*type == PROXY_TYPE_SOCKS5H ? "SOCKS5H" : "SOCKS5"),
116 display, strchr(tmp, '@') ? "with credentials" : "without credentials", proxy_source);
117 return 0;
118 }
119
120 char buf[1024];
121 snprintfz(buf, sizeof(buf),
122 "Environment var '%s' defined but of unknown format '%s'. "
123 "Supported syntax: 'http://[user:pass@]host:port' or 'socks5[h]://[user:pass@]host:port'.",
124 var, tmp);
125 safe_log_proxy_error(buf, tmp);
126
127 return 1;
128 }
129
130 const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
131 {
132 const char *proxy = cloud_config_proxy_get();
133
134 *type = PROXY_DISABLED;
135
136 if (!proxy || !*proxy || strcmp(proxy, "none") == 0) {
137 nd_log(NDLS_DAEMON, NDLP_INFO,
138 "ACLK: proxy is %s, will connect directly without proxy.",
139 (!proxy || !*proxy) ? "not configured" : "set to 'none'");
140 freez((void *)proxy_source);
141 proxy_source = NULL;
142 return proxy;
143 }
144
145 if (strcmp(proxy, ACLK_PROXY_ENV) == 0) {
146 if (check_environment_proxy(&proxy, type) != 0) {
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
159 *type = aclk_verify_proxy(proxy);
160
161 if (*type == PROXY_TYPE_UNKNOWN) {
162 *type = PROXY_DISABLED;
163 safe_log_proxy_error(
164 "Config var \"" ACLK_PROXY_CONFIG_VAR
165 "\" defined but of unknown format. Supported syntax: \"http://[user:pass@]host:port\" or \"socks5[h]://[user:pass@]host:port\".",
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" : (*type == PROXY_TYPE_SOCKS5H ? "SOCKS5H" : "SOCKS5"),
179 display,
180 strchr(proxy, '@') ? "with credentials" : "without credentials",
181 proxy_source);
182 }
183
184 return proxy;
185 }
186
187 // helper function to read settings only once (static)
188 // as claiming, challenge/response and ACLK
189 // read the same thing, no need to parse again
190 const char *aclk_get_proxy(ACLK_PROXY_TYPE *return_type, bool for_logging)
191 {
192 static const char *proxy = NULL;
193 static const char *safe_proxy = NULL;
194 static ACLK_PROXY_TYPE proxy_type = PROXY_NOT_SET;
195
196 if (proxy_type == PROXY_NOT_SET) {
197 proxy = aclk_lws_wss_get_proxy_setting(&proxy_type);
198 char *log = NULL;
199 if (proxy) {
200 log = strdupz(proxy);
201 safe_log_proxy_censor(log);
202 }
203 safe_proxy = log;
204 }
205
206 if (return_type)
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 }