connlim / noconnlim commands added to support connection / connectio rate limits

This commit is contained in:
z3APA3A 2018-01-12 19:09:42 +03:00
parent e076fff33c
commit ff91a6fe72
8 changed files with 168 additions and 23 deletions

View File

@ -795,6 +795,31 @@ if you want, for example, to limit all speed ecept access to POP3 you can use
.br
before the rest of bandlim rules.
.br
.B connlim
<rate> <period> <userlist> <sourcelist> <targetlist> <targetportlist> <operationlist>
.br
.B noconnlim
<userlist> <sourcelist> <targetlist> <targetportlist> <operationlist>
.br
connlim sets connections rate limit per time period for traffic
pattern controlled by ACL. Period is in seconds. If period is 0,
connlim limits a number of parallel connections.
.br
connlim 100 60 * 127.0.0.1
.br
allows 100 connections per minute for 127.0.0.1.
.br
connlim 20 0 * 127.0.0.1
.br
allows 20 simulationeous connections for 127.0.0.1.
.br
Like with bandlimin, if individual limit is required per client, separate
rule mustbe added for every client. Like with nobanlimin, noconnlim adds an
exception.
.br
.B counter
<filename> <reporttype> <repotname>

View File

@ -515,6 +515,7 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
pthread_mutex_init(&config_mutex, NULL);
pthread_mutex_init(&bandlim_mutex, NULL);
pthread_mutex_init(&connlim_mutex, NULL);
pthread_mutex_init(&hash_mutex, NULL);
pthread_mutex_init(&tc_mutex, NULL);
pthread_mutex_init(&pwl_mutex, NULL);

View File

@ -437,6 +437,60 @@ int ACLmatches(struct ace* acentry, struct clientparam * param){
return 1;
}
int startconnlims (struct clientparam *param){
struct connlim * ce;
time_t delta;
uint64_t rating;
int ret = 0;
pthread_mutex_lock(&connlim_mutex);
for(ce = conf.connlimiter; ce; ce = ce->next) {
if(ACLmatches(ce->ace, param)){
if(ce->ace->action == NOCONNLIM)break;
if(!ce->period){
if(ce->rate <= ce->rating) {
ret = 1;
break;
}
ce->rating++;
continue;
}
delta = conf.time - ce->basetime;
if(ce->period <= delta || ce->basetime > conf.time){
ce->basetime = conf.time;
ce->rating = 0x100000;
continue;
}
rating = delta? ((ce->rating * (ce->period - delta)) / ce->period) + 0x100000 : ce->rating + 0x100000;
if (rating > (ce->rate<<20)) {
ret = 2;
break;
}
ce->rating = rating;
ce->basetime = conf.time;
}
}
pthread_mutex_unlock(&connlim_mutex);
return ret;
}
void stopconnlims (struct clientparam *param){
struct connlim * ce;
pthread_mutex_lock(&connlim_mutex);
for(ce = conf.connlimiter; ce; ce = ce->next) {
if(ACLmatches(ce->ace, param)){
if(ce->ace->action == NOCONNLIM)break;
if(!ce->period && ce->rating){
ce->rating--;
continue;
}
}
}
pthread_mutex_unlock(&connlim_mutex);
}
static void initbandlims (struct clientparam *param){
struct bandlim * be;
int i;
@ -464,7 +518,7 @@ static void initbandlims (struct clientparam *param){
unsigned bandlimitfunc(struct clientparam *param, unsigned nbytesin, unsigned nbytesout){
unsigned sleeptime = 0, nsleeptime;
unsigned long sec;
time_t sec;
unsigned msec;
unsigned now;
int i;
@ -504,7 +558,7 @@ unsigned bandlimitfunc(struct clientparam *param, unsigned nbytesin, unsigned nb
param->bandlims[i]->nexttime = 0;
continue;
}
now = ((sec - param->bandlims[i]->basetime) * 1000000) + msec;
now = (unsigned)((sec - param->bandlims[i]->basetime) * 1000000) + msec;
nsleeptime = (param->bandlims[i]->nexttime > now)?
param->bandlims[i]->nexttime - now : 0;
sleeptime = (nsleeptime > sleeptime)? nsleeptime : sleeptime;
@ -521,7 +575,7 @@ unsigned bandlimitfunc(struct clientparam *param, unsigned nbytesin, unsigned nb
param->bandlimsout[i]->nexttime = 0;
continue;
}
now = ((sec - param->bandlimsout[i]->basetime) * 1000000) + msec;
now = (unsigned)((sec - param->bandlimsout[i]->basetime) * 1000000) + msec;
nsleeptime = (param->bandlimsout[i]->nexttime > now)?
param->bandlimsout[i]->nexttime - now : 0;
sleeptime = (nsleeptime > sleeptime)? nsleeptime : sleeptime;
@ -571,6 +625,8 @@ int alwaysauth(struct clientparam * param){
struct trafcount * tc;
int countout = 0;
if(conf.connlimiter && param->remsock == INVALID_SOCKET && startconnlims(param)) return 95;
res = doconnect(param);
if(!res){
initbandlims(param);
@ -610,7 +666,7 @@ int checkACL(struct clientparam * param){
struct ace* acentry;
if(!param->srv->acl) {
return alwaysauth(param);
return 0;
}
for(acentry = param->srv->acl; acentry; acentry = acentry->next) {
if(ACLmatches(acentry, param)) {
@ -868,11 +924,12 @@ struct auth authfuncs[] = {
{authfuncs+5, strongauth, checkACL, "strong"},
{authfuncs+6, cacheauth, checkACL, "cache"},
#ifndef NORADIUS
#define AUTHOFFSET 1
{authfuncs+7, radauth, checkACL, "radius"},
{authfuncs+8, NULL, NULL, "none"},
#else
{authfuncs+7, NULL, NULL, "none"},
#define AUTHOFFSET 0
#endif
{authfuncs+7+AUTHOFFSET, NULL, NULL, "none"},
{NULL, NULL, NULL, ""}
};

View File

@ -71,6 +71,7 @@ struct extparam conf = {
NULL, NULL,
NULL,
NULL,
NULL,
#ifdef __FreeBSD__
8192,
#else

View File

@ -19,6 +19,7 @@
#endif
pthread_mutex_t bandlim_mutex;
pthread_mutex_t connlim_mutex;
pthread_mutex_t tc_mutex;
pthread_mutex_t pwl_mutex;
pthread_mutex_t hash_mutex;
@ -1093,6 +1094,7 @@ static int h_ace(int argc, unsigned char **argv){
struct ace *acl = NULL;
struct bandlim * nbl;
struct trafcount * tl;
struct connlim * ncl;
if(!strcmp((char *)argv[0], "allow")){
res = ALLOW;
@ -1125,6 +1127,13 @@ static int h_ace(int argc, unsigned char **argv){
else if(!strcmp((char *)argv[0], "nocountout")){
res = NOCOUNTOUT;
}
else if(!strcmp((char *)argv[0], "connlim")){
res = CONNLIM;
offset = 2;
}
else if(!strcmp((char *)argv[0], "noconnlim")){
res = NOCONNLIM;
}
acl = make_ace(argc - (offset+1), argv + (offset + 1));
if(!acl) {
fprintf(stderr, "Unable to parse ACL entry, line %d\n", linenum);
@ -1155,6 +1164,32 @@ static int h_ace(int argc, unsigned char **argv){
acei->next = acl;
}
break;
case CONNLIM:
case NOCONNLIM:
ncl = myalloc(sizeof(struct connlim));
if(!ncl) {
fprintf(stderr, "No memory to create connection limit filter\n");
return(3);
}
memset(ncl, 0, sizeof(struct connlim));
ncl->ace = acl;
if(acl->action == CONNLIM) {
sscanf((char *)argv[1], "%u", &ncl->rate);
sscanf((char *)argv[2], "%u", &ncl->period);
}
pthread_mutex_lock(&connlim_mutex);
if(!conf.connlimiter){
conf.connlimiter = ncl;
}
else {
struct connlim * cli;
for(cli = conf.connlimiter; cli->next; cli = cli->next);
cli->next = ncl;
}
pthread_mutex_unlock(&connlim_mutex);
break;
case BANDLIM:
case NOBANDLIM:
@ -1460,22 +1495,24 @@ struct commands commandhandlers[]={
{commandhandlers+44, "nocountin", h_ace, 1, 0},
{commandhandlers+45, "countout", h_ace, 4, 0},
{commandhandlers+46, "nocountout", h_ace, 1, 0},
{commandhandlers+47, "plugin", h_plugin, 3, 0},
{commandhandlers+48, "logdump", h_logdump, 2, 3},
{commandhandlers+49, "filtermaxsize", h_filtermaxsize, 2, 2},
{commandhandlers+50, "nolog", h_nolog, 1, 1},
{commandhandlers+51, "weight", h_nolog, 2, 2},
{commandhandlers+52, "authcache", h_authcache, 2, 3},
{commandhandlers+53, "smtpp", h_proxy, 1, 0},
{commandhandlers+54, "icqpr", h_proxy, 4, 0},
{commandhandlers+55, "msnpr", h_proxy, 4, 0},
{commandhandlers+56, "delimchar",h_delimchar, 2, 2},
{commandhandlers+57, "authnserver", h_authnserver, 2, 2},
{commandhandlers+58, "stacksize", h_stacksize, 2, 2},
{commandhandlers+59, "force", h_force, 1, 1},
{commandhandlers+60, "noforce", h_noforce, 1, 1},
{commandhandlers+47, "connlim", h_ace, 4, 0},
{commandhandlers+48, "noconnlim", h_ace, 1, 0},
{commandhandlers+49, "plugin", h_plugin, 3, 0},
{commandhandlers+50, "logdump", h_logdump, 2, 3},
{commandhandlers+51, "filtermaxsize", h_filtermaxsize, 2, 2},
{commandhandlers+52, "nolog", h_nolog, 1, 1},
{commandhandlers+53, "weight", h_nolog, 2, 2},
{commandhandlers+54, "authcache", h_authcache, 2, 3},
{commandhandlers+55, "smtpp", h_proxy, 1, 0},
{commandhandlers+56, "icqpr", h_proxy, 4, 0},
{commandhandlers+57, "msnpr", h_proxy, 4, 0},
{commandhandlers+58, "delimchar",h_delimchar, 2, 2},
{commandhandlers+59, "authnserver", h_authnserver, 2, 2},
{commandhandlers+60, "stacksize", h_stacksize, 2, 2},
{commandhandlers+51, "force", h_force, 1, 1},
{commandhandlers+62, "noforce", h_noforce, 1, 1},
#ifndef NORADIUS
{commandhandlers+61, "radius", h_radius, 3, 0},
{commandhandlers+63, "radius", h_radius, 3, 0},
#endif
{specificcommands, "", h_noop, 1, 0}
};
@ -1644,6 +1681,7 @@ void freepwl(struct passwords *pwl){
void freeconf(struct extparam *confp){
struct bandlim * bl;
struct bandlim * blout;
struct connlim * cl;
struct trafcount * tc;
struct passwords *pw;
struct ace *acl;
@ -1674,6 +1712,10 @@ void freeconf(struct extparam *confp){
confp->bandlimiterout = NULL;
confp->bandlimfunc = NULL;
pthread_mutex_unlock(&bandlim_mutex);
pthread_mutex_lock(&connlim_mutex);
cl = confp->connlimiter;
confp->connlimiter = NULL;
pthread_mutex_unlock(&connlim_mutex);
pthread_mutex_lock(&pwl_mutex);
pw = confp->pwl;
@ -1731,6 +1773,7 @@ void freeconf(struct extparam *confp){
freepwl(pw);
for(; bl; bl = (struct bandlim *) itfree(bl, bl->next)) freeacl(bl->ace);
for(; blout; blout = (struct bandlim *) itfree(blout, blout->next))freeacl(blout->ace);
for(; cl; cl = (struct connlim *) itfree(cl, cl->next)) freeacl(cl->ace);
if(counterd != -1) {
close(counterd);

View File

@ -38,6 +38,8 @@
#define NOCOUNTIN 6
#define COUNTOUT 7
#define NOCOUNTOUT 8
#define CONNLIM 9
#define NOCONNLIM 10
#define UDPBUFSIZE 16384
#define TCPBUFSIZE 8192
@ -206,6 +208,9 @@ void freeparam(struct clientparam * param);
void clearstat(struct clientparam * param);
void dumpcounters(struct trafcount *tl, int counterd);
int startconnlims (struct clientparam *param);
void stopconnlims (struct clientparam *param);
extern struct auth authfuncs[];
@ -319,6 +324,7 @@ struct property;
extern unsigned char tmpbuf[8192];
extern pthread_mutex_t config_mutex;
extern pthread_mutex_t bandlim_mutex;
extern pthread_mutex_t connlim_mutex;
extern pthread_mutex_t hash_mutex;
extern pthread_mutex_t tc_mutex;
extern pthread_mutex_t pwl_mutex;

View File

@ -961,6 +961,7 @@ void freeparam(struct clientparam * param) {
}
myfree(param->filters);
}
if(conf.connlimiter && (param->res != 95 || param->remsock != INVALID_SOCKET)) stopconnlims(param);
#endif
if(param->clibuf) myfree(param->clibuf);
if(param->srvbuf) myfree(param->srvbuf);

View File

@ -299,11 +299,21 @@ struct ace {
struct bandlim {
struct bandlim *next;
struct ace *ace;
unsigned basetime;
unsigned rate;
time_t basetime;
unsigned nexttime;
unsigned rate;
};
struct connlim {
struct connlim *next;
struct ace *ace;
time_t basetime;
uint64_t rating;
unsigned period;
unsigned rate;
};
typedef enum {NONE, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, ANNUALLY, NEVER} ROTATION;
struct schedule {
@ -528,6 +538,7 @@ struct extparam {
struct ace * acl;
char * conffile;
struct bandlim * bandlimiter, *bandlimiterout;
struct connlim * connlimiter;
struct trafcount * trafcounter;
struct srvparam *services;
int stacksize,