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