| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- /*
- 3APA3A simpliest proxy server
- (c) 2002-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
- please read License Agreement
- */
- #include "proxy.h"
- #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
- char * commands[] = {"UNKNOWN", "CONNECT", "BIND", "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;
- char * buf=NULL;
- char c;
- 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
- int len;
- int heur = 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(441);}
- if (res == 2 && param->srv->needuser) {
- havepass = res;
- }
- }
- buf[0] = 5;
- buf[1] = (param->srv->needuser > 1 && !havepass)? 255 : havepass;
- if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(401);}
- if (param->srv->needuser > 1 && !havepass) RETURN(4);
- 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);};
- buf[i] = 0;
- if(!param->username)param->username = mystrdup(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);};
- buf[i] = 0;
- if(!param->password)param->password = mystrdup(buf);
- buf[0] = 1;
- buf[1] = 0;
- if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(481);}
- }
- 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);}
- buf[0] = (unsigned char) res;
- if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
- buf[1] = (unsigned char) res;
- port = *(unsigned short*)buf;
- c = 1;
- }
-
- size = 4;
- *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET;
- switch(c) {
- #ifndef NOIPV6
- case 4:
- if(param->srv->family == 4) RETURN(997);
- size = 16;
- *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET6;
- #endif
- case 1:
- for (i = 0; i<size; i++){
- if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
- 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(¶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(command == 1 && SAISNULL(¶m->req)) {
- RETURN(431);
- }
- myinet_ntop(*SAFAMILY(¶m->sinsr), SAADDR(¶m->sinsr), buf, 64);
- if(command == 3){
- if(*SAFAMILY(¶m->req) == *SAFAMILY(¶m->sincr) && !memcmp(SAADDR(¶m->req),SAADDR(¶m->sincr), SAADDRLEN(¶m->req))){
- heur = 1;
- }
- else if (!SAISNULL(¶m->req)){
- heur = 2;
- }
- }
- 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);}
- buf[i] = (unsigned char)res;
- }
- buf[i] = 0;
- if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100);
- param->sinsr = param->req;
- break;
- default:
- RETURN(997);
- }
- if(param->hostname)myfree(param->hostname);
- param->hostname = mystrdup(buf);
- if (ver == 5) {
- if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
- buf[0] = (unsigned char) res;
- if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
- buf[1] = (unsigned char) res;
- port = *(unsigned short*)buf;
- }
- else {
- sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]);
- buf[127] = 0;
- if(param->srv->needuser && *buf && !param->username)param->username = mystrdup(buf);
- if(!memcmp(SAADDR(¶m->req), "\0\0\0", 3)){
- 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 = mystrdup(buf);
- if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100);
- param->sinsr = param->req;
- }
- }
- *SAPORT(¶m->sinsr) = *SAPORT(¶m->req) = port;
- if(command == 1 && !*SAPORT(¶m->sinsr)) {RETURN(461);}
- switch(command) {
- case 1:
- param->operation = CONNECT;
- break;
- case 2:
- case 3:
- #ifndef NOIPV6
- param->sinsl = *SAFAMILY(¶m->req)==AF_INET6? param->srv->extsa6 : (SAISNULL(¶m->srv->extNat)?param->srv->extsa:param->srv->extNat);
- #else
- param->sinsl = SAISNULL(¶m->srv->extNat)?param->srv->extsa:param->srv->extNat;
- #endif
- if ((param->remsock=so._socket(SASOCK(¶m->req), command == 2? SOCK_STREAM:SOCK_DGRAM, command == 2?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);}
- param->operation = command == 2?BIND:UDPASSOC;
- #ifdef REUSE
- if (command == 2){
- int opt;
- #ifdef SO_REUSEADDR
- opt = 1;
- so._setsockopt(param->remsock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
- #endif
- #ifdef SO_REUSEPORT
- opt = 1;
- so._setsockopt(param->remsock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int));
- #endif
- }
- #endif
- break;
- default:
- RETURN(997);
- }
- if((res = (*param->srv->authfunc)(param))) {
- RETURN(res);
- }
- if(command > 1) {
- 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);
- #if SOCKSTRACE > 0
- fprintf(stderr, "%hu bound to communicate with server\n", *SAPORT(¶m->sins));
- fflush(stderr);
- #endif
- }
- sasize = SASIZE(¶m->sinsl);
- so._getsockname(param->remsock, (struct sockaddr *)¶m->sinsl, &sasize);
- if(command == 3) {
- param->ctrlsock = param->clisock;
- param->clisock = so._socket(SASOCK(¶m->sincr), SOCK_DGRAM, IPPROTO_UDP);
- if(param->clisock == INVALID_SOCKET) {RETURN(11);}
- sin = param->sincl;
- *SAPORT(&sin) = 0;
- if(so._bind(param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);}
- #if SOCKSTRACE > 0
- fprintf(stderr, "%hu binded to communicate with client\n",
- ntohs(*SAPORT(&sin))
- );
- fflush(stderr);
- #endif
- }
- }
- param->res = 0;
- CLEANRET:
- if(param->clisock != INVALID_SOCKET){
- int repcode;
- sasize = sizeof(sin);
- if(command != 3 && param->remsock != INVALID_SOCKET) 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;
- if(ver == 5){
- buf[0] = 5;
- buf[1] = repcode;
- 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]);
- }
- else{
- buf[0] = 0;
- buf[1] = 90 + !!(repcode);
- memcpy(buf+2, SAPORT(&sin), 2);
- memcpy(buf+4, SAADDR(&sin), 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 = mapsocket(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);
- if (res < 1 || fds[1].revents) {
- res = 460;
- break;
- }
- sasize = sizeof(param->sinsr);
- s = so._accept(param->remsock, (struct sockaddr *)¶m->sinsr, &sasize);
- so._closesocket(param->remsock);
- param->remsock = s;
- if(s == INVALID_SOCKET) {
- param->res = 462;
- break;
- }
- if(SAISNULL(¶m->req) &&
- memcmp(SAADDR(¶m->req),SAADDR(¶m->sinsr),SAADDRLEN(¶m->req))) {
- param->res = 470;
- break;
- }
- #if SOCKSTRACE > 0
- fprintf(stderr, "Sending incoming connection to client with code %d for %s with %hu\n",
- param->res,
- commands[command],
- *SAPORT(param->sins);
- );
- fflush(stderr);
- #endif
- if(ver == 5){
- 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]);
- }
- else {
- memcpy (buf+2, SAPORT(¶m->sinsr), 2);
- memcpy (buf+4, SAADDR(¶m->sinsr), 4);
- socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]);
- }
- param->res = mapsocket(param, conf.timeouts[CONNECTION_S]);
- break;
- case 3:
- param->sinsr = param->req;
- myfree(buf);
- if(!(buf = myalloc(LARGEBUFSIZE))) {RETURN(21);}
- sin = (heur == 1)?param->req:param->sincr;
- fds[2].events = fds[1].events = fds[0].events = 0;
- fds[0].fd = param->remsock;
- fds[1].fd = param->clisock;
- fds[2].fd = param->ctrlsock;
- for(;;){
- if(!fds[1].events || fds[1].revents){
- sasize = sizeof(sin);
- len = so._recvfrom(param->clisock, (char *)buf, 65535, 0, (struct sockaddr *)&sin, &sasize);
- if(len >= 0) {
- fds[1].events = fds[1].revents = 0;
- if(len < 10) continue;
- sasize = sizeof(sin);
- if(len <= 10) {
- param->res = 464;
- break;
- }
- if(SAADDRLEN(&sin) != SAADDRLEN(¶m->sincr) || memcmp(SAADDR(&sin), SAADDR(¶m->sincr), SAADDRLEN(&sin)) || (heur == 1 && *SAPORT(¶m->sincr)!=*SAPORT(&sin))){
- if(heur == 1){
- #if SOCKSTRACE > 0
- fprintf(stderr, "internal UDP packet ignored\n");
- fflush(stderr);
- #endif
- sin = param->req;
- continue;
- }
- param->res = 465;
- break;
- }
- if(buf[0] || buf[1] || buf[2]) {
- param->res = 466;
- break;
- }
- size = 4;
- switch(buf[3]) {
- case 4:
- size = 16;
- case 1:
- i = 4+size;
- memcpy(SAADDR(¶m->sinsr), buf+4, size);
- *SAFAMILY(¶m->sinsr) = (size == 4)?AF_INET:AF_INET6;
- 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+4, (struct sockaddr *) ¶m->sinsr)) RETURN(100);
- break;
- default:
- RETURN(997);
- }
- memcpy(SAPORT(¶m->sinsr), buf+i, 2);
- i+=2;
- sasize = sizeof(param->sinsr);
- if(len > (int)i){
- socksendto(param->remsock, (struct sockaddr *)¶m->sinsr, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000);
- param->statscli64+=(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
- }
- continue;
- }
- else if(len ==0 || (len <0 && errno != EINTR && errno != EAGAIN)){
- param->res = 464;
- break;
- }
- fds[1].events = POLLIN;
- }
- if (!fds[0].events || fds[0].revents) {
- sasize = sizeof(param->sinsr);
- buf[0]=buf[1]=buf[2]=0;
- buf[3]=(*SAFAMILY(¶m->sinsl) == AF_INET)?1:4;
- len = so._recvfrom(param->remsock, (char *)buf+6+SAADDRLEN(¶m->sinsl), 65535 - (6+SAADDRLEN(¶m->sinsl)), 0, (struct sockaddr *)¶m->sinsr, &sasize);
- if(len == 0 || (len < 0 && errno != EAGAIN && errno !=EINTR)) {
- param->res = 468;
- break;
- }
- else if(len > 0){
- fds[0].events = fds[0].revents = 0;
- param->statssrv64+=len;
- param->nreads++;
- if(!*SAPORT(&sin) || (heur == 2 && (*SAFAMILY(¶m->sinsr) != *SAFAMILY(¶m->req) || memcmp(SAADDR(¶m->sinsr),SAADDR(¶m->req), SAADDRLEN(¶m->req))))){
- #if SOCKSTRACE > 0
- fprintf(stderr, "external UDP packet ignored\n");
- fflush(stderr);
- #endif
- continue;
- }
- memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr));
- memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2);
- sasize = sizeof(sin);
- socksendto(param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(¶m->sinsr), conf.timeouts[SINGLEBYTE_L]*1000);
- #if SOCKSTRACE > 1
- fprintf(stderr, "UDP packet relayed to client from %hu size %d\n",
- ntohs(*SAPORT(¶m->sinsr)),
- len
- );
- fflush(stderr);
- #endif
- continue;
- }
- fds[0].events = POLLIN;
- }
-
- if (fds[2].revents) {
- param->res = 0;
- break;
- }
- fds[0].revents = fds[1].revents = fds[2].revents = 0;
- fds[2].events = POLLIN;
- res = so._poll(fds, 3, conf.timeouts[CONNECTION_L]*1000);
- if(res == 0 || (res < 0 && errno != EAGAIN && errno != EINTR)) {
- param->res = 463;
- break;
- }
- }
- 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_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)buf + strlen((char *)buf), 64);
- sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(*SAPORT(¶m->req)));
- dolog(param, buf);
- myfree(buf);
- }
- freeparam(param);
- return (NULL);
- }
- #ifdef WITHMAIN
- struct proxydef childdef = {
- sockschild,
- 1080,
- 0,
- S_SOCKS,
- "-N(EXTERNAL_IP) External NAT address to report to client for BIND\n"
- };
- #include "proxymain.c"
- #include "log.c"
- #endif
|