| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- /*
- 3APA3A simpliest proxy server
- (c) 2002-2008 by ZARAZA <3APA3A@security.nnov.ru>
- please read License Agreement
- $Id: socks.c,v 1.34 2009/09/17 12:21:09 v.dubrovin Exp $
- */
- #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 char * buf=NULL;
- unsigned char c;
- unsigned char command=0;
- struct pollfd fds[3];
- int ver=0;
- int havepass = 0;
- struct sockaddr_in sin;
- int len;
- param->req.sin_addr.s_addr = 0;
- 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(442);}
- if (res == 2 && !param->srv->nouser) {
- havepass = res;
- }
- }
- buf[0] = 5;
- buf[1] = havepass;
- if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(402);}
- 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(443);}
- if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(444);};
- 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(446);};
- 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(402);}
- }
- 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(448);}
- buf[0] = (unsigned char) res;
- if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(449);}
- buf[1] = (unsigned char) res;
- param->sins.sin_port = param->req.sin_port = *(unsigned short*)buf;
- c = 1;
- }
-
- switch(c) {
- case 1:
- for (i = 0; i<4; i++){
- if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(450);}
- buf[i] = (unsigned char)res;
- }
- param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = *(unsigned long *)buf;
- if(command==1 && !param->req.sin_addr.s_addr) {
- RETURN(422);
- }
- myinet_ntoa(param->sins.sin_addr, (char *)buf);
- 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(452);}
- buf[i] = (unsigned char)res;
- }
- buf[i] = 0;
- param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = getip(buf);
- if(command==1 && !param->req.sin_addr.s_addr) {
- RETURN(100);
- }
- break;
- default:
- RETURN(998);
- }
- 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(453);}
- buf[0] = (unsigned char) res;
- if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(454);}
- buf[1] = (unsigned char) res;
- param->sins.sin_port = param->req.sin_port = *(unsigned short*)buf;
- }
- else {
- sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]);
- buf[127] = 0;
- if(!param->srv->nouser && *buf && !param->username)param->username = (unsigned char *)mystrdup((char *)buf);
- if(param->sins.sin_addr.s_addr && ntohl(param->sins.sin_addr.s_addr)<256){
- 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);
- param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = getip(buf);
- }
- }
- if(command == 1 && !param->req.sin_port) {RETURN(424);}
- param->sins.sin_family = AF_INET;
- switch(command) {
- case 1:
- param->operation = CONNECT;
- break;
- case 2:
- param->sins.sin_addr.s_addr = param->extip;
- param->sins.sin_port = param->extport?param->extport:param->req.sin_port;
- if ((param->remsock=so._socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);}
- param->operation = BIND;
- break;
- case 3:
- param->sins.sin_port = param->extport?param->extport:param->req.sin_port;
- param->sins.sin_addr.s_addr = param->extip;
- if ((param->remsock=so._socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);}
- param->operation = UDPASSOC;
- break;
- default:
- RETURN(997);
- }
- if((res = (*param->srv->authfunc)(param))) {RETURN(res);}
- if(command > 1) {
- if(so._bind(param->remsock,(struct sockaddr *)¶m->sins,sizeof(param->sins))) {
- param->sins.sin_port = 0;
- if(so._bind(param->remsock,(struct sockaddr *)¶m->sins,sizeof(param->sins)))RETURN (12);
- #if SOCKSTRACE > 0
- fprintf(stderr, "%s:%hu binded to communicate with server\n",
- inet_ntoa(param->sins.sin_addr),
- ntohs(param->sins.sin_port)
- );
- fflush(stderr);
- #endif
- }
- sasize = sizeof(struct sockaddr_in);
- so._getsockname(param->remsock, (struct sockaddr *)¶m->sins, &sasize);
- if(command == 3) {
- param->ctrlsock = param->clisock;
- param->clisock = so._socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if(param->clisock == INVALID_SOCKET) {RETURN(11);}
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = param->srv->intip;
- sin.sin_port = htons(0);
- if(so._bind(param->clisock,(struct sockaddr *)&sin,sizeof(struct sockaddr_in))) {RETURN (12);}
- #if SOCKSTRACE > 0
- fprintf(stderr, "%s:%hu binded to communicate with client\n",
- inet_ntoa(sin.sin_addr),
- ntohs(sin.sin_port)
- );
- fflush(stderr);
- #endif
- }
- }
- param->res = 0;
- CLEANRET:
- if(param->clisock != INVALID_SOCKET){
- sasize = sizeof(struct sockaddr_in);
- 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(ver == 5){
- buf[0] = 5;
- buf[1] = param->res%10;
- buf[2] = 0;
- buf[3] = 1;
- memcpy(buf+4, &sin.sin_addr.s_addr, 4);
- memcpy(buf+8, &sin.sin_port, 2);
- socksend((command == 3)?param->ctrlsock:param->clisock, buf, 10, conf.timeouts[STRING_S]);
- }
- else{
- buf[0] = 0;
- buf[1] = 90 + (param->res%10);
- memcpy(buf+2, &sin.sin_port, 2);
- memcpy(buf+4, &sin.sin_addr.s_addr, 4);
- 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[(param->req.sin_addr.s_addr)?CONNECTION_S:CONNECTION_L] * 1000);
- if (res < 1 || fds[1].revents) {
- res = 460;
- break;
- }
- sasize = sizeof(param->sins);
- s = so._accept(param->remsock, (struct sockaddr *)¶m->sins, &sasize);
- so._closesocket(param->remsock);
- param->remsock = s;
- if(s == INVALID_SOCKET) {
- param->res = 462;
- break;
- }
- if(param->req.sin_addr.s_addr && param->req.sin_addr.s_addr != param->sins.sin_addr.s_addr) {
- param->res = 470;
- break;
- }
- #if SOCKSTRACE > 0
- fprintf(stderr, "Sending incoming connection to client with code %d for %s with %s:%hu\n",
- param->res,
- commands[command],
- inet_ntoa(param->sins.sin_addr),
- ntohs(param->sins.sin_port)
- );
- fflush(stderr);
- #endif
- if(ver == 5){
- memcpy (buf+4, ¶m->sins.sin_addr, 4);
- memcpy (buf+8, ¶m->sins.sin_port, 2);
- socksend(param->clisock, buf, 10, conf.timeouts[STRING_S]);
- }
- else {
- memcpy (buf+2, ¶m->sins.sin_port, 2);
- memcpy (buf+4, ¶m->sins.sin_addr, 4);
- socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]);
- }
- param->res = sockmap(param, conf.timeouts[CONNECTION_S]);
- break;
- case 3:
- param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr;
- param->sins.sin_port = param->req.sin_port;
- 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(struct sockaddr_in);
- if((len = so._recvfrom(param->clisock, buf, 65535, 0, (struct sockaddr *)&sin, &sasize)) <= 10) {
- param->res = 464;
- break;
- }
- if(sin.sin_addr.s_addr != param->sinc.sin_addr.s_addr){
- param->res = 465;
- break;
- }
- if(buf[0] || buf[1] || buf[2]) {
- param->res = 466;
- break;
- }
- switch(buf[3]) {
- case 1:
- i = 8;
- memcpy(¶m->sins.sin_addr.s_addr, buf+4, 4);
- break;
- case 3:
- size = buf[4];
- for (i=4; size; i++, size--){
- buf[i] = buf[i+1];
- }
- buf[i++] = 0;
- param->sins.sin_addr.s_addr = getip(buf+4);
- break;
- default:
- RETURN(996);
- }
- memcpy(¶m->sins.sin_port, buf+i, 2);
- i+=2;
- sasize = sizeof(param->sins);
- if(len > (int)i){
- if(socksendto(param->remsock, ¶m->sins, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000) <= 0){
- param->res = 467;
- break;
- }
- param->statscli+=(len - i);
- 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) {
- struct sockaddr_in tsin;
- sasize = sizeof(tsin);
- buf[0]=buf[1]=buf[2]=0;
- buf[3]=1;
- if((len = so._recvfrom(param->remsock, buf+10, 65535 - 10, 0, (struct sockaddr *)&tsin, &sasize)) <= 0) {
- param->res = 468;
- break;
- }
- param->statssrv+=len;
- param->nreads++;
- memcpy(buf+4, &tsin.sin_addr.s_addr, 4);
- memcpy(buf+8, &tsin.sin_port, 2);
- sasize = sizeof(param->sins);
- if(socksendto(param->clisock, &sin, buf, len + 10, conf.timeouts[SINGLEBYTE_L]*1000) <=0){
- param->res = 469;
- break;
- }
- #if SOCKSTRACE > 1
- fprintf(stderr, "UDP packet relayed to client from %s:%hu size %d\n",
- inet_ntoa(tsin.sin_addr),
- ntohs(tsin.sin_port),
- 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);
- }
- else myinet_ntoa(param->req.sin_addr, (char *)buf+strlen((char *)buf));
- sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(param->req.sin_port));
- (*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
|