1 /*
2 **  $Id$
3 **
4 **  perf.c
5 **
6 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
7 ** Copyright (C) 2002-2013 Sourcefire, Inc.
8 ** Dan Roelker <droelker@sourcefire.com>
9 **
10 ** This program is free software; you can redistribute it and/or modify
11 ** it under the terms of the GNU General Public License Version 2 as
12 ** published by the Free Software Foundation.  You may not use, modify or
13 ** distribute this program under any other version of the GNU General
14 ** Public License.
15 **
16 ** This program is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ** GNU General Public License for more details.
20 **
21 ** You should have received a copy of the GNU General Public License
22 ** along with this program; if not, write to the Free Software
23 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24 **
25 **
26 **  DESCRIPTION
27 **    These are the basic functions that are needed to call performance
28 **    functions.
29 **
30 */
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <errno.h>
38 
39 #ifndef WIN32
40 # include <time.h>
41 # include <unistd.h>
42 #endif /* WIN32 */
43 
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47 
48 #include "util.h"
49 #include "perf.h"
50 #include "sf_types.h"
51 #include "decode.h"
52 #include "snort.h"
53 
54 SFBASE sfBase;
55 SFFLOW sfFlow;
56 SFEVENT sfEvent;
57 int perfmon_rotate_perf_file = 0;
58 static uint32_t pkt_cnt = 0;
59 
60 #ifdef SNORT_RELOAD
61     extern SFPERF* perfmon_config;
62     PERFRELOAD_STATUS perfmon_reload_status = PERF_NOT_RELOADING;
63 #endif
64 
65 static void UpdatePerfStats(SFPERF *, Packet *p);
66 static bool CheckSampleInterval(SFPERF *, time_t);
67 static inline bool sfCheckFileSize(FILE *, uint32_t);
68 static inline void sfProcessBaseStats(SFPERF *);
69 static inline void sfProcessFlowStats(SFPERF *);
70 static inline void sfProcessFlowIpStats(SFPERF *);
71 static inline void sfProcessEventStats(SFPERF *);
72 static inline int sfRotateFlowIPStatsFile(SFPERF *);
73 static int sfRotateFile(const char *, FILE *, const char *, uint32_t);
74 
sfInitPerformanceStatistics(SFPERF * sfPerf)75 void sfInitPerformanceStatistics(SFPERF *sfPerf)
76 {
77     memset(sfPerf, 0, sizeof(SFPERF));
78     sfPerf->sample_interval = 60;
79     sfPerf->flow_max_port_to_track = 1023;
80     sfPerf->perf_flags |= SFPERF_BASE;
81     sfPerf->pkt_cnt = 10000;
82     sfPerf->max_file_size = MAX_PERF_FILE_SIZE;
83     sfPerf->flowip_memcap = 50*1024*1024;
84     sfPerf->base_reset = 1;
85 
86 #ifdef LINUX_SMP
87     sfInitProcPidStats(&(sfBase.sfProcPidStats));
88 #endif
89 }
90 
WriteTimeStamp(FILE * fh,const char * action)91 static void WriteTimeStamp(FILE *fh, const char *action)
92 {
93     time_t curr_time = time(NULL);
94 
95     if (fh == NULL)
96         return;
97 
98     fprintf(fh,
99         "################################### "
100         "Perfmon %s: pid=%u at=%.24s (%lu) "
101         "###################################\n",
102         action, getpid(),
103         ctime(&curr_time), (unsigned long)curr_time);
104 
105     fflush(fh);
106 }
107 
sfOpenBaseStatsFile(const char * file)108 FILE * sfOpenBaseStatsFile(const char *file)
109 {
110     static bool start_up = true;
111     FILE *fh = NULL;
112     bool reload = false;
113 
114 #ifdef SNORT_RELAOD
115     reload = perfmon_reload_status != PERF_NOT_RELOADING;
116 #endif
117 
118 #ifndef WIN32
119 
120     // This file needs to be readable by everyone
121     mode_t old_umask = umask(022);
122 #endif
123 
124     if (file != NULL)
125     {
126         // Append to the existing file if just starting up or reloading, otherwise we've
127         // rotated so start a new one.
128         bool append = start_up || reload;
129         fh = fopen(file, append ? "a" : "w");
130         if (fh != NULL)
131         {
132             WriteTimeStamp(fh, append ? "start" : "rotate");
133             LogBasePerfHeader(fh);
134         }
135     }
136 
137 #ifndef WIN32
138     umask(old_umask);
139 #endif
140 
141     if (start_up)
142         start_up = false;
143 
144     return fh;
145 }
146 
sfCloseBaseStatsFile(SFPERF * sfPerf)147 void sfCloseBaseStatsFile(SFPERF *sfPerf)
148 {
149     if (sfPerf->fh == NULL)
150         return;
151 
152     WriteTimeStamp(sfPerf->fh, "stop");
153     fclose(sfPerf->fh);
154     sfPerf->fh = NULL;
155 }
156 
sfOpenFlowStatsFile(const char * file)157 FILE * sfOpenFlowStatsFile(const char *file)
158 {
159     static bool start_up = true;
160     FILE *fh = NULL;
161     bool  reload = false;
162 
163 #ifdef SNORT_RELOAD
164     reload = perfmon_reload_status != PERF_NOT_RELOADING;
165 #endif
166 
167 #ifndef WIN32
168     // This file needs to be readable by everyone
169     mode_t old_umask = umask(022);
170 #endif
171 
172     if (file != NULL)
173     {
174         // Append to the existing file if just starting up or reloading, otherwise we've
175         // rotated so start a new one.
176         bool append = start_up || reload;
177         fh = fopen(file, append ? "a" : "w");
178         if (fh != NULL)
179         {
180             WriteTimeStamp(fh, append ? "start" : "rotate");
181             LogFlowPerfHeader(fh);
182         }
183     }
184 
185 #ifndef WIN32
186     umask(old_umask);
187 #endif
188 
189     if (start_up)
190         start_up = false;
191 
192     return fh;
193 }
194 
sfCloseFlowStatsFile(SFPERF * sfPerf)195 void sfCloseFlowStatsFile(SFPERF *sfPerf)
196 {
197     if (sfPerf->flow_fh == NULL)
198         return;
199 
200     WriteTimeStamp(sfPerf->flow_fh, "stop");
201     fclose(sfPerf->flow_fh);
202     sfPerf->flow_fh = NULL;
203 }
204 
sfOpenFlowIPStatsFile(const char * file)205 FILE * sfOpenFlowIPStatsFile(const char *file)
206 {
207     static bool start_up = true;
208     FILE *fh = NULL;
209     bool  reload = false;
210 
211 #ifdef SNORT_RELOAD
212     reload = perfmon_reload_status != PERF_NOT_RELOADING;
213 #endif
214 
215 #ifndef WIN32
216     // This file needs to be readable by everyone
217     mode_t old_umask = umask(022);
218 #endif
219 
220     if (file != NULL)
221     {
222         // Append to the existing file if just starting up or reloading, otherwise we've
223         // rotated so start a new one.
224         fh = fopen(file, start_up || reload ? "a" : "w");
225     }
226 
227 #ifndef WIN32
228     umask(old_umask);
229 #endif
230 
231     if (start_up)
232         start_up = false;
233 
234     return fh;
235 }
236 
sfCloseFlowIPStatsFile(SFPERF * sfPerf)237 void sfCloseFlowIPStatsFile(SFPERF *sfPerf)
238 {
239     if (sfPerf->flowip_fh == NULL)
240         return;
241 
242     fclose(sfPerf->flowip_fh);
243     sfPerf->flowip_fh = NULL;
244 }
245 
sfRotateFile(const char * old_file,FILE * old_fh,const char * rotate_prefix,uint32_t max_file_size)246 static int sfRotateFile(const char *old_file, FILE *old_fh,
247         const char *rotate_prefix, uint32_t max_file_size)
248 {
249     time_t ts;
250     struct tm *tm;
251     char rotate_file[PATH_MAX];
252     char *path_ptr;
253     int path_len = 0;
254     struct stat file_stats;
255 
256     if (old_file == NULL)
257         return -1;
258 
259     if (old_fh == NULL)
260     {
261         ErrorMessage("Perfmonitor: Performance stats file \"%s\" "
262                 "isn't open.\n", old_file);
263         return -1;
264     }
265 
266     // Close the current stats file if it's already open
267     fclose(old_fh);
268     old_fh = NULL;
269 
270     // Rename current stats file with yesterday's date
271 #ifndef WIN32
272     path_ptr = strrchr(old_file, '/');
273 #else
274     path_ptr = strrchr(old_file, '\\');
275 #endif
276 
277     if (path_ptr != NULL)
278     {
279         // Take the length of the file/path name up to the path separator and
280         // add one to include path separator
281         path_len = (path_ptr - old_file) + 1;
282     }
283 
284     // Get current time, then subtract one day to get yesterday
285     ts = time(NULL);
286     ts -= (24*60*60);
287     tm = localtime(&ts);
288 
289     // Create rotate file name based on path, optional prefix and date
290     SnortSnprintf(rotate_file, PATH_MAX, "%.*s%s%s%d-%02d-%02d", path_len, old_file,
291             (rotate_prefix != NULL) ? rotate_prefix : "", (rotate_prefix != NULL) ? "-" : "",
292             tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
293 
294     // If the rotate file doesn't exist, just rename the old one to the new one
295     if (stat(rotate_file, &file_stats) != 0)
296     {
297         if (rename(old_file, rotate_file) != 0)
298         {
299             ErrorMessage("Perfmonitor: Could not rename performance stats "
300                     "file from \"%s\" to \"%s\": %s.\n",
301                     old_file, rotate_file, strerror(errno));
302         }
303     }
304     else  // Otherwise, if it does exist, append data from current stats file to it
305     {
306         char read_buf[4096];
307         size_t num_read, num_wrote;
308         FILE *rotate_fh;
309         int rotate_index = 0;
310         char rotate_file_with_index[PATH_MAX];
311 #ifndef WIN32
312         // This file needs to be readable by everyone
313         mode_t old_umask = umask(022);
314 #endif
315 
316         do
317         {
318             do
319             {
320                 rotate_index++;
321 
322                 // Check to see if there are any files already rotated and indexed
323                 SnortSnprintf(rotate_file_with_index, PATH_MAX, "%s.%02d",
324                         rotate_file, rotate_index);
325 
326             } while (stat(rotate_file_with_index, &file_stats) == 0);
327 
328             // Subtract one to append to last existing file
329             rotate_index--;
330 
331             if (rotate_index == 0)
332             {
333                 rotate_file_with_index[0] = 0;
334                 rotate_fh = fopen(rotate_file, "a");
335             }
336             else
337             {
338                 SnortSnprintf(rotate_file_with_index, PATH_MAX, "%s.%02d",
339                         rotate_file, rotate_index);
340                 rotate_fh = fopen(rotate_file_with_index, "a");
341             }
342 
343             if (rotate_fh == NULL)
344             {
345                 ErrorMessage("Perfmonitor: Could not open performance stats "
346                         "archive file \"%s\" for appending: %s.\n",
347                         *rotate_file_with_index ? rotate_file_with_index : rotate_file,
348                         strerror(errno));
349                 break;
350             }
351 
352             old_fh = fopen(old_file, "r");
353             if (old_fh == NULL)
354             {
355                 ErrorMessage("Perfmonitor: Could not open performance stats file "
356                         "\"%s\" for reading to copy to archive \"%s\": %s.\n",
357                         old_file, (*rotate_file_with_index ? rotate_file_with_index :
358                         rotate_file), strerror(errno));
359                 break;
360             }
361 
362             while (!feof(old_fh))
363             {
364                 // This includes the newline from the file.
365                 if (fgets(read_buf, sizeof(read_buf), old_fh) == NULL)
366                 {
367                     if (feof(old_fh))
368                         break;
369 
370                     if (ferror(old_fh))
371                     {
372                         // A read error occurred
373                         ErrorMessage("Perfmonitor: Error reading performance stats "
374                                 "file \"%s\": %s.\n", old_file, strerror(errno));
375                         break;
376                     }
377                 }
378 
379                 num_read = strlen(read_buf);
380 
381                 if (num_read > 0)
382                 {
383                     int rotate_fd = fileno(rotate_fh);
384 
385                     if (fstat(rotate_fd, &file_stats) != 0)
386                     {
387                         ErrorMessage("Perfmonitor: Error getting file "
388                                 "information for \"%s\": %s.\n",
389                                 *rotate_file_with_index ? rotate_file_with_index : rotate_file,
390                                 strerror(errno));
391                         break;
392                     }
393 
394                     if (((uint32_t)file_stats.st_size + num_read) > max_file_size)
395                     {
396                         fclose(rotate_fh);
397 
398                         rotate_index++;
399 
400                         // Create new file same as before but with an index added to the end
401                         SnortSnprintf(rotate_file_with_index, PATH_MAX, "%s.%02d",
402                                 rotate_file, rotate_index);
403 
404                         rotate_fh = fopen(rotate_file_with_index, "a");
405                         if (rotate_fh == NULL)
406                         {
407                             ErrorMessage("Perfmonitor: Could not open performance "
408                                     "stats archive file \"%s\" for writing: %s.\n",
409                                     rotate_file_with_index, strerror(errno));
410                             break;
411                         }
412                     }
413 
414                     num_wrote = fprintf(rotate_fh, "%s", read_buf);
415                     if ((num_wrote != num_read) && ferror(rotate_fh))
416                     {
417                         // A bad write occurred
418                         ErrorMessage("Perfmonitor: Error writing to performance "
419                                 "stats archive file \"%s\": %s.\n", rotate_file, strerror(errno));
420                         break;
421                     }
422 
423                     fflush(rotate_fh);
424                 }
425             }
426         } while (0);
427 
428         if (rotate_fh != NULL)
429             fclose(rotate_fh);
430 
431         if (old_fh != NULL)
432             fclose(old_fh);
433 
434 #ifndef WIN32
435         umask(old_umask);
436 #endif
437     }
438 
439     return 0;
440 }
441 
sfRotateBaseStatsFile(SFPERF * sfPerf)442 int sfRotateBaseStatsFile(SFPERF *sfPerf)
443 {
444     if ((sfPerf != NULL) && (sfPerf->file != NULL))
445     {
446         int ret = sfRotateFile(sfPerf->file, sfPerf->fh, NULL, sfPerf->max_file_size);
447         if (ret != 0)
448             return ret;
449 
450         if ((sfPerf->fh = sfOpenBaseStatsFile(sfPerf->file)) == NULL)
451         {
452             FatalError("Cannot open performance stats file \"%s\": %s.\n",
453                     sfPerf->file, strerror(errno));
454         }
455     }
456 
457     return 0;
458 }
459 
sfRotateFlowStatsFile(SFPERF * sfPerf)460 int sfRotateFlowStatsFile(SFPERF *sfPerf)
461 {
462     if ((sfPerf != NULL) && (sfPerf->flow_file != NULL))
463     {
464         int ret = sfRotateFile(sfPerf->flow_file, sfPerf->flow_fh, "flow", sfPerf->max_file_size);
465         if (ret != 0)
466             return ret;
467 
468         if ((sfPerf->flow_fh = sfOpenFlowStatsFile(sfPerf->flow_file)) == NULL)
469         {
470             FatalError("Perfmonitor: Cannot open flow stats file \"%s\": %s.\n",
471                     sfPerf->flow_file, strerror(errno));
472         }
473     }
474 
475     return 0;
476 }
477 
sfRotateFlowIPStatsFile(SFPERF * sfPerf)478 static inline int sfRotateFlowIPStatsFile(SFPERF *sfPerf)
479 {
480     if ((sfPerf != NULL) && (sfPerf->flowip_file != NULL))
481     {
482         int ret = sfRotateFile(sfPerf->flowip_file, sfPerf->flowip_fh, "flow-ip", sfPerf->max_file_size);
483         if (ret != 0)
484             return ret;
485 
486         if ((sfPerf->flowip_fh = sfOpenFlowIPStatsFile(sfPerf->flowip_file)) == NULL)
487         {
488             FatalError("Perfmonitor: Cannot open flow-ip stats file \"%s\": %s.\n",
489                     sfPerf->flowip_file, strerror(errno));
490         }
491     }
492 
493     return 0;
494 }
495 
sfPerformanceStats(SFPERF * sfPerf,Packet * p)496 void sfPerformanceStats(SFPERF *sfPerf, Packet *p)
497 {
498     // Update stats first since other stats from various places like frag3 and
499     // stream5 have been added.
500     UpdatePerfStats(sfPerf, p);
501 
502     if ((sfPerf->perf_flags & SFPERF_TIME_COUNT) && !PacketIsRebuilt(p))
503     {
504         pkt_cnt++;
505         sfPerformanceStatsOOB(sfPerf, p->pkth->ts.tv_sec);
506     }
507 }
508 
sfPerformanceStatsOOB(SFPERF * sfPerf,time_t curr_time)509 void sfPerformanceStatsOOB(SFPERF *sfPerf, time_t curr_time)
510 {
511     if (sfPerf && pkt_cnt >= sfPerf->pkt_cnt) //For perfect alignment, sfPerf->pkt_count should be set to 0 in config
512     {
513         if (CheckSampleInterval(sfPerf, curr_time))
514         {
515             pkt_cnt = 0;
516 
517             if (!(sfPerf->perf_flags & SFPERF_SUMMARY_BASE))
518             {
519                 if (sfPerf->perf_flags & SFPERF_BASE)
520                 {
521                     sfProcessBaseStats(sfPerf);
522                     InitBaseStats(&sfBase);
523                 }
524             }
525 
526             if (!(sfPerf->perf_flags & SFPERF_SUMMARY_FLOW))
527             {
528                 if (sfPerf->perf_flags & SFPERF_FLOW)
529                 {
530                     sfProcessFlowStats(sfPerf);
531                     InitFlowStats(&sfFlow);
532                 }
533             }
534 
535             if (!(sfPerf->perf_flags & SFPERF_SUMMARY_FLOWIP))
536             {
537                 if (sfPerf->perf_flags & SFPERF_FLOWIP)
538                 {
539                     sfProcessFlowIpStats(sfPerf);
540                     InitFlowIPStats(&sfFlow);
541                 }
542             }
543 
544             if (!(sfPerf->perf_flags & SFPERF_SUMMARY_EVENT))
545             {
546                 if (sfPerf->perf_flags & SFPERF_EVENT)
547                 {
548                     sfProcessEventStats(sfPerf);
549                     InitEventStats(&sfEvent);
550                 }
551             }
552         }
553     }
554 }
555 
CheckSampleInterval(SFPERF * sfPerf,time_t curr_time)556 static bool CheckSampleInterval(SFPERF *sfPerf, time_t curr_time)
557 {
558     static time_t last_true = 0;
559 
560     //Initial alignment
561     if (last_true == 0)
562     {
563         last_true = curr_time;
564         last_true -= last_true % sfPerf->sample_interval;
565     }
566 
567     //Dump on aligned time if possible. If not, get close and say we did.
568     if (curr_time - last_true >= sfPerf->sample_interval)
569     {
570         curr_time -= curr_time % sfPerf->sample_interval;
571         sfBase.time = curr_time;
572         sfFlow.time = curr_time;
573         last_true = curr_time;
574         return true;
575     }
576 
577     return false;
578 }
579 
InitPerfStats(SFPERF * sfPerf)580 void InitPerfStats(SFPERF *sfPerf)
581 {
582 #ifdef LINUX_SMP
583     memset(&sfBase, 0, offsetof(SFBASE, sfProcPidStats));
584 #else
585     memset(&sfBase, 0, sizeof(SFBASE));
586 #endif
587     memset(&sfFlow, 0, sizeof(SFFLOW));
588     memset(&sfEvent, 0, sizeof(SFEVENT));
589     if (sfPerf->perf_flags & SFPERF_BASE)
590         InitBaseStats(&sfBase);
591 
592     if (sfPerf->perf_flags & SFPERF_FLOW)
593         InitFlowStats(&sfFlow);
594 
595     if (sfPerf->perf_flags & SFPERF_FLOWIP)
596         InitFlowIPStats(&sfFlow);
597 
598     if (sfPerf->perf_flags & SFPERF_EVENT)
599         InitEventStats(&sfEvent);
600 }
601 
UpdatePerfStats(SFPERF * sfPerf,Packet * p)602 static void UpdatePerfStats(SFPERF *sfPerf, Packet *p)
603 {
604     bool rebuilt = PacketIsRebuilt(p);
605 
606     if (sfPerf->perf_flags & SFPERF_BASE)
607         UpdateBaseStats(&sfBase, p, rebuilt);
608 
609     if ((sfPerf->perf_flags & SFPERF_FLOW) && !rebuilt)
610         UpdateFlowStats(&sfFlow, p);
611 
612     if ((sfPerf->perf_flags & SFPERF_FLOWIP) && IsIP(p) && !rebuilt)
613     {
614         SFSType type = SFS_TYPE_OTHER;
615 
616         if (p->tcph != NULL)
617             type = SFS_TYPE_TCP;
618         else if (p->udph != NULL)
619             type = SFS_TYPE_UDP;
620 
621         UpdateFlowIPStats(&sfFlow, GET_SRC_IP(p), GET_DST_IP(p), p->pkth->caplen, type);
622     }
623 }
624 
sfCheckFileSize(FILE * fh,uint32_t max_file_size)625 static inline bool sfCheckFileSize(FILE *fh, uint32_t max_file_size)
626 {
627     int fd;
628     struct stat file_stats;
629 
630     if (fh == NULL)
631         return false;
632 
633     fd = fileno(fh);
634     if ((fstat(fd, &file_stats) == 0)
635             && ((uint32_t)file_stats.st_size >= max_file_size))
636         return true;
637 
638     return false;
639 }
640 
sfProcessBaseStats(SFPERF * sfPerf)641 static inline void sfProcessBaseStats(SFPERF *sfPerf)
642 {
643     if (!(sfPerf->perf_flags & SFPERF_BASE))
644         return;
645 
646     ProcessBaseStats(&sfBase, sfPerf->fh,
647             sfPerf->perf_flags & SFPERF_CONSOLE,
648             sfPerf->perf_flags & SFPERF_MAX_BASE_STATS);
649 
650     if ((sfPerf->fh != NULL)
651             && sfCheckFileSize(sfPerf->fh, sfPerf->max_file_size))
652     {
653         sfRotateBaseStatsFile(sfPerf);
654     }
655 }
656 
sfProcessFlowStats(SFPERF * sfPerf)657 static inline void sfProcessFlowStats(SFPERF *sfPerf)
658 {
659     if (!(sfPerf->perf_flags & SFPERF_FLOW))
660         return;
661 
662     ProcessFlowStats(&sfFlow, sfPerf->flow_fh,
663             sfPerf->perf_flags & SFPERF_CONSOLE);
664 
665     if ((sfPerf->flow_fh != NULL)
666             && sfCheckFileSize(sfPerf->flow_fh, sfPerf->max_file_size))
667     {
668         sfRotateFlowStatsFile(sfPerf);
669     }
670 }
671 
sfProcessFlowIpStats(SFPERF * sfPerf)672 static inline void sfProcessFlowIpStats(SFPERF *sfPerf)
673 {
674     if (!(sfPerf->perf_flags & SFPERF_FLOWIP))
675         return;
676 
677     ProcessFlowIPStats(&sfFlow, sfPerf->flowip_fh,
678             sfPerf->perf_flags & SFPERF_CONSOLE);
679 
680     if ((sfPerf->flowip_fh != NULL)
681             && sfCheckFileSize(sfPerf->flowip_fh, sfPerf->max_file_size))
682     {
683         sfRotateFlowIPStatsFile(sfPerf);
684     }
685 }
686 
sfProcessEventStats(SFPERF * sfPerf)687 static inline void sfProcessEventStats(SFPERF *sfPerf)
688 {
689     if (!(sfPerf->perf_flags & SFPERF_EVENT))
690         return;
691 
692     if (sfPerf->perf_flags & SFPERF_CONSOLE)
693         ProcessEventStats(&sfEvent);
694 }
695 
sfPerfStatsSummary(SFPERF * sfPerf)696 void sfPerfStatsSummary(SFPERF *sfPerf)
697 {
698     if (sfPerf == NULL)
699         return;
700 
701     if (sfPerf->perf_flags & SFPERF_SUMMARY_BASE)
702         sfProcessBaseStats(sfPerf);
703 
704     if (sfPerf->perf_flags & SFPERF_SUMMARY_FLOW)
705         sfProcessFlowStats(sfPerf);
706 
707     if (sfPerf->perf_flags & SFPERF_SUMMARY_FLOWIP)
708         sfProcessFlowIpStats(sfPerf);
709 
710     if (sfPerf->perf_flags & SFPERF_SUMMARY_EVENT)
711         sfProcessEventStats(sfPerf);
712 }
713 
sfInitBaseStats(SFPERF * sfPerf)714 static void sfInitBaseStats(SFPERF *sfPerf)
715 {
716     if (sfPerf->perf_flags & SFPERF_BASE)
717         InitBaseStats(&sfBase);
718 }
719 
sfInitFlowStats(SFPERF * sfPerf)720 static void sfInitFlowStats(SFPERF *sfPerf)
721 {
722     if (sfPerf->perf_flags & SFPERF_FLOW)
723         InitFlowStats(&sfFlow);
724 }
725 
sfInitFlowIPStats(SFPERF * sfPerf)726 static void sfInitFlowIPStats(SFPERF *sfPerf)
727 {
728     if (sfPerf->perf_flags & SFPERF_FLOWIP)
729         InitFlowIPStats(&sfFlow);
730 }
731 
sfInitEventStats(SFPERF * sfPerf)732 static void sfInitEventStats(SFPERF *sfPerf)
733 {
734     if (sfPerf->perf_flags & SFPERF_EVENT)
735         InitEventStats(&sfEvent);
736 }
737 
sfFreeFlowStats(SFPERF * sfPerf)738 static void sfFreeFlowStats(SFPERF *sfPerf)
739 {
740     FreeFlowStats(&sfFlow);
741 }
742 
sfFreeFlowIPStats(SFPERF * sfPerf)743 static void sfFreeFlowIPStats(SFPERF *sfPerf)
744 {
745     FreeFlowIPStats(&sfFlow);
746 }
747 
748 #ifdef SNORT_RELOAD
749 //this function determines what is necessary to swap configs and keep stats and files synchronized
750 //it will perform the actions necessary durring the appropriate stage of ReloadSwap
751 // or you can force it to perform all actions by setting fullSync to a non-zero value
752 //
753 //if fullSync is set to 0 then actions are taken under the following conditions
754 //If files need to be opened they are opened durring ReloadVerify
755 //If stats need to be written to files and flushed it is done durring ReloadSwap
756 //If files need to be closed it is done durring ReloadSwapFree
syncStats(SFPERF * currentSFPerf,SFPERF * newSFPerf,int flag,int summaryFlag,char * currentFile,char * newFile,FILE ** currentFH,FILE ** newFH,void (* processFunc)(SFPERF *),void (* initFunc)(SFPERF *),void (* freeFunc)(SFPERF *),FILE * (* openFileFunc)(const char *),void (* closeFileFunc)(SFPERF *),int fullSync)757 static void syncStats(  SFPERF *currentSFPerf, SFPERF *newSFPerf,
758                         int flag, int summaryFlag, //if summaryFlag is set then flag is set
759                         char *currentFile, char *newFile,
760                         FILE **currentFH, FILE **newFH,
761                         void (*processFunc)(SFPERF *),
762                         void (*initFunc)(SFPERF *), void (*freeFunc)(SFPERF *),
763                         FILE* (*openFileFunc)(const char *), void (*closeFileFunc)(SFPERF *),
764                         int fullSync)
765 {
766     int old_flags = currentSFPerf->perf_flags;
767     int new_flags = newSFPerf->perf_flags;
768     int config_flags = old_flags | new_flags;
769 
770     //summaryFlag implies that flag is set
771     //otherwise code breaks <- I got this implication from other sets of code (i.e. InitPerfStats)
772 
773     //these stats were recorded, but are not recorded in new config
774     if (old_flags & flag && !(new_flags & flag))
775     {
776         //we need to flush the stats at the correct time
777         if (perfmon_reload_status == PERF_RELOAD_SWAP || fullSync)
778             //write stats for last period (or summary)
779             (*processFunc)(currentSFPerf);
780         //only close files in ReloadSwapFree to avoid latencies
781         if (perfmon_reload_status == PERF_RELOAD_SWAP_FREE || fullSync)
782         {
783             //not every stat group has a file
784             if (closeFileFunc != NULL)
785                 (*closeFileFunc)(currentSFPerf);
786             //not every stat group uses dynamic memory
787             if (freeFunc != NULL)
788                 (*freeFunc)(currentSFPerf);
789         }
790     }
791     //these stats were not recorded, but will be recorded in new config
792     else if ( !(old_flags & flag) && new_flags & flag )
793     {
794         if (perfmon_reload_status == PERF_RELOAD_VERIFY || fullSync)
795         {
796            //init/reset stats
797            (*initFunc)(newSFPerf);
798            //open up new file
799            if (openFileFunc)
800                *newFH = (*openFileFunc)(newFile);
801         }
802     }
803     // both configs have flag
804     else if (config_flags & flag)
805     {
806         //one config is not summary
807        if (!(old_flags & summaryFlag && new_flags & summaryFlag))
808         {
809             if (perfmon_reload_status == PERF_RELOAD_SWAP || fullSync)
810             {
811                 //log and clear stats
812                 (*processFunc)(currentSFPerf);
813                 (*initFunc)(currentSFPerf);
814             }
815         }
816         //stat group must have log files
817         if ( openFileFunc != NULL && closeFileFunc != NULL)
818         {
819             //the new file has a new name
820             if ( newFile != NULL
821                     && (currentFile == NULL || strcmp(currentFile,newFile) != 0))
822             {
823                 if (perfmon_reload_status == PERF_RELOAD_VERIFY || fullSync)
824                     *newFH = (*openFileFunc)(newFile);
825                 if (perfmon_reload_status == PERF_RELOAD_SWAP_FREE || fullSync)
826                     (*closeFileFunc)(currentSFPerf);
827             }
828             //use the same file
829             else if (*currentFH != NULL)
830             {
831                 if (perfmon_reload_status == PERF_RELOAD_SWAP || fullSync)
832                     *newFH = *currentFH;
833             }
834         }
835     }
836     //else neither config has stats logged
837 }
838 
839 //you can have SFPERF_SUMMARY_FLAG without a SFPERF_FLAG, but
840 //perfmon acts as though neither flag is set and doesn't do any logging
841 //for those statisitcs
syncAllStats(SFPERF * currentSFPerf,SFPERF * newSFPerf)842 void syncAllStats(SFPERF *currentSFPerf, SFPERF *newSFPerf)
843 {
844     if (currentSFPerf == NULL || newSFPerf == NULL)
845         return;
846 
847     //base stats
848     syncStats(  currentSFPerf, newSFPerf,
849                 SFPERF_BASE, SFPERF_SUMMARY_BASE,
850                 currentSFPerf->file, newSFPerf->file,
851                 &(currentSFPerf->fh), &(newSFPerf->fh),
852                 &sfProcessBaseStats,
853                 &sfInitBaseStats, NULL,
854                 &sfOpenBaseStatsFile, &sfCloseBaseStatsFile,
855                 0);
856     //flow stats
857     syncStats(  currentSFPerf,newSFPerf,
858                 SFPERF_FLOW, SFPERF_SUMMARY_FLOW,
859                 currentSFPerf->flow_file, newSFPerf->flow_file,
860                 &(currentSFPerf->flow_fh), &(newSFPerf->flow_fh),
861                 &sfProcessFlowStats,
862                 &sfInitFlowStats, &sfFreeFlowStats,
863                 &sfOpenFlowStatsFile, &sfCloseFlowStatsFile,
864                 0);
865 
866    //flowip stats
867     syncStats(  currentSFPerf, newSFPerf,
868                 SFPERF_FLOWIP, SFPERF_SUMMARY_FLOWIP,
869                 currentSFPerf->flowip_file, newSFPerf->flowip_file,
870                 &(currentSFPerf->flowip_fh), &(newSFPerf->flowip_fh),
871                 &sfProcessFlowIpStats,
872                 &sfInitFlowIPStats, &sfFreeFlowIPStats,
873                 &sfOpenFlowIPStatsFile, &sfCloseFlowIPStatsFile,
874                 0);
875 
876    //event stats
877    syncStats(   currentSFPerf, newSFPerf,
878                 SFPERF_EVENT, SFPERF_SUMMARY_EVENT,
879                 NULL, NULL,
880                 NULL, NULL,
881                 &sfProcessEventStats,
882                 &sfInitEventStats, NULL,
883                 NULL, NULL,
884                 0);
885 }
886 #endif
887 
888