mirror of
https://github.com/3proxy/3proxy.git
synced 2026-04-26 22:20:11 +08:00
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
This commit is contained in:
parent
a3729354b8
commit
7102afe856
@ -623,9 +623,10 @@ shared ones.
|
||||
|
||||
.br
|
||||
.B authcache
|
||||
<cachtype> <cachtime>
|
||||
<cachtype> <cachtime> <cachesize>
|
||||
.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
|
||||
|
||||
183
src/auth.c
183
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;
|
||||
}
|
||||
|
||||
27
src/conf.c
27
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;
|
||||
|
||||
100
src/hash.c
100
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);
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ char * proxy_stringtable[] = {
|
||||
"Content-type: text/html; charset=utf-8\r\n"
|
||||
"\r\n"
|
||||
"<html><head><title>503 Service Unavailable</title></head>\r\n"
|
||||
"<body><h2>503 Service Unavailable</h2><h3>You have exceeded your traffic limit</h3></body></html>\r\n",
|
||||
"<body><h2>503 Service Unavailable</h2><h3>You have exceeded your limits</h3></body></html>\r\n",
|
||||
|
||||
/* 3 */ "HTTP/1.0 503 Service Unavailable\r\n"
|
||||
"Connection: close\r\n"
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user