Mercurial > syslog2iptables
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); }