mirror of
https://github.com/3proxy/3proxy.git
synced 2026-07-16 17:30:11 +08:00
283 lines
7.2 KiB
C
283 lines
7.2 KiB
C
/*
|
|
3APA3A simplest proxy server
|
|
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
|
|
|
please read License Agreement
|
|
|
|
*/
|
|
|
|
#include "proxy.h"
|
|
#include "libs/blake2.h"
|
|
|
|
void initbandlims(struct clientparam *param);
|
|
|
|
int alwaysauth(struct clientparam * param){
|
|
int res;
|
|
struct trafcount * tc;
|
|
int countout = 0;
|
|
|
|
|
|
if(conf.connlimiter && !param->connlim && startconnlims(param)) return 10;
|
|
res = doconnect(param);
|
|
if(!res){
|
|
if(conf.bandlimfunc && (conf.bandlimiter||conf.bandlimiterout)){
|
|
_3proxy_mutex_lock(&bandlim_mutex);
|
|
initbandlims(param);
|
|
_3proxy_mutex_unlock(&bandlim_mutex);
|
|
}
|
|
|
|
if(conf.trafcountfunc && conf.trafcounter) {
|
|
_3proxy_mutex_lock(&tc_mutex);
|
|
for(tc = conf.trafcounter; tc; tc = tc->next) {
|
|
if(tc->disabled) continue;
|
|
if(ACLmatches(tc->ace, param)){
|
|
if(tc->ace->action == NOCOUNTIN) {
|
|
countout = 1;
|
|
break;
|
|
}
|
|
if(tc->ace->action == NOCOUNTALL) break;
|
|
if(tc->ace->action != COUNTIN) {
|
|
countout = 1;
|
|
if(tc->ace->action != COUNTALL) continue;
|
|
}
|
|
if(tc->traflim64 <= tc->traf64) {
|
|
_3proxy_mutex_unlock(&tc_mutex);
|
|
return 10;
|
|
}
|
|
param->trafcountfunc = conf.trafcountfunc;
|
|
param->maxtrafin64 = tc->traflim64 - tc->traf64;
|
|
}
|
|
}
|
|
if(countout)for(tc = conf.trafcounter; tc; tc = tc->next) {
|
|
if(tc->disabled) continue;
|
|
if(ACLmatches(tc->ace, param)){
|
|
if(tc->ace->action == NOCOUNTOUT || tc->ace->action == NOCOUNTALL) break;
|
|
if(tc->ace->action != COUNTOUT && tc->ace->action != COUNTALL) {
|
|
continue;
|
|
}
|
|
if(tc->traflim64 <= tc->traf64) {
|
|
_3proxy_mutex_unlock(&tc_mutex);
|
|
return 10;
|
|
}
|
|
param->trafcountfunc = conf.trafcountfunc;
|
|
param->maxtrafout64 = tc->traflim64 - tc->traf64;
|
|
}
|
|
}
|
|
_3proxy_mutex_unlock(&tc_mutex);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
int cacheauth(struct clientparam * param){
|
|
struct authcache ac;
|
|
uint32_t ttl;
|
|
unsigned type = param->srv->authcachetype;
|
|
|
|
|
|
if(
|
|
((type & 2) && !param->username) ||
|
|
((type & 4) && !param->password) ||
|
|
(
|
|
(type & 1) && *SAFAMILY(¶m->sincr) != AF_INET
|
|
#ifndef NOIPv6
|
|
&& *SAFAMILY(¶m->sincr) != AF_INET6
|
|
#endif
|
|
) || (!hashresolv(&auth_table, param, &ac, &ttl))) {
|
|
return 4;
|
|
}
|
|
if((type & 1) &&(type & 8) &&
|
|
(ac.sincr_family != *SAFAMILY(¶m->sincr) ||
|
|
memcmp(ac.sincr_addr, SAADDR(¶m->sincr), SAADDRLEN(¶m->sincr))
|
|
)) {
|
|
return 10;
|
|
}
|
|
|
|
if(!(type&2) && *ac.username){
|
|
if(param->username) free(param->username);
|
|
param->username = (unsigned char *)strdup((char *)ac.username);
|
|
}
|
|
if((type & 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;
|
|
char * tmp;
|
|
int ret = 0;
|
|
|
|
for(authfuncs=param->srv->authfuncs; authfuncs; authfuncs=authfuncs->next){
|
|
res = authfuncs->authenticate?(*authfuncs->authenticate)(param):0;
|
|
if(!res) {
|
|
if(authfuncs->authorize &&
|
|
(res = (*authfuncs->authorize)(param)))
|
|
return res;
|
|
if(param->srv->authcachetype && authfuncs->authenticate && authfuncs->authenticate != cacheauth && param->username && (!(param->srv->authcachetype&4) || (!param->pwtype && param->password))){
|
|
struct authcache ac={.username=""};
|
|
|
|
if(param->username) {
|
|
strncpy((char *)ac.username, (char *)param->username, 64);
|
|
ac.username[63] = 0;
|
|
}
|
|
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 + param->srv->authcachetime);
|
|
}
|
|
break;
|
|
}
|
|
if(res > ret) ret = res;
|
|
if(ret > 9) return ret;
|
|
}
|
|
if(!res){
|
|
ret = alwaysauth(param);
|
|
if (param->afterauthfilters){
|
|
FILTER_ACTION action;
|
|
|
|
action = handleafterauthflt(param);
|
|
if(action != PASS) return 19;
|
|
}
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int ipauth(struct clientparam * param){
|
|
int res;
|
|
unsigned char *username;
|
|
username = param->username;
|
|
param->username = NULL;
|
|
res = checkACL(param);
|
|
param->username = username;
|
|
return res;
|
|
}
|
|
|
|
int userauth(struct clientparam * param){
|
|
return (param->username)? 0:4;
|
|
}
|
|
|
|
int dnsauth(struct clientparam * param){
|
|
char buf[128];
|
|
char addr[16];
|
|
char dig[]="0123456789abcdef";
|
|
|
|
unsigned u;
|
|
int i;
|
|
|
|
if(*SAFAMILY(¶m->sincr)!=AF_INET){
|
|
char *s = buf;
|
|
for(i=15; i>=0; i--){
|
|
unsigned char c=((unsigned char *)SAADDR(¶m->sincr))[i];
|
|
*s++ = dig[(c&0xf)];
|
|
*s++ = '.';
|
|
*s++ = dig[(c>>4)];
|
|
*s++ = '.';
|
|
}
|
|
sprintf(s, "ip6.arpa");
|
|
}
|
|
else {
|
|
u = ntohl(*(uint32_t *)SAADDR(¶m->sincr));
|
|
|
|
sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
|
|
((u&0x000000FF)),
|
|
((u&0x0000FF00)>>8),
|
|
((u&0x00FF0000)>>16),
|
|
((u&0xFF000000)>>24));
|
|
|
|
}
|
|
if(!udpresolve(*SAFAMILY(¶m->sincr), (unsigned char *)buf, (unsigned char *)addr, NULL, param, 1)) {
|
|
return 3;
|
|
}
|
|
if(memcmp(SAADDR(¶m->sincr), addr, SAADDRLEN(¶m->sincr))) {
|
|
return 3;
|
|
}
|
|
|
|
return param->username? 0:3;
|
|
}
|
|
|
|
int strongauth(struct clientparam * param){
|
|
static char dummy;
|
|
unsigned char buf[256];
|
|
char pass[256] = {0};
|
|
|
|
if (!param->username) return 4;
|
|
if (!param->pwtype && param->password) {
|
|
if (pwl_table.ihashtable && hashresolv(&pwl_table, param->username, pass, NULL)) {
|
|
switch(pass[0]){
|
|
case CL: {
|
|
int pwlen = strlen((char *)param->password);
|
|
if(pwlen > 255) pwlen = 255;
|
|
if((unsigned)pwlen < pwl_table.recsize) {
|
|
if(!strncmp(pass + 1, (char *)param->password, pwl_table.recsize - 1)) return 0;
|
|
} else {
|
|
blake2b_state S;
|
|
unsigned hashsz;
|
|
hashsz = pwl_table.recsize - 1 < 64 ? pwl_table.recsize - 1 : 64;
|
|
memset(buf, 0, pwl_table.recsize - 1);
|
|
blake2b_init(&S, hashsz);
|
|
blake2b_update(&S, param->password, pwlen + 1);
|
|
blake2b_final(&S, buf, hashsz);
|
|
if(!memcmp(pass + 1, buf, pwl_table.recsize - 1)) return 0;
|
|
}
|
|
return 6;
|
|
}
|
|
case CR:
|
|
if (mycrypt(param->password, (unsigned char *)pass + 1, buf) &&
|
|
!strcmp(pass + 1, (char *)buf))
|
|
return 0;
|
|
else return 7;
|
|
#ifdef WITH_SSL
|
|
case NT:
|
|
if(ntpwdhash(buf, param->password, 1) && !strcmp(pass + 1, (char *)buf)) return 0;
|
|
else return 8;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 5;
|
|
}
|
|
|
|
int radauth(struct clientparam * param);
|
|
|
|
struct auth authfuncs[] = {
|
|
{authfuncs+1, NULL, NULL, ""},
|
|
{authfuncs+2, ipauth, NULL, "iponly"},
|
|
{authfuncs+3, userauth, checkACL, "useronly"},
|
|
{authfuncs+4, dnsauth, checkACL, "dnsname"},
|
|
{authfuncs+5, strongauth, checkACL, "strong"},
|
|
{authfuncs+6, cacheauth, checkACL, "cache"},
|
|
{authfuncs+7, cacheauth, NULL, "cacheacl"},
|
|
#ifndef NORADIUS
|
|
#define AUTHOFFSET 1
|
|
{authfuncs+8, radauth, checkACL, "radius"},
|
|
#else
|
|
#define AUTHOFFSET 0
|
|
#endif
|
|
{authfuncs+8+AUTHOFFSET, NULL, NULL, "none"},
|
|
{NULL, NULL, NULL, ""}
|
|
};
|
|
|