mirror of
https://github.com/3proxy/3proxy.git
synced 2026-04-28 15:10:12 +08:00
330 lines
10 KiB
C
330 lines
10 KiB
C
#include "proxy.h"
|
|
#include "libs/blake2.h"
|
|
|
|
|
|
struct hashentry {
|
|
time_t expires;
|
|
uint32_t inext;
|
|
char value[4];
|
|
};
|
|
|
|
static uint32_t hashindex(unsigned tablesize, const uint8_t* hash){
|
|
return (*(unsigned *)hash) % tablesize;
|
|
}
|
|
|
|
|
|
void destroyhashtable(struct hashtable *ht){
|
|
pthread_mutex_lock(&hash_mutex);
|
|
if(ht->ihashtable){
|
|
myfree(ht->ihashtable);
|
|
ht->ihashtable = NULL;
|
|
}
|
|
if(ht->hashvalues){
|
|
myfree(ht->hashvalues);
|
|
ht->hashvalues = NULL;
|
|
}
|
|
if(ht->hashhashvalues){
|
|
myfree(ht->hashhashvalues);
|
|
ht->hashhashvalues = NULL;
|
|
}
|
|
ht->poolsize = 0;
|
|
ht->tablesize = 0;
|
|
ht->ihashempty = 0;
|
|
pthread_mutex_unlock(&hash_mutex);
|
|
}
|
|
|
|
#define hvalue(ht,I) ((struct hashentry *)(ht->hashvalues + (I-1)*(sizeof(struct hashentry) + ht->recsize - 4)))
|
|
#define hhash(ht,I) ((ht->hashhashvalues + (I-1)*(ht->hash_size)))
|
|
|
|
int inithashtable(struct hashtable *ht, unsigned tablesize, unsigned poolsize, unsigned growlimit){
|
|
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(tablesize < 2 || poolsize < tablesize || growlimit < poolsize) return 1;
|
|
pthread_mutex_lock(&hash_mutex);
|
|
if(ht->ihashtable){
|
|
myfree(ht->ihashtable);
|
|
ht->ihashtable = NULL;
|
|
}
|
|
if(ht->hashvalues){
|
|
myfree(ht->hashvalues);
|
|
ht->hashvalues = NULL;
|
|
}
|
|
if(ht->hashhashvalues){
|
|
myfree(ht->hashhashvalues);
|
|
ht->hashhashvalues = NULL;
|
|
}
|
|
ht->poolsize = 0;
|
|
ht->tablesize = 0;
|
|
if(!(ht->ihashtable = myalloc(tablesize * sizeof(uint32_t)))
|
|
|| !(ht->hashvalues = myalloc(poolsize * (sizeof(struct hashentry) + (ht->recsize-4))))
|
|
|| !(ht->hashhashvalues = myalloc(poolsize * ht->hash_size))
|
|
){
|
|
myfree(ht->ihashtable);
|
|
ht->ihashtable = NULL;
|
|
myfree(ht->hashvalues);
|
|
ht->hashvalues = NULL;
|
|
pthread_mutex_unlock(&hash_mutex);
|
|
return 3;
|
|
}
|
|
ht->poolsize = poolsize;
|
|
ht->tablesize = tablesize;
|
|
ht->growlimit = growlimit;
|
|
memset(ht->ihashtable, 0, ht->tablesize * sizeof(uint32_t));
|
|
memset(ht->hashvalues, 0, ht->poolsize * (sizeof(struct hashentry) + ht->recsize - 4));
|
|
|
|
for(i = 1; i < ht->poolsize; i++) {
|
|
hvalue(ht,i)->inext = i+1;
|
|
}
|
|
ht->ihashempty = 1;
|
|
pthread_mutex_unlock(&hash_mutex);
|
|
return 0;
|
|
}
|
|
|
|
static void hashcompact(struct hashtable *ht){
|
|
int i;
|
|
uint32_t he, *hep;
|
|
|
|
if((conf.time - ht->compacted) < 300 || !ht->tablesize || !ht->poolsize || 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->poolsize + (ht->poolsize >> 1));
|
|
unsigned i;
|
|
void * newvalues;
|
|
|
|
if(!ht->tablesize || !ht->poolsize) return;
|
|
if(ht->poolsize / ht->tablesize < 4) hashcompact(ht);
|
|
if(ht->ihashempty) return;
|
|
if(ht->poolsize >= ht->growlimit) return;
|
|
if(newsize > ht->growlimit) newsize = ht->growlimit;
|
|
newvalues = myrealloc(ht->hashvalues, newsize * (sizeof(struct hashentry) + ht->recsize - 4));
|
|
if(!newvalues) return;
|
|
ht->hashvalues = newvalues;
|
|
newvalues = myrealloc(ht->hashhashvalues, newsize * ht->hash_size);
|
|
if(!newvalues) return;
|
|
ht->hashhashvalues = newvalues;
|
|
memset(ht->hashvalues + (ht->poolsize * (sizeof(struct hashentry) + ht->recsize - 4)), 0, (newsize - ht->poolsize) * (sizeof(struct hashentry) + ht->recsize - 4));
|
|
for(i = ht->poolsize + 1; i < newsize; i++) {
|
|
hvalue(ht,i)->inext = i+1;
|
|
}
|
|
hvalue(ht,newsize)->inext = ht->ihashempty;
|
|
ht->ihashempty = ht->poolsize + 1;
|
|
ht->poolsize = newsize;
|
|
if (ht->poolsize / ht->tablesize > 10) {
|
|
unsigned newtablesize = ht->poolsize / 3;
|
|
uint32_t *newitable = myalloc(newtablesize * sizeof(uint32_t));
|
|
if (newitable) {
|
|
unsigned j;
|
|
memset(newitable, 0, newtablesize * sizeof(uint32_t));
|
|
for (j = 0; j < ht->tablesize; j++) {
|
|
uint32_t he = ht->ihashtable[j];
|
|
while (he) {
|
|
uint32_t next = hvalue(ht, he)->inext;
|
|
unsigned idx = hashindex(newtablesize, hhash(ht, he));
|
|
hvalue(ht, he)->inext = newitable[idx];
|
|
newitable[idx] = he;
|
|
he = next;
|
|
}
|
|
}
|
|
myfree(ht->ihashtable);
|
|
ht->ihashtable = newitable;
|
|
ht->tablesize = newtablesize;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void hashadd(struct hashtable *ht, void* name, void* value, time_t expires){
|
|
uint32_t hen, he;
|
|
uint32_t *hep;
|
|
int overwrite = 0;
|
|
uint8_t hash[MAX_HASH_SIZE];
|
|
uint32_t index;
|
|
uint32_t last = 0;
|
|
|
|
if(!ht||!value||!name||!ht->ihashtable) {
|
|
return;
|
|
}
|
|
|
|
ht->index2hash_add(ht, name, hash);
|
|
pthread_mutex_lock(&hash_mutex);
|
|
index = hashindex(ht->tablesize, hash);
|
|
|
|
for(hep = ht->ihashtable + index; (he = *hep)!=0; ){
|
|
if(hvalue(ht,he)->expires < conf.time || !memcmp(hash, hhash(ht,he), ht->hash_size)) {
|
|
(*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);
|
|
last = he;
|
|
}
|
|
}
|
|
|
|
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(hhash(ht,hen), hash, ht->hash_size);
|
|
memcpy(hvalue(ht,hen)->value, value, ht->recsize);
|
|
hvalue(ht,hen)->expires = expires;
|
|
}
|
|
|
|
pthread_mutex_unlock(&hash_mutex);
|
|
}
|
|
|
|
int hashresolv(struct hashtable *ht, void* name, void* value, uint32_t *ttl){
|
|
uint8_t hash[MAX_HASH_SIZE];
|
|
uint32_t *hep;
|
|
uint32_t he;
|
|
uint32_t index;
|
|
|
|
if(!ht || !ht->ihashtable || !name) {
|
|
return 0;
|
|
}
|
|
ht->index2hash_search(ht,name, hash);
|
|
pthread_mutex_lock(&hash_mutex);
|
|
index = hashindex(ht->tablesize, hash);
|
|
for(hep = ht->ihashtable + index; (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 if(!memcmp(hash, hhash(ht,he), ht->hash_size)){
|
|
if(ttl) *ttl = (uint32_t)(hvalue(ht,he)->expires - conf.time);
|
|
memcpy(value, hvalue(ht,he)->value, ht->recsize);
|
|
pthread_mutex_unlock(&hash_mutex);
|
|
return 1;
|
|
}
|
|
else hep=&(hvalue(ht,he)->inext);
|
|
}
|
|
pthread_mutex_unlock(&hash_mutex);
|
|
return 0;
|
|
}
|
|
|
|
static void char_index2hash(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
char* name = index;
|
|
|
|
blake2b(hash, ht->hash_size, index, strlen((const char*)index), NULL, 0);
|
|
}
|
|
|
|
static void param2hash_add(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
blake2b_state S;
|
|
struct clientparam *param = (struct clientparam *)index;
|
|
unsigned type = param->srv->authcachetype;
|
|
|
|
blake2b_init(&S, ht->hash_size);
|
|
if((type & 2) && param->username)blake2b_update(&S, param->username, strlen((const char *)param->username) + 1);
|
|
if((type & 4) && param->password)blake2b_update(&S, param->password, strlen((const char *)param->password) + 1);
|
|
if((type & 1) && !(type & 8))blake2b_update(&S, SAADDR(¶m->sincr), SAADDRLEN(¶m->sincr));
|
|
if((type & 16))blake2b_update(&S, ¶m->srv->acl, sizeof(param->srv->acl));
|
|
if((type & 64))blake2b_update(&S, SAADDR(¶m->req), SAADDRLEN(¶m->req));
|
|
if((type & 128))blake2b_update(&S, SAPORT(¶m->req), 2);
|
|
if((type & 256) && param->hostname)blake2b_update(&S, param->hostname, strlen((const char *)param->hostname) + 1);
|
|
if((type & 512))blake2b_update(&S, ¶m->operation, sizeof(param->operation));
|
|
if((type & 1024))blake2b_update(&S, SAADDR(¶m->srv->intsa), SAADDRLEN(¶m->srv->intsa));
|
|
if((type & 2048))blake2b_update(&S, SAPORT(¶m->srv->intsa), 2);
|
|
blake2b_final(&S, hash, ht->hash_size);
|
|
memcpy(param->hash, hash, ht->hash_size);
|
|
}
|
|
|
|
static void pw2hash_add(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
char ** pw = (char **)index;
|
|
blake2b_state S;
|
|
|
|
blake2b_init(&S, ht->hash_size);
|
|
if(pw[0])blake2b_update(&S, pw[0], strlen(pw[0]) + 1);
|
|
if(pw[1])blake2b_update(&S, pw[1], strlen(pw[1]) + 1);
|
|
blake2b_final(&S, hash, ht->hash_size);
|
|
}
|
|
|
|
|
|
static void pw2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
struct clientparam *param = (struct clientparam *)index;
|
|
|
|
char *pw[2] = {(char *)param->username, (char *)param->password};
|
|
|
|
pw2hash_add(ht, pw, hash);
|
|
}
|
|
|
|
static void pwnt2hash_add(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
char ** pw = (char **)index;
|
|
blake2b_state S;
|
|
|
|
blake2b_init(&S, ht->hash_size);
|
|
if(pw[0])blake2b_update(&S, pw[0], strlen(pw[0]) + 1);
|
|
if(pw[1])blake2b_update(&S, pw[1], strlen(pw[1]) + 1);
|
|
blake2b_final(&S, hash, ht->hash_size);
|
|
}
|
|
|
|
|
|
static void pwnt2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
struct clientparam *param = (struct clientparam *)index;
|
|
unsigned char pass[40];
|
|
char *pw[2] = {(char *)param->username, (char *)pass};
|
|
|
|
ntpwdhash(pass, param->password, 1);
|
|
pwnt2hash_add(ht, pw, hash);
|
|
}
|
|
|
|
void param2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
struct clientparam *param = (struct clientparam *)index;
|
|
|
|
memcpy(hash, param->hash, ht->hash_size);
|
|
}
|
|
|
|
|
|
|
|
static void user2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
|
|
struct clientparam *param = (struct clientparam *)index;
|
|
blake2b(hash, ht->hash_size, param->username, strlen((const char *)param->username), NULL, 0);
|
|
}
|
|
|
|
struct hashtable dns_table = {char_index2hash, char_index2hash, 4, 12};
|
|
struct hashtable dns6_table = {char_index2hash, char_index2hash, 16, 12};
|
|
struct hashtable auth_table = {param2hash_add, param2hash_search, sizeof(struct authcache), 12};
|
|
struct hashtable pw_table = {pw2hash_add, pw2hash_search, 0, 12};
|
|
struct hashtable pwnt_table = {pwnt2hash_add, pwnt2hash_search, 0, 12};
|
|
struct hashtable pwcr_table = {char_index2hash, user2hash_search, 64, 12};
|