move hashtable/resolve/sql functions to separate files

This commit is contained in:
Vladimir Dubrovin 2026-04-17 19:29:50 +03:00
parent 4c0e3a1bac
commit a0d580b36d
9 changed files with 560 additions and 554 deletions

View File

@ -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

View File

@ -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)

View File

@ -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; i<n; i++){
unsigned short nq, na;
unsigned char b[4098], *buf, *s1, *s2;
int j, k, len, flen;
SOCKET sock;
uint32_t ttl;
PROXYSOCKADDRTYPE addr;
PROXYSOCKADDRTYPE *sinsr, *sinsl;
int usetcp = 0;
unsigned short serial = 1;
buf = b+2;
sinsl = (param && !makeauth)? &param->sinsl : &addr;
sinsr = (param && !makeauth)? &param->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 && buf[k]; k++) {
}
k++;
if( (k+4) >= 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

146
src/hash.c Normal file
View File

@ -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;
}

View File

@ -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,

View File

@ -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);

217
src/resolve.c Normal file
View File

@ -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; i<n; i++){
unsigned short nq, na;
unsigned char b[4098], *buf, *s1, *s2;
int j, k, len, flen;
SOCKET sock;
uint32_t ttl;
PROXYSOCKADDRTYPE addr;
PROXYSOCKADDRTYPE *sinsr, *sinsl;
int usetcp = 0;
unsigned short serial = 1;
buf = b+2;
sinsl = (param && !makeauth)? &param->sinsl : &addr;
sinsr = (param && !makeauth)? &param->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 && buf[k]; k++) {
}
k++;
if( (k+4) >= 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;
}

152
src/sql.c Normal file
View File

@ -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

View File

@ -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);