Imported Upstream version 2.7
[ossec-hids.git] / src / analysisd / stats.c
1 /* @(#) $Id: ./src/analysisd/stats.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13
14
15 #include "shared.h"
16 #include "analysisd.h"
17 #include "stats.h"
18 #include "rules.h"
19
20 #include "error_messages/error_messages.h"
21
22 #include "headers/file_op.h"
23 #include "alerts/alerts.h"
24
25 #include "headers/debug_op.h"
26
27
28 char *(weekdays[])={"Sunday","Monday","Tuesday","Wednesday","Thursday",
29                             "Friday","Saturday"};
30 char *(l_month[])={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug",
31                  "Sep","Oct","Nov","Dec"};
32
33
34
35 /* Global vars */
36
37 /* Hour 25 is internally used */
38 int _RWHour[7][25];
39 int _CWHour[7][25];
40
41 int _RHour[25];
42 int _CHour[25];
43
44 int _cignorehour = 0;
45 int _fired = 0;
46 int _daily_errors = 0;
47 int maxdiff = 0;
48 int mindiff = 0;
49 int percent_diff = 20;
50
51
52 char __stats_comment[192];
53
54 /* Last msgs, to avoid floods */
55 char *_lastmsg;
56 char *_prevlast;
57 char *_pprevlast;
58
59
60 void print_totals()
61 {
62     int i, totals = 0;
63     char logfile[OS_FLSIZE +1];
64     FILE *flog;
65
66
67     /* Creating the path for the logs */
68     snprintf(logfile, OS_FLSIZE,"%s/%d/", STATSAVED, prev_year);
69     if(IsDir(logfile) == -1)
70         if(mkdir(logfile,0770) == -1)
71         {
72             merror(MKDIR_ERROR,ARGV0,logfile);
73             return;
74         }
75
76     snprintf(logfile,OS_FLSIZE,"%s/%d/%s", STATSAVED, prev_year, prev_month);
77
78     if(IsDir(logfile) == -1)
79         if(mkdir(logfile,0770) == -1)
80         {
81             merror(MKDIR_ERROR, ARGV0, logfile);
82             return;
83         }
84
85
86     /* Creating the logfile name */
87     snprintf(logfile,OS_FLSIZE,"%s/%d/%s/ossec-%s-%02d.log",
88             STATSAVED,
89             prev_year,
90             prev_month,
91             "totals",
92             today);
93
94     flog = fopen(logfile, "a");
95     if(!flog)
96     {
97         merror(FOPEN_ERROR, ARGV0, logfile);
98         return;
99     }
100
101     /* Printing the hourly stats */
102     for(i=0;i<=23;i++)
103     {
104         fprintf(flog,"Hour totals - %d:%d\n", i, _CHour[i]);
105         totals+=_CHour[i];
106     }
107     fprintf(flog,"Total events for day:%d\n", totals);
108
109     fclose(flog);
110 }
111
112
113 /* gethour: v0.2
114  * Return the parameter (event_number + 20 % of it)
115  * If event_number < mindiff, return mindiff
116  * If event_number > maxdiff, return maxdiff
117  */
118 int gethour(int event_number)
119 {
120     int event_diff;
121
122     event_diff = (event_number * percent_diff)/100;
123
124     event_diff++;
125
126     if(event_diff < mindiff)
127         return(event_number + mindiff);
128     else if(event_diff > maxdiff)
129         return(event_number + maxdiff);
130
131     return(event_number + event_diff);
132 }
133
134
135 /* Update_Hour: done daily  */
136 void Update_Hour()
137 {
138     int i,j;
139     int inter;
140
141
142     /* Print total number of logs received per hour */
143     print_totals();
144
145
146     /* Hourly update */
147     _RHour[24]++;
148     inter = _RHour[24];
149     if(inter > 7)
150         inter = 7;
151
152     for(i=0;i<=24;i++)
153     {
154         char _hourly[128]; /* _hourly file */
155
156         FILE *fp;
157
158         if(i != 24)
159         {
160             /* If saved hourly = 0, just copy the current hourly rate */
161             if(_CHour[i] == 0)
162                 continue;
163
164             if(_RHour[i] == 0)
165                 _RHour[i]=_CHour[i] + 20;
166
167             else
168             {
169                 /* If we had too many errors this day */
170                 if(_daily_errors >= 3)
171                 {
172                     _RHour[i]=(((3*_CHour[i])+(inter*_RHour[i]))/(inter+3))+25;
173                 }
174
175                 else
176                 {
177                     /* The average is going to be the number of interactions +
178                      * the currently hourly rate, divided by 4 */
179                     _RHour[i]=((_CHour[i]+(inter*_RHour[i]))/(inter+1))+5;
180                 }
181             }
182         }
183
184         snprintf(_hourly,128,"%s/%d",STATQUEUE,i);
185         fp = fopen(_hourly, "w");
186         if(fp)
187         {
188             fprintf(fp,"%d",_RHour[i]);
189             fclose(fp);
190         }
191                 
192         else
193         {
194             merror(FOPEN_ERROR, "logstats", _hourly);
195         }
196
197         _CHour[i] = 0; /* Zeroing the currently  hour */
198     }
199
200     /* Weekly */
201     for(i=0;i <= 6;i++)
202     {
203         char _weekly[128];
204         FILE *fp;
205
206         _CWHour[i][24]++;
207         inter = _CWHour[i][24];
208         if(inter > 7)
209             inter = 7;
210
211         for(j=0;j<=24;j++)
212         {
213             if(j != 24)
214             {
215                 if(_CWHour[i][j] == 0)
216                    continue;
217
218                 if(_RWHour[i][j] == 0)
219                    _RWHour[i][j] = _CWHour[i][j] + 20;
220
221                 else
222                 {
223                     if(_daily_errors >= 3)
224                     {
225                         _RWHour[i][j]=(((3*_CWHour[i][j])+(inter*_RWHour[i][j]))/(inter+3))+25;
226                     }
227                     else
228                     {
229                         _RWHour[i][j]=((_CWHour[i][j]+(inter*_RWHour[i][j]))/(inter+1))+5;      
230                     }
231                 }
232             }
233
234             snprintf(_weekly,128,"%s/%d/%d",STATWQUEUE,i,j);
235             fp = fopen(_weekly, "w");
236             if(fp)
237             {
238                 fprintf(fp,"%d",_RWHour[i][j]);
239                 fclose(fp);
240             }
241             else
242             {
243                 merror(FOPEN_ERROR, "logstats", _weekly);
244             }
245
246             _CWHour[i][j] = 0;  
247         }
248     }
249
250     _daily_errors = 0;
251     return;
252 }
253
254
255 /* Check Hourly stats */
256 int Check_Hour(Eventinfo *lf)
257 {
258     _CHour[__crt_hour]++;
259     _CWHour[__crt_wday][__crt_hour]++;  
260
261     if(_RHour[24] <= 2)
262     {
263         return(0);
264     }
265
266     /* checking if any message was already fired for this hour */
267     if((_daily_errors >= 3)||((_fired == 1)&&(_cignorehour == __crt_hour)))
268         return(0);
269
270     else if(_cignorehour != __crt_hour)
271     {
272         _cignorehour=__crt_hour;
273         _fired = 0;
274     }
275
276
277     /* checking if passed the threshold */
278     if(_RHour[__crt_hour] != 0)
279     {
280         if(_CHour[__crt_hour] > (_RHour[__crt_hour]))
281         {
282             if(_CHour[__crt_hour] > (gethour(_RHour[__crt_hour])))
283             {
284                 /* snprintf will null terminate */
285                 snprintf(__stats_comment, 191,
286                                      "The average number of logs"
287                                      " between %d:00 and %d:00 is %d. We "
288                                      "reached %d.",__crt_hour,__crt_hour+1,
289                                      _RHour[__crt_hour],_CHour[__crt_hour]);
290
291
292                 _fired = 1;
293                 _daily_errors++;
294                 return(1);
295             }
296         }
297     }
298
299
300     /* We need to have at least 3 days of stats */
301     if(_RWHour[__crt_wday][24] <= 2)
302         return(0);
303
304     /* checking for the hour during a specific day of the week */
305     if(_RWHour[__crt_wday][__crt_hour] != 0)
306     {
307         if(_CWHour[__crt_wday][__crt_hour] > _RWHour[__crt_wday][__crt_hour])
308         {
309             if(_CWHour[__crt_wday][__crt_hour] >
310                     gethour(_RWHour[__crt_wday][__crt_hour]))
311             {
312                 snprintf(__stats_comment, 191,
313                                      "The average number of logs"
314                                      " between %d:00 and %d:00 on %s is %d. We"
315                                      " reached %d.",__crt_hour,__crt_hour+1,
316                                      weekdays[__crt_wday],
317                                      _RWHour[__crt_wday][__crt_hour],
318                                      _CWHour[__crt_wday][__crt_hour]);
319
320
321                 _fired = 1;
322                 _daily_errors++;
323                 return(1);
324             }
325         }
326     }
327     return(0);  
328 }
329
330 /* Starting hourly stats and other necessary variables */
331 int Start_Hour()
332 {
333     int i=0,j=0;
334     struct tm *p;
335
336     /* Current time */
337     p = localtime(&c_time);
338
339     /* Other global variables */
340     _fired = 0;
341     _cignorehour = 0;
342
343     today = p->tm_mday;
344     thishour = p->tm_hour;
345     prev_year = p->tm_year + 1900;
346     strncpy(prev_month, l_month[p->tm_mon], 3);
347     prev_month[3] = '\0';
348
349
350     /* Clearing some memory */
351     memset(__stats_comment, '\0', 192);
352
353
354     /* Getting maximum/minimum diffs */
355     maxdiff = getDefine_Int("analysisd",
356                             "stats_maxdiff",
357                             10, 99999);
358
359     mindiff = getDefine_Int("analysisd",
360                             "stats_mindiff",
361                             10, 99999);
362
363     percent_diff = getDefine_Int("analysisd",
364                                  "stats_percent_diff",
365                                  5, 999);
366
367
368     /* Last three messages
369      * They are used to keep track of the last
370      * messages received to avoid floods.
371      */
372     _lastmsg = NULL;
373     _prevlast = NULL;
374     _pprevlast = NULL;
375
376
377     /* They should not be null */
378     os_strdup(" ", _lastmsg);
379     os_strdup(" ", _prevlast);
380     os_strdup(" ", _pprevlast);
381
382
383     /* Creating the stat queue directories */
384     if(IsDir(STATWQUEUE) == -1)
385         if(mkdir(STATWQUEUE,0770) == -1)
386         {
387             merror("%s: logstat: Unable to create stat queue: %s",
388                             ARGV0, STATWQUEUE);
389             return(-1);
390         }
391
392     if(IsDir(STATQUEUE) == -1)
393         if(mkdir(STATQUEUE,0770) == -1)
394         {
395             merror("%s: logstat: Unable to create stat queue: %s",
396                             ARGV0, STATQUEUE);
397             return(-1);
398         }
399
400     /* Creating store dir */
401     if(IsDir(STATSAVED) == -1)
402         if(mkdir(STATSAVED,0770) == -1)
403         {
404             merror("%s: logstat: Unable to create stat directory: %s",
405                         ARGV0, STATQUEUE);
406             return(-1);
407         }
408
409     /* Creating hourly directory (24 hour is the stats) */
410     for(i=0;i<=24;i++)
411     {
412         char _hourly[128];
413         snprintf(_hourly,128,"%s/%d",STATQUEUE,i);
414
415         _CHour[i]=0;    
416         if(File_DateofChange(_hourly) < 0)
417             _RHour[i] = 0;
418
419         else
420         {
421             FILE *fp;
422             fp = fopen(_hourly, "r");
423             if(!fp)
424                 _RHour[i] = 0;
425             else
426             {
427                 if(fscanf(fp,"%d",&_RHour[i]) <= 0)
428                     _RHour[i] = 0;
429
430                 if(_RHour[i] < 0)
431                     _RHour[i] = 0;
432                 fclose(fp);
433             }   
434         }
435     }
436
437     /* Creating weekly/hourly directories */
438     for(i=0;i<=6;i++)
439     {
440         char _weekly[128];
441         snprintf(_weekly,128,"%s/%d",STATWQUEUE,i);
442         if(IsDir(_weekly) == -1)
443             if(mkdir(_weekly,0770) == -1)
444             {
445                 merror("%s: logstat: Unable to create stat queue: %s",
446                         ARGV0, _weekly);
447                 return(-1);
448             }
449
450         for(j=0;j<=24;j++)
451         {
452             _CWHour[i][j]=0;
453             snprintf(_weekly,128,"%s/%d/%d",STATWQUEUE,i,j);
454             if(File_DateofChange(_weekly) < 0)
455                 _RWHour[i][j] = 0;
456             else
457             {
458                 FILE *fp;
459                 fp = fopen(_weekly, "r");
460                 if(!fp)
461                     _RWHour[i][j] = 0;
462                 else
463                 {
464                     if(fscanf(fp,"%d",&_RWHour[i][j]) <= 0)
465                         _RWHour[i][j] = 0;
466
467                     if(_RWHour[i][j] < 0)
468                         _RWHour[i][j] = 0;
469                     fclose(fp);
470                 }       
471             }   
472         }       
473     }
474     return(0);
475 }
476
477
478 /* LastMsg_Stats: v0.3: 2006/03/21
479  * v0.3: Some performance fixes (2006/03/21).
480  * v0.2: 2005/03/17
481  * check if the message received is repeated. Doing
482  * it to avoid floods from same message.
483  */
484 int LastMsg_Stats(char *log)
485 {
486         if(strcmp(log,_lastmsg) == 0)
487                 return(1);              
488                 
489         else if(strcmp(log,_prevlast) == 0)
490                 return(1);
491
492         else if(strcmp(log,_pprevlast) == 0)
493                 return(1);
494         
495         return(0);
496 }
497
498 /* LastMsg_Change: v0.3: 2006/03/21
499  * v0.3: 2006/03/21: Some performance fixes.
500  * v0.2: 2005/03/17
501  * If the message is not repeated, rearrange the last
502  * received messages
503  */
504 void LastMsg_Change(char *log)
505 {
506     /* Removing the last one */
507     free(_pprevlast);
508
509     /* Moving the second to third and the last to second */
510     _pprevlast = _prevlast;
511
512     _prevlast = _lastmsg;
513
514
515     os_strdup(log, _lastmsg);
516     return;
517 }
518
519
520 /* EOF */