Mercurial > syslog2iptables
comparison src/syslogconfig.cpp @ 4:2737ab01659a
initial coding
author | carl |
---|---|
date | Thu, 01 Dec 2005 17:17:37 -0800 |
parents | 8fe310e5cd44 |
children | 276c4edc8521 |
comparison
equal
deleted
inserted
replaced
3:8fe310e5cd44 | 4:2737ab01659a |
---|---|
22 #include <fcntl.h> | 22 #include <fcntl.h> |
23 #include <sys/socket.h> | 23 #include <sys/socket.h> |
24 #include <netinet/in.h> | 24 #include <netinet/in.h> |
25 #include <arpa/inet.h> | 25 #include <arpa/inet.h> |
26 #include <netdb.h> | 26 #include <netdb.h> |
27 | 27 #include <limits.h> |
28 static char* syslogconfig_version="$Id$"; | 28 |
29 static char* syslogconfig_version = "$Id$"; | |
30 static char* iptables = "/sbin/iptables"; | |
29 | 31 |
30 char *token_bucket; | 32 char *token_bucket; |
31 char *token_file; | 33 char *token_file; |
32 char *token_ignore; | 34 char *token_ignore; |
33 char *token_include; | 35 char *token_include; |
45 { | 47 { |
46 return (unsigned)s1 < (unsigned)s2; | 48 return (unsigned)s1 < (unsigned)s2; |
47 } | 49 } |
48 }; | 50 }; |
49 | 51 |
52 struct bucket { | |
53 int count; | |
54 bool latch; // true iff ever count>threshold | |
55 }; | |
56 | |
50 string_set all_strings; // owns all the strings, only modified by the config loader thread | 57 string_set all_strings; // owns all the strings, only modified by the config loader thread |
51 const int maxlen = 1000; // used for snprintf buffers | 58 const int maxlen = 1000; // used for snprintf buffers |
52 typedef map<int, int, ltint> ip_buckets; | 59 typedef map<int, bucket, ltint> ip_buckets; |
53 | 60 |
54 class IPR { | 61 class IPR { |
55 ip_buckets violations; | 62 ip_buckets violations; |
56 public: | 63 public: |
57 void add(int ip, int bucket, CONFIG &con); | 64 void add(int ip, int amount, CONFIG &con); |
58 void changed(CONFIG &con); | 65 void changed(CONFIG &con); |
59 void leak(int amount, CONFIG &con); | 66 void leak(int amount, CONFIG &con); |
60 }; | 67 }; |
61 | 68 |
62 IPR recorder; | 69 IPR recorder; |
63 | 70 |
64 | 71 |
65 //////////////////////////////////////////////// | 72 //////////////////////////////////////////////// |
66 // | 73 // |
67 void IPR::add(int ip, int bucket, CONFIG &con) { | 74 void IPR::add(int ip, int amount, CONFIG &con) { |
68 if (con.looking(ip)) { | 75 if (con.looking(ip)) { |
69 ip_buckets::iterator i = violations.find(ip); | 76 ip_buckets::iterator i = violations.find(ip); |
70 if (i == violations.end()) violations[ip] = bucket; | 77 if (i == violations.end()) { |
78 bucket b; | |
79 b.count = amount; | |
80 b.latch = false; | |
81 violations[ip] = b; | |
82 } | |
71 else { | 83 else { |
72 (*i).second += bucket; | 84 bucket &b = (*i).second; |
73 if ((*i).second > con.get_threshold()) changed(con); | 85 if (b.count < (INT_MAX-amount)) { |
86 int t = con.get_threshold(); | |
87 int c = b.count; | |
88 b.count += amount; | |
89 if ((!b.latch) && (c < t) && (t <= b.count)) { | |
90 b.latch = true; | |
91 changed(con); | |
92 } | |
93 } | |
74 } | 94 } |
75 } | 95 } |
76 } | 96 } |
77 | 97 |
78 | 98 |
79 void IPR::leak(int amount, CONFIG &con) { | 99 void IPR::leak(int amount, CONFIG &con) { |
80 bool ch = false; | 100 bool ch = false; |
81 for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); ) { | 101 for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); ) { |
82 int ip = (*i).first; | 102 int ip = (*i).first; |
83 int n = (*i).second; | 103 bucket &b = (*i).second; |
84 in_addr ad; | 104 // in_addr ad; |
85 ad.s_addr = htonl(ip); | 105 // ad.s_addr = htonl(ip); |
86 char buf[maxlen]; | 106 // char buf[maxlen]; |
87 snprintf(buf, maxlen, "leak %s with %d count", inet_ntoa(ad), n); | 107 // snprintf(buf, maxlen, "leak %s with %d count", inet_ntoa(ad), n); |
88 my_syslog(buf); | 108 // my_syslog(buf); |
89 if (n <= amount) { | 109 if (b.count <= amount) { |
90 ch = true; | 110 ch |= b.latch; |
91 violations.erase(i++); | 111 violations.erase(i++); |
92 } | 112 } |
93 else { | 113 else { |
94 (*i).second -= amount; | 114 b.count -= amount; |
95 i++; | 115 i++; |
96 } | 116 } |
97 } | 117 } |
98 if (ch) changed(con); | 118 if (ch) changed(con); |
99 } | 119 } |
100 | 120 |
101 | 121 |
102 void IPR::changed(CONFIG &con) { | 122 void IPR::changed(CONFIG &con) { |
103 my_syslog("**** dump"); | 123 char buf[maxlen]; |
124 snprintf(buf, maxlen, "%s -F INPUT", iptables); | |
125 my_syslog(" "); | |
126 my_syslog(buf); | |
104 for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); i++) { | 127 for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); i++) { |
105 int ip = (*i).first; | 128 int ip = (*i).first; |
106 int n = (*i).second; | 129 bucket &b = (*i).second; |
107 in_addr ad; | 130 if (b.count > con.get_threshold()) { |
108 ad.s_addr = htonl(ip); | 131 in_addr ad; |
109 char buf[maxlen]; | 132 ad.s_addr = htonl(ip); |
110 snprintf(buf, maxlen, "%s with %d count", inet_ntoa(ad), n); | 133 snprintf(buf, maxlen, "count=%d %s -A INPUT --src %s --jump DROP", b.count, iptables, inet_ntoa(ad)); |
111 my_syslog(buf); | 134 my_syslog(buf); |
135 } | |
112 } | 136 } |
113 } | 137 } |
114 | 138 |
115 | 139 |
116 //////////////////////////////////////////////// | 140 //////////////////////////////////////////////// |
128 } | 152 } |
129 | 153 |
130 | 154 |
131 //////////////////////////////////////////////// | 155 //////////////////////////////////////////////// |
132 // | 156 // |
133 PATTERN::PATTERN(TOKEN &tok, char *pattern_, int index_, int bucket_) { | 157 PATTERN::PATTERN(TOKEN &tok, char *pattern_, int index_, int amount_) { |
134 pattern = pattern_; | 158 pattern = pattern_; |
135 index = index_; | 159 index = index_; |
136 bucket = bucket_; | 160 amount = amount_; |
137 if (pattern) { | 161 if (pattern) { |
138 int rc = regcomp(&re, pattern, REG_ICASE | REG_EXTENDED); | 162 int rc = regcomp(&re, pattern, REG_ICASE | REG_EXTENDED); |
139 if (rc) { | 163 if (rc) { |
140 char bu[maxlen]; | 164 char bu[maxlen]; |
141 regerror(rc, &re, bu, maxlen); | 165 regerror(rc, &re, bu, maxlen); |
162 int e = match[index].rm_eo; | 186 int e = match[index].rm_eo; |
163 // char bu[maxlen]; | 187 // char bu[maxlen]; |
164 // snprintf(bu, maxlen, "re match from %d to %d", s, e); | 188 // snprintf(bu, maxlen, "re match from %d to %d", s, e); |
165 // my_syslog(bu); | 189 // my_syslog(bu); |
166 if (s != -1) { | 190 if (s != -1) { |
167 my_syslog(buf); | |
168 buf[e] = '\0'; | 191 buf[e] = '\0'; |
169 int ip = ip_address(buf+s); | 192 int ip = ip_address(buf+s); |
170 if (ip) { | 193 if (ip) { |
171 my_syslog(buf+s); | 194 recorder.add(ip, amount, con); |
172 recorder.add(ip, bucket, con); | |
173 } | 195 } |
174 return true; | 196 return true; |
175 } | 197 } |
176 } | 198 } |
177 } | 199 } |
184 int i = min(maxlen-1, level*4); | 206 int i = min(maxlen-1, level*4); |
185 memset(indent, ' ', i); | 207 memset(indent, ' ', i); |
186 indent[i] = '\0'; | 208 indent[i] = '\0'; |
187 printf("%s pattern \"%s\" {; \n", indent, pattern); | 209 printf("%s pattern \"%s\" {; \n", indent, pattern); |
188 printf("%s index %d; \n", indent, index); | 210 printf("%s index %d; \n", indent, index); |
189 printf("%s bucket %d; \n", indent, bucket); | 211 printf("%s bucket %d; \n", indent, amount); |
190 printf("%s }; \n", indent); | 212 printf("%s }; \n", indent); |
191 } | 213 } |
192 | 214 |
193 | 215 |
194 //////////////////////////////////////////////// | 216 //////////////////////////////////////////////// |
243 bool have = false; | 265 bool have = false; |
244 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { | 266 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { |
245 SYSLOGCONFIGP c = *i; | 267 SYSLOGCONFIGP c = *i; |
246 have |= c->read(*this); | 268 have |= c->read(*this); |
247 } | 269 } |
248 break; //!! | |
249 if (!have) break; | 270 if (!have) break; |
250 } | 271 } |
251 } | 272 } |
252 | 273 |
253 | 274 |
254 void CONFIG::sleep(int duration) { | 275 void CONFIG::sleep(int duration, time_t &previous) { |
255 ::sleep(duration); | 276 ::sleep(duration); |
256 recorder.leak(duration, *this); | 277 time_t now = time(NULL); |
278 recorder.leak(now-previous, *this); | |
279 previous = now; | |
257 } | 280 } |
258 | 281 |
259 | 282 |
260 bool CONFIG::looking(int ip) { | 283 bool CONFIG::looking(int ip) { |
261 for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) { | 284 for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) { |
266 } | 289 } |
267 | 290 |
268 //////////////////////////////////////////////// | 291 //////////////////////////////////////////////// |
269 // | 292 // |
270 SYSLOGCONFIG::SYSLOGCONFIG(TOKEN &tok, char *file_name_) { | 293 SYSLOGCONFIG::SYSLOGCONFIG(TOKEN &tok, char *file_name_) { |
294 tokp = &tok; | |
271 file_name = file_name_; | 295 file_name = file_name_; |
272 fd = open(file_name, O_RDONLY); | 296 open(true); |
273 len = 0; | |
274 if (fd == -1) { | |
275 char buf[maxlen]; | |
276 snprintf(buf, sizeof(buf), "syslog file %s not readable", file_name); | |
277 tok.token_error(buf); | |
278 } | |
279 else { | |
280 //lseek(fd, 0, SEEK_END); //!! | |
281 } | |
282 } | 297 } |
283 | 298 |
284 | 299 |
285 SYSLOGCONFIG::~SYSLOGCONFIG() { | 300 SYSLOGCONFIG::~SYSLOGCONFIG() { |
286 if (fd != -1) close(fd); | 301 close(); |
287 fd = -1; | |
288 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { | 302 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { |
289 PATTERN *p = *i; | 303 PATTERN *p = *i; |
290 delete p; | 304 delete p; |
291 } | 305 } |
292 } | 306 } |
293 | 307 |
294 | 308 |
295 void SYSLOGCONFIG::add_pattern(PATTERNP pat) { | 309 void SYSLOGCONFIG::open(bool msg) { |
296 patterns.push_back(pat); | 310 fd = ::open(file_name, O_RDONLY); |
311 len = 0; | |
312 if (fd == -1) { | |
313 if (msg) { | |
314 char buf[maxlen]; | |
315 snprintf(buf, sizeof(buf), "syslog file %s not readable", file_name); | |
316 tokp->token_error(buf); | |
317 } | |
318 } | |
319 else { | |
320 lseek(fd, 0, SEEK_END); | |
321 if (fstat(fd, &openfdstat)) { | |
322 close(); | |
323 char buf[maxlen]; | |
324 snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", file_name); | |
325 tokp->token_error(buf); | |
326 } | |
327 } | |
297 } | 328 } |
298 | 329 |
299 | 330 |
300 bool SYSLOGCONFIG::read(CONFIG &con) { | 331 bool SYSLOGCONFIG::read(CONFIG &con) { |
301 if (failed()) return false; | 332 if (failed()) { |
333 open(false); | |
334 if (failed()) return false; | |
335 } | |
302 int n = ::read(fd, buf+len, buflen-len); | 336 int n = ::read(fd, buf+len, buflen-len); |
303 bool have = (n > 0); | 337 bool have = (n > 0); |
304 if (have) { | 338 if (have) { |
305 len += n; | 339 len += n; |
306 while (true) { | 340 while (true) { |
313 memmove(buf, p+1, len); | 347 memmove(buf, p+1, len); |
314 } | 348 } |
315 // no <lf> in a full buffer | 349 // no <lf> in a full buffer |
316 if (len == buflen) len = 0; | 350 if (len == buflen) len = 0; |
317 } | 351 } |
352 else { | |
353 // check for file close | |
354 struct stat filenamest; | |
355 if (0 == stat(file_name, &filenamest)) { | |
356 if ((filenamest.st_dev != openfdstat.st_dev) || | |
357 (filenamest.st_ino != openfdstat.st_ino)) { | |
358 close(); | |
359 } | |
360 } | |
361 else { | |
362 // filename no longer exists | |
363 close(); | |
364 } | |
365 | |
366 } | |
318 return have; | 367 return have; |
368 } | |
369 | |
370 | |
371 void SYSLOGCONFIG::close() { | |
372 if (fd != -1) ::close(fd); | |
373 fd = -1; | |
374 } | |
375 | |
376 | |
377 void SYSLOGCONFIG::add_pattern(PATTERNP pat) { | |
378 patterns.push_back(pat); | |
319 } | 379 } |
320 | 380 |
321 | 381 |
322 void SYSLOGCONFIG::process(CONFIG &con) { | 382 void SYSLOGCONFIG::process(CONFIG &con) { |
323 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { | 383 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { |
334 indent[i] = '\0'; | 394 indent[i] = '\0'; |
335 char buf[maxlen]; | 395 char buf[maxlen]; |
336 printf("%s file \"%s\" {\n", indent, file_name); | 396 printf("%s file \"%s\" {\n", indent, file_name); |
337 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { | 397 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { |
338 PATTERN *p = *i; | 398 PATTERN *p = *i; |
339 p->dump(level); | 399 p->dump(level+1); |
340 } | 400 } |
341 printf("%s }; \n", indent); | 401 printf("%s }; \n", indent); |
342 } | 402 } |
343 | 403 |
344 | 404 |