2 Copyright (c) 2003-2006 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 AtomPtr socksParentProxy
= NULL
;
42 do_socks_connect(char *name
, int port
,
43 int (*handler
)(int, SocksRequestPtr
),
46 SocksRequestRec request
;
47 request
.name
= internAtomLowerN(name
, strlen(name
));
49 request
.handler
= handler
;
53 handler(-ENOSYS
, &request
);
54 releaseAtom(request
.name
);
60 AtomPtr socksParentProxy
= NULL
;
61 AtomPtr socksProxyHost
= NULL
;
62 int socksProxyPort
= -1;
63 AtomPtr socksProxyAddress
= NULL
;
64 int socksProxyAddressIndex
= -1;
65 AtomPtr socksUserName
= NULL
;
66 AtomPtr socksProxyType
= NULL
;
67 AtomPtr aSocks4a
, aSocks5
;
69 static int socksParentProxySetter(ConfigVariablePtr
, void*);
70 static int socksProxyTypeSetter(ConfigVariablePtr
, void*);
71 static int do_socks_connect_common(SocksRequestPtr
);
72 static int socksDnsHandler(int, GethostbynameRequestPtr
);
73 static int socksConnectHandler(int, FdEventHandlerPtr
, ConnectRequestPtr
);
74 static int socksWriteHandler(int, FdEventHandlerPtr
, StreamRequestPtr
);
75 static int socksReadHandler(int, FdEventHandlerPtr
, StreamRequestPtr
);
76 static int socks5ReadHandler(int, FdEventHandlerPtr
, StreamRequestPtr
);
77 static int socks5WriteHandler(int, FdEventHandlerPtr
, StreamRequestPtr
);
78 static int socks5ReadHandler2(int, FdEventHandlerPtr
, StreamRequestPtr
);
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
,
93 CONFIG_VARIABLE_SETTABLE(socksProxyType
, CONFIG_ATOM_LOWER
,
95 "One of socks4a or socks5");
99 socksParentProxySetter(ConfigVariablePtr var
, void *value
)
101 configAtomSetter(var
, value
);
107 socksProxyTypeSetter(ConfigVariablePtr var
, void *value
)
109 if(*var
->value
.a
!= aSocks4a
&& *var
->value
.a
!= aSocks5
) {
110 do_log(L_ERROR
, "Unknown socksProxyType %s\n", (*var
->value
.a
)->string
);
114 return configAtomSetter(var
, value
);
121 AtomPtr host
= NULL
, port_atom
;
124 if(socksParentProxy
!= NULL
&& socksParentProxy
->length
== 0) {
125 releaseAtom(socksParentProxy
);
126 socksParentProxy
= NULL
;
129 if(socksParentProxy
) {
130 rc
= atomSplit(socksParentProxy
, ':', &host
, &port_atom
);
132 do_log(L_ERROR
, "Couldn't parse socksParentProxy");
135 port
= atoi(port_atom
->string
);
136 releaseAtom(port_atom
);
140 releaseAtom(socksProxyHost
);
141 socksProxyHost
= host
;
142 socksProxyPort
= port
;
143 if(socksProxyAddress
)
144 releaseAtom(socksProxyAddress
);
145 socksProxyAddress
= NULL
;
146 socksProxyAddressIndex
= -1;
148 if(socksProxyType
!= aSocks4a
&& socksProxyType
!= aSocks5
) {
149 do_log(L_ERROR
, "Unknown socksProxyType %s\n", socksProxyType
->string
);
155 destroySocksRequest(SocksRequestPtr request
)
157 releaseAtom(request
->name
);
164 do_socks_connect(char *name
, int port
,
165 int (*handler
)(int, SocksRequestPtr
),
168 SocksRequestPtr request
= malloc(sizeof(SocksRequestRec
));
169 SocksRequestRec request_nomem
;
173 request
->name
= internAtomLowerN(name
, strlen(name
));
174 if(request
->name
== NULL
) {
179 request
->port
= port
;
181 request
->handler
= handler
;
183 request
->data
= data
;
185 if(socksProxyAddress
== NULL
) {
186 do_gethostbyname(socksProxyHost
->string
, 0,
192 return do_socks_connect_common(request
);
195 request_nomem
.name
= internAtomLowerN(name
, strlen(name
));
196 request_nomem
.port
= port
;
197 request_nomem
.handler
= handler
;
198 request_nomem
.buf
= NULL
;
199 request_nomem
.data
= data
;
201 handler(-ENOMEM
, &request_nomem
);
202 releaseAtom(request_nomem
.name
);
207 do_socks_connect_common(SocksRequestPtr request
)
209 assert(socksProxyAddressIndex
>= 0);
211 do_connect(retainAtom(socksProxyAddress
),
212 socksProxyAddressIndex
,
214 socksConnectHandler
, request
);
219 socksDnsHandler(int status
, GethostbynameRequestPtr grequest
)
221 SocksRequestPtr request
= grequest
->data
;
223 request
->handler(status
, request
);
224 destroySocksRequest(request
);
228 if(grequest
->addr
->string
[0] == DNS_CNAME
) {
229 if(grequest
->count
> 10) {
230 do_log(L_ERROR
, "DNS CNAME loop.\n");
231 request
->handler(-EDNS_CNAME_LOOP
, request
);
232 destroySocksRequest(request
);
235 do_gethostbyname(grequest
->addr
->string
+ 1, grequest
->count
+ 1,
236 httpServerConnectionDnsHandler
, request
);
241 socksProxyAddress
= retainAtom(grequest
->addr
);
242 socksProxyAddressIndex
= 0;
244 do_socks_connect_common(request
);
249 socksConnectHandler(int status
,
250 FdEventHandlerPtr event
,
251 ConnectRequestPtr crequest
)
253 SocksRequestPtr request
= crequest
->data
;
257 request
->handler(status
, request
);
258 destroySocksRequest(request
);
262 assert(request
->fd
< 0);
263 request
->fd
= crequest
->fd
;
264 socksProxyAddressIndex
= crequest
->index
;
266 rc
= setNodelay(request
->fd
, 1);
268 do_log_error(L_WARN
, errno
, "Couldn't disable Nagle's algorithm");
270 if(socksProxyType
== aSocks4a
) {
271 request
->buf
= malloc(8 +
272 socksUserName
->length
+ 1 +
273 request
->name
->length
+ 1);
274 if(request
->buf
== NULL
) {
277 request
->handler(-ENOMEM
, request
);
278 destroySocksRequest(request
);
282 request
->buf
[0] = 4; /* VN */
283 request
->buf
[1] = 1; /* CD = REQUEST */
284 request
->buf
[2] = (request
->port
>> 8) & 0xFF;
285 request
->buf
[3] = request
->port
& 0xFF;
286 request
->buf
[4] = request
->buf
[5] = request
->buf
[6] = 0;
289 memcpy(request
->buf
+ 8, socksUserName
->string
, socksUserName
->length
);
290 request
->buf
[8 + socksUserName
->length
] = '\0';
292 memcpy(request
->buf
+ 8 + socksUserName
->length
+ 1,
293 request
->name
->string
, request
->name
->length
);
294 request
->buf
[8 + socksUserName
->length
+ 1 + request
->name
->length
] =
297 do_stream(IO_WRITE
, request
->fd
, 0, request
->buf
,
298 8 + socksUserName
->length
+ 1 + request
->name
->length
+ 1,
299 socksWriteHandler
, request
);
300 } else if(socksProxyType
== aSocks5
) {
301 request
->buf
= malloc(8); /* 8 needed for the subsequent read */
302 if(request
->buf
== NULL
) {
305 request
->handler(-ENOMEM
, request
);
306 destroySocksRequest(request
);
310 request
->buf
[0] = 5; /* ver */
311 request
->buf
[1] = 1; /* nmethods */
312 request
->buf
[2] = 0; /* no authentication required */
313 do_stream(IO_WRITE
, request
->fd
, 0, request
->buf
, 3,
314 socksWriteHandler
, request
);
316 request
->handler(-EUNKNOWN
, request
);
322 socksWriteHandler(int status
,
323 FdEventHandlerPtr event
,
324 StreamRequestPtr srequest
)
326 SocksRequestPtr request
= srequest
->data
;
331 if(!streamRequestDone(srequest
)) {
333 status
= -ESOCKS_PROTOCOL
;
339 do_stream(IO_READ
| IO_NOTNOW
, request
->fd
, 0, request
->buf
, 8,
340 socksProxyType
== aSocks5
?
341 socks5ReadHandler
: socksReadHandler
,
348 request
->handler(status
, request
);
349 destroySocksRequest(request
);
354 socksReadHandler(int status
,
355 FdEventHandlerPtr event
,
356 StreamRequestPtr srequest
)
358 SocksRequestPtr request
= srequest
->data
;
363 if(srequest
->offset
< 8) {
365 status
= -ESOCKS_PROTOCOL
;
371 if(request
->buf
[0] != 0 || request
->buf
[1] != 90) {
372 if(request
->buf
[1] >= 91 && request
->buf
[1] <= 93)
373 status
= -(ESOCKS_PROTOCOL
+ request
->buf
[1] - 90);
375 status
= -ESOCKS_PROTOCOL
;
379 request
->handler(1, request
);
380 destroySocksRequest(request
);
386 request
->handler(status
, request
);
387 destroySocksRequest(request
);
392 socks5ReadHandler(int status
,
393 FdEventHandlerPtr event
,
394 StreamRequestPtr srequest
)
396 SocksRequestPtr request
= srequest
->data
;
401 if(srequest
->offset
< 2) {
403 status
= -ESOCKS_PROTOCOL
;
409 if(request
->buf
[0] != 5 || request
->buf
[1] != 0) {
410 status
= -ESOCKS_PROTOCOL
;
415 request
->buf
= malloc(5 + request
->name
->length
+ 2);
416 if(request
->buf
== NULL
) {
421 request
->buf
[0] = 5; /* ver */
422 request
->buf
[1] = 1; /* cmd */
423 request
->buf
[2] = 0; /* rsv */
424 request
->buf
[3] = 3; /* atyp */
425 request
->buf
[4] = request
->name
->length
;
426 memcpy(request
->buf
+ 5, request
->name
->string
, request
->name
->length
);
427 request
->buf
[5 + request
->name
->length
] = (request
->port
>> 8) & 0xFF;
428 request
->buf
[5 + request
->name
->length
+ 1] = request
->port
& 0xFF;
430 do_stream(IO_WRITE
, request
->fd
, 0,
431 request
->buf
, 5 + request
->name
->length
+ 2,
432 socks5WriteHandler
, request
);
438 request
->handler(status
, request
);
439 destroySocksRequest(request
);
444 socks5WriteHandler(int status
,
445 FdEventHandlerPtr event
,
446 StreamRequestPtr srequest
)
448 SocksRequestPtr request
= srequest
->data
;
453 if(!streamRequestDone(srequest
)) {
455 status
= -ESOCKS_PROTOCOL
;
461 do_stream(IO_READ
| IO_NOTNOW
, request
->fd
, 0, request
->buf
, 10,
462 socks5ReadHandler2
, request
);
466 request
->handler(status
, request
);
467 destroySocksRequest(request
);
472 socks5ReadHandler2(int status
,
473 FdEventHandlerPtr event
,
474 StreamRequestPtr srequest
)
476 SocksRequestPtr request
= srequest
->data
;
481 if(srequest
->offset
< 4) {
483 status
= -ESOCKS_PROTOCOL
;
489 if(request
->buf
[0] != 5) {
490 status
= -ESOCKS_PROTOCOL
;
494 if(request
->buf
[1] != 0) {
495 status
= -(ESOCKS5_BASE
+ request
->buf
[1]);
499 if(request
->buf
[3] != 1) {
500 status
= -ESOCKS_PROTOCOL
;
504 if(srequest
->offset
< 10)
507 request
->handler(1, request
);
508 destroySocksRequest(request
);
514 request
->handler(status
, request
);
515 destroySocksRequest(request
);