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