3proxy/src/socks.c

459 lines
14 KiB
C
Raw Normal View History

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;
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;
#ifndef NOIPV6
struct sockaddr_in6 sin = {AF_INET6};
#else
struct sockaddr_in sin = {AF_INET};
#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--) {
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;
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);
}
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);}
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;
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 {
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;
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;
port = *(unsigned short*)buf;
2014-04-08 17:03:21 +08:00
c = 1;
}
size = 4;
*SAFAMILY(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET;
2014-04-08 17:03:21 +08:00
switch(c) {
#ifndef NOIPV6
case 4:
if(param->srv->family == 4) RETURN(997);
size = 16;
*SAFAMILY(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET6;
#endif
2014-04-08 17:03:21 +08:00
case 1:
for (i = 0; i<size; i++){
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;
}
#ifndef NOIPV6
if (c == 1 && param->srv->family==6){
char prefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255};
*SAFAMILY(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET6;
memcpy(SAADDR(&param->sinsr), prefix, 12);
memcpy(12 + (char *)SAADDR(&param->sinsr), buf, 4);
memcpy(SAADDR(&param->req), prefix, 12);
memcpy(12 + (char *)SAADDR(&param->req), buf, 4);
}
else {
#endif
memcpy(SAADDR(&param->sinsr), buf, size);
memcpy(SAADDR(&param->req), buf, size);
#ifndef NOIPV6
}
#endif
if(SAISNULL(&param->req)) {
RETURN(421);
2014-04-08 17:03:21 +08:00
}
myinet_ntop(*SAFAMILY(&param->sinsr), SAADDR(&param->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 */
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;
if(!getip46(param->srv->family, buf, (struct sockaddr *) &param->req)) RETURN(100);
2015-12-11 07:20:22 +08:00
memcpy(&param->sinsr, &param->req, sizeof(param->req));
2014-04-08 17:03:21 +08:00
break;
default:
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) {
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;
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;
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);
if(!memcmp(SAADDR(&param->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);
if(!getip46(param->srv->family, buf, (struct sockaddr *) &param->req)) RETURN(100);
memcpy(&param->sinsr, &param->req, sizeof(&param->req));
2014-04-08 17:03:21 +08:00
}
}
*SAPORT(&param->sinsr) = *SAPORT(&param->req) = port;
if(command == 1 && !*SAPORT(&param->sinsr)) {RETURN(421);}
2014-04-08 17:03:21 +08:00
switch(command) {
case 1:
param->operation = CONNECT;
break;
case 2:
case 3:
#ifndef NOIPV6
memcpy(&param->sinsl, *SAFAMILY(&param->req)==AF_INET6? (struct sockaddr *)&param->srv->extsa6:(struct sockaddr *)&param->srv->extsa, SASIZE(&param->req));
#else
memcpy(&param->sinsl, &param->srv->extsa, SASIZE(&param->req));
#endif
if ((param->remsock=so._socket(SASOCK(&param->req), command == 2? SOCK_STREAM:SOCK_DGRAM, command == 2?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);}
param->operation = command == 2?BIND:UDPASSOC;
2014-04-08 17:03:21 +08:00
break;
2014-04-08 17:03:21 +08:00
default:
RETURN(997);
}
if((res = (*param->srv->authfunc)(param))) {
RETURN(res);
}
2014-04-08 17:03:21 +08:00
if(command > 1) {
if(so._bind(param->remsock,(struct sockaddr *)&param->sinsl,SASIZE(&param->sinsl))) {
*SAPORT(&param->sinsl) = 0;
if(so._bind(param->remsock,(struct sockaddr *)&param->sinsl,SASIZE(&param->sinsl)))RETURN (12);
2014-04-08 17:03:21 +08:00
#if SOCKSTRACE > 0
fprintf(stderr, "%hu binded to communicate with server\n", *SAPORT(&param->sins));
2014-04-08 17:03:21 +08:00
fflush(stderr);
#endif
}
sasize = SASIZE(&param->sinsl);
so._getsockname(param->remsock, (struct sockaddr *)&param->sinsl, &sasize);
2014-04-08 17:03:21 +08:00
if(command == 3) {
param->ctrlsock = param->clisock;
param->clisock = so._socket(SASOCK(&param->sincr), SOCK_DGRAM, IPPROTO_UDP);
2014-04-08 17:03:21 +08:00
if(param->clisock == INVALID_SOCKET) {RETURN(11);}
memcpy(&sin, &param->sincl, sizeof(&sin));
*SAPORT(&sin) = 0;
if(so._bind(param->clisock,(struct sockaddr *)&sin,sizeof(sin))) {RETURN (12);}
2014-04-08 17:03:21 +08:00
#if SOCKSTRACE > 0
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){
int repcode;
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
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;
buf[1] = repcode;
2014-04-08 17:03:21 +08:00
buf[2] = 0;
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;
buf[1] = 90 + !!(repcode);
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;
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;
}
sasize = sizeof(param->sinsr);
s = so._accept(param->remsock, (struct sockaddr *)&param->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;
}
if(SAISNULL(&param->req) &&
memcmp(SAADDR(&param->req),SAADDR(&param->sinsr),SAADDRLEN(&param->req))) {
2014-04-08 17:03:21 +08:00
param->res = 470;
break;
}
#if SOCKSTRACE > 0
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],
*SAPORT(param->sins);
2014-04-08 17:03:21 +08:00
);
fflush(stderr);
#endif
if(ver == 5){
buf[3] = (*SAFAMILY(&param->sinsr) == AF_INET)?1:4;
memcpy(buf+4, SAADDR(&param->sinsr), SAADDRLEN(&param->sinsr));
memcpy(buf+4+SAADDRLEN(&param->sinsr), SAPORT(&param->sinsr), 2);
socksend(param->clisock, buf, 6+SAADDRLEN(&param->sinsr), conf.timeouts[STRING_S]);
2014-04-08 17:03:21 +08:00
}
else {
memcpy (buf+2, SAPORT(&param->sinsr), 2);
memcpy (buf+4, SAADDR(&param->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:
memcpy(&param->sinsr, &param->req, sizeof(param->sinsr));
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) {
sasize = sizeof(sin);
2014-04-08 17:03:21 +08:00
if((len = so._recvfrom(param->clisock, buf, 65535, 0, (struct sockaddr *)&sin, &sasize)) <= 10) {
param->res = 464;
break;
}
if(SAADDRLEN(&sin) != SAADDRLEN(&param->sincr) || memcmp(SAADDR(&sin), SAADDR(&param->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;
}
size = 4;
2014-04-08 17:03:21 +08:00
switch(buf[3]) {
case 4:
size = 16;
2014-04-08 17:03:21 +08:00
case 1:
i = 4+size;
memcpy(SAADDR(&param->sinsr), buf+4, size);
*SAFAMILY(&param->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;
if(!getip46(param->srv->family, buf, (struct sockaddr *) &param->sinsr)) RETURN(100);
2014-04-08 17:03:21 +08:00
break;
default:
RETURN(997);
2014-04-08 17:03:21 +08:00
}
memcpy(SAPORT(&param->sinsr), buf+i, 2);
2014-04-08 17:03:21 +08:00
i+=2;
sasize = sizeof(param->sinsr);
2014-04-08 17:03:21 +08:00
if(len > (int)i){
if(socksendto(param->remsock, (struct sockaddr *)&param->sinsr, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000) <= 0){
2014-04-08 17:03:21 +08:00
param->res = 467;
break;
}
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) {
sasize = sizeof(param->sinsr);
2014-04-08 17:03:21 +08:00
buf[0]=buf[1]=buf[2]=0;
buf[3]=(*SAFAMILY(&param->sinsl) == AF_INET)?1:4;
if((len = so._recvfrom(param->remsock, buf+6+SAADDRLEN(&param->sinsl), 65535 - 10, 0, (struct sockaddr *)&param->sinsr, &sasize)) <= 0) {
2014-04-08 17:03:21 +08:00
param->res = 468;
break;
}
param->statssrv64+=len;
2014-04-08 17:03:21 +08:00
param->nreads++;
memcpy(buf+4, SAADDR(&param->sinsr), SAADDRLEN(&param->sinsr));
memcpy(buf+4+SAADDRLEN(&param->sinsr), SAPORT(&param->sinsr), 2);
sasize = sizeof(sin);
if(socksendto(param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(&param->sinsr), conf.timeouts[SINGLEBYTE_L]*1000) <=0){
2014-04-08 17:03:21 +08:00
param->res = 469;
break;
}
#if SOCKSTRACE > 1
fprintf(stderr, "UDP packet relayed to client from %hu size %d\n",
ntohs(*SAPORT(&param->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(&param->req), SAADDR(&param->req), (char *)buf + strlen((char *)buf), 64);
sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(*SAPORT(&param->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