aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore_con/ecore_con_socks.c
diff options
context:
space:
mode:
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.c762
1 files changed, 603 insertions, 159 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
index aecaff0..686f73b 100644
--- a/libraries/ecore/src/lib/ecore_con/ecore_con_socks.c
+++ b/libraries/ecore/src/lib/ecore_con/ecore_con_socks.c
@@ -10,6 +10,10 @@
10#include <unistd.h> 10#include <unistd.h>
11#include <fcntl.h> 11#include <fcntl.h>
12 12
13#ifdef HAVE_SYS_SOCKET_H
14# include <sys/socket.h>
15#endif
16
13#ifdef HAVE_NETINET_TCP_H 17#ifdef HAVE_NETINET_TCP_H
14# include <netinet/tcp.h> 18# include <netinet/tcp.h>
15#endif 19#endif
@@ -36,10 +40,6 @@
36# include <arpa/inet.h> 40# include <arpa/inet.h>
37#endif 41#endif
38 42
39#ifdef HAVE_SYS_SOCKET_H
40# include <sys/socket.h>
41#endif
42
43#ifdef HAVE_SYS_UN_H 43#ifdef HAVE_SYS_UN_H
44# include <sys/un.h> 44# include <sys/un.h>
45#endif 45#endif
@@ -57,6 +57,27 @@
57#include "Ecore_Con.h" 57#include "Ecore_Con.h"
58#include "ecore_con_private.h" 58#include "ecore_con_private.h"
59 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
72static 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
60#define _ecore_con_server_kill(svr) do { \ 81#define _ecore_con_server_kill(svr) do { \
61 DBG("KILL %p", (svr)); \ 82 DBG("KILL %p", (svr)); \
62 _ecore_con_server_kill((svr)); \ 83 _ecore_con_server_kill((svr)); \
@@ -65,10 +86,10 @@
65Eina_List *ecore_con_socks_proxies = NULL; 86Eina_List *ecore_con_socks_proxies = NULL;
66 87
67static Ecore_Con_Socks * 88static Ecore_Con_Socks *
68_ecore_con_socks_find(unsigned char version, const char *ip, int port, const char *username) 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)
69{ 90{
70 Eina_List *l; 91 Eina_List *l;
71 Ecore_Con_Socks *ecs; 92 Ecore_Con_Socks_v5 *ecs;
72 93
73 if (!ecore_con_socks_proxies) return NULL; 94 if (!ecore_con_socks_proxies) return NULL;
74 95
@@ -77,8 +98,14 @@ _ecore_con_socks_find(unsigned char version, const char *ip, int port, const cha
77 if (ecs->version != version) continue; 98 if (ecs->version != version) continue;
78 if (strcmp(ecs->ip, ip)) continue; 99 if (strcmp(ecs->ip, ip)) continue;
79 if ((port != -1) && (port != ecs->port)) continue; 100 if ((port != -1) && (port != ecs->port)) continue;
101 if (ulen != ecs->ulen) continue;
80 if (username && strcmp(ecs->username, username)) continue; 102 if (username && strcmp(ecs->username, username)) continue;
81 return ecs; 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;
82 } 109 }
83 return NULL; 110 return NULL;
84} 111}
@@ -94,146 +121,424 @@ _ecore_con_socks_free(Ecore_Con_Socks *ecs)
94 eina_stringshare_del(ecs->username); 121 eina_stringshare_del(ecs->username);
95 free(ecs); 122 free(ecs);
96} 123}
97///////////////////////////////////////////////////////////////////////////////////// 124
98void 125static Eina_Bool
99ecore_con_socks_shutdown(void) 126_ecore_con_socks_svr_init_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4)
100{ 127{
101 Ecore_Con_Socks *ecs; 128 size_t addrlen, buflen, ulen = 1;
102 EINA_LIST_FREE(ecore_con_socks_proxies, ecs) 129 unsigned char *sbuf;
103 _ecore_con_socks_free(ecs); 130
104 _ecore_con_proxy_once = NULL; 131 addrlen = v4->lookup ? strlen(svr->name) + 1 : 0;
105 _ecore_con_proxy_global = NULL; 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;
106} 162}
107 163
108void 164static Eina_Bool
109ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num) 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
216static void
217_ecore_con_socks_read_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4 __UNUSED__, const unsigned char *buf, unsigned int num)
110{ 218{
111 const unsigned char *data; 219 const unsigned char *data;
112 ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return; 220 DBG("SOCKS: %d bytes", num);
221 ECORE_CON_SOCKS_READ(8);
113 222
114 if (svr->ecs_state != ECORE_CON_SOCKS_STATE_READ) return; 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];
115 247
116 if (v4) 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;
266error:
267 _ecore_con_server_kill(svr);
268}
269
270static 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
305static 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)
117 { 312 {
118 DBG("SOCKS: %d bytes", num);
119 if (num < 8)
120 {
121 if (!svr->ecs_recvbuf) svr->ecs_recvbuf = eina_binbuf_new();
122 if (!svr->ecs_recvbuf) goto error;
123 eina_binbuf_append_length(svr->ecs_recvbuf, buf, num);
124 /* the slowest connection on earth */
125 if (eina_binbuf_length_get(svr->ecs_recvbuf) != 8) return;
126 data = eina_binbuf_string_get(svr->ecs_recvbuf);
127 }
128 else if (num > 8) goto error;
129 else
130 data = buf;
131 313
132 /* http://ufasoft.com/doc/socks4_protocol.htm */ 314 case ECORE_CON_PROXY_STATE_READ:
133 if (data[0]) goto error; 315 ECORE_CON_SOCKS_READ(2);
134 switch (data[1]) 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:
135 { 359 {
136 case 90: 360 size_t addrlen, buflen;
137 /* success! */ 361 unsigned char *sbuf;
138 break; 362 addrlen = v5->lookup ? strlen(svr->name) + 1 : (unsigned int)svr->ecs_addrlen;
139 case 91: 363 buflen = sizeof(char) * (6 + addrlen);
140 ecore_con_event_server_error(svr, "proxy request rejected or failed"); 364 sbuf = malloc(buflen);
141 goto error; 365 if (!sbuf)
142 case 92: 366 {
143 ecore_con_event_server_error(svr, "proxying SOCKS server could not perform authentication"); 367 ecore_con_event_server_error(svr, "Memory allocation failure!");
144 goto error; 368 goto error;
145 case 93: 369 }
146 ecore_con_event_server_error(svr, "proxy request authentication rejected"); 370 sbuf[0] = 5;
147 goto error; 371 sbuf[1] = v5->bind ? 2 : 1; /* TODO: 0x03 for UDP port association */
148 default: 372 sbuf[2] = 0;
149 ecore_con_event_server_error(svr, "garbage data from proxy"); 373 if (v5->lookup) /* domain name */
150 goto error; 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;
151 } 390 }
152 if (svr->ecs->bind) 391 case ECORE_CON_PROXY_STATE_CONFIRM:
153 { 392 {
154 unsigned int nport; 393 /* this is ugly because we have to read an exact number of bytes,
155 char naddr[IF_NAMESIZE]; 394 * but we don't know what that number is until we've already read
156 395 * at least 5 bytes to determine the length of the unknown stream.
157 memcpy(&nport, &data[2], 2); 396 * yep.
158 svr->proxyport = ntohl(nport); 397 */
159 398 size_t to_read, len = svr->ecs_recvbuf ? eina_binbuf_length_get(svr->ecs_recvbuf) : 0;
160 if (!inet_ntop(AF_INET, &data[4], naddr, sizeof(naddr))) goto error; 399 if (num + len < 5)
161 svr->proxyip = eina_stringshare_add(naddr); 400 {
162 ecore_con_event_proxy_bind(svr); 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;
163 } 479 }
164 svr->ecs_state = ECORE_CON_SOCKS_STATE_DONE; 480 default:
165 INF("PROXY CONNECTED"); 481 break;
166 if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
167 svr->ecs_recvbuf = NULL;
168 svr->ecs_buf_offset = svr->ecs_addrlen = 0;
169 memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr));
170 if (!svr->ssl_state)
171 ecore_con_event_server_add(svr);
172 if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf)))
173 ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
174 } 482 }
483 if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
484 svr->ecs_recvbuf = NULL;
485
175 return; 486 return;
176error: 487error:
177 _ecore_con_server_kill(svr); 488 _ecore_con_server_kill(svr);
178} 489}
179 490
491/////////////////////////////////////////////////////////////////////////////////////
492void
493ecore_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
502void
503ecore_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
180Eina_Bool 513Eina_Bool
181ecore_con_socks_svr_init(Ecore_Con_Server *svr) 514ecore_con_socks_svr_init(Ecore_Con_Server *svr)
182{ 515{
183 unsigned char *sbuf;
184 ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return EINA_FALSE; 516 ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return EINA_FALSE;
185 517
186 if (!svr->ip) return EINA_FALSE; 518 if (!svr->ip) return EINA_FALSE;
187 if (svr->ecs_buf) return EINA_FALSE; 519 if (svr->ecs_buf) return EINA_FALSE;
188 if (svr->ecs_state != ECORE_CON_SOCKS_STATE_INIT) return EINA_FALSE; 520 if (svr->ecs_state != ECORE_CON_PROXY_STATE_INIT) return EINA_FALSE;
189 ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); 521 ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
190 if (v4) 522 if (v4) return _ecore_con_socks_svr_init_v4(svr, v4);
191 { 523 return _ecore_con_socks_svr_init_v5(svr, v5);
192 size_t addrlen, buflen, ulen = 1;
193 addrlen = svr->ecs->lookup ? strlen(svr->name) + 1: 0;
194 if (svr->ecs->username) ulen += strlen(svr->ecs->username);
195 buflen = sizeof(char) * (8 + ulen + addrlen);
196 sbuf = malloc(buflen);
197 if (!sbuf)
198 {
199 ecore_con_event_server_error(svr, "Memory allocation failure!");
200 _ecore_con_server_kill(svr);
201 return EINA_FALSE;
202 }
203 /* http://en.wikipedia.org/wiki/SOCKS */
204 sbuf[0] = 4;
205 sbuf[1] = v4->bind ? 2 : 1;
206 sbuf[2] = svr->port >> 8;
207 sbuf[3] = svr->port & 0xff;
208 if (addrlen)
209 {
210 sbuf[4] = sbuf[5] = sbuf[6] = 0;
211 sbuf[7] = 1;
212 }
213 else
214 memcpy(sbuf + 4, svr->ecs_addr, 4);
215 if (svr->ecs->username)
216 memcpy(sbuf + 8, svr->ecs->username, ulen);
217 else
218 sbuf[8] = 0;
219 if (addrlen) memcpy(sbuf + 8 + ulen, svr->name, addrlen);
220
221 svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen);
222 }
223 return EINA_TRUE;
224} 524}
225 525
226void 526void
227ecore_con_socks_dns_cb(const char *canonname __UNUSED__, const char *ip, struct sockaddr *addr, int addrlen, Ecore_Con_Server *svr) 527ecore_con_socks_dns_cb(const char *canonname __UNUSED__, const char *ip, struct sockaddr *addr, int addrlen __UNUSED__, Ecore_Con_Server *svr)
228{ 528{
229 svr->ip = eina_stringshare_add(ip); 529 svr->ip = eina_stringshare_add(ip);
230 svr->ecs_addrlen = addrlen;
231 svr->ecs_state++; 530 svr->ecs_state++;
232 if (addr->sa_family == AF_INET) 531 if (addr->sa_family == AF_INET)
233 memcpy(svr->ecs_addr, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4); 532 {
533 memcpy(svr->ecs_addr, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4);
534 svr->ecs_addrlen = 4;
535 }
234#ifdef HAVE_IPV6 536#ifdef HAVE_IPV6
235 else 537 else
236 memcpy(svr->ecs_addr, &((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, addrlen); 538 {
539 memcpy(svr->ecs_addr, &((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, 16);
540 svr->ecs_addrlen = 16;
541 }
237#endif 542#endif
238 ecore_con_socks_svr_init(svr); 543 ecore_con_socks_svr_init(svr);
239} 544}
@@ -242,36 +547,57 @@ void
242ecore_con_socks_init(void) 547ecore_con_socks_init(void)
243{ 548{
244 const char *socks; 549 const char *socks;
245 char *u, *h, *p, *l; 550 char *h, *p, *l, *u = NULL;
246 char buf[64]; 551 char buf[512];
247 int port, lookup = 0; 552 int port, lookup = 0;
553 Eina_Bool v5 = EINA_FALSE;
248 Ecore_Con_Socks *ecs; 554 Ecore_Con_Socks *ecs;
249 unsigned char addr[sizeof(struct in_addr)]; 555 unsigned char addr[sizeof(struct in_addr)];
556#ifdef HAVE_IPV6
557 unsigned char addr6[sizeof(struct in6_addr)];
558#endif
250 559
251 /* ECORE_CON_SOCKS_V4=user@host:port:[1|0] */ 560 /* ECORE_CON_SOCKS_V4=[user@]host:port-[1|0] */
252 socks = getenv("ECORE_CON_SOCKS_V4"); 561 socks = getenv("ECORE_CON_SOCKS_V4");
253 if ((!socks) || (!socks[0]) || (strlen(socks) > 64)) return; 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;
254 strncpy(buf, socks, sizeof(buf)); 569 strncpy(buf, socks, sizeof(buf));
255 h = strchr(buf, '@'); 570 h = strchr(buf, '@');
256 u = NULL;
257 /* username */ 571 /* username */
258 if (h && (h - buf > 0)) *h++ = 0, u = buf; 572 if (h && (h - buf > 0)) *h++ = 0, u = buf;
259 else h = buf; 573 else h = buf;
260 574
261 /* host ip; I ain't resolvin shit here */ 575 /* host ip; I ain't resolvin shit here */
262 p = strchr(h, ':'); 576 p = strchr(h, '-');
263 if (!p) return; 577 if (!p) return;
264 *p++ = 0; 578 *p++ = 0;
265 if (!inet_pton(AF_INET, h, addr)) return; 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
266 589
267 errno = 0; 590 errno = 0;
268 port = strtol(p, &l, 10); 591 port = strtol(p, &l, 10);
269 if (errno || (port < 0) || (port > 65535)) return; 592 if (errno || (port < 0) || (port > 65535)) return;
270 if (l && (l[0] == ':')) 593 if (l && (l[0] == ':'))
271 lookup = (l[1] == '1'); 594 lookup = (l[1] == '1');
272 ecs = ecore_con_socks4_remote_add(h, port, u); 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);
273 if (!ecs) return; 599 if (!ecs) return;
274 ecore_con_socks4_lookup_set(ecs, lookup); 600 ecore_con_socks_lookup_set(ecs, lookup);
275 ecore_con_socks_apply_always(ecs); 601 ecore_con_socks_apply_always(ecs);
276 INF("Added global proxy server %s%s%s:%d - DNS lookup %s", 602 INF("Added global proxy server %s%s%s:%d - DNS lookup %s",
277 u ?: "", u ? "@" : "", h, port, lookup ? "ENABLED" : "DISABLED"); 603 u ?: "", u ? "@" : "", h, port, lookup ? "ENABLED" : "DISABLED");
@@ -300,10 +626,17 @@ EAPI Ecore_Con_Socks *
300ecore_con_socks4_remote_add(const char *ip, int port, const char *username) 626ecore_con_socks4_remote_add(const char *ip, int port, const char *username)
301{ 627{
302 Ecore_Con_Socks *ecs; 628 Ecore_Con_Socks *ecs;
629 size_t ulen = 0;
303 630
304 if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL; 631 if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL;
305 632
306 ecs = _ecore_con_socks_find(4, ip, port, username); 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);
307 if (ecs) return ecs; 640 if (ecs) return ecs;
308 641
309 ecs = calloc(1, sizeof(Ecore_Con_Socks_v4)); 642 ecs = calloc(1, sizeof(Ecore_Con_Socks_v4));
@@ -313,92 +646,194 @@ ecore_con_socks4_remote_add(const char *ip, int port, const char *username)
313 ecs->ip = eina_stringshare_add(ip); 646 ecs->ip = eina_stringshare_add(ip);
314 ecs->port = port; 647 ecs->port = port;
315 ecs->username = eina_stringshare_add(username); 648 ecs->username = eina_stringshare_add(username);
649 ecs->ulen = ulen;
316 ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs); 650 ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs);
317 return ecs; 651 return ecs;
318} 652}
319 653
320/** 654/**
321 * Set DNS lookup mode on an existing SOCKS v4 proxy 655 * Find a SOCKS v4 proxy in the proxy list
322 * 656 *
323 * According to RFC, SOCKS v4 does not require that a proxy perform 657 * Use this to determine if a SOCKS proxy was previously added by checking
324 * its own DNS lookups for addresses. SOCKS v4a specifies the protocol 658 * the proxy list against the parameters given.
325 * for this. If you want to enable remote DNS lookup and are sure that your 659 * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
326 * proxy supports it, use this function. 660 * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
327 * @param ecs The proxy object 661 * @param username The username used for the proxy (OPTIONAL)
328 * @param enable If true, the proxy will perform the dns lookup 662 * @return true only if a proxy exists matching the given params
329 * @note By default, this setting is DISABLED. 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.
330 * @since 1.2 665 * @since 1.2
331 */ 666 */
332EAPI void 667EAPI Eina_Bool
333ecore_con_socks4_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable) 668ecore_con_socks4_remote_exists(const char *ip, int port, const char *username)
334{ 669{
335 ECORE_CON_SOCKS_CAST_ELSE(ecs) return; 670 if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])))
336 if (v4) v4->lookup = !!enable; 671 return EINA_FALSE;
672 return !!_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0);
337} 673}
338 674
339/** 675/**
340 * Get DNS lookup mode on an existing SOCKS v4 proxy 676 * Remove a SOCKS v4 proxy from the proxy list and delete it
341 * 677 *
342 * According to RFC, SOCKS v4 does not require that a proxy perform 678 * Use this to remove a SOCKS proxy from the proxy list by checking
343 * its own DNS lookups for addresses. SOCKS v4a specifies the protocol 679 * the list against the parameters given. The proxy will then be deleted.
344 * for this. This function returns whether lookups are enabled on a proxy object. 680 * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
345 * @param ecs The proxy object 681 * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
346 * @return If true, the proxy will perform the dns lookup 682 * @param username The username used for the proxy (OPTIONAL)
347 * @note By default, this setting is DISABLED. 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.
348 * @since 1.2 685 * @since 1.2
349 */ 686 */
350EAPI Eina_Bool 687EAPI void
351ecore_con_socks4_lookup_get(Ecore_Con_Socks *ecs) 688ecore_con_socks4_remote_del(const char *ip, int port, const char *username)
352{ 689{
353 ECORE_CON_SOCKS_CAST_ELSE(ecs) return EINA_FALSE; 690 Ecore_Con_Socks_v4 *v4;
354 return v4 ? v4->lookup : EINA_FALSE; 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 */
713EAPI Ecore_Con_Socks *
714ecore_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;
355} 748}
356 749
357/** 750/**
358 * Find a SOCKS v4 proxy in the proxy list 751 * Find a SOCKS v5 proxy in the proxy list
359 * 752 *
360 * Use this to determine if a SOCKS proxy was previously added by checking 753 * Use this to determine if a SOCKS proxy was previously added by checking
361 * the proxy list against the parameters given. 754 * the proxy list against the parameters given.
362 * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) 755 * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
363 * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip 756 * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
364 * @param username The username used for the proxy (OPTIONAL) 757 * @param username The username used for the proxy (OPTIONAL)
758 * @param password The password used for the proxy (OPTIONAL)
365 * @return true only if a proxy exists matching the given params 759 * @return true only if a proxy exists matching the given params
366 * @note This function matches slightly more loosely than ecore_con_socks4_remote_add(), and 760 * @note This function matches slightly more loosely than ecore_con_socks5_remote_add(), and
367 * ecore_con_socks4_remote_add() should be used to return the actual object. 761 * ecore_con_socks5_remote_add() should be used to return the actual object.
368 * @since 1.2 762 * @since 1.2
369 */ 763 */
370EAPI Eina_Bool 764EAPI Eina_Bool
371ecore_con_socks4_remote_exists(const char *ip, int port, const char *username) 765ecore_con_socks5_remote_exists(const char *ip, int port, const char *username, const char *password)
372{ 766{
373 if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) 767 if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0])))
374 return EINA_FALSE; 768 return EINA_FALSE;
375 return !!_ecore_con_socks_find(4, ip, port, username); 769 return !!_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0);
376} 770}
377 771
378/** 772/**
379 * Remove a SOCKS v4 proxy from the proxy list and delete it 773 * Remove a SOCKS v5 proxy from the proxy list and delete it
380 * 774 *
381 * Use this to remove a SOCKS proxy from the proxy list by checking 775 * Use this to remove a SOCKS proxy from the proxy list by checking
382 * the list against the parameters given. The proxy will then be deleted. 776 * the list against the parameters given. The proxy will then be deleted.
383 * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) 777 * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
384 * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip 778 * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
385 * @param username The username used for the proxy (OPTIONAL) 779 * @param username The username used for the proxy (OPTIONAL)
780 * @param password The password used for the proxy (OPTIONAL)
386 * @note This function matches in the same way as ecore_con_socks4_remote_exists(). 781 * @note This function matches in the same way as ecore_con_socks4_remote_exists().
387 * @warning Be aware that deleting a proxy which is being used WILL ruin your life. 782 * @warning Be aware that deleting a proxy which is being used WILL ruin your life.
388 * @since 1.2 783 * @since 1.2
389 */ 784 */
390EAPI void 785EAPI void
391ecore_con_socks4_remote_del(const char *ip, int port, const char *username) 786ecore_con_socks5_remote_del(const char *ip, int port, const char *username, const char *password)
392{ 787{
393 Ecore_Con_Socks_v4 *v4; 788 Ecore_Con_Socks_v5 *v5;
394 789
395 if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) return; 790 if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0])))
791 return;
396 if (!ecore_con_socks_proxies) return; 792 if (!ecore_con_socks_proxies) return;
397 793
398 v4 = (Ecore_Con_Socks_v4*)_ecore_con_socks_find(4, ip, port, username); 794 v5 = (Ecore_Con_Socks_v5*)_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0);
399 if (!v4) return; 795 if (!v5) return;
400 ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v4); 796 ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v5);
401 _ecore_con_socks_free((Ecore_Con_Socks*)v4); 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 */
813EAPI void
814ecore_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 */
832EAPI Eina_Bool
833ecore_con_socks_lookup_get(Ecore_Con_Socks *ecs)
834{
835 ECORE_CON_SOCKS_CAST_ELSE(ecs) return EINA_FALSE;
836 return ecs->lookup;
402} 837}
403 838
404/** 839/**
@@ -434,6 +869,14 @@ ecore_con_socks_bind_get(Ecore_Con_Socks *ecs)
434 return ecs->bind; 869 return ecs->bind;
435} 870}
436 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 */
437EAPI unsigned int 880EAPI unsigned int
438ecore_con_socks_version_get(Ecore_Con_Socks *ecs) 881ecore_con_socks_version_get(Ecore_Con_Socks *ecs)
439{ 882{
@@ -482,7 +925,8 @@ ecore_con_socks_apply_once(Ecore_Con_Socks *ecs)
482 * @see ecore_con_socks_apply_once() 925 * @see ecore_con_socks_apply_once()
483 * @since 1.2 926 * @since 1.2
484 * @note ecore-con supports setting this through environment variables like so: 927 * @note ecore-con supports setting this through environment variables like so:
485 * ECORE_CON_SOCKS_V4=[user@]server:port:lookup 928 * ECORE_CON_SOCKS_V4=[user@]server-port:lookup
929 * ECORE_CON_SOCKS_V5=[user@]server-port:lookup
486 * user is the OPTIONAL string that would be passed to the proxy as the username 930 * user is the OPTIONAL string that would be passed to the proxy as the username
487 * server is the IP_ADDRESS of the proxy server 931 * server is the IP_ADDRESS of the proxy server
488 * port is the port to connect to on the proxy server 932 * port is the port to connect to on the proxy server