diff --git a/CMakeLists.txt b/CMakeLists.txt index a12fa6e..16901a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,6 +283,9 @@ set(3PROXY_CORE_SOURCES src/3proxy.c src/auth.c src/authradius.c + src/hash.c + src/resolve.c + src/sql.c src/conf.c src/datatypes.c src/plugins.c diff --git a/src/Makefile.inc b/src/Makefile.inc index 922b20a..099e7b6 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -119,6 +119,9 @@ srvdnspr$(OBJSUFFICS): dnspr.c proxy.h structures.h auth$(OBJSUFFICS): auth.c proxy.h structures.h $(CC) $(COUT)auth$(OBJSUFFICS) $(CFLAGS) auth.c +hash$(OBJSUFFICS): hash.c proxy.h structures.h + $(CC) $(COUT)hash$(OBJSUFFICS) $(CFLAGS) hash.c + authradius$(OBJSUFFICS): authradius.c proxy.h structures.h $(CC) $(COUT)authradius$(OBJSUFFICS) $(CFLAGS) authradius.c @@ -150,6 +153,6 @@ md5$(OBJSUFFICS): libs/md5.h libs/md5.c stringtable$(OBJSUFFICS): stringtable.c $(CC) $(COUT)stringtable$(OBJSUFFICS) $(CFLAGS) stringtable.c -$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) mycrypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(VERSIONDEP) - $(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) mycrypt$(OBJSUFFICS) md5$(OBJSUFFICS) md4$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) +$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) mycrypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(VERSIONDEP) + $(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) mycrypt$(OBJSUFFICS) md5$(OBJSUFFICS) md4$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) diff --git a/src/auth.c b/src/auth.c index 387119e..6e09253 100644 --- a/src/auth.c +++ b/src/auth.c @@ -1035,516 +1035,3 @@ struct auth authfuncs[] = { {NULL, NULL, NULL, ""} }; - - -struct hashtable dns_table = {0, 4, {0,0,0,0}, NULL, NULL, NULL}; -struct hashtable dns6_table = {0, 16, {0,0,0,0}, NULL, NULL, NULL}; - - -void nametohash(const unsigned char * name, unsigned char *hash, unsigned char *rnd){ - unsigned i, j, k; - memcpy(hash, rnd, sizeof(unsigned)*4); - for(i=0, j=0, k=0; name[j]; j++){ - hash[i] += (toupper(name[j]) - 32)+rnd[((toupper(name[j]))*29277+rnd[(k+j+i)%16]+k+j+i)%16]; - if(++i == sizeof(unsigned)*4) { - i = 0; - k++; - } - } -} - -unsigned hashindex(struct hashtable *ht, const unsigned char* hash){ - unsigned t1, t2, t3, t4; - t1 = *(unsigned *)hash; - t2 = *(unsigned *)(hash + sizeof(unsigned)); - t3 = *(unsigned *)(hash + (2*sizeof(unsigned))); - t4 = *(unsigned *)(hash + (3*sizeof(unsigned))); - return (t1 + (t2 * 7) + (t3 * 17) + (t4 * 29) ) % (ht->hashsize >> 2); -} - - -void destroyhashtable(struct hashtable *ht){ - pthread_mutex_lock(&hash_mutex); - if(ht->hashtable){ - myfree(ht->hashtable); - ht->hashtable = NULL; - } - if(ht->hashvalues){ - myfree(ht->hashvalues); - ht->hashvalues = NULL; - } - ht->hashsize = 0; - pthread_mutex_unlock(&hash_mutex); -} - -#define hvalue(I) ((struct hashentry *)((char *)ht->hashvalues + (I)*(sizeof(struct hashentry) + ht->recsize - 4))) -int inithashtable(struct hashtable *ht, unsigned nhashsize){ - unsigned i; - clock_t c; - - -#ifdef _WIN32 - struct timeb tb; - - ftime(&tb); - -#else - struct timeval tb; - struct timezone tz; - gettimeofday(&tb, &tz); -#endif - c = clock(); - - if(nhashsize<4) return 1; - pthread_mutex_lock(&hash_mutex); - if(ht->hashtable){ - myfree(ht->hashtable); - ht->hashtable = NULL; - } - if(ht->hashvalues){ - myfree(ht->hashvalues); - ht->hashvalues = NULL; - } - ht->hashsize = 0; - if(!(ht->hashtable = myalloc((nhashsize>>2) * sizeof(struct hashentry *)))){ - pthread_mutex_unlock(&hash_mutex); - return 2; - } - if(!(ht->hashvalues = myalloc(nhashsize * (sizeof(struct hashentry) + (ht->recsize-4))))){ - myfree(ht->hashtable); - ht->hashtable = NULL; - pthread_mutex_unlock(&hash_mutex); - return 3; - } - ht->hashsize = nhashsize; - ht->rnd[0] = myrand(&tb, sizeof(tb)); - ht->rnd[1] = myrand(ht->hashtable, sizeof(ht->hashtable)); - ht->rnd[2] = myrand(&c, sizeof(c)); - ht->rnd[3] = myrand(ht->hashvalues,sizeof(ht->hashvalues)); - memset(ht->hashtable, 0, (ht->hashsize>>2) * sizeof(struct hashentry *)); - memset(ht->hashvalues, 0, ht->hashsize * (sizeof(struct hashentry) + ht->recsize -4)); - - for(i = 0; i< (ht->hashsize - 1); i++) { - hvalue(i)->next = hvalue(i+1); - } - ht->hashempty = ht->hashvalues; - pthread_mutex_unlock(&hash_mutex); - return 0; -} - -void hashadd(struct hashtable *ht, const unsigned char* name, unsigned char* value, time_t expires){ - struct hashentry * hen, *he; - struct hashentry ** hep; - - unsigned index; - - pthread_mutex_lock(&hash_mutex); - if(!ht||!value||!name||!ht->hashtable||!ht->hashempty) { - pthread_mutex_unlock(&hash_mutex); - return; - } - hen = ht->hashempty; - ht->hashempty = ht->hashempty->next; - nametohash(name, hen->hash, (unsigned char *)ht->rnd); - memcpy(hen->value, value, ht->recsize); - hen->expires = expires; - hen->next = NULL; - index = hashindex(ht, hen->hash); - - for(hep = ht->hashtable + index; (he = *hep)!=NULL; ){ - if(he->expires < conf.time || !memcmp(hen->hash, he->hash, sizeof(he->hash))) { - (*hep) = he->next; - he->expires = 0; - he->next = ht->hashempty; - ht->hashempty = he; - } - else hep=&(he->next); - } - hen->next = ht->hashtable[index]; - ht->hashtable[index] = hen; - pthread_mutex_unlock(&hash_mutex); -} - -uint32_t hashresolv(struct hashtable *ht, const unsigned char* name, unsigned char* value, uint32_t *ttl){ - unsigned char hash[sizeof(unsigned)*4]; - struct hashentry ** hep; - struct hashentry *he; - unsigned index; - - pthread_mutex_lock(&hash_mutex); - if(!ht || !ht->hashtable || !name) { - pthread_mutex_unlock(&hash_mutex); - return 0; - } - nametohash(name, hash, (unsigned char *)ht->rnd); - index = hashindex(ht, hash); - for(hep = ht->hashtable + index; (he = *hep)!=NULL; ){ - if(he->expires < conf.time) { - (*hep) = he->next; - he->expires = 0; - he->next = ht->hashempty; - ht->hashempty = he; - } - else if(!memcmp(hash, he->hash, sizeof(unsigned)*4)){ - if(ttl) *ttl = (uint32_t)(he->expires - conf.time); - memcpy(value, he->value, ht->recsize); - pthread_mutex_unlock(&hash_mutex); - return 1; - } - else hep=&(he->next); - } - pthread_mutex_unlock(&hash_mutex); - return 0; -} - -struct nserver nservers[MAXNSERVERS] = {{{0},0}, {{0},0}, {{0},0}, {{0},0}, {{0},0}}; -struct nserver authnserver; - - -uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_t *retttl, struct clientparam* param, int makeauth){ - - int i,n; - uint32_t retval; - - if((af == AF_INET) && (retval = hashresolv(&dns_table, name, value, retttl))) { - return retval; - } - if((af == AF_INET6) && (retval = hashresolv(&dns6_table, name, value, retttl))) { - return retval; - } - n = (makeauth && !SAISNULL(&authnserver.addr))? 1 : numservers; - for(i=0; isinsl : &addr; - sinsr = (param && !makeauth)? ¶m->sinsr : &addr; - memset(sinsl, 0, sizeof(addr)); - memset(sinsr, 0, sizeof(addr)); - - - if(makeauth && !SAISNULL(&authnserver.addr)){ - usetcp = authnserver.usetcp; - *SAFAMILY(sinsl) = *SAFAMILY(&authnserver.addr); - } - else { - usetcp = nservers[i].usetcp; - *SAFAMILY(sinsl) = *SAFAMILY(&nservers[i].addr); - } - if((sock=so._socket(so.state, SASOCK(sinsl), usetcp?SOCK_STREAM:SOCK_DGRAM, usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) break; - if(so._bind(so.state, sock,(struct sockaddr *)sinsl,SASIZE(sinsl))){ - so._shutdown(so.state, sock, SHUT_RDWR); - so._closesocket(so.state, sock); - break; - } - if(makeauth && !SAISNULL(&authnserver.addr)){ - *sinsr = authnserver.addr; - } - else { - *sinsr = nservers[i].addr; - } - if(usetcp){ - if(connectwithpoll(NULL, sock,(struct sockaddr *)sinsr,SASIZE(sinsr),conf.timeouts[CONNECT_TO])) { - so._shutdown(so.state, sock, SHUT_RDWR); - so._closesocket(so.state, sock); - break; - } -#ifdef TCP_NODELAY - { - int opt = 1; - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)); - } -#endif - } - len = (int)strlen((char *)name); - - serial = myrand(name,len); - *(unsigned short*)buf = serial; /* query id */ - buf[2] = 1; /* recursive */ - buf[3] = 0; - buf[4] = 0; - buf[5] = 1; /* 1 request */ - buf[6] = buf[7] = 0; /* no replies */ - buf[8] = buf[9] = 0; /* no ns count */ - buf[10] = buf[11] = 0; /* no additional */ - if(len > 255) { - len = 255; - } - memcpy(buf + 13, name, len); - len += 13; - buf[len] = 0; - for(s2 = buf + 12; (s1 = (unsigned char *)strchr((char *)s2 + 1, '.')); s2 = s1)*s2 = (unsigned char)((s1 - s2) - 1); - *s2 = (len - (int)(s2 - buf)) - 1; - len++; - buf[len++] = 0; - buf[len++] = (makeauth == 1)? 0x0c : (af==AF_INET6? 0x1c:0x01); /* PTR:host address */ - buf[len++] = 0; - buf[len++] = 1; /* INET */ - if(usetcp){ - buf-=2; - *(unsigned short*)buf = htons(len); - len+=2; - } - - if(socksendto(NULL, sock, (struct sockaddr *)sinsr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){ - so._shutdown(so.state, sock, SHUT_RDWR); - so._closesocket(so.state, sock); - continue; - } - if(param) param->statscli64 += len; - len = sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf, 4096, conf.timeouts[DNS_TO]*1000); - so._shutdown(so.state, sock, SHUT_RDWR); - so._closesocket(so.state, sock); - if(len <= 13) { - continue; - } - if(param) param->statssrv64 += len; - if(usetcp){ - unsigned short us; - us = ntohs(*(unsigned short*)buf); - len-=2; - buf+=2; - if(us > 4096 || us < len || (us > len && sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf+len, us-len, conf.timeouts[DNS_TO]*1000) != us-len)) { - continue; - } - } - if(*(unsigned short *)buf != serial)continue; - if((na = buf[7] + (((unsigned short)buf[6])<<8)) < 1) { - return 0; - } - nq = buf[5] + (((unsigned short)buf[4])<<8); - if (nq != 1) { - continue; /* we did only 1 request */ - } - for(k = 13; k= len) { - continue; - } - k += 4; - if(na > 255) na = 255; /* somebody is very evil */ - for (j = 0; j < na; j++) { /* now there should be answers */ - while(buf[k] < 192 && buf[k] !=0 && (k+buf[k]+14) < len) k+= (buf[k] + 1); - if(!buf[k]) k--; - if((k+(af == AF_INET6?28:16)) > len) { - break; - } - flen = buf[k+11] + (((unsigned short)buf[k+10])<<8); - if((k+12+flen) > len) { - break; - } - if(makeauth != 1){ - if(buf[k+2] != 0 || buf[k+3] != (af == AF_INET6?0x1c:0x1) || flen != (af == AF_INET6?16:4)) { - k+= (12 + flen); - continue; /* we need A IPv4 */ - } - ttl = ntohl(*(uint32_t *)(buf + k + 6)); - memcpy(value, buf + k + 12, af == AF_INET6? 16:4); - if(ttl < 0 || ttl > (3600*12)) ttl = 3600*12; - if(!ttl) ttl = 1; - hashadd(af == AF_INET6?&dns6_table:&dns_table, name, value, conf.time+ttl); - if(retttl) *retttl = ttl; - return 1; - } - else { - - if(buf[k+2] != 0 || buf[k+3] != 0x0c) { - k+= (12 + flen); - continue; /* we need A PTR */ - } - for (s2 = buf + k + 12; s2 < (buf + k + 12 + len) && *s2; ){ - s1 = s2 + ((unsigned)*s2) + 1; - *s2 = '.'; - s2 = s1; - } - *s2 = 0; - if(param->username)myfree(param->username); - param->username = (unsigned char *)mystrdup ((char *)buf + k + 13); - - return udpresolve(af,param->username, value, NULL, NULL, 2); - } - } - } - return 0; -} - -uint32_t myresolver(int af, unsigned char * name, unsigned char * value){ - return udpresolve(af, name, value, NULL, NULL, 0); -} - -uint32_t fakeresolver (int af, unsigned char *name, unsigned char * value){ - memset(value, 0, af == AF_INET6? 16 : 4); - if(af == AF_INET6){ - memset(value, 0, 16); - value[15] = 2; - } - else { - value[0] = 127; - value[1] = 0; - value[2] = 0; - value[3] = 2; - } - return 1; -} - -#ifndef NOODBC - -SQLHENV henv = NULL; -SQLHSTMT hstmt = NULL; -SQLHDBC hdbc = NULL; -char * sqlstring = NULL; - - -void close_sql(){ - if(hstmt) { - SQLFreeHandle(SQL_HANDLE_STMT, hstmt); - hstmt = NULL; - } - if(hdbc){ - SQLDisconnect(hdbc); - SQLFreeHandle(SQL_HANDLE_DBC, hdbc); - hdbc = NULL; - } - if(henv) { - SQLFreeHandle(SQL_HANDLE_ENV, henv); - henv = NULL; - } -} - -int attempt = 0; -time_t attempt_time = 0; - -int init_sql(char * s){ - SQLRETURN retcode; - char * datasource; - char * username; - char * password; - char * string; - - if(!s) return 0; - if(!sqlstring || strcmp(sqlstring, s)){ - string = sqlstring; - sqlstring=mystrdup(s); - if(string)myfree(string); - } - - if(hstmt || hdbc || henv) close_sql(); - attempt++; - attempt_time = time(0); - if(!henv){ - retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); - if (!henv || (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)){ - henv = NULL; - return 0; - } - retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); - - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { - return 0; - } - } - if(!hdbc){ - retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); - if (!hdbc || (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)) { - hdbc = NULL; - SQLFreeHandle(SQL_HANDLE_ENV, henv); - henv = NULL; - return 0; - } - SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (void*)15, 0); - } - string = mystrdup(sqlstring); - if(!string) return 0; - datasource = strtok(string, ","); - username = strtok(NULL, ","); - password = strtok(NULL, ","); - - - /* Connect to data source */ - retcode = SQLConnect(hdbc, (SQLCHAR*) datasource, (SQLSMALLINT)strlen(datasource), - (SQLCHAR*) username, (SQLSMALLINT)((username)?strlen(username):0), - (SQLCHAR*) password, (SQLSMALLINT)((password)?strlen(password):0)); - - myfree(string); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO){ - SQLFreeHandle(SQL_HANDLE_DBC, hdbc); - hdbc = NULL; - SQLFreeHandle(SQL_HANDLE_ENV, henv); - henv = NULL; - return 0; - } - retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO){ - close_sql(); - return 0; - } - return 1; -} - -void sqlerr (char *buf){ - if(conf.stdlog){ - fprintf(conf.stdlog, "%s\n", buf); - fflush(conf.stdlog); - } - pthread_mutex_unlock(&log_mutex); -} - -unsigned char statbuf[8192]; - -void logsql(struct clientparam * param, const unsigned char *s) { - SQLRETURN ret; - int len; - - - if(param->nolog) return; - pthread_mutex_lock(&log_mutex); - len = dobuf(param, statbuf, s, (unsigned char *)"\'"); - - if(attempt > 5){ - time_t t; - - t = time(0); - if (t - attempt_time < 180){ - sqlerr((char *)statbuf); - return; - } - } - if(!hstmt){ - if(!init_sql(sqlstring)) { - sqlerr((char *)statbuf); - return; - } - } - if(hstmt){ - ret = SQLExecDirect(hstmt, (SQLCHAR *)statbuf, (SQLINTEGER)len); - if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO){ - close_sql(); - if(!init_sql(sqlstring)){ - sqlerr((char *)statbuf); - return; - } - if(hstmt) { - ret = SQLExecDirect(hstmt, (SQLCHAR *)statbuf, (SQLINTEGER)len); - if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO){ - sqlerr((char *)statbuf); - return; - } - attempt = 0; - } - } - attempt = 0; - } - pthread_mutex_unlock(&log_mutex); -} - -#endif diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..f902ab6 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,146 @@ +#include "proxy.h" + + +unsigned hashindex(struct hashtable *ht, const unsigned char* hash){ + unsigned t1, t2, t3, t4; + t1 = *(unsigned *)hash; + t2 = *(unsigned *)(hash + sizeof(unsigned)); + t3 = *(unsigned *)(hash + (2*sizeof(unsigned))); + t4 = *(unsigned *)(hash + (3*sizeof(unsigned))); + return (t1 + (t2 * 7) + (t3 * 17) + (t4 * 29) ) % (ht->hashsize >> 2); +} + + +void destroyhashtable(struct hashtable *ht){ + pthread_mutex_lock(&hash_mutex); + if(ht->hashtable){ + myfree(ht->hashtable); + ht->hashtable = NULL; + } + if(ht->hashvalues){ + myfree(ht->hashvalues); + ht->hashvalues = NULL; + } + ht->hashsize = 0; + pthread_mutex_unlock(&hash_mutex); +} + +#define hvalue(I) ((struct hashentry *)((char *)ht->hashvalues + (I)*(sizeof(struct hashentry) + ht->recsize - 4))) +int inithashtable(struct hashtable *ht, unsigned nhashsize){ + unsigned i; + clock_t c; + + +#ifdef _WIN32 + struct timeb tb; + + ftime(&tb); + +#else + struct timeval tb; + struct timezone tz; + gettimeofday(&tb, &tz); +#endif + c = clock(); + + if(nhashsize<4) return 1; + pthread_mutex_lock(&hash_mutex); + if(ht->hashtable){ + myfree(ht->hashtable); + ht->hashtable = NULL; + } + if(ht->hashvalues){ + myfree(ht->hashvalues); + ht->hashvalues = NULL; + } + ht->hashsize = 0; + if(!(ht->hashtable = myalloc((nhashsize>>2) * sizeof(struct hashentry *)))){ + pthread_mutex_unlock(&hash_mutex); + return 2; + } + if(!(ht->hashvalues = myalloc(nhashsize * (sizeof(struct hashentry) + (ht->recsize-4))))){ + myfree(ht->hashtable); + ht->hashtable = NULL; + pthread_mutex_unlock(&hash_mutex); + return 3; + } + ht->hashsize = nhashsize; + ht->rnd[0] = myrand(&tb, sizeof(tb)); + ht->rnd[1] = myrand(ht->hashtable, sizeof(ht->hashtable)); + ht->rnd[2] = myrand(&c, sizeof(c)); + ht->rnd[3] = myrand(ht->hashvalues,sizeof(ht->hashvalues)); + memset(ht->hashtable, 0, (ht->hashsize>>2) * sizeof(struct hashentry *)); + memset(ht->hashvalues, 0, ht->hashsize * (sizeof(struct hashentry) + ht->recsize -4)); + + for(i = 0; i< (ht->hashsize - 1); i++) { + hvalue(i)->next = hvalue(i+1); + } + ht->hashempty = ht->hashvalues; + pthread_mutex_unlock(&hash_mutex); + return 0; +} + +void hashadd(struct hashtable *ht, const void* name, const void* value, time_t expires){ + struct hashentry * hen, *he; + struct hashentry ** hep; + + unsigned index; + + pthread_mutex_lock(&hash_mutex); + if(!ht||!value||!name||!ht->hashtable||!ht->hashempty) { + pthread_mutex_unlock(&hash_mutex); + return; + } + hen = ht->hashempty; + ht->hashempty = ht->hashempty->next; + ht->index2hash(name, hen->hash, (unsigned char *)ht->rnd); + memcpy(hen->value, value, ht->recsize); + hen->expires = expires; + hen->next = NULL; + index = hashindex(ht, hen->hash); + + for(hep = ht->hashtable + index; (he = *hep)!=NULL; ){ + if(he->expires < conf.time || !memcmp(hen->hash, he->hash, sizeof(he->hash))) { + (*hep) = he->next; + he->expires = 0; + he->next = ht->hashempty; + ht->hashempty = he; + } + else hep=&(he->next); + } + hen->next = ht->hashtable[index]; + ht->hashtable[index] = hen; + pthread_mutex_unlock(&hash_mutex); +} + +int hashresolv(struct hashtable *ht, const void* name, void* value, uint32_t *ttl){ + unsigned char hash[sizeof(unsigned)*4]; + struct hashentry ** hep; + struct hashentry *he; + unsigned index; + + pthread_mutex_lock(&hash_mutex); + if(!ht || !ht->hashtable || !name) { + pthread_mutex_unlock(&hash_mutex); + return 0; + } + ht->index2hash(name, hash, (unsigned char *)ht->rnd); + index = hashindex(ht, hash); + for(hep = ht->hashtable + index; (he = *hep)!=NULL; ){ + if(he->expires < conf.time) { + (*hep) = he->next; + he->expires = 0; + he->next = ht->hashempty; + ht->hashempty = he; + } + else if(!memcmp(hash, he->hash, sizeof(unsigned)*4)){ + if(ttl) *ttl = (uint32_t)(he->expires - conf.time); + memcpy(value, he->value, ht->recsize); + pthread_mutex_unlock(&hash_mutex); + return 1; + } + else hep=&(he->next); + } + pthread_mutex_unlock(&hash_mutex); + return 0; +} diff --git a/src/plugins.c b/src/plugins.c index 37d6aec..a376683 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -11,8 +11,6 @@ unsigned bandlimitfunc(struct clientparam *param, unsigned nbytesin, unsigned nbytesout); void trafcountfunc(struct clientparam *param); int checkACL(struct clientparam * param); -void nametohash(const unsigned char * name, unsigned char *hash, unsigned char *rnd); -unsigned hashindex(struct hashtable *ht, const unsigned char* hash); void decodeurl(unsigned char *s, int allowcr); int parsestr (unsigned char *str, unsigned char **argm, int nitems, unsigned char ** buff, int *inbuf, int *bufsize); struct ace * make_ace (int argc, unsigned char ** argv); @@ -45,38 +43,36 @@ struct symbol symbols[] = { {symbols+18, "ipauth", (void *) ipauth}, {symbols+19, "strongauth", (void *) strongauth}, {symbols+20, "checkACL", (void *) checkACL}, - {symbols+21, "nametohash", (void *) nametohash}, - {symbols+22, "hashindex", (void *) hashindex}, - {symbols+23, "nservers", (void *) nservers}, - {symbols+24, "udpresolve", (void *) udpresolve}, - {symbols+25, "bandlim_mutex", (void *) &bandlim_mutex}, - {symbols+26, "tc_mutex", (void *) &tc_mutex}, - {symbols+27, "hash_mutex", (void *) &hash_mutex}, - {symbols+28, "pwl_mutex", (void *) &pwl_mutex}, - {symbols+29, "linenum", (void *) &linenum}, - {symbols+30, "proxy_stringtable", (void *) proxy_stringtable}, - {symbols+31, "en64", (void *) en64}, - {symbols+32, "de64", (void *) de64}, - {symbols+33, "tohex", (void *) tohex}, - {symbols+34, "fromhex", (void *) fromhex}, - {symbols+35, "dnspr", (void *) dnsprchild}, - {symbols+36, "pop3p", (void *) pop3pchild}, - {symbols+37, "proxy", (void *) proxychild}, - {symbols+38, "socks", (void *) sockschild}, - {symbols+39, "tcppm", (void *) tcppmchild}, - {symbols+40, "udppm", (void *) udppmchild}, - {symbols+41, "admin", (void *) adminchild}, - {symbols+42, "ftppr", (void *) ftpprchild}, - {symbols+43, "smtpp", (void *) smtppchild}, - {symbols+44, "auto", (void *) smtppchild}, - {symbols+45, "tlspr", (void *) smtppchild}, - {symbols+46, "authfuncs", (void *) &authfuncs}, - {symbols+47, "commandhandlers", (void *) &commandhandlers}, - {symbols+48, "decodeurl", (void *) decodeurl}, - {symbols+49, "parsestr", (void *) parsestr}, - {symbols+50, "make_ace", (void *) make_ace}, - {symbols+51, "freeacl", (void *) freeacl}, - {symbols+52, "handleredirect", (void *) handleredirect}, + {symbols+21, "nservers", (void *) nservers}, + {symbols+22, "udpresolve", (void *) udpresolve}, + {symbols+23, "bandlim_mutex", (void *) &bandlim_mutex}, + {symbols+24, "tc_mutex", (void *) &tc_mutex}, + {symbols+25, "hash_mutex", (void *) &hash_mutex}, + {symbols+26, "pwl_mutex", (void *) &pwl_mutex}, + {symbols+27, "linenum", (void *) &linenum}, + {symbols+28, "proxy_stringtable", (void *) proxy_stringtable}, + {symbols+29, "en64", (void *) en64}, + {symbols+30, "de64", (void *) de64}, + {symbols+31, "tohex", (void *) tohex}, + {symbols+32, "fromhex", (void *) fromhex}, + {symbols+33, "dnspr", (void *) dnsprchild}, + {symbols+34, "pop3p", (void *) pop3pchild}, + {symbols+35, "proxy", (void *) proxychild}, + {symbols+36, "socks", (void *) sockschild}, + {symbols+37, "tcppm", (void *) tcppmchild}, + {symbols+38, "udppm", (void *) udppmchild}, + {symbols+39, "admin", (void *) adminchild}, + {symbols+40, "ftppr", (void *) ftpprchild}, + {symbols+41, "smtpp", (void *) smtppchild}, + {symbols+42, "auto", (void *) smtppchild}, + {symbols+43, "tlspr", (void *) smtppchild}, + {symbols+44, "authfuncs", (void *) &authfuncs}, + {symbols+45, "commandhandlers", (void *) &commandhandlers}, + {symbols+46, "decodeurl", (void *) decodeurl}, + {symbols+47, "parsestr", (void *) parsestr}, + {symbols+48, "make_ace", (void *) make_ace}, + {symbols+49, "freeacl", (void *) freeacl}, + {symbols+50, "handleredirect", (void *) handleredirect}, {NULL, "", NULL} }; @@ -111,8 +107,6 @@ struct pluginlink pluginlink = { ACLmatches, alwaysauth, checkACL, - nametohash, - hashindex, en64, de64, tohex, diff --git a/src/proxy.h b/src/proxy.h index 5ee5386..2f632d6 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -245,7 +245,11 @@ void mschap(const unsigned char *win_password, const unsigned char *challenge, unsigned char *response); struct hashtable; -void hashadd(struct hashtable *ht, const unsigned char* name, unsigned char* value, time_t expires); +unsigned hashindex(struct hashtable *ht, const unsigned char* hash); +void destroyhashtable(struct hashtable *ht); +int inithashtable(struct hashtable *ht, unsigned nhashsize); +void hashadd(struct hashtable *ht, const void* name, const void* value, time_t expires); +int hashresolv(struct hashtable *ht, const void* name, void* value, uint32_t *ttl); int parsehost(int family, unsigned char *host, struct sockaddr *sa); int parsehostname(char *hostname, struct clientparam *param, uint16_t port); diff --git a/src/resolve.c b/src/resolve.c new file mode 100644 index 0000000..5bc6686 --- /dev/null +++ b/src/resolve.c @@ -0,0 +1,217 @@ +#include "proxy.h" + +void char_index2hash(const void *index, unsigned char *hash, const unsigned char *rnd){ + const char* name = index; + unsigned i, j, k; + memcpy(hash, rnd, sizeof(unsigned)*4); + for(i=0, j=0, k=0; name[j]; j++){ + hash[i] += (toupper(name[j]) - 32)+rnd[((toupper(name[j]))*29277+rnd[(k+j+i)%16]+k+j+i)%16]; + if(++i == sizeof(unsigned)*4) { + i = 0; + k++; + } + } +} + +struct hashtable dns_table = {0, 4, {0,0,0,0}, NULL, NULL, NULL, char_index2hash}; +struct hashtable dns6_table = {0, 16, {0,0,0,0}, NULL, NULL, NULL, char_index2hash}; + +struct nserver nservers[MAXNSERVERS] = {{{0},0}, {{0},0}, {{0},0}, {{0},0}, {{0},0}}; +struct nserver authnserver; + + +uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_t *retttl, struct clientparam* param, int makeauth){ + + int i,n; + uint32_t retval; + + if((af == AF_INET) && (retval = hashresolv(&dns_table, name, value, retttl))) { + return retval; + } + if((af == AF_INET6) && (retval = hashresolv(&dns6_table, name, value, retttl))) { + return retval; + } + n = (makeauth && !SAISNULL(&authnserver.addr))? 1 : numservers; + for(i=0; isinsl : &addr; + sinsr = (param && !makeauth)? ¶m->sinsr : &addr; + memset(sinsl, 0, sizeof(addr)); + memset(sinsr, 0, sizeof(addr)); + + + if(makeauth && !SAISNULL(&authnserver.addr)){ + usetcp = authnserver.usetcp; + *SAFAMILY(sinsl) = *SAFAMILY(&authnserver.addr); + } + else { + usetcp = nservers[i].usetcp; + *SAFAMILY(sinsl) = *SAFAMILY(&nservers[i].addr); + } + if((sock=so._socket(so.state, SASOCK(sinsl), usetcp?SOCK_STREAM:SOCK_DGRAM, usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) break; + if(so._bind(so.state, sock,(struct sockaddr *)sinsl,SASIZE(sinsl))){ + so._shutdown(so.state, sock, SHUT_RDWR); + so._closesocket(so.state, sock); + break; + } + if(makeauth && !SAISNULL(&authnserver.addr)){ + *sinsr = authnserver.addr; + } + else { + *sinsr = nservers[i].addr; + } + if(usetcp){ + if(connectwithpoll(NULL, sock,(struct sockaddr *)sinsr,SASIZE(sinsr),conf.timeouts[CONNECT_TO])) { + so._shutdown(so.state, sock, SHUT_RDWR); + so._closesocket(so.state, sock); + break; + } +#ifdef TCP_NODELAY + { + int opt = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)); + } +#endif + } + len = (int)strlen((char *)name); + + serial = myrand(name,len); + *(unsigned short*)buf = serial; /* query id */ + buf[2] = 1; /* recursive */ + buf[3] = 0; + buf[4] = 0; + buf[5] = 1; /* 1 request */ + buf[6] = buf[7] = 0; /* no replies */ + buf[8] = buf[9] = 0; /* no ns count */ + buf[10] = buf[11] = 0; /* no additional */ + if(len > 255) { + len = 255; + } + memcpy(buf + 13, name, len); + len += 13; + buf[len] = 0; + for(s2 = buf + 12; (s1 = (unsigned char *)strchr((char *)s2 + 1, '.')); s2 = s1)*s2 = (unsigned char)((s1 - s2) - 1); + *s2 = (len - (int)(s2 - buf)) - 1; + len++; + buf[len++] = 0; + buf[len++] = (makeauth == 1)? 0x0c : (af==AF_INET6? 0x1c:0x01);/* PTR:host address */ + buf[len++] = 0; + buf[len++] = 1; /* INET */ + if(usetcp){ + buf-=2; + *(unsigned short*)buf = htons(len); + len+=2; + } + + if(socksendto(NULL, sock, (struct sockaddr *)sinsr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){ + so._shutdown(so.state, sock, SHUT_RDWR); + so._closesocket(so.state, sock); + continue; + } + if(param) param->statscli64 += len; + len = sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf, 4096, conf.timeouts[DNS_TO]*1000); + so._shutdown(so.state, sock, SHUT_RDWR); + so._closesocket(so.state, sock); + if(len <= 13) { + continue; + } + if(param) param->statssrv64 += len; + if(usetcp){ + unsigned short us; + us = ntohs(*(unsigned short*)buf); + len-=2; + buf+=2; + if(us > 4096 || us < len || (us > len && sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf+len, us-len, conf.timeouts[DNS_TO]*1000) != us-len)) { + continue; + } + } + if(*(unsigned short *)buf != serial)continue; + if((na = buf[7] + (((unsigned short)buf[6])<<8)) < 1) { + return 0; + } + nq = buf[5] + (((unsigned short)buf[4])<<8); + if (nq != 1) { + continue; /* we did only 1 request */ + } + for(k = 13; k= len) { + continue; + } + k += 4; + if(na > 255) na = 255; /* somebody is very evil */ + for (j = 0; j < na; j++) { /* now there should be answers */ + while(buf[k] < 192 && buf[k] !=0 && (k+buf[k]+14) < len) k+= (buf[k] + 1); + if(!buf[k]) k--; + if((k+(af == AF_INET6?28:16)) > len) { + break; + } + flen = buf[k+11] + (((unsigned short)buf[k+10])<<8); + if((k+12+flen) > len) { + break; + } + if(makeauth != 1){ + if(buf[k+2] != 0 || buf[k+3] != (af == AF_INET6?0x1c:0x1) || flen != (af == AF_INET6?16:4)) { + k+= (12 + flen); + continue; /* we need A IPv4 */ + } + ttl = ntohl(*(uint32_t *)(buf + k + 6)); + memcpy(value, buf + k + 12, af == AF_INET6? 16:4); + if(ttl < 0 || ttl > (3600*12)) ttl = 3600*12; + if(!ttl) ttl = 1; + hashadd(af == AF_INET6?&dns6_table:&dns_table, name, value, conf.time+ttl); + if(retttl) *retttl = ttl; + return 1; + } + else { + + if(buf[k+2] != 0 || buf[k+3] != 0x0c) { + k+= (12 + flen); + continue; /* we need A PTR */ + } + for (s2 = buf + k + 12; s2 < (buf + k + 12 + len) && *s2; ){ + s1 = s2 + ((unsigned)*s2) + 1; + *s2 = '.'; + s2 = s1; + } + *s2 = 0; + if(param->username)myfree(param->username); + param->username = (unsigned char *)mystrdup ((char *)buf + k + 13); + + return udpresolve(af,param->username, value, NULL, NULL, 2); + } + } + } + return 0; +} + +uint32_t myresolver(int af, unsigned char * name, unsigned char * value){ + return udpresolve(af, name, value, NULL, NULL, 0); +} + +uint32_t fakeresolver (int af, unsigned char *name, unsigned char * value){ + memset(value, 0, af == AF_INET6? 16 : 4); + if(af == AF_INET6){ + memset(value, 0, 16); + value[15] = 2; + } + else { + value[0] = 127; + value[1] = 0; + value[2] = 0; + value[3] = 2; + } + return 1; +} \ No newline at end of file diff --git a/src/sql.c b/src/sql.c new file mode 100644 index 0000000..da905cc --- /dev/null +++ b/src/sql.c @@ -0,0 +1,152 @@ +#include "proxy.h" +#ifndef NOODBC + +SQLHENV henv = NULL; +SQLHSTMT hstmt = NULL; +SQLHDBC hdbc = NULL; +char * sqlstring = NULL; + + +void close_sql(){ + if(hstmt) { + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + hstmt = NULL; + } + if(hdbc){ + SQLDisconnect(hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = NULL; + } + if(henv) { + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = NULL; + } +} + +int attempt = 0; +time_t attempt_time = 0; + +int init_sql(char * s){ + SQLRETURN retcode; + char * datasource; + char * username; + char * password; + char * string; + + if(!s) return 0; + if(!sqlstring || strcmp(sqlstring, s)){ + string = sqlstring; + sqlstring=mystrdup(s); + if(string)myfree(string); + } + + if(hstmt || hdbc || henv) close_sql(); + attempt++; + attempt_time = time(0); + if(!henv){ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + if (!henv || (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)){ + henv = NULL; + return 0; + } + retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); + + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { + return 0; + } + } + if(!hdbc){ + retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + if (!hdbc || (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)) { + hdbc = NULL; + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = NULL; + return 0; + } + SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (void*)15, 0); + } + string = mystrdup(sqlstring); + if(!string) return 0; + datasource = strtok(string, ","); + username = strtok(NULL, ","); + password = strtok(NULL, ","); + + + /* Connect to data source */ + retcode = SQLConnect(hdbc, (SQLCHAR*) datasource, (SQLSMALLINT)strlen(datasource), + (SQLCHAR*) username, (SQLSMALLINT)((username)?strlen(username):0), + (SQLCHAR*) password, (SQLSMALLINT)((password)?strlen(password):0)); + + myfree(string); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO){ + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = NULL; + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = NULL; + return 0; + } + retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO){ + close_sql(); + return 0; + } + return 1; +} + +void sqlerr (char *buf){ + if(conf.stdlog){ + fprintf(conf.stdlog, "%s\n", buf); + fflush(conf.stdlog); + } + pthread_mutex_unlock(&log_mutex); +} + +unsigned char statbuf[8192]; + +void logsql(struct clientparam * param, const unsigned char *s) { + SQLRETURN ret; + int len; + + + if(param->nolog) return; + pthread_mutex_lock(&log_mutex); + len = dobuf(param, statbuf, s, (unsigned char *)"\'"); + + if(attempt > 5){ + time_t t; + + t = time(0); + if (t - attempt_time < 180){ + sqlerr((char *)statbuf); + return; + } + } + if(!hstmt){ + if(!init_sql(sqlstring)) { + sqlerr((char *)statbuf); + return; + } + } + if(hstmt){ + ret = SQLExecDirect(hstmt, (SQLCHAR *)statbuf, (SQLINTEGER)len); + if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO){ + close_sql(); + if(!init_sql(sqlstring)){ + sqlerr((char *)statbuf); + return; + } + if(hstmt) { + ret = SQLExecDirect(hstmt, (SQLCHAR *)statbuf, (SQLINTEGER)len); + if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO){ + sqlerr((char *)statbuf); + return; + } + attempt = 0; + } + } + attempt = 0; + } + pthread_mutex_unlock(&log_mutex); +} + +#endif \ No newline at end of file diff --git a/src/structures.h b/src/structures.h index bd254ad..6ea8751 100644 --- a/src/structures.h +++ b/src/structures.h @@ -768,6 +768,8 @@ struct hashtable { struct hashentry ** hashtable; void * hashvalues; struct hashentry * hashempty; + void (*index2hash)(const void *index, unsigned char *hash, const unsigned char *rnd); + int grow; }; extern struct hashtable dns_table; @@ -795,8 +797,6 @@ struct pluginlink { int (*ACLMatches)(struct ace* acentry, struct clientparam * param); int (*alwaysauth)(struct clientparam * param); int (*checkACL)(struct clientparam * param); - void (*nametohash)(const unsigned char * name, unsigned char *hash, unsigned char *rnd); - unsigned (*hashindex)(struct hashtable *ht, const unsigned char* hash); unsigned char* (*en64)(const unsigned char *in, unsigned char *out, int inlen); int (*de64)(const unsigned char *in, unsigned char *out, int maxlen); void (*tohex)(unsigned char *in, unsigned char *out, int len);