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_NETINET_IN_H
22 # include <netinet/in.h>
23 #endif
24 
25 #ifdef HAVE_ARPA_INET_H
26 # include <arpa/inet.h>
27 #endif
28 
29 #ifdef HAVE_SYS_UN_H
30 #include <sys/un.h>
31 #endif
32 
33 #ifdef HAVE_NET_IF_H
34 # include <net/if.h>
35 #endif
36 
37 #ifdef _WIN32
38 # include <ws2tcpip.h>
39 #endif
40 
41 #include "Ecore.h"
42 #include "ecore_private.h"
43 #include "Ecore_Con.h"
44 #include "ecore_con_private.h"
45 
46 #define ECORE_CON_SOCKS_VERSION_CHECK(X)             do {    \
47        if (!(X) || ((X)->version < 4) || ((X)->version > 5)) \
48          return;                                             \
49   } while (0)
50 #define ECORE_CON_SOCKS_VERSION_CHECK_RETURN(X, ret) do {    \
51        if (!(X) || ((X)->version < 4) || ((X)->version > 5)) \
52          return (ret);                                       \
53   } while (0)
54 
55 static Eina_List *ecore_con_socks_proxies = NULL;
56 
57 static Ecore_Con_Socks *
_ecore_con_socks_find(unsigned char version,const char * ip,int port,const char * username,size_t ulen,const char * password,size_t plen)58 _ecore_con_socks_find(unsigned char version, const char *ip, int port, const char *username, size_t ulen, const char *password, size_t plen)
59 {
60    Eina_List *l;
61    Ecore_Con_Socks_v5 *ecs;
62 
63    if (!ecore_con_socks_proxies) return NULL;
64 
65    EINA_LIST_FOREACH(ecore_con_socks_proxies, l, ecs)
66      {
67         if (ecs->version != version) continue;
68         if (strcmp(ecs->ip, ip)) continue;
69         if ((port != -1) && (port != ecs->port)) continue;
70         if (ulen != ecs->ulen) continue;
71         if (username && strcmp(ecs->username, username)) continue;
72         if (version == 5)
73           {
74              if (plen != ecs->plen) continue;
75              if (password && strcmp(ecs->password, password)) continue;
76           }
77         return (Ecore_Con_Socks *)ecs;
78      }
79    return NULL;
80 }
81 
82 static void
_ecore_con_socks_free(Ecore_Con_Socks * ecs)83 _ecore_con_socks_free(Ecore_Con_Socks *ecs)
84 {
85    ECORE_CON_SOCKS_VERSION_CHECK(ecs);
86 
87    if (_ecore_con_proxy_once == ecs) _ecore_con_proxy_once = NULL;
88    if (_ecore_con_proxy_global == ecs) _ecore_con_proxy_global = NULL;
89    eina_stringshare_del(ecs->ip);
90    eina_stringshare_del(ecs->username);
91    free(ecs);
92 }
93 
94 void
ecore_con_socks_shutdown(void)95 ecore_con_socks_shutdown(void)
96 {
97    Ecore_Con_Socks *ecs;
98    EINA_LIST_FREE(ecore_con_socks_proxies, ecs)
99      _ecore_con_socks_free(ecs);
100    _ecore_con_proxy_once = NULL;
101    _ecore_con_proxy_global = NULL;
102 }
103 
104 void
ecore_con_socks_init(void)105 ecore_con_socks_init(void)
106 {
107    const char *socks = NULL;
108    char *h, *p, *l, *u = NULL;
109    char buf[512];
110    int port, lookup = 0;
111    Eina_Bool v5 = EINA_FALSE;
112    Ecore_Con_Socks *ecs;
113    unsigned char addr[sizeof(struct in_addr)];
114 #ifdef HAVE_IPV6
115    unsigned char addr6[sizeof(struct in6_addr)];
116 #endif
117 
118 #if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
119    if (getuid() == geteuid())
120 #endif
121      {
122         /* ECORE_CON_SOCKS_V4=[user@]host-port:[1|0] */
123         socks = getenv("ECORE_CON_SOCKS_V4");
124         if (!socks)
125           {
126              /* ECORE_CON_SOCKS_V5=[user@]host-port:[1|0] */
127              socks = getenv("ECORE_CON_SOCKS_V5");
128              v5 = EINA_TRUE;
129           }
130      }
131    if ((!socks) || (!socks[0]) || (strlen(socks) + 1 > 512)) return;
132    memcpy(buf, socks, strlen(socks) + 1);
133    h = strchr(buf, '@');
134    /* username */
135    if (h && (h - buf > 0)) *h++ = 0, u = buf;
136    else h = buf;
137 
138    /* host ip; I ain't resolvin shit here */
139    p = strchr(h, '-');
140    if (!p) return;
141    *p++ = 0;
142    if (!inet_pton(AF_INET, h, addr))
143 #ifdef HAVE_IPV6
144      {
145         if (!v5) return;
146         if (!inet_pton(AF_INET6, h, addr6))
147           return;
148      }
149 #else
150      return;
151 #endif
152 
153    errno = 0;
154    port = strtol(p, &l, 10);
155    if (errno || (port < 0) || (port > 65535)) return;
156    if (l && (l[0] == ':'))
157      lookup = (l[1] == '1');
158    if (v5)
159      ecs = ecore_con_socks5_remote_add(h, port, u, NULL);
160    else
161      ecs = ecore_con_socks4_remote_add(h, port, u);
162    if (!ecs) return;
163    ecore_con_socks_lookup_set(ecs, lookup);
164    ecore_con_socks_apply_always(ecs);
165    INF("Added global proxy server %s%s%s:%d - DNS lookup %s",
166        u ? : "", u ? "@" : "", h, port, lookup ? "ENABLED" : "DISABLED");
167 }
168 
169 /////////////////////////////////////////////////////////////////////////////////////
170 
171 /*
172  * General Socks API.
173  */
174 
175 EAPI Ecore_Con_Socks *
ecore_con_socks4_remote_add(const char * ip,int port,const char * username)176 ecore_con_socks4_remote_add(const char *ip, int port, const char *username)
177 {
178    Ecore_Con_Socks *ecs;
179    size_t ulen = 0;
180 
181    if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL;
182 
183    if (username)
184      {
185         ulen = strlen(username);
186         /* max length for protocol */
187         if ((!ulen) || (ulen > 255)) return NULL;
188      }
189    ecs = _ecore_con_socks_find(4, ip, port, username, ulen, NULL, 0);
190    if (ecs) return ecs;
191 
192    ecs = calloc(1, sizeof(Ecore_Con_Socks_v4));
193    if (!ecs) return NULL;
194 
195    ecs->version = 4;
196    ecs->ip = eina_stringshare_add(ip);
197    ecs->port = port;
198    ecs->username = eina_stringshare_add(username);
199    ecs->ulen = ulen;
200    ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs);
201    return ecs;
202 }
203 
204 EAPI Eina_Bool
ecore_con_socks4_remote_exists(const char * ip,int port,const char * username)205 ecore_con_socks4_remote_exists(const char *ip, int port, const char *username)
206 {
207    if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])))
208      return EINA_FALSE;
209    return !!_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0);
210 }
211 
212 EAPI void
ecore_con_socks4_remote_del(const char * ip,int port,const char * username)213 ecore_con_socks4_remote_del(const char *ip, int port, const char *username)
214 {
215    Ecore_Con_Socks_v4 *v4;
216 
217    if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) return;
218    if (!ecore_con_socks_proxies) return;
219 
220    v4 = (Ecore_Con_Socks_v4 *)_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0);
221    if (!v4) return;
222    ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v4);
223    _ecore_con_socks_free((Ecore_Con_Socks *)v4);
224 }
225 
226 EAPI Ecore_Con_Socks *
ecore_con_socks5_remote_add(const char * ip,int port,const char * username,const char * password)227 ecore_con_socks5_remote_add(const char *ip, int port, const char *username, const char *password)
228 {
229    Ecore_Con_Socks_v5 *ecs5;
230    size_t ulen = 0, plen = 0;
231 
232    if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL;
233 
234    if (username)
235      {
236         ulen = strlen(username);
237         /* max length for protocol */
238         if ((!ulen) || (ulen > 255)) return NULL;
239      }
240    if (password)
241      {
242         plen = strlen(password);
243         /* max length for protocol */
244         if ((!plen) || (plen > 255)) return NULL;
245      }
246    ecs5 = (Ecore_Con_Socks_v5 *)_ecore_con_socks_find(5, ip, port, username, ulen, password, plen);
247    if (ecs5) return (Ecore_Con_Socks *)ecs5;
248 
249    ecs5 = calloc(1, sizeof(Ecore_Con_Socks_v5));
250    if (!ecs5) return NULL;
251 
252    ecs5->version = 5;
253    ecs5->ip = eina_stringshare_add(ip);
254    ecs5->port = port;
255    ecs5->username = eina_stringshare_add(username);
256    ecs5->ulen = ulen;
257    ecs5->password = eina_stringshare_add(password);
258    ecs5->plen = plen;
259    ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs5);
260    return (Ecore_Con_Socks *)ecs5;
261 }
262 
263 EAPI Eina_Bool
ecore_con_socks5_remote_exists(const char * ip,int port,const char * username,const char * password)264 ecore_con_socks5_remote_exists(const char *ip, int port, const char *username, const char *password)
265 {
266    if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0])))
267      return EINA_FALSE;
268    return !!_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0);
269 }
270 
271 EAPI void
ecore_con_socks5_remote_del(const char * ip,int port,const char * username,const char * password)272 ecore_con_socks5_remote_del(const char *ip, int port, const char *username, const char *password)
273 {
274    Ecore_Con_Socks_v5 *v5;
275 
276    if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0])))
277      return;
278    if (!ecore_con_socks_proxies) return;
279 
280    v5 = (Ecore_Con_Socks_v5 *)_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0);
281    if (!v5) return;
282    ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v5);
283    _ecore_con_socks_free((Ecore_Con_Socks *)v5);
284 }
285 
286 EAPI void
ecore_con_socks_lookup_set(Ecore_Con_Socks * ecs,Eina_Bool enable)287 ecore_con_socks_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable)
288 {
289    ECORE_CON_SOCKS_VERSION_CHECK(ecs);
290    ecs->lookup = !!enable;
291 }
292 
293 EAPI Eina_Bool
ecore_con_socks_lookup_get(Ecore_Con_Socks * ecs)294 ecore_con_socks_lookup_get(Ecore_Con_Socks *ecs)
295 {
296    ECORE_CON_SOCKS_VERSION_CHECK_RETURN(ecs, EINA_FALSE);
297    return ecs->lookup;
298 }
299 
300 EAPI void
ecore_con_socks_bind_set(Ecore_Con_Socks * ecs,Eina_Bool is_bind)301 ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind)
302 {
303    EINA_SAFETY_ON_NULL_RETURN(ecs);
304    ECORE_CON_SOCKS_VERSION_CHECK(ecs);
305    ecs->bind = !!is_bind;
306 }
307 
308 EAPI Eina_Bool
ecore_con_socks_bind_get(Ecore_Con_Socks * ecs)309 ecore_con_socks_bind_get(Ecore_Con_Socks *ecs)
310 {
311    EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, EINA_FALSE);
312    ECORE_CON_SOCKS_VERSION_CHECK_RETURN(ecs, EINA_FALSE);
313    return ecs->bind;
314 }
315 
316 EAPI unsigned int
ecore_con_socks_version_get(Ecore_Con_Socks * ecs)317 ecore_con_socks_version_get(Ecore_Con_Socks *ecs)
318 {
319    EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, 0);
320    ECORE_CON_SOCKS_VERSION_CHECK_RETURN(ecs, 0);
321    return ecs->version;
322 }
323 
324 EAPI void
ecore_con_socks_remote_del(Ecore_Con_Socks * ecs)325 ecore_con_socks_remote_del(Ecore_Con_Socks *ecs)
326 {
327    EINA_SAFETY_ON_NULL_RETURN(ecs);
328    if (!ecore_con_socks_proxies) return;
329 
330    ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, ecs);
331    _ecore_con_socks_free(ecs);
332 }
333 
334 EAPI void
ecore_con_socks_apply_once(Ecore_Con_Socks * ecs)335 ecore_con_socks_apply_once(Ecore_Con_Socks *ecs)
336 {
337    _ecore_con_proxy_once = ecs;
338 }
339 
340 EAPI void
ecore_con_socks_apply_always(Ecore_Con_Socks * ecs)341 ecore_con_socks_apply_always(Ecore_Con_Socks *ecs)
342 {
343    _ecore_con_proxy_global = ecs;
344 }
345 
346