| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- /*
- 3APA3A simpliest proxy server
- (c) 2002-2021 by Vladimir Dubrovin <3proxy@3proxy.org>
- please read License Agreement
- */
- #include "proxy.h"
- char * copyright = COPYRIGHT;
- int randomizer = 1;
- #ifndef _WIN32
- pthread_attr_t pa;
- void daemonize(void){
- if(fork() > 0) {
- usleep(SLEEPTIME);
- _exit(0);
- }
- setsid();
- }
- #endif
- unsigned char **stringtable = NULL;
- #ifdef WITH_LINUX_FUTEX
- int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
- {
- return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
- }
- int mutex_lock(int *val)
- {
- int c;
- if ((c = __sync_val_compare_and_swap(val, 0, 1)) != 0)
- do {
- if(c == 2 || __sync_val_compare_and_swap(val, 1, 2) != 0)
- sys_futex(val, FUTEX_WAIT_PRIVATE, 2, NULL, NULL, 0);
- } while ((c = __sync_val_compare_and_swap(val, 0, 2)) != 0);
-
- return 0;
- }
- int mutex_unlock(int *val)
- {
- if(__sync_fetch_and_sub (val, 1) != 1){
- *val = 0;
- sys_futex(val, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
- }
-
-
- return 0;
- }
- #endif
- int myinet_ntop(int af, void *src, char *dst, socklen_t size){
- #ifndef NOIPV6
- if(af != AF_INET6){
- #endif
- unsigned u = ntohl(((struct in_addr *)src)->s_addr);
- return sprintf(dst, "%u.%u.%u.%u",
- ((u&0xFF000000)>>24),
- ((u&0x00FF0000)>>16),
- ((u&0x0000FF00)>>8),
- ((u&0x000000FF)));
- #ifndef NOIPV6
- }
- *dst = 0;
- inet_ntop(af, src, dst, size);
- return (int)strlen(dst);
- #endif
- }
- char *rotations[] = {
- "",
- "/min",
- "/hour",
- "/day",
- "/week",
- "/month",
- "/year",
- "",
- };
- struct extparam conf = {
- {1, 5, 30, 60, 180, 1800, 15, 60, 15, 5, 0, 0},
- NULL,
- NULL,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- 0,
- 0, -1, 0, 0, 0, 0,
- 0, 500, 0, 0, 0, 0, 0, 2,
- 6, 600,
- 1048576,
- NULL, NULL,
- NONE, NONE,
- NULL,
- #ifndef NOIPV6
- {AF_INET},{AF_INET6},{AF_INET},
- #else
- {AF_INET},{AF_INET},
- #endif
- NULL,
- NULL,
- doconnect,
- lognone,
- NULL,
- NULL,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- (time_t)0, (time_t)0,
- 0,0,
- '@',
- };
- int numservers=0;
- char* NULLADDR="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
- int myrand(void * entropy, int len){
- int i;
- uint16_t init;
- init = randomizer;
- for(i=0; i < len/2; i++){
- init ^= ((uint16_t *)entropy)[i];
- }
- srand(rand()+init);
- randomizer = rand();
- return rand();
-
- }
- #ifndef WITH_POLL
- #ifndef WITH_WSAPOLL
- int
- #ifdef _WIN32
- WINAPI
- #endif
- mypoll(struct mypollfd *fds, unsigned int nfds, int timeout){
- fd_set readfd;
- fd_set writefd;
- fd_set oobfd;
- struct timeval tv;
- unsigned i;
- int num;
- SOCKET maxfd = 0;
- tv.tv_sec = timeout/1000;
- tv.tv_usec = (timeout%1000)*1000;
- FD_ZERO(&readfd);
- FD_ZERO(&writefd);
- FD_ZERO(&oobfd);
- for(i=0; i<nfds; i++){
- if((fds[i].events&POLLIN))FD_SET(fds[i].fd, &readfd);
- if((fds[i].events&POLLOUT))FD_SET(fds[i].fd, &writefd);
- if((fds[i].events&POLLPRI))FD_SET(fds[i].fd, &oobfd);
- fds[i].revents = 0;
- if(fds[i].fd > maxfd) maxfd = fds[i].fd;
- }
- if((num = select(((int)(maxfd))+1, &readfd, &writefd, &oobfd, &tv)) < 1) return num;
- for(i=0; i<nfds; i++){
- if(FD_ISSET(fds[i].fd, &readfd)) fds[i].revents |= POLLIN;
- if(FD_ISSET(fds[i].fd, &writefd)) fds[i].revents |= POLLOUT;
- if(FD_ISSET(fds[i].fd, &oobfd)) fds[i].revents |= POLLPRI;
- }
- return num;
- }
- #endif
- #endif
- struct sockfuncs so = {
- socket,
- accept,
- bind,
- listen,
- connect,
- getpeername,
- getsockname,
- getsockopt,
- setsockopt,
- #ifndef WITH_POLL
- #ifndef WITH_WSAPOLL
- mypoll,
- #else
- WSAPoll,
- #endif
- #else
- poll,
- #endif
- (void *)send,
- (void *)sendto,
- (void *)recv,
- (void *)recvfrom,
- shutdown,
- #ifdef _WIN32
- closesocket
- #else
- close
- #endif
- };
- #ifdef _WINCE
- static char cebuf[1024];
- static char ceargbuf[256];
- char * ceargv[32];
- char * CEToUnicode (const char *str){
- int i;
- for(i=0; i<510 && str[i]; i++){
- cebuf[(i*2)] = str[i];
- cebuf[(i*2)+1] = 0;
- }
- cebuf[(i*2)] = 0;
- cebuf[(i*2)+1] = 0;
- return cebuf;
- };
- int cesystem(const char *str){
- STARTUPINFO startupInfo = {0};
- startupInfo.cb = sizeof(startupInfo);
- PROCESS_INFORMATION processInformation;
- return CreateProcessW((LPWSTR)CEToUnicode(str), NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startupInfo, &processInformation);
- }
- int ceparseargs(const char *str){
- int argc = 0, i;
- int space = 1;
- for(i=0; i<250 && argc<30 && str[2*i]; i++){
- ceargbuf[i] = str[2*i];
- if(space && ceargbuf[i]!=' '&& ceargbuf[i]!='\t'&& ceargbuf[i]!='\r'&& ceargbuf[i]!='\n'){
- ceargv[argc++] = ceargbuf + i;
- space = 0;
- }
- else if(!space && (ceargbuf[i]==' ' || ceargbuf[i]=='\t' || ceargbuf[i]=='\r' || ceargbuf[i]=='\n')){
- ceargbuf[i] = 0;
- space = 1;
- }
- }
- return argc;
- }
- #endif
- int parsehost(int family, unsigned char *host, struct sockaddr *sa){
- char *sp=NULL,*se=NULL;
- unsigned short port=0;
- int ret = 0;
- if(!host) return 2;
- if(*host == '[') se=strchr((char *)host, ']');
- if ( (sp = strchr(se?se:(char *)host, ':')) && !strchr(sp+1, ':')) *sp = 0;
- if(se){
- *se = 0;
- }
- if(sp){
- port = atoi(sp+1);
- }
- ret = !getip46(family, host + (se!=0), (struct sockaddr *)sa);
- if(se) *se = ']';
- if(sp) *sp = ':';
- if(port)*SAPORT(sa) = htons(port);
- return ret;
- }
- int parsehostname(char *hostname, struct clientparam *param, unsigned short port){
- char *sp=NULL,*se=NULL;
- int ret = 0;
- if(!hostname || !*hostname)return 2;
- if(*hostname == '[') se=strchr(hostname, ']');
- if ((sp = strchr(se?se:hostname, ':'))) {
- if(strchr(sp+1, ':'))sp = NULL;
- else *sp = 0;
- }
- if(se){
- *se = 0;
- }
- if(hostname != (char *)param->hostname){
- if(param->hostname) myfree(param->hostname);
- param->hostname = (unsigned char *)mystrdup(hostname + (se!=0));
- }
- if(sp){
- port = atoi(sp+1);
- }
- ret = !getip46(param->srv->family, param->hostname, (struct sockaddr *)¶m->req);
- if(se) *se = ']';
- if(sp) *sp = ':';
- *SAPORT(¶m->req) = htons(port);
- memset(¶m->sinsr, 0, sizeof(param->sinsr));
- return ret;
- }
- int parseusername(char *username, struct clientparam *param, int extpasswd){
- char *sb = NULL, *se = NULL, *sp = NULL;
- if(!username || !*username) return 1;
- if(param->srv->needuser && (sb = strchr(username, ':')) && (se = strchr(sb + 1, ':')) && (!extpasswd || (sp = strchr(se + 1, ':')))){
- *sb = 0;
- *se = 0;
- if(sp) *sp = 0;
- if(*(sb+1)) {
- if(param->password) myfree(param->password);
- param->password = (unsigned char *)mystrdup(sb+1);
- }
- if(*username) {
- if(param->username) myfree(param->username);
- param->username = (unsigned char *)mystrdup(username);
- }
- username = se+1;
- }
- if(extpasswd){
- if(!sp) sp = strchr(username, ':');
- if(sp){
- *sp = 0;
- if(param->extpassword) myfree(param->extpassword);
- param->extpassword = (unsigned char *) mystrdup(sp+1);
- }
- }
- if(param->extusername) myfree(param->extusername);
- param->extusername = (unsigned char *)mystrdup(username);
- if(sb) *sb = ':';
- if(se) *se = ':';
- if(sp) *sp = ':';
- return 0;
- }
- int parseconnusername(char *username, struct clientparam *param, int extpasswd, unsigned short port){
- char *sb, *se;
- if(!username || !*username) return 1;
- if ((sb=strchr(username, conf.delimchar)) == NULL){
- if(!param->hostname && param->remsock == INVALID_SOCKET) return 2;
- if(param->hostname)parsehostname((char *)param->hostname, param, port);
- return parseusername(username, param, extpasswd);
- }
- while ((se=strchr(sb+1, conf.delimchar)))sb=se;
- *(sb) = 0;
- if(parseusername(username, param, extpasswd)) return 3;
- *(sb) = conf.delimchar;
- if(parsehostname(sb+1, param, port)) return 4;
- return 0;
- }
- int connectwithpoll(SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to){
- struct pollfd fds[1];
- #ifdef _WIN32
- unsigned long ul = 1;
- ioctlsocket(sock, FIONBIO, &ul);
- #else
- fcntl(sock,F_SETFL, O_NONBLOCK | fcntl(sock,F_GETFL));
- #endif
- if(so._connect(sock,sa,size)) {
- if(errno != EAGAIN && errno != EINPROGRESS) return (13);
- }
- memset(fds, 0, sizeof(fds));
- fds[0].fd = sock;
- fds[0].events = POLLOUT;
- if(so._poll(fds, 1, to*1000) <= 0) {
- return (13);
- }
- return 0;
- }
- int doconnect(struct clientparam * param){
- SASIZETYPE size;
- if (*SAFAMILY(¶m->sincl) == *SAFAMILY(¶m->req) && !memcmp(SAADDR(¶m->sincl), SAADDR(¶m->req), SAADDRLEN(¶m->req)) &&
- *SAPORT(¶m->sincl) == *SAPORT(¶m->req)) return 519;
- if (param->operation == ADMIN || param->operation == DNSRESOLVE || param->operation == BIND || param->operation == UDPASSOC)
- return 0;
- if (param->remsock != INVALID_SOCKET){
- size = sizeof(param->sinsr);
- if(so._getpeername(param->remsock, (struct sockaddr *)¶m->sinsr, &size)==-1) {return (14);}
- }
- else {
- struct linger lg = {1,conf.timeouts[SINGLEBYTE_S]};
- if(SAISNULL(¶m->sinsr)){
- if(SAISNULL(¶m->req)) {
- return 100;
- }
- *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req);
- memcpy(SAADDR(¶m->sinsr), SAADDR(¶m->req), SAADDRLEN(¶m->req));
- }
- if(!*SAPORT(¶m->sinsr))*SAPORT(¶m->sinsr) = *SAPORT(¶m->req);
- if ((param->remsock=so._socket(SASOCK(¶m->sinsr), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {return (11);}
- setopts(param->remsock, param->srv->srvsockopts);
- so._setsockopt(param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
- #ifdef REUSE
- {
- int opt;
- #ifdef SO_REUSEADDR
- opt = 1;
- so._setsockopt(param->remsock, SOL_SOCKET, SO_REUSEADDR, (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
- #ifdef SO_BINDTODEVICE
- if(param->srv->obindtodevice) {
- if(so._setsockopt(param->remsock, SOL_SOCKET, SO_BINDTODEVICE, param->srv->obindtodevice, strlen(param->srv->obindtodevice) + 1))
- return 12;
- }
- #endif
- if(SAISNULL(¶m->sinsl)){
- #ifndef NOIPV6
- if(*SAFAMILY(¶m->sinsr) == AF_INET6) param->sinsl = param->srv->extsa6;
- else
- #endif
- param->sinsl = param->srv->extsa;
- }
- *SAPORT(¶m->sinsl) = 0;
- if(so._bind(param->remsock, (struct sockaddr*)¶m->sinsl, SASIZE(¶m->sinsl))==-1) {
- return 12;
- }
-
- if(param->operation >= 256 || (param->operation & CONNECT)){
- if(connectwithpoll(param->remsock,(struct sockaddr *)¶m->sinsr,SASIZE(¶m->sinsr),CONNECT_TO)) {
- return 13;
- }
- }
- size = sizeof(param->sinsl);
- if(so._getsockname(param->remsock, (struct sockaddr *)¶m->sinsl, &size)==-1) {return (15);}
- }
- return 0;
- }
- int scanaddr(const unsigned char *s, unsigned long * ip, unsigned long * mask) {
- unsigned d1, d2, d3, d4, m;
- int res;
- if ((res = sscanf((char *)s, "%u.%u.%u.%u/%u", &d1, &d2, &d3, &d4, &m)) < 4) return 0;
- if(mask && res == 4) *mask = 0xFFFFFFFF;
- else if (mask) *mask = htonl(0xFFFFFFFF << (32 - m));
- *ip = htonl ((d1<<24) ^ (d2<<16) ^ (d3<<8) ^ d4);
- return res;
- }
- RESOLVFUNC resolvfunc = NULL;
- #ifndef _WIN32
- pthread_mutex_t gethostbyname_mutex;
- int ghbn_init = 0;
- #endif
- #ifdef GETHOSTBYNAME_R
- struct hostent * my_gethostbyname(char *name, char *buf, struct hostent *hp){
- struct hostent *result;
- int gherrno;
- #ifdef _SOLARIS
- return gethostbyname_r(name, hp, buf, 1024, &gherrno);
- #else
- if(gethostbyname_r(name, hp, buf, 1024, &result, &gherrno) != 0)
- return NULL;
- return result;
- #endif
- }
- #endif
- #ifdef NOIPV6
- unsigned long getip(unsigned char *name){
- unsigned long retval;
- int i;
- int ndots = 0;
- struct hostent *hp=NULL;
- RESOLVFUNC tmpresolv;
- #ifdef GETHOSTBYNAME_R
- struct hostent he;
- char ghbuf[1024];
- #define gethostbyname(NAME) my_gethostbyname(NAME, ghbuf, &he)
- #endif
- if(strlen((char *)name)>255)name[255] = 0;
- for(i=0; name[i]; i++){
- if(name[i] == '.'){
- if(++ndots > 3) break;
- continue;
- }
- if(name[i] <'0' || name[i] >'9') break;
- }
- if(!name[i] && ndots == 3){
- if(scanaddr(name, &retval, NULL) == 4){
- return retval;
- }
- }
- if((tmpresolv=resolvfunc)){
- if((*tmpresolv)(AF_INET, name, (unsigned char *)&retval)) return retval;
- if(conf.demanddialprog) system(conf.demanddialprog);
- return (*tmpresolv)(AF_INET, name, (unsigned char *)&retval)?retval:0;
- }
- #if !defined(_WIN32) && !defined(GETHOSTBYNAME_R)
- if(!ghbn_init){
- pthread_mutex_init(&gethostbyname_mutex, NULL);
- ghbn_init++;
- }
- pthread_mutex_lock(&gethostbyname_mutex);
- #endif
- hp=gethostbyname((char *)name);
- if (!hp && conf.demanddialprog) {
- system(conf.demanddialprog);
- hp=gethostbyname((char *)name);
- }
- retval = hp?*(unsigned long *)hp->h_addr:0;
- #if !defined(_WIN32) && !defined(GETHOSTBYNAME_R)
- pthread_mutex_unlock(&gethostbyname_mutex);
- #endif
- #ifdef GETHOSTBYNAME_R
- #undef gethostbyname
- #endif
- return retval;
- }
- #endif
- int afdetect(unsigned char *name){
- int ndots=0, ncols=0, nhex=0;
- int i;
- for(i=0; name[i]; i++){
- if(name[i] == '.'){
- if(++ndots > 3) {
- return -1;
- }
- }
- else if(name[i] == ':'){
- if(++ncols > 7) {
- return -1;
- }
- }
- else if(name[i] == '%' || (name[i] >= 'a' && name[i] <= 'f') || (name[i] >= 'A' && name[i] <= 'F')){
- nhex++;
- }
- else if(name[i] <'0' || name[i] >'9') {
- return -1;
- }
- }
- if(ndots == 3 && ncols == 0 && nhex == 0){
- return AF_INET;
- }
- if(ncols >= 2) {
- return AF_INET6;
- }
- return -1;
- }
- unsigned long getip46(int family, unsigned char *name, struct sockaddr *sa){
- #ifndef NOIPV6
- int detect;
- struct addrinfo *ai, hint;
- RESOLVFUNC tmpresolv;
- if(!sa) return 0;
- if(!family) {
- family = 4;
- #else
- ((struct sockaddr_in *)sa)->sin_family = AF_INET;
- return (((struct sockaddr_in *)sa)->sin_addr.s_addr = getip(name))? AF_INET:0;
- #endif
- #ifndef NOIPV6
- }
- detect = afdetect(name);
- if(detect != -1){
- if(family == 4 && detect != AF_INET) return 0;
- *SAFAMILY(sa) = (family == 6)? AF_INET6 : detect;
- return inet_pton(*SAFAMILY(sa), (char *)name, SAADDR(sa))? *SAFAMILY(sa) : 0;
- }
- if((tmpresolv = resolvfunc)){
- int f = (family == 6 || family == 64)?AF_INET6:AF_INET;
- *SAFAMILY(sa) = f;
- if(tmpresolv(f, name, SAADDR(sa))) return f;
- if(family == 4 || family == 6) return 0;
- f = (family == 46)? AF_INET6 : AF_INET;
- *SAFAMILY(sa) = f;
- if(tmpresolv(f, name, SAADDR(sa))) return f;
- return 0;
- }
- memset(&hint, 0, sizeof(hint));
- hint.ai_family = (family == 6 || family == 64)?AF_INET6:AF_INET;
- if (getaddrinfo((char *)name, NULL, &hint, &ai)) {
- if(family == 64 || family == 46){
- hint.ai_family = (family == 64)?AF_INET:AF_INET6;
- if (getaddrinfo((char *)name, NULL, &hint, &ai)) return 0;
- }
- else return 0;
- }
- if(ai){
- if(ai->ai_addr->sa_family == AF_INET || ai->ai_addr->sa_family == AF_INET6){
- *SAFAMILY(sa)=ai->ai_addr->sa_family;
- memcpy(SAADDR(sa), SAADDR(ai->ai_addr), SAADDRLEN(ai->ai_addr));
- freeaddrinfo(ai);
- return *SAFAMILY(sa);
- }
- freeaddrinfo(ai);
- }
- return 0;
- #endif
- }
|