2014-04-08 17:03:21 +08:00
|
|
|
/*
|
|
|
|
3APA3A simpliest proxy server
|
|
|
|
(c) 2002-2008 by ZARAZA <3APA3A@security.nnov.ru>
|
|
|
|
|
|
|
|
please read License Agreement
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "proxy.h"
|
|
|
|
|
|
|
|
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
|
|
|
|
|
|
|
|
unsigned char * commands[] = {(unsigned char *)"UNKNOWN", (unsigned char *)"CONNECT", (unsigned char *)"BIND", (unsigned char *)"UDPMAP"};
|
|
|
|
|
|
|
|
#define BUFSIZE 1024
|
|
|
|
#define LARGEBUFSIZE 67000
|
|
|
|
|
|
|
|
void * sockschild(struct clientparam* param) {
|
|
|
|
int res;
|
|
|
|
unsigned i=0;
|
|
|
|
SOCKET s;
|
|
|
|
unsigned size;
|
|
|
|
SASIZETYPE sasize;
|
2014-10-20 01:54:24 +08:00
|
|
|
unsigned short port = 0;
|
2014-04-08 17:03:21 +08:00
|
|
|
unsigned char * buf=NULL;
|
|
|
|
unsigned char c;
|
|
|
|
unsigned char command=0;
|
|
|
|
struct pollfd fds[3];
|
|
|
|
int ver=0;
|
|
|
|
int havepass = 0;
|
2014-05-11 09:04:04 +08:00
|
|
|
#ifndef NOIPV6
|
2014-10-20 01:54:24 +08:00
|
|
|
struct sockaddr_in6 sin = {AF_INET6};
|
2014-05-11 09:04:04 +08:00
|
|
|
#else
|
2014-10-20 01:54:24 +08:00
|
|
|
struct sockaddr_in sin = {AF_INET};
|
2014-05-11 09:04:04 +08:00
|
|
|
#endif
|
2014-04-08 17:03:21 +08:00
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
|
|
param->service = S_SOCKS;
|
|
|
|
|
|
|
|
if(!(buf = myalloc(BUFSIZE))) {RETURN(21);}
|
|
|
|
memset(buf, 0, BUFSIZE);
|
|
|
|
if ((ver = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5 && ver != 4) {
|
|
|
|
RETURN(401);
|
|
|
|
} /* version */
|
|
|
|
param->service = ver;
|
|
|
|
if(ver == 5){
|
|
|
|
if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} /* nmethods */
|
|
|
|
for (; i; i--) {
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
|
2016-01-15 20:29:57 +08:00
|
|
|
if (res == 2 && param->srv->needuser) {
|
2014-04-08 17:03:21 +08:00
|
|
|
havepass = res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf[0] = 5;
|
2016-01-15 20:29:57 +08:00
|
|
|
buf[1] = (param->srv->needuser > 1 && !havepass)? 255 : havepass;
|
2014-07-02 01:08:31 +08:00
|
|
|
if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(401);}
|
2016-01-15 20:29:57 +08:00
|
|
|
if (param->srv->needuser > 1 && !havepass) RETURN(4);
|
2014-04-08 17:03:21 +08:00
|
|
|
if (havepass) {
|
|
|
|
if (((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0))) != 1) {
|
|
|
|
RETURN(412);
|
|
|
|
}
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);}
|
|
|
|
if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);};
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[i] = 0;
|
|
|
|
if(!param->username)param->username = (unsigned char *)mystrdup((char *)buf);
|
|
|
|
if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(445);}
|
2014-07-02 01:08:31 +08:00
|
|
|
if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);};
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[i] = 0;
|
|
|
|
if(!param->password)param->password = (unsigned char *)mystrdup((char *)buf);
|
|
|
|
buf[0] = 1;
|
|
|
|
buf[1] = 0;
|
2014-07-02 01:08:31 +08:00
|
|
|
if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(481);}
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
|
|
|
if ((c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5) {
|
|
|
|
RETURN(421);
|
|
|
|
} /* version */
|
|
|
|
}
|
|
|
|
if( (command = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) < 1 || command > 3){command = 0; RETURN(407);} /* command */
|
|
|
|
if(ver == 5){
|
|
|
|
if (sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0) == EOF) {RETURN(447);} /* reserved */
|
|
|
|
c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0); /* atype */
|
|
|
|
}
|
|
|
|
else {
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[0] = (unsigned char) res;
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[1] = (unsigned char) res;
|
2014-10-20 01:54:24 +08:00
|
|
|
port = *(unsigned short*)buf;
|
2014-04-08 17:03:21 +08:00
|
|
|
c = 1;
|
|
|
|
}
|
|
|
|
|
2014-10-20 01:54:24 +08:00
|
|
|
size = 4;
|
2015-12-08 03:58:31 +08:00
|
|
|
*SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET;
|
2014-04-08 17:03:21 +08:00
|
|
|
switch(c) {
|
2015-12-08 03:58:31 +08:00
|
|
|
#ifndef NOIPV6
|
2014-10-20 01:54:24 +08:00
|
|
|
case 4:
|
2015-12-08 03:58:31 +08:00
|
|
|
if(param->srv->family == 4) RETURN(997);
|
2014-10-20 01:54:24 +08:00
|
|
|
size = 16;
|
2015-12-08 03:58:31 +08:00
|
|
|
*SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET6;
|
|
|
|
#endif
|
2014-04-08 17:03:21 +08:00
|
|
|
case 1:
|
2014-10-20 01:54:24 +08:00
|
|
|
for (i = 0; i<size; i++){
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[i] = (unsigned char)res;
|
|
|
|
}
|
2015-12-08 03:58:31 +08:00
|
|
|
#ifndef NOIPV6
|
|
|
|
if (c == 1 && param->srv->family==6){
|
|
|
|
char prefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255};
|
|
|
|
*SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET6;
|
|
|
|
memcpy(SAADDR(¶m->sinsr), prefix, 12);
|
|
|
|
memcpy(12 + (char *)SAADDR(¶m->sinsr), buf, 4);
|
|
|
|
memcpy(SAADDR(¶m->req), prefix, 12);
|
|
|
|
memcpy(12 + (char *)SAADDR(¶m->req), buf, 4);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
#endif
|
|
|
|
memcpy(SAADDR(¶m->sinsr), buf, size);
|
|
|
|
memcpy(SAADDR(¶m->req), buf, size);
|
|
|
|
#ifndef NOIPV6
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if(SAISNULL(¶m->req)) {
|
2014-07-02 01:08:31 +08:00
|
|
|
RETURN(421);
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
2014-10-20 01:54:24 +08:00
|
|
|
myinet_ntop(*SAFAMILY(¶m->sinsr), SAADDR(¶m->sinsr), (char *)buf, 64);
|
2014-04-08 17:03:21 +08:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if ((size = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);} /* nmethods */
|
|
|
|
for (i=0; i<size; i++){ /* size < 256 */
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);}
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[i] = (unsigned char)res;
|
|
|
|
}
|
|
|
|
buf[i] = 0;
|
2014-10-20 01:54:24 +08:00
|
|
|
if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100);
|
2016-02-05 23:31:17 +08:00
|
|
|
param->sinsr = param->req;
|
2014-04-08 17:03:21 +08:00
|
|
|
break;
|
|
|
|
default:
|
2014-07-02 01:08:31 +08:00
|
|
|
RETURN(997);
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
|
|
|
if(param->hostname)myfree(param->hostname);
|
|
|
|
param->hostname = (unsigned char *)mystrdup((char *)buf);
|
|
|
|
if (ver == 5) {
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[0] = (unsigned char) res;
|
2014-07-02 01:08:31 +08:00
|
|
|
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[1] = (unsigned char) res;
|
2014-10-20 01:54:24 +08:00
|
|
|
port = *(unsigned short*)buf;
|
|
|
|
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]);
|
|
|
|
buf[127] = 0;
|
2016-01-15 20:29:57 +08:00
|
|
|
if(param->srv->needuser && *buf && !param->username)param->username = (unsigned char *)mystrdup((char *)buf);
|
2014-10-20 01:54:24 +08:00
|
|
|
if(!memcmp(SAADDR(¶m->req), "\0\0\0", 3)){
|
2014-04-08 17:03:21 +08:00
|
|
|
param->service = S_SOCKS45;
|
|
|
|
sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]);
|
|
|
|
buf[127] = 0;
|
|
|
|
if(param->hostname)myfree(param->hostname);
|
|
|
|
param->hostname = (unsigned char *)mystrdup((char *)buf);
|
2014-10-20 01:54:24 +08:00
|
|
|
if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100);
|
2016-02-05 23:31:17 +08:00
|
|
|
param->sinsr = param->req;
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
|
|
|
}
|
2014-10-20 01:54:24 +08:00
|
|
|
|
|
|
|
*SAPORT(¶m->sinsr) = *SAPORT(¶m->req) = port;
|
|
|
|
if(command == 1 && !*SAPORT(¶m->sinsr)) {RETURN(421);}
|
2014-04-08 17:03:21 +08:00
|
|
|
switch(command) {
|
|
|
|
case 1:
|
|
|
|
param->operation = CONNECT;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
2014-11-10 02:59:58 +08:00
|
|
|
|
|
|
|
#ifndef NOIPV6
|
2016-02-05 23:31:17 +08:00
|
|
|
param->sinsl = *SAFAMILY(¶m->req)==AF_INET6? param->srv->extsa6 : param->srv->extsa;
|
2014-11-10 02:59:58 +08:00
|
|
|
#else
|
2016-02-05 23:31:17 +08:00
|
|
|
param->sinsl = param->srv->extsa;
|
2014-11-10 02:59:58 +08:00
|
|
|
#endif
|
2014-12-11 08:06:34 +08:00
|
|
|
if ((param->remsock=so._socket(SASOCK(¶m->req), command == 2? SOCK_STREAM:SOCK_DGRAM, command == 2?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);}
|
2014-10-20 01:54:24 +08:00
|
|
|
param->operation = command == 2?BIND:UDPASSOC;
|
2016-01-23 20:34:24 +08:00
|
|
|
#ifdef REUSE
|
|
|
|
if (command == 2){
|
|
|
|
int opt;
|
|
|
|
|
|
|
|
#ifdef SO_REUSEADDR
|
|
|
|
opt = 1;
|
|
|
|
so._setsockopt(param->remsock, SOL_SOCKET, SO_REUSEADDR, (unsigned char *)&opt, sizeof(int));
|
|
|
|
#endif
|
|
|
|
#ifdef SO_REUSEPORT
|
|
|
|
opt = 1;
|
|
|
|
so._setsockopt(param->remsock, SOL_SOCKET, SO_REUSEPORT, (unsigned char *)&opt, sizeof(int));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
2014-04-08 17:03:21 +08:00
|
|
|
break;
|
2014-10-20 01:54:24 +08:00
|
|
|
|
2014-04-08 17:03:21 +08:00
|
|
|
default:
|
|
|
|
RETURN(997);
|
|
|
|
}
|
|
|
|
|
2014-07-02 01:08:31 +08:00
|
|
|
if((res = (*param->srv->authfunc)(param))) {
|
|
|
|
RETURN(res);
|
|
|
|
}
|
2014-04-08 17:03:21 +08:00
|
|
|
|
|
|
|
if(command > 1) {
|
2014-10-20 01:54:24 +08:00
|
|
|
if(so._bind(param->remsock,(struct sockaddr *)¶m->sinsl,SASIZE(¶m->sinsl))) {
|
|
|
|
*SAPORT(¶m->sinsl) = 0;
|
|
|
|
if(so._bind(param->remsock,(struct sockaddr *)¶m->sinsl,SASIZE(¶m->sinsl)))RETURN (12);
|
2014-04-08 17:03:21 +08:00
|
|
|
#if SOCKSTRACE > 0
|
2014-10-20 01:54:24 +08:00
|
|
|
fprintf(stderr, "%hu binded to communicate with server\n", *SAPORT(¶m->sins));
|
2014-04-08 17:03:21 +08:00
|
|
|
fflush(stderr);
|
|
|
|
#endif
|
|
|
|
}
|
2014-10-20 01:54:24 +08:00
|
|
|
sasize = SASIZE(¶m->sinsl);
|
|
|
|
so._getsockname(param->remsock, (struct sockaddr *)¶m->sinsl, &sasize);
|
2014-04-08 17:03:21 +08:00
|
|
|
if(command == 3) {
|
|
|
|
param->ctrlsock = param->clisock;
|
2014-05-11 09:04:04 +08:00
|
|
|
param->clisock = so._socket(SASOCK(¶m->sincr), SOCK_DGRAM, IPPROTO_UDP);
|
2014-04-08 17:03:21 +08:00
|
|
|
if(param->clisock == INVALID_SOCKET) {RETURN(11);}
|
2016-02-05 23:31:17 +08:00
|
|
|
sin = param->sincl;
|
2014-10-20 01:54:24 +08:00
|
|
|
*SAPORT(&sin) = 0;
|
2016-01-22 20:59:40 +08:00
|
|
|
if(so._bind(param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);}
|
2014-04-08 17:03:21 +08:00
|
|
|
#if SOCKSTRACE > 0
|
2014-05-11 09:04:04 +08:00
|
|
|
fprintf(stderr, "%hu binded to communicate with client\n",
|
|
|
|
ntohs(*SAPORT(&sin))
|
2014-04-08 17:03:21 +08:00
|
|
|
);
|
|
|
|
fflush(stderr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
param->res = 0;
|
|
|
|
|
|
|
|
CLEANRET:
|
|
|
|
|
|
|
|
if(param->clisock != INVALID_SOCKET){
|
2014-07-03 07:40:16 +08:00
|
|
|
int repcode;
|
|
|
|
|
2014-05-11 09:04:04 +08:00
|
|
|
sasize = sizeof(sin);
|
2014-04-08 17:03:21 +08:00
|
|
|
if(command != 3) so._getsockname(param->remsock, (struct sockaddr *)&sin, &sasize);
|
|
|
|
else so._getsockname(param->clisock, (struct sockaddr *)&sin, &sasize);
|
|
|
|
#if SOCKSTRACE > 0
|
|
|
|
fprintf(stderr, "Sending confirmation to client with code %d for %s with %s:%hu\n",
|
|
|
|
param->res,
|
|
|
|
commands[command],
|
|
|
|
inet_ntoa(sin.sin_addr),
|
|
|
|
ntohs(sin.sin_port)
|
|
|
|
);
|
|
|
|
fflush(stderr);
|
|
|
|
#endif
|
2014-07-03 07:40:16 +08:00
|
|
|
if(!param->res) repcode = 0;
|
|
|
|
else if(param->res <= 10) repcode = 2;
|
|
|
|
else if (param->res < 20) repcode = 5;
|
|
|
|
else if (param->res < 30) repcode = 1;
|
|
|
|
else if (param->res < 100) repcode = 4;
|
|
|
|
else repcode = param->res%10;
|
|
|
|
|
2014-04-08 17:03:21 +08:00
|
|
|
if(ver == 5){
|
|
|
|
buf[0] = 5;
|
2014-07-03 07:40:16 +08:00
|
|
|
buf[1] = repcode;
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[2] = 0;
|
2014-10-20 01:54:24 +08:00
|
|
|
buf[3] = (*SAFAMILY(&sin) == AF_INET)?1:4;
|
|
|
|
memcpy(buf+4, SAADDR(&sin), SAADDRLEN(&sin));
|
|
|
|
memcpy(buf+4+SAADDRLEN(&sin), SAPORT(&sin), 2);
|
|
|
|
socksend((command == 3)?param->ctrlsock:param->clisock, buf, 6+SAADDRLEN(&sin), conf.timeouts[STRING_S]);
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
buf[0] = 0;
|
2014-07-03 07:40:16 +08:00
|
|
|
buf[1] = 90 + !!(repcode);
|
2014-05-11 09:04:04 +08:00
|
|
|
memcpy(buf+2, SAPORT(&sin), 2);
|
|
|
|
memcpy(buf+4, SAADDR(&sin), 4);
|
2014-04-08 17:03:21 +08:00
|
|
|
socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param->res == 0) {
|
|
|
|
switch(command) {
|
|
|
|
case 1:
|
|
|
|
if(param->redirectfunc){
|
|
|
|
if(buf)myfree(buf);
|
|
|
|
return (*param->redirectfunc)(param);
|
|
|
|
}
|
|
|
|
param->res = sockmap(param, conf.timeouts[CONNECTION_L]);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
so._listen (param->remsock, 1);
|
|
|
|
|
|
|
|
fds[0].fd = param->remsock;
|
|
|
|
fds[1].fd = param->clisock;
|
|
|
|
fds[0].events = fds[1].events = POLLIN;
|
2014-10-20 01:54:24 +08:00
|
|
|
res = so._poll(fds, 2, conf.timeouts[CONNECTION_L] * 1000);
|
2014-04-08 17:03:21 +08:00
|
|
|
if (res < 1 || fds[1].revents) {
|
|
|
|
res = 460;
|
|
|
|
break;
|
|
|
|
}
|
2014-10-20 01:54:24 +08:00
|
|
|
sasize = sizeof(param->sinsr);
|
|
|
|
s = so._accept(param->remsock, (struct sockaddr *)¶m->sinsr, &sasize);
|
2014-04-08 17:03:21 +08:00
|
|
|
so._closesocket(param->remsock);
|
|
|
|
param->remsock = s;
|
|
|
|
if(s == INVALID_SOCKET) {
|
|
|
|
param->res = 462;
|
|
|
|
break;
|
|
|
|
}
|
2014-12-14 03:38:03 +08:00
|
|
|
if(SAISNULL(¶m->req) &&
|
2014-10-20 01:54:24 +08:00
|
|
|
memcmp(SAADDR(¶m->req),SAADDR(¶m->sinsr),SAADDRLEN(¶m->req))) {
|
2014-04-08 17:03:21 +08:00
|
|
|
param->res = 470;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if SOCKSTRACE > 0
|
2014-10-20 01:54:24 +08:00
|
|
|
fprintf(stderr, "Sending incoming connection to client with code %d for %s with %hu\n",
|
2014-04-08 17:03:21 +08:00
|
|
|
param->res,
|
|
|
|
commands[command],
|
2014-10-20 01:54:24 +08:00
|
|
|
*SAPORT(param->sins);
|
2014-04-08 17:03:21 +08:00
|
|
|
);
|
|
|
|
fflush(stderr);
|
|
|
|
#endif
|
|
|
|
if(ver == 5){
|
2014-10-20 01:54:24 +08:00
|
|
|
buf[3] = (*SAFAMILY(¶m->sinsr) == AF_INET)?1:4;
|
|
|
|
memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr));
|
|
|
|
memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2);
|
|
|
|
socksend(param->clisock, buf, 6+SAADDRLEN(¶m->sinsr), conf.timeouts[STRING_S]);
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
|
|
|
else {
|
2014-10-20 01:54:24 +08:00
|
|
|
memcpy (buf+2, SAPORT(¶m->sinsr), 2);
|
|
|
|
memcpy (buf+4, SAADDR(¶m->sinsr), 4);
|
2014-04-08 17:03:21 +08:00
|
|
|
socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]);
|
|
|
|
}
|
|
|
|
|
|
|
|
param->res = sockmap(param, conf.timeouts[CONNECTION_S]);
|
|
|
|
break;
|
|
|
|
case 3:
|
2016-02-05 23:31:17 +08:00
|
|
|
param->sinsr = param->req;
|
2014-04-08 17:03:21 +08:00
|
|
|
myfree(buf);
|
|
|
|
if(!(buf = myalloc(LARGEBUFSIZE))) {RETURN(21);}
|
|
|
|
|
|
|
|
for(;;){
|
|
|
|
fds[0].fd = param->remsock;
|
|
|
|
fds[1].fd = param->clisock;
|
|
|
|
fds[2].fd = param->ctrlsock;
|
|
|
|
fds[2].events = fds[1].events = fds[0].events = POLLIN;
|
|
|
|
|
|
|
|
res = so._poll(fds, 3, conf.timeouts[CONNECTION_L]*1000);
|
|
|
|
if(res <= 0) {
|
|
|
|
param->res = 463;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (fds[2].revents) {
|
|
|
|
param->res = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (fds[1].revents) {
|
2014-05-11 09:04:04 +08:00
|
|
|
sasize = sizeof(sin);
|
2016-02-16 20:29:51 +08:00
|
|
|
if((len = so._recvfrom(param->clisock, (char *)buf, 65535, 0, (struct sockaddr *)&sin, &sasize)) <= 10) {
|
2014-04-08 17:03:21 +08:00
|
|
|
param->res = 464;
|
|
|
|
break;
|
|
|
|
}
|
2014-05-11 09:04:04 +08:00
|
|
|
if(SAADDRLEN(&sin) != SAADDRLEN(¶m->sincr) || memcmp(SAADDR(&sin), SAADDR(¶m->sincr), SAADDRLEN(&sin))){
|
2014-04-08 17:03:21 +08:00
|
|
|
param->res = 465;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(buf[0] || buf[1] || buf[2]) {
|
|
|
|
param->res = 466;
|
|
|
|
break;
|
|
|
|
}
|
2014-10-20 01:54:24 +08:00
|
|
|
size = 4;
|
2014-04-08 17:03:21 +08:00
|
|
|
switch(buf[3]) {
|
2014-10-20 01:54:24 +08:00
|
|
|
case 4:
|
|
|
|
size = 16;
|
2014-04-08 17:03:21 +08:00
|
|
|
case 1:
|
2014-10-20 01:54:24 +08:00
|
|
|
i = 4+size;
|
|
|
|
memcpy(SAADDR(¶m->sinsr), buf+4, size);
|
|
|
|
*SAFAMILY(¶m->sinsr) = (size == 4)?AF_INET:AF_INET6;
|
2014-04-08 17:03:21 +08:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
size = buf[4];
|
|
|
|
for (i=4; size; i++, size--){
|
|
|
|
buf[i] = buf[i+1];
|
|
|
|
}
|
|
|
|
buf[i++] = 0;
|
2014-10-20 01:54:24 +08:00
|
|
|
if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->sinsr)) RETURN(100);
|
2014-04-08 17:03:21 +08:00
|
|
|
break;
|
|
|
|
default:
|
2014-07-02 01:08:31 +08:00
|
|
|
RETURN(997);
|
2014-04-08 17:03:21 +08:00
|
|
|
}
|
|
|
|
|
2014-10-20 01:54:24 +08:00
|
|
|
memcpy(SAPORT(¶m->sinsr), buf+i, 2);
|
2014-04-08 17:03:21 +08:00
|
|
|
i+=2;
|
|
|
|
|
2014-10-20 01:54:24 +08:00
|
|
|
sasize = sizeof(param->sinsr);
|
2014-04-08 17:03:21 +08:00
|
|
|
if(len > (int)i){
|
2014-10-20 01:54:24 +08:00
|
|
|
if(socksendto(param->remsock, (struct sockaddr *)¶m->sinsr, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000) <= 0){
|
2014-04-08 17:03:21 +08:00
|
|
|
param->res = 467;
|
|
|
|
break;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64+=(len - i);
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
#if SOCKSTRACE > 1
|
|
|
|
fprintf(stderr, "UDP packet relayed from client to %s:%hu size %d, header %d\n",
|
|
|
|
inet_ntoa(param->sins.sin_addr),
|
|
|
|
ntohs(param->sins.sin_port),
|
|
|
|
(len - i),
|
|
|
|
i
|
|
|
|
);
|
|
|
|
fprintf(stderr, "client address is assumed to be %s:%hu\n",
|
|
|
|
inet_ntoa(sin.sin_addr),
|
|
|
|
ntohs(sin.sin_port)
|
|
|
|
);
|
|
|
|
fflush(stderr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (fds[0].revents) {
|
2014-10-20 01:54:24 +08:00
|
|
|
sasize = sizeof(param->sinsr);
|
2014-04-08 17:03:21 +08:00
|
|
|
buf[0]=buf[1]=buf[2]=0;
|
2014-10-20 01:54:24 +08:00
|
|
|
buf[3]=(*SAFAMILY(¶m->sinsl) == AF_INET)?1:4;
|
2016-02-16 20:29:51 +08:00
|
|
|
if((len = so._recvfrom(param->remsock, (char *)buf+6+SAADDRLEN(¶m->sinsl), 65535 - 10, 0, (struct sockaddr *)¶m->sinsr, &sasize)) <= 0) {
|
2014-04-08 17:03:21 +08:00
|
|
|
param->res = 468;
|
|
|
|
break;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statssrv64+=len;
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nreads++;
|
2014-10-20 01:54:24 +08:00
|
|
|
memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr));
|
|
|
|
memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2);
|
|
|
|
sasize = sizeof(sin);
|
|
|
|
if(socksendto(param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(¶m->sinsr), conf.timeouts[SINGLEBYTE_L]*1000) <=0){
|
2014-04-08 17:03:21 +08:00
|
|
|
param->res = 469;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if SOCKSTRACE > 1
|
2014-10-20 01:54:24 +08:00
|
|
|
fprintf(stderr, "UDP packet relayed to client from %hu size %d\n",
|
|
|
|
ntohs(*SAPORT(¶m->sinsr)),
|
2014-04-08 17:03:21 +08:00
|
|
|
len
|
|
|
|
);
|
|
|
|
fflush(stderr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
param->res = 417;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(command > 3) command = 0;
|
|
|
|
if(buf){
|
|
|
|
sprintf((char *)buf, "%s ", commands[command]);
|
|
|
|
if(param->hostname){
|
|
|
|
sprintf((char *)buf + strlen((char *)buf), "%.265s", param->hostname);
|
|
|
|
}
|
2014-05-11 06:41:13 +08:00
|
|
|
else
|
|
|
|
myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)buf + strlen((char *)buf), 64);
|
2014-10-20 01:54:24 +08:00
|
|
|
sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(*SAPORT(¶m->req)));
|
2014-04-08 17:03:21 +08:00
|
|
|
(*param->srv->logfunc)(param, buf);
|
|
|
|
myfree(buf);
|
|
|
|
}
|
|
|
|
freeparam(param);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITHMAIN
|
|
|
|
struct proxydef childdef = {
|
|
|
|
sockschild,
|
|
|
|
1080,
|
|
|
|
0,
|
|
|
|
S_SOCKS,
|
|
|
|
""
|
|
|
|
};
|
|
|
|
#include "proxymain.c"
|
|
|
|
#endif
|