From 7102afe8568dbb06e1ae6be1d2bfd189919a3a07 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Sun, 19 Apr 2026 19:16:33 +0300 Subject: [PATCH] authcache switched to hashtables, overflow fixed - authcache switched to use hashtables, size parameter added - overflow fixed on hashinit - hashtable prefers new values on insert if table is full - hashtable is able to compact/grow --- man/3proxy.cfg.3 | 3 +- src/auth.c | 183 ++++++++++++++++++++--------------------------- src/conf.c | 27 ++++--- src/hash.c | 100 ++++++++++++++------------ src/proxy.c | 2 +- src/structures.h | 3 + 6 files changed, 159 insertions(+), 159 deletions(-) diff --git a/man/3proxy.cfg.3 b/man/3proxy.cfg.3 index b766c43..9122080 100644 --- a/man/3proxy.cfg.3 +++ b/man/3proxy.cfg.3 @@ -623,9 +623,10 @@ shared ones. .br .B authcache - + .br Cache authentication information for a given amount of time (cachetime) in seconds. +cachesize limits number of cache entries. Cachetype is one of: .br ip - after successful authentication all connections during caching time diff --git a/src/auth.c b/src/auth.c index 6e09253..487fc48 100644 --- a/src/auth.c +++ b/src/auth.c @@ -7,6 +7,7 @@ */ #include "proxy.h" +#include "libs/blake2.h" static FILTER_ACTION (*ext_ssl_parent)(struct clientparam * param) = NULL; @@ -776,73 +777,71 @@ int checkACL(struct clientparam * param){ } struct authcache { - char * username; - char * password; - time_t expires; - PROXYSOCKADDRTYPE sa; - PROXYSOCKADDRTYPE sinsl; - struct ace *acl; - struct authcache *next; -} *authc = NULL; + unsigned char username[64]; +#ifndef NOIPv6 + uint8_t sincr_addr[16]; + uint8_t sinsl_addr[16]; +#else + uint8_t sincr_addr[4]; + uint8_t sinsl_addr[4]; +#endif + uint16_t sincr_family; + uint16_t sinsl_family; +}; + +void param2hash(const void *index, uint8_t *hash, const unsigned char *rnd){ + blake2b_state S; + const struct clientparam *param = (struct clientparam *)index; + + blake2b_init_key(&S, HASH_SIZE, rnd, sizeof(unsigned)*4); + if((conf.authcachetype & 1) && !(conf.authcachetype & 8))blake2b_update(&S, SAADDR(¶m->sincr), SAADDRLEN(¶m->sincr)); + if((conf.authcachetype & 2) && param->username)blake2b_update(&S, param->username, strlen((const char *)param->username)); + if((conf.authcachetype & 4) && param->password)blake2b_update(&S, param->password, strlen((const char *)param->password)); + if((conf.authcachetype & 16))blake2b_update(&S, ¶m->srv->acl, sizeof(param->srv->acl)); + blake2b_final(&S, hash, HASH_SIZE); +} + +struct hashtable auth_table = {0, sizeof(struct authcache), {0,0,0,0}, NULL, NULL, 0, param2hash}; + int cacheauth(struct clientparam * param){ - struct authcache *ac, *last=NULL; - - pthread_mutex_lock(&hash_mutex); - for(ac = authc; ac; ){ - if(ac->expires <= conf.time){ - if(ac->username)myfree(ac->username); - if(ac->password)myfree(ac->password); - if(!last){ - authc = ac->next; - myfree(ac); - ac = authc; - } - else { - last->next = ac->next; - myfree(ac); - ac = last->next; - } - continue; - - } - if( - (!(conf.authcachetype&2) || (param->username && ac->username && !strcmp(ac->username, (char *)param->username))) && - (!(conf.authcachetype&4) || (ac->password && param->password && !strcmp(ac->password, (char *)param->password))) && - (!(conf.authcachetype&16) || (ac->acl == param->srv->acl)) - ) { - - if(!(conf.authcachetype&1) - || ((*SAFAMILY(&ac->sa) == *SAFAMILY(¶m->sincr) - && !memcmp(SAADDR(&ac->sa), SAADDR(¶m->sincr), SAADDRLEN(&ac->sa))))){ - - if(conf.authcachetype&32) { - param->sinsl = ac->sinsl; - } - if(param->username){ - myfree(param->username); - } - param->username = (unsigned char *)mystrdup(ac->username); - pthread_mutex_unlock(&hash_mutex); - return 0; - } - else if ((conf.authcachetype&1) && (conf.authcachetype&8)) { - pthread_mutex_unlock(&hash_mutex); - return 10; - } - } - last = ac; - ac = ac->next; + struct authcache ac; + uint32_t ttl; + + + if( + ((conf.authcachetype & 2) && !param->username) || + ((conf.authcachetype & 4) && !param->password) || + ( + (conf.authcachetype & 1) && *SAFAMILY(¶m->sincr) != AF_INET +#ifndef NOIPv6 + && *SAFAMILY(¶m->sincr) != AF_INET6 +#endif + ) || (!hashresolv(&auth_table, param, &ac, &ttl))) { + return 4; } - - pthread_mutex_unlock(&hash_mutex); - return 4; + if((conf.authcachetype & 1) &&(conf.authcachetype & 8) && + (ac.sincr_family != *SAFAMILY(¶m->sincr) || + memcmp(ac.sincr_addr, SAADDR(¶m->sincr), SAADDRLEN(¶m->sincr)) + )) { + return 10; + } + + if(!(conf.authcachetype&2) && *ac.username){ + if(param->username) myfree(param->username); + param->username = (unsigned char *)mystrdup((char *)ac.username); + } + if((conf.authcachetype & 32)){ + memset(¶m->sinsl, 0, sizeof(param->sinsl)); + *(SAFAMILY(¶m->sinsl)) = ac.sinsl_family; + memcpy(SAADDR(¶m->sinsl), ac.sinsl_addr, SAADDRLEN(¶m->sinsl)); + } + return 0; } int doauth(struct clientparam * param){ int res = 0; struct auth *authfuncs; - struct authcache *ac; char * tmp; int ret = 0; @@ -853,51 +852,27 @@ int doauth(struct clientparam * param){ (res = (*authfuncs->authorize)(param))) return res; if(conf.authcachetype && authfuncs->authenticate && authfuncs->authenticate != cacheauth && param->username && (!(conf.authcachetype&4) || (!param->pwtype && param->password))){ - pthread_mutex_lock(&hash_mutex); - for(ac = authc; ac; ac = ac->next){ - if( - (!(conf.authcachetype&2) || !strcmp(ac->username, (char *)param->username)) && - (!(conf.authcachetype&1) || (*SAFAMILY(&ac->sa) == *SAFAMILY(¶m->sincr) && !memcmp(SAADDR(&ac->sa), SAADDR(¶m->sincr), SAADDRLEN(&ac->sa)))) && - (!(conf.authcachetype&4) || (ac->password && !strcmp(ac->password, (char *)param->password))) && - (!(conf.authcachetype&16) || (ac->acl == param->srv->acl)) - ) { - ac->expires = conf.time + conf.authcachetime; - if(strcmp(ac->username, (char *)param->username)){ - tmp = ac->username; - ac->username = mystrdup((char *)param->username); - myfree(tmp); - } - if((conf.authcachetype&4)){ - tmp = ac->password; - ac->password = mystrdup((char *)param->password); - myfree(tmp); - } - ac->sa = param->sincr; - if(conf.authcachetype&32) { - ac->sinsl = param-> sinsl; - *SAPORT(&ac->sinsl) = 0; - } - - break; - } - } - if(!ac){ - ac = myalloc(sizeof(struct authcache)); - if(ac){ - ac->expires = conf.time + conf.authcachetime; - ac->username = param->username?mystrdup((char *)param->username):NULL; - ac->sa = param->sincr; - ac->password = NULL; - if((conf.authcachetype&4) && param->password) ac->password = mystrdup((char *)param->password); - if(conf.authcachetype&32) { - ac->sinsl = param->sinsl; - *SAPORT(&ac->sinsl) = 0; - } - } - ac->next = authc; - authc = ac; - } - pthread_mutex_unlock(&hash_mutex); + struct authcache ac={}; + + if(param->username) strncpy((char *)ac.username, (char *)param->username, 64); + if(*SAFAMILY(¶m->sincr) == AF_INET +#ifndef NOIPv6 + || *SAFAMILY(¶m->sincr) == AF_INET6 +#endif + ) { + ac.sincr_family = *SAFAMILY(¶m->sincr); + memcpy(ac.sincr_addr, SAADDR(¶m->sincr), SAADDRLEN(¶m->sincr)); + } + + if(*SAFAMILY(¶m->sinsl) == AF_INET +#ifndef NOIPv6 + || *SAFAMILY(¶m->sinsl) == AF_INET6 +#endif + ) { + ac.sinsl_family = *SAFAMILY(¶m->sinsl); + memcpy(ac.sinsl_addr, SAADDR(¶m->sinsl), SAADDRLEN(¶m->sinsl)); + } + hashadd(&auth_table, param, &ac, conf.time + conf.authcachetime); } break; } diff --git a/src/conf.c b/src/conf.c index bad8458..4c04360 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1430,6 +1430,7 @@ static int h_radius(int argc, unsigned char **argv){ #endif static int h_authcache(int argc, unsigned char **argv){ conf.authcachetype = 0; + int authcachesize; if(strstr((char *) *(argv + 1), "ip")) conf.authcachetype |= 1; if(strstr((char *) *(argv + 1), "user")) conf.authcachetype |= 2; if(strstr((char *) *(argv + 1), "pass")) conf.authcachetype |= 4; @@ -1437,8 +1438,14 @@ static int h_authcache(int argc, unsigned char **argv){ if(strstr((char *) *(argv + 1), "acl")) conf.authcachetype |= 16; if(strstr((char *) *(argv + 1), "ext")) conf.authcachetype |= 32; if(argc > 2) conf.authcachetime = (unsigned) atoi((char *) *(argv + 2)); + if(argc > 3) authcachesize = (unsigned) atoi((char *) *(argv + 2)); if(!conf.authcachetype) conf.authcachetype = 6; if(!conf.authcachetime) conf.authcachetime = 600; + if(inithashtable(&auth_table, authcachesize? authcachesize : 4096)){ + fprintf(stderr, "Failed to initialize auth cache\n"); + return 2; + } + if(!authcachesize)auth_table.growlimit = 65536*4; return 0; } @@ -1645,7 +1652,7 @@ struct commands commandhandlers[]={ {commandhandlers+53, "filtermaxsize", h_filtermaxsize, 2, 2}, {commandhandlers+54, "nolog", h_nolog, 1, 1}, {commandhandlers+55, "weight", h_nolog, 2, 2}, - {commandhandlers+56, "authcache", h_authcache, 2, 3}, + {commandhandlers+56, "authcache", h_authcache, 2, 4}, {commandhandlers+57, "smtpp", h_proxy, 1, 0}, {commandhandlers+58, "delimchar",h_delimchar, 2, 2}, {commandhandlers+59, "authnserver", h_authnserver, 2, 2}, @@ -1799,13 +1806,17 @@ int readconfig(FILE * fp){ res = 1; for(cm = commandhandlers; cm; cm = cm->next){ - if(!strcmp((char *)argv[0], (char *)cm->command) && argc >= cm->minargs && (!cm->maxargs || argc <= cm->maxargs)){ - res = (*cm->handler)(argc, argv); - if(res > 0){ - fprintf(stderr, "Command: '%s' failed with code %d, line %d\n", argv[0], res, linenum); - return(linenum); - } - if(!res) break; + if(!strcmp((char *)argv[0], (char *)cm->command)){ + if(argc < cm->minargs || (cm->maxargs && argc > cm->maxargs)){ + fprintf(stderr, "Command: '%s' wrong number of arguments , line %d\n", argv[0], linenum); + return(linenum); + } + res = (*cm->handler)(argc, argv); + if(res > 0){ + fprintf(stderr, "Command: '%s' failed with code %d, line %d\n", argv[0], res, linenum); + return(linenum); + } + if(!res) break; } } if(res != 1)continue; diff --git a/src/hash.c b/src/hash.c index 7769cf6..aa482e4 100644 --- a/src/hash.c +++ b/src/hash.c @@ -28,7 +28,6 @@ int inithashtable(struct hashtable *ht, unsigned nhashsize){ unsigned tablesize, hashsize; clock_t c; - #ifdef _WIN32 struct timeb tb; @@ -71,7 +70,7 @@ int inithashtable(struct hashtable *ht, unsigned nhashsize){ ht->rnd[1] = myrand(ht->ihashtable, sizeof(ht->ihashtable)); ht->rnd[2] = myrand(&c, sizeof(c)); ht->rnd[3] = myrand(ht->hashvalues,sizeof(ht->hashvalues)); - memset(ht->ihashtable, 0, ht->tablesize * sizeof(struct hashentry *)); + memset(ht->ihashtable, 0, ht->tablesize * sizeof(uint32_t)); memset(ht->hashvalues, 0, ht->hashsize * (sizeof(struct hashentry) + ht->recsize - 4)); for(i = 1; i < ht->hashsize; i++) { @@ -82,14 +81,35 @@ int inithashtable(struct hashtable *ht, unsigned nhashsize){ return 0; } +static void hashcompact(struct hashtable *ht){ + int i; + uint32_t he, *hep; + + if((conf.time - ht->compacted) < 300 || !ht->tablesize || !ht->hashsize || ht->ihashempty) return; + for(i = 0; i < ht->tablesize; i++){ + for(hep = ht->ihashtable + i; (he = *hep) != 0; ){ + if(hvalue(ht,he)->expires < conf.time ) { + (*hep) = hvalue(ht,he)->inext; + hvalue(ht,he)->expires = 0; + hvalue(ht,he)->inext = ht->ihashempty; + ht->ihashempty = he; + } + else hep=&(hvalue(ht,he)->inext); + } + } + ht->compacted = conf.time; + if(ht->ihashempty) return; +} + static void hashgrow(struct hashtable *ht){ unsigned newsize = (ht->hashsize + (ht->hashsize >> 1)); unsigned i; void * newvalues; if(!ht->tablesize || !ht->hashsize) return; + if(ht->hashsize / ht->tablesize < 4) hashcompact(ht); + if(ht->ihashempty) return; if(ht->hashsize >= ht->growlimit) return; - if(ht->hashsize / ht->tablesize > 100) return; if(newsize > ht->growlimit) newsize = ht->growlimit; newvalues = myrealloc(ht->hashvalues, newsize * (sizeof(struct hashentry) + ht->recsize - 4)); if(!newvalues) return; @@ -102,55 +122,24 @@ static void hashgrow(struct hashtable *ht){ ht->hashsize = newsize; } -/* -static void hashcompact(struct hashtable *ht){ - int i; - uint32_t he, *hep; - - if((conf.time - ht->compacted) < 60 || !ht->tablesize || !ht->hashsize || ht->ihashempty) return; - if(ht->grow && ht->hashsize/ht->tablesize < 100){ - hashgrow(ht); - if(ht->ihashempty) return; - } - if(ht->hashsize/ht->tablesize < 4){ - for(i = 0; i < ht->tablesize; i++){ - for(hep = ht->ihashtable + i; (he = *hep) != 0; ){ - if(hvalue(ht,he)->expires < conf.time ) { - (*hep) = hvalue(ht,he)->inext; - hvalue(ht,he)->expires = 0; - hvalue(ht,he)->inext = ht->ihashempty; - ht->ihashempty = he; - } - else hep=&(hvalue(ht,he)->inext); - } - } - ht->compacted = conf.time; - if(ht->ihashempty) return; - } -} -*/ + void hashadd(struct hashtable *ht, const void* name, const void* value, time_t expires){ uint32_t hen, he; uint32_t *hep; - + int overwrite = 0; + uint8_t hash[HASH_SIZE]; uint32_t index; + uint32_t last = 0; pthread_mutex_lock(&hash_mutex); - if(!ht->ihashempty){ - hashgrow(ht); - } - if(!ht||!value||!name||!ht->ihashtable||!ht->ihashempty) { + if(!ht||!value||!name||!ht->ihashtable) { pthread_mutex_unlock(&hash_mutex); return; } - hen = ht->ihashempty; - ht->ihashempty = hvalue(ht,ht->ihashempty)->inext; - ht->index2hash(name, hvalue(ht,hen)->hash, (unsigned char *)ht->rnd); - memcpy(hvalue(ht,hen)->value, value, ht->recsize); - hvalue(ht,hen)->expires = expires; - hvalue(ht,hen)->inext = 0; - index = hashindex(ht, hvalue(ht,hen)->hash); + + ht->index2hash(name, hash, (unsigned char *)ht->rnd); + index = hashindex(ht, hash); for(hep = ht->ihashtable + index; (he = *hep)!=0; ){ if(hvalue(ht,he)->expires < conf.time || !memcmp(hvalue(ht,hen)->hash, hvalue(ht,he)->hash, HASH_SIZE)) { @@ -159,10 +148,31 @@ void hashadd(struct hashtable *ht, const void* name, const void* value, time_t e hvalue(ht,he)->inext = ht->ihashempty; ht->ihashempty = he; } - else hep=&(hvalue(ht,he)->inext); + else { + hep=&(hvalue(ht,he)->inext); + last = he; + } } - hvalue(ht,hen)->inext = ht->ihashtable[index]; - ht->ihashtable[index] = hen; + + if(!ht->ihashempty){ + hashgrow(ht); + } + + if(ht->ihashempty){ + hen = ht->ihashempty; + ht->ihashempty = hvalue(ht,ht->ihashempty)->inext; + hvalue(ht,hen)->inext = ht->ihashtable[index]; + ht->ihashtable[index] = hen; + } + else { + hen = last; + } + if(hen){ + memcpy(hvalue(ht,hen)->hash, hash, HASH_SIZE); + memcpy(hvalue(ht,hen)->value, value, ht->recsize); + hvalue(ht,hen)->expires = expires; + } + pthread_mutex_unlock(&hash_mutex); } diff --git a/src/proxy.c b/src/proxy.c index a71b73b..4ab4909 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -31,7 +31,7 @@ char * proxy_stringtable[] = { "Content-type: text/html; charset=utf-8\r\n" "\r\n" "503 Service Unavailable\r\n" - "

503 Service Unavailable

You have exceeded your traffic limit

\r\n", + "

503 Service Unavailable

You have exceeded your limits

\r\n", /* 3 */ "HTTP/1.0 503 Service Unavailable\r\n" "Connection: close\r\n" diff --git a/src/structures.h b/src/structures.h index f746438..b2f5a41 100644 --- a/src/structures.h +++ b/src/structures.h @@ -773,10 +773,13 @@ struct hashtable { void (*index2hash)(const void *index, unsigned char *hash, const unsigned char *rnd); unsigned growlimit; int tablesize; + time_t compacted; }; extern struct hashtable dns_table; extern struct hashtable dns6_table; +extern struct hashtable auth_table; + struct pluginlink { struct symbol symbols; struct extparam *conf;