diff options
author | David Walter Seikel | 2013-01-13 17:29:19 +1000 |
---|---|---|
committer | David Walter Seikel | 2013-01-13 17:29:19 +1000 |
commit | 07274513e984f0b5544586c74508ccd16e7dcafa (patch) | |
tree | b32ff2a9136fbc1a4a6a0ed1e4d79cde0f5f16d9 /libraries/ecore/src/lib/ecore_con/ecore_con_socks.c | |
parent | Added Irrlicht 1.8, but without all the Windows binaries. (diff) | |
download | SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.zip SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.gz SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.bz2 SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.xz |
Remove EFL, since it's been released now.
Diffstat (limited to 'libraries/ecore/src/lib/ecore_con/ecore_con_socks.c')
-rw-r--r-- | libraries/ecore/src/lib/ecore_con/ecore_con_socks.c | 940 |
1 files changed, 0 insertions, 940 deletions
diff --git a/libraries/ecore/src/lib/ecore_con/ecore_con_socks.c b/libraries/ecore/src/lib/ecore_con/ecore_con_socks.c deleted file mode 100644 index 686f73b..0000000 --- a/libraries/ecore/src/lib/ecore_con/ecore_con_socks.c +++ /dev/null | |||
@@ -1,940 +0,0 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <stdio.h> | ||
6 | #include <string.h> | ||
7 | #include <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <errno.h> | ||
10 | #include <unistd.h> | ||
11 | #include <fcntl.h> | ||
12 | |||
13 | #ifdef HAVE_SYS_SOCKET_H | ||
14 | # include <sys/socket.h> | ||
15 | #endif | ||
16 | |||
17 | #ifdef HAVE_NETINET_TCP_H | ||
18 | # include <netinet/tcp.h> | ||
19 | #endif | ||
20 | |||
21 | #ifdef HAVE_NET_IF_H | ||
22 | # include <net/if.h> | ||
23 | #endif | ||
24 | |||
25 | /* if net/if.h is not found or if an older versions of net/if.h is provided | ||
26 | which does not define IF_NAMESIZE. We must define it ourselves */ | ||
27 | #ifndef IF_NAMESIZE | ||
28 | # ifdef IFNAMSIZ | ||
29 | # define IF_NAMESIZE IFNAMSIZ | ||
30 | # else | ||
31 | # define IF_NAMESIZE 16 | ||
32 | # endif | ||
33 | #endif | ||
34 | |||
35 | #ifdef HAVE_NETINET_IN_H | ||
36 | # include <netinet/in.h> | ||
37 | #endif | ||
38 | |||
39 | #ifdef HAVE_ARPA_INET_H | ||
40 | # include <arpa/inet.h> | ||
41 | #endif | ||
42 | |||
43 | #ifdef HAVE_SYS_UN_H | ||
44 | # include <sys/un.h> | ||
45 | #endif | ||
46 | |||
47 | #ifdef HAVE_WS2TCPIP_H | ||
48 | # include <ws2tcpip.h> | ||
49 | #endif | ||
50 | |||
51 | #ifdef HAVE_EVIL | ||
52 | # include <Evil.h> | ||
53 | #endif | ||
54 | |||
55 | #include "Ecore.h" | ||
56 | #include "ecore_private.h" | ||
57 | #include "Ecore_Con.h" | ||
58 | #include "ecore_con_private.h" | ||
59 | |||
60 | /* http://tools.ietf.org/html/rfc1928 | ||
61 | o X'00' NO AUTHENTICATION REQUIRED | ||
62 | o X'01' GSSAPI | ||
63 | o X'02' USERNAME/PASSWORD | ||
64 | o X'03' to X'7F' IANA ASSIGNED | ||
65 | o X'80' to X'FE' RESERVED FOR PRIVATE METHODS | ||
66 | o X'FF' NO ACCEPTABLE METHODS | ||
67 | */ | ||
68 | #define ECORE_CON_SOCKS_V5_METHOD_NONE 0 | ||
69 | #define ECORE_CON_SOCKS_V5_METHOD_GSSAPI 1 | ||
70 | #define ECORE_CON_SOCKS_V5_METHOD_USERPASS 2 | ||
71 | |||
72 | static int ECORE_CON_SOCKS_V5_METHODS[] = | ||
73 | { | ||
74 | ECORE_CON_SOCKS_V5_METHOD_NONE, | ||
75 | // ECORE_CON_SOCKS_V5_METHOD_GSSAPI, TODO | ||
76 | ECORE_CON_SOCKS_V5_METHOD_USERPASS | ||
77 | }; | ||
78 | |||
79 | #define ECORE_CON_SOCKS_V5_TOTAL_METHODS sizeof(ECORE_CON_SOCKS_V5_METHODS) | ||
80 | |||
81 | #define _ecore_con_server_kill(svr) do { \ | ||
82 | DBG("KILL %p", (svr)); \ | ||
83 | _ecore_con_server_kill((svr)); \ | ||
84 | } while (0) | ||
85 | |||
86 | Eina_List *ecore_con_socks_proxies = NULL; | ||
87 | |||
88 | static Ecore_Con_Socks * | ||
89 | _ecore_con_socks_find(unsigned char version, const char *ip, int port, const char *username, size_t ulen, const char *password, size_t plen) | ||
90 | { | ||
91 | Eina_List *l; | ||
92 | Ecore_Con_Socks_v5 *ecs; | ||
93 | |||
94 | if (!ecore_con_socks_proxies) return NULL; | ||
95 | |||
96 | EINA_LIST_FOREACH(ecore_con_socks_proxies, l, ecs) | ||
97 | { | ||
98 | if (ecs->version != version) continue; | ||
99 | if (strcmp(ecs->ip, ip)) continue; | ||
100 | if ((port != -1) && (port != ecs->port)) continue; | ||
101 | if (ulen != ecs->ulen) continue; | ||
102 | if (username && strcmp(ecs->username, username)) continue; | ||
103 | if (version == 5) | ||
104 | { | ||
105 | if (plen != ecs->plen) continue; | ||
106 | if (password && strcmp(ecs->password, password)) continue; | ||
107 | } | ||
108 | return (Ecore_Con_Socks*)ecs; | ||
109 | } | ||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | _ecore_con_socks_free(Ecore_Con_Socks *ecs) | ||
115 | { | ||
116 | ECORE_CON_SOCKS_CAST_ELSE(ecs) return; | ||
117 | |||
118 | if (_ecore_con_proxy_once == ecs) _ecore_con_proxy_once = NULL; | ||
119 | if (_ecore_con_proxy_global == ecs) _ecore_con_proxy_global = NULL; | ||
120 | eina_stringshare_del(ecs->ip); | ||
121 | eina_stringshare_del(ecs->username); | ||
122 | free(ecs); | ||
123 | } | ||
124 | |||
125 | static Eina_Bool | ||
126 | _ecore_con_socks_svr_init_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4) | ||
127 | { | ||
128 | size_t addrlen, buflen, ulen = 1; | ||
129 | unsigned char *sbuf; | ||
130 | |||
131 | addrlen = v4->lookup ? strlen(svr->name) + 1 : 0; | ||
132 | if (v4->username) ulen += v4->ulen; | ||
133 | buflen = sizeof(char) * (8 + ulen + addrlen); | ||
134 | sbuf = malloc(buflen); | ||
135 | if (!sbuf) | ||
136 | { | ||
137 | ecore_con_event_server_error(svr, "Memory allocation failure!"); | ||
138 | _ecore_con_server_kill(svr); | ||
139 | return EINA_FALSE; | ||
140 | } | ||
141 | /* http://en.wikipedia.org/wiki/SOCKS */ | ||
142 | sbuf[0] = 4; | ||
143 | sbuf[1] = v4->bind ? 2 : 1; | ||
144 | sbuf[2] = svr->port >> 8; | ||
145 | sbuf[3] = svr->port & 0xff; | ||
146 | if (addrlen) | ||
147 | { | ||
148 | sbuf[4] = sbuf[5] = sbuf[6] = 0; | ||
149 | sbuf[7] = 1; | ||
150 | } | ||
151 | else | ||
152 | /* SOCKSv4 only handles IPV4, so addrlen is always 4 */ | ||
153 | memcpy(sbuf + 4, svr->ecs_addr, 4); | ||
154 | if (v4->username) | ||
155 | memcpy(sbuf + 8, v4->username, ulen); | ||
156 | else | ||
157 | sbuf[8] = 0; | ||
158 | if (addrlen) memcpy(sbuf + 8 + ulen, svr->name, addrlen); | ||
159 | |||
160 | svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen); | ||
161 | return EINA_TRUE; | ||
162 | } | ||
163 | |||
164 | static Eina_Bool | ||
165 | _ecore_con_socks_svr_init_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5) | ||
166 | { | ||
167 | size_t buflen; | ||
168 | unsigned int x; | ||
169 | unsigned char *sbuf; | ||
170 | |||
171 | if (v5->username) | ||
172 | buflen = sizeof(char) * (2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS); | ||
173 | else | ||
174 | buflen = 3; | ||
175 | sbuf = malloc(buflen); | ||
176 | if (!sbuf) | ||
177 | { | ||
178 | ecore_con_event_server_error(svr, "Memory allocation failure!"); | ||
179 | _ecore_con_server_kill(svr); | ||
180 | return EINA_FALSE; | ||
181 | } | ||
182 | /* http://en.wikipedia.org/wiki/SOCKS | ||
183 | * http://tools.ietf.org/html/rfc1928 | ||
184 | */ | ||
185 | sbuf[0] = 5; | ||
186 | if (v5->username) | ||
187 | { | ||
188 | sbuf[1] = ECORE_CON_SOCKS_V5_TOTAL_METHODS; | ||
189 | for (x = 2; x < 2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS; x++) | ||
190 | sbuf[x] = ECORE_CON_SOCKS_V5_METHODS[x - 2]; | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | sbuf[1] = 1; | ||
195 | sbuf[2] = ECORE_CON_SOCKS_V5_METHOD_NONE; | ||
196 | } | ||
197 | |||
198 | svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen); | ||
199 | return EINA_TRUE; | ||
200 | } | ||
201 | |||
202 | #define ECORE_CON_SOCKS_READ(EXACT) \ | ||
203 | if (num < EXACT) \ | ||
204 | { \ | ||
205 | if (!svr->ecs_recvbuf) svr->ecs_recvbuf = eina_binbuf_new(); \ | ||
206 | if (!svr->ecs_recvbuf) goto error; \ | ||
207 | eina_binbuf_append_length(svr->ecs_recvbuf, buf, num); \ | ||
208 | /* the slowest connection on earth */ \ | ||
209 | if (eina_binbuf_length_get(svr->ecs_recvbuf) != EXACT) return; \ | ||
210 | data = eina_binbuf_string_get(svr->ecs_recvbuf); \ | ||
211 | } \ | ||
212 | else if (num > EXACT) goto error; \ | ||
213 | else \ | ||
214 | data = buf | ||
215 | |||
216 | static void | ||
217 | _ecore_con_socks_read_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4 __UNUSED__, const unsigned char *buf, unsigned int num) | ||
218 | { | ||
219 | const unsigned char *data; | ||
220 | DBG("SOCKS: %d bytes", num); | ||
221 | ECORE_CON_SOCKS_READ(8); | ||
222 | |||
223 | /* http://ufasoft.com/doc/socks4_protocol.htm */ | ||
224 | if (data[0]) goto error; | ||
225 | switch (data[1]) | ||
226 | { | ||
227 | case 90: | ||
228 | /* success! */ | ||
229 | break; | ||
230 | case 91: | ||
231 | ecore_con_event_server_error(svr, "proxy request rejected or failed"); | ||
232 | goto error; | ||
233 | case 92: | ||
234 | ecore_con_event_server_error(svr, "proxying SOCKS server could not perform authentication"); | ||
235 | goto error; | ||
236 | case 93: | ||
237 | ecore_con_event_server_error(svr, "proxy request authentication rejected"); | ||
238 | goto error; | ||
239 | default: | ||
240 | ecore_con_event_server_error(svr, "garbage data from proxy"); | ||
241 | goto error; | ||
242 | } | ||
243 | if (svr->ecs->bind) | ||
244 | { | ||
245 | unsigned int nport; | ||
246 | char naddr[IF_NAMESIZE]; | ||
247 | |||
248 | memcpy(&nport, &data[2], 2); | ||
249 | svr->proxyport = ntohl(nport); | ||
250 | |||
251 | if (!inet_ntop(AF_INET, &data[4], naddr, sizeof(naddr))) goto error; | ||
252 | svr->proxyip = eina_stringshare_add(naddr); | ||
253 | ecore_con_event_proxy_bind(svr); | ||
254 | } | ||
255 | svr->ecs_state = ECORE_CON_PROXY_STATE_DONE; | ||
256 | INF("PROXY CONNECTED"); | ||
257 | if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); | ||
258 | svr->ecs_recvbuf = NULL; | ||
259 | svr->ecs_buf_offset = svr->ecs_addrlen = 0; | ||
260 | memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr)); | ||
261 | if (!svr->ssl_state) | ||
262 | ecore_con_event_server_add(svr); | ||
263 | if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf))) | ||
264 | ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); | ||
265 | return; | ||
266 | error: | ||
267 | _ecore_con_server_kill(svr); | ||
268 | } | ||
269 | |||
270 | static Eina_Bool | ||
271 | _ecore_con_socks_auth_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5) | ||
272 | { | ||
273 | size_t size; | ||
274 | unsigned char *data; | ||
275 | switch (v5->method) | ||
276 | { | ||
277 | case ECORE_CON_SOCKS_V5_METHOD_NONE: | ||
278 | svr->ecs_state = ECORE_CON_PROXY_STATE_REQUEST; | ||
279 | return EINA_TRUE; | ||
280 | case ECORE_CON_SOCKS_V5_METHOD_GSSAPI: | ||
281 | return EINA_TRUE; | ||
282 | case ECORE_CON_SOCKS_V5_METHOD_USERPASS: | ||
283 | if (!v5->username) return EINA_FALSE; | ||
284 | if (!v5->password) v5->plen = 1; | ||
285 | /* http://tools.ietf.org/html/rfc1929 */ | ||
286 | size = sizeof(char) * (3 + v5->ulen + v5->plen); | ||
287 | data = malloc(size); | ||
288 | if (!data) break; | ||
289 | data[0] = 1; | ||
290 | data[1] = v5->ulen; | ||
291 | memcpy(&data[2], v5->username, v5->ulen); | ||
292 | data[1 + v5->ulen] = v5->plen; | ||
293 | if (v5->password) | ||
294 | memcpy(&data[2 + v5->ulen], v5->password, v5->plen); | ||
295 | else | ||
296 | data[2 + v5->ulen] = 0; | ||
297 | svr->ecs_buf = eina_binbuf_manage_new_length(data, size); | ||
298 | return EINA_TRUE; | ||
299 | default: | ||
300 | break; | ||
301 | } | ||
302 | return EINA_FALSE; | ||
303 | } | ||
304 | |||
305 | static void | ||
306 | _ecore_con_socks_read_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5, const unsigned char *buf, unsigned int num) | ||
307 | { | ||
308 | const unsigned char *data; | ||
309 | |||
310 | DBG("SOCKS: %d bytes", num); | ||
311 | switch (svr->ecs_state) | ||
312 | { | ||
313 | |||
314 | case ECORE_CON_PROXY_STATE_READ: | ||
315 | ECORE_CON_SOCKS_READ(2); | ||
316 | /* http://en.wikipedia.org/wiki/SOCKS */ | ||
317 | if (data[0] != 5) goto error; | ||
318 | if (data[1] == 0xFF) | ||
319 | { | ||
320 | ecore_con_event_server_error(svr, "proxy authentication methods rejected"); | ||
321 | goto error; | ||
322 | } | ||
323 | v5->method = data[1]; | ||
324 | if (!_ecore_con_socks_auth_v5(svr, v5)) goto error; | ||
325 | if (svr->ecs_state == ECORE_CON_PROXY_STATE_REQUEST) | ||
326 | { | ||
327 | /* run again to skip auth reading */ | ||
328 | _ecore_con_socks_read_v5(svr, v5, NULL, 0); | ||
329 | return; | ||
330 | } | ||
331 | ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); | ||
332 | svr->ecs_state = ECORE_CON_PROXY_STATE_AUTH; | ||
333 | break; | ||
334 | case ECORE_CON_PROXY_STATE_AUTH: | ||
335 | ECORE_CON_SOCKS_READ(2); | ||
336 | switch (v5->method) | ||
337 | { | ||
338 | case ECORE_CON_SOCKS_V5_METHOD_NONE: | ||
339 | CRIT("HOW DID THIS HAPPEN?????????"); | ||
340 | goto error; | ||
341 | case ECORE_CON_SOCKS_V5_METHOD_GSSAPI: | ||
342 | /* TODO: this */ | ||
343 | break; | ||
344 | case ECORE_CON_SOCKS_V5_METHOD_USERPASS: | ||
345 | if (data[0] != 1) | ||
346 | { | ||
347 | ecore_con_event_server_error(svr, "protocol error"); | ||
348 | goto error; /* wrong version */ | ||
349 | } | ||
350 | if (data[1]) | ||
351 | { | ||
352 | ecore_con_event_server_error(svr, "proxy request authentication rejected"); | ||
353 | goto error; | ||
354 | } | ||
355 | default: | ||
356 | break; | ||
357 | } | ||
358 | case ECORE_CON_PROXY_STATE_REQUEST: | ||
359 | { | ||
360 | size_t addrlen, buflen; | ||
361 | unsigned char *sbuf; | ||
362 | addrlen = v5->lookup ? strlen(svr->name) + 1 : (unsigned int)svr->ecs_addrlen; | ||
363 | buflen = sizeof(char) * (6 + addrlen); | ||
364 | sbuf = malloc(buflen); | ||
365 | if (!sbuf) | ||
366 | { | ||
367 | ecore_con_event_server_error(svr, "Memory allocation failure!"); | ||
368 | goto error; | ||
369 | } | ||
370 | sbuf[0] = 5; | ||
371 | sbuf[1] = v5->bind ? 2 : 1; /* TODO: 0x03 for UDP port association */ | ||
372 | sbuf[2] = 0; | ||
373 | if (v5->lookup) /* domain name */ | ||
374 | { | ||
375 | sbuf[3] = 3; | ||
376 | sbuf[4] = addrlen - 1; | ||
377 | memcpy(sbuf + 5, svr->name, addrlen - 1); | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | sbuf[3] = (svr->ecs_addrlen == 4) ? 1 : 4; | ||
382 | memcpy(sbuf + 4, svr->ecs_addr, addrlen); | ||
383 | } | ||
384 | sbuf[addrlen + 4] = svr->port >> 8; | ||
385 | sbuf[addrlen + 5] = svr->port & 0xff; | ||
386 | |||
387 | svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen); | ||
388 | ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); | ||
389 | break; | ||
390 | } | ||
391 | case ECORE_CON_PROXY_STATE_CONFIRM: | ||
392 | { | ||
393 | /* this is ugly because we have to read an exact number of bytes, | ||
394 | * but we don't know what that number is until we've already read | ||
395 | * at least 5 bytes to determine the length of the unknown stream. | ||
396 | * yep. | ||
397 | */ | ||
398 | size_t to_read, len = svr->ecs_recvbuf ? eina_binbuf_length_get(svr->ecs_recvbuf) : 0; | ||
399 | if (num + len < 5) | ||
400 | { | ||
401 | /* guarantees we get called again */ | ||
402 | ECORE_CON_SOCKS_READ(5); | ||
403 | } | ||
404 | if (len >= 5) | ||
405 | { | ||
406 | data = eina_binbuf_string_get(svr->ecs_recvbuf); | ||
407 | data += 3; | ||
408 | } | ||
409 | else | ||
410 | data = buf + 3 - len; | ||
411 | switch (data[0]) | ||
412 | { | ||
413 | case 1: | ||
414 | to_read = 4; | ||
415 | break; | ||
416 | case 3: | ||
417 | to_read = data[1] + 1; | ||
418 | break; | ||
419 | case 4: | ||
420 | to_read = 16; | ||
421 | /* lazy debugging stub comment */ | ||
422 | break; | ||
423 | default: | ||
424 | ecore_con_event_server_error(svr, "protocol error"); | ||
425 | goto error; | ||
426 | } | ||
427 | /* at this point, we finally know exactly how much we need to read */ | ||
428 | ECORE_CON_SOCKS_READ(6 + to_read); | ||
429 | |||
430 | if (data[0] != 5) | ||
431 | { | ||
432 | ecore_con_event_server_error(svr, "protocol error"); | ||
433 | goto error; /* wrong version */ | ||
434 | } | ||
435 | switch (data[1]) | ||
436 | { | ||
437 | case 0: | ||
438 | break; | ||
439 | case 1: | ||
440 | ecore_con_event_server_error(svr, "general proxy failure"); | ||
441 | goto error; | ||
442 | case 2: | ||
443 | ecore_con_event_server_error(svr, "connection not allowed by ruleset"); | ||
444 | goto error; | ||
445 | case 3: | ||
446 | ecore_con_event_server_error(svr, "network unreachable"); | ||
447 | goto error; | ||
448 | case 4: | ||
449 | ecore_con_event_server_error(svr, "host unreachable"); | ||
450 | goto error; | ||
451 | case 5: | ||
452 | ecore_con_event_server_error(svr, "connection refused by destination host"); | ||
453 | goto error; | ||
454 | case 6: | ||
455 | ecore_con_event_server_error(svr, "TTL expired"); | ||
456 | goto error; | ||
457 | case 7: | ||
458 | ecore_con_event_server_error(svr, "command not supported / protocol error"); | ||
459 | goto error; | ||
460 | case 8: | ||
461 | ecore_con_event_server_error(svr, "address type not supported"); | ||
462 | default: | ||
463 | goto error; | ||
464 | } | ||
465 | if (data[2]) | ||
466 | { | ||
467 | ecore_con_event_server_error(svr, "protocol error"); | ||
468 | goto error; | ||
469 | } | ||
470 | memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr)); | ||
471 | if (!svr->ssl_state) | ||
472 | ecore_con_event_server_add(svr); | ||
473 | if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf))) | ||
474 | ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); | ||
475 | svr->ecs_buf_offset = svr->ecs_addrlen = 0; | ||
476 | svr->ecs_state = ECORE_CON_PROXY_STATE_DONE; | ||
477 | INF("PROXY CONNECTED"); | ||
478 | break; | ||
479 | } | ||
480 | default: | ||
481 | break; | ||
482 | } | ||
483 | if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); | ||
484 | svr->ecs_recvbuf = NULL; | ||
485 | |||
486 | return; | ||
487 | error: | ||
488 | _ecore_con_server_kill(svr); | ||
489 | } | ||
490 | |||
491 | ///////////////////////////////////////////////////////////////////////////////////// | ||
492 | void | ||
493 | ecore_con_socks_shutdown(void) | ||
494 | { | ||
495 | Ecore_Con_Socks *ecs; | ||
496 | EINA_LIST_FREE(ecore_con_socks_proxies, ecs) | ||
497 | _ecore_con_socks_free(ecs); | ||
498 | _ecore_con_proxy_once = NULL; | ||
499 | _ecore_con_proxy_global = NULL; | ||
500 | } | ||
501 | |||
502 | void | ||
503 | ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num) | ||
504 | { | ||
505 | ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return; | ||
506 | |||
507 | if (svr->ecs_state < ECORE_CON_PROXY_STATE_READ) return; | ||
508 | |||
509 | if (v4) _ecore_con_socks_read_v4(svr, v4, buf, (unsigned int)num); | ||
510 | else _ecore_con_socks_read_v5(svr, v5, buf, (unsigned int)num); | ||
511 | } | ||
512 | |||
513 | Eina_Bool | ||
514 | ecore_con_socks_svr_init(Ecore_Con_Server *svr) | ||
515 | { | ||
516 | ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return EINA_FALSE; | ||
517 | |||
518 | if (!svr->ip) return EINA_FALSE; | ||
519 | if (svr->ecs_buf) return EINA_FALSE; | ||
520 | if (svr->ecs_state != ECORE_CON_PROXY_STATE_INIT) return EINA_FALSE; | ||
521 | ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); | ||
522 | if (v4) return _ecore_con_socks_svr_init_v4(svr, v4); | ||
523 | return _ecore_con_socks_svr_init_v5(svr, v5); | ||
524 | } | ||
525 | |||
526 | void | ||
527 | ecore_con_socks_dns_cb(const char *canonname __UNUSED__, const char *ip, struct sockaddr *addr, int addrlen __UNUSED__, Ecore_Con_Server *svr) | ||
528 | { | ||
529 | svr->ip = eina_stringshare_add(ip); | ||
530 | svr->ecs_state++; | ||
531 | if (addr->sa_family == AF_INET) | ||
532 | { | ||
533 | memcpy(svr->ecs_addr, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4); | ||
534 | svr->ecs_addrlen = 4; | ||
535 | } | ||
536 | #ifdef HAVE_IPV6 | ||
537 | else | ||
538 | { | ||
539 | memcpy(svr->ecs_addr, &((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, 16); | ||
540 | svr->ecs_addrlen = 16; | ||
541 | } | ||
542 | #endif | ||
543 | ecore_con_socks_svr_init(svr); | ||
544 | } | ||
545 | |||
546 | void | ||
547 | ecore_con_socks_init(void) | ||
548 | { | ||
549 | const char *socks; | ||
550 | char *h, *p, *l, *u = NULL; | ||
551 | char buf[512]; | ||
552 | int port, lookup = 0; | ||
553 | Eina_Bool v5 = EINA_FALSE; | ||
554 | Ecore_Con_Socks *ecs; | ||
555 | unsigned char addr[sizeof(struct in_addr)]; | ||
556 | #ifdef HAVE_IPV6 | ||
557 | unsigned char addr6[sizeof(struct in6_addr)]; | ||
558 | #endif | ||
559 | |||
560 | /* ECORE_CON_SOCKS_V4=[user@]host:port-[1|0] */ | ||
561 | socks = getenv("ECORE_CON_SOCKS_V4"); | ||
562 | if (!socks) | ||
563 | { | ||
564 | /* ECORE_CON_SOCKS_V5=[user@]host-port:[1|0] */ | ||
565 | socks = getenv("ECORE_CON_SOCKS_V5"); | ||
566 | v5 = EINA_TRUE; | ||
567 | } | ||
568 | if ((!socks) || (!socks[0]) || (strlen(socks) > 512)) return; | ||
569 | strncpy(buf, socks, sizeof(buf)); | ||
570 | h = strchr(buf, '@'); | ||
571 | /* username */ | ||
572 | if (h && (h - buf > 0)) *h++ = 0, u = buf; | ||
573 | else h = buf; | ||
574 | |||
575 | /* host ip; I ain't resolvin shit here */ | ||
576 | p = strchr(h, '-'); | ||
577 | if (!p) return; | ||
578 | *p++ = 0; | ||
579 | if (!inet_pton(AF_INET, h, addr)) | ||
580 | #ifdef HAVE_IPV6 | ||
581 | { | ||
582 | if (!v5) return; | ||
583 | if (!inet_pton(AF_INET6, h, addr6)) | ||
584 | return; | ||
585 | } | ||
586 | #else | ||
587 | return; | ||
588 | #endif | ||
589 | |||
590 | errno = 0; | ||
591 | port = strtol(p, &l, 10); | ||
592 | if (errno || (port < 0) || (port > 65535)) return; | ||
593 | if (l && (l[0] == ':')) | ||
594 | lookup = (l[1] == '1'); | ||
595 | if (v5) | ||
596 | ecs = ecore_con_socks5_remote_add(h, port, u, NULL); | ||
597 | else | ||
598 | ecs = ecore_con_socks4_remote_add(h, port, u); | ||
599 | if (!ecs) return; | ||
600 | ecore_con_socks_lookup_set(ecs, lookup); | ||
601 | ecore_con_socks_apply_always(ecs); | ||
602 | INF("Added global proxy server %s%s%s:%d - DNS lookup %s", | ||
603 | u ?: "", u ? "@" : "", h, port, lookup ? "ENABLED" : "DISABLED"); | ||
604 | } | ||
605 | |||
606 | ///////////////////////////////////////////////////////////////////////////////////// | ||
607 | |||
608 | /** | ||
609 | * @defgroup Ecore_Con_Socks_Group Ecore Connection SOCKS functions | ||
610 | * @{ | ||
611 | */ | ||
612 | |||
613 | /** | ||
614 | * Add a SOCKS v4 proxy to the proxy list | ||
615 | * | ||
616 | * Use this to create (or return, if previously added) a SOCKS proxy | ||
617 | * object which can be used by any ecore_con servers. | ||
618 | * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) | ||
619 | * @param port The port to connect to on the proxy | ||
620 | * @param username The username to use for the proxy (OPTIONAL) | ||
621 | * @return An allocated proxy object, or NULL on failure | ||
622 | * @note This object NEVER needs to be explicitly freed. | ||
623 | * @since 1.2 | ||
624 | */ | ||
625 | EAPI Ecore_Con_Socks * | ||
626 | ecore_con_socks4_remote_add(const char *ip, int port, const char *username) | ||
627 | { | ||
628 | Ecore_Con_Socks *ecs; | ||
629 | size_t ulen = 0; | ||
630 | |||
631 | if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL; | ||
632 | |||
633 | if (username) | ||
634 | { | ||
635 | ulen = strlen(username); | ||
636 | /* max length for protocol */ | ||
637 | if ((!ulen) || (ulen > 255)) return NULL; | ||
638 | } | ||
639 | ecs = _ecore_con_socks_find(4, ip, port, username, ulen, NULL, 0); | ||
640 | if (ecs) return ecs; | ||
641 | |||
642 | ecs = calloc(1, sizeof(Ecore_Con_Socks_v4)); | ||
643 | if (!ecs) return NULL; | ||
644 | |||
645 | ecs->version = 4; | ||
646 | ecs->ip = eina_stringshare_add(ip); | ||
647 | ecs->port = port; | ||
648 | ecs->username = eina_stringshare_add(username); | ||
649 | ecs->ulen = ulen; | ||
650 | ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs); | ||
651 | return ecs; | ||
652 | } | ||
653 | |||
654 | /** | ||
655 | * Find a SOCKS v4 proxy in the proxy list | ||
656 | * | ||
657 | * Use this to determine if a SOCKS proxy was previously added by checking | ||
658 | * the proxy list against the parameters given. | ||
659 | * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) | ||
660 | * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip | ||
661 | * @param username The username used for the proxy (OPTIONAL) | ||
662 | * @return true only if a proxy exists matching the given params | ||
663 | * @note This function matches slightly more loosely than ecore_con_socks4_remote_add(), and | ||
664 | * ecore_con_socks4_remote_add() should be used to return the actual object. | ||
665 | * @since 1.2 | ||
666 | */ | ||
667 | EAPI Eina_Bool | ||
668 | ecore_con_socks4_remote_exists(const char *ip, int port, const char *username) | ||
669 | { | ||
670 | if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) | ||
671 | return EINA_FALSE; | ||
672 | return !!_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0); | ||
673 | } | ||
674 | |||
675 | /** | ||
676 | * Remove a SOCKS v4 proxy from the proxy list and delete it | ||
677 | * | ||
678 | * Use this to remove a SOCKS proxy from the proxy list by checking | ||
679 | * the list against the parameters given. The proxy will then be deleted. | ||
680 | * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) | ||
681 | * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip | ||
682 | * @param username The username used for the proxy (OPTIONAL) | ||
683 | * @note This function matches in the same way as ecore_con_socks4_remote_exists(). | ||
684 | * @warning Be aware that deleting a proxy which is being used WILL ruin your life. | ||
685 | * @since 1.2 | ||
686 | */ | ||
687 | EAPI void | ||
688 | ecore_con_socks4_remote_del(const char *ip, int port, const char *username) | ||
689 | { | ||
690 | Ecore_Con_Socks_v4 *v4; | ||
691 | |||
692 | if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) return; | ||
693 | if (!ecore_con_socks_proxies) return; | ||
694 | |||
695 | v4 = (Ecore_Con_Socks_v4*)_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0); | ||
696 | if (!v4) return; | ||
697 | ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v4); | ||
698 | _ecore_con_socks_free((Ecore_Con_Socks*)v4); | ||
699 | } | ||
700 | /** | ||
701 | * Add a SOCKS v5 proxy to the proxy list | ||
702 | * | ||
703 | * Use this to create (or return, if previously added) a SOCKS proxy | ||
704 | * object which can be used by any ecore_con servers. | ||
705 | * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) | ||
706 | * @param port The port to connect to on the proxy | ||
707 | * @param username The username to use for the proxy (OPTIONAL) | ||
708 | * @param password The password to use for the proxy (OPTIONAL) | ||
709 | * @return An allocated proxy object, or NULL on failure | ||
710 | * @note This object NEVER needs to be explicitly freed. | ||
711 | * @since 1.2 | ||
712 | */ | ||
713 | EAPI Ecore_Con_Socks * | ||
714 | ecore_con_socks5_remote_add(const char *ip, int port, const char *username, const char *password) | ||
715 | { | ||
716 | Ecore_Con_Socks_v5 *ecs5; | ||
717 | size_t ulen = 0, plen = 0; | ||
718 | |||
719 | if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL; | ||
720 | |||
721 | if (username) | ||
722 | { | ||
723 | ulen = strlen(username); | ||
724 | /* max length for protocol */ | ||
725 | if ((!ulen) || (ulen > 255)) return NULL; | ||
726 | } | ||
727 | if (password) | ||
728 | { | ||
729 | plen = strlen(password); | ||
730 | /* max length for protocol */ | ||
731 | if ((!plen) || (plen > 255)) return NULL; | ||
732 | } | ||
733 | ecs5 = (Ecore_Con_Socks_v5*)_ecore_con_socks_find(5, ip, port, username, ulen, password, plen); | ||
734 | if (ecs5) return (Ecore_Con_Socks*)ecs5; | ||
735 | |||
736 | ecs5 = calloc(1, sizeof(Ecore_Con_Socks_v5)); | ||
737 | if (!ecs5) return NULL; | ||
738 | |||
739 | ecs5->version = 5; | ||
740 | ecs5->ip = eina_stringshare_add(ip); | ||
741 | ecs5->port = port; | ||
742 | ecs5->username = eina_stringshare_add(username); | ||
743 | ecs5->ulen = ulen; | ||
744 | ecs5->password = eina_stringshare_add(password); | ||
745 | ecs5->plen = plen; | ||
746 | ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs5); | ||
747 | return (Ecore_Con_Socks*)ecs5; | ||
748 | } | ||
749 | |||
750 | /** | ||
751 | * Find a SOCKS v5 proxy in the proxy list | ||
752 | * | ||
753 | * Use this to determine if a SOCKS proxy was previously added by checking | ||
754 | * the proxy list against the parameters given. | ||
755 | * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) | ||
756 | * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip | ||
757 | * @param username The username used for the proxy (OPTIONAL) | ||
758 | * @param password The password used for the proxy (OPTIONAL) | ||
759 | * @return true only if a proxy exists matching the given params | ||
760 | * @note This function matches slightly more loosely than ecore_con_socks5_remote_add(), and | ||
761 | * ecore_con_socks5_remote_add() should be used to return the actual object. | ||
762 | * @since 1.2 | ||
763 | */ | ||
764 | EAPI Eina_Bool | ||
765 | ecore_con_socks5_remote_exists(const char *ip, int port, const char *username, const char *password) | ||
766 | { | ||
767 | if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0]))) | ||
768 | return EINA_FALSE; | ||
769 | return !!_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0); | ||
770 | } | ||
771 | |||
772 | /** | ||
773 | * Remove a SOCKS v5 proxy from the proxy list and delete it | ||
774 | * | ||
775 | * Use this to remove a SOCKS proxy from the proxy list by checking | ||
776 | * the list against the parameters given. The proxy will then be deleted. | ||
777 | * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) | ||
778 | * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip | ||
779 | * @param username The username used for the proxy (OPTIONAL) | ||
780 | * @param password The password used for the proxy (OPTIONAL) | ||
781 | * @note This function matches in the same way as ecore_con_socks4_remote_exists(). | ||
782 | * @warning Be aware that deleting a proxy which is being used WILL ruin your life. | ||
783 | * @since 1.2 | ||
784 | */ | ||
785 | EAPI void | ||
786 | ecore_con_socks5_remote_del(const char *ip, int port, const char *username, const char *password) | ||
787 | { | ||
788 | Ecore_Con_Socks_v5 *v5; | ||
789 | |||
790 | if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0]))) | ||
791 | return; | ||
792 | if (!ecore_con_socks_proxies) return; | ||
793 | |||
794 | v5 = (Ecore_Con_Socks_v5*)_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0); | ||
795 | if (!v5) return; | ||
796 | ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v5); | ||
797 | _ecore_con_socks_free((Ecore_Con_Socks*)v5); | ||
798 | } | ||
799 | |||
800 | /** | ||
801 | * Set DNS lookup mode on an existing SOCKS proxy | ||
802 | * | ||
803 | * According to RFC, SOCKS v4 does not require that a proxy perform | ||
804 | * its own DNS lookups for addresses. SOCKS v4a specifies the protocol | ||
805 | * for this. SOCKS v5 allows DNS lookups. | ||
806 | * If you want to enable remote DNS lookup and are sure that your | ||
807 | * proxy supports it, use this function. | ||
808 | * @param ecs The proxy object | ||
809 | * @param enable If true, the proxy will perform the dns lookup | ||
810 | * @note By default, this setting is DISABLED. | ||
811 | * @since 1.2 | ||
812 | */ | ||
813 | EAPI void | ||
814 | ecore_con_socks_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable) | ||
815 | { | ||
816 | ECORE_CON_SOCKS_CAST_ELSE(ecs) return; | ||
817 | ecs->lookup = !!enable; | ||
818 | } | ||
819 | |||
820 | /** | ||
821 | * Get DNS lookup mode on an existing SOCKS proxy | ||
822 | * | ||
823 | * According to RFC, SOCKS v4 does not require that a proxy perform | ||
824 | * its own DNS lookups for addresses. SOCKS v4a specifies the protocol | ||
825 | * for this. SOCKS v5 allows DNS lookups. | ||
826 | * This function returns whether lookups are enabled on a proxy object. | ||
827 | * @param ecs The proxy object | ||
828 | * @return If true, the proxy will perform the dns lookup | ||
829 | * @note By default, this setting is DISABLED. | ||
830 | * @since 1.2 | ||
831 | */ | ||
832 | EAPI Eina_Bool | ||
833 | ecore_con_socks_lookup_get(Ecore_Con_Socks *ecs) | ||
834 | { | ||
835 | ECORE_CON_SOCKS_CAST_ELSE(ecs) return EINA_FALSE; | ||
836 | return ecs->lookup; | ||
837 | } | ||
838 | |||
839 | /** | ||
840 | * Enable bind mode on a SOCKS proxy | ||
841 | * | ||
842 | * Use this function to enable binding a remote port for use with a remote server. | ||
843 | * For more information, see http://ufasoft.com/doc/socks4_protocol.htm | ||
844 | * @param ecs The proxy object | ||
845 | * @param is_bind If true, the connection established will be a port binding | ||
846 | * @warning Be aware that changing the operation mode of an active proxy may result in undefined behavior | ||
847 | * @since 1.2 | ||
848 | */ | ||
849 | EAPI void | ||
850 | ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind) | ||
851 | { | ||
852 | EINA_SAFETY_ON_NULL_RETURN(ecs); | ||
853 | ecs->bind = !!is_bind; | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * Return bind mode of a SOCKS proxy | ||
858 | * | ||
859 | * Use this function to return bind mode of a proxy (binding a remote port for use with a remote server). | ||
860 | * For more information, see http://ufasoft.com/doc/socks4_protocol.htm | ||
861 | * @param ecs The proxy object | ||
862 | * @return If true, the connection established will be a port binding | ||
863 | * @since 1.2 | ||
864 | */ | ||
865 | EAPI Eina_Bool | ||
866 | ecore_con_socks_bind_get(Ecore_Con_Socks *ecs) | ||
867 | { | ||
868 | EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, EINA_FALSE); | ||
869 | return ecs->bind; | ||
870 | } | ||
871 | |||
872 | /** | ||
873 | * Return SOCKS version of a SOCKS proxy | ||
874 | * | ||
875 | * Use this function to return the SOCKS protocol version of a proxy | ||
876 | * @param ecs The proxy object | ||
877 | * @return 0 on error, else 4/5 | ||
878 | * @since 1.2 | ||
879 | */ | ||
880 | EAPI unsigned int | ||
881 | ecore_con_socks_version_get(Ecore_Con_Socks *ecs) | ||
882 | { | ||
883 | EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, 0); | ||
884 | return ecs->version; | ||
885 | } | ||
886 | |||
887 | /** | ||
888 | * Remove a SOCKS v4 proxy from the proxy list and delete it | ||
889 | * | ||
890 | * Use this to remove a SOCKS proxy from the proxy list by directly deleting the object given. | ||
891 | * @param ecs The proxy object to delete | ||
892 | * @warning Be aware that deleting a proxy which is being used WILL ruin your life. | ||
893 | * @since 1.2 | ||
894 | */ | ||
895 | EAPI void | ||
896 | ecore_con_socks_remote_del(Ecore_Con_Socks *ecs) | ||
897 | { | ||
898 | EINA_SAFETY_ON_NULL_RETURN(ecs); | ||
899 | if (!ecore_con_socks_proxies) return; | ||
900 | |||
901 | ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, ecs); | ||
902 | _ecore_con_socks_free(ecs); | ||
903 | } | ||
904 | |||
905 | /** | ||
906 | * Set a proxy object to be used with the next server created with ecore_con_server_connect() | ||
907 | * | ||
908 | * This function sets a proxy for the next ecore_con connection. After the next server is created, | ||
909 | * the proxy will NEVER be applied again unless explicitly enabled. | ||
910 | * @param ecs The proxy object | ||
911 | * @see ecore_con_socks_apply_always() | ||
912 | * @since 1.2 | ||
913 | */ | ||
914 | EAPI void | ||
915 | ecore_con_socks_apply_once(Ecore_Con_Socks *ecs) | ||
916 | { | ||
917 | _ecore_con_proxy_once = ecs; | ||
918 | } | ||
919 | |||
920 | /** | ||
921 | * Set a proxy object to be used with all servers created with ecore_con_server_connect() | ||
922 | * | ||
923 | * This function sets a proxy for all ecore_con connections. It will always be used. | ||
924 | * @param ecs The proxy object | ||
925 | * @see ecore_con_socks_apply_once() | ||
926 | * @since 1.2 | ||
927 | * @note ecore-con supports setting this through environment variables like so: | ||
928 | * ECORE_CON_SOCKS_V4=[user@]server-port:lookup | ||
929 | * ECORE_CON_SOCKS_V5=[user@]server-port:lookup | ||
930 | * user is the OPTIONAL string that would be passed to the proxy as the username | ||
931 | * server is the IP_ADDRESS of the proxy server | ||
932 | * port is the port to connect to on the proxy server | ||
933 | * lookup is 1 if the proxy should perform all DNS lookups, otherwise 0 or omitted | ||
934 | */ | ||
935 | EAPI void | ||
936 | ecore_con_socks_apply_always(Ecore_Con_Socks *ecs) | ||
937 | { | ||
938 | _ecore_con_proxy_global = ecs; | ||
939 | } | ||
940 | /** @} */ | ||