diff src/syslogconfig.cpp @ 4:2737ab01659a

initial coding
author carl
date Thu, 01 Dec 2005 17:17:37 -0800
parents 8fe310e5cd44
children 276c4edc8521
line wrap: on
line diff
--- a/src/syslogconfig.cpp	Sun Nov 27 21:12:01 2005 -0800
+++ b/src/syslogconfig.cpp	Thu Dec 01 17:17:37 2005 -0800
@@ -24,8 +24,10 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <limits.h>
 
 static char* syslogconfig_version="$Id$";
+static char* iptables = "/sbin/iptables";
 
 char *token_bucket;
 char *token_file;
@@ -47,14 +49,19 @@
   }
 };
 
+struct bucket {
+	int  count;
+	bool latch; // true iff ever count>threshold
+};
+
 string_set	all_strings;	// owns all the strings, only modified by the config loader thread
 const int maxlen = 1000;	// used for snprintf buffers
-typedef map<int, int, ltint>   ip_buckets;
+typedef map<int, bucket, ltint>   ip_buckets;
 
 class IPR {
 	ip_buckets	violations;
 public:
-	void add(int ip, int bucket, CONFIG &con);
+	void add(int ip, int amount, CONFIG &con);
 	void changed(CONFIG &con);
 	void leak(int amount, CONFIG &con);
 };
@@ -64,13 +71,26 @@
 
 ////////////////////////////////////////////////
 //
-void IPR::add(int ip, int bucket, CONFIG &con) {
+void IPR::add(int ip, int amount, CONFIG &con) {
 	if (con.looking(ip)) {
 		ip_buckets::iterator i = violations.find(ip);
-		if (i == violations.end()) violations[ip] = bucket;
+		if (i == violations.end()) {
+			bucket b;
+			b.count = amount;
+			b.latch = false;
+			violations[ip] = b;
+		}
 		else {
-			(*i).second += bucket;
-			if ((*i).second > con.get_threshold()) changed(con);
+			bucket &b = (*i).second;
+			if (b.count < (INT_MAX-amount)) {
+				int t = con.get_threshold();
+				int c = b.count;
+				b.count += amount;
+				if ((!b.latch) && (c < t) && (t <= b.count)) {
+					b.latch = true;
+					changed(con);
+				}
+			}
 		}
 	}
 }
@@ -80,18 +100,18 @@
 	bool ch = false;
 	for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); ) {
 		int ip = (*i).first;
-		int n  = (*i).second;
-		in_addr ad;
-		ad.s_addr = htonl(ip);
-		char buf[maxlen];
-		snprintf(buf, maxlen, "leak %s with %d count", inet_ntoa(ad), n);
-		my_syslog(buf);
-		if (n <= amount) {
-			ch = true;
+		bucket &b = (*i).second;
+	 // in_addr ad;
+	 // ad.s_addr = htonl(ip);
+	 // char buf[maxlen];
+	 // snprintf(buf, maxlen, "leak %s with %d count", inet_ntoa(ad), n);
+	 // my_syslog(buf);
+		if (b.count <= amount) {
+			ch |= b.latch;
 			violations.erase(i++);
 		}
 		else {
-			(*i).second -= amount;
+			b.count -= amount;
 			i++;
 		}
 	}
@@ -100,17 +120,21 @@
 
 
 void IPR::changed(CONFIG &con) {
-	my_syslog("**** dump");
+	char buf[maxlen];
+	snprintf(buf, maxlen, "%s -F INPUT", iptables);
+	my_syslog(" ");
+	my_syslog(buf);
 	for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); i++) {
 		int ip = (*i).first;
-		int n  = (*i).second;
+		bucket &b = (*i).second;
+		if (b.count > con.get_threshold()) {
 		in_addr ad;
 		ad.s_addr = htonl(ip);
-		char buf[maxlen];
-		snprintf(buf, maxlen, "%s with %d count", inet_ntoa(ad), n);
+			snprintf(buf, maxlen, "count=%d %s -A INPUT --src %s --jump DROP", b.count, iptables, inet_ntoa(ad));
 		my_syslog(buf);
 	}
 }
+}
 
 
 ////////////////////////////////////////////////
@@ -130,10 +154,10 @@
 
 ////////////////////////////////////////////////
 //
-PATTERN::PATTERN(TOKEN &tok, char *pattern_, int index_, int bucket_) {
+PATTERN::PATTERN(TOKEN &tok, char *pattern_, int index_, int amount_) {
 	pattern = pattern_;
 	index	= index_;
-	bucket	= bucket_;
+	amount	= amount_;
 	if (pattern) {
 		int rc = regcomp(&re, pattern, REG_ICASE | REG_EXTENDED);
 		if (rc) {
@@ -164,12 +188,10 @@
 		//	snprintf(bu, maxlen, "re match from %d to %d", s, e);
 		//	my_syslog(bu);
 			if (s != -1) {
-				my_syslog(buf);
 				buf[e] = '\0';
 				int ip = ip_address(buf+s);
 				if (ip) {
-					my_syslog(buf+s);
-					recorder.add(ip, bucket, con);
+					recorder.add(ip, amount, con);
 				}
 				return true;
 			}
@@ -186,7 +208,7 @@
 	indent[i] = '\0';
 	printf("%s pattern \"%s\" {; \n", indent, pattern);
 	printf("%s     index %d; \n", indent, index);
-	printf("%s     bucket %d; \n", indent, bucket);
+	printf("%s     bucket %d; \n", indent, amount);
 	printf("%s }; \n", indent);
 }
 
@@ -245,15 +267,16 @@
 			SYSLOGCONFIGP c = *i;
 			have |= c->read(*this);
 		}
-		break;	//!!
 		if (!have) break;
 	}
 }
 
 
-void CONFIG::sleep(int duration) {
+void CONFIG::sleep(int duration, time_t &previous) {
 	::sleep(duration);
-	recorder.leak(duration, *this);
+	time_t now = time(NULL);
+	recorder.leak(now-previous, *this);
+	previous = now;
 }
 
 
@@ -268,23 +291,14 @@
 ////////////////////////////////////////////////
 //
 SYSLOGCONFIG::SYSLOGCONFIG(TOKEN &tok, char *file_name_) {
+	tokp	  = &tok;
 	file_name = file_name_;
-	fd		  = open(file_name, O_RDONLY);
-	len 	  = 0;
-	if (fd == -1) {
-		char buf[maxlen];
-		snprintf(buf, sizeof(buf), "syslog file %s not readable", file_name);
-		tok.token_error(buf);
-	}
-	else {
-		//lseek(fd, 0, SEEK_END);	//!!
-	}
+	open(true);
 }
 
 
 SYSLOGCONFIG::~SYSLOGCONFIG() {
-	if (fd != -1) close(fd);
-	fd = -1;
+	close();
 	for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
 		PATTERN *p = *i;
 		delete p;
@@ -292,13 +306,33 @@
 }
 
 
-void SYSLOGCONFIG::add_pattern(PATTERNP pat) {
-	patterns.push_back(pat);
+void SYSLOGCONFIG::open(bool msg) {
+	fd		  = ::open(file_name, O_RDONLY);
+	len 	  = 0;
+	if (fd == -1) {
+		if (msg) {
+			char buf[maxlen];
+			snprintf(buf, sizeof(buf), "syslog file %s not readable", file_name);
+			tokp->token_error(buf);
+		}
+	}
+	else {
+		lseek(fd, 0, SEEK_END);
+		if (fstat(fd, &openfdstat)) {
+			close();
+			char buf[maxlen];
+			snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", file_name);
+			tokp->token_error(buf);
+		}
+	}
 }
 
 
 bool SYSLOGCONFIG::read(CONFIG &con) {
+	if (failed()) {
+		open(false);
 	if (failed()) return false;
+	}
 	int n = ::read(fd, buf+len, buflen-len);
 	bool have = (n > 0);
 	if (have) {
@@ -315,10 +349,36 @@
 		// no <lf> in a full buffer
 		if (len == buflen) len = 0;
 	}
+	else {
+		// check for file close
+		struct stat filenamest;
+		if (0 == stat(file_name, &filenamest)) {
+			if ((filenamest.st_dev != openfdstat.st_dev) ||
+				(filenamest.st_ino != openfdstat.st_ino)) {
+				close();
+			}
+		}
+		else {
+			// filename no longer exists
+			close();
+		}
+
+	}
 	return have;
 }
 
 
+void SYSLOGCONFIG::close() {
+	if (fd != -1) ::close(fd);
+	fd = -1;
+}
+
+
+void SYSLOGCONFIG::add_pattern(PATTERNP pat) {
+	patterns.push_back(pat);
+}
+
+
 void SYSLOGCONFIG::process(CONFIG &con) {
 	for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
 		PATTERN *p = *i;
@@ -336,7 +396,7 @@
 	printf("%s file \"%s\" {\n", indent, file_name);
 	for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
 		PATTERN *p = *i;
-		p->dump(level);
+		p->dump(level+1);
 	}
 	printf("%s }; \n", indent);
 }