root / trunk / src / dot / proxy / socks.c

Revision 7618, 13.5 kB (checked in by BradNeuberg, 22 months ago)

Local and remote SVN repositories somehow became out of sync and corrupted -- re-adding these in

Line 
1/*
2Copyright (c) 2003-2006 by Juliusz Chroboczek
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE SOFTWARE.
21*/
22
23#include "polipo.h"
24
25#ifdef NO_SOCKS
26
27AtomPtr socksParentProxy = NULL;
28
29void
30preinitSocks()
31{
32    return;
33}
34
35void
36initSocks()
37{
38    return;
39}
40
41int
42do_socks_connect(char *name, int port,
43                 int (*handler)(int, SocksRequestPtr),
44                 void *data)
45{
46    SocksRequestRec request;
47    request.name = internAtomLowerN(name, strlen(name));
48    request.port = port;
49    request.handler = handler;
50    request.buf = NULL;
51    request.data = data;
52
53    handler(-ENOSYS, &request);
54    releaseAtom(request.name);
55    return 1;
56}
57
58#else
59
60AtomPtr socksParentProxy = NULL;
61AtomPtr socksProxyHost = NULL;
62int socksProxyPort = -1;
63AtomPtr socksProxyAddress = NULL;
64int socksProxyAddressIndex = -1;
65AtomPtr socksUserName = NULL;
66AtomPtr socksProxyType = NULL;
67AtomPtr aSocks4a, aSocks5;
68
69static int socksParentProxySetter(ConfigVariablePtr, void*);
70static int socksProxyTypeSetter(ConfigVariablePtr, void*);
71static int do_socks_connect_common(SocksRequestPtr);
72static int socksDnsHandler(int, GethostbynameRequestPtr);
73static int socksConnectHandler(int, FdEventHandlerPtr, ConnectRequestPtr);
74static int socksWriteHandler(int, FdEventHandlerPtr, StreamRequestPtr);
75static int socksReadHandler(int, FdEventHandlerPtr, StreamRequestPtr);
76static int socks5ReadHandler(int, FdEventHandlerPtr, StreamRequestPtr);
77static int socks5WriteHandler(int, FdEventHandlerPtr, StreamRequestPtr);
78static int socks5ReadHandler2(int, FdEventHandlerPtr, StreamRequestPtr);
79
80void
81preinitSocks()
82{
83    aSocks4a = internAtom("socks4a");
84    aSocks5 = internAtom("socks5");
85    socksProxyType = retainAtom(aSocks5);
86    socksUserName = internAtom("");
87    CONFIG_VARIABLE_SETTABLE(socksParentProxy, CONFIG_ATOM_LOWER,
88                             socksParentProxySetter,
89                             "SOCKS parent proxy (host:port)");
90    CONFIG_VARIABLE_SETTABLE(socksUserName, CONFIG_ATOM,
91                             configAtomSetter,
92                             "SOCKS4a user name");
93    CONFIG_VARIABLE_SETTABLE(socksProxyType, CONFIG_ATOM_LOWER,
94                             socksProxyTypeSetter,
95                             "One of socks4a or socks5");
96}
97
98static int
99socksParentProxySetter(ConfigVariablePtr var, void *value)
100{
101    configAtomSetter(var, value);
102    initSocks();
103    return 1;
104}
105
106static int
107socksProxyTypeSetter(ConfigVariablePtr var, void *value)
108{
109    if(*var->value.a != aSocks4a && *var->value.a != aSocks5) {
110        do_log(L_ERROR, "Unknown socksProxyType %s\n", (*var->value.a)->string);
111        return -1;
112    }
113
114    return configAtomSetter(var, value);
115}
116
117void
118initSocks()
119{
120    int port = -1;
121    AtomPtr host = NULL, port_atom;
122    int rc;
123
124    if(socksParentProxy) {
125        rc = atomSplit(socksParentProxy, ':', &host, &port_atom);
126        if(rc <= 0) {
127            do_log(L_ERROR, "Couldn't parse socksParentProxy");
128            exit(1);
129        }
130        port = atoi(port_atom->string);
131        releaseAtom(port_atom);
132    }
133
134    if(socksProxyHost)
135        releaseAtom(socksProxyHost);
136    socksProxyHost = host;
137    socksProxyPort = port;
138    if(socksProxyAddress)
139        releaseAtom(socksProxyAddress);
140    socksProxyAddress = NULL;
141    socksProxyAddressIndex = -1;
142
143    if(socksProxyType != aSocks4a && socksProxyType != aSocks5) {
144        do_log(L_ERROR, "Unknown socksProxyType %s\n", socksProxyType->string);
145        exit(1);
146    }
147}
148
149static void
150destroySocksRequest(SocksRequestPtr request)
151{
152    releaseAtom(request->name);
153    if(request->buf)
154        free(request->buf);
155    free(request);
156}
157
158int
159do_socks_connect(char *name, int port,
160                 int (*handler)(int, SocksRequestPtr),
161                 void *data)
162{
163    SocksRequestPtr request = malloc(sizeof(SocksRequestRec));
164    SocksRequestRec request_nomem;
165    if(request == NULL)
166        goto nomem;
167
168    request->name = internAtomLowerN(name, strlen(name));
169    if(request->name == NULL) {
170        free(request);
171        goto nomem;
172    }
173
174    request->port = port;
175    request->fd = -1;
176    request->handler = handler;
177    request->buf = NULL;
178    request->data = data;
179
180    if(socksProxyAddress == NULL) {
181        do_gethostbyname(socksProxyHost->string, 0,
182                         socksDnsHandler,
183                         request);
184        return 1;
185    }
186
187    return do_socks_connect_common(request);
188
189 nomem:
190    request_nomem.name = internAtomLowerN(name, strlen(name));
191    request_nomem.port = port;
192    request_nomem.handler = handler;
193    request_nomem.buf = NULL;
194    request_nomem.data = data;
195
196    handler(-ENOMEM, &request_nomem);
197    releaseAtom(request_nomem.name);
198    return 1;
199}
200
201static int
202do_socks_connect_common(SocksRequestPtr request)
203{
204    assert(socksProxyAddressIndex >= 0);
205
206    do_connect(retainAtom(socksProxyAddress),
207               socksProxyAddressIndex,
208               socksProxyPort,
209               socksConnectHandler, request);
210    return 1;
211}
212
213static int
214socksDnsHandler(int status, GethostbynameRequestPtr grequest)
215{
216    SocksRequestPtr request = grequest->data;
217    if(status <= 0) {
218        request->handler(status, request);
219        destroySocksRequest(request);
220        return 1;
221    }
222
223    if(grequest->addr->string[0] == DNS_CNAME) {
224        if(grequest->count > 10) {
225            do_log(L_ERROR, "DNS CNAME loop.\n");
226            request->handler(-EDNS_CNAME_LOOP, request);
227            destroySocksRequest(request);
228            return 1;
229        }
230        do_gethostbyname(grequest->addr->string + 1, grequest->count + 1,
231                         httpServerConnectionDnsHandler, request);
232        return 1;
233    }
234
235
236    socksProxyAddress = retainAtom(grequest->addr);
237    socksProxyAddressIndex = 0;
238
239    do_socks_connect_common(request);
240    return 1;
241}
242
243static int
244socksConnectHandler(int status,
245                    FdEventHandlerPtr event,
246                    ConnectRequestPtr crequest)
247{
248    SocksRequestPtr request = crequest->data;
249    int rc;
250
251    if(status < 0) {
252        request->handler(status, request);
253        destroySocksRequest(request);
254        return 1;
255    }
256
257    assert(request->fd < 0);
258    request->fd = crequest->fd;
259    socksProxyAddressIndex = crequest->index;
260
261    rc = setNodelay(request->fd, 1);
262    if(rc < 0)
263        do_log_error(L_WARN, errno, "Couldn't disable Nagle's algorithm");
264
265    if(socksProxyType == aSocks4a) {
266        request->buf = malloc(8 +
267                              socksUserName->length + 1 +
268                              request->name->length + 1);
269        if(request->buf == NULL) {
270            close(request->fd);
271            request->fd = -1;
272            request->handler(-ENOMEM, request);
273            destroySocksRequest(request);
274            return 1;
275        }
276
277        request->buf[0] = 4;        /* VN */
278        request->buf[1] = 1;        /* CD = REQUEST */
279        request->buf[2] = (request->port >> 8) & 0xFF;
280        request->buf[3] = request->port & 0xFF;
281        request->buf[4] = request->buf[5] = request->buf[6] = 0;
282        request->buf[7] = 3;
283
284        memcpy(request->buf + 8, socksUserName->string, socksUserName->length);
285        request->buf[8 + socksUserName->length] = '\0';
286
287        memcpy(request->buf + 8 + socksUserName->length + 1,
288               request->name->string, request->name->length);
289        request->buf[8 + socksUserName->length + 1 + request->name->length] =
290            '\0';
291
292        do_stream(IO_WRITE, request->fd, 0, request->buf,
293                  8 + socksUserName->length + 1 + request->name->length + 1,
294                  socksWriteHandler, request);
295    } else if(socksProxyType == aSocks5) {
296        request->buf = malloc(8); /* 8 needed for the subsequent read */
297        if(request->buf == NULL) {
298            close(request->fd);
299            request->fd = -1;
300            request->handler(-ENOMEM, request);
301            destroySocksRequest(request);
302            return 1;
303        }
304
305        request->buf[0] = 5;             /* ver */
306        request->buf[1] = 1;             /* nmethods */
307        request->buf[2] = 0;             /* no authentication required */
308        do_stream(IO_WRITE, request->fd, 0, request->buf, 3,
309                  socksWriteHandler, request);
310    } else {
311        request->handler(-EUNKNOWN, request);
312    }
313    return 1;
314}
315
316static int
317socksWriteHandler(int status,
318                  FdEventHandlerPtr event,
319                  StreamRequestPtr srequest)
320{
321    SocksRequestPtr request = srequest->data;
322
323    if(status < 0)
324        goto error;
325
326    if(!streamRequestDone(srequest)) {
327        if(status) {
328            status = -ESOCKS_PROTOCOL;
329            goto error;
330        }
331        return 0;
332    }
333
334    do_stream(IO_READ | IO_NOTNOW, request->fd, 0, request->buf, 8,
335              socksProxyType == aSocks5 ?
336              socks5ReadHandler : socksReadHandler,
337              request);
338    return 1;
339
340 error:
341    close(request->fd);
342    request->fd = -1;
343    request->handler(status, request);
344    destroySocksRequest(request);
345    return 1;
346}
347
348static int
349socksReadHandler(int status,
350                 FdEventHandlerPtr event,
351                 StreamRequestPtr srequest)
352{
353    SocksRequestPtr request = srequest->data;
354
355    if(status < 0)
356        goto error;
357
358    if(srequest->offset < 8) {
359        if(status) {
360            status = -ESOCKS_PROTOCOL;
361            goto error;
362        }
363        return 0;
364    }
365
366    if(request->buf[0] != 0 || request->buf[1] != 90) {
367        if(request->buf[1] >= 91 && request->buf[1] <= 93)
368            status = -(ESOCKS_PROTOCOL + request->buf[1] - 90);
369        else
370            status = -ESOCKS_PROTOCOL;
371        goto error;
372    }
373
374    request->handler(1, request);
375    destroySocksRequest(request);
376    return 1;
377
378 error:
379    close(request->fd);
380    request->fd = -1;
381    request->handler(status, request);
382    destroySocksRequest(request);
383    return 1;
384}
385
386static int
387socks5ReadHandler(int status,
388                  FdEventHandlerPtr event,
389                  StreamRequestPtr srequest)
390{
391    SocksRequestPtr request = srequest->data;
392
393    if(status < 0)
394        goto error;
395
396    if(srequest->offset < 2) {
397        if(status) {
398            status = -ESOCKS_PROTOCOL;
399            goto error;
400        }
401        return 0;
402    }
403
404    if(request->buf[0] != 5 || request->buf[1] != 0) {
405        status = -ESOCKS_PROTOCOL;
406        goto error;
407    }
408
409    free(request->buf);
410    request->buf = malloc(5 + request->name->length + 2);
411    if(request->buf == NULL) {
412        status = -ENOMEM;
413        goto error;
414    }
415
416    request->buf[0] = 5;        /* ver */
417    request->buf[1] = 1;        /* cmd */
418    request->buf[2] = 0;        /* rsv */
419    request->buf[3] = 3;        /* atyp */
420    request->buf[4] = request->name->length;
421    memcpy(request->buf + 5, request->name->string, request->name->length);
422    request->buf[5 + request->name->length] = (request->port >> 8) & 0xFF;
423    request->buf[5 + request->name->length + 1] = request->port & 0xFF;
424
425    do_stream(IO_WRITE, request->fd, 0,
426              request->buf, 5 + request->name->length + 2,
427              socks5WriteHandler, request);
428    return 1;
429
430 error:
431    close(request->fd);
432    request->fd = -1;
433    request->handler(status, request);
434    destroySocksRequest(request);
435    return 1;
436}
437
438static int
439socks5WriteHandler(int status,
440                   FdEventHandlerPtr event,
441                   StreamRequestPtr srequest)
442{
443    SocksRequestPtr request = srequest->data;
444   
445    if(status < 0)
446        goto error;
447
448    if(!streamRequestDone(srequest)) {
449        if(status) {
450            status = -ESOCKS_PROTOCOL;
451            goto error;
452        }
453        return 0;
454    }
455
456    do_stream(IO_READ | IO_NOTNOW, request->fd, 0, request->buf, 10,
457              socks5ReadHandler2, request);
458    return 1;
459
460 error:
461    request->handler(status, request);
462    destroySocksRequest(request);
463    return 1;
464}
465
466static int
467socks5ReadHandler2(int status,
468                   FdEventHandlerPtr event,
469                   StreamRequestPtr srequest)
470{
471    SocksRequestPtr request = srequest->data;
472
473    if(status < 0)
474        goto error;
475
476    if(srequest->offset < 4) {
477        if(status) {
478            status = -ESOCKS_PROTOCOL;
479            goto error;
480        }
481        return 0;
482    }
483
484    if(request->buf[0] != 5) {
485        status = -ESOCKS_PROTOCOL;
486        goto error;
487    }
488
489    if(request->buf[1] != 0) {
490        status = -(ESOCKS5_BASE + request->buf[1]);
491        goto error;
492    }
493
494    if(request->buf[3] != 1) {
495        status = -ESOCKS_PROTOCOL;
496        goto error;
497    }
498
499    if(srequest->offset < 10)
500        return 0;
501
502    request->handler(1, request);
503    destroySocksRequest(request);
504    return 1;
505
506 error:
507    close(request->fd);
508    request->fd = -1;
509    request->handler(status, request);
510    destroySocksRequest(request);
511    return 1;
512}
513
514#endif
Note: See TracBrowser for help on using the browser.