1 /*
2 3APA3A simpliest proxy server
3 (c) 2002-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
4
5 please read License Agreement
6
7 */
8
9 #include "proxy.h"
10
11 #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
12
13 unsigned char * commands[] = {(unsigned char *)"UNKNOWN", (unsigned char *)"CONNECT", (unsigned char *)"BIND", (unsigned char *)"UDPMAP"};
14
15 #define BUFSIZE 1024
16 #define LARGEBUFSIZE 67000
17
sockschild(struct clientparam * param)18 void * sockschild(struct clientparam* param) {
19 int res;
20 unsigned i=0;
21 SOCKET s;
22 unsigned size;
23 SASIZETYPE sasize;
24 unsigned short port = 0;
25 unsigned char * buf=NULL;
26 unsigned char c;
27 unsigned char command=0;
28 struct pollfd fds[3];
29 int ver=0;
30 int havepass = 0;
31 #ifndef NOIPV6
32 struct sockaddr_in6 sin = {AF_INET6};
33 #else
34 struct sockaddr_in sin = {AF_INET};
35 #endif
36 int len;
37
38
39 param->service = S_SOCKS;
40
41 if(!(buf = myalloc(BUFSIZE))) {RETURN(21);}
42 memset(buf, 0, BUFSIZE);
43 if ((ver = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5 && ver != 4) {
44 RETURN(401);
45 } /* version */
46 param->service = ver;
47 if(ver == 5){
48 if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} /* nmethods */
49 for (; i; i--) {
50 if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
51 if (res == 2 && param->srv->needuser) {
52 havepass = res;
53 }
54 }
55 buf[0] = 5;
56 buf[1] = (param->srv->needuser > 1 && !havepass)? 255 : havepass;
57 if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(401);}
58 if (param->srv->needuser > 1 && !havepass) RETURN(4);
59 if (havepass) {
60 if (((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0))) != 1) {
61 RETURN(412);
62 }
63 if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);}
64 if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);};
65 buf[i] = 0;
66 if(!param->username)param->username = (unsigned char *)mystrdup((char *)buf);
67 if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(445);}
68 if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);};
69 buf[i] = 0;
70 if(!param->password)param->password = (unsigned char *)mystrdup((char *)buf);
71 buf[0] = 1;
72 buf[1] = 0;
73 if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(481);}
74 }
75 if ((c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5) {
76 RETURN(421);
77 } /* version */
78 }
79 if( (command = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) < 1 || command > 3){command = 0; RETURN(407);} /* command */
80 if(ver == 5){
81 if (sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0) == EOF) {RETURN(447);} /* reserved */
82 c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0); /* atype */
83 }
84 else {
85 if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
86 buf[0] = (unsigned char) res;
87 if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
88 buf[1] = (unsigned char) res;
89 port = *(unsigned short*)buf;
90 c = 1;
91 }
92
93 size = 4;
94 *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET;
95 switch(c) {
96 #ifndef NOIPV6
97 case 4:
98 if(param->srv->family == 4) RETURN(997);
99 size = 16;
100 *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET6;
101 #endif
102 case 1:
103 for (i = 0; i<size; i++){
104 if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
105 buf[i] = (unsigned char)res;
106 }
107 #ifndef NOIPV6
108 if (c == 1 && param->srv->family==6){
109 char prefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255};
110 *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET6;
111 memcpy(SAADDR(¶m->sinsr), prefix, 12);
112 memcpy(12 + (char *)SAADDR(¶m->sinsr), buf, 4);
113 memcpy(SAADDR(¶m->req), prefix, 12);
114 memcpy(12 + (char *)SAADDR(¶m->req), buf, 4);
115 }
116 else {
117 #endif
118 memcpy(SAADDR(¶m->sinsr), buf, size);
119 memcpy(SAADDR(¶m->req), buf, size);
120 #ifndef NOIPV6
121 }
122 #endif
123 if(command == 1 && SAISNULL(¶m->req)) {
124 RETURN(431);
125 }
126 myinet_ntop(*SAFAMILY(¶m->sinsr), SAADDR(¶m->sinsr), (char *)buf, 64);
127 break;
128 case 3:
129 if ((size = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);} /* nmethods */
130 for (i=0; i<size; i++){ /* size < 256 */
131 if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);}
132 buf[i] = (unsigned char)res;
133 }
134 buf[i] = 0;
135 if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100);
136 param->sinsr = param->req;
137 break;
138 default:
139 RETURN(997);
140 }
141 if(param->hostname)myfree(param->hostname);
142 param->hostname = (unsigned char *)mystrdup((char *)buf);
143 if (ver == 5) {
144 if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
145 buf[0] = (unsigned char) res;
146 if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
147 buf[1] = (unsigned char) res;
148 port = *(unsigned short*)buf;
149
150 }
151 else {
152 sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]);
153 buf[127] = 0;
154 if(param->srv->needuser && *buf && !param->username)param->username = (unsigned char *)mystrdup((char *)buf);
155 if(!memcmp(SAADDR(¶m->req), "\0\0\0", 3)){
156 param->service = S_SOCKS45;
157 sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]);
158 buf[127] = 0;
159 if(param->hostname)myfree(param->hostname);
160 param->hostname = (unsigned char *)mystrdup((char *)buf);
161 if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100);
162 param->sinsr = param->req;
163 }
164 }
165
166 *SAPORT(¶m->sinsr) = *SAPORT(¶m->req) = port;
167 if(command == 1 && !*SAPORT(¶m->sinsr)) {RETURN(461);}
168 switch(command) {
169 case 1:
170 param->operation = CONNECT;
171 break;
172 case 2:
173 case 3:
174
175 #ifndef NOIPV6
176 param->sinsl = *SAFAMILY(¶m->req)==AF_INET6? param->srv->extsa6 : (SAISNULL(¶m->srv->extNat)?param->srv->extsa:param->srv->extNat);
177 #else
178 param->sinsl = SAISNULL(¶m->srv->extNat)?param->srv->extsa:param->srv->extNat;
179 #endif
180 if ((param->remsock=so._socket(SASOCK(¶m->req), command == 2? SOCK_STREAM:SOCK_DGRAM, command == 2?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);}
181 param->operation = command == 2?BIND:UDPASSOC;
182 #ifdef REUSE
183 if (command == 2){
184 int opt;
185
186 #ifdef SO_REUSEADDR
187 opt = 1;
188 so._setsockopt(param->remsock, SOL_SOCKET, SO_REUSEADDR, (unsigned char *)&opt, sizeof(int));
189 #endif
190 #ifdef SO_REUSEPORT
191 opt = 1;
192 so._setsockopt(param->remsock, SOL_SOCKET, SO_REUSEPORT, (unsigned char *)&opt, sizeof(int));
193 #endif
194 }
195 #endif
196 break;
197
198 default:
199 RETURN(997);
200 }
201
202 if((res = (*param->srv->authfunc)(param))) {
203 RETURN(res);
204 }
205
206 if(command > 1) {
207 if(so._bind(param->remsock,(struct sockaddr *)¶m->sinsl,SASIZE(¶m->sinsl))) {
208 *SAPORT(¶m->sinsl) = 0;
209 if(so._bind(param->remsock,(struct sockaddr *)¶m->sinsl,SASIZE(¶m->sinsl)))RETURN (12);
210 #if SOCKSTRACE > 0
211 fprintf(stderr, "%hu bound to communicate with server\n", *SAPORT(¶m->sins));
212 fflush(stderr);
213 #endif
214 }
215 sasize = SASIZE(¶m->sinsl);
216 so._getsockname(param->remsock, (struct sockaddr *)¶m->sinsl, &sasize);
217 if(command == 3) {
218 param->ctrlsock = param->clisock;
219 param->clisock = so._socket(SASOCK(¶m->sincr), SOCK_DGRAM, IPPROTO_UDP);
220 if(param->clisock == INVALID_SOCKET) {RETURN(11);}
221 sin = param->sincl;
222 *SAPORT(&sin) = 0;
223 if(so._bind(param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);}
224 #if SOCKSTRACE > 0
225 fprintf(stderr, "%hu binded to communicate with client\n",
226 ntohs(*SAPORT(&sin))
227 );
228 fflush(stderr);
229 #endif
230 }
231 }
232 param->res = 0;
233
234 CLEANRET:
235
236 if(param->clisock != INVALID_SOCKET){
237 int repcode;
238
239 sasize = sizeof(sin);
240 if(command != 3 && param->remsock != INVALID_SOCKET) so._getsockname(param->remsock, (struct sockaddr *)&sin, &sasize);
241 else so._getsockname(param->clisock, (struct sockaddr *)&sin, &sasize);
242 #if SOCKSTRACE > 0
243 fprintf(stderr, "Sending confirmation to client with code %d for %s with %s:%hu\n",
244 param->res,
245 commands[command],
246 inet_ntoa(sin.sin_addr),
247 ntohs(sin.sin_port)
248 );
249 fflush(stderr);
250 #endif
251 if(!param->res) repcode = 0;
252 else if(param->res <= 10) repcode = 2;
253 else if (param->res < 20) repcode = 5;
254 else if (param->res < 30) repcode = 1;
255 else if (param->res < 100) repcode = 4;
256 else repcode = param->res%10;
257
258 if(ver == 5){
259 buf[0] = 5;
260 buf[1] = repcode;
261 buf[2] = 0;
262 buf[3] = (*SAFAMILY(&sin) == AF_INET)?1:4;
263 memcpy(buf+4, SAADDR(&sin), SAADDRLEN(&sin));
264 memcpy(buf+4+SAADDRLEN(&sin), SAPORT(&sin), 2);
265 socksend((command == 3)?param->ctrlsock:param->clisock, buf, 6+SAADDRLEN(&sin), conf.timeouts[STRING_S]);
266 }
267 else{
268 buf[0] = 0;
269 buf[1] = 90 + !!(repcode);
270 memcpy(buf+2, SAPORT(&sin), 2);
271 memcpy(buf+4, SAADDR(&sin), 4);
272 socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]);
273 }
274
275 if (param->res == 0) {
276 switch(command) {
277 case 1:
278 if(param->redirectfunc){
279 if(buf)myfree(buf);
280 return (*param->redirectfunc)(param);
281 }
282 param->res = mapsocket(param, conf.timeouts[CONNECTION_L]);
283 break;
284 case 2:
285 so._listen (param->remsock, 1);
286
287 fds[0].fd = param->remsock;
288 fds[1].fd = param->clisock;
289 fds[0].events = fds[1].events = POLLIN;
290 res = so._poll(fds, 2, conf.timeouts[CONNECTION_L] * 1000);
291 if (res < 1 || fds[1].revents) {
292 res = 460;
293 break;
294 }
295 sasize = sizeof(param->sinsr);
296 s = so._accept(param->remsock, (struct sockaddr *)¶m->sinsr, &sasize);
297 so._closesocket(param->remsock);
298 param->remsock = s;
299 if(s == INVALID_SOCKET) {
300 param->res = 462;
301 break;
302 }
303 if(SAISNULL(¶m->req) &&
304 memcmp(SAADDR(¶m->req),SAADDR(¶m->sinsr),SAADDRLEN(¶m->req))) {
305 param->res = 470;
306 break;
307 }
308 #if SOCKSTRACE > 0
309 fprintf(stderr, "Sending incoming connection to client with code %d for %s with %hu\n",
310 param->res,
311 commands[command],
312 *SAPORT(param->sins);
313 );
314 fflush(stderr);
315 #endif
316 if(ver == 5){
317 buf[3] = (*SAFAMILY(¶m->sinsr) == AF_INET)?1:4;
318 memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr));
319 memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2);
320 socksend(param->clisock, buf, 6+SAADDRLEN(¶m->sinsr), conf.timeouts[STRING_S]);
321 }
322 else {
323 memcpy (buf+2, SAPORT(¶m->sinsr), 2);
324 memcpy (buf+4, SAADDR(¶m->sinsr), 4);
325 socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]);
326 }
327
328 param->res = mapsocket(param, conf.timeouts[CONNECTION_S]);
329 break;
330 case 3:
331 param->sinsr = param->req;
332 myfree(buf);
333 if(!(buf = myalloc(LARGEBUFSIZE))) {RETURN(21);}
334 sin = param->sincr;
335
336 for(;;){
337 fds[0].fd = param->remsock;
338 fds[1].fd = param->clisock;
339 fds[2].fd = param->ctrlsock;
340 fds[2].events = fds[1].events = fds[0].events = POLLIN;
341
342 res = so._poll(fds, 3, conf.timeouts[CONNECTION_L]*1000);
343 if(res <= 0) {
344 param->res = 463;
345 break;
346 }
347 if (fds[2].revents) {
348 param->res = 0;
349 break;
350 }
351 if (fds[1].revents) {
352 sasize = sizeof(sin);
353 if((len = so._recvfrom(param->clisock, (char *)buf, 65535, 0, (struct sockaddr *)&sin, &sasize)) <= 10) {
354 param->res = 464;
355 break;
356 }
357 if(SAADDRLEN(&sin) != SAADDRLEN(¶m->sincr) || memcmp(SAADDR(&sin), SAADDR(¶m->sincr), SAADDRLEN(&sin))){
358 param->res = 465;
359 break;
360 }
361 if(buf[0] || buf[1] || buf[2]) {
362 param->res = 466;
363 break;
364 }
365 size = 4;
366 switch(buf[3]) {
367 case 4:
368 size = 16;
369 case 1:
370 i = 4+size;
371 memcpy(SAADDR(¶m->sinsr), buf+4, size);
372 *SAFAMILY(¶m->sinsr) = (size == 4)?AF_INET:AF_INET6;
373 break;
374 case 3:
375 size = buf[4];
376 for (i=4; size; i++, size--){
377 buf[i] = buf[i+1];
378 }
379 buf[i++] = 0;
380 if(!getip46(param->srv->family, buf+4, (struct sockaddr *) ¶m->sinsr)) RETURN(100);
381 break;
382 default:
383 RETURN(997);
384 }
385
386 memcpy(SAPORT(¶m->sinsr), buf+i, 2);
387 i+=2;
388
389 sasize = sizeof(param->sinsr);
390 if(len > (int)i){
391 socksendto(param->remsock, (struct sockaddr *)¶m->sinsr, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000);
392 param->statscli64+=(len - i);
393 param->nwrites++;
394 #if SOCKSTRACE > 1
395 fprintf(stderr, "UDP packet relayed from client to %s:%hu size %d, header %d\n",
396 inet_ntoa(param->sins.sin_addr),
397 ntohs(param->sins.sin_port),
398 (len - i),
399 i
400 );
401 fprintf(stderr, "client address is assumed to be %s:%hu\n",
402 inet_ntoa(sin.sin_addr),
403 ntohs(sin.sin_port)
404 );
405 fflush(stderr);
406 #endif
407 }
408
409 }
410 if (fds[0].revents) {
411 sasize = sizeof(param->sinsr);
412 buf[0]=buf[1]=buf[2]=0;
413 buf[3]=(*SAFAMILY(¶m->sinsl) == AF_INET)?1:4;
414 if((len = so._recvfrom(param->remsock, (char *)buf+6+SAADDRLEN(¶m->sinsl), 65535 - (6+SAADDRLEN(¶m->sinsl)), 0, (struct sockaddr *)¶m->sinsr, &sasize)) <= 0) {
415 param->res = 468;
416 break;
417 }
418 param->statssrv64+=len;
419 param->nreads++;
420 memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr));
421 memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2);
422 sasize = sizeof(sin);
423 socksendto(param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(¶m->sinsr), conf.timeouts[SINGLEBYTE_L]*1000);
424 #if SOCKSTRACE > 1
425 fprintf(stderr, "UDP packet relayed to client from %hu size %d\n",
426 ntohs(*SAPORT(¶m->sinsr)),
427 len
428 );
429 fflush(stderr);
430 #endif
431
432 }
433 }
434 break;
435 default:
436 param->res = 417;
437 break;
438 }
439 }
440 }
441
442 if(command > 3) command = 0;
443 if(buf){
444 sprintf((char *)buf, "%s ", commands[command]);
445 if(param->hostname){
446 sprintf((char *)buf + strlen((char *)buf), "%.265s", param->hostname);
447 }
448 else
449 myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)buf + strlen((char *)buf), 64);
450 sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(*SAPORT(¶m->req)));
451 dolog(param, buf);
452 myfree(buf);
453 }
454 freeparam(param);
455 return (NULL);
456 }
457
458 #ifdef WITHMAIN
459 struct proxydef childdef = {
460 sockschild,
461 1080,
462 0,
463 S_SOCKS,
464 "-N(EXTERNAL_IP) External NAT address to report to client for BIND\n"
465 };
466 #include "proxymain.c"
467 #endif
468