Просмотр исходного кода

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

z3APA3A 8 лет назад
Родитель
Сommit
ff91a6fe72
8 измененных файлов с 168 добавлено и 23 удалено
  1. 25 0
      man/3proxy.cfg.3
  2. 1 0
      src/3proxy.c
  3. 63 6
      src/auth.c
  4. 1 0
      src/common.c
  5. 58 15
      src/conf.c
  6. 6 0
      src/proxy.h
  7. 1 0
      src/proxymain.c
  8. 13 2
      src/structures.h

+ 25 - 0
man/3proxy.cfg.3

@@ -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>

+ 1 - 0
src/3proxy.c

@@ -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);

+ 63 - 6
src/auth.c

@@ -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, ""}
 };
 

+ 1 - 0
src/common.c

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

+ 58 - 15
src/conf.c

@@ -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);

+ 6 - 0
src/proxy.h

@@ -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;

+ 1 - 0
src/proxymain.c

@@ -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);

+ 13 - 2
src/structures.h

@@ -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,