comparison src/syslogconfig.cpp @ 36:6a2f26976898

shutdown removes iptables entries that we added
author carl
date Thu, 08 Nov 2007 10:52:56 -0800
parents d2ceebcf6595
children e4eb969dfc4a
comparison
equal deleted inserted replaced
35:d2ceebcf6595 36:6a2f26976898
1 /*************************************************************************** 1 /*
2 * Copyright (C) 2005 by 510 Software Group * 2
3 * * 3 Copyright (c) 2007 Carl Byington - 510 Software Group, released under
4 * * 4 the GPL version 3 or any later version at your choice available at
5 * This program is free software; you can redistribute it and/or modify * 5 http://www.gnu.org/licenses/gpl-3.0.txt
6 * it under the terms of the GNU General Public License as published by * 6
7 * the Free Software Foundation; either version 2 of the License, or * 7 */
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 8
21 #include "includes.h" 9 #include "includes.h"
22 #include <fcntl.h> 10 #include <fcntl.h>
23 #include <sys/socket.h> 11 #include <sys/socket.h>
24 #include <netinet/in.h> 12 #include <netinet/in.h>
45 33
46 struct ltint 34 struct ltint
47 { 35 {
48 bool operator()(const int s1, const int s2) const 36 bool operator()(const int s1, const int s2) const
49 { 37 {
50 return (unsigned)s1 < (unsigned)s2; 38 return (unsigned)s1 < (unsigned)s2;
51 } 39 }
52 }; 40 };
53 41
54 struct bucket { 42 struct bucket {
55 int count; 43 int count;
56 bool latch; // true iff ever count>threshold 44 bool latch; // true iff ever count>threshold
57 }; 45 };
58 46
59 string_set all_strings; // owns all the strings, only modified by the config loader thread 47 string_set all_strings; // owns all the strings, only modified by the config loader thread
60 const int maxlen = 1000; // used for snprintf buffers 48 const int maxlen = 1000; // used for snprintf buffers
61 typedef map<int, bucket, ltint> ip_buckets; 49 typedef map<int, bucket, ltint> ip_buckets;
62 50
63 class IPR { 51 class IPR {
64 ip_buckets violations; 52 ip_buckets violations;
65 public: 53 public:
66 void add(int ip, int amount, CONFIG &con, char *file_name, int pattern_index, char *message); 54 void add(int ip, int amount, CONFIG &con, char *file_name, int pattern_index, char *message);
67 void leak(int amount, CONFIG &con); 55 void leak(int amount, CONFIG &con);
68 void update(int ip, bool added, char *file_name, int pattern_index, char *message); 56 void free_all(CONFIG &con);
69 void changed(CONFIG &con, int ip, bool added); 57 void update(int ip, bool added, char *file_name, int pattern_index, char *message);
58 void changed(CONFIG &con, int ip, bool added);
70 }; 59 };
71 60
72 IPR recorder; 61 IPR recorder;
73 62
74 63
75 //////////////////////////////////////////////// 64 ////////////////////////////////////////////////
76 // 65 //
77 void IPR::add(int ip, int amount, CONFIG &con, char *file_name, int pattern_index, char *message) { 66 void IPR::add(int ip, int amount, CONFIG &con, char *file_name, int pattern_index, char *message) {
78 if (con.looking(ip)) { 67 if (con.looking(ip)) {
79 ip_buckets::iterator i = violations.find(ip); 68 ip_buckets::iterator i = violations.find(ip);
80 if (i == violations.end()) { 69 if (i == violations.end()) {
81 bucket b; 70 bucket b;
82 b.count = amount; 71 b.count = amount;
83 b.latch = (con.get_threshold() <= b.count); 72 b.latch = (con.get_threshold() <= b.count);
84 violations[ip] = b; 73 violations[ip] = b;
85 if (b.latch) { 74 if (b.latch) {
86 update(ip, true, file_name, pattern_index, message); 75 update(ip, true, file_name, pattern_index, message);
87 changed(con, ip, true); 76 changed(con, ip, true);
88 } 77 }
89 } 78 }
90 else { 79 else {
91 bucket &b = (*i).second; 80 bucket &b = (*i).second;
92 if (b.count < (INT_MAX-amount)) { 81 if (b.count < (INT_MAX-amount)) {
93 int t = con.get_threshold(); 82 int t = con.get_threshold();
94 int c = b.count; 83 int c = b.count;
95 b.count += amount; 84 b.count += amount;
96 if ((!b.latch) && (c < t) && (t <= b.count)) { 85 if ((!b.latch) && (c < t) && (t <= b.count)) {
97 b.latch = true; 86 b.latch = true;
98 update(ip, true, file_name, pattern_index, message); 87 update(ip, true, file_name, pattern_index, message);
99 changed(con, ip, true); 88 changed(con, ip, true);
100 } 89 }
101 } 90 }
102 } 91 }
103 } 92 }
104 } 93 }
105 94
106 95
107 void IPR::leak(int amount, CONFIG &con) { 96 void IPR::leak(int amount, CONFIG &con) {
108 for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); ) { 97 for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); ) {
109 int ip = (*i).first; 98 int ip = (*i).first;
110 bucket &b = (*i).second; 99 bucket &b = (*i).second;
111 if (b.count <= amount) { 100 if (b.count <= amount) {
112 if (b.latch) { 101 if (b.latch) {
113 update(ip, false, NULL, 0, NULL); 102 update(ip, false, NULL, 0, NULL);
114 changed(con, ip, false); 103 changed(con, ip, false);
115 } 104 }
116 violations.erase(i++); 105 violations.erase(i++);
117 } 106 }
118 else { 107 else {
119 b.count -= amount; 108 b.count -= amount;
120 i++; 109 i++;
121 } 110 }
122 } 111 }
112 }
113
114
115 void IPR::free_all(CONFIG &con) {
116 for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); i++) {
117 int ip = (*i).first;
118 bucket &b = (*i).second;
119 if (b.latch) {
120 update(ip, false, NULL, 0, NULL);
121 changed(con, ip, false);
122 }
123 }
124 violations.clear();
123 } 125 }
124 126
125 127
126 void IPR::update(int ip, bool added, char *file_name, int pattern_index, char *message) { 128 void IPR::update(int ip, bool added, char *file_name, int pattern_index, char *message) {
127 if (debug_syslog > 2) { 129 if (debug_syslog > 2) {
128 char buf[maxlen]; 130 char buf[maxlen];
129 in_addr ad; 131 in_addr ad;
130 ad.s_addr = htonl(ip); 132 ad.s_addr = htonl(ip);
131 if (added) { 133 if (added) {
132 if (message) snprintf(buf, maxlen, "dropping traffic from/to %s based on %s in %s", inet_ntoa(ad), message, file_name); 134 if (message) snprintf(buf, maxlen, "dropping traffic from/to %s based on %s in %s", inet_ntoa(ad), message, file_name);
133 else snprintf(buf, maxlen, "dropping traffic from/to %s based on pattern match %d in %s", inet_ntoa(ad), pattern_index, file_name); 135 else snprintf(buf, maxlen, "dropping traffic from/to %s based on pattern match %d in %s", inet_ntoa(ad), pattern_index, file_name);
134 } 136 }
135 else snprintf(buf, maxlen, "allowing traffic from/to %s", inet_ntoa(ad)); 137 else snprintf(buf, maxlen, "allowing traffic from/to %s", inet_ntoa(ad));
136 my_syslog(buf); 138 my_syslog(buf);
137 } 139 }
138 } 140 }
139 141
140 142
141 void IPR::changed(CONFIG &con, int ip, bool added) { 143 void IPR::changed(CONFIG &con, int ip, bool added) {
142 int t = con.get_threshold(); 144 int t = con.get_threshold();
143 char buf[maxlen]; 145 char buf[maxlen];
144 if (added) { 146 if (added) {
145 bucket &b = violations[ip]; 147 bucket &b = violations[ip];
146 if (con.looking(ip) && (b.count > t)) { 148 if (con.looking(ip) && (b.count > t)) {
147 in_addr ad; 149 in_addr ad;
148 ad.s_addr = htonl(ip); 150 ad.s_addr = htonl(ip);
149 snprintf(buf, maxlen, con.add_command, inet_ntoa(ad)); 151 snprintf(buf, maxlen, con.add_command, inet_ntoa(ad));
150 system(buf); 152 system(buf);
151 } 153 }
152 } 154 }
153 else { 155 else {
154 in_addr ad; 156 in_addr ad;
155 ad.s_addr = htonl(ip); 157 ad.s_addr = htonl(ip);
156 snprintf(buf, maxlen, con.remove_command, inet_ntoa(ad)); 158 snprintf(buf, maxlen, con.remove_command, inet_ntoa(ad));
157 system(buf); 159 system(buf);
158 } 160 }
159 } 161 }
160 162
161 163
162 //////////////////////////////////////////////// 164 ////////////////////////////////////////////////
163 // 165 //
164 int ip_address(char *have); 166 int ip_address(char *have);
165 int ip_address(char *have) { 167 int ip_address(char *have) {
166 int ipaddr = 0; 168 int ipaddr = 0;
167 in_addr ip; 169 in_addr ip;
168 if (inet_aton(have, &ip)) ipaddr = ip.s_addr; 170 if (inet_aton(have, &ip)) ipaddr = ip.s_addr;
169 else { 171 else {
170 struct hostent *host = gethostbyname(have); 172 struct hostent *host = gethostbyname(have);
171 if (host && host->h_addrtype == AF_INET) memcpy(&ipaddr, host->h_addr, sizeof(ipaddr)); 173 if (host && host->h_addrtype == AF_INET) memcpy(&ipaddr, host->h_addr, sizeof(ipaddr));
172 } 174 }
173 return ntohl(ipaddr); 175 return ntohl(ipaddr);
174 } 176 }
175 177
176 178
177 //////////////////////////////////////////////// 179 ////////////////////////////////////////////////
178 // 180 //
179 PATTERN::PATTERN(TOKEN &tok, char *pattern_, int index_, int amount_, char *msg_) { 181 PATTERN::PATTERN(TOKEN &tok, char *pattern_, int index_, int amount_, char *msg_) {
180 pattern = pattern_; 182 pattern = pattern_;
181 index = index_; 183 index = index_;
182 amount = amount_; 184 amount = amount_;
183 message = msg_; 185 message = msg_;
184 if (pattern) { 186 if (pattern) {
185 int rc = regcomp(&re, pattern, REG_ICASE | REG_EXTENDED); 187 int rc = regcomp(&re, pattern, REG_ICASE | REG_EXTENDED);
186 if (rc) { 188 if (rc) {
187 char bu[maxlen]; 189 char bu[maxlen];
188 regerror(rc, &re, bu, maxlen); 190 regerror(rc, &re, bu, maxlen);
189 char buf[maxlen]; 191 char buf[maxlen];
190 snprintf(buf, sizeof(buf), "pattern %s not valid - %s", pattern, bu); 192 snprintf(buf, sizeof(buf), "pattern %s not valid - %s", pattern, bu);
191 tok.token_error(buf); 193 tok.token_error(buf);
192 pattern = NULL; 194 pattern = NULL;
193 } 195 }
194 } 196 }
195 } 197 }
196 198
197 199
198 PATTERN::~PATTERN() { 200 PATTERN::~PATTERN() {
199 regfree(&re); 201 regfree(&re);
200 } 202 }
201 203
202 204
203 bool PATTERN::process(char *buf, CONFIG &con, char *file_name, int pattern_index) { 205 bool PATTERN::process(char *buf, CONFIG &con, char *file_name, int pattern_index) {
204 if (pattern) { 206 if (pattern) {
205 const int nmatch = index+1; 207 const int nmatch = index+1;
206 regmatch_t match[nmatch]; 208 regmatch_t match[nmatch];
207 if (0 == regexec(&re, buf, nmatch, match, 0)) { 209 if (0 == regexec(&re, buf, nmatch, match, 0)) {
208 int s = match[index].rm_so; 210 int s = match[index].rm_so;
209 int e = match[index].rm_eo; 211 int e = match[index].rm_eo;
210 if (s != -1) { 212 if (s != -1) {
211 if (debug_syslog > 3) { 213 if (debug_syslog > 3) {
212 my_syslog(buf); // show lines with matches 214 my_syslog(buf); // show lines with matches
213 } 215 }
214 buf[e] = '\0'; 216 buf[e] = '\0';
215 int ip = ip_address(buf+s); 217 int ip = ip_address(buf+s);
216 if (ip) { 218 if (ip) {
217 recorder.add(ip, amount, con, file_name, pattern_index, message); 219 recorder.add(ip, amount, con, file_name, pattern_index, message);
218 } 220 }
219 return true; 221 return true;
220 } 222 }
221 } 223 }
222 } 224 }
223 return false; 225 return false;
224 } 226 }
225 227
226 228
227 void PATTERN::dump(int level) { 229 void PATTERN::dump(int level) {
228 char indent[maxlen]; 230 char indent[maxlen];
229 int i = min(maxlen-1, level*4); 231 int i = min(maxlen-1, level*4);
230 memset(indent, ' ', i); 232 memset(indent, ' ', i);
231 indent[i] = '\0'; 233 indent[i] = '\0';
232 printf("%s pattern \"%s\" {; \n", indent, pattern); 234 printf("%s pattern \"%s\" {; \n", indent, pattern);
233 printf("%s index %d; \n", indent, index); 235 printf("%s index %d; \n", indent, index);
234 printf("%s bucket %d; \n", indent, amount); 236 printf("%s bucket %d; \n", indent, amount);
235 if (message) printf("%s message \"%s\"; \n", indent, message); 237 if (message) printf("%s message \"%s\"; \n", indent, message);
236 printf("%s }; \n", indent); 238 printf("%s }; \n", indent);
237 } 239 }
238 240
239 241
240 //////////////////////////////////////////////// 242 ////////////////////////////////////////////////
241 // 243 //
242 CONFIG::CONFIG() { 244 CONFIG::CONFIG() {
243 reference_count = 0; 245 reference_count = 0;
244 generation = 0; 246 generation = 0;
245 load_time = 0; 247 load_time = 0;
246 threshold = 500; 248 threshold = 500;
247 add_command = "/sbin/iptables -I INPUT --src %s --jump DROP"; 249 add_command = "/sbin/iptables -I INPUT --src %s --jump DROP";
248 remove_command = "/sbin/iptables -D INPUT --src %s --jump DROP"; 250 remove_command = "/sbin/iptables -D INPUT --src %s --jump DROP";
249 } 251 }
250 252
251 253
252 CONFIG::~CONFIG() { 254 CONFIG::~CONFIG() {
253 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { 255 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) {
254 SYSLOGCONFIG *c = *i; 256 SYSLOGCONFIG *c = *i;
255 delete c; 257 delete c;
256 } 258 }
257 ignore.clear(); 259 ignore.clear();
258 } 260 }
259 261
260 262
261 void CONFIG::add_syslogconfig(SYSLOGCONFIGP con) { 263 void CONFIG::add_syslogconfig(SYSLOGCONFIGP con) {
262 syslogconfigs.push_back(con); 264 syslogconfigs.push_back(con);
263 } 265 }
264 266
265 267
266 void CONFIG::add_pair(IPPAIR pair) { 268 void CONFIG::add_pair(IPPAIR pair) {
267 ignore.push_back(pair); 269 ignore.push_back(pair);
268 } 270 }
269 271
270 272
271 void CONFIG::dump() { 273 void CONFIG::dump() {
272 printf(" threshold %d; \n\n", threshold); 274 printf(" threshold %d; \n\n", threshold);
273 275
274 printf(" add_command \"%s\"; \n", add_command); 276 printf(" add_command \"%s\"; \n", add_command);
275 printf(" remove_command \"%s\"; \n\n", remove_command); 277 printf(" remove_command \"%s\"; \n\n", remove_command);
276 278
277 printf(" ignore { \n"); 279 printf(" ignore { \n");
278 for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) { 280 for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) {
279 IPPAIR &p = *i; 281 IPPAIR &p = *i;
280 in_addr ip; 282 in_addr ip;
281 ip.s_addr = htonl(p.first); 283 ip.s_addr = htonl(p.first);
282 printf(" %s/%d; \n", inet_ntoa(ip), p.cidr); 284 printf(" %s/%d; \n", inet_ntoa(ip), p.cidr);
283 } 285 }
284 printf(" }; \n\n"); 286 printf(" }; \n\n");
285 287
286 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { 288 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) {
287 SYSLOGCONFIGP c = *i; 289 SYSLOGCONFIGP c = *i;
288 c->dump(0); 290 c->dump(0);
289 } 291 }
290 } 292 }
291 293
292 294
293 void CONFIG::read() { 295 void CONFIG::read() {
294 while (true) { 296 while (true) {
295 bool have = false; 297 bool have = false;
296 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) { 298 for (syslogconfig_list::iterator i=syslogconfigs.begin(); i!=syslogconfigs.end(); i++) {
297 SYSLOGCONFIGP c = *i; 299 SYSLOGCONFIGP c = *i;
298 have |= c->read(*this); 300 have |= c->read(*this);
299 } 301 }
300 if (!have) break; 302 if (!have) break;
301 } 303 }
302 } 304 }
303 305
304 306
305 void CONFIG::sleep(int duration, time_t &previous) { 307 void CONFIG::sleep(int duration, time_t &previous) {
306 ::sleep(duration); 308 ::sleep(duration);
307 time_t now = time(NULL); 309 time_t now = time(NULL);
308 recorder.leak(now-previous, *this); 310 recorder.leak(now-previous, *this);
309 previous = now; 311 previous = now;
310 } 312 }
311 313
314
315 void CONFIG::free_all() {
316 recorder.free_all(*this);
317 }
312 318
313 bool CONFIG::looking(int ip) { 319 bool CONFIG::looking(int ip) {
314 for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) { 320 for (ippair_list::iterator i=ignore.begin(); i!=ignore.end(); i++) {
315 IPPAIR &p = *i; 321 IPPAIR &p = *i;
316 if ((p.first <= ip) && (ip <= p.last)) return false; 322 if ((p.first <= ip) && (ip <= p.last)) return false;
317 } 323 }
318 return true; 324 return true;
319 } 325 }
320 326
321 //////////////////////////////////////////////// 327 ////////////////////////////////////////////////
322 // 328 //
323 SYSLOGCONFIG::SYSLOGCONFIG(TOKEN &tok, char *file_name_) { 329 SYSLOGCONFIG::SYSLOGCONFIG(TOKEN &tok, char *file_name_) {
324 tokp = &tok; 330 tokp = &tok;
325 file_name = file_name_; 331 file_name = file_name_;
326 open(true); 332 open(true);
327 } 333 }
328 334
329 335
330 SYSLOGCONFIG::~SYSLOGCONFIG() { 336 SYSLOGCONFIG::~SYSLOGCONFIG() {
331 close(); 337 close();
332 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { 338 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
333 PATTERN *p = *i; 339 PATTERN *p = *i;
334 delete p; 340 delete p;
335 } 341 }
336 } 342 }
337 343
338 344
339 void SYSLOGCONFIG::open(bool msg) { 345 void SYSLOGCONFIG::open(bool msg) {
340 fd = ::open(file_name, O_RDONLY); 346 fd = ::open(file_name, O_RDONLY);
341 len = 0; 347 len = 0;
342 if (fd == -1) { 348 if (fd == -1) {
343 if (msg) { 349 if (msg) {
344 char buf[maxlen]; 350 char buf[maxlen];
345 snprintf(buf, sizeof(buf), "syslog file %s not readable", file_name); 351 snprintf(buf, sizeof(buf), "syslog file %s not readable", file_name);
346 tokp->token_error(buf); 352 tokp->token_error(buf);
347 } 353 }
348 } 354 }
349 else { 355 else {
350 if (debug_syslog > 1) { 356 if (debug_syslog > 1) {
351 snprintf(buf, sizeof(buf), "syslog file %s opened", file_name); 357 snprintf(buf, sizeof(buf), "syslog file %s opened", file_name);
352 my_syslog(buf); 358 my_syslog(buf);
353 } 359 }
354 lseek(fd, 0, SEEK_END); 360 lseek(fd, 0, SEEK_END);
355 if (fstat(fd, &openfdstat)) { 361 if (fstat(fd, &openfdstat)) {
356 close(); 362 close();
357 snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", file_name); 363 snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", file_name);
358 tokp->token_error(buf); 364 tokp->token_error(buf);
359 } 365 }
360 // specify that this fd gets closed on exec, so that selinux 366 // specify that this fd gets closed on exec, so that selinux
361 // won't complain about iptables trying to read log files. 367 // won't complain about iptables trying to read log files.
362 int oldflags = fcntl(fd, F_GETFD, 0); 368 int oldflags = fcntl(fd, F_GETFD, 0);
363 if (oldflags >= 0) { 369 if (oldflags >= 0) {
364 fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC); 370 fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC);
365 } 371 }
366 } 372 }
367 } 373 }
368 374
369 375
370 bool SYSLOGCONFIG::read(CONFIG &con) { 376 bool SYSLOGCONFIG::read(CONFIG &con) {
371 if (failed()) { 377 if (failed()) {
372 open(false); 378 open(false);
373 if (failed()) return false; 379 if (failed()) return false;
374 } 380 }
375 int n = ::read(fd, buf+len, buflen-len); 381 int n = ::read(fd, buf+len, buflen-len);
376 bool have = (n > 0); 382 bool have = (n > 0);
377 if (have) { 383 if (have) {
378 len += n; 384 len += n;
379 while (true) { 385 while (true) {
380 char *p = (char*)memchr(buf, '\n', len); 386 char *p = (char*)memchr(buf, '\n', len);
381 if (!p) break; 387 if (!p) break;
382 n = p-buf; 388 n = p-buf;
383 *p = '\0'; 389 *p = '\0';
384 process(con); // process null terminated string 390 process(con); // process null terminated string
385 len -= n+1; 391 len -= n+1;
386 memmove(buf, p+1, len); 392 memmove(buf, p+1, len);
387 } 393 }
388 // no <lf> in a full buffer 394 // no <lf> in a full buffer
389 if (len == buflen) len = 0; 395 if (len == buflen) len = 0;
390 } 396 }
391 else { 397 else {
392 // check for file close 398 // check for file close
393 struct stat filenamest; 399 struct stat filenamest;
394 if (0 == stat(file_name, &filenamest)) { 400 if (0 == stat(file_name, &filenamest)) {
395 if ((filenamest.st_dev != openfdstat.st_dev) || 401 if ((filenamest.st_dev != openfdstat.st_dev) ||
396 (filenamest.st_ino != openfdstat.st_ino)) { 402 (filenamest.st_ino != openfdstat.st_ino)) {
397 close(); 403 close();
398 } 404 }
399 } 405 }
400 else { 406 else {
401 // filename no longer exists 407 // filename no longer exists
402 close(); 408 close();
403 } 409 }
404 } 410 }
405 return have; 411 return have;
406 } 412 }
407 413
408 414
409 void SYSLOGCONFIG::close() { 415 void SYSLOGCONFIG::close() {
410 if (debug_syslog > 1) { 416 if (debug_syslog > 1) {
411 snprintf(buf, sizeof(buf), "syslog file %s closed", file_name); 417 snprintf(buf, sizeof(buf), "syslog file %s closed", file_name);
412 my_syslog(buf); 418 my_syslog(buf);
413 } 419 }
414 if (fd != -1) ::close(fd); 420 if (fd != -1) ::close(fd);
415 fd = -1; 421 fd = -1;
416 } 422 }
417 423
418 424
419 void SYSLOGCONFIG::add_pattern(PATTERNP pat) { 425 void SYSLOGCONFIG::add_pattern(PATTERNP pat) {
420 patterns.push_back(pat); 426 patterns.push_back(pat);
421 } 427 }
422 428
423 429
424 void SYSLOGCONFIG::process(CONFIG &con) { 430 void SYSLOGCONFIG::process(CONFIG &con) {
425 int pi=0; 431 int pi=0;
426 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { 432 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
427 PATTERN *p = *i; 433 PATTERN *p = *i;
428 if (p->process(buf, con, file_name, pi)) break; 434 if (p->process(buf, con, file_name, pi)) break;
429 pi++; 435 pi++;
430 } 436 }
431 } 437 }
432 438
433 439
434 void SYSLOGCONFIG::dump(int level) { 440 void SYSLOGCONFIG::dump(int level) {
435 char indent[maxlen]; 441 char indent[maxlen];
436 int i = min(maxlen-1, level*4); 442 int i = min(maxlen-1, level*4);
437 memset(indent, ' ', i); 443 memset(indent, ' ', i);
438 indent[i] = '\0'; 444 indent[i] = '\0';
439 char buf[maxlen]; 445 char buf[maxlen];
440 printf("%s file \"%s\" {\n", indent, file_name); 446 printf("%s file \"%s\" {\n", indent, file_name);
441 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) { 447 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
442 PATTERN *p = *i; 448 PATTERN *p = *i;
443 p->dump(level+1); 449 p->dump(level+1);
444 } 450 }
445 printf("%s }; \n", indent); 451 printf("%s }; \n", indent);
446 } 452 }
447 453
448 454
449 //////////////////////////////////////////////// 455 ////////////////////////////////////////////////
450 // helper to discard the strings held by a string_set 456 // helper to discard the strings held by a string_set
451 // 457 //
452 void discard(string_set &s) { 458 void discard(string_set &s) {
453 for (string_set::iterator i=s.begin(); i!=s.end(); i++) { 459 for (string_set::iterator i=s.begin(); i!=s.end(); i++) {
454 free(*i); 460 free(*i);
455 } 461 }
456 s.clear(); 462 s.clear();
457 } 463 }
458 464
459 465
460 //////////////////////////////////////////////// 466 ////////////////////////////////////////////////
461 // helper to register a string in a string set 467 // helper to register a string in a string set
462 // 468 //
463 char* register_string(string_set &s, char *name) { 469 char* register_string(string_set &s, char *name) {
464 string_set::iterator i = s.find(name); 470 string_set::iterator i = s.find(name);
465 if (i != s.end()) return *i; 471 if (i != s.end()) return *i;
466 char *x = strdup(name); 472 char *x = strdup(name);
467 s.insert(x); 473 s.insert(x);
468 return x; 474 return x;
469 } 475 }
470 476
471 477
472 //////////////////////////////////////////////// 478 ////////////////////////////////////////////////
473 // register a global string 479 // register a global string
474 // 480 //
475 char* register_string(char *name) { 481 char* register_string(char *name) {
476 return register_string(all_strings, name); 482 return register_string(all_strings, name);
477 } 483 }
478 484
479 485
480 //////////////////////////////////////////////// 486 ////////////////////////////////////////////////
481 // 487 //
482 bool tsa(TOKEN &tok, char *token); 488 bool tsa(TOKEN &tok, char *token);
483 bool tsa(TOKEN &tok, char *token) { 489 bool tsa(TOKEN &tok, char *token) {
484 char *have = tok.next(); 490 char *have = tok.next();
485 if (have == token) return true; 491 if (have == token) return true;
486 tok.token_error(token, have); 492 tok.token_error(token, have);
487 return false; 493 return false;
488 } 494 }
489 495
490 496
491 //////////////////////////////////////////////// 497 ////////////////////////////////////////////////
492 // 498 //
493 bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con); 499 bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con);
494 bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con) { 500 bool parse_pattern(TOKEN &tok, SYSLOGCONFIG &con) {
495 char *pat = tok.next(); 501 char *pat = tok.next();
496 int ind, buc; 502 int ind, buc;
497 char *msg = NULL; 503 char *msg = NULL;
498 if (!tsa(tok, token_lbrace)) return false; 504 if (!tsa(tok, token_lbrace)) return false;
499 while (true) { 505 while (true) {
500 char *have = tok.next(); 506 char *have = tok.next();
501 if (!have) break; 507 if (!have) break;
502 if (have == token_rbrace) break; 508 if (have == token_rbrace) break;
503 if (have == token_index) { 509 if (have == token_index) {
504 have = tok.next(); 510 have = tok.next();
505 ind = atoi(have); 511 ind = atoi(have);
506 if (!tsa(tok, token_semi)) return false; 512 if (!tsa(tok, token_semi)) return false;
507 } 513 }
508 else if (have == token_bucket) { 514 else if (have == token_bucket) {
509 have = tok.next(); 515 have = tok.next();
510 buc = atoi(have); 516 buc = atoi(have);
511 if (!tsa(tok, token_semi)) return false; 517 if (!tsa(tok, token_semi)) return false;
512 } 518 }
513 else if (have == token_message) { 519 else if (have == token_message) {
514 msg = tok.next(); 520 msg = tok.next();
515 if (!tsa(tok, token_semi)) return false; 521 if (!tsa(tok, token_semi)) return false;
516 } 522 }
517 else { 523 else {
518 tok.token_error("index/bucket", have); 524 tok.token_error("index/bucket", have);
519 return false; 525 return false;
520 } 526 }
521 } 527 }
522 if (!tsa(tok, token_semi)) return false; 528 if (!tsa(tok, token_semi)) return false;
523 PATTERNP patt = new PATTERN(tok, pat, ind, buc, msg); 529 PATTERNP patt = new PATTERN(tok, pat, ind, buc, msg);
524 con.add_pattern(patt); 530 con.add_pattern(patt);
525 return true; 531 return true;
526 } 532 }
527 533
528 534
529 //////////////////////////////////////////////// 535 ////////////////////////////////////////////////
530 // 536 //
531 bool parse_ignore(TOKEN &tok, CONFIG &dc); 537 bool parse_ignore(TOKEN &tok, CONFIG &dc);
532 bool parse_ignore(TOKEN &tok, CONFIG &dc) { 538 bool parse_ignore(TOKEN &tok, CONFIG &dc) {
533 if (!tsa(tok, token_lbrace)) return false; 539 if (!tsa(tok, token_lbrace)) return false;
534 while (true) { 540 while (true) {
535 char *have = tok.next(); 541 char *have = tok.next();
536 if (!have) break; 542 if (!have) break;
537 if (have == token_rbrace) break; 543 if (have == token_rbrace) break;
538 int ipaddr = ip_address(have); 544 int ipaddr = ip_address(have);
539 if (ipaddr == 0) { 545 if (ipaddr == 0) {
540 tok.token_error("ip address", have); 546 tok.token_error("ip address", have);
541 return false; 547 return false;
542 } 548 }
543 if (!tsa(tok, token_slash)) return false; 549 if (!tsa(tok, token_slash)) return false;
544 have = tok.next(); 550 have = tok.next();
545 int mask = atoi(have); 551 int mask = atoi(have);
546 if ((mask < 8) || (mask > 32)) { 552 if ((mask < 8) || (mask > 32)) {
547 tok.token_error("cidr 8..32 value", have); 553 tok.token_error("cidr 8..32 value", have);
548 return false; 554 return false;
549 } 555 }
550 if (!tsa(tok, token_semi)) return false; 556 if (!tsa(tok, token_semi)) return false;
551 IPPAIR pair; 557 IPPAIR pair;
552 const int masks[33] = {0xffffffff, // 0 558 const int masks[33] = {0xffffffff, // 0
553 0x7fffffff, // 1 559 0x7fffffff, // 1
554 0x3fffffff, // 2 560 0x3fffffff, // 2
555 0x1fffffff, // 3 561 0x1fffffff, // 3
556 0x0fffffff, // 4 562 0x0fffffff, // 4
557 0x07ffffff, // 5 563 0x07ffffff, // 5
558 0x03ffffff, // 6 564 0x03ffffff, // 6
559 0x01ffffff, // 7 565 0x01ffffff, // 7
560 0x00ffffff, // 8 566 0x00ffffff, // 8
561 0x007fffff, // 9 567 0x007fffff, // 9
562 0x003fffff, // 10 568 0x003fffff, // 10
563 0x001fffff, // 11 569 0x001fffff, // 11
564 0x000fffff, // 12 570 0x000fffff, // 12
565 0x0007ffff, // 13 571 0x0007ffff, // 13
566 0x0003ffff, // 14 572 0x0003ffff, // 14
567 0x0001ffff, // 15 573 0x0001ffff, // 15
568 0x0000ffff, // 16 574 0x0000ffff, // 16
569 0x00007fff, // 17 575 0x00007fff, // 17
570 0x00003fff, // 18 576 0x00003fff, // 18
571 0x00001fff, // 19 577 0x00001fff, // 19
572 0x00000fff, // 20 578 0x00000fff, // 20
573 0x000007ff, // 21 579 0x000007ff, // 21
574 0x000003ff, // 22 580 0x000003ff, // 22
575 0x000001ff, // 23 581 0x000001ff, // 23
576 0x000000ff, // 24 582 0x000000ff, // 24
577 0x0000007f, // 25 583 0x0000007f, // 25
578 0x0000003f, // 26 584 0x0000003f, // 26
579 0x0000001f, // 27 585 0x0000001f, // 27
580 0x0000000f, // 28 586 0x0000000f, // 28
581 0x00000007, // 29 587 0x00000007, // 29
582 0x00000003, // 30 588 0x00000003, // 30
583 0x00000001, // 31 589 0x00000001, // 31
584 0x00000000}; // 32 590 0x00000000}; // 32
585 pair.first = ipaddr; 591 pair.first = ipaddr;
586 pair.last = ipaddr | masks[mask]; 592 pair.last = ipaddr | masks[mask];
587 pair.cidr = mask; 593 pair.cidr = mask;
588 dc.add_pair(pair); 594 dc.add_pair(pair);
589 } 595 }
590 if (!tsa(tok, token_semi)) return false; 596 if (!tsa(tok, token_semi)) return false;
591 return true; 597 return true;
592 } 598 }
593 599
594 600
595 //////////////////////////////////////////////// 601 ////////////////////////////////////////////////
596 // 602 //
597 bool parse_syslogconfig(TOKEN &tok, CONFIG &dc); 603 bool parse_syslogconfig(TOKEN &tok, CONFIG &dc);
598 bool parse_syslogconfig(TOKEN &tok, CONFIG &dc) { 604 bool parse_syslogconfig(TOKEN &tok, CONFIG &dc) {
599 char *name = tok.next(); 605 char *name = tok.next();
600 if (!tsa(tok, token_lbrace)) return false; 606 if (!tsa(tok, token_lbrace)) return false;
601 SYSLOGCONFIGP con = new SYSLOGCONFIG(tok, name); 607 SYSLOGCONFIGP con = new SYSLOGCONFIG(tok, name);
602 if (con->failed()) { 608 if (con->failed()) {
603 delete con; 609 delete con;
604 return false; 610 return false;
605 } 611 }
606 dc.add_syslogconfig(con); 612 dc.add_syslogconfig(con);
607 while (true) { 613 while (true) {
608 char *have = tok.next(); 614 char *have = tok.next();
609 if (!have) break; 615 if (!have) break;
610 if (have == token_rbrace) break; 616 if (have == token_rbrace) break;
611 if (have == token_pattern) { 617 if (have == token_pattern) {
612 if (!parse_pattern(tok, *con)) return false; 618 if (!parse_pattern(tok, *con)) return false;
613 } 619 }
614 else { 620 else {
615 tok.token_error("pattern", have); 621 tok.token_error("pattern", have);
616 return false; 622 return false;
617 } 623 }
618 } 624 }
619 if (!tsa(tok, token_semi)) return false; 625 if (!tsa(tok, token_semi)) return false;
620 return true; 626 return true;
621 } 627 }
622 628
623 629
624 //////////////////////////////////////////////// 630 ////////////////////////////////////////////////
625 // parse a config file 631 // parse a config file
626 // 632 //
627 bool load_conf(CONFIG &dc, char *fn) { 633 bool load_conf(CONFIG &dc, char *fn) {
628 int count = 0; 634 int count = 0;
629 TOKEN tok(fn, &dc.config_files); 635 TOKEN tok(fn, &dc.config_files);
630 while (true) { 636 while (true) {
631 char *have = tok.next(); 637 char *have = tok.next();
632 if (!have) break; 638 if (!have) break;
633 if (have == token_threshold) { 639 if (have == token_threshold) {
634 have = tok.next(); 640 have = tok.next();
635 dc.set_threshold(atoi(have)); 641 dc.set_threshold(atoi(have));
636 if (!tsa(tok, token_semi)) return false; 642 if (!tsa(tok, token_semi)) return false;
637 } 643 }
638 else if (have == token_ignore) { 644 else if (have == token_ignore) {
639 if (!parse_ignore(tok, dc)) return false; 645 if (!parse_ignore(tok, dc)) return false;
640 } 646 }
641 else if (have == token_add) { 647 else if (have == token_add) {
642 have = tok.next(); 648 have = tok.next();
643 dc.set_add(have); 649 dc.set_add(have);
644 if (!tsa(tok, token_semi)) return false; 650 if (!tsa(tok, token_semi)) return false;
645 } 651 }
646 else if (have == token_remove) { 652 else if (have == token_remove) {
647 have = tok.next(); 653 have = tok.next();
648 dc.set_remove(have); 654 dc.set_remove(have);
649 if (!tsa(tok, token_semi)) return false; 655 if (!tsa(tok, token_semi)) return false;
650 } 656 }
651 else if (have == token_file) { 657 else if (have == token_file) {
652 if (!parse_syslogconfig(tok, dc)) return false; 658 if (!parse_syslogconfig(tok, dc)) return false;
653 count++; 659 count++;
654 } 660 }
655 else { 661 else {
656 tok.token_error("threshold/ignore/add_command/remove_command/file", have); 662 tok.token_error("threshold/ignore/add_command/remove_command/file", have);
657 return false; 663 return false;
658 } 664 }
659 } 665 }
660 tok.token_error("load_conf() found %d syslog files in %s", count, fn); 666 tok.token_error("load_conf() found %d syslog files in %s", count, fn);
661 return (!dc.syslogconfigs.empty()); 667 return (!dc.syslogconfigs.empty());
662 } 668 }
663 669
664 670
665 //////////////////////////////////////////////// 671 ////////////////////////////////////////////////
666 // init the tokens 672 // init the tokens
667 // 673 //
668 void token_init() { 674 void token_init() {
669 token_add = register_string("add_command"); 675 token_add = register_string("add_command");
670 token_bucket = register_string("bucket"); 676 token_bucket = register_string("bucket");
671 token_file = register_string("file"); 677 token_file = register_string("file");
672 token_ignore = register_string("ignore"); 678 token_ignore = register_string("ignore");
673 token_include = register_string("include"); 679 token_include = register_string("include");
674 token_index = register_string("index"); 680 token_index = register_string("index");
675 token_lbrace = register_string("{"); 681 token_lbrace = register_string("{");
676 token_message = register_string("message"); 682 token_message = register_string("message");
677 token_pattern = register_string("pattern"); 683 token_pattern = register_string("pattern");
678 token_rbrace = register_string("}"); 684 token_rbrace = register_string("}");
679 token_remove = register_string("remove_command"); 685 token_remove = register_string("remove_command");
680 token_semi = register_string(";"); 686 token_semi = register_string(";");
681 token_slash = register_string("/"); 687 token_slash = register_string("/");
682 token_threshold = register_string("threshold"); 688 token_threshold = register_string("threshold");
683 } 689 }