Mercurial > syslog2iptables
diff src/syslogconfig.cpp @ 51:206448c00b55 stable-1-0-12
Allow multiple contexts with independent add/remove commands.
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Sat, 24 Jan 2009 15:52:20 -0800 |
parents | ba0259c9e411 |
children | b45dddebe8fc |
line wrap: on
line diff
--- a/src/syslogconfig.cpp Wed Dec 24 18:40:54 2008 -0800 +++ b/src/syslogconfig.cpp Sat Jan 24 15:52:20 2009 -0800 @@ -16,6 +16,7 @@ const char *token_add; const char *token_bucket; +const char *token_context; const char *token_file; const char *token_ignore; const char *token_include; @@ -28,40 +29,38 @@ const char *token_semi; const char *token_slash; const char *token_threshold; - -struct ltint -{ - bool operator()(const int s1, const int s2) const - { - return (unsigned)s1 < (unsigned)s2; - } -}; - -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 +recorder_map recorders; // all the recorders are named const int maxlen = 1000; // used for snprintf buffers -typedef map<int, bucket, ltint> ip_buckets; - -class IPR { - ip_buckets violations; -public: - void add(int ip, int amount, CONFIG &con, const char *file_name, int pattern_index, const char *message); - void leak(int amount, CONFIG &con); - void free_all(CONFIG &con); - void update(int ip, bool added, const char *file_name, int pattern_index, const char *message); - void changed(CONFIG &con, int ip, bool added); -}; - -IPR recorder; //////////////////////////////////////////////// // -void IPR::add(int ip, int amount, CONFIG &con, const char *file_name, int pattern_index, const char *message) { + +IPR::IPR() { + reference_count = 0; +} + +IPR* IPR::find(const char* name) { + recorder_map::iterator m = recorders.find(name); + if (m == recorders.end()) recorders[name] = new IPR; + recorders[name]->reference(1); + return recorders[name]; +} + + +void IPR::release(const char* name) { + recorder_map::iterator m = recorders.find(name); + IPR* i = (*m).second; + int r = i->reference(-1); + if (r == 0) { + delete i; + recorders.erase(m); + } +} + + +void IPR::add(int ip, int amount, CONTEXT &con, const char *file_name, int pattern_index, const char *message) { if (con.looking(ip)) { ip_buckets::iterator i = violations.find(ip); if (i == violations.end()) { @@ -91,7 +90,7 @@ } -void IPR::leak(int amount, CONFIG &con) { +void IPR::leak(int amount, CONTEXT &con) { for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); ) { int ip = (*i).first; bucket &b = (*i).second; @@ -110,7 +109,7 @@ } -void IPR::free_all(CONFIG &con) { +void IPR::free_all(CONTEXT &con) { if (debug_syslog > 2) { my_syslog("syslog2iptables shutting down"); } @@ -141,7 +140,7 @@ } -void IPR::changed(CONFIG &con, int ip, bool added) { +void IPR::changed(CONTEXT &con, int ip, bool added) { int t = con.get_threshold(); char buf[maxlen]; if (added) { @@ -203,7 +202,7 @@ } -bool PATTERN::process(char *buf, CONFIG &con, const char *file_name, int pattern_index) { +bool PATTERN::process(char *buf, CONTEXT &con, const char *file_name, int pattern_index) { if (pattern) { const int nmatch = index+1; regmatch_t match[nmatch]; @@ -217,7 +216,7 @@ buf[e] = '\0'; int ip = ip_address(buf+s); if (ip) { - recorder.add(ip, amount, con, file_name, pattern_index, message); + con.recorder->add(ip, amount, con, file_name, pattern_index, message); } return true; } @@ -242,58 +241,65 @@ //////////////////////////////////////////////// // -CONFIG::CONFIG() { - reference_count = 0; - generation = 0; - load_time = 0; +CONTEXT::CONTEXT(const char *nam) { + name = nam; threshold = 500; add_command = "/sbin/iptables -I INPUT --src %s --jump DROP"; remove_command = "/sbin/iptables -D INPUT --src %s --jump DROP"; + recorder = IPR::find(name); } -CONFIG::~CONFIG() { +//////////////////////////////////////////////// +// +CONTEXT::~CONTEXT() { + ignore.clear(); for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { SYSLOGCONFIG *c = *i; delete c; } - ignore.clear(); + IPR::release(name); } -void CONFIG::add_syslogconfig(SYSLOGCONFIGP con) { +void CONTEXT::add_syslogconfig(SYSLOGCONFIGP con) { syslogconfigs.push_back(con); } -void CONFIG::add_pair(IPPAIR pair) { +void CONTEXT::add_pair(IPPAIR pair) { ignore.push_back(pair); } -void CONFIG::dump() { - printf(" threshold %d; \n\n", threshold); +void CONTEXT::dump() { + string indents(" "); + const char *indent = indents.c_str(); - printf(" add_command \"%s\"; \n", add_command); - printf(" remove_command \"%s\"; \n\n", remove_command); + printf("context %s {\n", name); + printf("%s threshold %d; \n\n", indent, threshold); - printf(" ignore { \n"); + printf("%s add_command \"%s\"; \n", indent, add_command); + printf("%s remove_command \"%s\"; \n\n", indent, remove_command); + + printf("%s ignore { \n", indent); for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) { IPPAIR &p = *i; in_addr ip; ip.s_addr = htonl(p.first); - printf(" %s/%d; \n", inet_ntoa(ip), p.cidr); + printf("%s %s/%d; \n", indent, inet_ntoa(ip), p.cidr); } - printf(" }; \n\n"); + printf("%s }; \n\n", indent); for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { SYSLOGCONFIGP c = *i; - c->dump(0); + c->dump(1); } + printf("}; \n\n"); } -void CONFIG::read() { +void CONTEXT::read(CONFIG &con) { while (true) { bool have = false; for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { @@ -305,19 +311,18 @@ } -void CONFIG::sleep(int duration, time_t &previous) { - ::sleep(duration); - time_t now = time(NULL); - recorder.leak(now-previous, *this); - previous = now; +void CONTEXT::free_all() { + recorder->free_all(*this); } -void CONFIG::free_all() { - recorder.free_all(*this); +void CONTEXT::leak(int delta) { + recorder->leak(delta, *this); + } -bool CONFIG::looking(int ip) { + +bool CONTEXT::looking(int ip) { for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) { IPPAIR &p = *i; if ((p.first <= ip) && (ip <= p.last)) return false; @@ -327,6 +332,58 @@ //////////////////////////////////////////////// // +CONFIG::CONFIG() { + reference_count = 0; + generation = 0; + load_time = 0; +} + + +CONFIG::~CONFIG() { + for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { + CONTEXT *c = *i; + delete c; + } +} + + +void CONFIG::dump() { + for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { + CONTEXTP c = *i; + c->dump(); + } +} + + +void CONFIG::read() { + for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { + CONTEXT *c = *i; + c->read(*this); + } +} + + +void CONFIG::sleep(int duration, time_t &previous) { + ::sleep(duration); + time_t now = time(NULL); + for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { + CONTEXT *c = *i; + c->leak(now-previous); + } + previous = now; +} + + +void CONFIG::free_all() { + for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { + CONTEXT *c = *i; + c->free_all(); + } +} + + +//////////////////////////////////////////////// +// SYSLOGCONFIG::SYSLOGCONFIG(TOKEN &tok, const char *file_name_) { tokp = &tok; file_name = file_name_; @@ -374,7 +431,7 @@ } -bool SYSLOGCONFIG::read(CONFIG &con) { +bool SYSLOGCONFIG::read(CONTEXT &con) { if (failed()) { open(false); if (failed()) return false; @@ -428,7 +485,7 @@ } -void SYSLOGCONFIG::process(CONFIG &con) { +void SYSLOGCONFIG::process(CONTEXT &con) { int pi=0; for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { PATTERN *p = *i; @@ -504,8 +561,8 @@ //////////////////////////////////////////////// // -bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con); -bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con) { +bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con, CONTEXT &me); +bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con, CONTEXT &me) { const char *pat = tok.next(); int ind = 0; int buc = 0; @@ -543,8 +600,8 @@ //////////////////////////////////////////////// // -bool parse_ignore(TOKEN &tok, CONFIG &dc); -bool parse_ignore(TOKEN &tok, CONFIG &dc) { +bool parse_ignore(TOKEN &tok, CONFIG &dc, CONTEXT &me); +bool parse_ignore(TOKEN &tok, CONFIG &dc, CONTEXT &me) { if (!tsa(tok, token_lbrace)) return false; while (true) { const char *have = tok.next(); @@ -600,7 +657,36 @@ pair.first = ipaddr; pair.last = ipaddr | masks[mask]; pair.cidr = mask; - dc.add_pair(pair); + me.add_pair(pair); + } + if (!tsa(tok, token_semi)) return false; + return true; +} + + +//////////////////////////////////////////////// +// +bool parse_syslogconfig(TOKEN &tok, CONFIG &dc, CONTEXT &me); +bool parse_syslogconfig(TOKEN &tok, CONFIG &dc, CONTEXT &me) { + const char *name = tok.next(); + if (!tsa(tok, token_lbrace)) return false; + SYSLOGCONFIGP con = new SYSLOGCONFIG(tok, name); + if (con->failed()) { + delete con; + return false; + } + me.add_syslogconfig(con); + while (true) { + const char *have = tok.next(); + if (!have) break; + if (have == token_rbrace) break; + if (have == token_pattern) { + if (!parse_pattern(tok, *con, me)) return false; + } + else { + tok.token_error("pattern", have); + return false; + } } if (!tsa(tok, token_semi)) return false; return true; @@ -609,29 +695,47 @@ //////////////////////////////////////////////// // -bool parse_syslogconfig(TOKEN &tok, CONFIG &dc); -bool parse_syslogconfig(TOKEN &tok, CONFIG &dc) { +bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent); +bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) { const char *name = tok.next(); if (!tsa(tok, token_lbrace)) return false; - SYSLOGCONFIGP con = new SYSLOGCONFIG(tok, name); - if (con->failed()) { + CONTEXTP con = new CONTEXT(name); + + while (true) { + const char *have = tok.next(); + if (!have) break; + if (have == token_rbrace) break; // done + if (have == token_threshold) { + have = tok.next(); + con->set_threshold(atoi(have)); + if (!tsa(tok, token_semi)) return false; + } + else if (have == token_ignore) { + if (!parse_ignore(tok, dc, *con)) return false; + } + else if (have == token_add) { + have = tok.next(); + con->set_add(have); + if (!tsa(tok, token_semi)) return false; + } + else if (have == token_remove) { + have = tok.next(); + con->set_remove(have); + if (!tsa(tok, token_semi)) return false; + } + else if (have == token_file) { + if (!parse_syslogconfig(tok, dc, *con)) return false; + } + else { + tok.token_error("threshold/ignore/add_command/remove_command/file", have); + return false; + } + } + if (!tsa(tok, token_semi)) { delete con; return false; } - dc.add_syslogconfig(con); - while (true) { - const char *have = tok.next(); - if (!have) break; - if (have == token_rbrace) break; - if (have == token_pattern) { - if (!parse_pattern(tok, *con)) return false; - } - else { - tok.token_error("pattern", have); - return false; - } - } - if (!tsa(tok, token_semi)) return false; + dc.add_context(con); return true; } @@ -645,35 +749,20 @@ while (true) { const char *have = tok.next(); if (!have) break; - if (have == token_threshold) { - have = tok.next(); - dc.set_threshold(atoi(have)); - if (!tsa(tok, token_semi)) return false; - } - else if (have == token_ignore) { - if (!parse_ignore(tok, dc)) return false; + if (have == token_context) { + if (!parse_context(tok, dc, NULL)) { + tok.token_error("load_conf() failed to parse context"); + return false; } - else if (have == token_add) { - have = tok.next(); - dc.set_add(have); - if (!tsa(tok, token_semi)) return false; - } - else if (have == token_remove) { - have = tok.next(); - dc.set_remove(have); - if (!tsa(tok, token_semi)) return false; - } - else if (have == token_file) { - if (!parse_syslogconfig(tok, dc)) return false; - count++; + else count++; } else { - tok.token_error("threshold/ignore/add_command/remove_command/file", have); + tok.token_error(token_context, have); return false; } } - tok.token_error("load_conf() found %d syslog files in %s", count, fn); - return (!dc.syslogconfigs.empty()); + tok.token_error("load_conf() found %d contexts in %s", count, fn); + return (!dc.contexts.empty()); } @@ -683,6 +772,7 @@ void token_init() { token_add = register_string("add_command"); token_bucket = register_string("bucket"); + token_context = register_string("context"); token_file = register_string("file"); token_ignore = register_string("ignore"); token_include = register_string("include");