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